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