1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
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.
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.
14 * You should have received a copy of the GNU Lesser 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 "gdkeventsource.h"
24 #include "gdkinternals.h"
25 #include "gdkwindow-x11.h"
26 #include "gdkprivate-x11.h"
29 static gboolean gdk_event_source_prepare (GSource *source,
31 static gboolean gdk_event_source_check (GSource *source);
32 static gboolean gdk_event_source_dispatch (GSource *source,
35 static void gdk_event_source_finalize (GSource *source);
37 #define HAS_FOCUS(toplevel) \
38 ((toplevel)->has_focus || (toplevel)->has_pointer_focus)
40 struct _GdkEventSource
45 GPollFD event_poll_fd;
49 static GSourceFuncs event_funcs = {
50 gdk_event_source_prepare,
51 gdk_event_source_check,
52 gdk_event_source_dispatch,
53 gdk_event_source_finalize
56 static GList *event_sources = NULL;
59 gdk_event_apply_filters (XEvent *xevent,
64 GdkFilterReturn result;
67 tmp_list = _gdk_default_filters;
69 tmp_list = window->filters;
73 GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data;
76 if ((filter->flags & GDK_EVENT_FILTER_REMOVED) != 0)
78 tmp_list = tmp_list->next;
83 result = filter->function (xevent, event, filter->data);
85 /* Protect against unreffing the filter mutating the list */
86 node = tmp_list->next;
88 _gdk_event_filter_unref (window, filter);
92 if (result != GDK_FILTER_CONTINUE)
96 return GDK_FILTER_CONTINUE;
100 gdk_event_source_get_filter_window (GdkEventSource *event_source,
102 GdkEventTranslator **event_translator)
104 GList *list = event_source->translators;
107 *event_translator = NULL;
111 GdkEventTranslator *translator = list->data;
114 window = _gdk_x11_event_translator_get_window (translator,
115 event_source->display,
119 *event_translator = translator;
124 window = gdk_x11_window_lookup_for_display (event_source->display,
125 xevent->xany.window);
127 if (window && !GDK_IS_WINDOW (window))
134 handle_focus_change (GdkEventCrossing *event)
136 GdkToplevelX11 *toplevel;
137 gboolean focus_in, had_focus;
139 toplevel = _gdk_x11_window_get_toplevel (event->window);
140 focus_in = (event->type == GDK_ENTER_NOTIFY);
142 if (!toplevel || event->detail == GDK_NOTIFY_INFERIOR)
145 toplevel->has_pointer = focus_in;
147 if (!event->focus || toplevel->has_focus_window)
150 had_focus = HAS_FOCUS (toplevel);
151 toplevel->has_pointer_focus = focus_in;
153 if (HAS_FOCUS (toplevel) != had_focus)
155 GdkEvent *focus_event;
157 focus_event = gdk_event_new (GDK_FOCUS_CHANGE);
158 focus_event->focus_change.window = g_object_ref (event->window);
159 focus_event->focus_change.send_event = FALSE;
160 focus_event->focus_change.in = focus_in;
161 gdk_event_set_device (focus_event, gdk_event_get_device ((GdkEvent *) event));
163 gdk_event_put (focus_event);
164 gdk_event_free (focus_event);
169 gdk_event_source_translate_event (GdkEventSource *event_source,
172 GdkEvent *event = gdk_event_new (GDK_NOTHING);
173 GdkFilterReturn result = GDK_FILTER_CONTINUE;
174 GdkEventTranslator *event_translator;
175 GdkWindow *filter_window;
178 dpy = GDK_DISPLAY_XDISPLAY (event_source->display);
180 #ifdef HAVE_XGENERICEVENTS
181 /* Get cookie data here so it's available
182 * to every event translator and event filter.
184 if (xevent->type == GenericEvent)
185 XGetEventData (dpy, &xevent->xcookie);
188 filter_window = gdk_event_source_get_filter_window (event_source, xevent,
191 event->any.window = g_object_ref (filter_window);
193 /* Run default filters */
194 if (_gdk_default_filters)
196 /* Apply global filters */
197 result = gdk_event_apply_filters (xevent, event, NULL);
200 if (result == GDK_FILTER_CONTINUE &&
201 filter_window && filter_window->filters)
203 /* Apply per-window filters */
204 result = gdk_event_apply_filters (xevent, event, filter_window);
207 if (result != GDK_FILTER_CONTINUE)
209 #ifdef HAVE_XGENERICEVENTS
210 if (xevent->type == GenericEvent)
211 XFreeEventData (dpy, &xevent->xcookie);
214 if (result == GDK_FILTER_REMOVE)
216 gdk_event_free (event);
219 else /* GDK_FILTER_TRANSLATE */
223 gdk_event_free (event);
226 if (event_translator)
228 /* Event translator was gotten before in get_filter_window() */
229 event = _gdk_x11_event_translator_translate (event_translator,
230 event_source->display,
235 GList *list = event_source->translators;
237 while (list && !event)
239 GdkEventTranslator *translator = list->data;
242 event = _gdk_x11_event_translator_translate (translator,
243 event_source->display,
249 (event->type == GDK_ENTER_NOTIFY ||
250 event->type == GDK_LEAVE_NOTIFY) &&
251 event->crossing.window != NULL)
253 /* Handle focusing (in the case where no window manager is running */
254 handle_focus_change (&event->crossing);
257 #ifdef HAVE_XGENERICEVENTS
258 if (xevent->type == GenericEvent)
259 XFreeEventData (dpy, &xevent->xcookie);
266 gdk_check_xpending (GdkDisplay *display)
268 return XPending (GDK_DISPLAY_XDISPLAY (display));
272 gdk_event_source_prepare (GSource *source,
275 GdkDisplay *display = ((GdkEventSource*) source)->display;
278 GDK_THREADS_ENTER ();
281 retval = (_gdk_event_queue_find_first (display) != NULL ||
282 gdk_check_xpending (display));
284 GDK_THREADS_LEAVE ();
290 gdk_event_source_check (GSource *source)
292 GdkEventSource *event_source = (GdkEventSource*) source;
295 GDK_THREADS_ENTER ();
297 if (event_source->event_poll_fd.revents & G_IO_IN)
298 retval = (_gdk_event_queue_find_first (event_source->display) != NULL ||
299 gdk_check_xpending (event_source->display));
303 GDK_THREADS_LEAVE ();
309 _gdk_x11_display_queue_events (GdkDisplay *display)
313 Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
314 GdkEventSource *event_source;
315 GdkX11Display *display_x11;
317 display_x11 = GDK_X11_DISPLAY (display);
318 event_source = (GdkEventSource *) display_x11->event_source;
320 while (!_gdk_event_queue_find_first (display) && XPending (xdisplay))
322 XNextEvent (xdisplay, &xevent);
330 if (XFilterEvent (&xevent, None))
334 event = gdk_event_source_translate_event (event_source, &xevent);
340 node = _gdk_event_queue_append (display, event);
341 _gdk_windowing_got_event (display, node, event, xevent.xany.serial);
347 gdk_event_source_dispatch (GSource *source,
348 GSourceFunc callback,
351 GdkDisplay *display = ((GdkEventSource*) source)->display;
354 GDK_THREADS_ENTER ();
356 event = gdk_display_get_event (display);
360 _gdk_event_emit (event);
362 gdk_event_free (event);
365 GDK_THREADS_LEAVE ();
371 gdk_event_source_finalize (GSource *source)
373 GdkEventSource *event_source = (GdkEventSource *)source;
375 g_list_free (event_source->translators);
376 event_source->translators = NULL;
378 event_sources = g_list_remove (event_sources, source);
382 gdk_x11_event_source_new (GdkDisplay *display)
385 GdkEventSource *event_source;
386 GdkX11Display *display_x11;
387 int connection_number;
390 source = g_source_new (&event_funcs, sizeof (GdkEventSource));
391 name = g_strdup_printf ("GDK X11 Event source (%s)",
392 gdk_display_get_name (display));
393 g_source_set_name (source, name);
395 event_source = (GdkEventSource *) source;
396 event_source->display = display;
398 display_x11 = GDK_X11_DISPLAY (display);
399 connection_number = ConnectionNumber (display_x11->xdisplay);
401 event_source->event_poll_fd.fd = connection_number;
402 event_source->event_poll_fd.events = G_IO_IN;
403 g_source_add_poll (source, &event_source->event_poll_fd);
405 g_source_set_priority (source, GDK_PRIORITY_EVENTS);
406 g_source_set_can_recurse (source, TRUE);
407 g_source_attach (source, NULL);
409 event_sources = g_list_prepend (event_sources, source);
415 gdk_x11_event_source_add_translator (GdkEventSource *source,
416 GdkEventTranslator *translator)
418 g_return_if_fail (GDK_IS_EVENT_TRANSLATOR (translator));
420 source->translators = g_list_append (source->translators, translator);
424 gdk_x11_event_source_select_events (GdkEventSource *source,
426 GdkEventMask event_mask,
427 unsigned int extra_x_mask)
429 unsigned int xmask = extra_x_mask;
433 list = source->translators;
437 GdkEventTranslator *translator = list->data;
438 GdkEventMask translator_mask, mask;
440 translator_mask = _gdk_x11_event_translator_get_handled_events (translator);
441 mask = event_mask & translator_mask;
445 _gdk_x11_event_translator_select_window_events (translator, window, mask);
452 for (i = 0; i < _gdk_x11_event_mask_table_size; i++)
454 if (event_mask & (1 << (i + 1)))
455 xmask |= _gdk_x11_event_mask_table[i];
458 XSelectInput (GDK_DISPLAY_XDISPLAY (source->display), window, xmask);