/* GDK - The GIMP Drawing Kit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "../config.h" /* If you don't want to use gdk's signal handlers define this */ /* #define I_NEED_TO_ACTUALLY_DEBUG_MY_PROGRAMS 1 */ #include #include #include #include #include #include #include #ifdef USE_XIM #include #endif #ifdef HAVE_SYS_SELECT_H #include #endif /* HAVE_SYS_SELECT_H_ */ #define XLIB_ILLEGAL_ACCESS #include #include #include #include #include #ifdef USE_XIM #include #endif #include #include "gdk.h" #include "gdkprivate.h" #include "gdkinput.h" #include "gdkx.h" #include "gdkkeysyms.h" #include "gdki18n.h" #ifndef X_GETTIMEOFDAY #define X_GETTIMEOFDAY(tv) gettimeofday (tv, NULL) #endif /* X_GETTIMEOFDAY */ #define DOUBLE_CLICK_TIME 250 #define TRIPLE_CLICK_TIME 500 #define DOUBLE_CLICK_DIST 5 #define TRIPLE_CLICK_DIST 5 #ifndef NO_FD_SET # define SELECT_MASK fd_set #else # ifndef _AIX typedef long fd_mask; # endif # if defined(_IBMR2) # define SELECT_MASK void # else # define SELECT_MASK int # endif #endif typedef struct _GdkInput GdkInput; typedef struct _GdkPredicate GdkPredicate; struct _GdkInput { gint tag; gint source; GdkInputCondition condition; GdkInputFunction function; gpointer data; GdkDestroyNotify destroy; }; struct _GdkPredicate { GdkEventFunc func; gpointer data; }; /* * Private function declarations */ static GdkEvent *gdk_event_new (void); static gint gdk_event_wait (void); static gint gdk_event_apply_filters (XEvent *xevent, GdkEvent *event, GList *filters); static gint gdk_event_translate (GdkEvent *event, XEvent *xevent); #if 0 static Bool gdk_event_get_type (Display *display, XEvent *xevent, XPointer arg); #endif static void gdk_synthesize_click (GdkEvent *event, gint nclicks); static void gdk_dnd_drag_begin (GdkWindow *initial_window); static void gdk_dnd_drag_enter (Window dest); static void gdk_dnd_drag_leave (Window dest); static void gdk_dnd_drag_end (Window dest, GdkPoint coords); static GdkAtom gdk_dnd_check_types (GdkWindow *window, XEvent *xevent); #ifdef DEBUG_DND static void gdk_print_atom (GdkAtom anatom); #endif #ifndef HAVE_XCONVERTCASE static void gdkx_XConvertCase (KeySym symbol, KeySym *lower, KeySym *upper); #define XConvertCase gdkx_XConvertCase #endif /* * old junk from offix, we might use it though so leave it */ Window gdk_get_client_window (Display *dpy, Window win); #ifdef WE_HAVE_MOTIF_DROPS_DONE static GdkWindow * gdk_drop_get_real_window (GdkWindow *w, guint16 *x, guint16 *y); #endif static void gdk_exit_func (void); static int gdk_x_error (Display *display, XErrorEvent *error); static int gdk_x_io_error (Display *display); static RETSIGTYPE gdk_signal (int signum); #ifdef USE_XIM static guint gdk_im_va_count (va_list list); static XVaNestedList gdk_im_va_to_nested (va_list list, guint count); static GdkIM gdk_im_get (void); static gint gdk_im_open (XrmDatabase db, gchar* res_name, gchar* rec_class); static void gdk_im_close (void); static void gdk_ic_cleanup (void); #endif /* USE_XIM */ /* Private variable declarations */ static int gdk_initialized = 0; /* 1 if the library is initialized, * 0 otherwise. */ static int connection_number = 0; /* The file descriptor number of our * connection to the X server. This * is used so that we may determine * when events are pending by using * the "select" system call. */ static struct timeval start; /* The time at which the library was * last initialized. */ static struct timeval timer; /* Timeout interval to use in the call * to "select". This is used in * conjunction with "timerp" to create * a maximum time to wait for an event * to arrive. */ static struct timeval *timerp; /* The actual timer passed to "select" * This may be NULL, in which case * "select" will block until an event * arrives. */ static guint32 timer_val; /* The timeout length as specified by * the user in milliseconds. */ static GList *inputs; /* A list of the input file descriptors * that we care about. Each list node * contains a GdkInput struct that describes * when we are interested in the specified * file descriptor. That is, when it is * available for read, write or has an * exception pending. */ static guint32 button_click_time[2]; /* The last 2 button click times. Used * to determine if the latest button click * is part of a double or triple click. */ static GdkWindow *button_window[2]; /* The last 2 windows to receive button presses. * Also used to determine if the latest button * click is part of a double or triple click. */ static guint button_number[2]; /* The last 2 buttons to be pressed. */ static GdkWindowPrivate *xgrab_window = NULL; /* Window that currently holds the * x pointer grab */ #ifdef USE_XIM static gint xim_using; /* using XIM Protocol if TRUE */ static GdkIM xim_im; /* global IM */ static XIMStyles* xim_styles; /* im supports these styles */ static XIMStyle xim_best_allowed_style; static GdkICPrivate *xim_ic; /* currently using IC */ static GdkWindow* xim_window; /* currently using Widow */ static GList* xim_ic_list; #endif static GList *putback_events = NULL; static gulong base_id; static gint autorepeat; #ifdef G_ENABLE_DEBUG static GDebugKey gdk_debug_keys[] = { {"events", GDK_DEBUG_EVENTS}, {"misc", GDK_DEBUG_MISC}, {"dnd", GDK_DEBUG_DND}, {"color-context", GDK_DEBUG_COLOR_CONTEXT}, {"xim", GDK_DEBUG_XIM} }; static const int gdk_ndebug_keys = sizeof(gdk_debug_keys)/sizeof(GDebugKey); #endif /* G_ENABLE_DEBUG */ /* *-------------------------------------------------------------- * gdk_init * * Initialize the library for use. * * Arguments: * "argc" is the number of arguments. * "argv" is an array of strings. * * Results: * "argc" and "argv" are modified to reflect any arguments * which were not handled. (Such arguments should either * be handled by the application or dismissed). * * Side effects: * The library is initialized. * *-------------------------------------------------------------- */ void gdk_init (int *argc, char ***argv) { XKeyboardState keyboard_state; gint synchronize; gint i, j, k; XClassHint *class_hint; gchar **argv_orig = NULL; gint argc_orig = 0; if (gdk_initialized) return; if (argc && argv) { argc_orig = *argc; argv_orig = g_malloc ((argc_orig + 1) * sizeof (char*)); for (i = 0; i < argc_orig; i++) argv_orig[i] = g_strdup ((*argv)[i]); argv_orig[argc_orig] = NULL; } X_GETTIMEOFDAY (&start); #ifndef I_NEED_TO_ACTUALLY_DEBUG_MY_PROGRAMS signal (SIGHUP, gdk_signal); signal (SIGINT, gdk_signal); signal (SIGQUIT, gdk_signal); signal (SIGBUS, gdk_signal); signal (SIGSEGV, gdk_signal); signal (SIGPIPE, gdk_signal); signal (SIGTERM, gdk_signal); #endif gdk_display_name = NULL; XSetErrorHandler (gdk_x_error); XSetIOErrorHandler (gdk_x_io_error); synchronize = FALSE; #ifdef G_ENABLE_DEBUG { gchar *debug_string = getenv("GDK_DEBUG"); if (debug_string != NULL) gdk_debug_flags = g_parse_debug_string (debug_string, gdk_debug_keys, gdk_ndebug_keys); } #endif /* G_ENABLE_DEBUG */ if (argc && argv) { if (*argc > 0) { gchar *d; d = strrchr((*argv)[0],'/'); if (d != NULL) g_set_prgname (d + 1); else g_set_prgname ((*argv)[0]); } for (i = 1; i < *argc;) { #ifdef G_ENABLE_DEBUG if ((strcmp ("--gdk-debug", (*argv)[i]) == 0) || (strncmp ("--gdk-debug=", (*argv)[i], 12) == 0)) { gchar *equal_pos = strchr ((*argv)[i], '='); if (equal_pos != NULL) { gdk_debug_flags |= g_parse_debug_string (equal_pos+1, gdk_debug_keys, gdk_ndebug_keys); } else if ((i + 1) < *argc && (*argv)[i + 1]) { gdk_debug_flags |= g_parse_debug_string ((*argv)[i+1], gdk_debug_keys, gdk_ndebug_keys); (*argv)[i] = NULL; i += 1; } (*argv)[i] = NULL; } else if ((strcmp ("--gdk-no-debug", (*argv)[i]) == 0) || (strncmp ("--gdk-no-debug=", (*argv)[i], 15) == 0)) { gchar *equal_pos = strchr ((*argv)[i], '='); if (equal_pos != NULL) { gdk_debug_flags &= ~g_parse_debug_string (equal_pos+1, gdk_debug_keys, gdk_ndebug_keys); } else if ((i + 1) < *argc && (*argv)[i + 1]) { gdk_debug_flags &= ~g_parse_debug_string ((*argv)[i+1], gdk_debug_keys, gdk_ndebug_keys); (*argv)[i] = NULL; i += 1; } (*argv)[i] = NULL; } else #endif /* G_ENABLE_DEBUG */ if (strcmp ("--display", (*argv)[i]) == 0) { (*argv)[i] = NULL; if ((i + 1) < *argc && (*argv)[i + 1]) { gdk_display_name = g_strdup ((*argv)[i + 1]); (*argv)[i + 1] = NULL; i += 1; } } else if (strcmp ("--sync", (*argv)[i]) == 0) { (*argv)[i] = NULL; synchronize = TRUE; } else if (strcmp ("--no-xshm", (*argv)[i]) == 0) { (*argv)[i] = NULL; gdk_use_xshm = FALSE; } else if (strcmp ("--name", (*argv)[i]) == 0) { if ((i + 1) < *argc && (*argv)[i + 1]) { (*argv)[i++] = NULL; g_set_prgname ((*argv)[i]); (*argv)[i] = NULL; } } else if (strcmp ("--class", (*argv)[i]) == 0) { if ((i + 1) < *argc && (*argv)[i + 1]) { (*argv)[i++] = NULL; gdk_progclass = (*argv)[i]; (*argv)[i] = NULL; } } #ifdef XINPUT_GXI else if (strcmp ("--gxid_host", (*argv)[i]) == 0) { if ((i + 1) < *argc && (*argv)[i + 1]) { (*argv)[i++] = NULL; gdk_input_gxid_host = ((*argv)[i]); (*argv)[i] = NULL; } } else if (strcmp ("--gxid_port", (*argv)[i]) == 0) { if ((i + 1) < *argc && (*argv)[i + 1]) { (*argv)[i++] = NULL; gdk_input_gxid_port = atoi ((*argv)[i]); (*argv)[i] = NULL; } } #endif #ifdef USE_XIM else if (strcmp ("--xim-preedit", (*argv)[i]) == 0) { if ((i + 1) < *argc && (*argv)[i + 1]) { (*argv)[i++] = NULL; if (strcmp ("none", (*argv)[i]) == 0) gdk_im_set_best_style (GDK_IM_PREEDIT_NONE); else if (strcmp ("nothing", (*argv)[i]) == 0) gdk_im_set_best_style (GDK_IM_PREEDIT_NOTHING); else if (strcmp ("area", (*argv)[i]) == 0) gdk_im_set_best_style (GDK_IM_PREEDIT_AREA); else if (strcmp ("position", (*argv)[i]) == 0) gdk_im_set_best_style (GDK_IM_PREEDIT_POSITION); else if (strcmp ("callbacks", (*argv)[i]) == 0) gdk_im_set_best_style (GDK_IM_PREEDIT_CALLBACKS); } } else if (strcmp ("--xim-status", (*argv)[i]) == 0) { if ((i + 1) < *argc && (*argv)[i + 1]) { (*argv)[i++] = NULL; if (strcmp ("none", (*argv)[i]) == 0) gdk_im_set_best_style (GDK_IM_STATUS_NONE); else if (strcmp ("nothing", (*argv)[i]) == 0) gdk_im_set_best_style (GDK_IM_STATUS_NOTHING); else if (strcmp ("area", (*argv)[i]) == 0) gdk_im_set_best_style (GDK_IM_STATUS_AREA); else if (strcmp ("callbacks", (*argv)[i]) == 0) gdk_im_set_best_style (GDK_IM_STATUS_CALLBACKS); } } #endif i += 1; } for (i = 1; i < *argc; i++) { for (k = i; k < *argc; k++) if ((*argv)[k] != NULL) break; if (k > i) { k -= i; for (j = i + k; j < *argc; j++) (*argv)[j-k] = (*argv)[j]; *argc -= k; } } } else { g_set_prgname (""); } GDK_NOTE (MISC, g_message ("progname: \"%s\"", g_get_prgname ())); gdk_display = XOpenDisplay (gdk_display_name); if (!gdk_display) { g_warning ("cannot open display: %s", XDisplayName (gdk_display_name)); exit(1); } /* This is really crappy. We have to look into the display structure * to find the base resource id. This is only needed for recording * and playback of events. */ /* base_id = RESOURCE_BASE; */ base_id = 0; GDK_NOTE (EVENTS, g_message ("base id: %lu", base_id)); connection_number = ConnectionNumber (gdk_display); GDK_NOTE (MISC, g_message ("connection number: %d", connection_number)); if (synchronize) XSynchronize (gdk_display, True); gdk_screen = DefaultScreen (gdk_display); gdk_root_window = RootWindow (gdk_display, gdk_screen); gdk_leader_window = XCreateSimpleWindow(gdk_display, gdk_root_window, 10, 10, 10, 10, 0, 0 , 0); class_hint = XAllocClassHint(); class_hint->res_name = g_get_prgname (); if (gdk_progclass == NULL) { gdk_progclass = g_strdup (g_get_prgname ()); gdk_progclass[0] = toupper (gdk_progclass[0]); } class_hint->res_class = gdk_progclass; XSetClassHint(gdk_display, gdk_leader_window, class_hint); XSetCommand(gdk_display, gdk_leader_window, argv_orig, argc_orig); XFree (class_hint); for (i = 0; i < argc_orig; i++) g_free(argv_orig[i]); g_free(argv_orig); gdk_wm_delete_window = XInternAtom (gdk_display, "WM_DELETE_WINDOW", True); gdk_wm_take_focus = XInternAtom (gdk_display, "WM_TAKE_FOCUS", True); gdk_wm_protocols = XInternAtom (gdk_display, "WM_PROTOCOLS", True); gdk_wm_window_protocols[0] = gdk_wm_delete_window; gdk_wm_window_protocols[1] = gdk_wm_take_focus; gdk_selection_property = XInternAtom (gdk_display, "GDK_SELECTION", False); gdk_dnd.gdk_XdeEnter = gdk_atom_intern("_XDE_ENTER", FALSE); gdk_dnd.gdk_XdeLeave = gdk_atom_intern("_XDE_LEAVE", FALSE); gdk_dnd.gdk_XdeRequest = gdk_atom_intern("_XDE_REQUEST", FALSE); gdk_dnd.gdk_XdeDataAvailable = gdk_atom_intern("_XDE_DATA_AVAILABLE", FALSE); gdk_dnd.gdk_XdeTypelist = gdk_atom_intern("_XDE_TYPELIST", FALSE); gdk_dnd.c->gdk_cursor_dragdefault = XCreateFontCursor(gdk_display, XC_bogosity); gdk_dnd.c->gdk_cursor_dragok = XCreateFontCursor(gdk_display, XC_heart); XGetKeyboardControl (gdk_display, &keyboard_state); autorepeat = keyboard_state.global_auto_repeat; timer.tv_sec = 0; timer.tv_usec = 0; timerp = NULL; button_click_time[0] = 0; button_click_time[1] = 0; button_window[0] = NULL; button_window[1] = NULL; button_number[0] = -1; button_number[1] = -1; g_atexit (gdk_exit_func); gdk_visual_init (); gdk_window_init (); gdk_image_init (); gdk_input_init (); #ifdef USE_XIM /* initialize XIM Protocol variables */ xim_using = FALSE; xim_im = NULL; xim_styles = NULL; if (!(xim_best_allowed_style & GDK_IM_PREEDIT_MASK)) gdk_im_set_best_style (GDK_IM_PREEDIT_CALLBACKS); if (!(xim_best_allowed_style & GDK_IM_STATUS_MASK)) gdk_im_set_best_style (GDK_IM_STATUS_CALLBACKS); xim_ic = NULL; xim_window = (GdkWindow*)NULL; gdk_im_open (NULL, NULL, NULL); #endif gdk_initialized = 1; } /* *-------------------------------------------------------------- * gdk_exit * * Restores the library to an un-itialized state and exits * the program using the "exit" system call. * * Arguments: * "errorcode" is the error value to pass to "exit". * * Results: * Allocated structures are freed and the program exits * cleanly. * * Side effects: * *-------------------------------------------------------------- */ void gdk_exit (int errorcode) { /* de-initialisation is done by the gdk_exit_funct(), no need to do this here (Alex J.) */ exit (errorcode); } /* *-------------------------------------------------------------- * gdk_set_locale * * Arguments: * * Results: * * Side effects: * *-------------------------------------------------------------- */ gchar* gdk_set_locale (void) { if (!setlocale (LC_ALL,"")) g_message ("locale not supported by C library"); if (!XSupportsLocale ()) { g_message ("locale not supported by Xlib, locale set to C"); setlocale (LC_ALL, "C"); } if (!XSetLocaleModifiers ("")) { g_message ("can not set locale modifiers"); } return setlocale (LC_ALL,NULL); } /* *-------------------------------------------------------------- * gdk_events_pending * * Returns the number of events pending on the queue. * These events have already been read from the server * connection. * * Arguments: * * Results: * Returns the number of events on XLib's event queue. * * Side effects: * *-------------------------------------------------------------- */ gint gdk_events_pending (void) { gint result; GList *tmp_list; result = XPending (gdk_display); tmp_list = putback_events; while (tmp_list) { result++; tmp_list = tmp_list->next; } return result; } /* *-------------------------------------------------------------- * gdk_event_get_graphics_expose * * Waits for a GraphicsExpose or NoExpose event * * Arguments: * * Results: * For GraphicsExpose events, returns a pointer to the event * converted into a GdkEvent Otherwise, returns NULL. * * Side effects: * *-------------------------------------------------------------- */ static Bool graphics_expose_predicate (Display *display, XEvent *xevent, XPointer arg) { GdkWindowPrivate *private = (GdkWindowPrivate *)arg; g_return_val_if_fail (private != NULL, False); if ((xevent->xany.window == private->xwindow) && ((xevent->xany.type == GraphicsExpose) || (xevent->xany.type == NoExpose))) return True; else return False; } GdkEvent * gdk_event_get_graphics_expose (GdkWindow *window) { XEvent xevent; GdkEvent *event; g_return_val_if_fail (window != NULL, NULL); XIfEvent (gdk_display, &xevent, graphics_expose_predicate, (XPointer)window); if (xevent.xany.type == GraphicsExpose) { event = gdk_event_new (); if (gdk_event_translate (event, &xevent)) return event; else gdk_event_free (event); } return NULL; } /* *-------------------------------------------------------------- * gdk_event_get * * Gets the next event. * * Arguments: * * Results: * If an event was received that we care about, returns * a pointer to that event, to be freed with gdk_event_free. * Otherwise, returns NULL. This function will also return * before an event is received if the timeout interval * runs out. * * Side effects: * *-------------------------------------------------------------- */ GdkEvent * gdk_event_get (void) { GdkEvent *event; GList *temp_list; XEvent xevent; #if 0 if (pred) { temp_list = putback_events; while (temp_list) { temp_event = temp_list->data; if ((* pred) (temp_event, data)) { if (event) *event = *temp_event; putback_events = g_list_remove_link (putback_events, temp_list); g_list_free (temp_list); return TRUE; } temp_list = temp_list->next; } event_pred.func = pred; event_pred.data = data; if (XCheckIfEvent (gdk_display, &xevent, gdk_event_get_type, (XPointer) & event_pred)) if (event) return gdk_event_translate (event, &xevent); } else #endif if (putback_events) { event = putback_events->data; temp_list = putback_events; putback_events = g_list_remove_link (putback_events, temp_list); g_list_free_1 (temp_list); return event; } /* Wait for an event to occur or the timeout to elapse. * If an event occurs "gdk_event_wait" will return TRUE. * If the timeout elapses "gdk_event_wait" will return * FALSE. */ if (gdk_event_wait ()) { /* If we get here we can rest assurred that an event * has occurred. Read it. */ #ifdef USE_XIM gint filter_status; if (xim_using && xim_window) do { /* don't dispatch events used by IM */ XNextEvent (gdk_display, &xevent); filter_status = XFilterEvent (&xevent, GDK_WINDOW_XWINDOW (xim_window)); } while (filter_status == True); else XNextEvent (gdk_display, &xevent); #else XNextEvent (gdk_display, &xevent); #endif event = gdk_event_new (); event->any.type = GDK_NOTHING; event->any.window = NULL; event->any.send_event = FALSE; event->any.send_event = xevent.xany.send_event; if (gdk_event_translate (event, &xevent)) return event; else gdk_event_free (event); } return NULL; } void gdk_event_put (GdkEvent *event) { GdkEvent *new_event; g_return_if_fail (event != NULL); new_event = gdk_event_copy (event); putback_events = g_list_prepend (putback_events, new_event); } /* *-------------------------------------------------------------- * gdk_event_copy * * Copy a event structure into new storage. * * Arguments: * "event" is the event struct to copy. * * Results: * A new event structure. Free it with gdk_event_free. * * Side effects: * The reference count of the window in the event is increased. * *-------------------------------------------------------------- */ static GMemChunk *event_chunk; static GdkEvent* gdk_event_new (void) { GdkEvent *new_event; if (event_chunk == NULL) event_chunk = g_mem_chunk_new ("events", sizeof (GdkEvent), 4096, G_ALLOC_AND_FREE); new_event = g_chunk_new (GdkEvent, event_chunk); return new_event; } GdkEvent* gdk_event_copy (GdkEvent *event) { GdkEvent *new_event; g_return_val_if_fail (event != NULL, NULL); new_event = gdk_event_new (); *new_event = *event; gdk_window_ref (new_event->any.window); switch (event->any.type) { case GDK_KEY_PRESS: case GDK_KEY_RELEASE: new_event->key.string = g_strdup (event->key.string); break; case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: if (event->crossing.subwindow != NULL) gdk_window_ref (event->crossing.subwindow); break; case GDK_DROP_DATA_AVAIL: new_event->dropdataavailable.data_type = g_strdup (event->dropdataavailable.data_type); new_event->dropdataavailable.data = g_malloc (event->dropdataavailable.data_numbytes); memcpy (new_event->dropdataavailable.data, event->dropdataavailable.data, event->dropdataavailable.data_numbytes); break; default: break; } return new_event; } /* *-------------------------------------------------------------- * gdk_event_free * * Free a event structure obtained from gdk_event_copy. Do not use * with other event structures. * * Arguments: * "event" is the event struct to free. * * Results: * * Side effects: * The reference count of the window in the event is decreased and * might be freed, too. * *-------------------------------------------------------------- */ void gdk_event_free (GdkEvent *event) { g_assert (event_chunk != NULL); g_return_if_fail (event != NULL); if (event->any.window) gdk_window_unref (event->any.window); switch (event->any.type) { case GDK_KEY_PRESS: case GDK_KEY_RELEASE: g_free (event->key.string); break; case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: if (event->crossing.subwindow != NULL) gdk_window_unref (event->crossing.subwindow); break; case GDK_DROP_DATA_AVAIL: g_free (event->dropdataavailable.data_type); g_free (event->dropdataavailable.data); break; case GDK_DRAG_REQUEST: g_free (event->dragrequest.data_type); break; default: break; } g_mem_chunk_free (event_chunk, event); } /* *-------------------------------------------------------------- * gdk_set_show_events * * Turns on/off the showing of events. * * Arguments: * "show_events" is a boolean describing whether or * not to show the events gdk receives. * * Results: * * Side effects: * When "show_events" is TRUE, calls to "gdk_event_get" * will output debugging informatin regarding the event * received to stdout. * *-------------------------------------------------------------- */ void gdk_set_show_events (int show_events) { if (show_events) gdk_debug_flags |= GDK_DEBUG_EVENTS; else gdk_debug_flags &= ~GDK_DEBUG_EVENTS; } void gdk_set_use_xshm (gint use_xshm) { gdk_use_xshm = use_xshm; } gint gdk_get_show_events (void) { return gdk_debug_flags & GDK_DEBUG_EVENTS; } gint gdk_get_use_xshm (void) { return gdk_use_xshm; } /* *-------------------------------------------------------------- * gdk_time_get * * Get the number of milliseconds since the library was * initialized. * * Arguments: * * Results: * The time since the library was initialized is returned. * This time value is accurate to milliseconds even though * a more accurate time down to the microsecond could be * returned. * * Side effects: * *-------------------------------------------------------------- */ guint32 gdk_time_get (void) { struct timeval end; struct timeval elapsed; guint32 milliseconds; X_GETTIMEOFDAY (&end); if (start.tv_usec > end.tv_usec) { end.tv_usec += 1000000; end.tv_sec--; } elapsed.tv_sec = end.tv_sec - start.tv_sec; elapsed.tv_usec = end.tv_usec - start.tv_usec; milliseconds = (elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000); return milliseconds; } /* *-------------------------------------------------------------- * gdk_timer_get * * Returns the current timer. * * Arguments: * * Results: * Returns the current timer interval. This interval is * in units of milliseconds. * * Side effects: * *-------------------------------------------------------------- */ guint32 gdk_timer_get (void) { return timer_val; } /* *-------------------------------------------------------------- * gdk_timer_set * * Sets the timer interval. * * Arguments: * "milliseconds" is the new value for the timer. * * Results: * * Side effects: * Calls to "gdk_event_get" will last for a maximum * of time of "milliseconds". However, a value of 0 * milliseconds will cause "gdk_event_get" to block * indefinately until an event is received. * *-------------------------------------------------------------- */ void gdk_timer_set (guint32 milliseconds) { timer_val = milliseconds; timer.tv_sec = milliseconds / 1000; timer.tv_usec = (milliseconds % 1000) * 1000; } void gdk_timer_enable (void) { timerp = &timer; } void gdk_timer_disable (void) { timerp = NULL; } gint gdk_input_add_full (gint source, GdkInputCondition condition, GdkInputFunction function, gpointer data, GdkDestroyNotify destroy) { static gint next_tag = 1; GList *list; GdkInput *input; gint tag; tag = 0; list = inputs; while (list) { input = list->data; list = list->next; if ((input->source == source) && (input->condition == condition)) { if (input->destroy) (input->destroy) (input->data); input->function = function; input->data = data; input->destroy = destroy; tag = input->tag; } } if (!tag) { input = g_new (GdkInput, 1); input->tag = next_tag++; input->source = source; input->condition = condition; input->function = function; input->data = data; input->destroy = destroy; tag = input->tag; inputs = g_list_prepend (inputs, input); } return tag; } gint gdk_input_add (gint source, GdkInputCondition condition, GdkInputFunction function, gpointer data) { return gdk_input_add_interp (source, condition, function, data, NULL); } void gdk_input_remove (gint tag) { GList *list; GdkInput *input; list = inputs; while (list) { input = list->data; if (input->tag == tag) { if (input->destroy) (input->destroy) (input->data); input->tag = 0; /* do not free it here */ input->condition = 0; /* it's done in gdk_event_wait */ break; } list = list->next; } } /* *-------------------------------------------------------------- * gdk_pointer_grab * * Grabs the pointer to a specific window * * Arguments: * "window" is the window which will receive the grab * "owner_events" specifies whether events will be reported as is, * or relative to "window" * "event_mask" masks only interesting events * "confine_to" limits the cursor movement to the specified window * "cursor" changes the cursor for the duration of the grab * "time" specifies the time * * Results: * * Side effects: * requires a corresponding call to gdk_pointer_ungrab * *-------------------------------------------------------------- */ gint gdk_pointer_grab (GdkWindow * window, gint owner_events, GdkEventMask event_mask, GdkWindow * confine_to, GdkCursor * cursor, guint32 time) { /* From gdkwindow.c */ extern int nevent_masks; extern int event_mask_table[]; gint return_val; GdkWindowPrivate *window_private; GdkWindowPrivate *confine_to_private; GdkCursorPrivate *cursor_private; guint xevent_mask; Window xwindow; Window xconfine_to; Cursor xcursor; int i; g_return_val_if_fail (window != NULL, 0); window_private = (GdkWindowPrivate*) window; confine_to_private = (GdkWindowPrivate*) confine_to; cursor_private = (GdkCursorPrivate*) cursor; xwindow = window_private->xwindow; if (!confine_to || confine_to_private->destroyed) xconfine_to = None; else xconfine_to = confine_to_private->xwindow; if (!cursor) xcursor = None; else xcursor = cursor_private->xcursor; xevent_mask = 0; for (i = 0; i < nevent_masks; i++) { if (event_mask & (1 << (i + 1))) xevent_mask |= event_mask_table[i]; } if (gdk_input_vtable.grab_pointer) return_val = gdk_input_vtable.grab_pointer (window, owner_events, event_mask, confine_to, time); else return_val = Success; if (return_val == Success) { if (!window_private->destroyed) return_val = XGrabPointer (window_private->xdisplay, xwindow, owner_events, xevent_mask, GrabModeAsync, GrabModeAsync, xconfine_to, xcursor, time); else return_val = AlreadyGrabbed; } if (return_val == GrabSuccess) xgrab_window = window_private; return return_val; } /* *-------------------------------------------------------------- * gdk_pointer_ungrab * * Releases any pointer grab * * Arguments: * * Results: * * Side effects: * *-------------------------------------------------------------- */ void gdk_pointer_ungrab (guint32 time) { if (gdk_input_vtable.ungrab_pointer) gdk_input_vtable.ungrab_pointer (time); XUngrabPointer (gdk_display, time); xgrab_window = NULL; } /* *-------------------------------------------------------------- * gdk_pointer_is_grabbed * * Tell wether there is an active x pointer grab in effect * * Arguments: * * Results: * * Side effects: * *-------------------------------------------------------------- */ gint gdk_pointer_is_grabbed (void) { return xgrab_window != NULL; } /* *-------------------------------------------------------------- * gdk_keyboard_grab * * Grabs the keyboard to a specific window * * Arguments: * "window" is the window which will receive the grab * "owner_events" specifies whether events will be reported as is, * or relative to "window" * "time" specifies the time * * Results: * * Side effects: * requires a corresponding call to gdk_keyboard_ungrab * *-------------------------------------------------------------- */ gint gdk_keyboard_grab (GdkWindow * window, gint owner_events, guint32 time) { GdkWindowPrivate *window_private; Window xwindow; g_return_val_if_fail (window != NULL, 0); window_private = (GdkWindowPrivate*) window; xwindow = window_private->xwindow; if (!window_private->destroyed) return XGrabKeyboard (window_private->xdisplay, xwindow, owner_events, GrabModeAsync, GrabModeAsync, time); else return AlreadyGrabbed; } /* *-------------------------------------------------------------- * gdk_keyboard_ungrab * * Releases any keyboard grab * * Arguments: * * Results: * * Side effects: * *-------------------------------------------------------------- */ void gdk_keyboard_ungrab (guint32 time) { XUngrabKeyboard (gdk_display, time); } /* *-------------------------------------------------------------- * gdk_screen_width * * Return the width of the screen. * * Arguments: * * Results: * * Side effects: * *-------------------------------------------------------------- */ gint gdk_screen_width (void) { gint return_val; return_val = DisplayWidth (gdk_display, gdk_screen); return return_val; } /* *-------------------------------------------------------------- * gdk_screen_height * * Return the height of the screen. * * Arguments: * * Results: * * Side effects: * *-------------------------------------------------------------- */ gint gdk_screen_height (void) { gint return_val; return_val = DisplayHeight (gdk_display, gdk_screen); return return_val; } /* *-------------------------------------------------------------- * gdk_screen_width_mm * * Return the width of the screen in millimeters. * * Arguments: * * Results: * * Side effects: * *-------------------------------------------------------------- */ gint gdk_screen_width_mm (void) { gint return_val; return_val = DisplayWidthMM (gdk_display, gdk_screen); return return_val; } /* *-------------------------------------------------------------- * gdk_screen_height * * Return the height of the screen in millimeters. * * Arguments: * * Results: * * Side effects: * *-------------------------------------------------------------- */ gint gdk_screen_height_mm (void) { gint return_val; return_val = DisplayHeightMM (gdk_display, gdk_screen); return return_val; } void gdk_key_repeat_disable (void) { XAutoRepeatOff (gdk_display); } void gdk_key_repeat_restore (void) { if (autorepeat) XAutoRepeatOn (gdk_display); else XAutoRepeatOff (gdk_display); } /* *-------------------------------------------------------------- * gdk_flush * * Flushes the Xlib output buffer and then waits * until all requests have been received and processed * by the X server. The only real use for this function * is in dealing with XShm. * * Arguments: * * Results: * * Side effects: * *-------------------------------------------------------------- */ void gdk_flush (void) { XSync (gdk_display, False); } void gdk_beep (void) { XBell(gdk_display, 100); } /* *-------------------------------------------------------------- * gdk_event_wait * * Waits until an event occurs or the timer runs out. * * Arguments: * * Results: * Returns TRUE if an event is ready to be read and FALSE * if the timer ran out. * * Side effects: * *-------------------------------------------------------------- */ static gint gdk_event_wait (void) { GList *list; GList *temp_list; GdkInput *input; GdkInputCondition condition; SELECT_MASK readfds; SELECT_MASK writefds; SELECT_MASK exceptfds; int max_input; int nfd; /* If there are no events pending we will wait for an event. * The time we wait is dependant on the "timer". If no timer * has been specified then we'll block until an event arrives. * If a timer has been specified we'll block until an event * arrives or the timer expires. (This is all done using the * "select" system call). */ if (XPending (gdk_display) == 0) { FD_ZERO (&readfds); FD_ZERO (&writefds); FD_ZERO (&exceptfds); FD_SET (connection_number, &readfds); max_input = connection_number; list = inputs; while (list) { input = list->data; if (input->tag) { if (input->condition & GDK_INPUT_READ) FD_SET (input->source, &readfds); if (input->condition & GDK_INPUT_WRITE) FD_SET (input->source, &writefds); if (input->condition & GDK_INPUT_EXCEPTION) FD_SET (input->source, &exceptfds); max_input = MAX (max_input, input->source); list = list->next; } else /* free removed inputs */ { temp_list = list; if (list->next) list->next->prev = list->prev; if (list->prev) list->prev->next = list->next; if (inputs == list) inputs = list->next; list = list->next; temp_list->next = NULL; temp_list->prev = NULL; g_free (temp_list->data); g_list_free (temp_list); } } #ifdef USE_PTHREADS if (gdk_using_threads) { gdk_select_waiting = TRUE; FD_SET (gdk_threads_pipe[0], &readfds); max_input = MAX (max_input, gdk_threads_pipe[0]); gdk_threads_leave (); } #endif nfd = select (max_input+1, &readfds, &writefds, &exceptfds, timerp); #ifdef USE_PTHREADS if (gdk_using_threads) { gchar c; gdk_threads_enter (); gdk_select_waiting = FALSE; if (FD_ISSET (gdk_threads_pipe[0], &readfds)) read (gdk_threads_pipe[0], &c, 1); } #endif timerp = NULL; timer_val = 0; if (nfd > 0) { if (FD_ISSET (connection_number, &readfds)) { if (XPending (gdk_display) == 0) { if (nfd == 1) { XNoOp (gdk_display); XFlush (gdk_display); } return FALSE; } else return TRUE; } list = inputs; while (list) { input = list->data; list = list->next; condition = 0; if (FD_ISSET (input->source, &readfds)) condition |= GDK_INPUT_READ; if (FD_ISSET (input->source, &writefds)) condition |= GDK_INPUT_WRITE; if (FD_ISSET (input->source, &exceptfds)) condition |= GDK_INPUT_EXCEPTION; if (condition && input->function) (* input->function) (input->data, input->source, condition); } } } else return TRUE; return FALSE; } static gint gdk_event_apply_filters (XEvent *xevent, GdkEvent *event, GList *filters) { GdkEventFilter *filter; GList *tmp_list; GdkFilterReturn result; tmp_list = filters; while (tmp_list) { filter = (GdkEventFilter *)tmp_list->data; result = (*filter->function)(xevent, event, filter->data); if (result != GDK_FILTER_CONTINUE) return result; tmp_list = tmp_list->next; } return GDK_FILTER_CONTINUE; } static gint gdk_event_translate (GdkEvent *event, XEvent *xevent) { GdkWindow *window; GdkWindowPrivate *window_private; static XComposeStatus compose; KeySym keysym; int charcount; #ifdef USE_XIM static gchar* buf = NULL; static gint buf_len= 0; #else char buf[16]; #endif gint return_val; return_val = FALSE; /* We need to play catch-up with the dnd motion events */ if(gdk_dnd.drag_really && xevent->type == MotionNotify) while (XCheckTypedEvent(xevent->xany.display,MotionNotify,xevent)); /* Find the GdkWindow that this event occurred in. * All events occur in some GdkWindow (otherwise, why * would we be receiving them). It really is an error * to receive an event for which we cannot find the * corresponding GdkWindow. We handle events with window=None * specially - they are generated by XFree86's XInput under * some circumstances. */ if ((xevent->xany.window == None) && gdk_input_vtable.window_none_event) { return_val = gdk_input_vtable.window_none_event (event,xevent); if (return_val >= 0) /* was handled */ return return_val; else return_val = FALSE; } window = gdk_window_lookup (xevent->xany.window); window_private = (GdkWindowPrivate *) window; if (window != NULL) gdk_window_ref (window); else if (gdk_null_window_warnings) { /* Special purpose programs that * get events for other windows may * want to disable this */ g_warning ("xwindow(%#lx) lookup reveals NULL", xevent->xany.window); } /* Check for filters for this window */ { GdkFilterReturn result; result = gdk_event_apply_filters (xevent, event, window_private ?window_private->filters :gdk_default_filters); if (result != GDK_FILTER_CONTINUE) { return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE; } } /* We do a "manual" conversion of the XEvent to a * GdkEvent. The structures are mostly the same so * the conversion is fairly straightforward. We also * optionally print debugging info regarding events * received. */ /* Addendum: * During drag & drop you get events where the pointer is * in other windows. Need to just do finer-grained checking */ switch (xevent->type) { case KeyPress: /* Lookup the string corresponding to the given keysym. */ #ifdef USE_XIM if (buf_len == 0) { buf_len = 128; buf = g_new (gchar, buf_len); } keysym = GDK_VoidSymbol; if (xim_using == TRUE && xim_ic) { Status status; /* Clear keyval. Depending on status, may not be set */ charcount = XmbLookupString(xim_ic->xic, &xevent->xkey, buf, buf_len-1, &keysym, &status); if (status == XBufferOverflow) { /* retry */ /* alloc adequate size of buffer */ GDK_NOTE (XIM, g_message("XIM: overflow (required %i)", charcount)); while (buf_len <= charcount) buf_len *= 2; buf = (gchar *) g_realloc (buf, buf_len); charcount = XmbLookupString (xim_ic->xic, &xevent->xkey, buf, buf_len-1, &keysym, &status); } if (status == XLookupNone) { return_val = FALSE; break; } } else charcount = XLookupString (&xevent->xkey, buf, buf_len, &keysym, &compose); #else charcount = XLookupString (&xevent->xkey, buf, 16, &keysym, &compose); #endif event->key.keyval = keysym; if (charcount > 0 && buf[charcount-1] == '\0') charcount --; else buf[charcount] = '\0'; /* Print debugging info. */ #ifdef G_ENABLE_DEBUG if (gdk_debug_flags & GDK_DEBUG_EVENTS) { g_message ("key press:\twindow: %ld key: %12s %d", xevent->xkey.window - base_id, event->key.keyval ? XKeysymToString (event->key.keyval) : "(none)", event->key.keyval); if (charcount > 0) g_message ("\t\tlength: %4d string: \"%s\"", charcount, buf); } #endif /* G_ENABLE_DEBUG */ event->key.type = GDK_KEY_PRESS; event->key.window = window; event->key.time = xevent->xkey.time; event->key.state = (GdkModifierType) xevent->xkey.state; event->key.string = g_strdup (buf); event->key.length = charcount; return_val = window_private && !window_private->destroyed; if (!return_val) g_free (event->key.string); break; case KeyRelease: /* Lookup the string corresponding to the given keysym. */ keysym = GDK_VoidSymbol; charcount = XLookupString (&xevent->xkey, buf, 16, &keysym, &compose); event->key.keyval = keysym; /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("key release:\t\twindow: %ld key: %12s %d", xevent->xkey.window - base_id, XKeysymToString (event->key.keyval), event->key.keyval)); event->key.type = GDK_KEY_RELEASE; event->key.window = window; event->key.time = xevent->xkey.time; event->key.state = (GdkModifierType) xevent->xkey.state; event->key.length = 0; event->key.string = NULL; return_val = window_private && !window_private->destroyed; break; case ButtonPress: /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("button press[%d]:\t\twindow: %ld x,y: %d %d button: %d", window_private?window_private->dnd_drag_enabled:0, xevent->xbutton.window - base_id, xevent->xbutton.x, xevent->xbutton.y, xevent->xbutton.button)); if (window_private && (window_private->extension_events != 0) && gdk_input_ignore_core) break; event->button.type = GDK_BUTTON_PRESS; event->button.window = window; event->button.time = xevent->xbutton.time; event->button.x = xevent->xbutton.x; event->button.y = xevent->xbutton.y; event->button.x_root = (gfloat)xevent->xbutton.x_root; event->button.y_root = (gfloat)xevent->xbutton.y_root; event->button.pressure = 0.5; event->button.xtilt = 0; event->button.ytilt = 0; event->button.state = (GdkModifierType) xevent->xbutton.state; event->button.button = xevent->xbutton.button; event->button.source = GDK_SOURCE_MOUSE; event->button.deviceid = GDK_CORE_POINTER; if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) && (event->button.window == button_window[1]) && (event->button.button == button_number[1])) { gdk_synthesize_click (event, 3); button_click_time[1] = 0; button_click_time[0] = 0; button_window[1] = NULL; button_window[0] = 0; button_number[1] = -1; button_number[0] = -1; } else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) && (event->button.window == button_window[0]) && (event->button.button == button_number[0])) { gdk_synthesize_click (event, 2); button_click_time[1] = button_click_time[0]; button_click_time[0] = event->button.time; button_window[1] = button_window[0]; button_window[0] = event->button.window; button_number[1] = button_number[0]; button_number[0] = event->button.button; } else { button_click_time[1] = 0; button_click_time[0] = event->button.time; button_window[1] = NULL; button_window[0] = event->button.window; button_number[1] = -1; button_number[0] = event->button.button; } if(window_private && window_private->dnd_drag_enabled && !gdk_dnd.drag_perhaps && event->button.button == 1 && !gdk_dnd.drag_really) { gdk_dnd.drag_perhaps = 1; gdk_dnd.dnd_drag_start.x = xevent->xbutton.x_root; gdk_dnd.dnd_drag_start.y = xevent->xbutton.y_root; gdk_dnd.real_sw = window_private; if(gdk_dnd.drag_startwindows) { g_free(gdk_dnd.drag_startwindows); gdk_dnd.drag_startwindows = NULL; } gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0; gdk_dnd.dnd_grabbed = FALSE; { /* Set motion mask for first DnD'd window, since it will be the one that is actually dragged */ XWindowAttributes dnd_winattr; XSetWindowAttributes dnd_setwinattr; /* We need to get motion events while the button is down, so we can know whether to really start dragging or not... */ XGetWindowAttributes(gdk_display, (Window)window_private->xwindow, &dnd_winattr); window_private->dnd_drag_savedeventmask = dnd_winattr.your_event_mask; dnd_setwinattr.event_mask = window_private->dnd_drag_eventmask = ButtonMotionMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | ExposureMask; XChangeWindowAttributes(gdk_display, window_private->xwindow, CWEventMask, &dnd_setwinattr); } } return_val = window_private && !window_private->destroyed; break; case ButtonRelease: /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("button release[%d]:\twindow: %ld x,y: %d %d button: %d", window_private?window_private->dnd_drag_enabled:0, xevent->xbutton.window - base_id, xevent->xbutton.x, xevent->xbutton.y, xevent->xbutton.button)); if (window_private && (window_private->extension_events != 0) && gdk_input_ignore_core) break; event->button.type = GDK_BUTTON_RELEASE; event->button.window = window; event->button.time = xevent->xbutton.time; event->button.x = xevent->xbutton.x; event->button.y = xevent->xbutton.y; event->button.x_root = (gfloat)xevent->xbutton.x_root; event->button.y_root = (gfloat)xevent->xbutton.y_root; event->button.pressure = 0.5; event->button.xtilt = 0; event->button.ytilt = 0; event->button.state = (GdkModifierType) xevent->xbutton.state; event->button.button = xevent->xbutton.button; event->button.source = GDK_SOURCE_MOUSE; event->button.deviceid = GDK_CORE_POINTER; gdk_dnd.last_drop_time = xevent->xbutton.time; if(gdk_dnd.drag_perhaps) { { XSetWindowAttributes attrs; /* Reset event mask to pre-drag value, assuming event_mask doesn't change during drag */ attrs.event_mask = gdk_dnd.real_sw->dnd_drag_savedeventmask; XChangeWindowAttributes(gdk_display, gdk_dnd.real_sw->xwindow, CWEventMask, &attrs); } if (gdk_dnd.dnd_grabbed) { gdk_dnd_display_drag_cursor(-2, -2, FALSE, TRUE); XUngrabPointer(gdk_display, CurrentTime); gdk_dnd.dnd_grabbed = FALSE; } if(gdk_dnd.drag_really) { GdkPoint foo; foo.x = xevent->xbutton.x_root; foo.y = xevent->xbutton.y_root; if(gdk_dnd.dnd_drag_target != None) gdk_dnd_drag_end(gdk_dnd.dnd_drag_target, foo); gdk_dnd.drag_really = 0; gdk_dnd.drag_numwindows = 0; if(gdk_dnd.drag_startwindows) { g_free(gdk_dnd.drag_startwindows); gdk_dnd.drag_startwindows = NULL; } gdk_dnd.real_sw = NULL; } gdk_dnd.drag_perhaps = 0; gdk_dnd.dnd_drag_start.x = gdk_dnd.dnd_drag_start.y = 0; gdk_dnd.dnd_drag_dropzone.x = gdk_dnd.dnd_drag_dropzone.y = 0; gdk_dnd.dnd_drag_dropzone.width = gdk_dnd.dnd_drag_dropzone.height = 0; gdk_dnd.dnd_drag_curwin = None; return_val = window_private?TRUE:FALSE; } else return_val = window_private && !window_private->destroyed; break; case MotionNotify: /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s d:%d r%d", xevent->xmotion.window - base_id, xevent->xmotion.x, xevent->xmotion.y, (xevent->xmotion.is_hint) ? "true" : "false", gdk_dnd.drag_perhaps, gdk_dnd.drag_really)); if (window_private && (window_private->extension_events != 0) && gdk_input_ignore_core) break; event->motion.type = GDK_MOTION_NOTIFY; event->motion.window = window; event->motion.time = xevent->xmotion.time; event->motion.x = xevent->xmotion.x; event->motion.y = xevent->xmotion.y; event->motion.x_root = (gfloat)xevent->xmotion.x_root; event->motion.y_root = (gfloat)xevent->xmotion.y_root; event->motion.pressure = 0.5; event->motion.xtilt = 0; event->motion.ytilt = 0; event->motion.state = (GdkModifierType) xevent->xmotion.state; event->motion.is_hint = xevent->xmotion.is_hint; event->motion.source = GDK_SOURCE_MOUSE; event->motion.deviceid = GDK_CORE_POINTER; #define IS_IN_ZONE(cx, cy) (cx >= gdk_dnd.dnd_drag_dropzone.x \ && cy >= gdk_dnd.dnd_drag_dropzone.y \ && cx < (gdk_dnd.dnd_drag_dropzone.x + gdk_dnd.dnd_drag_dropzone.width) \ && cy < (gdk_dnd.dnd_drag_dropzone.y + gdk_dnd.dnd_drag_dropzone.height)) if(gdk_dnd.drag_perhaps && gdk_dnd.drag_really /* && event->motion.is_hint */ /* HINTME */) { /* First, we have to find what window the motion was in... */ /* XXX there has to be a better way to do this, perhaps with XTranslateCoordinates or XQueryTree - I don't know how, and this sort of works */ static Window lastwin = None, curwin = None; #if 0 Window twin; #endif Window childwin = gdk_root_window; int x, y, ox, oy; /* Interlude - display cursor for the drag ASAP */ gdk_dnd_display_drag_cursor(xevent->xmotion.x_root, xevent->xmotion.y_root, gdk_dnd.dnd_drag_target?TRUE:FALSE, FALSE); lastwin = curwin; curwin = gdk_root_window; ox = x = xevent->xmotion.x_root; oy = y = xevent->xmotion.y_root; #if 1 curwin = gdk_window_xid_at_coords(xevent->xmotion.x_root, xevent->xmotion.y_root, gdk_dnd.c->xids,TRUE); XTranslateCoordinates(gdk_display, gdk_root_window, curwin, x, y, &x, &y, &childwin); #else while(childwin != None) { ox = x; oy = y; curwin = childwin; XTranslateCoordinates(gdk_display, curwin, curwin, x, y, &x, &y, &childwin); if(childwin != None) { XTranslateCoordinates(gdk_display, curwin, childwin, x, y, &x, &y, &twin); } } #endif GDK_NOTE (DND, g_message("Drag is now in window %#lx, lastwin was %#lx, ddc = %#lx", curwin, lastwin, gdk_dnd.dnd_drag_curwin)); if(curwin != gdk_dnd.dnd_drag_curwin && curwin != lastwin) { /* We have left one window and entered another (do leave & enter bits) */ if(gdk_dnd.dnd_drag_curwin != None) gdk_dnd_drag_leave(gdk_dnd.dnd_drag_curwin); gdk_dnd.dnd_drag_curwin = curwin; gdk_dnd_drag_enter(gdk_dnd.dnd_drag_curwin); gdk_dnd.dnd_drag_dropzone.x = gdk_dnd.dnd_drag_dropzone.y = 0; gdk_dnd.dnd_drag_dropzone.width = gdk_dnd.dnd_drag_dropzone.height = 0; gdk_dnd.dnd_drag_target = None; GDK_NOTE (DND, g_message("curwin = %#lx, lastwin = %#lx, dnd_drag_curwin = %#lx", curwin, lastwin, gdk_dnd.dnd_drag_curwin)); gdk_dnd_display_drag_cursor(xevent->xmotion.x_root, xevent->xmotion.y_root, FALSE, TRUE); } else if(gdk_dnd.dnd_drag_dropzone.width > 0 && gdk_dnd.dnd_drag_dropzone.height > 0 && curwin == gdk_dnd.dnd_drag_curwin) { /* Handle all that dropzone stuff - thanks John ;-) */ if (gdk_dnd.dnd_drag_target != None) { gboolean in_zone = IS_IN_ZONE(xevent->xmotion.x_root, xevent->xmotion.y_root); gboolean old_in_zone = IS_IN_ZONE(gdk_dnd.dnd_drag_oldpos.x, gdk_dnd.dnd_drag_oldpos.y); if (!in_zone && old_in_zone) { /* We were in the drop zone and moved out */ gdk_dnd.dnd_drag_target = None; gdk_dnd_drag_leave(curwin); gdk_dnd_display_drag_cursor(xevent->xmotion.x_root, xevent->xmotion.y_root, FALSE, TRUE); } else if (!in_zone && !old_in_zone) { /* We were outside drop zone but in the window - have to send enter events */ gdk_dnd_drag_enter(curwin); gdk_dnd.dnd_drag_curwin = curwin; gdk_dnd.dnd_drag_dropzone.x = gdk_dnd.dnd_drag_dropzone.y = 0; gdk_dnd.dnd_drag_target = None; } } } /* else dnd_drag_curwin = None; */ return_val = FALSE; } else return_val = window_private && !window_private->destroyed; break; case EnterNotify: /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("enter notify:\t\twindow: %ld detail: %d subwin: %ld", xevent->xcrossing.window - base_id, xevent->xcrossing.detail, xevent->xcrossing.subwindow - base_id)); /* Tell XInput stuff about it if appropriate */ if (window_private && (window_private->extension_events != 0) && gdk_input_vtable.enter_event) gdk_input_vtable.enter_event (&xevent->xcrossing, window); event->crossing.type = GDK_ENTER_NOTIFY; event->crossing.window = window; /* If the subwindow field of the XEvent is non-NULL, then * lookup the corresponding GdkWindow. */ if (xevent->xcrossing.subwindow != None) event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow); else event->crossing.subwindow = NULL; event->crossing.time = xevent->xcrossing.time; event->crossing.x = xevent->xcrossing.x; event->crossing.y = xevent->xcrossing.y; event->crossing.x_root = xevent->xcrossing.x_root; event->crossing.y_root = xevent->xcrossing.y_root; /* Translate the crossing mode into Gdk terms. */ switch (xevent->xcrossing.mode) { case NotifyNormal: event->crossing.mode = GDK_CROSSING_NORMAL; break; case NotifyGrab: event->crossing.mode = GDK_CROSSING_GRAB; break; case NotifyUngrab: event->crossing.mode = GDK_CROSSING_UNGRAB; break; }; /* Translate the crossing detail into Gdk terms. */ switch (xevent->xcrossing.detail) { case NotifyInferior: event->crossing.detail = GDK_NOTIFY_INFERIOR; break; case NotifyAncestor: event->crossing.detail = GDK_NOTIFY_ANCESTOR; break; case NotifyVirtual: event->crossing.detail = GDK_NOTIFY_VIRTUAL; break; case NotifyNonlinear: event->crossing.detail = GDK_NOTIFY_NONLINEAR; break; case NotifyNonlinearVirtual: event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL; break; default: event->crossing.detail = GDK_NOTIFY_UNKNOWN; break; } event->crossing.focus = xevent->xcrossing.focus; event->crossing.state = xevent->xcrossing.state; #ifdef G_ENABLE_DEBUG if ((gdk_debug_flags & GDK_DEBUG_DND) & gdk_dnd.drag_perhaps) { g_message("We may[%d] have a drag into %#lx = %#lx", gdk_dnd.drag_really, xevent->xcrossing.window, gdk_dnd.real_sw->xwindow); } #endif /* G_ENABLE_DEBUG */ if (gdk_dnd.drag_perhaps && gdk_dnd.drag_really && (xevent->xcrossing.window == gdk_dnd.real_sw->xwindow)) { #if 0 gdk_dnd.drag_really = 0; GDK_NOTE (DND, g_message("Ungrabbed")); gdk_dnd.drag_numwindows = 0; g_free(gdk_dnd.drag_startwindows); gdk_dnd.drag_startwindows = NULL; /* We don't want to ungrab the pointer here, or we'll * start getting spurious enter/leave events */ #endif #if 0 XChangeActivePointerGrab (gdk_display, 0, None, CurrentTime); #endif } return_val = window_private && !window_private->destroyed; break; case LeaveNotify: /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("leave notify:\t\twindow: %ld detail: %d subwin: %ld", xevent->xcrossing.window - base_id, xevent->xcrossing.detail, xevent->xcrossing.subwindow - base_id)); event->crossing.type = GDK_LEAVE_NOTIFY; event->crossing.window = window; /* If the subwindow field of the XEvent is non-NULL, then * lookup the corresponding GdkWindow. */ if (xevent->xcrossing.subwindow != None) event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow); else event->crossing.subwindow = NULL; event->crossing.time = xevent->xcrossing.time; event->crossing.x = xevent->xcrossing.x; event->crossing.y = xevent->xcrossing.y; event->crossing.x_root = xevent->xcrossing.x_root; event->crossing.y_root = xevent->xcrossing.y_root; /* Translate the crossing mode into Gdk terms. */ switch (xevent->xcrossing.mode) { case NotifyNormal: event->crossing.mode = GDK_CROSSING_NORMAL; break; case NotifyGrab: event->crossing.mode = GDK_CROSSING_GRAB; break; case NotifyUngrab: event->crossing.mode = GDK_CROSSING_UNGRAB; break; }; /* Translate the crossing detail into Gdk terms. */ switch (xevent->xcrossing.detail) { case NotifyInferior: event->crossing.detail = GDK_NOTIFY_INFERIOR; break; case NotifyAncestor: event->crossing.detail = GDK_NOTIFY_ANCESTOR; break; case NotifyVirtual: event->crossing.detail = GDK_NOTIFY_VIRTUAL; break; case NotifyNonlinear: event->crossing.detail = GDK_NOTIFY_NONLINEAR; break; case NotifyNonlinearVirtual: event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL; break; default: event->crossing.detail = GDK_NOTIFY_UNKNOWN; break; } event->crossing.focus = xevent->xcrossing.focus; event->crossing.state = xevent->xcrossing.state; #ifdef G_ENABLE_DEBUG if ((gdk_debug_flags & GDK_DEBUG_DND) & gdk_dnd.drag_perhaps) { g_message("We may[%d] have a drag out of %#lx = %#lx", gdk_dnd.drag_really, xevent->xcrossing.window, gdk_dnd.real_sw->xwindow); } #endif /* G_ENABLE_DEBUG */ if (gdk_dnd.drag_perhaps && !gdk_dnd.drag_really && (xevent->xcrossing.window == gdk_dnd.real_sw->xwindow)) { gboolean xgpret; gdk_dnd_drag_addwindow((GdkWindow *) gdk_dnd.real_sw); gdk_dnd_drag_begin((GdkWindow *) gdk_dnd.real_sw); xgpret = XGrabPointer(gdk_display, gdk_dnd.real_sw->xwindow, False, ButtonMotionMask | PointerMotionMask | /* PointerMotionHintMask | */ /* HINTME */ ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); #ifdef G_ENABLE_DEBUG GDK_NOTE(DND, g_message("xgpret = %d", xgpret)); #endif gdk_dnd.dnd_grabbed = TRUE; gdk_dnd.drag_really = 1; gdk_dnd_display_drag_cursor(xevent->xmotion.x_root, xevent->xmotion.y_root, FALSE, TRUE); } return_val = window_private && !window_private->destroyed; break; case FocusIn: case FocusOut: /* We only care about focus events that indicate that _this_ * window (not a ancestor or child) got or lost the focus */ switch (xevent->xfocus.detail) { case NotifyAncestor: case NotifyInferior: case NotifyNonlinear: /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("focus %s:\t\twindow: %ld", (xevent->xany.type == FocusIn) ? "in" : "out", xevent->xfocus.window - base_id)); event->focus_change.type = GDK_FOCUS_CHANGE; event->focus_change.window = window; event->focus_change.in = (xevent->xany.type == FocusIn); return_val = window_private && !window_private->destroyed; break; default: ; } break; case KeymapNotify: /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("keymap notify")); /* Not currently handled */ break; case Expose: /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("expose:\t\twindow: %ld %d x,y: %d %d w,h: %d %d", xevent->xexpose.window - base_id, xevent->xexpose.count, xevent->xexpose.x, xevent->xexpose.y, xevent->xexpose.width, xevent->xexpose.height)); event->expose.type = GDK_EXPOSE; event->expose.window = window; event->expose.area.x = xevent->xexpose.x; event->expose.area.y = xevent->xexpose.y; event->expose.area.width = xevent->xexpose.width; event->expose.area.height = xevent->xexpose.height; event->expose.count = xevent->xexpose.count; return_val = window_private && !window_private->destroyed; break; case GraphicsExpose: /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("graphics expose:\tdrawable: %ld", xevent->xgraphicsexpose.drawable - base_id)); event->expose.type = GDK_EXPOSE; event->expose.window = window; event->expose.area.x = xevent->xgraphicsexpose.x; event->expose.area.y = xevent->xgraphicsexpose.y; event->expose.area.width = xevent->xgraphicsexpose.width; event->expose.area.height = xevent->xgraphicsexpose.height; event->expose.count = xevent->xexpose.count; return_val = window_private && !window_private->destroyed; break; case NoExpose: /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("no expose:\t\tdrawable: %ld", xevent->xnoexpose.drawable - base_id)); event->no_expose.type = GDK_NO_EXPOSE; event->no_expose.window = window; return_val = window_private && !window_private->destroyed; break; case VisibilityNotify: /* Print debugging info. */ #ifdef G_ENABLE_DEBUG if (gdk_debug_flags & GDK_DEBUG_EVENTS) switch (xevent->xvisibility.state) { case VisibilityFullyObscured: g_message ("visibility notify:\twindow: %ld none", xevent->xvisibility.window - base_id); break; case VisibilityPartiallyObscured: g_message ("visibility notify:\twindow: %ld partial", xevent->xvisibility.window - base_id); break; case VisibilityUnobscured: g_message ("visibility notify:\twindow: %ld full", xevent->xvisibility.window - base_id); break; } #endif /* G_ENABLE_DEBUG */ event->visibility.type = GDK_VISIBILITY_NOTIFY; event->visibility.window = window; switch (xevent->xvisibility.state) { case VisibilityFullyObscured: event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED; break; case VisibilityPartiallyObscured: event->visibility.state = GDK_VISIBILITY_PARTIAL; break; case VisibilityUnobscured: event->visibility.state = GDK_VISIBILITY_UNOBSCURED; break; } return_val = window_private && !window_private->destroyed; break; case CreateNotify: /* Not currently handled */ break; case DestroyNotify: /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("destroy notify:\twindow: %ld", xevent->xdestroywindow.window - base_id)); event->any.type = GDK_DESTROY; event->any.window = window; return_val = window_private && !window_private->destroyed; if(window && window_private->xwindow != GDK_ROOT_WINDOW()) gdk_window_destroy_notify (window); break; case UnmapNotify: /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("unmap notify:\t\twindow: %ld", xevent->xmap.window - base_id)); event->any.type = GDK_UNMAP; event->any.window = window; if (xgrab_window == window_private) xgrab_window = NULL; return_val = window_private && !window_private->destroyed; break; case MapNotify: /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("map notify:\t\twindow: %ld", xevent->xmap.window - base_id)); event->any.type = GDK_MAP; event->any.window = window; return_val = window_private && !window_private->destroyed; break; case ReparentNotify: /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("reparent notify:\twindow: %ld", xevent->xreparent.window - base_id)); /* Not currently handled */ break; case ConfigureNotify: /* Print debugging info. */ while ((XPending (gdk_display) > 0) && XCheckTypedWindowEvent(gdk_display, xevent->xany.window, ConfigureNotify, xevent)) { GdkFilterReturn result; GDK_NOTE (EVENTS, g_message ("configure notify discarded:\twindow: %ld", xevent->xconfigure.window - base_id)); result = gdk_event_apply_filters (xevent, event, window_private ?window_private->filters :gdk_default_filters); /* If the result is GDK_FILTER_REMOVE, there will be * trouble, but anybody who filtering the Configure events * better know what they are doing */ if (result != GDK_FILTER_CONTINUE) { return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE; } /*XSync (gdk_display, 0);*/ } GDK_NOTE (EVENTS, g_message ("configure notify:\twindow: %ld x,y: %d %d w,h: %d %d b-w: %d above: %ld ovr: %d", xevent->xconfigure.window - base_id, xevent->xconfigure.x, xevent->xconfigure.y, xevent->xconfigure.width, xevent->xconfigure.height, xevent->xconfigure.border_width, xevent->xconfigure.above - base_id, xevent->xconfigure.override_redirect)); if (window_private) { if ((window_private->extension_events != 0) && gdk_input_vtable.configure_event) gdk_input_vtable.configure_event (&xevent->xconfigure, window); if (window_private->window_type != GDK_WINDOW_CHILD) { event->configure.type = GDK_CONFIGURE; event->configure.window = window; event->configure.width = xevent->xconfigure.width; event->configure.height = xevent->xconfigure.height; if (!xevent->xconfigure.x && !xevent->xconfigure.y && !window_private->destroyed) { gint tx = 0; gint ty = 0; Window child_window = 0; if (!XTranslateCoordinates (window_private->xdisplay, window_private->xwindow, gdk_root_window, 0, 0, &tx, &ty, &child_window)) g_warning ("GdkWindow %ld doesn't share root windows display?", window_private->xwindow - base_id); event->configure.x = tx; event->configure.y = ty; } else { event->configure.x = xevent->xconfigure.x; event->configure.y = xevent->xconfigure.y; } window_private->x = event->configure.x; window_private->y = event->configure.y; window_private->width = xevent->xconfigure.width; window_private->height = xevent->xconfigure.height; if (window_private->resize_count > 1) window_private->resize_count -= 1; return_val = !window_private->destroyed; } } break; case PropertyNotify: /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("property notify:\twindow: %ld", xevent->xproperty.window - base_id)); event->property.type = GDK_PROPERTY_NOTIFY; event->property.window = window; event->property.atom = xevent->xproperty.atom; event->property.time = xevent->xproperty.time; event->property.state = xevent->xproperty.state; return_val = window_private && !window_private->destroyed; break; case SelectionClear: GDK_NOTE (EVENTS, g_message ("selection clear:\twindow: %ld", xevent->xproperty.window - base_id)); event->selection.type = GDK_SELECTION_CLEAR; event->selection.window = window; event->selection.selection = xevent->xselectionclear.selection; event->selection.time = xevent->xselectionclear.time; return_val = window_private && !window_private->destroyed; break; case SelectionRequest: GDK_NOTE (EVENTS, g_message ("selection request:\twindow: %ld", xevent->xproperty.window - base_id)); event->selection.type = GDK_SELECTION_REQUEST; event->selection.window = window; event->selection.selection = xevent->xselectionrequest.selection; event->selection.target = xevent->xselectionrequest.target; event->selection.property = xevent->xselectionrequest.property; event->selection.requestor = xevent->xselectionrequest.requestor; event->selection.time = xevent->xselectionrequest.time; return_val = window_private && !window_private->destroyed; break; case SelectionNotify: GDK_NOTE (EVENTS, g_message ("selection notify:\twindow: %ld", xevent->xproperty.window - base_id)); event->selection.type = GDK_SELECTION_NOTIFY; event->selection.window = window; event->selection.selection = xevent->xselection.selection; event->selection.target = xevent->xselection.target; event->selection.property = xevent->xselection.property; event->selection.time = xevent->xselection.time; return_val = window_private && !window_private->destroyed; break; case ColormapNotify: /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("colormap notify:\twindow: %ld", xevent->xcolormap.window - base_id)); /* Not currently handled */ break; case ClientMessage: /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("client message:\twindow: %ld", xevent->xclient.window - base_id)); /* Client messages are the means of the window manager * communicating with a program. We'll first check to * see if this is really the window manager talking * to us. */ if (xevent->xclient.message_type == gdk_wm_protocols) { if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window) { /* The delete window request specifies a window * to delete. We don't actually destroy the * window because "it is only a request". (The * window might contain vital data that the * program does not want destroyed). Instead * the event is passed along to the program, * which should then destroy the window. */ /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("delete window:\t\twindow: %ld", xevent->xclient.window - base_id)); event->any.type = GDK_DELETE; event->any.window = window; return_val = window_private && !window_private->destroyed; } else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus) { } } else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter) { Atom reptype = 0; event->dropenter.u.allflags = xevent->xclient.data.l[1]; GDK_NOTE (DND, g_message ("GDK_DROP_ENTER [%d][%d]", window_private->dnd_drop_enabled, event->dropenter.u.flags.sendreply)); return_val = FALSE; /* Now figure out if we really want this drop... * If someone is trying funky clipboard stuff, ignore */ if (window_private && window_private->dnd_drop_enabled && event->dropenter.u.flags.sendreply && (reptype = gdk_dnd_check_types (window, xevent))) { XEvent replyev; replyev.xclient.type = ClientMessage; replyev.xclient.window = xevent->xclient.data.l[0]; replyev.xclient.format = 32; replyev.xclient.message_type = gdk_dnd.gdk_XdeRequest; replyev.xclient.data.l[0] = window_private->xwindow; event->dragrequest.u.allflags = 0; event->dragrequest.u.flags.protocol_version = DND_PROTOCOL_VERSION; event->dragrequest.u.flags.willaccept = 1; event->dragrequest.u.flags.delete_data = (window_private->dnd_drop_destructive_op) ? 1 : 0; replyev.xclient.data.l[1] = event->dragrequest.u.allflags; replyev.xclient.data.l[2] = replyev.xclient.data.l[3] = 0; replyev.xclient.data.l[4] = reptype; if (!gdk_send_xevent (replyev.xclient.window, False, NoEventMask, &replyev)) GDK_NOTE (DND, g_message("Sending XdeRequest to %#lx failed", replyev.xclient.window)); event->any.type = GDK_DROP_ENTER; event->any.window = window; event->dropenter.requestor = replyev.xclient.window; event->dropenter.u.allflags = xevent->xclient.data.l[1]; GDK_NOTE (DND, g_message("We sent a GDK_DROP_ENTER on to Gtk")); return_val = TRUE; } } else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeLeave) { #ifdef G_ENABLE_DEBUG if (gdk_debug_flags & (GDK_DEBUG_EVENTS | GDK_DEBUG_DND)) g_message ("GDK_DROP_LEAVE"); #endif if (window_private && window_private->dnd_drop_enabled) { event->dropleave.type = GDK_DROP_LEAVE; event->dropleave.window = window; event->dropleave.requestor = xevent->xclient.data.l[0]; event->dropleave.u.allflags = xevent->xclient.data.l[1]; return_val = TRUE; } else return_val = FALSE; } else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeRequest) { /* * make sure to only handle requests from the window the cursor is * over */ #ifdef G_ENABLE_DEBUG if (gdk_debug_flags & (GDK_DEBUG_EVENTS | GDK_DEBUG_DND)) g_message ("GDK_DRAG_REQUEST"); #endif event->dragrequest.u.allflags = xevent->xclient.data.l[1]; return_val = FALSE; if (window && gdk_dnd.drag_really && xevent->xclient.data.l[0] == gdk_dnd.dnd_drag_curwin && event->dragrequest.u.flags.sendreply == 0) { /* Got request - do we need to ask user? */ if (!event->dragrequest.u.flags.willaccept && event->dragrequest.u.flags.senddata) { /* Yes we do :) */ event->dragrequest.type = GDK_DRAG_REQUEST; event->dragrequest.window = window; event->dragrequest.requestor = xevent->xclient.data.l[0]; event->dragrequest.isdrop = 0; event->dragrequest.drop_coords.x = event->dragrequest.drop_coords.y = 0; return_val = TRUE; } else if (event->dragrequest.u.flags.willaccept) { window_private->dnd_drag_destructive_op = event->dragrequest.u.flags.delete_data; window_private->dnd_drag_accepted = 1; window_private->dnd_drag_data_type = xevent->xclient.data.l[4]; gdk_dnd.dnd_drag_target = gdk_dnd.dnd_drag_curwin; gdk_dnd_display_drag_cursor(-1, -1, TRUE, TRUE); } gdk_dnd.dnd_drag_dropzone.x = xevent->xclient.data.l[2] & 65535; gdk_dnd.dnd_drag_dropzone.y = (xevent->xclient.data.l[2] >> 16) & 65535; gdk_dnd.dnd_drag_dropzone.width = xevent->xclient.data.l[3] & 65535; gdk_dnd.dnd_drag_dropzone.height = (xevent->xclient.data.l[3] >> 16) & 65535; } } else if(xevent->xclient.message_type == gdk_dnd.gdk_XdeDataAvailable) { gint tmp_int; Atom tmp_atom; gulong tmp_long; guchar *tmp_charptr; #ifdef G_ENABLE_DEBUG if (gdk_debug_flags & (GDK_DEBUG_EVENTS | GDK_DEBUG_DND)) g_message("GDK_DROP_DATA_AVAIL"); #endif event->dropdataavailable.u.allflags = xevent->xclient.data.l[1]; event->dropdataavailable.timestamp = xevent->xclient.data.l[4]; event->dropdataavailable.coords.x = xevent->xclient.data.l[3] & 0xffff; event->dropdataavailable.coords.y = (xevent->xclient.data.l[3] >> 16) & 0xffff; if(window /* No preview of data ATM */ && event->dropdataavailable.u.flags.isdrop) { event->dropdataavailable.type = GDK_DROP_DATA_AVAIL; event->dropdataavailable.window = window; event->dropdataavailable.requestor = xevent->xclient.data.l[0]; event->dropdataavailable.data_type = gdk_atom_name(xevent->xclient.data.l[2]); if(XGetWindowProperty (gdk_display, event->dropdataavailable.requestor, xevent->xclient.data.l[2], 0, LONG_MAX - 1, False, XA_PRIMARY, &tmp_atom, &tmp_int, &event->dropdataavailable.data_numbytes, &tmp_long, &tmp_charptr) != Success) { g_warning("XGetWindowProperty on %#x may have failed\n", event->dropdataavailable.requestor); event->dropdataavailable.data = NULL; } else { GDK_NOTE (DND, g_message("XGetWindowProperty got us %ld bytes", event->dropdataavailable.data_numbytes)); event->dropdataavailable.data = g_malloc (event->dropdataavailable.data_numbytes); memcpy (event->dropdataavailable.data, tmp_charptr, event->dropdataavailable.data_numbytes); XFree(tmp_charptr); return_val = TRUE; } return_val = TRUE; } } else { /* Send unknown ClientMessage's on to Gtk for it to use */ event->client.type = GDK_CLIENT_EVENT; event->client.window = window; event->client.message_type = xevent->xclient.message_type; event->client.data_format = xevent->xclient.format; memcpy(&event->client.data, &xevent->xclient.data, sizeof(event->client.data)); if(window) return_val = TRUE; else return_val = FALSE; } if(window_private) return_val = return_val && !window_private->destroyed; break; case MappingNotify: /* Print debugging info. */ GDK_NOTE (EVENTS, g_message ("mapping notify")); /* Let XLib know that there is a new keyboard mapping. */ XRefreshKeyboardMapping (&xevent->xmapping); break; default: /* something else - (e.g., a Xinput event) */ if (window_private && (window_private->extension_events != 0) && gdk_input_vtable.other_event) return_val = gdk_input_vtable.other_event(event, xevent, window); else return_val = FALSE; return_val = return_val && !window_private->destroyed; break; } if (return_val) { if (event->any.window) gdk_window_ref (event->any.window); if (((event->any.type == GDK_ENTER_NOTIFY) || (event->any.type == GDK_LEAVE_NOTIFY)) && (event->crossing.subwindow != NULL)) gdk_window_ref (event->crossing.subwindow); } else { /* Mark this event as having no resources to be freed */ event->any.window = NULL; event->any.type = GDK_NOTHING; } if (window) gdk_window_unref (window); return return_val; } #if 0 static Bool gdk_event_get_type (Display *display, XEvent *xevent, XPointer arg) { GdkEvent event; GdkPredicate *pred; if (gdk_event_translate (&event, xevent)) { pred = (GdkPredicate*) arg; return (* pred->func) (&event, pred->data); } return FALSE; } #endif static void gdk_synthesize_click (GdkEvent *event, gint nclicks) { GdkEvent temp_event; g_return_if_fail (event != NULL); temp_event = *event; temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS; gdk_event_put (&temp_event); } /* *-------------------------------------------------------------- * gdk_exit_func * * This is the "atexit" function that makes sure the * library gets a chance to cleanup. * * Arguments: * * Results: * * Side effects: * The library is un-initialized and the program exits. * *-------------------------------------------------------------- */ static void gdk_exit_func (void) { static gboolean in_gdk_exit_func = FALSE; /* This is to avoid an infinite loop if a program segfaults in an atexit() handler (and yes, it does happen, especially if a program has trounced over memory too badly for even g_message to work) */ if (in_gdk_exit_func == TRUE) return; in_gdk_exit_func = TRUE; if (gdk_initialized) { #ifdef USE_XIM /* cleanup IC */ gdk_ic_cleanup (); /* close IM */ gdk_im_close (); #endif gdk_image_exit (); gdk_input_exit (); gdk_key_repeat_restore (); XCloseDisplay (gdk_display); gdk_initialized = 0; } } /* *-------------------------------------------------------------- * gdk_x_error * * The X error handling routine. * * Arguments: * "display" is the X display the error orignated from. * "error" is the XErrorEvent that we are handling. * * Results: * Either we were expecting some sort of error to occur, * in which case we set the "gdk_error_code" flag, or this * error was unexpected, in which case we will print an * error message and exit. (Since trying to continue will * most likely simply lead to more errors). * * Side effects: * *-------------------------------------------------------------- */ static int gdk_x_error (Display *display, XErrorEvent *error) { char buf[64]; if (gdk_error_warnings) { XGetErrorText (display, error->error_code, buf, 63); g_error ("%s\n serial %ld error_code %d request_code %d minor_code %d\n", buf, error->serial, error->error_code, error->request_code, error->minor_code); } gdk_error_code = -1; return 0; } /* *-------------------------------------------------------------- * gdk_x_io_error * * The X I/O error handling routine. * * Arguments: * "display" is the X display the error orignated from. * * Results: * An X I/O error basically means we lost our connection * to the X server. There is not much we can do to * continue, so simply print an error message and exit. * * Side effects: * *-------------------------------------------------------------- */ static int gdk_x_io_error (Display *display) { g_error ("an x io error occurred"); return 0; } /* *-------------------------------------------------------------- * gdk_signal * * The signal handler. * * Arguments: * "sig_num" is the number of the signal we received. * * Results: * The signals we catch are all fatal. So we simply build * up a nice little error message and print it and exit. * If in the process of doing so another signal is received * we notice that we are already exiting and simply kill * our process. * * Side effects: * *-------------------------------------------------------------- */ static RETSIGTYPE gdk_signal (int sig_num) { static int caught_fatal_sig = 0; char *sig; if (caught_fatal_sig) kill (getpid (), sig_num); caught_fatal_sig = 1; switch (sig_num) { case SIGHUP: sig = "sighup"; break; case SIGINT: sig = "sigint"; break; case SIGQUIT: sig = "sigquit"; break; case SIGBUS: sig = "sigbus"; break; case SIGSEGV: sig = "sigsegv"; break; case SIGPIPE: sig = "sigpipe"; break; case SIGTERM: sig = "sigterm"; break; default: sig = "unknown signal"; break; } g_message ("\n** ERROR **: %s caught", sig); #ifdef G_ENABLE_DEBUG abort (); #else /* !G_ENABLE_DEBUG */ gdk_exit (1); #endif /* !G_ENABLE_DEBUG */ } static void gdk_dnd_drag_begin (GdkWindow *initial_window) { GdkEvent tev; GDK_NOTE(DND, g_message("------- STARTING DRAG from %p", initial_window)); tev.type = GDK_DRAG_BEGIN; tev.dragbegin.window = initial_window; tev.dragbegin.u.allflags = 0; tev.dragbegin.u.flags.protocol_version = DND_PROTOCOL_VERSION; gdk_event_put (&tev); } static void gdk_dnd_drag_enter (Window dest) { XEvent sev; GdkEventDropEnter tev; int i; GdkWindowPrivate *wp; sev.xclient.type = ClientMessage; sev.xclient.format = 32; sev.xclient.message_type = gdk_dnd.gdk_XdeEnter; sev.xclient.window = dest; tev.u.allflags = 0; tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; tev.u.flags.sendreply = 1; for (i = 0; i < gdk_dnd.drag_numwindows; i++) { wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; if (wp->dnd_drag_data_numtypesavail) { sev.xclient.data.l[0] = wp->xwindow; tev.u.flags.extended_typelist = (wp->dnd_drag_data_numtypesavail > 3)?1:0; sev.xclient.data.l[1] = tev.u.allflags; sev.xclient.data.l[2] = wp->dnd_drag_data_typesavail[0]; if (wp->dnd_drag_data_numtypesavail > 1) { sev.xclient.data.l[3] = wp->dnd_drag_data_typesavail[1]; if (wp->dnd_drag_data_numtypesavail > 2) { sev.xclient.data.l[4] = wp->dnd_drag_data_typesavail[2]; } else sev.xclient.data.l[4] = None; } else sev.xclient.data.l[3] = sev.xclient.data.l[4] = None; if (!gdk_send_xevent (dest, False, StructureNotifyMask, &sev)) GDK_NOTE (DND, g_message("Sending XdeEnter to %#lx failed", dest)); } } } #ifdef USE_XIM /* The following routines duplicate functionality in Xlib to * translate from varargs to X's internal opaque XVaNestedList. * * If all vendors have stuck close to the reference implementation, * then we should hopefully be OK. */ /* This needs to match XIMArg as defined in Xlcint.h exactly */ typedef struct { gchar *name; gpointer value; } GdkImArg; /************************************************************* * gdk_im_va_count: * Counts the number of name/value pairs in the vararg list * * arguments: * * results: *************************************************************/ static guint gdk_im_va_count (va_list list) { gint count = 0; gchar *name; name = va_arg (list, gchar *); while (name) { count++; (void)va_arg (list, gpointer); name = va_arg (list, gchar *); } return count; } /************************************************************* * gdk_im_va_to_nested: * Given a varargs list and the result of gdk_im_va_count, * create a XVaNestedList. * * arguments: * * results: *************************************************************/ static XVaNestedList gdk_im_va_to_nested (va_list list, guint count) { GdkImArg *result; GdkImArg *arg; gchar *name; if (count == 0) return NULL; result = g_new (GdkImArg, count+1); arg = result; name = va_arg (list, gchar *); while (name) { arg->name = name; arg->value = va_arg (list, gpointer); arg++; name = va_arg (list, gchar *); } arg->name = NULL; return (XVaNestedList)result; } /* *-------------------------------------------------------------- * gdk_im_begin * * Begin using input method with XIM Protocol(X11R6 standard) * * Arguments: * "ic" is the "Input Context" which is created by gtk_ic_new. * The input area is specified with "window". * * Results: * The gdk's event handling routine is switched to XIM based routine. * XIM based routine uses XFilterEvent to get rid of events used by IM, * and uses XmbLookupString instead of XLookupString. * * Side effects: * *-------------------------------------------------------------- */ void gdk_im_begin (GdkIC ic, GdkWindow* window) { GdkICPrivate *private; Window xwin; g_return_if_fail (ic != NULL); g_return_if_fail (window); private = (GdkICPrivate *) ic; xim_using = TRUE; xim_ic = private; xim_window = window; if (gdk_im_ready()) { XGetICValues (private->xic, XNFocusWindow, &xwin, NULL); if (xwin != GDK_WINDOW_XWINDOW(window)) XSetICValues (private->xic, XNFocusWindow, GDK_WINDOW_XWINDOW(window), NULL); if (private != xim_ic) XSetICFocus (private->xic); } } /* *-------------------------------------------------------------- * gdk_im_end * * End using input method with XIM Protocol(X11R6 standard) * * Arguments: * * Results: * The gdk's event handling routine is switched to normal routine. * User should call this function before ic and window will be destroyed. * * Side effects: * *-------------------------------------------------------------- */ void gdk_im_end (void) { xim_using = FALSE; xim_ic = NULL; xim_window = NULL; } static GdkIM gdk_im_get (void) { return xim_im; } static GdkIMStyle gdk_im_choose_better_style (GdkIMStyle style1, GdkIMStyle style2) { GdkIMStyle s1, s2, u; if (style1 == 0) return style2; if (style2 == 0) return style1; if ((style1 & (GDK_IM_PREEDIT_MASK | GDK_IM_STATUS_MASK)) == (style2 & (GDK_IM_PREEDIT_MASK | GDK_IM_STATUS_MASK))) return style1; s1 = style1 & GDK_IM_PREEDIT_MASK; s2 = style2 & GDK_IM_PREEDIT_MASK; u = s1 | s2; if (s1 != s2) { if (u & GDK_IM_PREEDIT_CALLBACKS) return (s1 == GDK_IM_PREEDIT_CALLBACKS)? style1:style2; else if (u & GDK_IM_PREEDIT_POSITION) return (s1 == GDK_IM_PREEDIT_POSITION)? style1:style2; else if (u & GDK_IM_PREEDIT_AREA) return (s1 == GDK_IM_PREEDIT_AREA)? style1:style2; else if (u & GDK_IM_PREEDIT_NOTHING) return (s1 == GDK_IM_PREEDIT_NOTHING)? style1:style2; } else { s1 = style1 & GDK_IM_STATUS_MASK; s2 = style2 & GDK_IM_STATUS_MASK; u = s1 | s2; if ( u & GDK_IM_STATUS_CALLBACKS) return (s1 == GDK_IM_STATUS_CALLBACKS)? style1:style2; else if ( u & GDK_IM_STATUS_AREA) return (s1 == GDK_IM_STATUS_AREA)? style1:style2; else if ( u & GDK_IM_STATUS_NOTHING) return (s1 == GDK_IM_STATUS_NOTHING)? style1:style2; else if ( u & GDK_IM_STATUS_NONE) return (s1 == GDK_IM_STATUS_NONE)? style1:style2; } return 0; /* Get rid of stupid warning */ } GdkIMStyle gdk_im_decide_style (GdkIMStyle supported_style) { gint i; GdkIMStyle style, tmp; g_return_val_if_fail (xim_styles != NULL, 0); style = 0; for (i=0; icount_styles; i++) { tmp = xim_styles->supported_styles[i]; if (tmp == (tmp & supported_style & xim_best_allowed_style)) style = gdk_im_choose_better_style (style, tmp); } return style; } GdkIMStyle gdk_im_set_best_style (GdkIMStyle style) { if (style & GDK_IM_PREEDIT_MASK) { xim_best_allowed_style &= ~GDK_IM_PREEDIT_MASK; xim_best_allowed_style |= GDK_IM_PREEDIT_NONE; if (!(style & GDK_IM_PREEDIT_NONE)) { xim_best_allowed_style |= GDK_IM_PREEDIT_NOTHING; if (!(style & GDK_IM_PREEDIT_NOTHING)) { xim_best_allowed_style |= GDK_IM_PREEDIT_AREA; if (!(style & GDK_IM_PREEDIT_AREA)) { xim_best_allowed_style |= GDK_IM_PREEDIT_POSITION; if (!(style & GDK_IM_PREEDIT_POSITION)) xim_best_allowed_style |= GDK_IM_PREEDIT_CALLBACKS; } } } } if (style & GDK_IM_STATUS_MASK) { xim_best_allowed_style &= ~GDK_IM_STATUS_MASK; xim_best_allowed_style |= GDK_IM_STATUS_NONE; if (!(style & GDK_IM_STATUS_NONE)) { xim_best_allowed_style |= GDK_IM_STATUS_NOTHING; if (!(style & GDK_IM_STATUS_NOTHING)) { xim_best_allowed_style |= GDK_IM_STATUS_AREA; if (!(style & GDK_IM_STATUS_AREA)) xim_best_allowed_style |= GDK_IM_STATUS_CALLBACKS; } } } return xim_best_allowed_style; } static gint gdk_im_open (XrmDatabase db, gchar* res_name, gchar* res_class) { xim_im = XOpenIM (GDK_DISPLAY(), db, res_name, res_class); if (xim_im == NULL) { GDK_NOTE (XIM, g_warning ("Unable to open open IM.")); return FALSE; } XGetIMValues (xim_im, XNQueryInputStyle, &xim_styles, NULL, NULL); return TRUE; } static void gdk_im_close (void) { if (xim_im) { XCloseIM (xim_im); xim_im = NULL; } if (xim_styles) { XFree (xim_styles); xim_styles = NULL; } } gint gdk_im_ready (void) { return (xim_im != NULL); } GdkIC gdk_ic_new (GdkWindow* client_window, GdkWindow* focus_window, GdkIMStyle style, ...) { va_list list; GdkICPrivate *private; XVaNestedList preedit_attr = NULL; guint count; g_return_val_if_fail (client_window != NULL, NULL); g_return_val_if_fail (focus_window != NULL, NULL); g_return_val_if_fail (gdk_im_ready(), NULL); private = g_new (GdkICPrivate, 1); va_start (list, style); count = gdk_im_va_count (list); va_end (list); va_start (list, style); preedit_attr = gdk_im_va_to_nested (list, count); va_end (list); private->style = gdk_im_decide_style (style); if (private->style != style) { g_warning ("can not create input context with specified input style."); g_free (private); return NULL; } private->xic = XCreateIC(gdk_im_get (), XNInputStyle, style, XNClientWindow, GDK_WINDOW_XWINDOW (client_window), XNFocusWindow, GDK_WINDOW_XWINDOW (focus_window), preedit_attr? XNPreeditAttributes : NULL, preedit_attr, NULL); g_free (preedit_attr); if (!private->xic) { g_free (private); return NULL; } xim_ic_list = g_list_append (xim_ic_list, private); return private; } void gdk_ic_destroy (GdkIC ic) { GdkICPrivate *private; g_return_if_fail (ic != NULL); private = (GdkICPrivate *) ic; if (xim_ic == private) gdk_im_end (); XDestroyIC (private->xic); xim_ic_list = g_list_remove (xim_ic_list, private); g_free (private); } GdkIMStyle gdk_ic_get_style (GdkIC ic) { GdkICPrivate *private; g_return_val_if_fail (ic != NULL, 0); private = (GdkICPrivate *) ic; return private->style; } void gdk_ic_set_values (GdkIC ic, ...) { va_list list; XVaNestedList args; GdkICPrivate *private; guint count; g_return_if_fail (ic != NULL); private = (GdkICPrivate *) ic; va_start (list, ic); count = gdk_im_va_count (list); va_end (list); va_start (list, ic); args = gdk_im_va_to_nested (list, count); va_end (list); XSetICValues (private->xic, XNVaNestedList, args, NULL); g_free (args); } void gdk_ic_get_values (GdkIC ic, ...) { va_list list; XVaNestedList args; GdkICPrivate *private; guint count; g_return_if_fail (ic != NULL); private = (GdkICPrivate *) ic; va_start (list, ic); count = gdk_im_va_count (list); va_end (list); va_start (list, ic); args = gdk_im_va_to_nested (list, count); va_end (list); XGetICValues (private->xic, XNVaNestedList, args, NULL); g_free (args); } void gdk_ic_set_attr (GdkIC ic, const char *target, ...) { va_list list; XVaNestedList attr; GdkICPrivate *private; guint count; g_return_if_fail (ic != NULL); g_return_if_fail (target != NULL); private = (GdkICPrivate *) ic; va_start (list, target); count = gdk_im_va_count (list); va_end (list); va_start (list, target); attr = gdk_im_va_to_nested (list, count); va_end (list); XSetICValues (private->xic, target, attr, NULL); g_free (attr); } void gdk_ic_get_attr (GdkIC ic, const char *target, ...) { va_list list; XVaNestedList attr; GdkICPrivate *private; guint count; g_return_if_fail (ic != NULL); g_return_if_fail (target != NULL); private = (GdkICPrivate *) ic; va_start (list, target); count = gdk_im_va_count (list); va_end (list); va_start (list, target); attr = gdk_im_va_to_nested (list, count); va_end (list); XGetICValues (private->xic, target, attr, NULL); g_free (attr); } GdkEventMask gdk_ic_get_events (GdkIC ic) { GdkEventMask mask; glong xmask; glong bit; GdkICPrivate *private; gint i; /* From gdkwindow.c */ extern int nevent_masks; extern int event_mask_table[]; g_return_val_if_fail (ic != NULL, 0); private = (GdkICPrivate *) ic; if (XGetICValues (private->xic, XNFilterEvents, &xmask, NULL) != NULL) { GDK_NOTE (XIM, g_warning ("Call to XGetICValues: %s failed", XNFilterEvents)); return 0; } mask = 0; for (i=0, bit=2; i < nevent_masks; i++, bit <<= 1) if (xmask & event_mask_table [i]) { mask |= bit; xmask &= ~ event_mask_table [i]; } if (xmask) g_warning ("ic requires events not supported by the application (%#04lx)", xmask); return mask; } static void gdk_ic_cleanup (void) { GList* node; gint destroyed; GdkICPrivate *private; destroyed = 0; for (node = xim_ic_list; node != NULL; node = node->next) { if (node->data) { private = (GdkICPrivate *) (node->data); XDestroyIC (private->xic); g_free (private); destroyed++; } } #ifdef G_ENABLE_DEBUG if ((gdk_debug_flags & GDK_DEBUG_XIM) && destroyed > 0) { g_warning ("Cleaned up %i IC(s)\n", destroyed); } #endif /* G_ENABLE_DEBUG */ g_list_free(xim_ic_list); xim_ic_list = NULL; } #else /* !USE_XIM */ void gdk_im_begin (GdkIC ic, GdkWindow* window) { } void gdk_im_end (void) { } GdkIMStyle gdk_im_decide_style (GdkIMStyle supported_style) { return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE; } GdkIMStyle gdk_im_set_best_style (GdkIMStyle style) { return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE; } gint gdk_im_ready (void) { return FALSE; } GdkIC gdk_ic_new (GdkWindow* client_window, GdkWindow* focus_window, GdkIMStyle style, ...) { return NULL; } void gdk_ic_destroy (GdkIC ic) { } GdkIMStyle gdk_ic_get_style (GdkIC ic) { return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE; } void gdk_ic_set_values (GdkIC ic, ...) { } void gdk_ic_get_values (GdkIC ic, ...) { } void gdk_ic_set_attr (GdkIC ic, const char *target, ...) { } void gdk_ic_get_attr (GdkIC ic, const char *target, ...) { } GdkEventMask gdk_ic_get_events (GdkIC ic) { return 0; } #endif /* USE_XIM */ #ifdef X_LOCALE gint _g_mbtowc (wchar_t *wstr, const char *str, size_t len) { static wchar_t wcs[MB_CUR_MAX + 1]; static gchar mbs[MB_CUR_MAX + 1]; wcs[0] = (wchar_t) NULL; mbs[0] = '\0'; /* The last argument isn't a mistake. The X locale code trims * the input string to the length of the output string! */ len = _Xmbstowcs (wcs, str, (lenxwindow; if (!gdk_send_xevent (dest, False, StructureNotifyMask, &sev)) GDK_NOTE (DND, g_message("Sending XdeLeave to %#lx failed", dest)); wp->dnd_drag_accepted = 0; } } /* * when a drop occurs, we go through the list of windows being dragged and * tell them that it has occurred, so that they can set things up and reply * to 'dest' window */ static void gdk_dnd_drag_end (Window dest, GdkPoint coords) { GdkWindowPrivate *wp; GdkEvent tev; int i; tev.dragrequest.type = GDK_DRAG_REQUEST; tev.dragrequest.drop_coords = coords; tev.dragrequest.requestor = dest; tev.dragrequest.u.allflags = 0; tev.dragrequest.u.flags.protocol_version = DND_PROTOCOL_VERSION; tev.dragrequest.isdrop = 1; for (i = 0; i < gdk_dnd.drag_numwindows; i++) { wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; if (wp->dnd_drag_accepted) { tev.dragrequest.window = (GdkWindow *) wp; tev.dragrequest.u.flags.delete_data = wp->dnd_drag_destructive_op; tev.dragrequest.timestamp = gdk_dnd.last_drop_time; tev.dragrequest.data_type = gdk_atom_name(wp->dnd_drag_data_type); gdk_event_put(&tev); } } } static GdkAtom gdk_dnd_check_types (GdkWindow *window, XEvent *xevent) { GdkWindowPrivate *wp = (GdkWindowPrivate *) window; int i, j; GdkEventDropEnter event; g_return_val_if_fail(window != NULL, 0); g_return_val_if_fail(xevent != NULL, 0); g_return_val_if_fail(xevent->type == ClientMessage, 0); g_return_val_if_fail(xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter, 0); if(wp->dnd_drop_data_numtypesavail <= 0 || !wp->dnd_drop_data_typesavail) return 0; for (i = 2; i <= 4; i++) { for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++) { if (xevent->xclient.data.l[i] == wp->dnd_drop_data_typesavail[j]) return xevent->xclient.data.l[i]; } } /* Now we get the extended type list if it's available */ event.u.allflags = xevent->xclient.data.l[1]; if (event.u.flags.extended_typelist) { Atom *exttypes, realtype; gulong nitems, nbar; gint realfmt; if (XGetWindowProperty(gdk_display, xevent->xclient.data.l[0], gdk_dnd.gdk_XdeTypelist, 0L, LONG_MAX - 1, False, AnyPropertyType, &realtype, &realfmt, &nitems, &nbar, (unsigned char **) &exttypes) != Success) return 0; if (realfmt != (sizeof(Atom) * 8)) { g_warning("XdeTypelist property had format of %d instead of the expected %ld, on window %#lx\n", realfmt, (glong)sizeof(Atom) * 8, xevent->xclient.data.l[0]); return 0; } for (i = 0; i <= nitems; i++) { for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++) { if (exttypes[i] == wp->dnd_drop_data_typesavail[j]) { XFree (exttypes); return exttypes[i]; } } } XFree (exttypes); } return 0; } /* * used for debugging only */ #ifdef DEBUG_DND static void gdk_print_atom (GdkAtom anatom) { gchar *tmpstr = NULL; tmpstr = (anatom!=None)?gdk_atom_name(anatom):"(none)"; g_message("Atom %lu has name %s", anatom, tmpstr); if(tmpstr) g_free(tmpstr); } #endif /* * used only by below routine and itself */ static Window getchildren (Display *dpy, Window win, Atom WM_STATE) { Window root, parent, *children, inf = 0; Atom type = None; unsigned int nchildren, i; int format; unsigned long nitems, after; unsigned char *data; if (XQueryTree(dpy, win, &root, &parent, &children, &nchildren) == 0) return 0; for (i = 0; !inf && (i < nchildren); i++) { XGetWindowProperty (dpy, children[i], WM_STATE, 0, 0, False, AnyPropertyType, &type, &format, &nitems, &after, &data); if (type != 0) inf = children[i]; XFree(data); } for (i = 0; !inf && (i < nchildren); i++) inf = getchildren (dpy, children[i], WM_STATE); if (children != None) XFree ((char *) children); return inf; } /* * find a window with WM_STATE, else return win itself, as per ICCCM * * modification of the XmuClientWindow() routine from X11R6.3 */ Window gdk_get_client_window (Display *dpy, Window win) { Atom WM_STATE; Atom type = None; int format; unsigned long nitems, after; unsigned char *data; Window inf; if (win == 0) return DefaultRootWindow(dpy); if ((WM_STATE = XInternAtom (dpy, "WM_STATE", True)) == 0) return win; XGetWindowProperty (dpy, win, WM_STATE, 0, 0, False, AnyPropertyType, &type, &format, &nitems, &after, &data); if (type) return win; inf = getchildren (dpy, win, WM_STATE); if (inf == 0) return win; else return inf; } #ifdef WE_HAVE_MOTIF_DROPS_DONE static GdkWindow * gdk_drop_get_real_window (GdkWindow *w, guint16 *x, guint16 *y) { GdkWindow *retval = w; GdkWindowPrivate *awin; GList *children; gint16 myx = *x, myy = *y; g_return_val_if_fail (w != NULL && x != NULL && y != NULL, NULL); myx = *x; myy = *y; descend: for (children = gdk_window_get_children(retval); children && children->next; children = children->next) { awin = (GdkWindowPrivate *) children->data; if ((myx >= awin->x) && (myy >= awin->y) && (myx < (awin->x + awin->width)) && (myy < (awin->y + awin->height))) { retval = (GdkWindow *) awin; myx -= awin->x; myy -= awin->y; goto descend; } } *x = myx; *y = myy; return retval; } #endif /* Sends a ClientMessage to all toplevel client windows */ void gdk_event_send_clientmessage_toall (GdkEvent *event) { XEvent sev; Window *ret_children, ret_root, ret_parent, curwin; unsigned int ret_nchildren; int i; g_return_if_fail(event != NULL); /* Set up our event to send, with the exception of its target window */ sev.xclient.type = ClientMessage; sev.xclient.display = gdk_display; sev.xclient.format = event->client.data_format; sev.xclient.serial = CurrentTime; memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data)); sev.xclient.message_type = event->client.message_type; /* OK, we're all set, now let's find some windows to send this to */ if(XQueryTree(gdk_display, gdk_root_window, &ret_root, &ret_parent, &ret_children, &ret_nchildren) != True) return; /* foreach true child window of the root window, send an event to it */ for(i = 0; i < ret_nchildren; i++) { curwin = gdk_get_client_window(gdk_display, ret_children[i]); sev.xclient.window = curwin; if (!gdk_send_xevent (curwin, False, NoEventMask, &sev)) GDK_NOTE (MISC, g_message ("Sending client message %ld to %#lx failed", event->client.message_type, curwin)); } XFree(ret_children); } gchar * gdk_get_display(void) { return (gchar *)XDisplayName (gdk_display_name); } gint gdk_send_xevent (Window window, gboolean propagate, glong event_mask, XEvent *event_send) { Status result; gdk_error_code = 0; gdk_error_warnings = 0; result = XSendEvent (gdk_display, window, propagate, event_mask, event_send); XSync (gdk_display, False); gdk_error_warnings = 1; return result && (gdk_error_code != -1); } #ifndef HAVE_XCONVERTCASE /* compatibility function from X11R6.3, since XConvertCase is not * supplied by X11R5. */ static void gdkx_XConvertCase (KeySym symbol, KeySym *lower, KeySym *upper) { register KeySym sym = symbol; g_return_if_fail (lower != NULL); g_return_if_fail (upper != NULL); *lower = sym; *upper = sym; switch (sym >> 8) { #if defined (GDK_A) && defined (GDK_Ooblique) case 0: /* Latin 1 */ if ((sym >= GDK_A) && (sym <= GDK_Z)) *lower += (GDK_a - GDK_A); else if ((sym >= GDK_a) && (sym <= GDK_z)) *upper -= (GDK_a - GDK_A); else if ((sym >= GDK_Agrave) && (sym <= GDK_Odiaeresis)) *lower += (GDK_agrave - GDK_Agrave); else if ((sym >= GDK_agrave) && (sym <= GDK_odiaeresis)) *upper -= (GDK_agrave - GDK_Agrave); else if ((sym >= GDK_Ooblique) && (sym <= GDK_Thorn)) *lower += (GDK_oslash - GDK_Ooblique); else if ((sym >= GDK_oslash) && (sym <= GDK_thorn)) *upper -= (GDK_oslash - GDK_Ooblique); break; #endif /* LATIN1 */ #if defined (GDK_Aogonek) && defined (GDK_tcedilla) case 1: /* Latin 2 */ /* Assume the KeySym is a legal value (ignore discontinuities) */ if (sym == GDK_Aogonek) *lower = GDK_aogonek; else if (sym >= GDK_Lstroke && sym <= GDK_Sacute) *lower += (GDK_lstroke - GDK_Lstroke); else if (sym >= GDK_Scaron && sym <= GDK_Zacute) *lower += (GDK_scaron - GDK_Scaron); else if (sym >= GDK_Zcaron && sym <= GDK_Zabovedot) *lower += (GDK_zcaron - GDK_Zcaron); else if (sym == GDK_aogonek) *upper = GDK_Aogonek; else if (sym >= GDK_lstroke && sym <= GDK_sacute) *upper -= (GDK_lstroke - GDK_Lstroke); else if (sym >= GDK_scaron && sym <= GDK_zacute) *upper -= (GDK_scaron - GDK_Scaron); else if (sym >= GDK_zcaron && sym <= GDK_zabovedot) *upper -= (GDK_zcaron - GDK_Zcaron); else if (sym >= GDK_Racute && sym <= GDK_Tcedilla) *lower += (GDK_racute - GDK_Racute); else if (sym >= GDK_racute && sym <= GDK_tcedilla) *upper -= (GDK_racute - GDK_Racute); break; #endif /* LATIN2 */ #if defined (GDK_Hstroke) && defined (GDK_Cabovedot) case 2: /* Latin 3 */ /* Assume the KeySym is a legal value (ignore discontinuities) */ if (sym >= GDK_Hstroke && sym <= GDK_Hcircumflex) *lower += (GDK_hstroke - GDK_Hstroke); else if (sym >= GDK_Gbreve && sym <= GDK_Jcircumflex) *lower += (GDK_gbreve - GDK_Gbreve); else if (sym >= GDK_hstroke && sym <= GDK_hcircumflex) *upper -= (GDK_hstroke - GDK_Hstroke); else if (sym >= GDK_gbreve && sym <= GDK_jcircumflex) *upper -= (GDK_gbreve - GDK_Gbreve); else if (sym >= GDK_Cabovedot && sym <= GDK_Scircumflex) *lower += (GDK_cabovedot - GDK_Cabovedot); else if (sym >= GDK_cabovedot && sym <= GDK_scircumflex) *upper -= (GDK_cabovedot - GDK_Cabovedot); break; #endif /* LATIN3 */ #if defined (GDK_Rcedilla) && defined (GDK_Amacron) case 3: /* Latin 4 */ /* Assume the KeySym is a legal value (ignore discontinuities) */ if (sym >= GDK_Rcedilla && sym <= GDK_Tslash) *lower += (GDK_rcedilla - GDK_Rcedilla); else if (sym >= GDK_rcedilla && sym <= GDK_tslash) *upper -= (GDK_rcedilla - GDK_Rcedilla); else if (sym == GDK_ENG) *lower = GDK_eng; else if (sym == GDK_eng) *upper = GDK_ENG; else if (sym >= GDK_Amacron && sym <= GDK_Umacron) *lower += (GDK_amacron - GDK_Amacron); else if (sym >= GDK_amacron && sym <= GDK_umacron) *upper -= (GDK_amacron - GDK_Amacron); break; #endif /* LATIN4 */ #if defined (GDK_Serbian_DJE) && defined (GDK_Cyrillic_yu) case 6: /* Cyrillic */ /* Assume the KeySym is a legal value (ignore discontinuities) */ if (sym >= GDK_Serbian_DJE && sym <= GDK_Serbian_DZE) *lower -= (GDK_Serbian_DJE - GDK_Serbian_dje); else if (sym >= GDK_Serbian_dje && sym <= GDK_Serbian_dze) *upper += (GDK_Serbian_DJE - GDK_Serbian_dje); else if (sym >= GDK_Cyrillic_YU && sym <= GDK_Cyrillic_HARDSIGN) *lower -= (GDK_Cyrillic_YU - GDK_Cyrillic_yu); else if (sym >= GDK_Cyrillic_yu && sym <= GDK_Cyrillic_hardsign) *upper += (GDK_Cyrillic_YU - GDK_Cyrillic_yu); break; #endif /* CYRILLIC */ #if defined (GDK_Greek_ALPHAaccent) && defined (GDK_Greek_finalsmallsigma) case 7: /* Greek */ /* Assume the KeySym is a legal value (ignore discontinuities) */ if (sym >= GDK_Greek_ALPHAaccent && sym <= GDK_Greek_OMEGAaccent) *lower += (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent); else if (sym >= GDK_Greek_alphaaccent && sym <= GDK_Greek_omegaaccent && sym != GDK_Greek_iotaaccentdieresis && sym != GDK_Greek_upsilonaccentdieresis) *upper -= (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent); else if (sym >= GDK_Greek_ALPHA && sym <= GDK_Greek_OMEGA) *lower += (GDK_Greek_alpha - GDK_Greek_ALPHA); else if (sym >= GDK_Greek_alpha && sym <= GDK_Greek_omega && sym != GDK_Greek_finalsmallsigma) *upper -= (GDK_Greek_alpha - GDK_Greek_ALPHA); break; #endif /* GREEK */ } } #endif gchar* gdk_keyval_name (guint keyval) { return XKeysymToString (keyval); } guint gdk_keyval_from_name (const gchar *keyval_name) { g_return_val_if_fail (keyval_name != NULL, 0); return XStringToKeysym (keyval_name); } guint gdk_keyval_to_upper (guint keyval) { if (keyval) { KeySym lower_val = 0; KeySym upper_val = 0; XConvertCase (keyval, &lower_val, &upper_val); return upper_val; } return 0; } guint gdk_keyval_to_lower (guint keyval) { if (keyval) { KeySym lower_val = 0; KeySym upper_val = 0; XConvertCase (keyval, &lower_val, &upper_val); return lower_val; } return 0; } gboolean gdk_keyval_is_upper (guint keyval) { if (keyval) { KeySym lower_val = 0; KeySym upper_val = 0; XConvertCase (keyval, &lower_val, &upper_val); return upper_val == keyval; } return TRUE; } gboolean gdk_keyval_is_lower (guint keyval) { if (keyval) { KeySym lower_val = 0; KeySym upper_val = 0; XConvertCase (keyval, &lower_val, &upper_val); return lower_val == keyval; } return TRUE; }