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