/* * Copyright (C) 2006 OpenedHand * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #include "config.h" #include "clutter/clutter-context-private.h" #ifdef HAVE_FONTS #include #include #endif #include "clutter/clutter-accessibility-private.h" #include "clutter/clutter-backend-private.h" #include "clutter/clutter-color-manager.h" #include "clutter/clutter-debug.h" #include "clutter/clutter-main.h" #include "clutter/clutter-private.h" #include "clutter/clutter-paint-node-private.h" #include "clutter/clutter-settings-private.h" #ifdef HAVE_FONTS #include "clutter/pango/clutter-pango-private.h" #endif static gboolean clutter_show_fps = FALSE; static gboolean clutter_enable_accessibility = TRUE; #ifdef CLUTTER_ENABLE_DEBUG static const GDebugKey clutter_debug_keys[] = { { "misc", CLUTTER_DEBUG_MISC }, { "actor", CLUTTER_DEBUG_ACTOR }, { "texture", CLUTTER_DEBUG_TEXTURE }, { "event", CLUTTER_DEBUG_EVENT }, { "paint", CLUTTER_DEBUG_PAINT }, { "pick", CLUTTER_DEBUG_PICK }, { "pango", CLUTTER_DEBUG_PANGO }, { "backend", CLUTTER_DEBUG_BACKEND }, { "scheduler", CLUTTER_DEBUG_SCHEDULER }, { "script", CLUTTER_DEBUG_SCRIPT }, { "shader", CLUTTER_DEBUG_SHADER }, { "animation", CLUTTER_DEBUG_ANIMATION }, { "layout", CLUTTER_DEBUG_LAYOUT }, { "clipping", CLUTTER_DEBUG_CLIPPING }, { "oob-transforms", CLUTTER_DEBUG_OOB_TRANSFORMS }, { "frame-timings", CLUTTER_DEBUG_FRAME_TIMINGS }, { "detailed-trace", CLUTTER_DEBUG_DETAILED_TRACE }, { "grabs", CLUTTER_DEBUG_GRABS }, { "frame-clock", CLUTTER_DEBUG_FRAME_CLOCK }, { "gestures", CLUTTER_DEBUG_GESTURES }, }; #endif /* CLUTTER_ENABLE_DEBUG */ static const GDebugKey clutter_pick_debug_keys[] = { { "nop-picking", CLUTTER_DEBUG_NOP_PICKING }, }; static const GDebugKey clutter_paint_debug_keys[] = { { "disable-swap-events", CLUTTER_DEBUG_DISABLE_SWAP_EVENTS }, { "disable-clipped-redraws", CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS }, { "redraws", CLUTTER_DEBUG_REDRAWS }, { "paint-volumes", CLUTTER_DEBUG_PAINT_VOLUMES }, { "disable-culling", CLUTTER_DEBUG_DISABLE_CULLING }, { "disable-offscreen-redirect", CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT }, { "continuous-redraw", CLUTTER_DEBUG_CONTINUOUS_REDRAW }, { "paint-deform-tiles", CLUTTER_DEBUG_PAINT_DEFORM_TILES }, { "damage-region", CLUTTER_DEBUG_PAINT_DAMAGE_REGION }, { "disable-dynamic-max-render-time", CLUTTER_DEBUG_DISABLE_DYNAMIC_MAX_RENDER_TIME }, { "max-render-time", CLUTTER_DEBUG_PAINT_MAX_RENDER_TIME }, { "disable-triple-buffering", CLUTTER_DEBUG_DISABLE_TRIPLE_BUFFERING }, }; typedef struct _ClutterContextPrivate { ClutterTextDirection text_direction; ClutterColorManager *color_manager; ClutterPipelineCache *pipeline_cache; } ClutterContextPrivate; G_DEFINE_TYPE_WITH_PRIVATE (ClutterContext, clutter_context, G_TYPE_OBJECT) static void clutter_context_dispose (GObject *object) { ClutterContext *context = CLUTTER_CONTEXT (object); ClutterContextPrivate *priv = clutter_context_get_instance_private (context); g_clear_object (&priv->pipeline_cache); g_clear_object (&priv->color_manager); g_clear_pointer (&context->events_queue, g_async_queue_unref); g_clear_pointer (&context->backend, clutter_backend_destroy); g_clear_object (&context->stage_manager); g_clear_object (&context->settings); #ifdef HAVE_FONTS g_clear_object (&context->font_map); #endif G_OBJECT_CLASS (clutter_context_parent_class)->dispose (object); } static void clutter_context_class_init (ClutterContextClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = clutter_context_dispose; clutter_interval_register_progress_funcs (); } static void clutter_context_init (ClutterContext *context) { ClutterContextPrivate *priv = clutter_context_get_instance_private (context); priv->text_direction = CLUTTER_TEXT_DIRECTION_LTR; } ClutterTextDirection clutter_get_text_direction (void) { ClutterTextDirection dir = CLUTTER_TEXT_DIRECTION_LTR; const gchar *direction; direction = g_getenv ("CLUTTER_TEXT_DIRECTION"); if (direction && *direction != '\0') { if (strcmp (direction, "rtl") == 0) dir = CLUTTER_TEXT_DIRECTION_RTL; else if (strcmp (direction, "ltr") == 0) dir = CLUTTER_TEXT_DIRECTION_LTR; } #ifdef HAVE_FONTS else { PangoLanguage *language; const PangoScript *scripts; int n_scripts, i; language = pango_language_get_default (); scripts = pango_language_get_scripts (language, &n_scripts); for (i = 0; i < n_scripts; i++) { hb_script_t script; hb_direction_t text_dir; script = hb_glib_script_to_script ((GUnicodeScript) scripts[i]); text_dir = hb_script_get_horizontal_direction (script); if (text_dir == HB_DIRECTION_LTR) dir = CLUTTER_TEXT_DIRECTION_LTR; else if (text_dir == HB_DIRECTION_RTL) dir = CLUTTER_TEXT_DIRECTION_RTL; else continue; } } #endif CLUTTER_NOTE (MISC, "Text direction: %s", dir == CLUTTER_TEXT_DIRECTION_RTL ? "rtl" : "ltr"); return dir; } static gboolean clutter_context_init_real (ClutterContext *context, GError **error) { ClutterContextPrivate *priv = clutter_context_get_instance_private (context); /* If we are displaying the regions that would get redrawn with clipped * redraws enabled we actually have to disable the clipped redrawing * because otherwise we end up with nasty trails of rectangles everywhere. */ if (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS) clutter_paint_debug_flags |= CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS; /* The same is true when drawing the outlines of paint volumes... */ if (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES) { clutter_paint_debug_flags |= CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS | CLUTTER_DEBUG_DISABLE_CULLING; } if (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_DAMAGE_REGION) g_message ("Enabling damaged region"); if (!_clutter_backend_create_context (context->backend, error)) return FALSE; priv->text_direction = clutter_get_text_direction (); /* Initialize a11y */ if (clutter_enable_accessibility) { _clutter_accessibility_override_atk_util (); CLUTTER_NOTE (MISC, "Clutter Accessibility initialized"); } /* Initialize types required for paint nodes */ clutter_paint_node_init_types (context->backend); return TRUE; } static void init_clutter_debug (ClutterContext *context) { const char *env_string; #ifdef CLUTTER_ENABLE_DEBUG env_string = g_getenv ("CLUTTER_DEBUG"); if (env_string != NULL) { clutter_debug_flags = g_parse_debug_string (env_string, clutter_debug_keys, G_N_ELEMENTS (clutter_debug_keys)); env_string = NULL; } #endif /* CLUTTER_ENABLE_DEBUG */ env_string = g_getenv ("CLUTTER_PICK"); if (env_string != NULL) { clutter_pick_debug_flags = g_parse_debug_string (env_string, clutter_pick_debug_keys, G_N_ELEMENTS (clutter_pick_debug_keys)); env_string = NULL; } env_string = g_getenv ("CLUTTER_PAINT"); if (env_string != NULL) { clutter_paint_debug_flags = g_parse_debug_string (env_string, clutter_paint_debug_keys, G_N_ELEMENTS (clutter_paint_debug_keys)); env_string = NULL; } env_string = g_getenv ("CLUTTER_SHOW_FPS"); if (env_string) clutter_show_fps = TRUE; env_string = g_getenv ("CLUTTER_DISABLE_ACCESSIBILITY"); if (env_string) clutter_enable_accessibility = FALSE; } ClutterContext * clutter_context_new (ClutterBackendConstructor backend_constructor, gpointer user_data, GError **error) { ClutterContext *context; ClutterContextPrivate *priv; context = g_object_new (CLUTTER_TYPE_CONTEXT, NULL); priv = clutter_context_get_instance_private (context); init_clutter_debug (context); context->show_fps = clutter_show_fps; context->backend = backend_constructor (context, user_data); context->settings = g_object_new (CLUTTER_TYPE_SETTINGS, NULL); _clutter_settings_set_backend (context->settings, context->backend); context->stage_manager = g_object_new (CLUTTER_TYPE_STAGE_MANAGER, NULL); context->events_queue = g_async_queue_new_full ((GDestroyNotify) clutter_event_free); context->last_repaint_id = 1; priv->color_manager = g_object_new (CLUTTER_TYPE_COLOR_MANAGER, "context", context, NULL); priv->pipeline_cache = g_object_new (CLUTTER_TYPE_PIPELINE_CACHE, NULL); if (!clutter_context_init_real (context, error)) return NULL; return context; } void clutter_context_destroy (ClutterContext *context) { g_object_run_dispose (G_OBJECT (context)); g_object_unref (context); } ClutterBackend * clutter_context_get_backend (ClutterContext *context) { return context->backend; } #ifdef HAVE_FONTS PangoFontMap * clutter_context_get_pango_fontmap (ClutterContext *context) { PangoFontMap *font_map; PangoRenderer *font_renderer; gdouble resolution; ClutterBackend *backend; CoglContext *cogl_context; if (G_LIKELY (context->font_map != NULL)) return context->font_map; backend = clutter_context_get_backend (context); cogl_context = clutter_backend_get_cogl_context (backend); font_map = pango_cairo_font_map_new (); font_renderer = clutter_pango_renderer_new (cogl_context); resolution = clutter_backend_get_resolution (context->backend); pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (font_map), resolution); context->font_map = font_map; context->font_renderer = font_renderer; return context->font_map; } PangoRenderer * clutter_context_get_font_renderer (ClutterContext *context) { g_return_val_if_fail (CLUTTER_IS_CONTEXT (context), NULL); return context->font_renderer; } #endif ClutterTextDirection clutter_context_get_text_direction (ClutterContext *context) { ClutterContextPrivate *priv = clutter_context_get_instance_private (context); return priv->text_direction; } /** * clutter_context_get_pipeline_cache: (skip) */ ClutterPipelineCache * clutter_context_get_pipeline_cache (ClutterContext *context) { ClutterContextPrivate *priv = clutter_context_get_instance_private (context); return priv->pipeline_cache; } ClutterColorManager * clutter_context_get_color_manager (ClutterContext *context) { ClutterContextPrivate *priv = clutter_context_get_instance_private (context); return priv->color_manager; } /** * clutter_get_accessibility_enabled: * * Returns whether Clutter has accessibility support enabled. * * Return value: %TRUE if Clutter has accessibility support enabled */ gboolean clutter_get_accessibility_enabled (void) { return clutter_enable_accessibility; } ClutterStageManager * clutter_context_get_stage_manager (ClutterContext *context) { return context->stage_manager; } gboolean clutter_context_get_show_fps (ClutterContext *context) { return context->show_fps; } ClutterSettings * clutter_context_get_settings (ClutterContext *context) { g_return_val_if_fail (CLUTTER_IS_CONTEXT (context), NULL); return context->settings; }