update to 1.10.4
[profile/ivi/clutter.git] / clutter / x11 / clutter-event-x11.c
1 /* Clutter.
2  * An OpenGL based 'interactive canvas' library.
3  *
4  * Copyright (C) 2006, 2007, 2008  OpenedHand Ltd
5  * Copyright (C) 2009, 2010  Intel Corp.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
19  *
20  *
21  *
22  * Authored by:
23  *      Matthew Allum <mallum@openedhand.com>
24  *      Emmanuele Bassi <ebassi@linux.intel.com>
25  */
26
27 #include "config.h"
28
29 #include "clutter-backend-x11.h"
30 #include "clutter-x11.h"
31
32 #include "clutter-backend-private.h"
33 #include "clutter-debug.h"
34 #include "clutter-event-private.h"
35 #include "clutter-main.h"
36
37 #include <string.h>
38
39 #include <glib.h>
40
41 #if 0
42 /* XEMBED protocol support for toolkit embedding */
43 #define XEMBED_MAPPED                   (1 << 0)
44 #define MAX_SUPPORTED_XEMBED_VERSION    1
45
46 #define XEMBED_EMBEDDED_NOTIFY          0
47 #define XEMBED_WINDOW_ACTIVATE          1
48 #define XEMBED_WINDOW_DEACTIVATE        2
49 #define XEMBED_REQUEST_FOCUS            3
50 #define XEMBED_FOCUS_IN                 4
51 #define XEMBED_FOCUS_OUT                5
52 #define XEMBED_FOCUS_NEXT               6
53 #define XEMBED_FOCUS_PREV               7
54 /* 8-9 were used for XEMBED_GRAB_KEY/XEMBED_UNGRAB_KEY */
55 #define XEMBED_MODALITY_ON              10
56 #define XEMBED_MODALITY_OFF             11
57 #define XEMBED_REGISTER_ACCELERATOR     12
58 #define XEMBED_UNREGISTER_ACCELERATOR   13
59 #define XEMBED_ACTIVATE_ACCELERATOR     14
60
61 static Window ParentEmbedderWin = None;
62 #endif
63
64 typedef struct _ClutterEventSource      ClutterEventSource;
65
66 struct _ClutterEventSource
67 {
68   GSource source;
69
70   ClutterBackendX11 *backend;
71
72   GPollFD event_poll_fd;
73 };
74
75 ClutterEventX11 *
76 _clutter_event_x11_new (void)
77 {
78   return g_slice_new0 (ClutterEventX11);
79 }
80
81 ClutterEventX11 *
82 _clutter_event_x11_copy (ClutterEventX11 *event_x11)
83 {
84   if (event_x11 != NULL)
85     return g_slice_dup (ClutterEventX11, event_x11);
86
87   return NULL;
88 }
89
90 void
91 _clutter_event_x11_free (ClutterEventX11 *event_x11)
92 {
93   if (event_x11 != NULL)
94     g_slice_free (ClutterEventX11, event_x11);
95 }
96
97 static gboolean clutter_event_prepare  (GSource     *source,
98                                         gint        *timeout);
99 static gboolean clutter_event_check    (GSource     *source);
100 static gboolean clutter_event_dispatch (GSource     *source,
101                                         GSourceFunc  callback,
102                                         gpointer     user_data);
103
104 static GSourceFuncs event_funcs = {
105   clutter_event_prepare,
106   clutter_event_check,
107   clutter_event_dispatch,
108   NULL
109 };
110
111 GSource *
112 _clutter_x11_event_source_new (ClutterBackendX11 *backend_x11)
113 {
114   ClutterEventSource *event_source;
115   int connection_number;
116   GSource *source;
117   gchar *name;
118
119   connection_number = ConnectionNumber (backend_x11->xdpy);
120   CLUTTER_NOTE (EVENT, "Connection number: %d", connection_number);
121
122   source = g_source_new (&event_funcs, sizeof (ClutterEventSource));
123   event_source = (ClutterEventSource *) source;
124
125   name = g_strdup_printf ("Clutter X11 Event (connection: %d)",
126                           connection_number);
127   g_source_set_name (source, name);
128   g_free (name);
129
130   event_source->backend = backend_x11;
131   event_source->event_poll_fd.fd = connection_number;
132   event_source->event_poll_fd.events = G_IO_IN;
133
134   g_source_add_poll (source, &event_source->event_poll_fd);
135   g_source_set_can_recurse (source, TRUE);
136
137   return source;
138 }
139
140 /**
141  * clutter_x11_handle_event:
142  * @xevent: pointer to XEvent structure
143  *
144  * This function processes a single X event; it can be used to hook
145  * into external X11 event processing (for example, a GDK filter
146  * function).
147  *
148  * If clutter_x11_disable_event_retrieval() has been called, you must
149  * let this function process events to update Clutter's internal state.
150  *
151  * Return value: #ClutterX11FilterReturn. %CLUTTER_X11_FILTER_REMOVE
152  *  indicates that Clutter has internally handled the event and the
153  *  caller should do no further processing. %CLUTTER_X11_FILTER_CONTINUE
154  *  indicates that Clutter is either not interested in the event,
155  *  or has used the event to update internal state without taking
156  *  any exclusive action. %CLUTTER_X11_FILTER_TRANSLATE will not
157  *  occur.
158  *
159  * Since: 0.8
160  */
161 ClutterX11FilterReturn
162 clutter_x11_handle_event (XEvent *xevent)
163 {
164   ClutterX11FilterReturn result;
165   ClutterBackend *backend;
166   ClutterEvent *event;
167   gint spin = 1;
168 #ifdef HAVE_XGE
169   ClutterBackendX11 *backend_x11;
170   Display *xdisplay;
171   gboolean allocated_event;
172 #endif
173
174   /* The return values here are someone approximate; we return
175    * CLUTTER_X11_FILTER_REMOVE if a clutter event is
176    * generated for the event. This mostly, but not entirely,
177    * corresponds to whether other event processing should be
178    * excluded. As long as the stage window is not shared with another
179    * toolkit it should be safe, and never return
180    * %CLUTTER_X11_FILTER_REMOVE when more processing is needed.
181    */
182
183   result = CLUTTER_X11_FILTER_CONTINUE;
184
185   clutter_threads_enter ();
186
187   backend = clutter_get_default_backend ();
188
189   event = clutter_event_new (CLUTTER_NOTHING);
190
191 #ifdef HAVE_XGE
192   backend_x11 = CLUTTER_BACKEND_X11 (backend);
193   xdisplay = backend_x11->xdpy;
194
195   allocated_event = XGetEventData (xdisplay, &xevent->xcookie);
196 #endif
197
198   if (_clutter_backend_translate_event (backend, xevent, event))
199     {
200       _clutter_event_push (event, FALSE);
201
202       result = CLUTTER_X11_FILTER_REMOVE;
203     }
204   else
205     {
206       clutter_event_free (event);
207       goto out;
208     }
209
210   /*
211    * Motion events can generate synthetic enter and leave events, so if we
212    * are processing a motion event, we need to spin the event loop at least
213    * two extra times to pump the enter/leave events through (otherwise they
214    * just get pushed down the queue and never processed).
215    */
216   if (event->type == CLUTTER_MOTION)
217     spin += 2;
218
219   while (spin > 0 && (event = clutter_event_get ()))
220     {
221       /* forward the event into clutter for emission etc. */
222       clutter_do_event (event);
223       clutter_event_free (event);
224       --spin;
225     }
226
227 out:
228 #ifdef HAVE_XGE
229   if (allocated_event)
230     XFreeEventData (xdisplay, &xevent->xcookie);
231 #endif
232
233   clutter_threads_leave ();
234
235   return result;
236 }
237
238 static gboolean
239 clutter_event_prepare (GSource *source,
240                        gint    *timeout)
241 {
242   ClutterBackendX11 *backend = ((ClutterEventSource *) source)->backend;
243   gboolean retval;
244
245   clutter_threads_enter ();
246
247   *timeout = -1;
248   retval = (clutter_events_pending () || XPending (backend->xdpy));
249
250   clutter_threads_leave ();
251
252   return retval;
253 }
254
255 static gboolean
256 clutter_event_check (GSource *source)
257 {
258   ClutterEventSource *event_source = (ClutterEventSource *) source;
259   ClutterBackendX11 *backend = event_source->backend;
260   gboolean retval;
261
262   clutter_threads_enter ();
263
264   if (event_source->event_poll_fd.revents & G_IO_IN)
265     retval = (clutter_events_pending () || XPending (backend->xdpy));
266   else
267     retval = FALSE;
268
269   clutter_threads_leave ();
270
271   return retval;
272 }
273
274 static void
275 events_queue (ClutterBackendX11 *backend_x11)
276 {
277   ClutterBackend *backend = CLUTTER_BACKEND (backend_x11);
278   Display *xdisplay = backend_x11->xdpy;
279   ClutterEvent *event;
280   XEvent xevent;
281
282   while (!clutter_events_pending () && XPending (xdisplay))
283     {
284       XNextEvent (xdisplay, &xevent);
285
286       event = clutter_event_new (CLUTTER_NOTHING);
287
288 #ifdef HAVE_XGE
289       XGetEventData (xdisplay, &xevent.xcookie);
290 #endif
291
292       if (_clutter_backend_translate_event (backend, &xevent, event))
293         _clutter_event_push (event, FALSE);
294       else
295         clutter_event_free (event);
296
297 #ifdef HAVE_XGE
298       XFreeEventData (xdisplay, &xevent.xcookie);
299 #endif
300     }
301 }
302
303 static gboolean
304 clutter_event_dispatch (GSource     *source,
305                         GSourceFunc  callback,
306                         gpointer     user_data)
307 {
308   ClutterBackendX11 *backend = ((ClutterEventSource *) source)->backend;
309   ClutterEvent *event;
310
311   clutter_threads_enter ();
312
313   /*  Grab the event(s), translate and figure out double click.
314    *  The push onto queue (stack) if valid.
315   */
316   events_queue (backend);
317
318   /* Pop an event off the queue if any */
319   event = clutter_event_get ();
320   if (event != NULL)
321     {
322       /* forward the event into clutter for emission etc. */
323       clutter_do_event (event);
324       clutter_event_free (event);
325     }
326
327   clutter_threads_leave ();
328
329   return TRUE;
330 }
331
332 /**
333  * clutter_x11_get_current_event_time: (skip)
334  *
335  * Retrieves the timestamp of the last X11 event processed by
336  * Clutter. This might be different from the timestamp returned
337  * by clutter_get_current_event_time(), as Clutter may synthesize
338  * or throttle events.
339  *
340  * Return value: a timestamp, in milliseconds
341  *
342  * Since: 1.0
343  */
344 Time
345 clutter_x11_get_current_event_time (void)
346 {
347   ClutterBackend *backend = clutter_get_default_backend ();
348
349   return CLUTTER_BACKEND_X11 (backend)->last_event_time;
350 }
351
352 /**
353  * clutter_x11_event_get_key_group:
354  * @event: a #ClutterEvent of type %CLUTTER_KEY_PRESS or %CLUTTER_KEY_RELEASE
355  *
356  * Retrieves the group for the modifiers set in @event
357  *
358  * Return value: the group id
359  *
360  * Since: 1.4
361  */
362 gint
363 clutter_x11_event_get_key_group (const ClutterEvent *event)
364 {
365   ClutterEventX11 *event_x11;
366
367   g_return_val_if_fail (event != NULL, 0);
368   g_return_val_if_fail (event->type == CLUTTER_KEY_PRESS ||
369                         event->type == CLUTTER_KEY_RELEASE, 0);
370
371   event_x11 = _clutter_event_get_platform_data (event);
372   if (event_x11 == NULL)
373     return 0;
374
375   return event_x11->key_group;
376 }