]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkeventsource.c
gdk_display_get_event: don't unqueue events from the windowing system when paused
[~andy/gtk] / gdk / x11 / gdkeventsource.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser 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.
8  *
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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include "config.h"
19
20 #include "gdkeventsource.h"
21
22 #include "gdkinternals.h"
23 #include "gdkwindow-x11.h"
24 #include "gdkprivate-x11.h"
25
26
27 static gboolean gdk_event_source_prepare  (GSource     *source,
28                                            gint        *timeout);
29 static gboolean gdk_event_source_check    (GSource     *source);
30 static gboolean gdk_event_source_dispatch (GSource     *source,
31                                            GSourceFunc  callback,
32                                            gpointer     user_data);
33 static void     gdk_event_source_finalize (GSource     *source);
34
35 #define HAS_FOCUS(toplevel)                           \
36   ((toplevel)->has_focus || (toplevel)->has_pointer_focus)
37
38 struct _GdkEventSource
39 {
40   GSource source;
41
42   GdkDisplay *display;
43   GPollFD event_poll_fd;
44   GList *translators;
45 };
46
47 static GSourceFuncs event_funcs = {
48   gdk_event_source_prepare,
49   gdk_event_source_check,
50   gdk_event_source_dispatch,
51   gdk_event_source_finalize
52 };
53
54 static GList *event_sources = NULL;
55
56 static gint
57 gdk_event_apply_filters (XEvent    *xevent,
58                          GdkEvent  *event,
59                          GdkWindow *window)
60 {
61   GList *tmp_list;
62   GdkFilterReturn result;
63
64   if (window == NULL)
65     tmp_list = _gdk_default_filters;
66   else
67     tmp_list = window->filters;
68
69   while (tmp_list)
70     {
71       GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data;
72       GList *node;
73
74       if ((filter->flags & GDK_EVENT_FILTER_REMOVED) != 0)
75         {
76           tmp_list = tmp_list->next;
77           continue;
78         }
79
80       filter->ref_count++;
81       result = filter->function (xevent, event, filter->data);
82
83       /* Protect against unreffing the filter mutating the list */
84       node = tmp_list->next;
85
86       _gdk_event_filter_unref (window, filter);
87
88       tmp_list = node;
89
90       if (result != GDK_FILTER_CONTINUE)
91         return result;
92     }
93
94   return GDK_FILTER_CONTINUE;
95 }
96
97 static GdkWindow *
98 gdk_event_source_get_filter_window (GdkEventSource      *event_source,
99                                     XEvent              *xevent,
100                                     GdkEventTranslator **event_translator)
101 {
102   GList *list = event_source->translators;
103   GdkWindow *window;
104
105   *event_translator = NULL;
106
107   while (list)
108     {
109       GdkEventTranslator *translator = list->data;
110
111       list = list->next;
112       window = _gdk_x11_event_translator_get_window (translator,
113                                                      event_source->display,
114                                                      xevent);
115       if (window)
116         {
117           *event_translator = translator;
118           return window;
119         }
120     }
121
122   window = gdk_x11_window_lookup_for_display (event_source->display,
123                                               xevent->xany.window);
124
125   if (window && !GDK_IS_WINDOW (window))
126     window = NULL;
127
128   return window;
129 }
130
131 static void
132 handle_focus_change (GdkEventCrossing *event)
133 {
134   GdkToplevelX11 *toplevel;
135   gboolean focus_in, had_focus;
136
137   toplevel = _gdk_x11_window_get_toplevel (event->window);
138   focus_in = (event->type == GDK_ENTER_NOTIFY);
139
140   if (!toplevel || event->detail == GDK_NOTIFY_INFERIOR)
141     return;
142
143   toplevel->has_pointer = focus_in;
144
145   if (!event->focus || toplevel->has_focus_window)
146     return;
147
148   had_focus = HAS_FOCUS (toplevel);
149   toplevel->has_pointer_focus = focus_in;
150
151   if (HAS_FOCUS (toplevel) != had_focus)
152     {
153       GdkEvent *focus_event;
154
155       focus_event = gdk_event_new (GDK_FOCUS_CHANGE);
156       focus_event->focus_change.window = g_object_ref (event->window);
157       focus_event->focus_change.send_event = FALSE;
158       focus_event->focus_change.in = focus_in;
159       gdk_event_set_device (focus_event, gdk_event_get_device ((GdkEvent *) event));
160
161       gdk_event_put (focus_event);
162       gdk_event_free (focus_event);
163     }
164 }
165
166 static GdkEvent *
167 gdk_event_source_translate_event (GdkEventSource *event_source,
168                                   XEvent         *xevent)
169 {
170   GdkEvent *event = gdk_event_new (GDK_NOTHING);
171   GdkFilterReturn result = GDK_FILTER_CONTINUE;
172   GdkEventTranslator *event_translator;
173   GdkWindow *filter_window;
174   Display *dpy;
175
176   dpy = GDK_DISPLAY_XDISPLAY (event_source->display);
177
178 #ifdef HAVE_XGENERICEVENTS
179   /* Get cookie data here so it's available
180    * to every event translator and event filter.
181    */
182   if (xevent->type == GenericEvent)
183     XGetEventData (dpy, &xevent->xcookie);
184 #endif
185
186   filter_window = gdk_event_source_get_filter_window (event_source, xevent,
187                                                       &event_translator);
188   if (filter_window)
189     event->any.window = g_object_ref (filter_window);
190
191   /* Run default filters */
192   if (_gdk_default_filters)
193     {
194       /* Apply global filters */
195       result = gdk_event_apply_filters (xevent, event, NULL);
196     }
197
198   if (result == GDK_FILTER_CONTINUE &&
199       filter_window && filter_window->filters)
200     {
201       /* Apply per-window filters */
202       result = gdk_event_apply_filters (xevent, event, filter_window);
203     }
204
205   if (result != GDK_FILTER_CONTINUE)
206     {
207 #ifdef HAVE_XGENERICEVENTS
208       if (xevent->type == GenericEvent)
209         XFreeEventData (dpy, &xevent->xcookie);
210 #endif
211
212       if (result == GDK_FILTER_REMOVE)
213         {
214           gdk_event_free (event);
215           return NULL;
216         }
217       else /* GDK_FILTER_TRANSLATE */
218         return event;
219     }
220
221   gdk_event_free (event);
222   event = NULL;
223
224   if (event_translator)
225     {
226       /* Event translator was gotten before in get_filter_window() */
227       event = _gdk_x11_event_translator_translate (event_translator,
228                                                    event_source->display,
229                                                    xevent);
230     }
231   else
232     {
233       GList *list = event_source->translators;
234
235       while (list && !event)
236         {
237           GdkEventTranslator *translator = list->data;
238
239           list = list->next;
240           event = _gdk_x11_event_translator_translate (translator,
241                                                        event_source->display,
242                                                        xevent);
243         }
244     }
245
246   if (event &&
247       (event->type == GDK_ENTER_NOTIFY ||
248        event->type == GDK_LEAVE_NOTIFY) &&
249       event->crossing.window != NULL)
250     {
251       /* Handle focusing (in the case where no window manager is running */
252       handle_focus_change (&event->crossing);
253     }
254
255 #ifdef HAVE_XGENERICEVENTS
256   if (xevent->type == GenericEvent)
257     XFreeEventData (dpy, &xevent->xcookie);
258 #endif
259
260   return event;
261 }
262
263 static gboolean
264 gdk_check_xpending (GdkDisplay *display)
265 {
266   return XPending (GDK_DISPLAY_XDISPLAY (display));
267 }
268
269 static gboolean
270 gdk_event_source_prepare (GSource *source,
271                           gint    *timeout)
272 {
273   GdkDisplay *display = ((GdkEventSource*) source)->display;
274   gboolean retval;
275
276   gdk_threads_enter ();
277
278   *timeout = -1;
279
280   if (display->event_pause_count > 0)
281     retval = FALSE;
282   else
283     retval = (_gdk_event_queue_find_first (display) != NULL ||
284               gdk_check_xpending (display));
285
286   gdk_threads_leave ();
287
288   return retval;
289 }
290
291 static gboolean
292 gdk_event_source_check (GSource *source)
293 {
294   GdkEventSource *event_source = (GdkEventSource*) source;
295   gboolean retval;
296
297   gdk_threads_enter ();
298
299   if (event_source->display->event_pause_count > 0)
300     retval = FALSE;
301   else if (event_source->event_poll_fd.revents & G_IO_IN)
302     retval = (_gdk_event_queue_find_first (event_source->display) != NULL ||
303               gdk_check_xpending (event_source->display));
304   else
305     retval = FALSE;
306
307   gdk_threads_leave ();
308
309   return retval;
310 }
311
312 void
313 _gdk_x11_display_queue_events (GdkDisplay *display)
314 {
315   GdkEvent *event;
316   XEvent xevent;
317   Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
318   GdkEventSource *event_source;
319   GdkX11Display *display_x11;
320
321   display_x11 = GDK_X11_DISPLAY (display);
322   event_source = (GdkEventSource *) display_x11->event_source;
323
324   while (!_gdk_event_queue_find_first (display) && XPending (xdisplay))
325     {
326       XNextEvent (xdisplay, &xevent);
327
328       switch (xevent.type)
329         {
330         case KeyPress:
331         case KeyRelease:
332           break;
333         default:
334           if (XFilterEvent (&xevent, None))
335             continue;
336         }
337
338       event = gdk_event_source_translate_event (event_source, &xevent);
339
340       if (event)
341         {
342           GList *node;
343
344           node = _gdk_event_queue_append (display, event);
345           _gdk_windowing_got_event (display, node, event, xevent.xany.serial);
346         }
347     }
348 }
349
350 static gboolean
351 gdk_event_source_dispatch (GSource     *source,
352                            GSourceFunc  callback,
353                            gpointer     user_data)
354 {
355   GdkDisplay *display = ((GdkEventSource*) source)->display;
356   GdkEvent *event;
357
358   gdk_threads_enter ();
359
360   event = gdk_display_get_event (display);
361
362   if (event)
363     {
364       _gdk_event_emit (event);
365
366       gdk_event_free (event);
367     }
368
369   gdk_threads_leave ();
370
371   return TRUE;
372 }
373
374 static void
375 gdk_event_source_finalize (GSource *source)
376 {
377   GdkEventSource *event_source = (GdkEventSource *)source;
378
379   g_list_free (event_source->translators);
380   event_source->translators = NULL;
381
382   event_sources = g_list_remove (event_sources, source);
383 }
384
385 GSource *
386 gdk_x11_event_source_new (GdkDisplay *display)
387 {
388   GSource *source;
389   GdkEventSource *event_source;
390   GdkX11Display *display_x11;
391   int connection_number;
392   char *name;
393
394   source = g_source_new (&event_funcs, sizeof (GdkEventSource));
395   name = g_strdup_printf ("GDK X11 Event source (%s)",
396                           gdk_display_get_name (display));
397   g_source_set_name (source, name);
398   g_free (name);
399   event_source = (GdkEventSource *) source;
400   event_source->display = display;
401
402   display_x11 = GDK_X11_DISPLAY (display);
403   connection_number = ConnectionNumber (display_x11->xdisplay);
404
405   event_source->event_poll_fd.fd = connection_number;
406   event_source->event_poll_fd.events = G_IO_IN;
407   g_source_add_poll (source, &event_source->event_poll_fd);
408
409   g_source_set_priority (source, GDK_PRIORITY_EVENTS);
410   g_source_set_can_recurse (source, TRUE);
411   g_source_attach (source, NULL);
412
413   event_sources = g_list_prepend (event_sources, source);
414
415   return source;
416 }
417
418 void
419 gdk_x11_event_source_add_translator (GdkEventSource     *source,
420                                      GdkEventTranslator *translator)
421 {
422   g_return_if_fail (GDK_IS_EVENT_TRANSLATOR (translator));
423
424   source->translators = g_list_append (source->translators, translator);
425 }
426
427 void
428 gdk_x11_event_source_select_events (GdkEventSource *source,
429                                     Window          window,
430                                     GdkEventMask    event_mask,
431                                     unsigned int    extra_x_mask)
432 {
433   unsigned int xmask = extra_x_mask;
434   GList *list;
435   gint i;
436
437   list = source->translators;
438
439   while (list)
440     {
441       GdkEventTranslator *translator = list->data;
442       GdkEventMask translator_mask, mask;
443
444       translator_mask = _gdk_x11_event_translator_get_handled_events (translator);
445       mask = event_mask & translator_mask;
446
447       if (mask != 0)
448         {
449           _gdk_x11_event_translator_select_window_events (translator, window, mask);
450           event_mask &= ~mask;
451         }
452
453       list = list->next;
454     }
455
456   for (i = 0; i < _gdk_x11_event_mask_table_size; i++)
457     {
458       if (event_mask & (1 << (i + 1)))
459         xmask |= _gdk_x11_event_mask_table[i];
460     }
461
462   XSelectInput (GDK_DISPLAY_XDISPLAY (source->display), window, xmask);
463 }