diff options
Diffstat (limited to 'clutter/mir/clutter-stage-mir.c')
-rw-r--r-- | clutter/mir/clutter-stage-mir.c | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/clutter/mir/clutter-stage-mir.c b/clutter/mir/clutter-stage-mir.c new file mode 100644 index 000000000..9ca022517 --- /dev/null +++ b/clutter/mir/clutter-stage-mir.c @@ -0,0 +1,293 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2014 Canonical Ltd. + * + * 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 <http://www.gnu.org/licenses/>. + * + * Authors: + * Marco Trevisan <marco.trevisan@canonical.com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "clutter-mir.h" +#include "clutter-stage-mir.h" +#include "clutter-backend-mir-priv.h" +#include "clutter-stage-private.h" +#include "clutter-mir.h" +#include <cogl/cogl.h> + +#define clutter_stage_mir_get_type _clutter_stage_mir_get_type + +static ClutterStageWindowIface *clutter_stage_window_parent_iface = NULL; + +static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface); +static void clutter_stage_mir_set_fullscreen (ClutterStageWindow *stage_window, + gboolean fullscreen); +static void clutter_stage_mir_set_cursor_visible (ClutterStageWindow *stage_window, + gboolean cursor_visible); + +G_DEFINE_TYPE_WITH_CODE (ClutterStageMir, + clutter_stage_mir, + CLUTTER_TYPE_STAGE_COGL, + G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW, + clutter_stage_window_iface_init)); + +static void +on_stage_resized (CoglOnscreen *onscreen, + int width, + int height, + void *user_data) +{ + clutter_actor_set_size (CLUTTER_ACTOR (user_data), width, height); +} + +static gboolean +clutter_stage_mir_realize (ClutterStageWindow *stage_window) +{ + ClutterStageMir *stage_mir = CLUTTER_STAGE_MIR (stage_window); + ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); + MirSurface *mir_surface; + + if (!clutter_stage_window_parent_iface->realize (stage_window)) + return FALSE; + + cogl_framebuffer_allocate (COGL_FRAMEBUFFER (stage_cogl->onscreen), NULL); + mir_surface = cogl_mir_onscreen_get_surface (stage_cogl->onscreen); + + if (!mir_surface_is_valid (mir_surface)) + { + g_warning ("Realized Mir surface not valid"); + return FALSE; + } + + if (!stage_mir->foreign_mir_surface) + { + cogl_onscreen_add_resize_callback (stage_cogl->onscreen, on_stage_resized, + stage_cogl->wrapper, NULL); + } + + if (stage_mir->surface_state == mir_surface_state_fullscreen) + { + clutter_stage_mir_set_fullscreen (stage_window, TRUE); + stage_mir->surface_state = mir_surface_state_unknown; + } + + if (!stage_mir->cursor_visible) + { + clutter_stage_mir_set_cursor_visible (stage_window, FALSE); + } + + return TRUE; +} + +static void +clutter_stage_mir_show (ClutterStageWindow *stage_window, + gboolean do_raise) +{ + ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); + + cogl_onscreen_show (stage_cogl->onscreen); + clutter_actor_map (CLUTTER_ACTOR (stage_cogl->wrapper)); + clutter_actor_queue_redraw (CLUTTER_ACTOR (stage_cogl->wrapper)); +} + +static void +clutter_stage_mir_hide (ClutterStageWindow *stage_window) +{ + ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); + + cogl_onscreen_hide (stage_cogl->onscreen); + clutter_actor_unmap (CLUTTER_ACTOR (stage_cogl->wrapper)); + clutter_actor_queue_redraw (CLUTTER_ACTOR (stage_cogl->wrapper)); +} + +static void +clutter_stage_mir_set_cursor_visible (ClutterStageWindow *stage_window, + gboolean cursor_visible) +{ + ClutterStageMir *stage_mir = CLUTTER_STAGE_MIR (stage_window); + ClutterActor *actor = _clutter_stage_window_get_wrapper (stage_window); + MirSurface *surface = clutter_mir_stage_get_mir_surface ((ClutterStage *) actor); + MirCursorConfiguration *cursor_conf; + + if (mir_surface_is_valid (surface)) + { + cursor_conf = mir_cursor_configuration_from_name (cursor_visible ? + mir_default_cursor_name : + mir_disabled_cursor_name); + mir_surface_configure_cursor (surface, cursor_conf); + mir_cursor_configuration_destroy (cursor_conf); + } + + stage_mir->cursor_visible = cursor_visible; +} + +static void +clutter_stage_mir_set_fullscreen (ClutterStageWindow *stage_window, + gboolean fullscreen) +{ + ClutterStageMir *stage_mir = CLUTTER_STAGE_MIR (stage_window); + ClutterActor *actor = _clutter_stage_window_get_wrapper (stage_window); + MirSurface *surface = clutter_mir_stage_get_mir_surface ((ClutterStage *) actor); + + if (!mir_surface_is_valid (surface)) + { + stage_mir->surface_state = fullscreen ? + mir_surface_state_fullscreen : + mir_surface_state_unknown; + } + else + { + if (fullscreen) + { + stage_mir->surface_state = mir_surface_get_state (surface); + + if (stage_mir->surface_state != mir_surface_state_fullscreen) + mir_wait_for (mir_surface_set_state (surface, + mir_surface_state_fullscreen)); + } + else if (mir_surface_get_state (surface) == mir_surface_state_fullscreen) + { + mir_wait_for (mir_surface_set_state (surface, stage_mir->surface_state)); + } + } +} + +static void +clutter_stage_mir_resize (ClutterStageWindow *stage_window, + gint width, + gint height) +{ + ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); + + if (stage_cogl->onscreen) + { + cogl_mir_onscreen_resize (stage_cogl->onscreen, width, height); + clutter_actor_queue_redraw (CLUTTER_ACTOR (stage_cogl->wrapper)); + } +} + +static gboolean +clutter_stage_mir_can_clip_redraws (ClutterStageWindow *stage_window) +{ + return TRUE; +} + +static void +clutter_stage_mir_init (ClutterStageMir *stage_mir) +{ + stage_mir->cursor_visible = TRUE; + stage_mir->surface_state = mir_surface_state_unknown; +} + +static void +clutter_stage_window_iface_init (ClutterStageWindowIface *iface) +{ + clutter_stage_window_parent_iface = g_type_interface_peek_parent (iface); + + iface->realize = clutter_stage_mir_realize; + iface->show = clutter_stage_mir_show; + iface->hide = clutter_stage_mir_hide; + iface->set_fullscreen = clutter_stage_mir_set_fullscreen; + iface->set_cursor_visible = clutter_stage_mir_set_cursor_visible; + iface->resize = clutter_stage_mir_resize; + iface->can_clip_redraws = clutter_stage_mir_can_clip_redraws; +} + +static void +clutter_stage_mir_class_init (ClutterStageMirClass *klass) +{ +} + +/** + * clutter_mir_stage_get_mir_surface: (skip) + * @stage: a #ClutterStage + * + * Access the underlying data structure representing the surface that is + * backing the #ClutterStage + * + * Note: this function can only be called when running on the Mir + * platform. Calling this function at any other time will return %NULL. + * + * Returns: (transfer none): the Mir surface associated with @stage + * + * Since: 1.22 + */ +MirSurface * +clutter_mir_stage_get_mir_surface (ClutterStage *stage) +{ + ClutterStageWindow *stage_window = _clutter_stage_get_window (stage); + ClutterStageCogl *stage_cogl; + + if (!CLUTTER_IS_STAGE_COGL (stage_window)) + return NULL; + + stage_cogl = CLUTTER_STAGE_COGL (stage_window); + + if (!cogl_is_onscreen (stage_cogl->onscreen)) + return NULL; + + return cogl_mir_onscreen_get_surface (stage_cogl->onscreen); +} + +/** + * clutter_mir_stage_set_mir_surface: + * @stage: a #ClutterStage + * @surface: A Mir surface to associate with the @stage. + * + * Allows you to explicitly provide an existing Mir surface to associate + * with @stage, preventing Cogl from allocating a surface and shell surface for + * the stage automatically. + * + * This function must be called before @stage is shown. + * + * Note: this function can only be called when running on the Mir + * platform. Calling this function at any other time has no effect. + * + * Since: 1.22 + */ +void +clutter_mir_stage_set_mir_surface (ClutterStage *stage, + MirSurface *surface) +{ + ClutterStageWindow *stage_window = _clutter_stage_get_window (stage); + ClutterStageCogl *stage_cogl; + + if (!CLUTTER_IS_STAGE_MIR (stage_window)) + return; + + g_return_if_fail (mir_surface_is_valid (surface)); + + stage_cogl = CLUTTER_STAGE_COGL (stage_window); + + if (stage_cogl->onscreen == NULL) + { + ClutterBackend *backend = clutter_get_default_backend (); + + /* Use the same default dimensions as clutter_stage_cogl_realize() */ + stage_cogl->onscreen = cogl_onscreen_new (backend->cogl_context, + 800, 600); + + cogl_mir_onscreen_set_foreign_surface (stage_cogl->onscreen, surface); + CLUTTER_STAGE_MIR (stage_window)->foreign_mir_surface = TRUE; + } + else + g_warning (G_STRLOC ": cannot set foreign surface for stage"); +} |