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

source code of gtk/gdk/x11/gdkeventsource.c