Release Clutter 1.11.4 (snapshot)
[profile/ivi/clutter.git] / clutter / clutter-backend.c
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-profile.h"
53 #include "clutter-stage-manager-private.h"
54 #include "clutter-stage-private.h"
55 #include "clutter-stage-window.h"
56 #include "clutter-version.h"
57
58 #ifdef HAVE_CLUTTER_WAYLAND_COMPOSITOR
59 #include "wayland/clutter-wayland-compositor.h"
60 #endif /* HAVE_CLUTTER_WAYLAND_COMPOSITOR */
61
62 #include <cogl/cogl.h>
63
64 #ifdef CLUTTER_INPUT_X11
65 #include "x11/clutter-backend-x11.h"
66 #endif
67 #ifdef CLUTTER_INPUT_WIN32
68 #include "win32/clutter-backend-win32.h"
69 #endif
70 #ifdef CLUTTER_INPUT_OSX
71 #include "osx/clutter-backend-osx.h"
72 #endif
73 #ifdef CLUTTER_INPUT_GDK
74 #include "gdk/clutter-backend-gdk.h"
75 #endif
76 #ifdef CLUTTER_INPUT_EVDEV
77 #include "evdev/clutter-device-manager-evdev.h"
78 #endif
79 #ifdef CLUTTER_INPUT_TSLIB
80 /* XXX - should probably warn, here */
81 #include "tslib/clutter-event-tslib.h"
82 #endif
83 #ifdef CLUTTER_INPUT_WAYLAND
84 #include "wayland/clutter-device-manager-wayland.h"
85 #endif
86
87 #ifdef HAVE_CLUTTER_WAYLAND_COMPOSITOR
88 #include <cogl/cogl-wayland-server.h>
89 #include <wayland-server.h>
90 #include "wayland/clutter-wayland-compositor.h"
91 #endif
92
93 G_DEFINE_ABSTRACT_TYPE (ClutterBackend, clutter_backend, G_TYPE_OBJECT);
94
95 #define DEFAULT_FONT_NAME       "Sans 10"
96
97 #define CLUTTER_BACKEND_GET_PRIVATE(obj) \
98 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_BACKEND, ClutterBackendPrivate))
99
100 struct _ClutterBackendPrivate
101 {
102   cairo_font_options_t *font_options;
103
104   gchar *font_name;
105
106   gfloat units_per_em;
107   gint32 units_serial;
108
109   GList *event_translators;
110 };
111
112 enum
113 {
114   RESOLUTION_CHANGED,
115   FONT_CHANGED,
116   SETTINGS_CHANGED,
117
118   LAST_SIGNAL
119 };
120
121 static guint backend_signals[LAST_SIGNAL] = { 0, };
122
123 /* Global for being able to specify a compositor side wayland display
124  * pointer before clutter initialization */
125 #ifdef HAVE_CLUTTER_WAYLAND_COMPOSITOR
126 static struct wl_display *_wayland_compositor_display;
127 #endif
128
129
130 static void
131 clutter_backend_dispose (GObject *gobject)
132 {
133   ClutterBackendPrivate *priv = CLUTTER_BACKEND (gobject)->priv;
134
135   /* clear the events still in the queue of the main context */
136   _clutter_clear_events_queue ();
137
138   /* remove all event translators */
139   if (priv->event_translators != NULL)
140     {
141       g_list_free (priv->event_translators);
142       priv->event_translators = NULL;
143     }
144
145   G_OBJECT_CLASS (clutter_backend_parent_class)->dispose (gobject);
146 }
147
148 static void
149 clutter_backend_finalize (GObject *gobject)
150 {
151   ClutterBackend *backend = CLUTTER_BACKEND (gobject);
152
153   g_source_destroy (backend->cogl_source);
154
155   g_free (backend->priv->font_name);
156   clutter_backend_set_font_options (backend, NULL);
157
158   G_OBJECT_CLASS (clutter_backend_parent_class)->finalize (gobject);
159 }
160
161 static gfloat
162 get_units_per_em (ClutterBackend       *backend,
163                   PangoFontDescription *font_desc)
164 {
165   gfloat units_per_em = -1.0;
166   gboolean free_font_desc = FALSE;
167   gdouble dpi;
168
169   dpi = clutter_backend_get_resolution (backend);
170
171   if (font_desc == NULL)
172     {
173       ClutterSettings *settings;
174       gchar *font_name = NULL;
175
176       settings = clutter_settings_get_default ();
177       g_object_get (settings, "font-name", &font_name, NULL);
178
179       if (G_LIKELY (font_name != NULL && *font_name != '\0'))
180         {
181           font_desc = pango_font_description_from_string (font_name);
182           free_font_desc = TRUE;
183
184           g_free (font_name);
185         }
186     }
187
188   if (font_desc != NULL)
189     {
190       gdouble font_size = 0;
191       gint pango_size;
192       gboolean is_absolute;
193
194       pango_size = pango_font_description_get_size (font_desc);
195       is_absolute = pango_font_description_get_size_is_absolute (font_desc);
196
197       /* "absolute" means "device units" (usually, pixels); otherwise,
198        * it means logical units (points)
199        */
200       if (is_absolute)
201         font_size = (gdouble) pango_size / PANGO_SCALE;
202       else
203         font_size = dpi * ((gdouble) pango_size / PANGO_SCALE) / 72.0f;
204
205       /* 10 points at 96 DPI is 13.3 pixels */
206       units_per_em = (1.2f * font_size) * dpi / 96.0f;
207     }
208   else
209     units_per_em = -1.0f;
210
211   if (free_font_desc)
212     pango_font_description_free (font_desc);
213
214   return units_per_em;
215 }
216
217 static void
218 clutter_backend_real_resolution_changed (ClutterBackend *backend)
219 {
220   ClutterBackendPrivate *priv = backend->priv;
221   ClutterMainContext *context;
222   ClutterSettings *settings;
223   gdouble resolution;
224   gint dpi;
225
226   settings = clutter_settings_get_default ();
227   g_object_get (settings, "font-dpi", &dpi, NULL);
228
229   if (dpi < 0)
230     resolution = 96.0;
231   else
232     resolution = dpi / 1024.0;
233
234   context = _clutter_context_get_default ();
235   if (context->font_map != NULL)
236     cogl_pango_font_map_set_resolution (context->font_map, resolution);
237
238   priv->units_per_em = get_units_per_em (backend, NULL);
239   priv->units_serial += 1;
240
241   CLUTTER_NOTE (BACKEND, "Units per em: %.2f", priv->units_per_em);
242 }
243
244 static void
245 clutter_backend_real_font_changed (ClutterBackend *backend)
246 {
247   ClutterBackendPrivate *priv = backend->priv;
248
249   priv->units_per_em = get_units_per_em (backend, NULL);
250   priv->units_serial += 1;
251
252   CLUTTER_NOTE (BACKEND, "Units per em: %.2f", priv->units_per_em);
253 }
254
255 static gboolean
256 clutter_backend_real_create_context (ClutterBackend  *backend,
257                                      GError         **error)
258 {
259   ClutterBackendClass *klass;
260   CoglSwapChain *swap_chain;
261   GError *internal_error;
262
263   if (backend->cogl_context != NULL)
264     return TRUE;
265
266   klass = CLUTTER_BACKEND_GET_CLASS (backend);
267
268   swap_chain = NULL;
269   internal_error = NULL;
270
271   CLUTTER_NOTE (BACKEND, "Creating Cogl renderer");
272   if (klass->get_renderer != NULL)
273     backend->cogl_renderer = klass->get_renderer (backend, &internal_error);
274   else
275     backend->cogl_renderer = cogl_renderer_new ();
276
277   if (backend->cogl_renderer == NULL)
278     goto error;
279
280 #ifdef HAVE_CLUTTER_WAYLAND_COMPOSITOR
281   /* If the application is trying to act as a Wayland compositor then
282      it needs to have an EGL-based renderer backend */
283   if (_wayland_compositor_display)
284     cogl_renderer_add_constraint (backend->cogl_renderer,
285                                   COGL_RENDERER_CONSTRAINT_USES_EGL);
286 #endif
287
288   CLUTTER_NOTE (BACKEND, "Connecting the renderer");
289   if (!cogl_renderer_connect (backend->cogl_renderer, &internal_error))
290     goto error;
291
292   CLUTTER_NOTE (BACKEND, "Creating Cogl swap chain");
293   swap_chain = cogl_swap_chain_new ();
294
295   CLUTTER_NOTE (BACKEND, "Creating Cogl display");
296   if (klass->get_display != NULL)
297     {
298       backend->cogl_display = klass->get_display (backend,
299                                                   backend->cogl_renderer,
300                                                   swap_chain,
301                                                   &internal_error);
302     }
303   else
304     {
305       CoglOnscreenTemplate *tmpl;
306       gboolean res;
307
308       tmpl = cogl_onscreen_template_new (swap_chain);
309
310       /* XXX: I have some doubts that this is a good design.
311        *
312        * Conceptually should we be able to check an onscreen_template
313        * without more details about the CoglDisplay configuration?
314        */
315       res = cogl_renderer_check_onscreen_template (backend->cogl_renderer,
316                                                    tmpl,
317                                                    &internal_error);
318
319       if (!res)
320         goto error;
321
322       backend->cogl_display = cogl_display_new (backend->cogl_renderer, tmpl);
323
324       /* the display owns the template */
325       cogl_object_unref (tmpl);
326     }
327
328   if (backend->cogl_display == NULL)
329     goto error;
330
331 #ifdef HAVE_CLUTTER_WAYLAND_COMPOSITOR
332   cogl_wayland_display_set_compositor_display (backend->cogl_display,
333                                                _wayland_compositor_display);
334 #endif
335
336   CLUTTER_NOTE (BACKEND, "Setting up the display");
337   if (!cogl_display_setup (backend->cogl_display, &internal_error))
338     goto error;
339
340   CLUTTER_NOTE (BACKEND, "Creating the Cogl context");
341   backend->cogl_context = cogl_context_new (backend->cogl_display, &internal_error);
342   if (backend->cogl_context == NULL)
343     goto error;
344
345   backend->cogl_source = cogl_glib_source_new (backend->cogl_context,
346                                                G_PRIORITY_DEFAULT);
347   g_source_attach (backend->cogl_source, NULL);
348
349   /* the display owns the renderer and the swap chain */
350   cogl_object_unref (backend->cogl_renderer);
351   cogl_object_unref (swap_chain);
352
353   return TRUE;
354
355 error:
356   if (backend->cogl_display != NULL)
357     {
358       cogl_object_unref (backend->cogl_display);
359       backend->cogl_display = NULL;
360     }
361
362   if (backend->cogl_renderer != NULL)
363     {
364       cogl_object_unref (backend->cogl_renderer);
365       backend->cogl_renderer = NULL;
366     }
367
368   if (swap_chain != NULL)
369     cogl_object_unref (swap_chain);
370
371   if (internal_error != NULL)
372     g_propagate_error (error, internal_error);
373   else
374     g_set_error_literal (error, CLUTTER_INIT_ERROR,
375                          CLUTTER_INIT_ERROR_BACKEND,
376                          _("Unable to initialize the Clutter backend"));
377
378   return FALSE;
379 }
380
381 static void
382 clutter_backend_real_ensure_context (ClutterBackend *backend,
383                                      ClutterStage   *stage)
384 {
385   ClutterStageWindow *stage_impl;
386   CoglFramebuffer *framebuffer;
387
388   if (stage == NULL)
389     return;
390
391   stage_impl = _clutter_stage_get_window (stage);
392   if (stage_impl == NULL)
393     return;
394
395   framebuffer = _clutter_stage_window_get_active_framebuffer (stage_impl);
396   if (framebuffer == NULL)
397     return;
398
399   cogl_set_framebuffer (framebuffer);
400 }
401
402 static ClutterFeatureFlags
403 clutter_backend_real_get_features (ClutterBackend *backend)
404 {
405   ClutterFeatureFlags flags = 0;
406
407   if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN))
408     {
409       CLUTTER_NOTE (BACKEND, "Cogl supports multiple onscreen framebuffers");
410       flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;
411     }
412   else
413     {
414       CLUTTER_NOTE (BACKEND, "Cogl only supports one onscreen framebuffer");
415       flags |= CLUTTER_FEATURE_STAGE_STATIC;
416     }
417
418   if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_THROTTLE))
419     {
420       CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers throttling");
421       flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
422     }
423   else
424     CLUTTER_NOTE (BACKEND, "Cogl doesn't support swap buffers throttling");
425
426   if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT))
427     {
428       CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers complete events");
429       flags |= CLUTTER_FEATURE_SWAP_EVENTS;
430     }
431
432   return flags;
433 }
434
435 static ClutterStageWindow *
436 clutter_backend_real_create_stage (ClutterBackend  *backend,
437                                    ClutterStage    *wrapper,
438                                    GError         **error)
439 {
440   ClutterBackendClass *klass;
441
442   if (!clutter_feature_available (CLUTTER_FEATURE_STAGE_MULTIPLE))
443     {
444       ClutterStageManager *manager = clutter_stage_manager_get_default ();
445
446       if (clutter_stage_manager_get_default_stage (manager) != NULL)
447         {
448           g_set_error (error, CLUTTER_INIT_ERROR,
449                        CLUTTER_INIT_ERROR_BACKEND,
450                        _("The backend of type '%s' does not support "
451                          "creating multiple stages"),
452                        G_OBJECT_TYPE_NAME (backend));
453           return NULL;
454         }
455     }
456
457   klass = CLUTTER_BACKEND_GET_CLASS (backend);
458   g_assert (klass->stage_window_type != G_TYPE_INVALID);
459
460   return g_object_new (klass->stage_window_type,
461                        "backend", backend,
462                        "wrapper", wrapper,
463                        NULL);
464 }
465
466 static void
467 clutter_backend_real_init_events (ClutterBackend *backend)
468 {
469   const char *input_backend = NULL;
470
471   input_backend = g_getenv ("CLUTTER_INPUT_BACKEND");
472   if (input_backend != NULL)
473     input_backend = g_intern_string (input_backend);
474
475 #ifdef CLUTTER_INPUT_OSX
476   if (clutter_check_windowing_backend (CLUTTER_WINDOWING_OSX) &&
477       (input_backend == NULL || input_backend == I_(CLUTTER_INPUT_OSX)))
478     {
479       _clutter_backend_osx_events_init (backend);
480     }
481   else
482 #endif
483 #ifdef CLUTTER_INPUT_WIN32
484   if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WIN32) &&
485       (input_backend == NULL || input_backend == I_(CLUTTER_INPUT_WIN32)))
486     {
487       _clutter_backend_win32_events_init (backend);
488     }
489   else
490 #endif
491 #ifdef CLUTTER_INPUT_X11
492   if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11) &&
493       (input_backend == NULL || input_backend == I_(CLUTTER_INPUT_X11)))
494     {
495       _clutter_backend_x11_events_init (backend);
496     }
497   else
498 #endif
499 #ifdef CLUTTER_INPUT_GDK
500   if (clutter_check_windowing_backend (CLUTTER_WINDOWING_GDK) &&
501       (input_backend == NULL || input_backend == I_(CLUTTER_INPUT_GDK)))
502     {
503       _clutter_backend_gdk_events_init (backend);
504     }
505   else
506 #endif
507 #ifdef CLUTTER_INPUT_EVDEV
508   /* Evdev can be used regardless of the windowing system */
509   if (input_backend != NULL &&
510       strcmp (input_backend, CLUTTER_INPUT_EVDEV) == 0)
511     {
512       _clutter_events_evdev_init (backend);
513     }
514   else
515 #endif
516 #ifdef CLUTTER_INPUT_TSLIB
517   /* Tslib can be used regardless of the windowing system */
518   if (input_backend != NULL &&
519       strcmp (input_backend, CLUTTER_INPUT_TSLIB) == 0)
520     {
521       _clutter_events_tslib_init (backend);
522     }
523   else
524 #endif
525 #ifdef CLUTTER_INPUT_WAYLAND
526   if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WAYLAND) &&
527       (input_backend == NULL || input_backend == I_(CLUTTER_INPUT_WAYLAND)))
528     {
529       _clutter_events_wayland_init (backend);
530     }
531   else
532 #endif
533   if (input_backend != NULL)
534     {
535       if (input_backend != I_(CLUTTER_INPUT_NULL))
536         g_error ("Unrecognized input backend '%s'", input_backend);
537     }
538   else
539     g_error ("Unknown input backend");
540 }
541
542 static ClutterDeviceManager *
543 clutter_backend_real_get_device_manager (ClutterBackend *backend)
544 {
545   if (G_UNLIKELY (backend->device_manager == NULL))
546     {
547       g_critical ("No device manager available, expect broken input");
548       return NULL;
549     }
550
551   return backend->device_manager;
552 }
553
554 static gboolean
555 clutter_backend_real_translate_event (ClutterBackend *backend,
556                                       gpointer        native,
557                                       ClutterEvent   *event)
558 {
559   ClutterBackendPrivate *priv = backend->priv;
560   GList *l;
561
562   for (l = priv->event_translators;
563        l != NULL;
564        l = l->next)
565     {
566       ClutterEventTranslator *translator = l->data;
567       ClutterTranslateReturn retval;
568
569       retval = _clutter_event_translator_translate_event (translator,
570                                                           native,
571                                                           event);
572
573       if (retval == CLUTTER_TRANSLATE_QUEUE)
574         return TRUE;
575
576       if (retval == CLUTTER_TRANSLATE_REMOVE)
577         return FALSE;
578     }
579
580   return FALSE;
581 }
582
583 static void
584 clutter_backend_class_init (ClutterBackendClass *klass)
585 {
586   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
587
588   gobject_class->dispose = clutter_backend_dispose;
589   gobject_class->finalize = clutter_backend_finalize;
590
591   g_type_class_add_private (gobject_class, sizeof (ClutterBackendPrivate));
592
593   klass->stage_window_type = G_TYPE_INVALID;
594
595   /**
596    * ClutterBackend::resolution-changed:
597    * @backend: the #ClutterBackend that emitted the signal
598    *
599    * The ::resolution-changed signal is emitted each time the font
600    * resolutions has been changed through #ClutterSettings.
601    *
602    * Since: 1.0
603    */
604   backend_signals[RESOLUTION_CHANGED] =
605     g_signal_new (I_("resolution-changed"),
606                   G_TYPE_FROM_CLASS (klass),
607                   G_SIGNAL_RUN_FIRST,
608                   G_STRUCT_OFFSET (ClutterBackendClass, resolution_changed),
609                   NULL, NULL,
610                   _clutter_marshal_VOID__VOID,
611                   G_TYPE_NONE, 0);
612
613   /**
614    * ClutterBackend::font-changed:
615    * @backend: the #ClutterBackend that emitted the signal
616    *
617    * The ::font-changed signal is emitted each time the font options
618    * have been changed through #ClutterSettings.
619    *
620    * Since: 1.0
621    */
622   backend_signals[FONT_CHANGED] =
623     g_signal_new (I_("font-changed"),
624                   G_TYPE_FROM_CLASS (klass),
625                   G_SIGNAL_RUN_FIRST,
626                   G_STRUCT_OFFSET (ClutterBackendClass, font_changed),
627                   NULL, NULL,
628                   _clutter_marshal_VOID__VOID,
629                   G_TYPE_NONE, 0);
630
631   /**
632    * ClutterBackend::settings-changed:
633    * @backend: the #ClutterBackend that emitted the signal
634    *
635    * The ::settings-changed signal is emitted each time the #ClutterSettings
636    * properties have been changed.
637    *
638    * Since: 1.4
639    */
640   backend_signals[SETTINGS_CHANGED] =
641     g_signal_new (I_("settings-changed"),
642                   G_TYPE_FROM_CLASS (klass),
643                   G_SIGNAL_RUN_FIRST,
644                   G_STRUCT_OFFSET (ClutterBackendClass, settings_changed),
645                   NULL, NULL,
646                   _clutter_marshal_VOID__VOID,
647                   G_TYPE_NONE, 0);
648
649   klass->resolution_changed = clutter_backend_real_resolution_changed;
650   klass->font_changed = clutter_backend_real_font_changed;
651
652   klass->init_events = clutter_backend_real_init_events;
653   klass->get_device_manager = clutter_backend_real_get_device_manager;
654   klass->translate_event = clutter_backend_real_translate_event;
655   klass->create_context = clutter_backend_real_create_context;
656   klass->ensure_context = clutter_backend_real_ensure_context;
657   klass->get_features = clutter_backend_real_get_features;
658   klass->create_stage = clutter_backend_real_create_stage;
659 }
660
661 static void
662 clutter_backend_init (ClutterBackend *backend)
663 {
664   ClutterBackendPrivate *priv;
665
666   priv = backend->priv = CLUTTER_BACKEND_GET_PRIVATE (backend);
667
668   priv->units_per_em = -1.0;
669   priv->units_serial = 1;
670 }
671
672 void
673 _clutter_backend_add_options (ClutterBackend *backend,
674                               GOptionGroup   *group)
675 {
676   ClutterBackendClass *klass;
677
678   g_assert (CLUTTER_IS_BACKEND (backend));
679
680   klass = CLUTTER_BACKEND_GET_CLASS (backend);
681   if (klass->add_options)
682     klass->add_options (backend, group);
683 }
684
685 gboolean
686 _clutter_backend_pre_parse (ClutterBackend  *backend,
687                             GError         **error)
688 {
689   ClutterBackendClass *klass;
690
691   g_assert (CLUTTER_IS_BACKEND (backend));
692
693   klass = CLUTTER_BACKEND_GET_CLASS (backend);
694   if (klass->pre_parse)
695     return klass->pre_parse (backend, error);
696
697   return TRUE;
698 }
699
700 gboolean
701 _clutter_backend_post_parse (ClutterBackend  *backend,
702                              GError         **error)
703 {
704   ClutterBackendClass *klass;
705
706   g_assert (CLUTTER_IS_BACKEND (backend));
707
708   klass = CLUTTER_BACKEND_GET_CLASS (backend);
709   if (klass->post_parse)
710     return klass->post_parse (backend, error);
711
712   return TRUE;
713 }
714
715 ClutterStageWindow *
716 _clutter_backend_create_stage (ClutterBackend  *backend,
717                                ClutterStage    *wrapper,
718                                GError         **error)
719 {
720   ClutterBackendClass *klass;
721   ClutterStageWindow *stage_window;
722
723   g_assert (CLUTTER_IS_BACKEND (backend));
724   g_assert (CLUTTER_IS_STAGE (wrapper));
725
726   klass = CLUTTER_BACKEND_GET_CLASS (backend);
727   if (klass->create_stage != NULL)
728     stage_window = klass->create_stage (backend, wrapper, error);
729   else
730     stage_window = NULL;
731
732   if (stage_window == NULL)
733     return NULL;
734
735   g_assert (CLUTTER_IS_STAGE_WINDOW (stage_window));
736
737   return stage_window;
738 }
739
740 gboolean
741 _clutter_backend_create_context (ClutterBackend  *backend,
742                                  GError         **error)
743 {
744   ClutterBackendClass *klass;
745
746   klass = CLUTTER_BACKEND_GET_CLASS (backend);
747
748   return klass->create_context (backend, error);
749 }
750
751 void
752 _clutter_backend_ensure_context_internal (ClutterBackend  *backend,
753                                           ClutterStage    *stage)
754 {
755   ClutterBackendClass *klass = CLUTTER_BACKEND_GET_CLASS (backend);
756   if (G_LIKELY (klass->ensure_context))
757     klass->ensure_context (backend, stage);
758 }
759
760 void
761 _clutter_backend_ensure_context (ClutterBackend *backend,
762                                  ClutterStage   *stage)
763 {
764   static ClutterStage *current_context_stage = NULL;
765
766   g_assert (CLUTTER_IS_BACKEND (backend));
767   g_assert (CLUTTER_IS_STAGE (stage));
768
769   if (current_context_stage != stage || !CLUTTER_ACTOR_IS_REALIZED (stage))
770     {
771       ClutterStage *new_stage = NULL;
772
773       if (!CLUTTER_ACTOR_IS_REALIZED (stage))
774         {
775           new_stage = NULL;
776
777           CLUTTER_NOTE (BACKEND,
778                         "Stage [%p] is not realized, unsetting the stage",
779                         stage);
780         }
781       else
782         {
783           new_stage = stage;
784
785           CLUTTER_NOTE (BACKEND,
786                         "Setting the new stage [%p]",
787                         new_stage);
788         }
789
790       /* XXX: Until Cogl becomes fully responsible for backend windows
791        * Clutter need to manually keep it informed of the current window size
792        *
793        * NB: This must be done after we ensure_context above because Cogl
794        * always assumes there is a current GL context.
795        */
796       if (new_stage != NULL)
797         {
798           float width, height;
799
800           _clutter_backend_ensure_context_internal (backend, new_stage);
801
802           clutter_actor_get_size (CLUTTER_ACTOR (stage), &width, &height);
803
804           cogl_onscreen_clutter_backend_set_size (width, height);
805
806           /* Eventually we will have a separate CoglFramebuffer for
807            * each stage and each one will track private projection
808            * matrix and viewport state, but until then we need to make
809            * sure we update the projection and viewport whenever we
810            * switch between stages.
811            *
812            * This dirty mechanism will ensure they are asserted before
813            * the next paint...
814            */
815           _clutter_stage_dirty_viewport (stage);
816           _clutter_stage_dirty_projection (stage);
817         }
818
819       /* FIXME: With a NULL stage and thus no active context it may make more
820        * sense to clean the context but then re call with the default stage 
821        * so at least there is some kind of context in place (as to avoid
822        * potential issue of GL calls with no context).
823        */
824       current_context_stage = new_stage;
825     }
826   else
827     CLUTTER_NOTE (BACKEND, "Stage is the same");
828 }
829
830
831 ClutterFeatureFlags
832 _clutter_backend_get_features (ClutterBackend *backend)
833 {
834   ClutterBackendClass *klass;
835   GError *error;
836
837   g_assert (CLUTTER_IS_BACKEND (backend));
838
839   klass = CLUTTER_BACKEND_GET_CLASS (backend);
840
841   /* we need to have a context here; so we create the
842    * GL context first and the ask for features. if the
843    * context already exists this should be a no-op
844    */
845   error = NULL;
846   if (klass->create_context != NULL)
847     {
848       gboolean res;
849
850       res = klass->create_context (backend, &error);
851       if (!res)
852         {
853           if (error)
854             {
855               g_critical ("Unable to create a context: %s", error->message);
856               g_error_free (error);
857             }
858           else
859             g_critical ("Unable to create a context: unknown error");
860
861           return 0;
862         }
863     }
864
865   if (klass->get_features)
866     return klass->get_features (backend);
867   
868   return 0;
869 }
870
871 void
872 _clutter_backend_init_events (ClutterBackend *backend)
873 {
874   ClutterBackendClass *klass;
875
876   g_assert (CLUTTER_IS_BACKEND (backend));
877
878   klass = CLUTTER_BACKEND_GET_CLASS (backend);
879   klass->init_events (backend);
880 }
881
882 gfloat
883 _clutter_backend_get_units_per_em (ClutterBackend       *backend,
884                                    PangoFontDescription *font_desc)
885 {
886   ClutterBackendPrivate *priv;
887
888   priv = backend->priv;
889
890   /* recompute for the font description, but do not cache the result */
891   if (font_desc != NULL)
892     return get_units_per_em (backend, font_desc);
893
894   if (priv->units_per_em < 0)
895     priv->units_per_em = get_units_per_em (backend, NULL);
896
897   return priv->units_per_em;
898 }
899
900 void
901 _clutter_backend_copy_event_data (ClutterBackend     *backend,
902                                   const ClutterEvent *src,
903                                   ClutterEvent       *dest)
904 {
905   ClutterBackendClass *klass;
906
907   klass = CLUTTER_BACKEND_GET_CLASS (backend);
908   if (klass->copy_event_data != NULL)
909     klass->copy_event_data (backend, src, dest);
910 }
911
912 void
913 _clutter_backend_free_event_data (ClutterBackend *backend,
914                                   ClutterEvent   *event)
915 {
916   ClutterBackendClass *klass;
917
918   klass = CLUTTER_BACKEND_GET_CLASS (backend);
919   if (klass->free_event_data != NULL)
920     klass->free_event_data (backend, event);
921 }
922
923 /**
924  * clutter_get_default_backend:
925  *
926  * Retrieves the default #ClutterBackend used by Clutter. The
927  * #ClutterBackend holds backend-specific configuration options.
928  *
929  * Return value: (transfer none): the default backend. You should
930  *   not ref or unref the returned object. Applications should rarely
931  *   need to use this.
932  *
933  * Since: 0.4
934  */
935 ClutterBackend *
936 clutter_get_default_backend (void)
937 {
938   ClutterMainContext *clutter_context;
939
940   clutter_context = _clutter_context_get_default ();
941
942   return clutter_context->backend;
943 }
944
945 /**
946  * clutter_backend_set_double_click_time:
947  * @backend: a #ClutterBackend
948  * @msec: milliseconds between two button press events
949  *
950  * Sets the maximum time between two button press events, used to
951  * verify whether it's a double click event or not.
952  *
953  * Since: 0.4
954  *
955  * Deprecated: 1.4: Use #ClutterSettings:double-click-time instead
956  */
957 void
958 clutter_backend_set_double_click_time (ClutterBackend *backend,
959                                        guint           msec)
960 {
961   ClutterSettings *settings = clutter_settings_get_default ();
962
963   g_object_set (settings, "double-click-time", msec, NULL);
964 }
965
966 /**
967  * clutter_backend_get_double_click_time:
968  * @backend: a #ClutterBackend
969  *
970  * Gets the maximum time between two button press events, as set
971  * by clutter_backend_set_double_click_time().
972  *
973  * Return value: a time in milliseconds
974  *
975  * Since: 0.4
976  *
977  * Deprecated: 1.4: Use #ClutterSettings:double-click-time instead
978  */
979 guint
980 clutter_backend_get_double_click_time (ClutterBackend *backend)
981 {
982   ClutterSettings *settings = clutter_settings_get_default ();
983   gint retval;
984
985   g_object_get (settings, "double-click-time", &retval, NULL);
986
987   return retval;
988 }
989
990 /**
991  * clutter_backend_set_double_click_distance:
992  * @backend: a #ClutterBackend
993  * @distance: a distance, in pixels
994  *
995  * Sets the maximum distance used to verify a double click event.
996  *
997  * Since: 0.4
998  *
999  * Deprecated: 1.4: Use #ClutterSettings:double-click-distance instead
1000  */
1001 void
1002 clutter_backend_set_double_click_distance (ClutterBackend *backend,
1003                                            guint           distance)
1004 {
1005   ClutterSettings *settings = clutter_settings_get_default ();
1006
1007   g_object_set (settings, "double-click-distance", distance, NULL);
1008 }
1009
1010 /**
1011  * clutter_backend_get_double_click_distance:
1012  * @backend: a #ClutterBackend
1013  *
1014  * Retrieves the distance used to verify a double click event
1015  *
1016  * Return value: a distance, in pixels.
1017  *
1018  * Since: 0.4
1019  *
1020  * Deprecated: 1.4: Use #ClutterSettings:double-click-distance instead
1021  */
1022 guint
1023 clutter_backend_get_double_click_distance (ClutterBackend *backend)
1024 {
1025   ClutterSettings *settings = clutter_settings_get_default ();
1026   gint retval;
1027
1028   g_object_get (settings, "double-click-distance", &retval, NULL);
1029
1030   return retval;
1031 }
1032
1033 /**
1034  * clutter_backend_set_resolution:
1035  * @backend: a #ClutterBackend
1036  * @dpi: the resolution in "dots per inch" (Physical inches aren't
1037  *   actually involved; the terminology is conventional).
1038  *
1039  * Sets the resolution for font handling on the screen. This is a
1040  * scale factor between points specified in a #PangoFontDescription
1041  * and cairo units. The default value is 96, meaning that a 10 point
1042  * font will be 13 units high. (10 * 96. / 72. = 13.3).
1043  *
1044  * Applications should never need to call this function.
1045  *
1046  * Since: 0.4
1047  *
1048  * Deprecated: 1.4: Use #ClutterSettings:font-dpi instead
1049  */
1050 void
1051 clutter_backend_set_resolution (ClutterBackend *backend,
1052                                 gdouble         dpi)
1053 {
1054   ClutterSettings *settings;
1055   gint resolution;
1056
1057   g_return_if_fail (CLUTTER_IS_BACKEND (backend));
1058
1059   if (dpi < 0)
1060     resolution = -1;
1061   else
1062     resolution = dpi * 1024;
1063
1064   settings = clutter_settings_get_default ();
1065   g_object_set (settings, "font-dpi", resolution, NULL);
1066 }
1067
1068 /**
1069  * clutter_backend_get_resolution:
1070  * @backend: a #ClutterBackend
1071  *
1072  * Gets the resolution for font handling on the screen.
1073  *
1074  * The resolution is a scale factor between points specified in a
1075  * #PangoFontDescription and cairo units. The default value is 96.0,
1076  * meaning that a 10 point font will be 13 units
1077  * high (10 * 96. / 72. = 13.3).
1078  *
1079  * Clutter will set the resolution using the current backend when
1080  * initializing; the resolution is also stored in the
1081  * #ClutterSettings:font-dpi property.
1082  *
1083  * Return value: the current resolution, or -1 if no resolution
1084  *   has been set.
1085  *
1086  * Since: 0.4
1087  */
1088 gdouble
1089 clutter_backend_get_resolution (ClutterBackend *backend)
1090 {
1091   ClutterSettings *settings;
1092   gint resolution;
1093
1094   g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), -1.0);
1095
1096   settings = clutter_settings_get_default ();
1097   g_object_get (settings, "font-dpi", &resolution, NULL);
1098
1099   if (resolution < 0)
1100     return 96.0;
1101
1102   return resolution / 1024.0;
1103 }
1104
1105 /**
1106  * clutter_backend_set_font_options:
1107  * @backend: a #ClutterBackend
1108  * @options: Cairo font options for the backend, or %NULL
1109  *
1110  * Sets the new font options for @backend. The #ClutterBackend will
1111  * copy the #cairo_font_options_t.
1112  *
1113  * If @options is %NULL, the first following call to
1114  * clutter_backend_get_font_options() will return the default font
1115  * options for @backend.
1116  *
1117  * This function is intended for actors creating a Pango layout
1118  * using the PangoCairo API.
1119  *
1120  * Since: 0.8
1121  */
1122 void
1123 clutter_backend_set_font_options (ClutterBackend             *backend,
1124                                   const cairo_font_options_t *options)
1125 {
1126   ClutterBackendPrivate *priv;
1127
1128   g_return_if_fail (CLUTTER_IS_BACKEND (backend));
1129
1130   priv = backend->priv;
1131
1132   if (priv->font_options != options)
1133     {
1134       if (priv->font_options)
1135         cairo_font_options_destroy (priv->font_options);
1136
1137       if (options)
1138         priv->font_options = cairo_font_options_copy (options);
1139       else
1140         priv->font_options = NULL;
1141
1142       g_signal_emit (backend, backend_signals[FONT_CHANGED], 0);
1143     }
1144 }
1145
1146 /**
1147  * clutter_backend_get_font_options:
1148  * @backend: a #ClutterBackend
1149  *
1150  * Retrieves the font options for @backend.
1151  *
1152  * Return value: (transfer none): the font options of the #ClutterBackend.
1153  *   The returned #cairo_font_options_t is owned by the backend and should
1154  *   not be modified or freed
1155  *
1156  * Since: 0.8
1157  */
1158 const cairo_font_options_t *
1159 clutter_backend_get_font_options (ClutterBackend *backend)
1160 {
1161   ClutterBackendPrivate *priv;
1162
1163   g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), NULL);
1164
1165   priv = backend->priv;
1166
1167   if (G_LIKELY (priv->font_options))
1168     return priv->font_options;
1169
1170   priv->font_options = cairo_font_options_create ();
1171
1172   cairo_font_options_set_hint_style (priv->font_options,
1173                                      CAIRO_HINT_STYLE_NONE);
1174   cairo_font_options_set_subpixel_order (priv->font_options,
1175                                          CAIRO_SUBPIXEL_ORDER_DEFAULT);
1176   cairo_font_options_set_antialias (priv->font_options,
1177                                     CAIRO_ANTIALIAS_DEFAULT);
1178
1179   g_signal_emit (backend, backend_signals[FONT_CHANGED], 0);
1180
1181   return priv->font_options;
1182 }
1183
1184 /**
1185  * clutter_backend_set_font_name:
1186  * @backend: a #ClutterBackend
1187  * @font_name: the name of the font
1188  *
1189  * Sets the default font to be used by Clutter. The @font_name string
1190  * must either be %NULL, which means that the font name from the
1191  * default #ClutterBackend will be used; or be something that can
1192  * be parsed by the pango_font_description_from_string() function.
1193  *
1194  * Since: 1.0
1195  *
1196  * Deprecated: 1.4: Use #ClutterSettings:font-name instead
1197  */
1198 void
1199 clutter_backend_set_font_name (ClutterBackend *backend,
1200                                const gchar    *font_name)
1201 {
1202   ClutterSettings *settings = clutter_settings_get_default ();
1203
1204   g_object_set (settings, "font-name", font_name, NULL);
1205 }
1206
1207 /**
1208  * clutter_backend_get_font_name:
1209  * @backend: a #ClutterBackend
1210  *
1211  * Retrieves the default font name as set by
1212  * clutter_backend_set_font_name().
1213  *
1214  * Return value: the font name for the backend. The returned string is
1215  *   owned by the #ClutterBackend and should never be modified or freed
1216  *
1217  * Since: 1.0
1218  *
1219  * Deprecated: 1.4: Use #ClutterSettings:font-name instead
1220  */
1221 const gchar *
1222 clutter_backend_get_font_name (ClutterBackend *backend)
1223 {
1224   ClutterBackendPrivate *priv;
1225   ClutterSettings *settings;
1226
1227   g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), NULL);
1228
1229   priv = backend->priv;
1230
1231   settings = clutter_settings_get_default ();
1232
1233   /* XXX yuck. but we return a const pointer, so we need to
1234    * store it in the backend
1235    */
1236   g_free (priv->font_name);
1237   g_object_get (settings, "font-name", &priv->font_name, NULL);
1238
1239   return priv->font_name;
1240 }
1241
1242 gint32
1243 _clutter_backend_get_units_serial (ClutterBackend *backend)
1244 {
1245   return backend->priv->units_serial;
1246 }
1247
1248 gboolean
1249 _clutter_backend_translate_event (ClutterBackend *backend,
1250                                   gpointer        native,
1251                                   ClutterEvent   *event)
1252 {
1253   return CLUTTER_BACKEND_GET_CLASS (backend)->translate_event (backend,
1254                                                                native,
1255                                                                event);
1256 }
1257
1258 void
1259 _clutter_backend_add_event_translator (ClutterBackend         *backend,
1260                                        ClutterEventTranslator *translator)
1261 {
1262   ClutterBackendPrivate *priv = backend->priv;
1263
1264   if (g_list_find (priv->event_translators, translator) != NULL)
1265     return;
1266
1267   priv->event_translators =
1268     g_list_prepend (priv->event_translators, translator);
1269 }
1270
1271 void
1272 _clutter_backend_remove_event_translator (ClutterBackend         *backend,
1273                                           ClutterEventTranslator *translator)
1274 {
1275   ClutterBackendPrivate *priv = backend->priv;
1276
1277   if (g_list_find (priv->event_translators, translator) == NULL)
1278     return;
1279
1280   priv->event_translators =
1281     g_list_remove (priv->event_translators, translator);
1282 }
1283
1284 /**
1285  * clutter_backend_get_cogl_context:
1286  * @backend: a #ClutterBackend
1287  *
1288  * Retrieves the #CoglContext associated with the given clutter
1289  * @backend. A #CoglContext is required when using some of the
1290  * experimental 2.0 Cogl API.
1291  *
1292  * <note>Since CoglContext is itself experimental API this API should
1293  * be considered experimental too.</note>
1294  *
1295  * <note>This API is not yet supported on OSX because OSX still
1296  * uses the stub Cogl winsys and the Clutter backend doesn't
1297  * explicitly create a CoglContext.</note>
1298  *
1299  * Return value: The #CoglContext associated with @backend.
1300  *
1301  * Since: 1.8
1302  * Stability: unstable
1303  */
1304 CoglContext *
1305 clutter_backend_get_cogl_context (ClutterBackend *backend)
1306 {
1307   return backend->cogl_context;
1308 }
1309
1310 #ifdef HAVE_CLUTTER_WAYLAND_COMPOSITOR
1311 /**
1312  * clutter_wayland_set_compositor_display:
1313  * @display: A compositor side struct wl_display pointer
1314  *
1315  * This informs Clutter of your compositor side Wayland display
1316  * object. This must be called before calling clutter_init().
1317  *
1318  * Since: 1.8
1319  * Stability: unstable
1320  */
1321 void
1322 clutter_wayland_set_compositor_display (struct wl_display *display)
1323 {
1324   if (_clutter_context_is_initialized ())
1325     {
1326       g_warning ("%s() can only be used before calling clutter_init()",
1327                  G_STRFUNC);
1328       return;
1329     }
1330
1331   _wayland_compositor_display = display;
1332 }
1333 #endif