2 * An OpenGL based 'interactive canvas' library.
4 * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
5 * Copyright (C) 2009, 2010 Intel Corp.
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.
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.
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/>.
23 * Matthew Allum <mallum@openedhand.com>
24 * Emmanuele Bassi <ebassi@linux.intel.com>
29 #include "clutter-backend-x11.h"
30 #include "clutter-x11.h"
32 #include "clutter-backend-private.h"
33 #include "clutter-debug.h"
34 #include "clutter-event-private.h"
35 #include "clutter-main.h"
42 /* XEMBED protocol support for toolkit embedding */
43 #define XEMBED_MAPPED (1 << 0)
44 #define MAX_SUPPORTED_XEMBED_VERSION 1
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
61 static Window ParentEmbedderWin = None;
64 typedef struct _ClutterEventSource ClutterEventSource;
66 struct _ClutterEventSource
70 ClutterBackendX11 *backend;
72 GPollFD event_poll_fd;
76 _clutter_event_x11_new (void)
78 return g_slice_new0 (ClutterEventX11);
82 _clutter_event_x11_copy (ClutterEventX11 *event_x11)
84 if (event_x11 != NULL)
85 return g_slice_dup (ClutterEventX11, event_x11);
91 _clutter_event_x11_free (ClutterEventX11 *event_x11)
93 if (event_x11 != NULL)
94 g_slice_free (ClutterEventX11, event_x11);
97 static gboolean clutter_event_prepare (GSource *source,
99 static gboolean clutter_event_check (GSource *source);
100 static gboolean clutter_event_dispatch (GSource *source,
101 GSourceFunc callback,
104 static GSourceFuncs event_funcs = {
105 clutter_event_prepare,
107 clutter_event_dispatch,
112 _clutter_x11_event_source_new (ClutterBackendX11 *backend_x11)
114 ClutterEventSource *event_source;
115 int connection_number;
119 connection_number = ConnectionNumber (backend_x11->xdpy);
120 CLUTTER_NOTE (EVENT, "Connection number: %d", connection_number);
122 source = g_source_new (&event_funcs, sizeof (ClutterEventSource));
123 event_source = (ClutterEventSource *) source;
125 name = g_strdup_printf ("Clutter X11 Event (connection: %d)",
127 g_source_set_name (source, name);
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;
134 g_source_add_poll (source, &event_source->event_poll_fd);
135 g_source_set_can_recurse (source, TRUE);
141 * clutter_x11_handle_event:
142 * @xevent: pointer to XEvent structure
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
148 * If clutter_x11_disable_event_retrieval() has been called, you must
149 * let this function process events to update Clutter's internal state.
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
161 ClutterX11FilterReturn
162 clutter_x11_handle_event (XEvent *xevent)
164 ClutterX11FilterReturn result;
165 ClutterBackend *backend;
169 ClutterBackendX11 *backend_x11;
171 gboolean allocated_event;
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.
183 result = CLUTTER_X11_FILTER_CONTINUE;
185 clutter_threads_enter ();
187 backend = clutter_get_default_backend ();
189 event = clutter_event_new (CLUTTER_NOTHING);
192 backend_x11 = CLUTTER_BACKEND_X11 (backend);
193 xdisplay = backend_x11->xdpy;
195 allocated_event = XGetEventData (xdisplay, &xevent->xcookie);
198 if (_clutter_backend_translate_event (backend, xevent, event))
200 _clutter_event_push (event, FALSE);
202 result = CLUTTER_X11_FILTER_REMOVE;
206 clutter_event_free (event);
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).
216 if (event->type == CLUTTER_MOTION)
219 while (spin > 0 && (event = clutter_event_get ()))
221 /* forward the event into clutter for emission etc. */
222 clutter_do_event (event);
223 clutter_event_free (event);
230 XFreeEventData (xdisplay, &xevent->xcookie);
233 clutter_threads_leave ();
239 clutter_event_prepare (GSource *source,
242 ClutterBackendX11 *backend = ((ClutterEventSource *) source)->backend;
245 clutter_threads_enter ();
248 retval = (clutter_events_pending () || XPending (backend->xdpy));
250 clutter_threads_leave ();
256 clutter_event_check (GSource *source)
258 ClutterEventSource *event_source = (ClutterEventSource *) source;
259 ClutterBackendX11 *backend = event_source->backend;
262 clutter_threads_enter ();
264 if (event_source->event_poll_fd.revents & G_IO_IN)
265 retval = (clutter_events_pending () || XPending (backend->xdpy));
269 clutter_threads_leave ();
275 events_queue (ClutterBackendX11 *backend_x11)
277 ClutterBackend *backend = CLUTTER_BACKEND (backend_x11);
278 Display *xdisplay = backend_x11->xdpy;
282 while (!clutter_events_pending () && XPending (xdisplay))
284 XNextEvent (xdisplay, &xevent);
286 event = clutter_event_new (CLUTTER_NOTHING);
289 XGetEventData (xdisplay, &xevent.xcookie);
292 if (_clutter_backend_translate_event (backend, &xevent, event))
293 _clutter_event_push (event, FALSE);
295 clutter_event_free (event);
298 XFreeEventData (xdisplay, &xevent.xcookie);
304 clutter_event_dispatch (GSource *source,
305 GSourceFunc callback,
308 ClutterBackendX11 *backend = ((ClutterEventSource *) source)->backend;
311 clutter_threads_enter ();
313 /* Grab the event(s), translate and figure out double click.
314 * The push onto queue (stack) if valid.
316 events_queue (backend);
318 /* Pop an event off the queue if any */
319 event = clutter_event_get ();
322 /* forward the event into clutter for emission etc. */
323 clutter_do_event (event);
324 clutter_event_free (event);
327 clutter_threads_leave ();
333 * clutter_x11_get_current_event_time: (skip)
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.
340 * Return value: a timestamp, in milliseconds
345 clutter_x11_get_current_event_time (void)
347 ClutterBackend *backend = clutter_get_default_backend ();
349 return CLUTTER_BACKEND_X11 (backend)->last_event_time;
353 * clutter_x11_event_get_key_group:
354 * @event: a #ClutterEvent of type %CLUTTER_KEY_PRESS or %CLUTTER_KEY_RELEASE
356 * Retrieves the group for the modifiers set in @event
358 * Return value: the group id
363 clutter_x11_event_get_key_group (const ClutterEvent *event)
365 ClutterEventX11 *event_x11;
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);
371 event_x11 = _clutter_event_get_platform_data (event);
372 if (event_x11 == NULL)
375 return event_x11->key_group;