]> Pileus Git - ~andy/gtk/blob - gdk/broadway/gdkeventsource.c
[broadway] Copy X backend to broadway
[~andy/gtk] / gdk / broadway / 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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include "gdkeventsource.h"
23
24 #include "gdkinternals.h"
25 #include "gdkx.h"
26
27
28 static gboolean gdk_event_source_prepare  (GSource     *source,
29                                            gint        *timeout);
30 static gboolean gdk_event_source_check    (GSource     *source);
31 static gboolean gdk_event_source_dispatch (GSource     *source,
32                                            GSourceFunc  callback,
33                                            gpointer     user_data);
34 static void     gdk_event_source_finalize (GSource     *source);
35
36 #define HAS_FOCUS(toplevel)                           \
37   ((toplevel)->has_focus || (toplevel)->has_pointer_focus)
38
39 struct _GdkEventSource
40 {
41   GSource source;
42
43   GdkDisplay *display;
44   GPollFD event_poll_fd;
45   GList *translators;
46 };
47
48 static GSourceFuncs event_funcs = {
49   gdk_event_source_prepare,
50   gdk_event_source_check,
51   gdk_event_source_dispatch,
52   gdk_event_source_finalize
53 };
54
55 static GList *event_sources = NULL;
56
57 static gint
58 gdk_event_apply_filters (XEvent   *xevent,
59                          GdkEvent *event,
60                          GList    *filters)
61 {
62   GList *tmp_list;
63   GdkFilterReturn result;
64
65   tmp_list = filters;
66
67   while (tmp_list)
68     {
69       GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data;
70
71       tmp_list = tmp_list->next;
72       result = filter->function (xevent, event, filter->data);
73
74       if (result != GDK_FILTER_CONTINUE)
75         return result;
76     }
77
78   return GDK_FILTER_CONTINUE;
79 }
80
81 static GdkWindow *
82 gdk_event_source_get_filter_window (GdkEventSource *event_source,
83                                     XEvent         *xevent)
84 {
85   GdkWindow *window;
86
87   window = gdk_window_lookup_for_display (event_source->display,
88                                           xevent->xany.window);
89
90   if (window && !GDK_IS_WINDOW (window))
91     window = NULL;
92
93   return window;
94 }
95
96 static void
97 handle_focus_change (GdkEventCrossing *event)
98 {
99   GdkToplevelX11 *toplevel;
100   gboolean focus_in, had_focus;
101
102   toplevel = _gdk_x11_window_get_toplevel (event->window);
103   focus_in = (event->type == GDK_ENTER_NOTIFY);
104
105   if (!toplevel || event->detail == GDK_NOTIFY_INFERIOR)
106     return;
107
108   toplevel->has_pointer = focus_in;
109
110   if (!event->focus || toplevel->has_focus_window)
111     return;
112
113   had_focus = HAS_FOCUS (toplevel);
114   toplevel->has_pointer_focus = focus_in;
115
116   if (HAS_FOCUS (toplevel) != had_focus)
117     {
118       GdkEvent *focus_event;
119
120       focus_event = gdk_event_new (GDK_FOCUS_CHANGE);
121       focus_event->focus_change.window = g_object_ref (event->window);
122       focus_event->focus_change.send_event = FALSE;
123       focus_event->focus_change.in = focus_in;
124       gdk_event_set_device (focus_event, gdk_event_get_device ((GdkEvent *) event));
125
126       gdk_event_put (focus_event);
127       gdk_event_free (focus_event);
128     }
129 }
130
131 static GdkEvent *
132 gdk_event_source_translate_event (GdkEventSource *event_source,
133                                   XEvent         *xevent)
134 {
135   GdkEvent *event = gdk_event_new (GDK_NOTHING);
136   GList *list = event_source->translators;
137   GdkFilterReturn result;
138   GdkWindow *filter_window;
139
140   /* Run default filters */
141   if (_gdk_default_filters)
142     {
143       /* Apply global filters */
144
145       result = gdk_event_apply_filters (xevent, event,
146                                         _gdk_default_filters);
147
148       if (result == GDK_FILTER_REMOVE)
149         {
150           gdk_event_free (event);
151           return NULL;
152         }
153       else if (result == GDK_FILTER_TRANSLATE)
154         return event;
155     }
156
157   filter_window = gdk_event_source_get_filter_window (event_source, xevent);
158
159   if (filter_window)
160     {
161       /* Apply per-window filters */
162       GdkWindowObject *filter_private = (GdkWindowObject *) filter_window;
163       GdkFilterReturn result;
164
165       event->any.window = g_object_ref (filter_window);
166
167       if (filter_private->filters)
168         {
169           result = gdk_event_apply_filters (xevent, event,
170                                             filter_private->filters);
171
172           if (result == GDK_FILTER_REMOVE)
173             {
174               gdk_event_free (event);
175               return NULL;
176             }
177           else if (result == GDK_FILTER_TRANSLATE)
178             return event;
179         }
180     }
181
182   gdk_event_free (event);
183   event = NULL;
184
185   while (list && !event)
186     {
187       GdkEventTranslator *translator = list->data;
188
189       list = list->next;
190       event = gdk_event_translator_translate (translator,
191                                               event_source->display,
192                                               xevent);
193     }
194
195   if (event &&
196       (event->type == GDK_ENTER_NOTIFY ||
197        event->type == GDK_LEAVE_NOTIFY) &&
198       event->crossing.window != NULL)
199     {
200       /* Handle focusing (in the case where no window manager is running */
201       handle_focus_change (&event->crossing);
202     }
203
204   return event;
205 }
206
207 static gboolean
208 gdk_check_xpending (GdkDisplay *display)
209 {
210   return XPending (GDK_DISPLAY_XDISPLAY (display));
211 }
212
213 static gboolean
214 gdk_event_source_prepare (GSource *source,
215                           gint    *timeout)
216 {
217   GdkDisplay *display = ((GdkEventSource*) source)->display;
218   gboolean retval;
219
220   GDK_THREADS_ENTER ();
221
222   *timeout = -1;
223   retval = (_gdk_event_queue_find_first (display) != NULL ||
224             gdk_check_xpending (display));
225
226   GDK_THREADS_LEAVE ();
227
228   return retval;
229 }
230
231 static gboolean
232 gdk_event_source_check (GSource *source)
233 {
234   GdkEventSource *event_source = (GdkEventSource*) source;
235   gboolean retval;
236
237   GDK_THREADS_ENTER ();
238
239   if (event_source->event_poll_fd.revents & G_IO_IN)
240     retval = (_gdk_event_queue_find_first (event_source->display) != NULL ||
241               gdk_check_xpending (event_source->display));
242   else
243     retval = FALSE;
244
245   GDK_THREADS_LEAVE ();
246
247   return retval;
248 }
249
250 void
251 _gdk_events_queue (GdkDisplay *display)
252 {
253   GdkEvent *event;
254   XEvent xevent;
255   Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
256   GdkEventSource *event_source;
257   GdkDisplayX11 *display_x11;
258
259   display_x11 = GDK_DISPLAY_X11 (display);
260   event_source = (GdkEventSource *) display_x11->event_source;
261
262   while (!_gdk_event_queue_find_first (display) && XPending (xdisplay))
263     {
264       XNextEvent (xdisplay, &xevent);
265
266       switch (xevent.type)
267         {
268         case KeyPress:
269         case KeyRelease:
270           break;
271         default:
272           if (XFilterEvent (&xevent, None))
273             continue;
274         }
275
276       event = gdk_event_source_translate_event (event_source, &xevent);
277
278       if (event)
279         {
280           GList *node;
281
282           node = _gdk_event_queue_append (display, event);
283           _gdk_windowing_got_event (display, node, event, xevent.xany.serial);
284         }
285     }
286 }
287
288 static gboolean
289 gdk_event_source_dispatch (GSource     *source,
290                            GSourceFunc  callback,
291                            gpointer     user_data)
292 {
293   GdkDisplay *display = ((GdkEventSource*) source)->display;
294   GdkEvent *event;
295
296   GDK_THREADS_ENTER ();
297
298   event = gdk_display_get_event (display);
299
300   if (event)
301     {
302       if (_gdk_event_func)
303         (*_gdk_event_func) (event, _gdk_event_data);
304
305       gdk_event_free (event);
306     }
307
308   GDK_THREADS_LEAVE ();
309
310   return TRUE;
311 }
312
313 static void
314 gdk_event_source_finalize (GSource *source)
315 {
316   GdkEventSource *event_source = (GdkEventSource *)source;
317
318   g_list_free (event_source->translators);
319   event_source->translators = NULL;
320
321   event_sources = g_list_remove (event_sources, source);
322 }
323
324 GSource *
325 gdk_event_source_new (GdkDisplay *display)
326 {
327   GSource *source;
328   GdkEventSource *event_source;
329   GdkDisplayX11 *display_x11;
330   int connection_number;
331   char *name;
332
333   source = g_source_new (&event_funcs, sizeof (GdkEventSource));
334   name = g_strdup_printf ("GDK X11 Event source (%s)",
335                           gdk_display_get_name (display));
336   g_source_set_name (source, name);
337   g_free (name);
338   event_source = (GdkEventSource *) source;
339   event_source->display = display;
340
341   display_x11 = GDK_DISPLAY_X11 (display);
342   connection_number = ConnectionNumber (display_x11->xdisplay);
343
344   event_source->event_poll_fd.fd = connection_number;
345   event_source->event_poll_fd.events = G_IO_IN;
346   g_source_add_poll (source, &event_source->event_poll_fd);
347
348   g_source_set_priority (source, GDK_PRIORITY_EVENTS);
349   g_source_set_can_recurse (source, TRUE);
350   g_source_attach (source, NULL);
351
352   event_sources = g_list_prepend (event_sources, source);
353
354   return source;
355 }
356
357 void
358 gdk_event_source_add_translator (GdkEventSource     *source,
359                                  GdkEventTranslator *translator)
360 {
361   g_return_if_fail (GDK_IS_EVENT_TRANSLATOR (translator));
362
363   source->translators = g_list_append (source->translators, translator);
364 }
365
366 void
367 gdk_event_source_select_events (GdkEventSource *source,
368                                 Window          window,
369                                 GdkEventMask    event_mask,
370                                 unsigned int    extra_x_mask)
371 {
372   unsigned int xmask = extra_x_mask;
373   GList *list;
374   gint i;
375
376   list = source->translators;
377
378   while (list)
379     {
380       GdkEventTranslator *translator = list->data;
381       GdkEventMask translator_mask, mask;
382
383       translator_mask = gdk_event_translator_get_handled_events (translator);
384       mask = event_mask & translator_mask;
385
386       if (mask != 0)
387         {
388           gdk_event_translator_select_window_events (translator, window, mask);
389           event_mask &= ~mask;
390         }
391
392       list = list->next;
393     }
394
395   for (i = 0; i < _gdk_nenvent_masks; i++)
396     {
397       if (event_mask & (1 << (i + 1)))
398         xmask |= _gdk_event_mask_table[i];
399     }
400
401   XSelectInput (GDK_DISPLAY_XDISPLAY (source->display), window, xmask);
402 }
403
404 /**
405  * gdk_events_pending:
406  *
407  * Checks if any events are ready to be processed for any display.
408  *
409  * Return value:  %TRUE if any events are pending.
410  **/
411 gboolean
412 gdk_events_pending (void)
413 {
414   GList *tmp_list;
415
416   for (tmp_list = event_sources; tmp_list; tmp_list = tmp_list->next)
417     {
418       GdkEventSource *tmp_source = tmp_list->data;
419       GdkDisplay *display = tmp_source->display;
420
421       if (_gdk_event_queue_find_first (display))
422         return TRUE;
423     }
424
425   for (tmp_list = event_sources; tmp_list; tmp_list = tmp_list->next)
426     {
427       GdkEventSource *tmp_source = tmp_list->data;
428       GdkDisplay *display = tmp_source->display;
429
430       if (gdk_check_xpending (display))
431         return TRUE;
432     }
433
434   return FALSE;
435 }