diff options
author | Owen Taylor <otaylor@redhat.com> | 1998-12-15 13:54:20 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@src.gnome.org> | 1998-12-15 13:54:20 +0000 |
commit | a2fc714adb56de007954c13941abde62ac47550c (patch) | |
tree | c49a1898051867bcae15a87b4fa44a858a771a7a /gdk/gdkevents.c | |
parent | a0c84d6818f278d273b43c651c345f2110bc7f37 (diff) | |
download | gtk+-a2fc714adb56de007954c13941abde62ac47550c.tar.gz |
Remove gdk_signal, which crept back in in last commit.
Tue Dec 15 08:53:38 1998 Owen Taylor <otaylor@redhat.com>
* gdk/gdk.c (gdk_get_display): Remove gdk_signal,
which crept back in in last commit.
gdk/gdkevents.c: File missed on last commit.
CVS
Diffstat (limited to 'gdk/gdkevents.c')
-rw-r--r-- | gdk/gdkevents.c | 2055 |
1 files changed, 2055 insertions, 0 deletions
diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c new file mode 100644 index 0000000000..9a270667bb --- /dev/null +++ b/gdk/gdkevents.c @@ -0,0 +1,2055 @@ +/* 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 "gdk.h" +#include "gdkx.h" +#include "gdkprivate.h" +#include "gdkinput.h" +#include "gdkkeysyms.h" + +typedef struct _GdkIOClosure GdkIOClosure; + +#define DOUBLE_CLICK_TIME 250 +#define TRIPLE_CLICK_TIME 500 +#define DOUBLE_CLICK_DIST 5 +#define TRIPLE_CLICK_DIST 5 + +struct _GdkIOClosure { + GdkInputFunction function; + GdkInputCondition condition; + GdkDestroyNotify notify; + gpointer data; +}; + +/* + * Private function declarations + */ + +static GdkEvent *gdk_event_new (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_events_queue (void); + +static gboolean gdk_event_prepare (gpointer source_data, + GTimeVal *current_time, + gint *timeout); +static gboolean gdk_event_check (gpointer source_data, + GTimeVal *current_time); +static gboolean gdk_event_dispatch (gpointer source_data, + GTimeVal *current_time, + gpointer user_data); + +static void gdk_synthesize_click (GdkEvent *event, + gint nclicks); + +GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev, + GdkEvent *event, + gpointer data); + +/* Private variable declarations + */ + +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 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 GdkEventFunc event_func; /* Callback for events */ +static gpointer event_data; +static GDestroyNotify event_notify; + +static GList *client_filters; /* Filters for client messages */ + +static GList *queued_events = NULL; + +static GSourceFuncs event_funcs = { + gdk_event_prepare, + gdk_event_check, + gdk_event_dispatch, + (GDestroyNotify)g_free +}; + +GPollFD event_poll_fd; + +void +gdk_events_init (void) +{ + connection_number = ConnectionNumber (gdk_display); + GDK_NOTE (MISC, + g_message ("connection number: %d", connection_number)); + + g_source_add (-10, TRUE, &event_funcs, NULL, NULL, NULL); + + event_poll_fd.fd = connection_number; + event_poll_fd.events = G_IO_IN; + + g_main_poll_add (-10, &event_poll_fd); + + /* 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. + */ + 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; + + gdk_add_client_message_filter (gdk_wm_protocols, + gdk_wm_protocols_filter, NULL); +} + +/* + *-------------------------------------------------------------- + * gdk_events_pending + * + * Returns if events are pending on the queue. + * + * Arguments: + * + * Results: + * Returns TRUE if events are pending + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_events_pending (void) +{ + return g_main_pending(); +} + +/* + *-------------------------------------------------------------- + * 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; +} + +/************************ + * Exposure compression * + ************************/ + +/* + * The following implements simple exposure compression. It is + * modelled after the way Xt does exposure compression - in + * particular compress_expose = XtExposeCompressMultiple. + * It compress consecutive sequences of exposure events, + * but not sequences that cross other events. (This is because + * if it crosses a ConfigureNotify, we could screw up and + * mistakenly compress the exposures generated for the new + * size - could we just check for ConfigureNotify?) + * + * Xt compresses to a region / bounding rectangle, we compress + * to two rectangles, and try find the two rectangles of minimal + * area for this - this is supposed to handle the typical + * L-shaped regions generated by OpaqueMove. + */ + +/* Given three rectangles, find the two rectangles that cover + * them with the smallest area. + */ +static void +gdk_add_rect_to_rects (GdkRectangle *rect1, + GdkRectangle *rect2, + GdkRectangle *new_rect) +{ + GdkRectangle t1, t2, t3; + gint size1, size2, size3; + + gdk_rectangle_union (rect1, rect2, &t1); + gdk_rectangle_union (rect1, new_rect, &t2); + gdk_rectangle_union (rect2, new_rect, &t3); + + size1 = t1.width * t1.height + new_rect->width * new_rect->height; + size2 = t2.width * t2.height + rect2->width * rect2->height; + size3 = t1.width * t1.height + rect1->width * rect1->height; + + if (size1 < size2) + { + if (size1 < size3) + { + *rect1 = t1; + *rect2 = *new_rect; + } + else + *rect2 = t3; + } + else + { + if (size2 < size3) + *rect1 = t2; + else + *rect2 = t3; + } +} + +typedef struct _GdkExposeInfo GdkExposeInfo; + +struct _GdkExposeInfo { + Window window; + gboolean seen_nonmatching; +}; + +Bool +expose_predicate (Display *display, XEvent *xevent, XPointer arg) +{ + GdkExposeInfo *info = (GdkExposeInfo *)arg; + + if (xevent->xany.type != Expose) + { + info->seen_nonmatching = TRUE; + } + + if (info->seen_nonmatching || (xevent->xany.window != info->window)) + return FALSE; + else + return TRUE; +} + +void +gdk_compress_exposures (XEvent *xevent, GdkWindow *window) +{ + gint nrects = 1; + gint count = 0; + GdkRectangle rect1; + GdkRectangle rect2; + GdkRectangle tmp_rect; + XEvent tmp_event; + GdkFilterReturn result; + GdkExposeInfo info; + GdkEvent event; + + info.window = xevent->xany.window; + info.seen_nonmatching = FALSE; + + rect1.x = xevent->xexpose.x; + rect1.y = xevent->xexpose.y; + rect1.width = xevent->xexpose.width; + rect1.height = xevent->xexpose.height; + + while (1) + { + if (count == 0) + { + if (!XCheckIfEvent (gdk_display, + &tmp_event, + expose_predicate, + (XPointer)&info)) + break; + } + else + XIfEvent (gdk_display, + &tmp_event, + expose_predicate, + (XPointer)&info); + + /* We apply filters here, and if it was filtered, completely + * ignore the return + */ + result = gdk_event_apply_filters (xevent, &event, + window ? + ((GdkWindowPrivate *)window)->filters + : gdk_default_filters); + + if (result != GDK_FILTER_CONTINUE) + { + if (result == GDK_FILTER_TRANSLATE) + gdk_event_put (&event); + continue; + } + + if (nrects == 1) + { + rect2.x = tmp_event.xexpose.x; + rect2.y = tmp_event.xexpose.y; + rect2.width = tmp_event.xexpose.width; + rect2.height = tmp_event.xexpose.height; + + nrects++; + } + else + { + tmp_rect.x = tmp_event.xexpose.x; + tmp_rect.y = tmp_event.xexpose.y; + tmp_rect.width = tmp_event.xexpose.width; + tmp_rect.height = tmp_event.xexpose.height; + + gdk_add_rect_to_rects (&rect1, &rect2, &tmp_rect); + } + + count = tmp_event.xexpose.count; + } + + if (nrects == 2) + { + gdk_rectangle_union (&rect1, &rect2, &tmp_rect); + + if ((tmp_rect.width * tmp_rect.height) < + 2 * (rect1.height * rect1.width + + rect2.height * rect2.width)) + { + rect1 = tmp_rect; + nrects = 1; + } + } + + if (nrects == 2) + { + event.expose.type = GDK_EXPOSE; + event.expose.window = window; + event.expose.area.x = rect2.x; + event.expose.area.y = rect2.y; + event.expose.area.width = rect2.width; + event.expose.area.height = rect2.height; + event.expose.count = 0; + + gdk_event_put (&event); + } + + xevent->xexpose.count = nrects - 1; + xevent->xexpose.x = rect1.x; + xevent->xexpose.y = rect1.y; + xevent->xexpose.width = rect1.width; + xevent->xexpose.height = rect1.height; +} + +/************************************************************* + * gdk_event_handler_set: + * + * arguments: + * func: Callback function to be called for each event. + * data: Data supplied to the function + * notify: function called when function is no longer needed + * + * results: + *************************************************************/ + +void +gdk_event_handler_set (GdkEventFunc func, + gpointer data, + GDestroyNotify notify) +{ + if (event_func && event_notify) + (*event_notify) (event_data); + + event_func = func; + event_data = data; + event_notify = notify; +} + +/* + *-------------------------------------------------------------- + * 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; + + gdk_events_queue(); + + if (queued_events) + { + event = queued_events->data; + + temp_list = queued_events; + queued_events = g_list_remove_link (queued_events, temp_list); + g_list_free_1 (temp_list); + + return event; + } + else + return NULL; +} + +void +gdk_event_put (GdkEvent *event) +{ + GdkEvent *new_event; + + g_return_if_fail (event != NULL); + + new_event = gdk_event_copy (event); + + queued_events = g_list_prepend (queued_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_DRAG_ENTER: + case GDK_DRAG_LEAVE: + case GDK_DRAG_MOTION: + case GDK_DRAG_STATUS: + case GDK_DROP_START: + case GDK_DROP_FINISHED: + gdk_drag_context_ref (event->dnd.context); + 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_DRAG_ENTER: + case GDK_DRAG_LEAVE: + case GDK_DRAG_MOTION: + case GDK_DRAG_STATUS: + case GDK_DROP_START: + case GDK_DROP_FINISHED: + gdk_drag_context_unref (event->dnd.context); + break; + + + default: + break; + } + + g_mem_chunk_free (event_chunk, event); +} + +/* + *-------------------------------------------------------------- + * gdk_event_get_time: + * Get the timestamp from an event. + * arguments: + * event: + * results: + * The event's time stamp, if it has one, otherwise + * GDK_CURRENT_TIME. + *-------------------------------------------------------------- + */ + +guint32 +gdk_event_get_time (GdkEvent *event) +{ + if (event) + switch (event->type) + { + case GDK_MOTION_NOTIFY: + return event->motion.time; + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + return event->button.time; + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + return event->key.time; + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + return event->crossing.time; + case GDK_PROPERTY_NOTIFY: + return event->property.time; + case GDK_SELECTION_CLEAR: + case GDK_SELECTION_REQUEST: + case GDK_SELECTION_NOTIFY: + return event->selection.time; + case GDK_PROXIMITY_IN: + case GDK_PROXIMITY_OUT: + return event->proximity.time; + case GDK_DRAG_ENTER: + case GDK_DRAG_LEAVE: + case GDK_DRAG_MOTION: + case GDK_DRAG_STATUS: + case GDK_DROP_START: + case GDK_DROP_FINISHED: + return event->dnd.time; + default: /* use current time */ + break; + } + + return GDK_CURRENT_TIME; +} + +/* + *-------------------------------------------------------------- + * 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; +} + +gint +gdk_get_show_events (void) +{ + return gdk_debug_flags & GDK_DEBUG_EVENTS; +} + +static void +gdk_io_destroy (gpointer data) +{ + GdkIOClosure *closure = data; + + if (closure->notify) + closure->notify (closure->data); + + g_free (closure); +} + +static gboolean +gdk_io_invoke (GIOChannel *source, + GIOCondition condition, + gpointer data) +{ + GdkIOClosure *closure = data; + GdkInputCondition gdk_cond = 0; + + if (condition & (G_IO_IN | G_IO_PRI)) + gdk_cond |= GDK_INPUT_READ; + if (condition & G_IO_OUT) + gdk_cond |= GDK_INPUT_WRITE; + if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) + gdk_cond |= GDK_INPUT_EXCEPTION; + + if (closure->condition & gdk_cond) + closure->function (closure->data, g_io_channel_unix_get_fd (source), gdk_cond); + + return TRUE; +} + +gint +gdk_input_add_full (gint source, + GdkInputCondition condition, + GdkInputFunction function, + gpointer data, + GdkDestroyNotify destroy) +{ + guint result; + GdkIOClosure *closure = g_new (GdkIOClosure, 1); + GIOChannel *channel; + GIOCondition cond = 0; + + closure->function = function; + closure->condition = condition; + closure->notify = destroy; + closure->data = data; + + if (condition & GDK_INPUT_READ) + cond |= (G_IO_IN | G_IO_PRI); + if (condition & GDK_INPUT_WRITE) + cond |= G_IO_OUT; + /* The things that correspond to GDK_INPUT_EXCEPTION don't + * need to be added to events + */ + + channel = g_io_channel_unix_new (source); + result = g_io_add_watch_full (channel, 0, cond, gdk_io_invoke, + closure, gdk_io_destroy); + g_io_channel_unref (channel); + + return result; +} + +gint +gdk_input_add (gint source, + GdkInputCondition condition, + GdkInputFunction function, + gpointer data) +{ + return gdk_input_add_full (source, condition, function, data, NULL); +} + +void +gdk_input_remove (gint tag) +{ + g_source_remove (tag); +} + +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; +} + +void +gdk_add_client_message_filter (GdkAtom message_type, + GdkFilterFunc func, + gpointer data) +{ + GdkClientFilter *filter = g_new (GdkClientFilter, 1); + + filter->type = message_type; + filter->function = func; + filter->data = data; + + client_filters = g_list_prepend (client_filters, filter); +} + +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; + + /* Find the GdkWindow that this event occurred in. + * + * 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); + + event->any.window = window; + event->any.send_event = xevent->xany.send_event; + + if (window_private && window_private->destroyed) + { + if (xevent->type != DestroyNotify) + return FALSE; + } + else + { + /* 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; + } + } + +#ifdef USE_XIM + if (window == NULL && gdk_xim_window && xevent->type == KeyPress && + !((GdkWindowPrivate *) gdk_xim_window)->destroyed) + { + /* + * If user presses a key in Preedit or Status window, keypress event + * is sometimes sent to these windows. These windows are not managed + * by GDK, so we redirect KeyPress event to xim_window. + * + * If someone want to use the window whitch is not managed by GDK + * and want to get KeyPress event, he/she must register the filter + * function to gdk_default_filters to intercept the event. + */ + + GdkFilterReturn result; + + window = gdk_xim_window; + window_private = (GdkWindowPrivate *) window; + gdk_window_ref (window); + event->any.window = window; + + GDK_NOTE (XIM, + g_message ("KeyPress event is redirected to xim_window: %#lx", + xevent->xany.window)); + + result = gdk_event_apply_filters (xevent, event, + window_private->filters); + if (result != GDK_FILTER_CONTINUE) + return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE; + } +#endif + + if (window == NULL) + g_message ("Got event for unknown window: %#lx\n", xevent->xany.window); + + /* 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. + */ + + return_val = TRUE; + + 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 (gdk_xim_ic && gdk_xim_ic->xic) + { + Status status; + + /* Clear keyval. Depending on status, may not be set */ + charcount = XmbLookupString(gdk_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 (gdk_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, + 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; + + break; + + case KeyRelease: + /* Lookup the string corresponding to the given keysym. + */ +#ifdef USE_XIM + if (buf_len == 0) + { + buf_len = 128; + buf = g_new (gchar, buf_len); + } +#endif + 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, + 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; + + break; + + case ButtonPress: + /* Print debugging info. + */ + GDK_NOTE (EVENTS, + g_message ("button press:\t\twindow: %ld x,y: %d %d button: %d", + xevent->xbutton.window, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.button)); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + { + return_val = FALSE; + 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; + } + + break; + + case ButtonRelease: + /* Print debugging info. + */ + GDK_NOTE (EVENTS, + g_message ("button release:\twindow: %ld x,y: %d %d button: %d", + xevent->xbutton.window, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.button)); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + { + return_val = FALSE; + 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; + + break; + + case MotionNotify: + /* Print debugging info. + */ + GDK_NOTE (EVENTS, + g_message ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s", + xevent->xmotion.window, + xevent->xmotion.x, xevent->xmotion.y, + (xevent->xmotion.is_hint) ? "true" : "false")); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + { + return_val = FALSE; + 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; + + break; + + case EnterNotify: + /* Print debugging info. + */ + GDK_NOTE (EVENTS, + g_message ("enter notify:\t\twindow: %ld detail: %d subwin: %ld", + xevent->xcrossing.window, + xevent->xcrossing.detail, + xevent->xcrossing.subwindow)); + + /* Tell XInput stuff about it if appropriate */ + if (window_private && + !window_private->destroyed && + (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; + + break; + + case LeaveNotify: + /* Print debugging info. + */ + GDK_NOTE (EVENTS, + g_message ("leave notify:\t\twindow: %ld detail: %d subwin: %ld", + xevent->xcrossing.window, + xevent->xcrossing.detail, xevent->xcrossing.subwindow)); + + 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; + + 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)); + + /* gdk_keyboard_grab() causes following events. These events confuse + * the XIM focus, so ignore them. + */ + if (xevent->xfocus.mode == NotifyGrab || + xevent->xfocus.mode == NotifyUngrab) + break; + + event->focus_change.type = GDK_FOCUS_CHANGE; + event->focus_change.window = window; + event->focus_change.in = (xevent->xany.type == FocusIn); + + break; + default: + return_val = FALSE; + } + break; + + case KeymapNotify: + /* Print debugging info. + */ + GDK_NOTE (EVENTS, + g_message ("keymap notify")); + + /* Not currently handled */ + return_val = FALSE; + 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, xevent->xexpose.count, + xevent->xexpose.x, xevent->xexpose.y, + xevent->xexpose.width, xevent->xexpose.height)); + gdk_compress_exposures (xevent, window); + + 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; + + break; + + case GraphicsExpose: + /* Print debugging info. + */ + GDK_NOTE (EVENTS, + g_message ("graphics expose:\tdrawable: %ld", + xevent->xgraphicsexpose.drawable)); + + 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; + + break; + + case NoExpose: + /* Print debugging info. + */ + GDK_NOTE (EVENTS, + g_message ("no expose:\t\tdrawable: %ld", + xevent->xnoexpose.drawable)); + + event->no_expose.type = GDK_NO_EXPOSE; + event->no_expose.window = window; + + 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); + break; + case VisibilityPartiallyObscured: + g_message ("visibility notify:\twindow: %ld partial", + xevent->xvisibility.window); + break; + case VisibilityUnobscured: + g_message ("visibility notify:\twindow: %ld full", + xevent->xvisibility.window); + 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; + } + + break; + + case CreateNotify: + /* Not currently handled */ + break; + + case DestroyNotify: + /* Print debugging info. + */ + GDK_NOTE (EVENTS, + g_message ("destroy notify:\twindow: %ld", + xevent->xdestroywindow.window)); + + 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)); + + event->any.type = GDK_UNMAP; + event->any.window = window; + + if (gdk_xgrab_window == window_private) + gdk_xgrab_window = NULL; + + break; + + case MapNotify: + /* Print debugging info. + */ + GDK_NOTE (EVENTS, + g_message ("map notify:\t\twindow: %ld", + xevent->xmap.window)); + + event->any.type = GDK_MAP; + event->any.window = window; + + break; + + case ReparentNotify: + /* Print debugging info. + */ + GDK_NOTE (EVENTS, + g_message ("reparent notify:\twindow: %ld", + xevent->xreparent.window)); + + /* Not currently handled */ + return_val = FALSE; + 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)); + + 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, + xevent->xconfigure.x, + xevent->xconfigure.y, + xevent->xconfigure.width, + xevent->xconfigure.height, + xevent->xconfigure.border_width, + xevent->xconfigure.above, + xevent->xconfigure.override_redirect)); + + if (!window_private->destroyed && + (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) + return_val = FALSE; + else + { + 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); + 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; + } + break; + + case PropertyNotify: + /* Print debugging info. + */ + GDK_NOTE (EVENTS, + g_message ("property notify:\twindow: %ld", + xevent->xproperty.window)); + + 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; + + break; + + case SelectionClear: + GDK_NOTE (EVENTS, + g_message ("selection clear:\twindow: %ld", + xevent->xproperty.window)); + + event->selection.type = GDK_SELECTION_CLEAR; + event->selection.window = window; + event->selection.selection = xevent->xselectionclear.selection; + event->selection.time = xevent->xselectionclear.time; + + break; + + case SelectionRequest: + GDK_NOTE (EVENTS, + g_message ("selection request:\twindow: %ld", + xevent->xproperty.window)); + + 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; + + break; + + case SelectionNotify: + GDK_NOTE (EVENTS, + g_message ("selection notify:\twindow: %ld", + xevent->xproperty.window)); + + + 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; + + break; + + case ColormapNotify: + /* Print debugging info. + */ + GDK_NOTE (EVENTS, + g_message ("colormap notify:\twindow: %ld", + xevent->xcolormap.window)); + + /* Not currently handled */ + return_val = FALSE; + break; + + case ClientMessage: + { + GList *tmp_list; + GdkFilterReturn result = GDK_FILTER_CONTINUE; + + /* Print debugging info. + */ + GDK_NOTE (EVENTS, + g_message ("client message:\twindow: %ld", + xevent->xclient.window)); + + tmp_list = client_filters; + while (tmp_list) + { + GdkClientFilter *filter = tmp_list->data; + if (filter->type == xevent->xclient.message_type) + { + result = (*filter->function) (xevent, event, filter->data); + break; + } + + tmp_list = tmp_list->next; + } + + switch (result) + { + case GDK_FILTER_REMOVE: + return_val = FALSE; + break; + case GDK_FILTER_TRANSLATE: + return_val = TRUE; + break; + case GDK_FILTER_CONTINUE: + /* 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)); + } + } + + 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); + return_val = FALSE; + break; + + default: + /* something else - (e.g., a Xinput event) */ + + if (window_private && + !window_private->destroyed && + (window_private->extension_events != 0) && + gdk_input_vtable.other_event) + return_val = gdk_input_vtable.other_event(event, xevent, window); + else + return_val = FALSE; + + 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; +} + +GdkFilterReturn +gdk_wm_protocols_filter (GdkXEvent *xev, + GdkEvent *event, + gpointer data) +{ + XEvent *xevent = (XEvent *)xev; + + 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. + */ + GDK_NOTE (EVENTS, + g_message ("delete window:\t\twindow: %ld", + xevent->xclient.window)); + + event->any.type = GDK_DELETE; + + return GDK_FILTER_TRANSLATE; + } + else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus) + { + } + + return GDK_FILTER_REMOVE; +} + +#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_events_queue (void) +{ + GdkEvent *event; + XEvent xevent; + + while (!queued_events && XPending (gdk_display)) + { + #ifdef USE_XIM + Window w = None; + + XNextEvent (gdk_display, &xevent); + if (gdk_xim_window) + switch (xevent.type) + { + case KeyPress: + case KeyRelease: + case ButtonPress: + case ButtonRelease: + w = GDK_WINDOW_XWINDOW (gdk_xim_window); + break; + } + + if (XFilterEvent (&xevent, w)) + continue; +#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)) + queued_events = g_list_prepend (queued_events, event); + else + gdk_event_free (event); + } +} + +static gboolean +gdk_event_prepare (gpointer source_data, + GTimeVal *current_time, + gint *timeout) +{ + *timeout = -1; + + gdk_events_queue (); + return (queued_events != NULL); +} + +static gboolean +gdk_event_check (gpointer source_data, + GTimeVal *current_time) +{ + if (event_poll_fd.revents & G_IO_IN) + { + gdk_events_queue (); + return (queued_events != NULL); + } + else + return FALSE; +} + +static gboolean +gdk_event_dispatch (gpointer source_data, + GTimeVal *current_time, + gpointer user_data) +{ + if (queued_events) + { + GdkEvent *event = queued_events->data; + GList *tmp_list = queued_events; + queued_events = g_list_remove_link (queued_events, queued_events); + g_list_free_1 (tmp_list); + + if (event_func) + (*event_func) (event, event_data); + + gdk_event_free (event); + } + + return TRUE; +} + +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); +} + +/* Sends a ClientMessage to all toplevel client windows */ +gboolean +gdk_event_send_client_message (GdkEvent *event, guint32 xid) +{ + XEvent sev; + + g_return_val_if_fail(event != NULL, FALSE); + + /* 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.window = xid; + memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data)); + sev.xclient.message_type = event->client.message_type; + + return gdk_send_xevent (xid, False, NoEventMask, &sev); +} + +/* Sends a ClientMessage to all toplevel client windows */ +gboolean +gdk_event_send_client_message_to_all_recurse (XEvent *xev, + guint32 xid, + guint level) +{ + static GdkAtom wm_state_atom = GDK_NONE; + + Atom type = None; + int format; + unsigned long nitems, after; + unsigned char *data; + + Window *ret_children, ret_root, ret_parent; + unsigned int ret_nchildren; + int i; + + gboolean send = FALSE; + gboolean found = FALSE; + + if (!wm_state_atom) + wm_state_atom = gdk_atom_intern ("WM_STATE", FALSE); + + gdk_error_code = 0; + XGetWindowProperty (gdk_display, xid, wm_state_atom, 0, 0, False, AnyPropertyType, + &type, &format, &nitems, &after, &data); + + if (gdk_error_code) + { + gdk_error_code = 0; + return FALSE; + } + + if (type) + { + send = TRUE; + XFree (data); + } + else + { + /* OK, we're all set, now let's find some windows to send this to */ + if (XQueryTree(gdk_display, xid, &ret_root, &ret_parent, + &ret_children, &ret_nchildren) != True) + return FALSE; + + if (gdk_error_code) + return FALSE; + + for(i = 0; i < ret_nchildren; i++) + if (gdk_event_send_client_message_to_all_recurse(xev, ret_children[i], level + 1)) + found = TRUE; + + XFree(ret_children); + } + + if (send || (!found && (level == 1))) + { + xev->xclient.window = xid; + gdk_send_xevent (xid, False, NoEventMask, xev); + } + + return (send || found); +} + +void +gdk_event_send_clientmessage_toall (GdkEvent *event) +{ + XEvent sev; + gint old_warnings = gdk_error_warnings; + + 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; + memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data)); + sev.xclient.message_type = event->client.message_type; + + gdk_event_send_client_message_to_all_recurse(&sev, gdk_root_window, 0); + + gdk_error_warnings = old_warnings; +} + +/* + *-------------------------------------------------------------- + * 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); +} + + |