1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By:
7  *      Matthew Allum <mallum@openedhand.com>
8  *      Emmanuele Bassi <ebassi@linux.intel.com>
9  *
10  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
11  * Copyright (C) 2009, 2010 Intel Corp
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public
15  * License as published by the Free Software Foundation; either
16  * version 2 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public
24  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
25  */
26 
27 /**
28  * SECTION:clutter-backend
29  * @short_description: Backend abstraction
30  *
31  * Clutter can be compiled against different backends. Each backend
32  * has to implement a set of functions, in order to be used by Clutter.
33  *
34  * #ClutterBackend is the base class abstracting the various implementation;
35  * it provides a basic API to query the backend for generic information
36  * and settings.
37  *
38  * #ClutterBackend is available since Clutter 0.4
39  */
40 
41 #ifdef HAVE_CONFIG_H
42 #include "config.h"
43 #endif
44 
45 #define CLUTTER_ENABLE_EXPERIMENTAL_API
46 
47 #include "clutter-backend-private.h"
48 #include "clutter-debug.h"
49 #include "clutter-event-private.h"
50 #include "clutter-marshal.h"
51 #include "clutter-private.h"
52 #include "clutter-stage-manager-private.h"
53 #include "clutter-stage-private.h"
54 #include "clutter-stage-window.h"
55 #include "clutter-version.h"
56 #include "clutter-device-manager-private.h"
57 
58 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
59 #include "deprecated/clutter-backend.h"
60 
61 #ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
62 #include "wayland/clutter-wayland-compositor.h"
63 #endif
64 
65 #include <cogl/cogl.h>
66 
67 #ifdef CLUTTER_INPUT_X11
68 #include "x11/clutter-backend-x11.h"
69 #endif
70 #ifdef CLUTTER_INPUT_WIN32
71 #include "win32/clutter-backend-win32.h"
72 #endif
73 #ifdef CLUTTER_INPUT_OSX
74 #include "osx/clutter-backend-osx.h"
75 #endif
76 #ifdef CLUTTER_INPUT_GDK
77 #include "gdk/clutter-backend-gdk.h"
78 #endif
79 #ifdef CLUTTER_INPUT_EVDEV
80 #include "evdev/clutter-device-manager-evdev.h"
81 #endif
82 #ifdef CLUTTER_INPUT_TSLIB
83 /* XXX - should probably warn, here */
84 #include "tslib/clutter-event-tslib.h"
85 #endif
86 #ifdef CLUTTER_WINDOWING_EGL
87 #include "egl/clutter-backend-eglnative.h"
88 #endif
89 #ifdef CLUTTER_INPUT_WAYLAND
90 #include "wayland/clutter-device-manager-wayland.h"
91 #endif
92 #ifdef CLUTTER_WINDOWING_MIR
93 #include "mir/clutter-backend-mir.h"
94 #endif
95 #ifdef CLUTTER_INPUT_MIR
96 #include "mir/clutter-device-manager-mir.h"
97 #endif
98 
99 #ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
100 #include <cogl/cogl-wayland-server.h>
101 #include <wayland-server.h>
102 #include "wayland/clutter-wayland-compositor.h"
103 #endif
104 
105 #define DEFAULT_FONT_NAME       "Sans 10"
106 
107 enum
108 {
109   RESOLUTION_CHANGED,
110   FONT_CHANGED,
111   SETTINGS_CHANGED,
112 
113   LAST_SIGNAL
114 };
115 
116 G_DEFINE_ABSTRACT_TYPE (ClutterBackend, clutter_backend, G_TYPE_OBJECT)
117 
118 static guint backend_signals[LAST_SIGNAL] = { 0, };
119 
120 /* Global for being able to specify a compositor side wayland display
121  * pointer before clutter initialization */
122 #ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
123 static struct wl_display *_wayland_compositor_display;
124 #endif
125 
126 static void
clutter_backend_dispose(GObject * gobject)127 clutter_backend_dispose (GObject *gobject)
128 {
129   ClutterBackend *backend = CLUTTER_BACKEND (gobject);
130 
131   /* clear the events still in the queue of the main context */
132   _clutter_clear_events_queue ();
133 
134   /* remove all event translators */
135   g_clear_pointer (&backend->event_translators, g_list_free);
136 
137   g_clear_pointer (&backend->dummy_onscreen, cogl_object_unref);
138 
139   G_OBJECT_CLASS (clutter_backend_parent_class)->dispose (gobject);
140 }
141 
142 static void
clutter_backend_finalize(GObject * gobject)143 clutter_backend_finalize (GObject *gobject)
144 {
145   ClutterBackend *backend = CLUTTER_BACKEND (gobject);
146 
147   g_source_destroy (backend->cogl_source);
148 
149   g_free (backend->font_name);
150   clutter_backend_set_font_options (backend, NULL);
151 
152   G_OBJECT_CLASS (clutter_backend_parent_class)->finalize (gobject);
153 }
154 
155 static gfloat
get_units_per_em(ClutterBackend * backend,PangoFontDescription * font_desc)156 get_units_per_em (ClutterBackend       *backend,
157                   PangoFontDescription *font_desc)
158 {
159   gfloat units_per_em = -1.0;
160   gboolean free_font_desc = FALSE;
161   gdouble dpi;
162 
163   dpi = clutter_backend_get_resolution (backend);
164 
165   if (font_desc == NULL)
166     {
167       ClutterSettings *settings;
168       gchar *font_name = NULL;
169 
170       settings = clutter_settings_get_default ();
171       g_object_get (settings, "font-name", &font_name, NULL);
172 
173       if (G_LIKELY (font_name != NULL && *font_name != '\0'))
174         {
175           font_desc = pango_font_description_from_string (font_name);
176           free_font_desc = TRUE;
177 
178           g_free (font_name);
179         }
180     }
181 
182   if (font_desc != NULL)
183     {
184       gdouble font_size = 0;
185       gint pango_size;
186       gboolean is_absolute;
187 
188       pango_size = pango_font_description_get_size (font_desc);
189       is_absolute = pango_font_description_get_size_is_absolute (font_desc);
190 
191       /* "absolute" means "device units" (usually, pixels); otherwise,
192        * it means logical units (points)
193        */
194       if (is_absolute)
195         font_size = (gdouble) pango_size / PANGO_SCALE;
196       else
197         font_size = dpi * ((gdouble) pango_size / PANGO_SCALE) / 72.0f;
198 
199       /* 10 points at 96 DPI is 13.3 pixels */
200       units_per_em = (1.2f * font_size) * dpi / 96.0f;
201     }
202   else
203     units_per_em = -1.0f;
204 
205   if (free_font_desc)
206     pango_font_description_free (font_desc);
207 
208   return units_per_em;
209 }
210 
211 static void
clutter_backend_real_resolution_changed(ClutterBackend * backend)212 clutter_backend_real_resolution_changed (ClutterBackend *backend)
213 {
214   ClutterMainContext *context;
215   ClutterSettings *settings;
216   gdouble resolution;
217   gint dpi;
218 
219   settings = clutter_settings_get_default ();
220   g_object_get (settings, "font-dpi", &dpi, NULL);
221 
222   if (dpi < 0)
223     resolution = 96.0;
224   else
225     resolution = dpi / 1024.0;
226 
227   context = _clutter_context_get_default ();
228   if (context->font_map != NULL)
229     cogl_pango_font_map_set_resolution (context->font_map, resolution);
230 
231   backend->units_per_em = get_units_per_em (backend, NULL);
232   backend->units_serial += 1;
233 
234   CLUTTER_NOTE (BACKEND, "Units per em: %.2f", backend->units_per_em);
235 }
236 
237 static void
clutter_backend_real_font_changed(ClutterBackend * backend)238 clutter_backend_real_font_changed (ClutterBackend *backend)
239 {
240   backend->units_per_em = get_units_per_em (backend, NULL);
241   backend->units_serial += 1;
242 
243   CLUTTER_NOTE (BACKEND, "Units per em: %.2f", backend->units_per_em);
244 }
245 
246 static gboolean
clutter_backend_do_real_create_context(ClutterBackend * backend,CoglDriver driver_id,GError ** error)247 clutter_backend_do_real_create_context (ClutterBackend  *backend,
248                                         CoglDriver       driver_id,
249                                         GError         **error)
250 {
251   ClutterBackendClass *klass;
252   CoglSwapChain *swap_chain;
253   GError *internal_error;
254 
255   klass = CLUTTER_BACKEND_GET_CLASS (backend);
256 
257   swap_chain = NULL;
258   internal_error = NULL;
259 
260   CLUTTER_NOTE (BACKEND, "Creating Cogl renderer");
261   if (klass->get_renderer != NULL)
262     backend->cogl_renderer = klass->get_renderer (backend, &internal_error);
263   else
264     backend->cogl_renderer = cogl_renderer_new ();
265 
266   if (backend->cogl_renderer == NULL)
267     goto error;
268 
269 #ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
270   /* If the application is trying to act as a Wayland compositor then
271      it needs to have an EGL-based renderer backend */
272   if (_wayland_compositor_display)
273     cogl_renderer_add_constraint (backend->cogl_renderer,
274                                   COGL_RENDERER_CONSTRAINT_USES_EGL);
275 #endif
276 
277   CLUTTER_NOTE (BACKEND, "Connecting the renderer");
278   cogl_renderer_set_driver (backend->cogl_renderer, driver_id);
279   if (!cogl_renderer_connect (backend->cogl_renderer, &internal_error))
280     goto error;
281 
282   CLUTTER_NOTE (BACKEND, "Creating Cogl swap chain");
283   swap_chain = cogl_swap_chain_new ();
284 
285   CLUTTER_NOTE (BACKEND, "Creating Cogl display");
286   if (klass->get_display != NULL)
287     {
288       backend->cogl_display = klass->get_display (backend,
289                                                   backend->cogl_renderer,
290                                                   swap_chain,
291                                                   &internal_error);
292     }
293   else
294     {
295       CoglOnscreenTemplate *tmpl;
296       gboolean res;
297 
298       tmpl = cogl_onscreen_template_new (swap_chain);
299 
300       /* XXX: I have some doubts that this is a good design.
301        *
302        * Conceptually should we be able to check an onscreen_template
303        * without more details about the CoglDisplay configuration?
304        */
305       res = cogl_renderer_check_onscreen_template (backend->cogl_renderer,
306                                                    tmpl,
307                                                    &internal_error);
308 
309       if (!res)
310         goto error;
311 
312       backend->cogl_display = cogl_display_new (backend->cogl_renderer, tmpl);
313 
314       /* the display owns the template */
315       cogl_object_unref (tmpl);
316     }
317 
318   if (backend->cogl_display == NULL)
319     goto error;
320 
321 #ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
322   cogl_wayland_display_set_compositor_display (backend->cogl_display,
323                                                _wayland_compositor_display);
324 #endif
325 
326   CLUTTER_NOTE (BACKEND, "Setting up the display");
327   if (!cogl_display_setup (backend->cogl_display, &internal_error))
328     goto error;
329 
330   CLUTTER_NOTE (BACKEND, "Creating the Cogl context");
331   backend->cogl_context = cogl_context_new (backend->cogl_display, &internal_error);
332   if (backend->cogl_context == NULL)
333     goto error;
334 
335   /* the display owns the renderer and the swap chain */
336   cogl_object_unref (backend->cogl_renderer);
337   cogl_object_unref (swap_chain);
338 
339   return TRUE;
340 
341 error:
342   if (backend->cogl_display != NULL)
343     {
344       cogl_object_unref (backend->cogl_display);
345       backend->cogl_display = NULL;
346     }
347 
348   if (backend->cogl_renderer != NULL)
349     {
350       cogl_object_unref (backend->cogl_renderer);
351       backend->cogl_renderer = NULL;
352     }
353 
354   if (swap_chain != NULL)
355     cogl_object_unref (swap_chain);
356 
357   return FALSE;
358 }
359 
360 static const struct {
361   const char *driver_name;
362   const char *driver_desc;
363   CoglDriver driver_id;
364 } all_known_drivers[] = {
365   { "gl3", "OpenGL 3.2 core profile", COGL_DRIVER_GL3 },
366   { "gl", "OpenGL legacy profile", COGL_DRIVER_GL },
367   { "gles2", "OpenGL ES 2.0", COGL_DRIVER_GLES2 },
368   { "any", "Default Cogl driver", COGL_DRIVER_ANY },
369 };
370 
371 static const char *allowed_drivers;
372 
373 static gboolean
clutter_backend_real_create_context(ClutterBackend * backend,GError ** error)374 clutter_backend_real_create_context (ClutterBackend  *backend,
375                                      GError         **error)
376 {
377   GError *internal_error = NULL;
378   const char *drivers_list;
379   char **known_drivers;
380   gboolean allow_any;
381   int i;
382 
383   if (backend->cogl_context != NULL)
384     return TRUE;
385 
386   if (allowed_drivers == NULL)
387     allowed_drivers = CLUTTER_DRIVERS;
388 
389   allow_any = strstr (allowed_drivers, "*") != NULL;
390 
391   drivers_list = g_getenv ("CLUTTER_DRIVER");
392   if (drivers_list == NULL)
393     drivers_list = allowed_drivers;
394 
395   known_drivers = g_strsplit (drivers_list, ",", 0);
396 
397   for (i = 0; backend->cogl_context == NULL && known_drivers[i] != NULL; i++)
398     {
399       const char *driver_name = known_drivers[i];
400       gboolean is_any = g_str_equal (driver_name, "*");
401       int j;
402 
403       for (j = 0; j < G_N_ELEMENTS (all_known_drivers); j++)
404         {
405           if (!allow_any && !is_any && !strstr (driver_name, all_known_drivers[j].driver_name))
406             continue;
407 
408           if ((allow_any && is_any) ||
409               (is_any && strstr (allowed_drivers, all_known_drivers[j].driver_name)) ||
410               g_str_equal (all_known_drivers[j].driver_name, driver_name))
411             {
412               CLUTTER_NOTE (BACKEND, "Checking for the %s driver", all_known_drivers[j].driver_desc);
413 
414               if (clutter_backend_do_real_create_context (backend, all_known_drivers[j].driver_id, &internal_error))
415                 break;
416 
417               if (internal_error)
418                 {
419                   CLUTTER_NOTE (BACKEND, "Unable to use the %s driver: %s",
420                                 all_known_drivers[j].driver_desc,
421                                 internal_error->message);
422                   g_clear_error (&internal_error);
423                 }
424             }
425         }
426     }
427 
428   g_strfreev (known_drivers);
429 
430   if (backend->cogl_context == NULL)
431     {
432       if (internal_error != NULL)
433         g_propagate_error (error, internal_error);
434       else
435         g_set_error_literal (error, CLUTTER_INIT_ERROR,
436                              CLUTTER_INIT_ERROR_BACKEND,
437                             _("Unable to initialize the Clutter backend: no available drivers found."));
438 
439       return FALSE;
440     }
441 
442   backend->cogl_source = cogl_glib_source_new (backend->cogl_context, G_PRIORITY_DEFAULT);
443   g_source_attach (backend->cogl_source, NULL);
444 
445   return TRUE;
446 }
447 
448 static void
clutter_backend_real_ensure_context(ClutterBackend * backend,ClutterStage * stage)449 clutter_backend_real_ensure_context (ClutterBackend *backend,
450                                      ClutterStage   *stage)
451 {
452   ClutterStageWindow *stage_impl;
453   CoglFramebuffer *framebuffer;
454 
455   if (stage == NULL)
456     return;
457 
458   stage_impl = _clutter_stage_get_window (stage);
459   if (stage_impl == NULL)
460     return;
461 
462   framebuffer = _clutter_stage_window_get_active_framebuffer (stage_impl);
463   if (framebuffer == NULL)
464     return;
465 
466   cogl_set_framebuffer (framebuffer);
467 }
468 
469 static ClutterFeatureFlags
clutter_backend_real_get_features(ClutterBackend * backend)470 clutter_backend_real_get_features (ClutterBackend *backend)
471 {
472   ClutterFeatureFlags flags = 0;
473 
474   if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN))
475     {
476       CLUTTER_NOTE (BACKEND, "Cogl supports multiple onscreen framebuffers");
477       flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;
478     }
479   else
480     {
481       CLUTTER_NOTE (BACKEND, "Cogl only supports one onscreen framebuffer");
482       flags |= CLUTTER_FEATURE_STAGE_STATIC;
483     }
484 
485   if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_THROTTLE))
486     {
487       CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers throttling");
488       flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
489     }
490   else
491     CLUTTER_NOTE (BACKEND, "Cogl doesn't support swap buffers throttling");
492 
493   if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT))
494     {
495       CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers complete events");
496       flags |= CLUTTER_FEATURE_SWAP_EVENTS;
497     }
498 
499   return flags;
500 }
501 
502 static ClutterStageWindow *
clutter_backend_real_create_stage(ClutterBackend * backend,ClutterStage * wrapper,GError ** error)503 clutter_backend_real_create_stage (ClutterBackend  *backend,
504                                    ClutterStage    *wrapper,
505                                    GError         **error)
506 {
507   ClutterBackendClass *klass;
508 
509   if (!clutter_feature_available (CLUTTER_FEATURE_STAGE_MULTIPLE))
510     {
511       ClutterStageManager *manager = clutter_stage_manager_get_default ();
512 
513       if (clutter_stage_manager_get_default_stage (manager) != NULL)
514         {
515           g_set_error (error, CLUTTER_INIT_ERROR,
516                        CLUTTER_INIT_ERROR_BACKEND,
517                        _("The backend of type “%s” does not support "
518                          "creating multiple stages"),
519                        G_OBJECT_TYPE_NAME (backend));
520           return NULL;
521         }
522     }
523 
524   klass = CLUTTER_BACKEND_GET_CLASS (backend);
525   g_assert (klass->stage_window_type != G_TYPE_INVALID);
526 
527   return g_object_new (klass->stage_window_type,
528                        "backend", backend,
529                        "wrapper", wrapper,
530                        NULL);
531 }
532 
533 static const char *allowed_backends;
534 
535 static const struct {
536   const char *name;
537   ClutterBackend * (* create_backend) (void);
538 } available_backends[] = {
539 #ifdef CLUTTER_WINDOWING_OSX
540   { CLUTTER_WINDOWING_OSX, clutter_backend_osx_new },
541 #endif
542 #ifdef CLUTTER_WINDOWING_WIN32
543   { CLUTTER_WINDOWING_WIN32, clutter_backend_win32_new },
544 #endif
545 #ifdef CLUTTER_WINDOWING_GDK
546   { CLUTTER_WINDOWING_GDK, clutter_backend_gdk_new },
547 #endif
548 #ifdef CLUTTER_WINDOWING_WAYLAND
549   { CLUTTER_WINDOWING_WAYLAND, clutter_backend_wayland_new },
550 #endif
551 #ifdef CLUTTER_WINDOWING_X11
552   { CLUTTER_WINDOWING_X11, clutter_backend_x11_new },
553 #endif
554 #ifdef CLUTTER_WINDOWING_EGL
555   { CLUTTER_WINDOWING_EGL, clutter_backend_egl_native_new },
556 #endif
557 #ifdef CLUTTER_WINDOWING_MIR
558   { CLUTTER_WINDOWING_MIR, clutter_backend_mir_new },
559 #endif
560   { NULL, NULL },
561 };
562 
563 ClutterBackend *
_clutter_create_backend(void)564 _clutter_create_backend (void)
565 {
566   const char *backends_list;
567   ClutterBackend *retval;
568   gboolean allow_any;
569   char **backends;
570   int i;
571 
572   if (allowed_backends == NULL)
573     allowed_backends = "*";
574 
575   allow_any = strstr (allowed_backends, "*") != NULL;
576 
577   backends_list = g_getenv ("CLUTTER_BACKEND");
578   if (backends_list == NULL)
579     backends_list = allowed_backends;
580 
581   backends = g_strsplit (backends_list, ",", 0);
582 
583   retval = NULL;
584 
585   for (i = 0; retval == NULL && backends[i] != NULL; i++)
586     {
587       const char *backend = backends[i];
588       gboolean is_any = g_str_equal (backend, "*");
589       int j;
590 
591       for (j = 0; available_backends[j].name != NULL; j++)
592         {
593           if ((is_any && allow_any) ||
594               (is_any && strstr (allowed_backends, available_backends[j].name)) ||
595               g_str_equal (backend, available_backends[j].name))
596             {
597               retval = available_backends[j].create_backend ();
598               if (retval != NULL)
599                 break;
600             }
601         }
602     }
603 
604   g_strfreev (backends);
605 
606   if (retval == NULL)
607     g_error ("No default Clutter backend found.");
608 
609   return retval;
610 }
611 
612 static void
clutter_backend_real_init_events(ClutterBackend * backend)613 clutter_backend_real_init_events (ClutterBackend *backend)
614 {
615   const char *input_backend = NULL;
616 
617   input_backend = g_getenv ("CLUTTER_INPUT_BACKEND");
618   if (input_backend != NULL)
619     input_backend = g_intern_string (input_backend);
620 
621 #ifdef CLUTTER_INPUT_OSX
622   if (clutter_check_windowing_backend (CLUTTER_WINDOWING_OSX) &&
623       (input_backend == NULL || input_backend == I_(CLUTTER_INPUT_OSX)))
624     {
625       _clutter_backend_osx_events_init (backend);
626     }
627   else
628 #endif
629 #ifdef CLUTTER_INPUT_WIN32
630   if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WIN32) &&
631       (input_backend == NULL || input_backend == I_(CLUTTER_INPUT_WIN32)))
632     {
633       _clutter_backend_win32_events_init (backend);
634     }
635   else
636 #endif
637 #ifdef CLUTTER_INPUT_X11
638   if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11) &&
639       (input_backend == NULL || input_backend == I_(CLUTTER_INPUT_X11)))
640     {
641       _clutter_backend_x11_events_init (backend);
642     }
643   else
644 #endif
645 #ifdef CLUTTER_INPUT_GDK
646   if (clutter_check_windowing_backend (CLUTTER_WINDOWING_GDK) &&
647       (input_backend == NULL || input_backend == I_(CLUTTER_INPUT_GDK)))
648     {
649       _clutter_backend_gdk_events_init (backend);
650     }
651   else
652 #endif
653 #ifdef CLUTTER_INPUT_EVDEV
654   /* Evdev can be used regardless of the windowing system */
655   if ((input_backend != NULL && strcmp (input_backend, CLUTTER_INPUT_EVDEV) == 0)
656 #ifdef CLUTTER_WINDOWING_EGL
657       /* but we do want to always use it for EGL native */
658       || clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL)
659 #endif
660       )
661     {
662       _clutter_events_evdev_init (backend);
663     }
664   else
665 #endif
666 #ifdef CLUTTER_INPUT_TSLIB
667   /* Tslib can be used regardless of the windowing system */
668   if (input_backend != NULL &&
669       strcmp (input_backend, CLUTTER_INPUT_TSLIB) == 0)
670     {
671       _clutter_events_tslib_init (backend);
672     }
673   else
674 #endif
675 #ifdef CLUTTER_INPUT_WAYLAND
676   if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WAYLAND) &&
677       (input_backend == NULL || input_backend == I_(CLUTTER_INPUT_WAYLAND)))
678     {
679       _clutter_events_wayland_init (backend);
680     }
681   else
682 #endif
683 #ifdef CLUTTER_INPUT_MIR
684   if (clutter_check_windowing_backend (CLUTTER_WINDOWING_MIR) &&
685       (input_backend == NULL || input_backend == I_(CLUTTER_INPUT_MIR)))
686     {
687       _clutter_events_mir_init (backend);
688     }
689   else
690 #endif
691   if (input_backend != NULL)
692     {
693       if (input_backend != I_(CLUTTER_INPUT_NULL))
694         g_error ("Unrecognized input backend '%s'", input_backend);
695     }
696   else
697     g_error ("Unknown input backend");
698 }
699 
700 static ClutterDeviceManager *
clutter_backend_real_get_device_manager(ClutterBackend * backend)701 clutter_backend_real_get_device_manager (ClutterBackend *backend)
702 {
703   if (G_UNLIKELY (backend->device_manager == NULL))
704     {
705       g_critical ("No device manager available, expect broken input");
706       return NULL;
707     }
708 
709   return backend->device_manager;
710 }
711 
712 static gboolean
clutter_backend_real_translate_event(ClutterBackend * backend,gpointer native,ClutterEvent * event)713 clutter_backend_real_translate_event (ClutterBackend *backend,
714                                       gpointer        native,
715                                       ClutterEvent   *event)
716 {
717   GList *l;
718 
719   for (l = backend->event_translators;
720        l != NULL;
721        l = l->next)
722     {
723       ClutterEventTranslator *translator = l->data;
724       ClutterTranslateReturn retval;
725 
726       retval = _clutter_event_translator_translate_event (translator,
727                                                           native,
728                                                           event);
729 
730       if (retval == CLUTTER_TRANSLATE_QUEUE)
731         return TRUE;
732 
733       if (retval == CLUTTER_TRANSLATE_REMOVE)
734         return FALSE;
735     }
736 
737   return FALSE;
738 }
739 
740 static void
clutter_backend_class_init(ClutterBackendClass * klass)741 clutter_backend_class_init (ClutterBackendClass *klass)
742 {
743   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
744 
745   gobject_class->dispose = clutter_backend_dispose;
746   gobject_class->finalize = clutter_backend_finalize;
747 
748   klass->stage_window_type = G_TYPE_INVALID;
749 
750   /**
751    * ClutterBackend::resolution-changed:
752    * @backend: the #ClutterBackend that emitted the signal
753    *
754    * The ::resolution-changed signal is emitted each time the font
755    * resolutions has been changed through #ClutterSettings.
756    *
757    * Since: 1.0
758    */
759   backend_signals[RESOLUTION_CHANGED] =
760     g_signal_new (I_("resolution-changed"),
761                   G_TYPE_FROM_CLASS (klass),
762                   G_SIGNAL_RUN_FIRST,
763                   G_STRUCT_OFFSET (ClutterBackendClass, resolution_changed),
764                   NULL, NULL,
765                   _clutter_marshal_VOID__VOID,
766                   G_TYPE_NONE, 0);
767 
768   /**
769    * ClutterBackend::font-changed:
770    * @backend: the #ClutterBackend that emitted the signal
771    *
772    * The ::font-changed signal is emitted each time the font options
773    * have been changed through #ClutterSettings.
774    *
775    * Since: 1.0
776    */
777   backend_signals[FONT_CHANGED] =
778     g_signal_new (I_("font-changed"),
779                   G_TYPE_FROM_CLASS (klass),
780                   G_SIGNAL_RUN_FIRST,
781                   G_STRUCT_OFFSET (ClutterBackendClass, font_changed),
782                   NULL, NULL,
783                   _clutter_marshal_VOID__VOID,
784                   G_TYPE_NONE, 0);
785 
786   /**
787    * ClutterBackend::settings-changed:
788    * @backend: the #ClutterBackend that emitted the signal
789    *
790    * The ::settings-changed signal is emitted each time the #ClutterSettings
791    * properties have been changed.
792    *
793    * Since: 1.4
794    */
795   backend_signals[SETTINGS_CHANGED] =
796     g_signal_new (I_("settings-changed"),
797                   G_TYPE_FROM_CLASS (klass),
798                   G_SIGNAL_RUN_FIRST,
799                   G_STRUCT_OFFSET (ClutterBackendClass, settings_changed),
800                   NULL, NULL,
801                   _clutter_marshal_VOID__VOID,
802                   G_TYPE_NONE, 0);
803 
804   klass->resolution_changed = clutter_backend_real_resolution_changed;
805   klass->font_changed = clutter_backend_real_font_changed;
806 
807   klass->init_events = clutter_backend_real_init_events;
808   klass->get_device_manager = clutter_backend_real_get_device_manager;
809   klass->translate_event = clutter_backend_real_translate_event;
810   klass->create_context = clutter_backend_real_create_context;
811   klass->ensure_context = clutter_backend_real_ensure_context;
812   klass->get_features = clutter_backend_real_get_features;
813   klass->create_stage = clutter_backend_real_create_stage;
814 }
815 
816 static void
clutter_backend_init(ClutterBackend * self)817 clutter_backend_init (ClutterBackend *self)
818 {
819   self->units_per_em = -1.0;
820   self->units_serial = 1;
821 
822   self->dummy_onscreen = COGL_INVALID_HANDLE;
823 }
824 
825 void
_clutter_backend_add_options(ClutterBackend * backend,GOptionGroup * group)826 _clutter_backend_add_options (ClutterBackend *backend,
827                               GOptionGroup   *group)
828 {
829   ClutterBackendClass *klass;
830 
831   g_assert (CLUTTER_IS_BACKEND (backend));
832 
833   klass = CLUTTER_BACKEND_GET_CLASS (backend);
834   if (klass->add_options)
835     klass->add_options (backend, group);
836 }
837 
838 gboolean
_clutter_backend_pre_parse(ClutterBackend * backend,GError ** error)839 _clutter_backend_pre_parse (ClutterBackend  *backend,
840                             GError         **error)
841 {
842   ClutterBackendClass *klass;
843 
844   g_assert (CLUTTER_IS_BACKEND (backend));
845 
846   klass = CLUTTER_BACKEND_GET_CLASS (backend);
847   if (klass->pre_parse)
848     return klass->pre_parse (backend, error);
849 
850   return TRUE;
851 }
852 
853 gboolean
_clutter_backend_post_parse(ClutterBackend * backend,GError ** error)854 _clutter_backend_post_parse (ClutterBackend  *backend,
855                              GError         **error)
856 {
857   ClutterBackendClass *klass;
858 
859   g_assert (CLUTTER_IS_BACKEND (backend));
860 
861   klass = CLUTTER_BACKEND_GET_CLASS (backend);
862   if (klass->post_parse)
863     return klass->post_parse (backend, error);
864 
865   return TRUE;
866 }
867 
868 ClutterStageWindow *
_clutter_backend_create_stage(ClutterBackend * backend,ClutterStage * wrapper,GError ** error)869 _clutter_backend_create_stage (ClutterBackend  *backend,
870                                ClutterStage    *wrapper,
871                                GError         **error)
872 {
873   ClutterBackendClass *klass;
874   ClutterStageWindow *stage_window;
875 
876   g_assert (CLUTTER_IS_BACKEND (backend));
877   g_assert (CLUTTER_IS_STAGE (wrapper));
878 
879   klass = CLUTTER_BACKEND_GET_CLASS (backend);
880   if (klass->create_stage != NULL)
881     stage_window = klass->create_stage (backend, wrapper, error);
882   else
883     stage_window = NULL;
884 
885   if (stage_window == NULL)
886     return NULL;
887 
888   g_assert (CLUTTER_IS_STAGE_WINDOW (stage_window));
889 
890   return stage_window;
891 }
892 
893 gboolean
_clutter_backend_create_context(ClutterBackend * backend,GError ** error)894 _clutter_backend_create_context (ClutterBackend  *backend,
895                                  GError         **error)
896 {
897   ClutterBackendClass *klass;
898 
899   klass = CLUTTER_BACKEND_GET_CLASS (backend);
900 
901   return klass->create_context (backend, error);
902 }
903 
904 void
_clutter_backend_ensure_context_internal(ClutterBackend * backend,ClutterStage * stage)905 _clutter_backend_ensure_context_internal (ClutterBackend  *backend,
906                                           ClutterStage    *stage)
907 {
908   ClutterBackendClass *klass = CLUTTER_BACKEND_GET_CLASS (backend);
909   if (G_LIKELY (klass->ensure_context))
910     klass->ensure_context (backend, stage);
911 }
912 
913 void
_clutter_backend_ensure_context(ClutterBackend * backend,ClutterStage * stage)914 _clutter_backend_ensure_context (ClutterBackend *backend,
915                                  ClutterStage   *stage)
916 {
917   static ClutterStage *current_context_stage = NULL;
918 
919   g_assert (CLUTTER_IS_BACKEND (backend));
920   g_assert (CLUTTER_IS_STAGE (stage));
921 
922   if (current_context_stage != stage ||
923       !clutter_actor_is_realized (CLUTTER_ACTOR (stage)))
924     {
925       ClutterStage *new_stage = NULL;
926 
927       if (!clutter_actor_is_realized (CLUTTER_ACTOR (stage)))
928         {
929           new_stage = NULL;
930 
931           CLUTTER_NOTE (BACKEND,
932                         "Stage [%p] is not realized, unsetting the stage",
933                         stage);
934         }
935       else
936         {
937           new_stage = stage;
938 
939           CLUTTER_NOTE (BACKEND,
940                         "Setting the new stage [%p]",
941                         new_stage);
942         }
943 
944       /* XXX: Until Cogl becomes fully responsible for backend windows
945        * Clutter need to manually keep it informed of the current window size
946        *
947        * NB: This must be done after we ensure_context above because Cogl
948        * always assumes there is a current GL context.
949        */
950       if (new_stage != NULL)
951         {
952           float width, height;
953 
954           _clutter_backend_ensure_context_internal (backend, new_stage);
955 
956           clutter_actor_get_size (CLUTTER_ACTOR (stage), &width, &height);
957 
958           cogl_onscreen_clutter_backend_set_size (width, height);
959 
960           /* Eventually we will have a separate CoglFramebuffer for
961            * each stage and each one will track private projection
962            * matrix and viewport state, but until then we need to make
963            * sure we update the projection and viewport whenever we
964            * switch between stages.
965            *
966            * This dirty mechanism will ensure they are asserted before
967            * the next paint...
968            */
969           _clutter_stage_dirty_viewport (stage);
970           _clutter_stage_dirty_projection (stage);
971         }
972 
973       /* FIXME: With a NULL stage and thus no active context it may make more
974        * sense to clean the context but then re call with the default stage
975        * so at least there is some kind of context in place (as to avoid
976        * potential issue of GL calls with no context).
977        */
978       current_context_stage = new_stage;
979     }
980   else
981     CLUTTER_NOTE (BACKEND, "Stage is the same");
982 }
983 
984 
985 ClutterFeatureFlags
_clutter_backend_get_features(ClutterBackend * backend)986 _clutter_backend_get_features (ClutterBackend *backend)
987 {
988   ClutterBackendClass *klass;
989   GError *error;
990 
991   g_assert (CLUTTER_IS_BACKEND (backend));
992 
993   klass = CLUTTER_BACKEND_GET_CLASS (backend);
994 
995   /* we need to have a context here; so we create the
996    * GL context first and the ask for features. if the
997    * context already exists this should be a no-op
998    */
999   error = NULL;
1000   if (klass->create_context != NULL)
1001     {
1002       gboolean res;
1003 
1004       res = klass->create_context (backend, &error);
1005       if (!res)
1006         {
1007           if (error)
1008             {
1009               g_critical ("Unable to create a context: %s", error->message);
1010               g_error_free (error);
1011             }
1012           else
1013             g_critical ("Unable to create a context: unknown error");
1014 
1015           return 0;
1016         }
1017     }
1018 
1019   if (klass->get_features)
1020     return klass->get_features (backend);
1021 
1022   return 0;
1023 }
1024 
1025 void
_clutter_backend_init_events(ClutterBackend * backend)1026 _clutter_backend_init_events (ClutterBackend *backend)
1027 {
1028   ClutterBackendClass *klass;
1029 
1030   g_assert (CLUTTER_IS_BACKEND (backend));
1031 
1032   klass = CLUTTER_BACKEND_GET_CLASS (backend);
1033   klass->init_events (backend);
1034 }
1035 
1036 gfloat
_clutter_backend_get_units_per_em(ClutterBackend * backend,PangoFontDescription * font_desc)1037 _clutter_backend_get_units_per_em (ClutterBackend       *backend,
1038                                    PangoFontDescription *font_desc)
1039 {
1040   /* recompute for the font description, but do not cache the result */
1041   if (font_desc != NULL)
1042     return get_units_per_em (backend, font_desc);
1043 
1044   if (backend->units_per_em < 0)
1045     backend->units_per_em = get_units_per_em (backend, NULL);
1046 
1047   return backend->units_per_em;
1048 }
1049 
1050 void
_clutter_backend_copy_event_data(ClutterBackend * backend,const ClutterEvent * src,ClutterEvent * dest)1051 _clutter_backend_copy_event_data (ClutterBackend     *backend,
1052                                   const ClutterEvent *src,
1053                                   ClutterEvent       *dest)
1054 {
1055   ClutterEventExtenderInterface *iface;
1056   ClutterBackendClass *klass;
1057 
1058   klass = CLUTTER_BACKEND_GET_CLASS (backend);
1059   if (CLUTTER_IS_EVENT_EXTENDER (backend->device_manager))
1060     {
1061       iface = CLUTTER_EVENT_EXTENDER_GET_IFACE (backend->device_manager);
1062       iface->copy_event_data (CLUTTER_EVENT_EXTENDER (backend->device_manager),
1063                               src, dest);
1064     }
1065   else if (klass->copy_event_data != NULL)
1066     klass->copy_event_data (backend, src, dest);
1067 }
1068 
1069 void
_clutter_backend_free_event_data(ClutterBackend * backend,ClutterEvent * event)1070 _clutter_backend_free_event_data (ClutterBackend *backend,
1071                                   ClutterEvent   *event)
1072 {
1073   ClutterEventExtenderInterface *iface;
1074   ClutterBackendClass *klass;
1075 
1076   klass = CLUTTER_BACKEND_GET_CLASS (backend);
1077 
1078   if (CLUTTER_IS_EVENT_EXTENDER (backend->device_manager))
1079     {
1080       iface = CLUTTER_EVENT_EXTENDER_GET_IFACE (backend->device_manager);
1081       iface->free_event_data (CLUTTER_EVENT_EXTENDER (backend->device_manager),
1082                               event);
1083     }
1084   else if (klass->free_event_data != NULL)
1085     klass->free_event_data (backend, event);
1086 }
1087 
1088 /**
1089  * clutter_get_default_backend:
1090  *
1091  * Retrieves the default #ClutterBackend used by Clutter. The
1092  * #ClutterBackend holds backend-specific configuration options.
1093  *
1094  * Return value: (transfer none): the default backend. You should
1095  *   not ref or unref the returned object. Applications should rarely
1096  *   need to use this.
1097  *
1098  * Since: 0.4
1099  */
1100 ClutterBackend *
clutter_get_default_backend(void)1101 clutter_get_default_backend (void)
1102 {
1103   ClutterMainContext *clutter_context;
1104 
1105   clutter_context = _clutter_context_get_default ();
1106 
1107   return clutter_context->backend;
1108 }
1109 
1110 /**
1111  * clutter_backend_set_double_click_time:
1112  * @backend: a #ClutterBackend
1113  * @msec: milliseconds between two button press events
1114  *
1115  * Sets the maximum time between two button press events, used to
1116  * verify whether it's a double click event or not.
1117  *
1118  * Since: 0.4
1119  *
1120  * Deprecated: 1.4: Use #ClutterSettings:double-click-time instead
1121  */
1122 void
clutter_backend_set_double_click_time(ClutterBackend * backend,guint msec)1123 clutter_backend_set_double_click_time (ClutterBackend *backend,
1124                                        guint           msec)
1125 {
1126   ClutterSettings *settings = clutter_settings_get_default ();
1127 
1128   g_object_set (settings, "double-click-time", msec, NULL);
1129 }
1130 
1131 /**
1132  * clutter_backend_get_double_click_time:
1133  * @backend: a #ClutterBackend
1134  *
1135  * Gets the maximum time between two button press events, as set
1136  * by clutter_backend_set_double_click_time().
1137  *
1138  * Return value: a time in milliseconds
1139  *
1140  * Since: 0.4
1141  *
1142  * Deprecated: 1.4: Use #ClutterSettings:double-click-time instead
1143  */
1144 guint
clutter_backend_get_double_click_time(ClutterBackend * backend)1145 clutter_backend_get_double_click_time (ClutterBackend *backend)
1146 {
1147   ClutterSettings *settings = clutter_settings_get_default ();
1148   gint retval;
1149 
1150   g_object_get (settings, "double-click-time", &retval, NULL);
1151 
1152   return retval;
1153 }
1154 
1155 /**
1156  * clutter_backend_set_double_click_distance:
1157  * @backend: a #ClutterBackend
1158  * @distance: a distance, in pixels
1159  *
1160  * Sets the maximum distance used to verify a double click event.
1161  *
1162  * Since: 0.4
1163  *
1164  * Deprecated: 1.4: Use #ClutterSettings:double-click-distance instead
1165  */
1166 void
clutter_backend_set_double_click_distance(ClutterBackend * backend,guint distance)1167 clutter_backend_set_double_click_distance (ClutterBackend *backend,
1168                                            guint           distance)
1169 {
1170   ClutterSettings *settings = clutter_settings_get_default ();
1171 
1172   g_object_set (settings, "double-click-distance", distance, NULL);
1173 }
1174 
1175 /**
1176  * clutter_backend_get_double_click_distance:
1177  * @backend: a #ClutterBackend
1178  *
1179  * Retrieves the distance used to verify a double click event
1180  *
1181  * Return value: a distance, in pixels.
1182  *
1183  * Since: 0.4
1184  *
1185  * Deprecated: 1.4: Use #ClutterSettings:double-click-distance instead
1186  */
1187 guint
clutter_backend_get_double_click_distance(ClutterBackend * backend)1188 clutter_backend_get_double_click_distance (ClutterBackend *backend)
1189 {
1190   ClutterSettings *settings = clutter_settings_get_default ();
1191   gint retval;
1192 
1193   g_object_get (settings, "double-click-distance", &retval, NULL);
1194 
1195   return retval;
1196 }
1197 
1198 /**
1199  * clutter_backend_set_resolution:
1200  * @backend: a #ClutterBackend
1201  * @dpi: the resolution in "dots per inch" (Physical inches aren't
1202  *   actually involved; the terminology is conventional).
1203  *
1204  * Sets the resolution for font handling on the screen. This is a
1205  * scale factor between points specified in a #PangoFontDescription
1206  * and cairo units. The default value is 96, meaning that a 10 point
1207  * font will be 13 units high. (10 * 96. / 72. = 13.3).
1208  *
1209  * Applications should never need to call this function.
1210  *
1211  * Since: 0.4
1212  *
1213  * Deprecated: 1.4: Use #ClutterSettings:font-dpi instead
1214  */
1215 void
clutter_backend_set_resolution(ClutterBackend * backend,gdouble dpi)1216 clutter_backend_set_resolution (ClutterBackend *backend,
1217                                 gdouble         dpi)
1218 {
1219   ClutterSettings *settings;
1220   gint resolution;
1221 
1222   g_return_if_fail (CLUTTER_IS_BACKEND (backend));
1223 
1224   if (dpi < 0)
1225     resolution = -1;
1226   else
1227     resolution = dpi * 1024;
1228 
1229   settings = clutter_settings_get_default ();
1230   g_object_set (settings, "font-dpi", resolution, NULL);
1231 }
1232 
1233 /**
1234  * clutter_backend_get_resolution:
1235  * @backend: a #ClutterBackend
1236  *
1237  * Gets the resolution for font handling on the screen.
1238  *
1239  * The resolution is a scale factor between points specified in a
1240  * #PangoFontDescription and cairo units. The default value is 96.0,
1241  * meaning that a 10 point font will be 13 units
1242  * high (10 * 96. / 72. = 13.3).
1243  *
1244  * Clutter will set the resolution using the current backend when
1245  * initializing; the resolution is also stored in the
1246  * #ClutterSettings:font-dpi property.
1247  *
1248  * Return value: the current resolution, or -1 if no resolution
1249  *   has been set.
1250  *
1251  * Since: 0.4
1252  */
1253 gdouble
clutter_backend_get_resolution(ClutterBackend * backend)1254 clutter_backend_get_resolution (ClutterBackend *backend)
1255 {
1256   ClutterSettings *settings;
1257   gint resolution;
1258 
1259   g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), -1.0);
1260 
1261   settings = clutter_settings_get_default ();
1262   g_object_get (settings, "font-dpi", &resolution, NULL);
1263 
1264   if (resolution < 0)
1265     return 96.0;
1266 
1267   return resolution / 1024.0;
1268 }
1269 
1270 /**
1271  * clutter_backend_set_font_options:
1272  * @backend: a #ClutterBackend
1273  * @options: Cairo font options for the backend, or %NULL
1274  *
1275  * Sets the new font options for @backend. The #ClutterBackend will
1276  * copy the #cairo_font_options_t.
1277  *
1278  * If @options is %NULL, the first following call to
1279  * clutter_backend_get_font_options() will return the default font
1280  * options for @backend.
1281  *
1282  * This function is intended for actors creating a Pango layout
1283  * using the PangoCairo API.
1284  *
1285  * Since: 0.8
1286  */
1287 void
clutter_backend_set_font_options(ClutterBackend * backend,const cairo_font_options_t * options)1288 clutter_backend_set_font_options (ClutterBackend             *backend,
1289                                   const cairo_font_options_t *options)
1290 {
1291   g_return_if_fail (CLUTTER_IS_BACKEND (backend));
1292 
1293   if (backend->font_options != options)
1294     {
1295       if (backend->font_options)
1296         cairo_font_options_destroy (backend->font_options);
1297 
1298       if (options)
1299         backend->font_options = cairo_font_options_copy (options);
1300       else
1301         backend->font_options = NULL;
1302 
1303       g_signal_emit (backend, backend_signals[FONT_CHANGED], 0);
1304     }
1305 }
1306 
1307 /**
1308  * clutter_backend_get_font_options:
1309  * @backend: a #ClutterBackend
1310  *
1311  * Retrieves the font options for @backend.
1312  *
1313  * Return value: (transfer none): the font options of the #ClutterBackend.
1314  *   The returned #cairo_font_options_t is owned by the backend and should
1315  *   not be modified or freed
1316  *
1317  * Since: 0.8
1318  */
1319 const cairo_font_options_t *
clutter_backend_get_font_options(ClutterBackend * backend)1320 clutter_backend_get_font_options (ClutterBackend *backend)
1321 {
1322   g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), NULL);
1323 
1324   if (G_LIKELY (backend->font_options))
1325     return backend->font_options;
1326 
1327   backend->font_options = cairo_font_options_create ();
1328 
1329   cairo_font_options_set_hint_style (backend->font_options, CAIRO_HINT_STYLE_NONE);
1330   cairo_font_options_set_subpixel_order (backend->font_options, CAIRO_SUBPIXEL_ORDER_DEFAULT);
1331   cairo_font_options_set_antialias (backend->font_options, CAIRO_ANTIALIAS_DEFAULT);
1332 
1333   g_signal_emit (backend, backend_signals[FONT_CHANGED], 0);
1334 
1335   return backend->font_options;
1336 }
1337 
1338 /**
1339  * clutter_backend_set_font_name:
1340  * @backend: a #ClutterBackend
1341  * @font_name: the name of the font
1342  *
1343  * Sets the default font to be used by Clutter. The @font_name string
1344  * must either be %NULL, which means that the font name from the
1345  * default #ClutterBackend will be used; or be something that can
1346  * be parsed by the pango_font_description_from_string() function.
1347  *
1348  * Since: 1.0
1349  *
1350  * Deprecated: 1.4: Use #ClutterSettings:font-name instead
1351  */
1352 void
clutter_backend_set_font_name(ClutterBackend * backend,const gchar * font_name)1353 clutter_backend_set_font_name (ClutterBackend *backend,
1354                                const gchar    *font_name)
1355 {
1356   ClutterSettings *settings = clutter_settings_get_default ();
1357 
1358   g_object_set (settings, "font-name", font_name, NULL);
1359 }
1360 
1361 /**
1362  * clutter_backend_get_font_name:
1363  * @backend: a #ClutterBackend
1364  *
1365  * Retrieves the default font name as set by
1366  * clutter_backend_set_font_name().
1367  *
1368  * Return value: the font name for the backend. The returned string is
1369  *   owned by the #ClutterBackend and should never be modified or freed
1370  *
1371  * Since: 1.0
1372  *
1373  * Deprecated: 1.4: Use #ClutterSettings:font-name instead
1374  */
1375 const gchar *
clutter_backend_get_font_name(ClutterBackend * backend)1376 clutter_backend_get_font_name (ClutterBackend *backend)
1377 {
1378   ClutterSettings *settings;
1379 
1380   g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), NULL);
1381 
1382   settings = clutter_settings_get_default ();
1383 
1384   /* XXX yuck. but we return a const pointer, so we need to
1385    * store it in the backend
1386    */
1387   g_free (backend->font_name);
1388   g_object_get (settings, "font-name", &backend->font_name, NULL);
1389 
1390   return backend->font_name;
1391 }
1392 
1393 gint32
_clutter_backend_get_units_serial(ClutterBackend * backend)1394 _clutter_backend_get_units_serial (ClutterBackend *backend)
1395 {
1396   return backend->units_serial;
1397 }
1398 
1399 gboolean
_clutter_backend_translate_event(ClutterBackend * backend,gpointer native,ClutterEvent * event)1400 _clutter_backend_translate_event (ClutterBackend *backend,
1401                                   gpointer        native,
1402                                   ClutterEvent   *event)
1403 {
1404   return CLUTTER_BACKEND_GET_CLASS (backend)->translate_event (backend,
1405                                                                native,
1406                                                                event);
1407 }
1408 
1409 void
_clutter_backend_add_event_translator(ClutterBackend * backend,ClutterEventTranslator * translator)1410 _clutter_backend_add_event_translator (ClutterBackend         *backend,
1411                                        ClutterEventTranslator *translator)
1412 {
1413   if (g_list_find (backend->event_translators, translator) != NULL)
1414     return;
1415 
1416   backend->event_translators =
1417     g_list_prepend (backend->event_translators, translator);
1418 }
1419 
1420 void
_clutter_backend_remove_event_translator(ClutterBackend * backend,ClutterEventTranslator * translator)1421 _clutter_backend_remove_event_translator (ClutterBackend         *backend,
1422                                           ClutterEventTranslator *translator)
1423 {
1424   if (g_list_find (backend->event_translators, translator) == NULL)
1425     return;
1426 
1427   backend->event_translators =
1428     g_list_remove (backend->event_translators, translator);
1429 }
1430 
1431 /**
1432  * clutter_backend_get_cogl_context:
1433  * @backend: a #ClutterBackend
1434  *
1435  * Retrieves the #CoglContext associated with the given clutter
1436  * @backend. A #CoglContext is required when using some of the
1437  * experimental 2.0 Cogl API.
1438  *
1439  * Since CoglContext is itself experimental API this API should
1440  * be considered experimental too.
1441  *
1442  * This API is not yet supported on OSX because OSX still
1443  * uses the stub Cogl winsys and the Clutter backend doesn't
1444  * explicitly create a CoglContext.
1445  *
1446  * Return value: (transfer none): The #CoglContext associated with @backend.
1447  *
1448  * Since: 1.8
1449  * Stability: unstable
1450  */
1451 CoglContext *
clutter_backend_get_cogl_context(ClutterBackend * backend)1452 clutter_backend_get_cogl_context (ClutterBackend *backend)
1453 {
1454   return backend->cogl_context;
1455 }
1456 
1457 #ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
1458 /**
1459  * clutter_wayland_set_compositor_display:
1460  * @display: A compositor side struct wl_display pointer
1461  *
1462  * This informs Clutter of your compositor side Wayland display
1463  * object. This must be called before calling clutter_init().
1464  *
1465  * Since: 1.8
1466  * Stability: unstable
1467  */
1468 void
clutter_wayland_set_compositor_display(void * display)1469 clutter_wayland_set_compositor_display (void *display)
1470 {
1471   if (_clutter_context_is_initialized ())
1472     {
1473       g_warning ("%s() can only be used before calling clutter_init()",
1474                  G_STRFUNC);
1475       return;
1476     }
1477 
1478   _wayland_compositor_display = display;
1479 }
1480 #endif
1481 
1482 /**
1483  * clutter_set_windowing_backend:
1484  * @backend_type: a comma separated list of windowing backends
1485  *
1486  * Restricts Clutter to only use the specified backend or list of backends.
1487  *
1488  * You can use one of the `CLUTTER_WINDOWING_*` symbols, e.g.
1489  *
1490  * |[<!-- language="C" -->
1491  *   clutter_set_windowing_backend (CLUTTER_WINDOWING_X11);
1492  * ]|
1493  *
1494  * Will force Clutter to use the X11 windowing and input backend, and terminate
1495  * if the X11 backend could not be initialized successfully.
1496  *
1497  * Since Clutter 1.26, you can also use a comma-separated list of windowing
1498  * system backends to provide a fallback in case backends are not available or
1499  * enabled, e.g.:
1500  *
1501  * |[<!-- language="C" -->
1502  *   clutter_set_windowing_backend ("gdk,wayland,x11");
1503  * ]|
1504  *
1505  * Will make Clutter test for the GDK, Wayland, and X11 backends in that order.
1506  *
1507  * You can use the `*` special value to ask Clutter to use the internally
1508  * defined list of backends. For instance:
1509  *
1510  * |[<!-- language="C" -->
1511  *   clutter_set_windowing_backend ("x11,wayland,*");
1512  * ]|
1513  *
1514  * Will make Clutter test the X11 and Wayland backends, and then fall back
1515  * to the internal list of available backends.
1516  *
1517  * This function must be called before the first API call to Clutter, including
1518  * clutter_get_option_context()
1519  *
1520  * Since: 1.16
1521  */
1522 void
clutter_set_windowing_backend(const char * backend_type)1523 clutter_set_windowing_backend (const char *backend_type)
1524 {
1525   g_return_if_fail (backend_type != NULL);
1526 
1527   allowed_backends = g_strdup (backend_type);
1528 }
1529 
1530 void
clutter_try_set_windowing_backend(const char * backend_type)1531 clutter_try_set_windowing_backend (const char *backend_type)
1532 {
1533   if (allowed_backends == NULL)
1534     clutter_set_windowing_backend (backend_type);
1535 }
1536 
1537 PangoDirection
_clutter_backend_get_keymap_direction(ClutterBackend * backend)1538 _clutter_backend_get_keymap_direction (ClutterBackend *backend)
1539 {
1540   ClutterBackendClass *klass;
1541 
1542   klass = CLUTTER_BACKEND_GET_CLASS (backend);
1543   if (klass->get_keymap_direction != NULL)
1544     return klass->get_keymap_direction (backend);
1545 
1546   return PANGO_DIRECTION_NEUTRAL;
1547 }
1548 
1549 void
_clutter_backend_reset_cogl_framebuffer(ClutterBackend * backend)1550 _clutter_backend_reset_cogl_framebuffer (ClutterBackend *backend)
1551 {
1552   if (backend->dummy_onscreen == COGL_INVALID_HANDLE)
1553     {
1554       CoglError *internal_error = NULL;
1555 
1556       backend->dummy_onscreen = cogl_onscreen_new (backend->cogl_context, 1, 1);
1557 
1558       if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (backend->dummy_onscreen),
1559                                       &internal_error))
1560         {
1561           g_critical ("Unable to create dummy onscreen: %s", internal_error->message);
1562           cogl_error_free (internal_error);
1563           return;
1564         }
1565     }
1566 
1567   cogl_set_framebuffer (COGL_FRAMEBUFFER (backend->dummy_onscreen));
1568 }
1569 
1570 void
clutter_set_allowed_drivers(const char * drivers)1571 clutter_set_allowed_drivers (const char *drivers)
1572 {
1573   if (_clutter_context_is_initialized ())
1574     {
1575       g_warning ("Clutter has already been initialized.\n");
1576       return;
1577     }
1578 
1579   allowed_drivers = g_strdup (drivers);
1580 }
1581