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 "gdksurface-x11.h"
24 #include "gdkprivate-x11.h"
25 #include "gdkdisplay-x11.h"
26 #include "xsettings-client.h"
27 
28 
29 static gboolean gdk_event_source_prepare  (GSource     *source,
30                                            int         *timeout);
31 static gboolean gdk_event_source_check    (GSource     *source);
32 static gboolean gdk_event_source_dispatch (GSource     *source,
33                                            GSourceFunc  callback,
34                                            gpointer     user_data);
35 static void     gdk_event_source_finalize (GSource     *source);
36 
37 static GQuark quark_needs_enter = 0;
38 
39 #define HAS_FOCUS(toplevel)                           \
40   ((toplevel)->has_focus || (toplevel)->has_pointer_focus)
41 
42 struct _GdkEventSource
43 {
44   GSource source;
45 
46   GdkDisplay *display;
47   GPollFD event_poll_fd;
48   GList *translators;
49 };
50 
51 static GSourceFuncs event_funcs = {
52   gdk_event_source_prepare,
53   gdk_event_source_check,
54   gdk_event_source_dispatch,
55   gdk_event_source_finalize
56 };
57 
58 static GdkSurface *
gdk_event_source_get_filter_surface(GdkEventSource * event_source,const XEvent * xevent,GdkEventTranslator ** event_translator)59 gdk_event_source_get_filter_surface (GdkEventSource      *event_source,
60                                      const XEvent        *xevent,
61                                      GdkEventTranslator **event_translator)
62 {
63   GList *list = event_source->translators;
64   GdkSurface *surface;
65 
66   *event_translator = NULL;
67 
68   while (list)
69     {
70       GdkEventTranslator *translator = list->data;
71 
72       list = list->next;
73       surface = _gdk_x11_event_translator_get_surface (translator,
74                                                      event_source->display,
75                                                      xevent);
76       if (surface)
77         {
78           *event_translator = translator;
79           return surface;
80         }
81     }
82 
83   surface = gdk_x11_surface_lookup_for_display (event_source->display,
84                                               xevent->xany.window);
85 
86   return surface;
87 }
88 
89 static void
handle_focus_change(GdkEvent * event)90 handle_focus_change (GdkEvent *event)
91 {
92   GdkToplevelX11 *toplevel;
93   GdkX11Screen *x11_screen;
94   gboolean focus_in, had_focus;
95 
96   toplevel = _gdk_x11_surface_get_toplevel (gdk_event_get_surface (event));
97   x11_screen = GDK_X11_SCREEN (GDK_SURFACE_SCREEN (gdk_event_get_surface (event)));
98   focus_in = (gdk_event_get_event_type (event) == GDK_ENTER_NOTIFY);
99 
100   if (x11_screen->wmspec_check_window)
101     return;
102 
103   if (!toplevel || gdk_crossing_event_get_detail (event) == GDK_NOTIFY_INFERIOR)
104     return;
105 
106   toplevel->has_pointer = focus_in;
107 
108   if (!gdk_crossing_event_get_focus (event) || toplevel->has_focus_window)
109     return;
110 
111   had_focus = HAS_FOCUS (toplevel);
112   toplevel->has_pointer_focus = focus_in;
113 
114   if (HAS_FOCUS (toplevel) != had_focus)
115     {
116       GdkEvent *focus_event;
117 
118       focus_event = gdk_focus_event_new (gdk_event_get_surface (event),
119                                          gdk_event_get_device (event),
120                                          focus_in);
121       gdk_display_put_event (gdk_event_get_display (event), focus_event);
122       gdk_event_unref (focus_event);
123     }
124 }
125 
126 static GdkEvent *
create_synth_crossing_event(GdkEventType evtype,GdkCrossingMode mode,GdkEvent * real_event)127 create_synth_crossing_event (GdkEventType     evtype,
128                              GdkCrossingMode  mode,
129                              GdkEvent        *real_event)
130 {
131   GdkEvent *event;
132   double x, y;
133 
134   g_assert (evtype == GDK_ENTER_NOTIFY || evtype == GDK_LEAVE_NOTIFY);
135 
136   gdk_event_get_position (real_event, &x, &y);
137   event = gdk_crossing_event_new (evtype,
138                                   gdk_event_get_surface (real_event),
139                                   gdk_event_get_device (real_event),
140                                   gdk_event_get_time (real_event),
141                                   gdk_event_get_modifier_state (real_event),
142                                   x, y,
143                                   mode,
144                                   GDK_NOTIFY_ANCESTOR);
145 
146   return event;
147 }
148 
149 static void
handle_touch_synthetic_crossing(GdkEvent * event)150 handle_touch_synthetic_crossing (GdkEvent *event)
151 {
152   GdkEventType evtype = gdk_event_get_event_type (event);
153   GdkEvent *crossing = NULL;
154   GdkSeat *seat = gdk_event_get_seat (event);
155   gboolean needs_enter, set_needs_enter = FALSE;
156 
157   if (quark_needs_enter == 0)
158     quark_needs_enter = g_quark_from_static_string ("gdk-x11-needs-enter-after-touch-end");
159 
160   needs_enter =
161     GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (seat), quark_needs_enter));
162 
163   if (evtype == GDK_MOTION_NOTIFY && needs_enter)
164     {
165       set_needs_enter = FALSE;
166       crossing = create_synth_crossing_event (GDK_ENTER_NOTIFY,
167                                               GDK_CROSSING_DEVICE_SWITCH,
168                                               event);
169     }
170   else if (evtype == GDK_TOUCH_BEGIN && needs_enter &&
171            gdk_event_get_pointer_emulated (event))
172     {
173       set_needs_enter = FALSE;
174       crossing = create_synth_crossing_event (GDK_ENTER_NOTIFY,
175                                               GDK_CROSSING_TOUCH_BEGIN,
176                                               event);
177     }
178   else if (evtype == GDK_TOUCH_END &&
179            gdk_event_get_pointer_emulated (event))
180     {
181       set_needs_enter = TRUE;
182       crossing = create_synth_crossing_event (GDK_LEAVE_NOTIFY,
183                                               GDK_CROSSING_TOUCH_END,
184                                               event);
185     }
186   else if (evtype == GDK_ENTER_NOTIFY ||
187            evtype == GDK_LEAVE_NOTIFY)
188     {
189       /* We are receiving or shall receive a real crossing event,
190        * turn this off.
191        */
192       set_needs_enter = FALSE;
193     }
194   else
195     return;
196 
197   if (needs_enter != set_needs_enter)
198     {
199       if (!set_needs_enter)
200         g_object_steal_qdata (G_OBJECT (seat), quark_needs_enter);
201       else
202         g_object_set_qdata (G_OBJECT (seat), quark_needs_enter,
203                             GUINT_TO_POINTER (TRUE));
204     }
205 
206   if (crossing)
207     {
208       gdk_display_put_event (gdk_seat_get_display (seat), crossing);
209       gdk_event_unref (crossing);
210     }
211 }
212 
213 static GdkEvent *
gdk_event_source_translate_event(GdkX11Display * x11_display,const XEvent * xevent)214 gdk_event_source_translate_event (GdkX11Display  *x11_display,
215                                   const XEvent   *xevent)
216 {
217   GdkEventSource *event_source = (GdkEventSource *) x11_display->event_source;
218   GdkEvent *event;
219   GdkFilterReturn result = GDK_FILTER_CONTINUE;
220   GdkDisplay *display = GDK_DISPLAY (x11_display);
221   GdkEventTranslator *event_translator;
222   GdkSurface *filter_surface;
223   Display *dpy;
224   GdkX11Screen *x11_screen;
225   gpointer cache;
226 
227   x11_screen = GDK_X11_DISPLAY (display)->screen;
228   dpy = GDK_DISPLAY_XDISPLAY (display);
229 
230   event = NULL;
231   filter_surface = gdk_event_source_get_filter_surface (event_source, xevent,
232                                                       &event_translator);
233 
234   /* apply XSettings filters */
235   if (xevent->xany.window == XRootWindow (dpy, 0))
236     result = gdk_xsettings_root_window_filter (xevent, x11_screen);
237 
238   if (result == GDK_FILTER_CONTINUE &&
239       xevent->xany.window == x11_screen->xsettings_manager_window)
240     result = gdk_xsettings_manager_window_filter (xevent, x11_screen);
241 
242   cache = gdk_surface_cache_get (display);
243   if (cache)
244     {
245       if (result == GDK_FILTER_CONTINUE)
246         result = gdk_surface_cache_shape_filter (xevent, cache);
247 
248       if (result == GDK_FILTER_CONTINUE &&
249           xevent->xany.window == XRootWindow (dpy, 0))
250         result = gdk_surface_cache_filter (xevent, cache);
251     }
252 
253   if (result == GDK_FILTER_CONTINUE)
254     result = _gdk_wm_protocols_filter (xevent, filter_surface, &event, NULL);
255 
256   if (result == GDK_FILTER_CONTINUE &&
257       gdk_x11_drop_filter (filter_surface, xevent))
258     result = GDK_FILTER_REMOVE;
259 
260   if (result != GDK_FILTER_CONTINUE)
261     {
262       if (result == GDK_FILTER_REMOVE)
263         return NULL;
264       else /* GDK_FILTER_TRANSLATE */
265         return event;
266     }
267 
268   if (event_translator)
269     {
270       /* Event translator was gotten before in get_filter_window() */
271       event = _gdk_x11_event_translator_translate (event_translator,
272                                                    display,
273                                                    xevent);
274     }
275   else
276     {
277       GList *list = event_source->translators;
278 
279       while (list && !event)
280         {
281           GdkEventTranslator *translator = list->data;
282 
283           list = list->next;
284           event = _gdk_x11_event_translator_translate (translator,
285                                                        display,
286                                                        xevent);
287         }
288     }
289 
290   if (event)
291     {
292       GdkEventType evtype = gdk_event_get_event_type (event);
293 
294       if ((evtype == GDK_ENTER_NOTIFY ||
295            evtype == GDK_LEAVE_NOTIFY) &&
296           gdk_event_get_surface (event) != NULL)
297         {
298           /* Handle focusing (in the case where no window manager is running */
299           handle_focus_change (event);
300         }
301 
302       if (evtype == GDK_TOUCH_BEGIN ||
303           evtype == GDK_TOUCH_END ||
304           evtype == GDK_MOTION_NOTIFY ||
305           evtype == GDK_ENTER_NOTIFY ||
306           evtype == GDK_LEAVE_NOTIFY)
307         {
308           handle_touch_synthetic_crossing (event);
309         }
310     }
311 
312   return event;
313 }
314 
315 gboolean
gdk_event_source_xevent(GdkX11Display * x11_display,const XEvent * xevent)316 gdk_event_source_xevent (GdkX11Display  *x11_display,
317                          const XEvent   *xevent)
318 {
319   GdkDisplay *display = GDK_DISPLAY (x11_display);
320   GdkEvent *event;
321   GList *node;
322 
323   event = gdk_event_source_translate_event (x11_display, xevent);
324   if (event == NULL)
325     return FALSE;
326 
327   node = _gdk_event_queue_append (display, event);
328   _gdk_windowing_got_event (display, node, event, xevent->xany.serial);
329 
330   return TRUE;
331 }
332 
333 static gboolean
gdk_check_xpending(GdkDisplay * display)334 gdk_check_xpending (GdkDisplay *display)
335 {
336   return XPending (GDK_DISPLAY_XDISPLAY (display));
337 }
338 
339 static gboolean
gdk_event_source_prepare(GSource * source,int * timeout)340 gdk_event_source_prepare (GSource *source,
341                           int     *timeout)
342 {
343   GdkDisplay *display = ((GdkEventSource*) source)->display;
344   gboolean retval;
345 
346   *timeout = -1;
347 
348   if (display->event_pause_count > 0)
349     retval = _gdk_event_queue_find_first (display) != NULL;
350   else
351     retval = (_gdk_event_queue_find_first (display) != NULL ||
352               gdk_check_xpending (display));
353 
354   return retval;
355 }
356 
357 static gboolean
gdk_event_source_check(GSource * source)358 gdk_event_source_check (GSource *source)
359 {
360   GdkEventSource *event_source = (GdkEventSource*) source;
361   gboolean retval;
362 
363   if (event_source->display->event_pause_count > 0)
364     retval = _gdk_event_queue_find_first (event_source->display) != NULL;
365   else if (event_source->event_poll_fd.revents & G_IO_IN)
366     retval = (_gdk_event_queue_find_first (event_source->display) != NULL ||
367               gdk_check_xpending (event_source->display));
368   else
369     retval = FALSE;
370 
371   return retval;
372 }
373 
374 void
_gdk_x11_display_queue_events(GdkDisplay * display)375 _gdk_x11_display_queue_events (GdkDisplay *display)
376 {
377   Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
378   XEvent xevent;
379   gboolean unused;
380 
381   while (!_gdk_event_queue_find_first (display) && XPending (xdisplay))
382     {
383       XNextEvent (xdisplay, &xevent);
384 
385       switch (xevent.type)
386         {
387         case KeyPress:
388         case KeyRelease:
389           break;
390         default:
391           if (XFilterEvent (&xevent, None))
392             continue;
393         }
394 
395 #ifdef HAVE_XGENERICEVENTS
396       /* Get cookie data here so it's available
397        * to every event translator and event filter.
398        */
399       if (xevent.type == GenericEvent)
400         XGetEventData (xdisplay, &xevent.xcookie);
401 #endif
402 
403       g_signal_emit_by_name (display, "xevent", &xevent, &unused);
404 
405 #ifdef HAVE_XGENERICEVENTS
406       if (xevent.type == GenericEvent)
407         XFreeEventData (xdisplay, &xevent.xcookie);
408 #endif
409     }
410 }
411 
412 static gboolean
gdk_event_source_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)413 gdk_event_source_dispatch (GSource     *source,
414                            GSourceFunc  callback,
415                            gpointer     user_data)
416 {
417   GdkDisplay *display = ((GdkEventSource*) source)->display;
418   GdkEvent *event;
419 
420   event = gdk_display_get_event (display);
421 
422   if (event)
423     {
424       _gdk_event_emit (event);
425 
426       gdk_event_unref (event);
427     }
428 
429   return TRUE;
430 }
431 
432 static void
gdk_event_source_finalize(GSource * source)433 gdk_event_source_finalize (GSource *source)
434 {
435   GdkEventSource *event_source = (GdkEventSource *)source;
436 
437   g_list_free (event_source->translators);
438   event_source->translators = NULL;
439 }
440 
441 GSource *
gdk_x11_event_source_new(GdkDisplay * display)442 gdk_x11_event_source_new (GdkDisplay *display)
443 {
444   GSource *source;
445   GdkEventSource *event_source;
446   GdkX11Display *display_x11;
447   int connection_number;
448   char *name;
449 
450   source = g_source_new (&event_funcs, sizeof (GdkEventSource));
451   name = g_strdup_printf ("GDK X11 Event source (%s)",
452                           gdk_display_get_name (display));
453   g_source_set_name (source, name);
454   g_free (name);
455   event_source = (GdkEventSource *) source;
456   event_source->display = display;
457 
458   display_x11 = GDK_X11_DISPLAY (display);
459   connection_number = ConnectionNumber (display_x11->xdisplay);
460 
461   event_source->event_poll_fd.fd = connection_number;
462   event_source->event_poll_fd.events = G_IO_IN;
463   g_source_add_poll (source, &event_source->event_poll_fd);
464 
465   g_source_set_priority (source, GDK_PRIORITY_EVENTS);
466   g_source_set_can_recurse (source, TRUE);
467   g_source_attach (source, NULL);
468 
469   return source;
470 }
471 
472 void
gdk_x11_event_source_add_translator(GdkEventSource * source,GdkEventTranslator * translator)473 gdk_x11_event_source_add_translator (GdkEventSource     *source,
474                                      GdkEventTranslator *translator)
475 {
476   g_return_if_fail (GDK_IS_EVENT_TRANSLATOR (translator));
477 
478   source->translators = g_list_append (source->translators, translator);
479 }
480 
481 void
gdk_x11_event_source_select_events(GdkEventSource * source,Window window,GdkEventMask event_mask,unsigned int extra_x_mask)482 gdk_x11_event_source_select_events (GdkEventSource *source,
483                                     Window          window,
484                                     GdkEventMask    event_mask,
485                                     unsigned int    extra_x_mask)
486 {
487   unsigned int xmask = extra_x_mask;
488   GList *list;
489   int i;
490 
491   list = source->translators;
492 
493   while (list)
494     {
495       GdkEventTranslator *translator = list->data;
496       GdkEventMask translator_mask, mask;
497 
498       translator_mask = _gdk_x11_event_translator_get_handled_events (translator);
499       mask = event_mask & translator_mask;
500 
501       if (mask != 0)
502         {
503           _gdk_x11_event_translator_select_surface_events (translator, window, mask);
504           event_mask &= ~mask;
505         }
506 
507       list = list->next;
508     }
509 
510   for (i = 0; i < _gdk_x11_event_mask_table_size; i++)
511     {
512       if (event_mask & (1 << (i + 1)))
513         xmask |= _gdk_x11_event_mask_table[i];
514     }
515 
516   XSelectInput (GDK_DISPLAY_XDISPLAY (source->display), window, xmask);
517 }
518