1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #include "gdkprivate.h"
24 #include "gdkkeysyms.h"
34 typedef struct _GdkIOClosure GdkIOClosure;
36 #define DOUBLE_CLICK_TIME 250
37 #define TRIPLE_CLICK_TIME 500
38 #define DOUBLE_CLICK_DIST 5
39 #define TRIPLE_CLICK_DIST 5
41 struct _GdkIOClosure {
42 GdkInputFunction function;
43 GdkInputCondition condition;
44 GdkDestroyNotify notify;
49 * Private function declarations
52 static GdkEvent *gdk_event_new (void);
53 static gint gdk_event_apply_filters (XEvent *xevent,
56 static gint gdk_event_translate (GdkEvent *event,
59 static Bool gdk_event_get_type (Display *display,
63 static void gdk_events_queue (void);
64 static GdkEvent *gdk_event_unqueue (void);
66 static gboolean gdk_event_prepare (gpointer source_data,
67 GTimeVal *current_time,
69 static gboolean gdk_event_check (gpointer source_data,
70 GTimeVal *current_time);
71 static gboolean gdk_event_dispatch (gpointer source_data,
72 GTimeVal *current_time,
75 static void gdk_synthesize_click (GdkEvent *event,
78 GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
82 /* Private variable declarations
85 static int connection_number = 0; /* The file descriptor number of our
86 * connection to the X server. This
87 * is used so that we may determine
88 * when events are pending by using
89 * the "select" system call.
91 static guint32 button_click_time[2]; /* The last 2 button click times. Used
92 * to determine if the latest button click
93 * is part of a double or triple click.
95 static GdkWindow *button_window[2]; /* The last 2 windows to receive button presses.
96 * Also used to determine if the latest button
97 * click is part of a double or triple click.
99 static guint button_number[2]; /* The last 2 buttons to be pressed.
101 static GdkEventFunc event_func; /* Callback for events */
102 static gpointer event_data;
103 static GDestroyNotify event_notify;
105 static GList *client_filters; /* Filters for client messages */
107 /* FIFO's for event queue, and for events put back using
108 * gdk_event_put(). We keep separate queues so that
109 * we can make the putback events both FIFO and preemptive
112 static GList *queued_events = NULL;
113 static GList *queued_tail = NULL;
114 static GList *putback_events = NULL;
115 static GList *putback_tail = NULL;
117 static GSourceFuncs event_funcs = {
121 (GDestroyNotify)g_free
124 GPollFD event_poll_fd;
127 gdk_events_init (void)
129 connection_number = ConnectionNumber (gdk_display);
131 g_message ("connection number: %d", connection_number));
133 g_source_add (G_PRIORITY_DEFAULT, TRUE, &event_funcs, NULL, NULL, NULL);
135 event_poll_fd.fd = connection_number;
136 event_poll_fd.events = G_IO_IN;
138 g_main_add_poll (&event_poll_fd, GDK_PRIORITY_EVENTS);
140 /* This is really crappy. We have to look into the display structure
141 * to find the base resource id. This is only needed for recording
142 * and playback of events.
144 button_click_time[0] = 0;
145 button_click_time[1] = 0;
146 button_window[0] = NULL;
147 button_window[1] = NULL;
148 button_number[0] = -1;
149 button_number[1] = -1;
151 gdk_add_client_message_filter (gdk_wm_protocols,
152 gdk_wm_protocols_filter, NULL);
156 *--------------------------------------------------------------
159 * Returns if events are pending on the queue.
164 * Returns TRUE if events are pending
168 *--------------------------------------------------------------
172 gdk_events_pending (void)
174 return (queued_events || putback_events);
178 *--------------------------------------------------------------
179 * gdk_event_get_graphics_expose
181 * Waits for a GraphicsExpose or NoExpose event
186 * For GraphicsExpose events, returns a pointer to the event
187 * converted into a GdkEvent Otherwise, returns NULL.
191 *-------------------------------------------------------------- */
194 graphics_expose_predicate (Display *display,
198 GdkWindowPrivate *private = (GdkWindowPrivate *)arg;
200 g_return_val_if_fail (private != NULL, False);
202 if ((xevent->xany.window == private->xwindow) &&
203 ((xevent->xany.type == GraphicsExpose) ||
204 (xevent->xany.type == NoExpose)))
211 gdk_event_get_graphics_expose (GdkWindow *window)
216 g_return_val_if_fail (window != NULL, NULL);
218 XIfEvent (gdk_display, &xevent, graphics_expose_predicate, (XPointer)window);
220 if (xevent.xany.type == GraphicsExpose)
222 event = gdk_event_new ();
224 if (gdk_event_translate (event, &xevent))
227 gdk_event_free (event);
233 /************************
234 * Exposure compression *
235 ************************/
238 * The following implements simple exposure compression. It is
239 * modelled after the way Xt does exposure compression - in
240 * particular compress_expose = XtExposeCompressMultiple.
241 * It compress consecutive sequences of exposure events,
242 * but not sequences that cross other events. (This is because
243 * if it crosses a ConfigureNotify, we could screw up and
244 * mistakenly compress the exposures generated for the new
245 * size - could we just check for ConfigureNotify?)
247 * Xt compresses to a region / bounding rectangle, we compress
248 * to two rectangles, and try find the two rectangles of minimal
249 * area for this - this is supposed to handle the typical
250 * L-shaped regions generated by OpaqueMove.
253 /* Given three rectangles, find the two rectangles that cover
254 * them with the smallest area.
257 gdk_add_rect_to_rects (GdkRectangle *rect1,
259 GdkRectangle *new_rect)
261 GdkRectangle t1, t2, t3;
262 gint size1, size2, size3;
264 gdk_rectangle_union (rect1, rect2, &t1);
265 gdk_rectangle_union (rect1, new_rect, &t2);
266 gdk_rectangle_union (rect2, new_rect, &t3);
268 size1 = t1.width * t1.height + new_rect->width * new_rect->height;
269 size2 = t2.width * t2.height + rect2->width * rect2->height;
270 size3 = t1.width * t1.height + rect1->width * rect1->height;
291 typedef struct _GdkExposeInfo GdkExposeInfo;
293 struct _GdkExposeInfo {
295 gboolean seen_nonmatching;
299 expose_predicate (Display *display, XEvent *xevent, XPointer arg)
301 GdkExposeInfo *info = (GdkExposeInfo *)arg;
303 if (xevent->xany.type != Expose)
305 info->seen_nonmatching = TRUE;
308 if (info->seen_nonmatching || (xevent->xany.window != info->window))
315 gdk_compress_exposures (XEvent *xevent, GdkWindow *window)
321 GdkRectangle tmp_rect;
323 GdkFilterReturn result;
327 info.window = xevent->xany.window;
328 info.seen_nonmatching = FALSE;
330 rect1.x = xevent->xexpose.x;
331 rect1.y = xevent->xexpose.y;
332 rect1.width = xevent->xexpose.width;
333 rect1.height = xevent->xexpose.height;
339 if (!XCheckIfEvent (gdk_display,
346 XIfEvent (gdk_display,
351 /* We apply filters here, and if it was filtered, completely
354 result = gdk_event_apply_filters (xevent, &event,
356 ((GdkWindowPrivate *)window)->filters
357 : gdk_default_filters);
359 if (result != GDK_FILTER_CONTINUE)
361 if (result == GDK_FILTER_TRANSLATE)
362 gdk_event_put (&event);
368 rect2.x = tmp_event.xexpose.x;
369 rect2.y = tmp_event.xexpose.y;
370 rect2.width = tmp_event.xexpose.width;
371 rect2.height = tmp_event.xexpose.height;
377 tmp_rect.x = tmp_event.xexpose.x;
378 tmp_rect.y = tmp_event.xexpose.y;
379 tmp_rect.width = tmp_event.xexpose.width;
380 tmp_rect.height = tmp_event.xexpose.height;
382 gdk_add_rect_to_rects (&rect1, &rect2, &tmp_rect);
385 count = tmp_event.xexpose.count;
390 gdk_rectangle_union (&rect1, &rect2, &tmp_rect);
392 if ((tmp_rect.width * tmp_rect.height) <
393 2 * (rect1.height * rect1.width +
394 rect2.height * rect2.width))
403 event.expose.type = GDK_EXPOSE;
404 event.expose.window = window;
405 event.expose.area.x = rect2.x;
406 event.expose.area.y = rect2.y;
407 event.expose.area.width = rect2.width;
408 event.expose.area.height = rect2.height;
409 event.expose.count = 0;
411 gdk_event_put (&event);
414 xevent->xexpose.count = nrects - 1;
415 xevent->xexpose.x = rect1.x;
416 xevent->xexpose.y = rect1.y;
417 xevent->xexpose.width = rect1.width;
418 xevent->xexpose.height = rect1.height;
421 /*************************************************************
422 * gdk_event_handler_set:
425 * func: Callback function to be called for each event.
426 * data: Data supplied to the function
427 * notify: function called when function is no longer needed
430 *************************************************************/
433 gdk_event_handler_set (GdkEventFunc func,
435 GDestroyNotify notify)
437 if (event_func && event_notify)
438 (*event_notify) (event_data);
442 event_notify = notify;
446 *--------------------------------------------------------------
449 * Gets the next event.
454 * If an event was received that we care about, returns
455 * a pointer to that event, to be freed with gdk_event_free.
456 * Otherwise, returns NULL. This function will also return
457 * before an event is received if the timeout interval
462 *--------------------------------------------------------------
470 return gdk_event_unqueue();
474 gdk_event_put (GdkEvent *event)
478 g_return_if_fail (event != NULL);
480 new_event = gdk_event_copy (event);
482 putback_tail = g_list_append(putback_tail, new_event);
485 putback_events = putback_tail;
487 putback_tail = putback_tail->next;
491 *--------------------------------------------------------------
494 * Copy a event structure into new storage.
497 * "event" is the event struct to copy.
500 * A new event structure. Free it with gdk_event_free.
503 * The reference count of the window in the event is increased.
505 *--------------------------------------------------------------
508 static GMemChunk *event_chunk;
515 if (event_chunk == NULL)
516 event_chunk = g_mem_chunk_new ("events",
521 new_event = g_chunk_new (GdkEvent, event_chunk);
527 gdk_event_copy (GdkEvent *event)
531 g_return_val_if_fail (event != NULL, NULL);
533 new_event = gdk_event_new ();
536 gdk_window_ref (new_event->any.window);
538 switch (event->any.type)
541 case GDK_KEY_RELEASE:
542 new_event->key.string = g_strdup (event->key.string);
545 case GDK_ENTER_NOTIFY:
546 case GDK_LEAVE_NOTIFY:
547 if (event->crossing.subwindow != NULL)
548 gdk_window_ref (event->crossing.subwindow);
553 case GDK_DRAG_MOTION:
554 case GDK_DRAG_STATUS:
556 case GDK_DROP_FINISHED:
557 gdk_drag_context_ref (event->dnd.context);
569 *--------------------------------------------------------------
572 * Free a event structure obtained from gdk_event_copy. Do not use
573 * with other event structures.
576 * "event" is the event struct to free.
581 * The reference count of the window in the event is decreased and
582 * might be freed, too.
584 *-------------------------------------------------------------- */
587 gdk_event_free (GdkEvent *event)
589 g_assert (event_chunk != NULL);
590 g_return_if_fail (event != NULL);
592 if (event->any.window)
593 gdk_window_unref (event->any.window);
595 switch (event->any.type)
598 case GDK_KEY_RELEASE:
599 g_free (event->key.string);
602 case GDK_ENTER_NOTIFY:
603 case GDK_LEAVE_NOTIFY:
604 if (event->crossing.subwindow != NULL)
605 gdk_window_unref (event->crossing.subwindow);
610 case GDK_DRAG_MOTION:
611 case GDK_DRAG_STATUS:
613 case GDK_DROP_FINISHED:
614 gdk_drag_context_unref (event->dnd.context);
622 g_mem_chunk_free (event_chunk, event);
626 *--------------------------------------------------------------
627 * gdk_event_get_time:
628 * Get the timestamp from an event.
632 * The event's time stamp, if it has one, otherwise
634 *--------------------------------------------------------------
638 gdk_event_get_time (GdkEvent *event)
643 case GDK_MOTION_NOTIFY:
644 return event->motion.time;
645 case GDK_BUTTON_PRESS:
646 case GDK_2BUTTON_PRESS:
647 case GDK_3BUTTON_PRESS:
648 case GDK_BUTTON_RELEASE:
649 return event->button.time;
651 case GDK_KEY_RELEASE:
652 return event->key.time;
653 case GDK_ENTER_NOTIFY:
654 case GDK_LEAVE_NOTIFY:
655 return event->crossing.time;
656 case GDK_PROPERTY_NOTIFY:
657 return event->property.time;
658 case GDK_SELECTION_CLEAR:
659 case GDK_SELECTION_REQUEST:
660 case GDK_SELECTION_NOTIFY:
661 return event->selection.time;
662 case GDK_PROXIMITY_IN:
663 case GDK_PROXIMITY_OUT:
664 return event->proximity.time;
667 case GDK_DRAG_MOTION:
668 case GDK_DRAG_STATUS:
670 case GDK_DROP_FINISHED:
671 return event->dnd.time;
672 default: /* use current time */
676 return GDK_CURRENT_TIME;
680 *--------------------------------------------------------------
681 * gdk_set_show_events
683 * Turns on/off the showing of events.
686 * "show_events" is a boolean describing whether or
687 * not to show the events gdk receives.
692 * When "show_events" is TRUE, calls to "gdk_event_get"
693 * will output debugging informatin regarding the event
694 * received to stdout.
696 *--------------------------------------------------------------
700 gdk_set_show_events (int show_events)
703 gdk_debug_flags |= GDK_DEBUG_EVENTS;
705 gdk_debug_flags &= ~GDK_DEBUG_EVENTS;
709 gdk_get_show_events (void)
711 return gdk_debug_flags & GDK_DEBUG_EVENTS;
715 gdk_io_destroy (gpointer data)
717 GdkIOClosure *closure = data;
720 closure->notify (closure->data);
726 gdk_io_invoke (GIOChannel *source,
727 GIOCondition condition,
730 GdkIOClosure *closure = data;
731 GdkInputCondition gdk_cond = 0;
733 if (condition & (G_IO_IN | G_IO_PRI))
734 gdk_cond |= GDK_INPUT_READ;
735 if (condition & G_IO_OUT)
736 gdk_cond |= GDK_INPUT_WRITE;
737 if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
738 gdk_cond |= GDK_INPUT_EXCEPTION;
740 if (closure->condition & gdk_cond)
741 closure->function (closure->data, g_io_channel_unix_get_fd (source), gdk_cond);
747 gdk_input_add_full (gint source,
748 GdkInputCondition condition,
749 GdkInputFunction function,
751 GdkDestroyNotify destroy)
754 GdkIOClosure *closure = g_new (GdkIOClosure, 1);
756 GIOCondition cond = 0;
758 closure->function = function;
759 closure->condition = condition;
760 closure->notify = destroy;
761 closure->data = data;
763 if (condition & GDK_INPUT_READ)
764 cond |= (G_IO_IN | G_IO_PRI);
765 if (condition & GDK_INPUT_WRITE)
767 if (condition & GDK_INPUT_EXCEPTION)
768 cond |= G_IO_ERR|G_IO_HUP|G_IO_NVAL;
770 channel = g_io_channel_unix_new (source);
771 result = g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, cond,
773 closure, gdk_io_destroy);
774 g_io_channel_unref (channel);
780 gdk_input_add (gint source,
781 GdkInputCondition condition,
782 GdkInputFunction function,
785 return gdk_input_add_full (source, condition, function, data, NULL);
789 gdk_input_remove (gint tag)
791 g_source_remove (tag);
795 gdk_event_apply_filters (XEvent *xevent,
799 GdkEventFilter *filter;
801 GdkFilterReturn result;
807 filter = (GdkEventFilter *)tmp_list->data;
809 result = (*filter->function)(xevent, event, filter->data);
810 if (result != GDK_FILTER_CONTINUE)
813 tmp_list = tmp_list->next;
816 return GDK_FILTER_CONTINUE;
820 gdk_add_client_message_filter (GdkAtom message_type,
824 GdkClientFilter *filter = g_new (GdkClientFilter, 1);
826 filter->type = message_type;
827 filter->function = func;
830 client_filters = g_list_prepend (client_filters, filter);
834 gdk_event_translate (GdkEvent *event,
839 GdkWindowPrivate *window_private;
840 static XComposeStatus compose;
844 static gchar* buf = NULL;
845 static gint buf_len= 0;
853 /* Find the GdkWindow that this event occurred in.
855 * We handle events with window=None
856 * specially - they are generated by XFree86's XInput under
857 * some circumstances.
860 if ((xevent->xany.window == None) &&
861 gdk_input_vtable.window_none_event)
863 return_val = gdk_input_vtable.window_none_event (event,xevent);
865 if (return_val >= 0) /* was handled */
871 window = gdk_window_lookup (xevent->xany.window);
872 window_private = (GdkWindowPrivate *) window;
875 gdk_window_ref (window);
877 event->any.window = window;
878 event->any.send_event = xevent->xany.send_event;
880 if (window_private && window_private->destroyed)
882 if (xevent->type != DestroyNotify)
887 /* Check for filters for this window
889 GdkFilterReturn result;
890 result = gdk_event_apply_filters (xevent, event,
892 ?window_private->filters
893 :gdk_default_filters);
895 if (result != GDK_FILTER_CONTINUE)
897 return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
902 if (window == NULL && gdk_xim_window && xevent->type == KeyPress &&
903 !((GdkWindowPrivate *) gdk_xim_window)->destroyed)
906 * If user presses a key in Preedit or Status window, keypress event
907 * is sometimes sent to these windows. These windows are not managed
908 * by GDK, so we redirect KeyPress event to xim_window.
910 * If someone want to use the window whitch is not managed by GDK
911 * and want to get KeyPress event, he/she must register the filter
912 * function to gdk_default_filters to intercept the event.
915 GdkFilterReturn result;
917 window = gdk_xim_window;
918 window_private = (GdkWindowPrivate *) window;
919 gdk_window_ref (window);
920 event->any.window = window;
923 g_message ("KeyPress event is redirected to xim_window: %#lx",
924 xevent->xany.window));
926 result = gdk_event_apply_filters (xevent, event,
927 window_private->filters);
928 if (result != GDK_FILTER_CONTINUE)
929 return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
934 g_message ("Got event for unknown window: %#lx\n", xevent->xany.window);
936 /* We do a "manual" conversion of the XEvent to a
937 * GdkEvent. The structures are mostly the same so
938 * the conversion is fairly straightforward. We also
939 * optionally print debugging info regarding events
945 switch (xevent->type)
948 /* Lookup the string corresponding to the given keysym.
955 buf = g_new (gchar, buf_len);
957 keysym = GDK_VoidSymbol;
959 if (gdk_xim_ic && gdk_xim_ic->xic)
963 /* Clear keyval. Depending on status, may not be set */
964 charcount = XmbLookupString(gdk_xim_ic->xic,
965 &xevent->xkey, buf, buf_len-1,
967 if (status == XBufferOverflow)
969 /* alloc adequate size of buffer */
971 g_message("XIM: overflow (required %i)", charcount));
973 while (buf_len <= charcount)
975 buf = (gchar *) g_realloc (buf, buf_len);
977 charcount = XmbLookupString (gdk_xim_ic->xic,
978 &xevent->xkey, buf, buf_len-1,
981 if (status == XLookupNone)
988 charcount = XLookupString (&xevent->xkey, buf, buf_len,
991 charcount = XLookupString (&xevent->xkey, buf, 16,
994 event->key.keyval = keysym;
996 if (charcount > 0 && buf[charcount-1] == '\0')
999 buf[charcount] = '\0';
1001 /* Print debugging info. */
1003 #ifdef G_ENABLE_DEBUG
1004 if (gdk_debug_flags & GDK_DEBUG_EVENTS)
1006 g_message ("key press:\twindow: %ld key: %12s %d",
1007 xevent->xkey.window,
1008 event->key.keyval ? XKeysymToString (event->key.keyval) : "(none)",
1011 g_message ("\t\tlength: %4d string: \"%s\"",
1014 #endif /* G_ENABLE_DEBUG */
1016 event->key.type = GDK_KEY_PRESS;
1017 event->key.window = window;
1018 event->key.time = xevent->xkey.time;
1019 event->key.state = (GdkModifierType) xevent->xkey.state;
1020 event->key.string = g_strdup (buf);
1021 event->key.length = charcount;
1026 /* Lookup the string corresponding to the given keysym.
1032 buf = g_new (gchar, buf_len);
1035 keysym = GDK_VoidSymbol;
1036 charcount = XLookupString (&xevent->xkey, buf, 16,
1038 event->key.keyval = keysym;
1040 /* Print debugging info.
1043 g_message ("key release:\t\twindow: %ld key: %12s %d",
1044 xevent->xkey.window,
1045 XKeysymToString (event->key.keyval),
1046 event->key.keyval));
1048 event->key.type = GDK_KEY_RELEASE;
1049 event->key.window = window;
1050 event->key.time = xevent->xkey.time;
1051 event->key.state = (GdkModifierType) xevent->xkey.state;
1052 event->key.length = 0;
1053 event->key.string = NULL;
1058 /* Print debugging info.
1061 g_message ("button press:\t\twindow: %ld x,y: %d %d button: %d",
1062 xevent->xbutton.window,
1063 xevent->xbutton.x, xevent->xbutton.y,
1064 xevent->xbutton.button));
1066 if (window_private &&
1067 (window_private->extension_events != 0) &&
1068 gdk_input_ignore_core)
1074 event->button.type = GDK_BUTTON_PRESS;
1075 event->button.window = window;
1076 event->button.time = xevent->xbutton.time;
1077 event->button.x = xevent->xbutton.x;
1078 event->button.y = xevent->xbutton.y;
1079 event->button.x_root = (gfloat)xevent->xbutton.x_root;
1080 event->button.y_root = (gfloat)xevent->xbutton.y_root;
1081 event->button.pressure = 0.5;
1082 event->button.xtilt = 0;
1083 event->button.ytilt = 0;
1084 event->button.state = (GdkModifierType) xevent->xbutton.state;
1085 event->button.button = xevent->xbutton.button;
1086 event->button.source = GDK_SOURCE_MOUSE;
1087 event->button.deviceid = GDK_CORE_POINTER;
1089 if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) &&
1090 (event->button.window == button_window[1]) &&
1091 (event->button.button == button_number[1]))
1093 gdk_synthesize_click (event, 3);
1095 button_click_time[1] = 0;
1096 button_click_time[0] = 0;
1097 button_window[1] = NULL;
1098 button_window[0] = 0;
1099 button_number[1] = -1;
1100 button_number[0] = -1;
1102 else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) &&
1103 (event->button.window == button_window[0]) &&
1104 (event->button.button == button_number[0]))
1106 gdk_synthesize_click (event, 2);
1108 button_click_time[1] = button_click_time[0];
1109 button_click_time[0] = event->button.time;
1110 button_window[1] = button_window[0];
1111 button_window[0] = event->button.window;
1112 button_number[1] = button_number[0];
1113 button_number[0] = event->button.button;
1117 button_click_time[1] = 0;
1118 button_click_time[0] = event->button.time;
1119 button_window[1] = NULL;
1120 button_window[0] = event->button.window;
1121 button_number[1] = -1;
1122 button_number[0] = event->button.button;
1128 /* Print debugging info.
1131 g_message ("button release:\twindow: %ld x,y: %d %d button: %d",
1132 xevent->xbutton.window,
1133 xevent->xbutton.x, xevent->xbutton.y,
1134 xevent->xbutton.button));
1136 if (window_private &&
1137 (window_private->extension_events != 0) &&
1138 gdk_input_ignore_core)
1144 event->button.type = GDK_BUTTON_RELEASE;
1145 event->button.window = window;
1146 event->button.time = xevent->xbutton.time;
1147 event->button.x = xevent->xbutton.x;
1148 event->button.y = xevent->xbutton.y;
1149 event->button.x_root = (gfloat)xevent->xbutton.x_root;
1150 event->button.y_root = (gfloat)xevent->xbutton.y_root;
1151 event->button.pressure = 0.5;
1152 event->button.xtilt = 0;
1153 event->button.ytilt = 0;
1154 event->button.state = (GdkModifierType) xevent->xbutton.state;
1155 event->button.button = xevent->xbutton.button;
1156 event->button.source = GDK_SOURCE_MOUSE;
1157 event->button.deviceid = GDK_CORE_POINTER;
1162 /* Print debugging info.
1165 g_message ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s",
1166 xevent->xmotion.window,
1167 xevent->xmotion.x, xevent->xmotion.y,
1168 (xevent->xmotion.is_hint) ? "true" : "false"));
1170 if (window_private &&
1171 (window_private->extension_events != 0) &&
1172 gdk_input_ignore_core)
1178 event->motion.type = GDK_MOTION_NOTIFY;
1179 event->motion.window = window;
1180 event->motion.time = xevent->xmotion.time;
1181 event->motion.x = xevent->xmotion.x;
1182 event->motion.y = xevent->xmotion.y;
1183 event->motion.x_root = (gfloat)xevent->xmotion.x_root;
1184 event->motion.y_root = (gfloat)xevent->xmotion.y_root;
1185 event->motion.pressure = 0.5;
1186 event->motion.xtilt = 0;
1187 event->motion.ytilt = 0;
1188 event->motion.state = (GdkModifierType) xevent->xmotion.state;
1189 event->motion.is_hint = xevent->xmotion.is_hint;
1190 event->motion.source = GDK_SOURCE_MOUSE;
1191 event->motion.deviceid = GDK_CORE_POINTER;
1196 /* Print debugging info.
1199 g_message ("enter notify:\t\twindow: %ld detail: %d subwin: %ld",
1200 xevent->xcrossing.window,
1201 xevent->xcrossing.detail,
1202 xevent->xcrossing.subwindow));
1204 /* Tell XInput stuff about it if appropriate */
1205 if (window_private &&
1206 !window_private->destroyed &&
1207 (window_private->extension_events != 0) &&
1208 gdk_input_vtable.enter_event)
1209 gdk_input_vtable.enter_event (&xevent->xcrossing, window);
1211 event->crossing.type = GDK_ENTER_NOTIFY;
1212 event->crossing.window = window;
1214 /* If the subwindow field of the XEvent is non-NULL, then
1215 * lookup the corresponding GdkWindow.
1217 if (xevent->xcrossing.subwindow != None)
1218 event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
1220 event->crossing.subwindow = NULL;
1222 event->crossing.time = xevent->xcrossing.time;
1223 event->crossing.x = xevent->xcrossing.x;
1224 event->crossing.y = xevent->xcrossing.y;
1225 event->crossing.x_root = xevent->xcrossing.x_root;
1226 event->crossing.y_root = xevent->xcrossing.y_root;
1228 /* Translate the crossing mode into Gdk terms.
1230 switch (xevent->xcrossing.mode)
1233 event->crossing.mode = GDK_CROSSING_NORMAL;
1236 event->crossing.mode = GDK_CROSSING_GRAB;
1239 event->crossing.mode = GDK_CROSSING_UNGRAB;
1243 /* Translate the crossing detail into Gdk terms.
1245 switch (xevent->xcrossing.detail)
1247 case NotifyInferior:
1248 event->crossing.detail = GDK_NOTIFY_INFERIOR;
1250 case NotifyAncestor:
1251 event->crossing.detail = GDK_NOTIFY_ANCESTOR;
1254 event->crossing.detail = GDK_NOTIFY_VIRTUAL;
1256 case NotifyNonlinear:
1257 event->crossing.detail = GDK_NOTIFY_NONLINEAR;
1259 case NotifyNonlinearVirtual:
1260 event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
1263 event->crossing.detail = GDK_NOTIFY_UNKNOWN;
1267 event->crossing.focus = xevent->xcrossing.focus;
1268 event->crossing.state = xevent->xcrossing.state;
1273 /* Print debugging info.
1276 g_message ("leave notify:\t\twindow: %ld detail: %d subwin: %ld",
1277 xevent->xcrossing.window,
1278 xevent->xcrossing.detail, xevent->xcrossing.subwindow));
1280 event->crossing.type = GDK_LEAVE_NOTIFY;
1281 event->crossing.window = window;
1283 /* If the subwindow field of the XEvent is non-NULL, then
1284 * lookup the corresponding GdkWindow.
1286 if (xevent->xcrossing.subwindow != None)
1287 event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
1289 event->crossing.subwindow = NULL;
1291 event->crossing.time = xevent->xcrossing.time;
1292 event->crossing.x = xevent->xcrossing.x;
1293 event->crossing.y = xevent->xcrossing.y;
1294 event->crossing.x_root = xevent->xcrossing.x_root;
1295 event->crossing.y_root = xevent->xcrossing.y_root;
1297 /* Translate the crossing mode into Gdk terms.
1299 switch (xevent->xcrossing.mode)
1302 event->crossing.mode = GDK_CROSSING_NORMAL;
1305 event->crossing.mode = GDK_CROSSING_GRAB;
1308 event->crossing.mode = GDK_CROSSING_UNGRAB;
1312 /* Translate the crossing detail into Gdk terms.
1314 switch (xevent->xcrossing.detail)
1316 case NotifyInferior:
1317 event->crossing.detail = GDK_NOTIFY_INFERIOR;
1319 case NotifyAncestor:
1320 event->crossing.detail = GDK_NOTIFY_ANCESTOR;
1323 event->crossing.detail = GDK_NOTIFY_VIRTUAL;
1325 case NotifyNonlinear:
1326 event->crossing.detail = GDK_NOTIFY_NONLINEAR;
1328 case NotifyNonlinearVirtual:
1329 event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
1332 event->crossing.detail = GDK_NOTIFY_UNKNOWN;
1336 event->crossing.focus = xevent->xcrossing.focus;
1337 event->crossing.state = xevent->xcrossing.state;
1343 /* We only care about focus events that indicate that _this_
1344 * window (not a ancestor or child) got or lost the focus
1346 switch (xevent->xfocus.detail)
1348 case NotifyAncestor:
1349 case NotifyInferior:
1350 case NotifyNonlinear:
1351 /* Print debugging info.
1354 g_message ("focus %s:\t\twindow: %ld",
1355 (xevent->xany.type == FocusIn) ? "in" : "out",
1356 xevent->xfocus.window));
1358 /* gdk_keyboard_grab() causes following events. These events confuse
1359 * the XIM focus, so ignore them.
1361 if (xevent->xfocus.mode == NotifyGrab ||
1362 xevent->xfocus.mode == NotifyUngrab)
1365 event->focus_change.type = GDK_FOCUS_CHANGE;
1366 event->focus_change.window = window;
1367 event->focus_change.in = (xevent->xany.type == FocusIn);
1376 /* Print debugging info.
1379 g_message ("keymap notify"));
1381 /* Not currently handled */
1386 /* Print debugging info.
1389 g_message ("expose:\t\twindow: %ld %d x,y: %d %d w,h: %d %d",
1390 xevent->xexpose.window, xevent->xexpose.count,
1391 xevent->xexpose.x, xevent->xexpose.y,
1392 xevent->xexpose.width, xevent->xexpose.height));
1393 gdk_compress_exposures (xevent, window);
1395 event->expose.type = GDK_EXPOSE;
1396 event->expose.window = window;
1397 event->expose.area.x = xevent->xexpose.x;
1398 event->expose.area.y = xevent->xexpose.y;
1399 event->expose.area.width = xevent->xexpose.width;
1400 event->expose.area.height = xevent->xexpose.height;
1401 event->expose.count = xevent->xexpose.count;
1405 case GraphicsExpose:
1406 /* Print debugging info.
1409 g_message ("graphics expose:\tdrawable: %ld",
1410 xevent->xgraphicsexpose.drawable));
1412 event->expose.type = GDK_EXPOSE;
1413 event->expose.window = window;
1414 event->expose.area.x = xevent->xgraphicsexpose.x;
1415 event->expose.area.y = xevent->xgraphicsexpose.y;
1416 event->expose.area.width = xevent->xgraphicsexpose.width;
1417 event->expose.area.height = xevent->xgraphicsexpose.height;
1418 event->expose.count = xevent->xexpose.count;
1423 /* Print debugging info.
1426 g_message ("no expose:\t\tdrawable: %ld",
1427 xevent->xnoexpose.drawable));
1429 event->no_expose.type = GDK_NO_EXPOSE;
1430 event->no_expose.window = window;
1434 case VisibilityNotify:
1435 /* Print debugging info.
1437 #ifdef G_ENABLE_DEBUG
1438 if (gdk_debug_flags & GDK_DEBUG_EVENTS)
1439 switch (xevent->xvisibility.state)
1441 case VisibilityFullyObscured:
1442 g_message ("visibility notify:\twindow: %ld none",
1443 xevent->xvisibility.window);
1445 case VisibilityPartiallyObscured:
1446 g_message ("visibility notify:\twindow: %ld partial",
1447 xevent->xvisibility.window);
1449 case VisibilityUnobscured:
1450 g_message ("visibility notify:\twindow: %ld full",
1451 xevent->xvisibility.window);
1454 #endif /* G_ENABLE_DEBUG */
1456 event->visibility.type = GDK_VISIBILITY_NOTIFY;
1457 event->visibility.window = window;
1459 switch (xevent->xvisibility.state)
1461 case VisibilityFullyObscured:
1462 event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
1465 case VisibilityPartiallyObscured:
1466 event->visibility.state = GDK_VISIBILITY_PARTIAL;
1469 case VisibilityUnobscured:
1470 event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
1477 /* Not currently handled */
1481 /* Print debugging info.
1484 g_message ("destroy notify:\twindow: %ld",
1485 xevent->xdestroywindow.window));
1487 event->any.type = GDK_DESTROY;
1488 event->any.window = window;
1490 return_val = window_private && !window_private->destroyed;
1492 if(window && window_private->xwindow != GDK_ROOT_WINDOW())
1493 gdk_window_destroy_notify (window);
1497 /* Print debugging info.
1500 g_message ("unmap notify:\t\twindow: %ld",
1501 xevent->xmap.window));
1503 event->any.type = GDK_UNMAP;
1504 event->any.window = window;
1506 if (gdk_xgrab_window == window_private)
1507 gdk_xgrab_window = NULL;
1512 /* Print debugging info.
1515 g_message ("map notify:\t\twindow: %ld",
1516 xevent->xmap.window));
1518 event->any.type = GDK_MAP;
1519 event->any.window = window;
1523 case ReparentNotify:
1524 /* Print debugging info.
1527 g_message ("reparent notify:\twindow: %ld",
1528 xevent->xreparent.window));
1530 /* Not currently handled */
1534 case ConfigureNotify:
1535 /* Print debugging info.
1537 while ((XPending (gdk_display) > 0) &&
1538 XCheckTypedWindowEvent(gdk_display, xevent->xany.window,
1539 ConfigureNotify, xevent))
1541 GdkFilterReturn result;
1544 g_message ("configure notify discarded:\twindow: %ld",
1545 xevent->xconfigure.window));
1547 result = gdk_event_apply_filters (xevent, event,
1549 ?window_private->filters
1550 :gdk_default_filters);
1552 /* If the result is GDK_FILTER_REMOVE, there will be
1553 * trouble, but anybody who filtering the Configure events
1554 * better know what they are doing
1556 if (result != GDK_FILTER_CONTINUE)
1558 return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
1561 /*XSync (gdk_display, 0);*/
1566 g_message ("configure notify:\twindow: %ld x,y: %d %d w,h: %d %d b-w: %d above: %ld ovr: %d",
1567 xevent->xconfigure.window,
1568 xevent->xconfigure.x,
1569 xevent->xconfigure.y,
1570 xevent->xconfigure.width,
1571 xevent->xconfigure.height,
1572 xevent->xconfigure.border_width,
1573 xevent->xconfigure.above,
1574 xevent->xconfigure.override_redirect));
1576 if (!window_private->destroyed &&
1577 (window_private->extension_events != 0) &&
1578 gdk_input_vtable.configure_event)
1579 gdk_input_vtable.configure_event (&xevent->xconfigure, window);
1581 if (window_private->window_type == GDK_WINDOW_CHILD)
1585 event->configure.type = GDK_CONFIGURE;
1586 event->configure.window = window;
1587 event->configure.width = xevent->xconfigure.width;
1588 event->configure.height = xevent->xconfigure.height;
1590 if (!xevent->xconfigure.x &&
1591 !xevent->xconfigure.y &&
1592 !window_private->destroyed)
1596 Window child_window = 0;
1598 if (!XTranslateCoordinates (window_private->xdisplay,
1599 window_private->xwindow,
1604 g_warning ("GdkWindow %ld doesn't share root windows display?",
1605 window_private->xwindow);
1606 event->configure.x = tx;
1607 event->configure.y = ty;
1611 event->configure.x = xevent->xconfigure.x;
1612 event->configure.y = xevent->xconfigure.y;
1614 window_private->x = event->configure.x;
1615 window_private->y = event->configure.y;
1616 window_private->width = xevent->xconfigure.width;
1617 window_private->height = xevent->xconfigure.height;
1618 if (window_private->resize_count > 1)
1619 window_private->resize_count -= 1;
1623 case PropertyNotify:
1624 /* Print debugging info.
1627 g_message ("property notify:\twindow: %ld",
1628 xevent->xproperty.window));
1630 event->property.type = GDK_PROPERTY_NOTIFY;
1631 event->property.window = window;
1632 event->property.atom = xevent->xproperty.atom;
1633 event->property.time = xevent->xproperty.time;
1634 event->property.state = xevent->xproperty.state;
1638 case SelectionClear:
1640 g_message ("selection clear:\twindow: %ld",
1641 xevent->xproperty.window));
1643 event->selection.type = GDK_SELECTION_CLEAR;
1644 event->selection.window = window;
1645 event->selection.selection = xevent->xselectionclear.selection;
1646 event->selection.time = xevent->xselectionclear.time;
1650 case SelectionRequest:
1652 g_message ("selection request:\twindow: %ld",
1653 xevent->xproperty.window));
1655 event->selection.type = GDK_SELECTION_REQUEST;
1656 event->selection.window = window;
1657 event->selection.selection = xevent->xselectionrequest.selection;
1658 event->selection.target = xevent->xselectionrequest.target;
1659 event->selection.property = xevent->xselectionrequest.property;
1660 event->selection.requestor = xevent->xselectionrequest.requestor;
1661 event->selection.time = xevent->xselectionrequest.time;
1665 case SelectionNotify:
1667 g_message ("selection notify:\twindow: %ld",
1668 xevent->xproperty.window));
1671 event->selection.type = GDK_SELECTION_NOTIFY;
1672 event->selection.window = window;
1673 event->selection.selection = xevent->xselection.selection;
1674 event->selection.target = xevent->xselection.target;
1675 event->selection.property = xevent->xselection.property;
1676 event->selection.time = xevent->xselection.time;
1680 case ColormapNotify:
1681 /* Print debugging info.
1684 g_message ("colormap notify:\twindow: %ld",
1685 xevent->xcolormap.window));
1687 /* Not currently handled */
1694 GdkFilterReturn result = GDK_FILTER_CONTINUE;
1696 /* Print debugging info.
1699 g_message ("client message:\twindow: %ld",
1700 xevent->xclient.window));
1702 tmp_list = client_filters;
1705 GdkClientFilter *filter = tmp_list->data;
1706 if (filter->type == xevent->xclient.message_type)
1708 result = (*filter->function) (xevent, event, filter->data);
1712 tmp_list = tmp_list->next;
1717 case GDK_FILTER_REMOVE:
1720 case GDK_FILTER_TRANSLATE:
1723 case GDK_FILTER_CONTINUE:
1724 /* Send unknown ClientMessage's on to Gtk for it to use */
1725 event->client.type = GDK_CLIENT_EVENT;
1726 event->client.window = window;
1727 event->client.message_type = xevent->xclient.message_type;
1728 event->client.data_format = xevent->xclient.format;
1729 memcpy(&event->client.data, &xevent->xclient.data,
1730 sizeof(event->client.data));
1737 /* Print debugging info.
1740 g_message ("mapping notify"));
1742 /* Let XLib know that there is a new keyboard mapping.
1744 XRefreshKeyboardMapping (&xevent->xmapping);
1749 /* something else - (e.g., a Xinput event) */
1751 if (window_private &&
1752 !window_private->destroyed &&
1753 (window_private->extension_events != 0) &&
1754 gdk_input_vtable.other_event)
1755 return_val = gdk_input_vtable.other_event(event, xevent, window);
1764 if (event->any.window)
1765 gdk_window_ref (event->any.window);
1766 if (((event->any.type == GDK_ENTER_NOTIFY) ||
1767 (event->any.type == GDK_LEAVE_NOTIFY)) &&
1768 (event->crossing.subwindow != NULL))
1769 gdk_window_ref (event->crossing.subwindow);
1773 /* Mark this event as having no resources to be freed */
1774 event->any.window = NULL;
1775 event->any.type = GDK_NOTHING;
1779 gdk_window_unref (window);
1785 gdk_wm_protocols_filter (GdkXEvent *xev,
1789 XEvent *xevent = (XEvent *)xev;
1791 if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window)
1793 /* The delete window request specifies a window
1794 * to delete. We don't actually destroy the
1795 * window because "it is only a request". (The
1796 * window might contain vital data that the
1797 * program does not want destroyed). Instead
1798 * the event is passed along to the program,
1799 * which should then destroy the window.
1802 g_message ("delete window:\t\twindow: %ld",
1803 xevent->xclient.window));
1805 event->any.type = GDK_DELETE;
1807 return GDK_FILTER_TRANSLATE;
1809 else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
1813 return GDK_FILTER_REMOVE;
1818 gdk_event_get_type (Display *display,
1825 if (gdk_event_translate (&event, xevent))
1827 pred = (GdkPredicate*) arg;
1828 return (* pred->func) (&event, pred->data);
1836 gdk_events_queue (void)
1841 while (!(putback_events || queued_events) && XPending (gdk_display))
1846 XNextEvent (gdk_display, &xevent);
1848 switch (xevent.type)
1854 w = GDK_WINDOW_XWINDOW (gdk_xim_window);
1858 if (XFilterEvent (&xevent, w))
1861 XNextEvent (gdk_display, &xevent);
1864 event = gdk_event_new ();
1866 event->any.type = GDK_NOTHING;
1867 event->any.window = NULL;
1868 event->any.send_event = FALSE;
1869 event->any.send_event = xevent.xany.send_event;
1871 if (gdk_event_translate (event, &xevent))
1873 queued_tail = g_list_append(queued_tail, event);
1876 queued_events = queued_tail;
1878 queued_tail = queued_tail->next;
1881 gdk_event_free (event);
1886 gdk_event_prepare (gpointer source_data,
1887 GTimeVal *current_time,
1892 GDK_THREADS_ENTER ();
1896 gdk_events_queue ();
1897 retval = (queued_events || putback_events);
1899 GDK_THREADS_LEAVE ();
1905 gdk_event_check (gpointer source_data,
1906 GTimeVal *current_time)
1910 GDK_THREADS_ENTER ();
1912 if (event_poll_fd.revents & G_IO_IN)
1913 gdk_events_queue ();
1915 retval = (queued_events || putback_events);
1917 GDK_THREADS_LEAVE ();
1923 gdk_event_unqueue (void)
1926 GList *tmp_list, **head, **tail;
1930 head = &putback_events;
1931 tail = &putback_tail;
1933 else if (queued_events)
1935 head = &queued_events;
1936 tail = &queued_tail;
1945 event = tmp_list->data;
1946 *head = g_list_remove_link (tmp_list, tmp_list);
1947 g_list_free_1 (tmp_list);
1953 gdk_event_dispatch (gpointer source_data,
1954 GTimeVal *current_time,
1959 GDK_THREADS_ENTER ();
1961 event = gdk_event_unqueue();
1966 (*event_func) (event, event_data);
1968 gdk_event_free (event);
1971 GDK_THREADS_LEAVE ();
1977 gdk_synthesize_click (GdkEvent *event,
1980 GdkEvent temp_event;
1982 g_return_if_fail (event != NULL);
1984 temp_event = *event;
1985 temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
1987 gdk_event_put (&temp_event);
1990 /* Sends a ClientMessage to all toplevel client windows */
1992 gdk_event_send_client_message (GdkEvent *event, guint32 xid)
1996 g_return_val_if_fail(event != NULL, FALSE);
1998 /* Set up our event to send, with the exception of its target window */
1999 sev.xclient.type = ClientMessage;
2000 sev.xclient.display = gdk_display;
2001 sev.xclient.format = event->client.data_format;
2002 sev.xclient.window = xid;
2003 memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
2004 sev.xclient.message_type = event->client.message_type;
2006 return gdk_send_xevent (xid, False, NoEventMask, &sev);
2009 /* Sends a ClientMessage to all toplevel client windows */
2011 gdk_event_send_client_message_to_all_recurse (XEvent *xev,
2015 static GdkAtom wm_state_atom = GDK_NONE;
2019 unsigned long nitems, after;
2020 unsigned char *data;
2022 Window *ret_children, ret_root, ret_parent;
2023 unsigned int ret_nchildren;
2026 gboolean send = FALSE;
2027 gboolean found = FALSE;
2030 wm_state_atom = gdk_atom_intern ("WM_STATE", FALSE);
2033 XGetWindowProperty (gdk_display, xid, wm_state_atom, 0, 0, False, AnyPropertyType,
2034 &type, &format, &nitems, &after, &data);
2049 /* OK, we're all set, now let's find some windows to send this to */
2050 if (XQueryTree(gdk_display, xid, &ret_root, &ret_parent,
2051 &ret_children, &ret_nchildren) != True)
2057 for(i = 0; i < ret_nchildren; i++)
2058 if (gdk_event_send_client_message_to_all_recurse(xev, ret_children[i], level + 1))
2061 XFree(ret_children);
2064 if (send || (!found && (level == 1)))
2066 xev->xclient.window = xid;
2067 gdk_send_xevent (xid, False, NoEventMask, xev);
2070 return (send || found);
2074 gdk_event_send_clientmessage_toall (GdkEvent *event)
2077 gint old_warnings = gdk_error_warnings;
2079 g_return_if_fail(event != NULL);
2081 /* Set up our event to send, with the exception of its target window */
2082 sev.xclient.type = ClientMessage;
2083 sev.xclient.display = gdk_display;
2084 sev.xclient.format = event->client.data_format;
2085 memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
2086 sev.xclient.message_type = event->client.message_type;
2088 gdk_event_send_client_message_to_all_recurse(&sev, gdk_root_window, 0);
2090 gdk_error_warnings = old_warnings;
2094 *--------------------------------------------------------------
2097 * Flushes the Xlib output buffer and then waits
2098 * until all requests have been received and processed
2099 * by the X server. The only real use for this function
2100 * is in dealing with XShm.
2108 *--------------------------------------------------------------
2111 void gdk_flush (void)
2113 XSync (gdk_display, False);