1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 
3 /*
4  * Copyright (C) 2016 Red Hat
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19  * 02111-1307, USA.
20  *
21  * Written by:
22  *     Jonas Ådahl <jadahl@gmail.com>
23  */
24 
25 #include "config.h"
26 
27 #include <glib-object.h>
28 
29 #include "backends/meta-backend-private.h"
30 #include "backends/meta-renderer.h"
31 #include "backends/x11/meta-clutter-backend-x11.h"
32 #include "backends/x11/meta-keymap-x11.h"
33 #include "backends/x11/meta-seat-x11.h"
34 #include "backends/x11/meta-xkb-a11y-x11.h"
35 #include "backends/x11/nested/meta-stage-x11-nested.h"
36 #include "clutter/clutter-mutter.h"
37 #include "clutter/clutter.h"
38 #include "cogl/cogl-xlib.h"
39 #include "core/bell.h"
40 #include "meta/meta-backend.h"
41 
42 typedef struct _MetaX11EventFilter MetaX11EventFilter;
43 
44 struct _MetaX11EventFilter
45 {
46   MetaX11FilterFunc func;
47   gpointer data;
48 };
49 
50 G_DEFINE_TYPE (MetaClutterBackendX11, meta_clutter_backend_x11,
51                CLUTTER_TYPE_BACKEND)
52 
53 
54 /* atoms; remember to add the code that assigns the atom value to
55  * the member of the MetaClutterBackendX11 structure if you add an
56  * atom name here. do not change the order!
57  */
58 static const gchar *atom_names[] = {
59   "_NET_WM_PID",
60   "_NET_WM_PING",
61   "_NET_WM_STATE",
62   "_NET_WM_USER_TIME",
63   "WM_PROTOCOLS",
64   "WM_DELETE_WINDOW",
65   "_XEMBED",
66   "_XEMBED_INFO",
67   "_NET_WM_NAME",
68   "UTF8_STRING",
69 };
70 
71 #define N_ATOM_NAMES G_N_ELEMENTS (atom_names)
72 
73 /* various flags corresponding to pre init setup calls */
74 static gboolean clutter_enable_xinput = TRUE;
75 static gboolean clutter_enable_stereo = FALSE;
76 static Display  *_foreign_dpy = NULL;
77 
78 /* options */
79 static gchar *clutter_display_name = NULL;
80 static gint clutter_screen = -1;
81 static gboolean clutter_synchronise = FALSE;
82 
83 /* X error trap */
84 static int TrappedErrorCode = 0;
85 static int (* old_error_handler) (Display *, XErrorEvent *);
86 
87 static MetaX11FilterReturn
cogl_xlib_filter(XEvent * xevent,ClutterEvent * event,gpointer data)88 cogl_xlib_filter (XEvent       *xevent,
89                   ClutterEvent *event,
90                   gpointer      data)
91 {
92   ClutterBackend *backend = data;
93   MetaX11FilterReturn retval;
94   CoglFilterReturn ret;
95 
96   ret = cogl_xlib_renderer_handle_event (backend->cogl_renderer, xevent);
97   switch (ret)
98     {
99     case COGL_FILTER_REMOVE:
100       retval = META_X11_FILTER_REMOVE;
101       break;
102 
103     case COGL_FILTER_CONTINUE:
104     default:
105       retval = META_X11_FILTER_CONTINUE;
106       break;
107     }
108 
109   return retval;
110 }
111 
112 static gboolean
meta_clutter_backend_x11_pre_parse(ClutterBackend * backend,GError ** error)113 meta_clutter_backend_x11_pre_parse (ClutterBackend  *backend,
114                                     GError         **error)
115 {
116   const gchar *env_string;
117 
118   /* we don't fail here if DISPLAY is not set, as the user
119    * might pass the --display command line switch
120    */
121   env_string = g_getenv ("DISPLAY");
122   if (env_string)
123     {
124       clutter_display_name = g_strdup (env_string);
125       env_string = NULL;
126     }
127 
128   env_string = g_getenv ("CLUTTER_DISABLE_XINPUT");
129   if (env_string)
130     {
131       clutter_enable_xinput = FALSE;
132       env_string = NULL;
133     }
134 
135   return TRUE;
136 }
137 
138 static gboolean
meta_clutter_backend_x11_post_parse(ClutterBackend * backend,GError ** error)139 meta_clutter_backend_x11_post_parse (ClutterBackend  *backend,
140                                      GError         **error)
141 {
142   MetaClutterBackendX11 *backend_x11 = META_CLUTTER_BACKEND_X11 (backend);
143   Atom atoms[N_ATOM_NAMES];
144 
145   if (_foreign_dpy)
146     backend_x11->xdisplay = _foreign_dpy;
147 
148   /* Only open connection if not already set by prior call to
149    * clutter_x11_set_display()
150    */
151   if (backend_x11->xdisplay == NULL)
152     {
153       if (clutter_display_name != NULL &&
154           *clutter_display_name != '\0')
155 	{
156 	  g_debug ("XOpenDisplay on '%s'", clutter_display_name);
157 
158 	  backend_x11->xdisplay = XOpenDisplay (clutter_display_name);
159           if (backend_x11->xdisplay == NULL)
160             {
161               g_set_error (error, CLUTTER_INIT_ERROR,
162                            CLUTTER_INIT_ERROR_BACKEND,
163                            "Unable to open display '%s'",
164                            clutter_display_name);
165               return FALSE;
166             }
167 	}
168       else
169 	{
170 	  g_set_error_literal (error, CLUTTER_INIT_ERROR,
171                                CLUTTER_INIT_ERROR_BACKEND,
172                                "Unable to open display. You have to set the "
173                                "DISPLAY environment variable, or use the "
174                                "--display command line argument");
175 	  return FALSE;
176 	}
177     }
178 
179   g_assert (backend_x11->xdisplay != NULL);
180 
181   g_debug ("Getting the X screen");
182 
183   /* add event filter for Cogl events */
184   meta_clutter_x11_add_filter (cogl_xlib_filter, backend);
185 
186   if (clutter_screen == -1)
187     backend_x11->xscreen = DefaultScreenOfDisplay (backend_x11->xdisplay);
188   else
189     backend_x11->xscreen = ScreenOfDisplay (backend_x11->xdisplay,
190                                             clutter_screen);
191 
192   backend_x11->xscreen_num = XScreenNumberOfScreen (backend_x11->xscreen);
193   backend_x11->xscreen_width = WidthOfScreen (backend_x11->xscreen);
194   backend_x11->xscreen_height = HeightOfScreen (backend_x11->xscreen);
195 
196   backend_x11->xwin_root = RootWindow (backend_x11->xdisplay,
197                                        backend_x11->xscreen_num);
198 
199   backend_x11->display_name = g_strdup (clutter_display_name);
200 
201   if (clutter_synchronise)
202     XSynchronize (backend_x11->xdisplay, True);
203 
204   XInternAtoms (backend_x11->xdisplay,
205                 (char **) atom_names, N_ATOM_NAMES,
206                 False, atoms);
207 
208   backend_x11->atom_NET_WM_PID = atoms[0];
209   backend_x11->atom_NET_WM_PING = atoms[1];
210   backend_x11->atom_NET_WM_STATE = atoms[2];
211   backend_x11->atom_NET_WM_USER_TIME = atoms[3];
212   backend_x11->atom_WM_PROTOCOLS = atoms[4];
213   backend_x11->atom_WM_DELETE_WINDOW = atoms[5];
214   backend_x11->atom_XEMBED = atoms[6];
215   backend_x11->atom_XEMBED_INFO = atoms[7];
216   backend_x11->atom_NET_WM_NAME = atoms[8];
217   backend_x11->atom_UTF8_STRING = atoms[9];
218 
219   g_free (clutter_display_name);
220 
221   g_debug ("X Display '%s'[%p] opened (screen:%d, root:%u, dpi:%f)",
222            backend_x11->display_name,
223            backend_x11->xdisplay,
224            backend_x11->xscreen_num,
225            (unsigned int) backend_x11->xwin_root,
226            clutter_backend_get_resolution (backend));
227 
228   return TRUE;
229 }
230 
231 static const GOptionEntry entries[] =
232 {
233   {
234     "display", 0,
235     G_OPTION_FLAG_IN_MAIN,
236     G_OPTION_ARG_STRING, &clutter_display_name,
237     N_("X display to use"), "DISPLAY"
238   },
239   {
240     "screen", 0,
241     G_OPTION_FLAG_IN_MAIN,
242     G_OPTION_ARG_INT, &clutter_screen,
243     N_("X screen to use"), "SCREEN"
244   },
245   { "synch", 0,
246     0,
247     G_OPTION_ARG_NONE, &clutter_synchronise,
248     N_("Make X calls synchronous"), NULL
249   },
250   {
251     "disable-xinput", 0,
252     G_OPTION_FLAG_REVERSE,
253     G_OPTION_ARG_NONE, &clutter_enable_xinput,
254     N_("Disable XInput support"), NULL
255   },
256   { NULL }
257 };
258 
259 static void
meta_clutter_backend_x11_add_options(ClutterBackend * backend,GOptionGroup * group)260 meta_clutter_backend_x11_add_options (ClutterBackend *backend,
261                                       GOptionGroup   *group)
262 {
263   g_option_group_add_entries (group, entries);
264 }
265 
266 static void
meta_clutter_backend_x11_finalize(GObject * gobject)267 meta_clutter_backend_x11_finalize (GObject *gobject)
268 {
269   MetaClutterBackendX11 *backend_x11 = META_CLUTTER_BACKEND_X11 (gobject);
270 
271   g_free (backend_x11->display_name);
272 
273   meta_clutter_x11_remove_filter (cogl_xlib_filter, gobject);
274 
275   XCloseDisplay (backend_x11->xdisplay);
276 
277   G_OBJECT_CLASS (meta_clutter_backend_x11_parent_class)->finalize (gobject);
278 }
279 
280 static ClutterFeatureFlags
meta_clutter_backend_x11_get_features(ClutterBackend * backend)281 meta_clutter_backend_x11_get_features (ClutterBackend *backend)
282 {
283   ClutterFeatureFlags flags = CLUTTER_FEATURE_STAGE_CURSOR;
284 
285   flags |=
286     CLUTTER_BACKEND_CLASS (meta_clutter_backend_x11_parent_class)->get_features (backend);
287 
288   return flags;
289 }
290 
291 static void
update_last_event_time(MetaClutterBackendX11 * backend_x11,XEvent * xevent)292 update_last_event_time (MetaClutterBackendX11 *backend_x11,
293                         XEvent                *xevent)
294 {
295   Time current_time = CurrentTime;
296   Time last_time = backend_x11->last_event_time;
297 
298   switch (xevent->type)
299     {
300     case KeyPress:
301     case KeyRelease:
302       current_time = xevent->xkey.time;
303       break;
304 
305     case ButtonPress:
306     case ButtonRelease:
307       current_time = xevent->xbutton.time;
308       break;
309 
310     case MotionNotify:
311       current_time = xevent->xmotion.time;
312       break;
313 
314     case EnterNotify:
315     case LeaveNotify:
316       current_time = xevent->xcrossing.time;
317       break;
318 
319     case PropertyNotify:
320       current_time = xevent->xproperty.time;
321       break;
322 
323     default:
324       break;
325     }
326 
327   /* only change the current event time if it's after the previous event
328    * time, or if it is at least 30 seconds earlier - in case the system
329    * clock was changed
330    */
331   if ((current_time != CurrentTime) &&
332       (current_time > last_time || (last_time - current_time > (30 * 1000))))
333     backend_x11->last_event_time = current_time;
334 }
335 
336 static gboolean
check_onscreen_template(CoglRenderer * renderer,CoglOnscreenTemplate * onscreen_template,gboolean enable_stereo,GError ** error)337 check_onscreen_template (CoglRenderer         *renderer,
338                          CoglOnscreenTemplate *onscreen_template,
339                          gboolean              enable_stereo,
340                          GError              **error)
341 {
342   GError *internal_error = NULL;
343 
344   cogl_onscreen_template_set_stereo_enabled (onscreen_template,
345 					     clutter_enable_stereo);
346 
347   /* cogl_renderer_check_onscreen_template() is actually just a
348    * shorthand for creating a CoglDisplay, and calling
349    * cogl_display_setup() on it, then throwing the display away. If we
350    * could just return that display, then it would be more efficient
351    * not to use cogl_renderer_check_onscreen_template(). However, the
352    * backend API requires that we return an CoglDisplay that has not
353    * yet been setup, so one way or the other we'll have to discard the
354    * first display and make a new fresh one.
355    */
356   if (cogl_renderer_check_onscreen_template (renderer, onscreen_template, &internal_error))
357     {
358       clutter_enable_stereo = enable_stereo;
359 
360       return TRUE;
361     }
362   else
363     {
364       g_set_error_literal (error, CLUTTER_INIT_ERROR,
365                            CLUTTER_INIT_ERROR_BACKEND,
366                            internal_error != NULL
367                            ? internal_error->message
368                            : "Creation of a CoglDisplay failed");
369 
370       g_clear_error (&internal_error);
371 
372       return FALSE;
373     }
374 }
375 
376 static CoglDisplay *
meta_clutter_backend_x11_get_display(ClutterBackend * backend,CoglRenderer * renderer,CoglSwapChain * swap_chain,GError ** error)377 meta_clutter_backend_x11_get_display (ClutterBackend  *backend,
378                                       CoglRenderer    *renderer,
379                                       CoglSwapChain   *swap_chain,
380                                       GError         **error)
381 {
382   CoglOnscreenTemplate *onscreen_template;
383   CoglDisplay *display = NULL;
384   gboolean res = FALSE;
385 
386   onscreen_template = cogl_onscreen_template_new (swap_chain);
387 
388   /* It's possible that the current renderer doesn't support transparency
389    * or doesn't support stereo, so we try the different combinations.
390    */
391   if (clutter_enable_stereo)
392     res = check_onscreen_template (renderer, onscreen_template,
393                                    TRUE, error);
394 
395   if (!res)
396     res = check_onscreen_template (renderer, onscreen_template,
397                                    FALSE, error);
398 
399   if (res)
400     display = cogl_display_new (renderer, onscreen_template);
401 
402   cogl_object_unref (onscreen_template);
403 
404   return display;
405 }
406 
407 static CoglRenderer *
meta_clutter_backend_x11_get_renderer(ClutterBackend * clutter_backend,GError ** error)408 meta_clutter_backend_x11_get_renderer (ClutterBackend  *clutter_backend,
409                                        GError         **error)
410 {
411   MetaBackend *backend = meta_get_backend ();
412   MetaRenderer *renderer = meta_backend_get_renderer (backend);
413 
414   return meta_renderer_create_cogl_renderer (renderer);
415 }
416 
417 static ClutterStageWindow *
meta_clutter_backend_x11_create_stage(ClutterBackend * backend,ClutterStage * wrapper,GError ** error)418 meta_clutter_backend_x11_create_stage (ClutterBackend  *backend,
419                                        ClutterStage    *wrapper,
420                                        GError         **error)
421 {
422   ClutterStageWindow *stage;
423   GType stage_type;
424 
425   if (meta_is_wayland_compositor ())
426     stage_type = META_TYPE_STAGE_X11_NESTED;
427   else
428     stage_type  = META_TYPE_STAGE_X11;
429 
430   stage = g_object_new (stage_type,
431 			"backend", backend,
432 			"wrapper", wrapper,
433 			NULL);
434   return stage;
435 }
436 
437 static gboolean
meta_clutter_backend_x11_process_event_filters(MetaClutterBackendX11 * backend_x11,gpointer native,ClutterEvent * event)438 meta_clutter_backend_x11_process_event_filters (MetaClutterBackendX11 *backend_x11,
439                                                 gpointer               native,
440                                                 ClutterEvent          *event)
441 {
442   XEvent *xevent = native;
443 
444   /* X11 filter functions have a higher priority */
445   if (backend_x11->event_filters != NULL)
446     {
447       GSList *node = backend_x11->event_filters;
448 
449       while (node != NULL)
450         {
451           MetaX11EventFilter *filter = node->data;
452 
453           switch (filter->func (xevent, event, filter->data))
454             {
455             case META_X11_FILTER_CONTINUE:
456               break;
457 
458             case META_X11_FILTER_TRANSLATE:
459               return TRUE;
460 
461             case META_X11_FILTER_REMOVE:
462               return FALSE;
463 
464             default:
465               break;
466             }
467 
468           node = node->next;
469         }
470     }
471 
472   return FALSE;
473 }
474 
475 static gboolean
meta_clutter_backend_x11_translate_event(ClutterBackend * clutter_backend,gpointer native,ClutterEvent * event)476 meta_clutter_backend_x11_translate_event (ClutterBackend *clutter_backend,
477                                           gpointer        native,
478                                           ClutterEvent   *event)
479 {
480   MetaClutterBackendX11 *backend_x11 =
481     META_CLUTTER_BACKEND_X11 (clutter_backend);
482   MetaBackend *backend = meta_get_backend ();
483   MetaStageX11 *stage_x11;
484   ClutterSeat *seat;
485 
486   if (meta_clutter_backend_x11_process_event_filters (backend_x11,
487                                                       native,
488                                                       event))
489     return TRUE;
490 
491   /* we update the event time only for events that can
492    * actually reach Clutter's event queue
493    */
494   update_last_event_time (backend_x11, native);
495 
496   stage_x11 =
497     META_STAGE_X11 (clutter_backend_get_stage_window (clutter_backend));
498   if (meta_stage_x11_translate_event (stage_x11, native, event))
499     return TRUE;
500 
501   seat = meta_backend_get_default_seat (backend);
502   if (meta_seat_x11_translate_event (META_SEAT_X11 (seat), native, event))
503     return TRUE;
504 
505   return FALSE;
506 }
507 
508 static ClutterSeat *
meta_clutter_backend_x11_get_default_seat(ClutterBackend * clutter_backend)509 meta_clutter_backend_x11_get_default_seat (ClutterBackend *clutter_backend)
510 {
511   MetaBackend *backend = meta_get_backend ();
512 
513   return meta_backend_get_default_seat (backend);
514 }
515 
516 static gboolean
meta_clutter_backend_x11_is_display_server(ClutterBackend * backend)517 meta_clutter_backend_x11_is_display_server (ClutterBackend *backend)
518 {
519   return meta_is_wayland_compositor ();
520 }
521 
522 static void
meta_clutter_backend_x11_init(MetaClutterBackendX11 * clutter_backend_x11)523 meta_clutter_backend_x11_init (MetaClutterBackendX11 *clutter_backend_x11)
524 {
525   clutter_backend_x11->last_event_time = CurrentTime;
526 }
527 
528 static void
meta_clutter_backend_x11_class_init(MetaClutterBackendX11Class * klass)529 meta_clutter_backend_x11_class_init (MetaClutterBackendX11Class *klass)
530 {
531   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
532   ClutterBackendClass *clutter_backend_class = CLUTTER_BACKEND_CLASS (klass);
533 
534   gobject_class->finalize = meta_clutter_backend_x11_finalize;
535 
536   clutter_backend_class->pre_parse = meta_clutter_backend_x11_pre_parse;
537   clutter_backend_class->post_parse = meta_clutter_backend_x11_post_parse;
538   clutter_backend_class->add_options = meta_clutter_backend_x11_add_options;
539   clutter_backend_class->get_features = meta_clutter_backend_x11_get_features;
540 
541   clutter_backend_class->get_display = meta_clutter_backend_x11_get_display;
542   clutter_backend_class->get_renderer = meta_clutter_backend_x11_get_renderer;
543   clutter_backend_class->create_stage = meta_clutter_backend_x11_create_stage;
544   clutter_backend_class->translate_event = meta_clutter_backend_x11_translate_event;
545   clutter_backend_class->get_default_seat = meta_clutter_backend_x11_get_default_seat;
546   clutter_backend_class->is_display_server = meta_clutter_backend_x11_is_display_server;
547 }
548 
549 static int
error_handler(Display * xdisplay,XErrorEvent * error)550 error_handler (Display     *xdisplay,
551                XErrorEvent *error)
552 {
553   TrappedErrorCode = error->error_code;
554   return 0;
555 }
556 
557 void
meta_clutter_x11_trap_x_errors(void)558 meta_clutter_x11_trap_x_errors (void)
559 {
560   TrappedErrorCode  = 0;
561   old_error_handler = XSetErrorHandler (error_handler);
562 }
563 
564 gint
meta_clutter_x11_untrap_x_errors(void)565 meta_clutter_x11_untrap_x_errors (void)
566 {
567   XSetErrorHandler (old_error_handler);
568 
569   return TrappedErrorCode;
570 }
571 
572 Display *
meta_clutter_x11_get_default_display(void)573 meta_clutter_x11_get_default_display (void)
574 {
575   ClutterBackend *backend = clutter_get_default_backend ();
576 
577   if (backend == NULL)
578     {
579       g_critical ("The Clutter backend has not been initialised");
580       return NULL;
581     }
582 
583   if (!META_IS_CLUTTER_BACKEND_X11 (backend))
584     {
585       g_critical ("The Clutter backend is not a X11 backend");
586       return NULL;
587     }
588 
589   return META_CLUTTER_BACKEND_X11 (backend)->xdisplay;
590 }
591 
592 void
meta_clutter_x11_set_display(Display * xdisplay)593 meta_clutter_x11_set_display (Display *xdisplay)
594 {
595   if (_clutter_context_is_initialized ())
596     {
597       g_warning ("%s() can only be used before calling clutter_init()",
598                  G_STRFUNC);
599       return;
600     }
601 
602   _foreign_dpy= xdisplay;
603 }
604 
605 int
meta_clutter_x11_get_default_screen(void)606 meta_clutter_x11_get_default_screen (void)
607 {
608  ClutterBackend *backend = clutter_get_default_backend ();
609 
610   if (backend == NULL)
611     {
612       g_critical ("The Clutter backend has not been initialised");
613       return 0;
614     }
615 
616   if (!META_IS_CLUTTER_BACKEND_X11 (backend))
617     {
618       g_critical ("The Clutter backend is not a X11 backend");
619       return 0;
620     }
621 
622   return META_CLUTTER_BACKEND_X11 (backend)->xscreen_num;
623 }
624 
625 Window
meta_clutter_x11_get_root_window(void)626 meta_clutter_x11_get_root_window (void)
627 {
628  ClutterBackend *backend = clutter_get_default_backend ();
629 
630   if (backend == NULL)
631     {
632       g_critical ("The Clutter backend has not been initialised");
633       return None;
634     }
635 
636   if (!META_IS_CLUTTER_BACKEND_X11 (backend))
637     {
638       g_critical ("The Clutter backend is not a X11 backend");
639       return None;
640     }
641 
642   return META_CLUTTER_BACKEND_X11 (backend)->xwin_root;
643 }
644 
645 void
meta_clutter_x11_add_filter(MetaX11FilterFunc func,gpointer data)646 meta_clutter_x11_add_filter (MetaX11FilterFunc func,
647                              gpointer             data)
648 {
649   MetaX11EventFilter *filter;
650   ClutterBackend *backend = clutter_get_default_backend ();
651   MetaClutterBackendX11 *backend_x11;
652 
653   g_return_if_fail (func != NULL);
654 
655   if (backend == NULL)
656     {
657       g_critical ("The Clutter backend has not been initialised");
658       return;
659     }
660 
661   if (!META_IS_CLUTTER_BACKEND_X11 (backend))
662     {
663       g_critical ("The Clutter backend is not a X11 backend");
664       return;
665     }
666 
667   backend_x11 = META_CLUTTER_BACKEND_X11 (backend);
668 
669   filter = g_new0 (MetaX11EventFilter, 1);
670   filter->func = func;
671   filter->data = data;
672 
673   backend_x11->event_filters =
674     g_slist_append (backend_x11->event_filters, filter);
675 
676   return;
677 }
678 
679 void
meta_clutter_x11_remove_filter(MetaX11FilterFunc func,gpointer data)680 meta_clutter_x11_remove_filter (MetaX11FilterFunc func,
681                                 gpointer          data)
682 {
683   GSList *tmp_list, *this;
684   MetaX11EventFilter *filter;
685   ClutterBackend *backend = clutter_get_default_backend ();
686   MetaClutterBackendX11 *backend_x11;
687 
688   g_return_if_fail (func != NULL);
689 
690   if (backend == NULL)
691     {
692       g_critical ("The Clutter backend has not been initialised");
693       return;
694     }
695 
696   if (!META_IS_CLUTTER_BACKEND_X11 (backend))
697     {
698       g_critical ("The Clutter backend is not a X11 backend");
699       return;
700     }
701 
702   backend_x11 = META_CLUTTER_BACKEND_X11 (backend);
703 
704   tmp_list = backend_x11->event_filters;
705 
706   while (tmp_list)
707     {
708       filter   = tmp_list->data;
709       this     =  tmp_list;
710       tmp_list = tmp_list->next;
711 
712       if (filter->func == func && filter->data == data)
713         {
714           backend_x11->event_filters =
715             g_slist_remove_link (backend_x11->event_filters, this);
716 
717           g_slist_free_1 (this);
718           g_free (filter);
719 
720           return;
721         }
722     }
723 }
724 
725 void
meta_clutter_x11_set_use_stereo_stage(gboolean use_stereo)726 meta_clutter_x11_set_use_stereo_stage (gboolean use_stereo)
727 {
728   if (_clutter_context_is_initialized ())
729     {
730       g_warning ("%s() can only be used before calling clutter_init()",
731                  G_STRFUNC);
732       return;
733     }
734 
735   g_debug ("STEREO stages are %s",
736            use_stereo ? "enabled" : "disabled");
737 
738   clutter_enable_stereo = use_stereo;
739 }
740 
741 gboolean
meta_clutter_x11_get_use_stereo_stage(void)742 meta_clutter_x11_get_use_stereo_stage (void)
743 {
744   return clutter_enable_stereo;
745 }
746