[clutter] clutter: add Mir windowing/input backend



commit 77db9993391c8c575b5154cb4559417e2e90dd33
Author: Marco Trevisan (TreviƱo) <marco ubuntu com>
Date:   Fri Feb 20 17:41:49 2015 +0100

    clutter: add Mir windowing/input backend
    
    Added support for Mir, now clutter can natively draw on MirSurfaces.
    This depends on latest cogl git.
    
    Run your clutter apps using CLUTTER_BACKEND=mir
    
    Signed-off-by: Emmanuele Bassi <ebassi gnome org>

 clutter/Makefile.am                      |   31 +++-
 clutter/clutter-backend.c                |   19 ++
 clutter/clutter-main.c                   |    9 +
 clutter/mir/clutter-backend-mir-priv.h   |   46 ++++
 clutter/mir/clutter-backend-mir.c        |  231 +++++++++++++++++
 clutter/mir/clutter-backend-mir.h        |   55 ++++
 clutter/mir/clutter-device-manager-mir.c |  192 +++++++++++++++
 clutter/mir/clutter-device-manager-mir.h |   64 +++++
 clutter/mir/clutter-event-mir.c          |  395 ++++++++++++++++++++++++++++++
 clutter/mir/clutter-event-mir.h          |   40 +++
 clutter/mir/clutter-input-device-mir.c   |   55 ++++
 clutter/mir/clutter-input-device-mir.h   |   45 ++++
 clutter/mir/clutter-mir.h                |   57 +++++
 clutter/mir/clutter-stage-mir.c          |  293 ++++++++++++++++++++++
 clutter/mir/clutter-stage-mir.h          |   64 +++++
 configure.ac                             |   48 ++++
 16 files changed, 1642 insertions(+), 2 deletions(-)
---
diff --git a/clutter/Makefile.am b/clutter/Makefile.am
index 41ff69c..cbd76fd 100644
--- a/clutter/Makefile.am
+++ b/clutter/Makefile.am
@@ -699,6 +699,33 @@ clutter-wayland-compositor-$(CLUTTER_API_VERSION).pc: clutter-$(CLUTTER_API_VERS
 pc_files += clutter-wayland-compositor-$(CLUTTER_API_VERSION).pc
 endif
 
+# Mir backend rules
+if SUPPORT_MIR
+backend_source_h_priv += \
+       mir/clutter-backend-mir.h             \
+       mir/clutter-backend-mir-priv.h        \
+       mir/clutter-stage-mir.h               \
+       mir/clutter-event-mir.h               \
+       mir/clutter-input-device-mir.h        \
+       mir/clutter-device-manager-mir.h
+
+backend_source_c += \
+       mir/clutter-backend-mir.c             \
+       mir/clutter-stage-mir.c               \
+       mir/clutter-event-mir.c               \
+       mir/clutter-input-device-mir.c        \
+       mir/clutter-device-manager-mir.c
+
+
+cluttermir_includedir = $(clutter_includedir)/mir
+cluttermir_include_HEADERS = $(srcdir)/mir/clutter-mir.h
+
+clutter-mir-$(CLUTTER_API_VERSION).pc: clutter-$(CLUTTER_API_VERSION).pc
+       $(QUIET_GEN)cp -f $< $(@F)
+
+pc_files += clutter-mir-$(CLUTTER_API_VERSION).pc
+endif # SUPPORT_MIR
+
 if SUPPORT_EGL
 backend_source_h += $(egl_source_h)
 backend_source_c += $(egl_source_c)
@@ -898,7 +925,7 @@ clutter.vsenums_h:
        echo 'perl %1\bin\glib-mkenums --template ../../clutter/clutter-enum-types.h.in ' >vsenums_h.temp1
        for F in `echo $(source_h) $(backend_source_h) $(srcdir)/win32/clutter-win32.h`; do \
                case $$F in \
-               *-x11*.h|*-wayland*.h|*-gdk*.h|*-glx*.h|*-cex*.h|*-egl*.h|*-osx*.h) ;; \
+               *-x11*.h|*-wayland*.h|*-gdk*.h|*-glx*.h|*-cex*.h|*-egl*.h|*-osx*.h|*-mir*.h) ;; \
                *.h) echo '../../clutter'$$F' ' \
                        ;;      \
                esac;   \
@@ -913,7 +940,7 @@ clutter.vsenums_c:
        echo 'perl %1\bin\glib-mkenums --template ../../clutter/clutter-enum-types.c.in ' >vsenums_c.temp1
        for F in `echo $(source_h) $(backend_source_h) $(srcdir)/win32/clutter-win32.h`; do \
                case $$F in \
-               *-x11*.h|*-wayland*.h|*-gdk*.h|*-glx*.h|*-cex*.h|*-egl*.h|*-osx*.h) ;; \
+               *-x11*.h|*-wayland*.h|*-gdk*.h|*-glx*.h|*-cex*.h|*-egl*.h|*-osx*.h|*-mir*.h) ;; \
                *.h) echo '../../clutter'$$F' ' \
                        ;;      \
                esac;   \
diff --git a/clutter/clutter-backend.c b/clutter/clutter-backend.c
index 4b17956..ac00d27 100644
--- a/clutter/clutter-backend.c
+++ b/clutter/clutter-backend.c
@@ -89,6 +89,12 @@
 #ifdef CLUTTER_INPUT_WAYLAND
 #include "wayland/clutter-device-manager-wayland.h"
 #endif
+#ifdef CLUTTER_WINDOWING_MIR
+#include "mir/clutter-backend-mir.h"
+#endif
+#ifdef CLUTTER_INPUT_MIR
+#include "mir/clutter-device-manager-mir.h"
+#endif
 
 #ifdef HAVE_CLUTTER_WAYLAND_COMPOSITOR
 #include <cogl/cogl-wayland-server.h>
@@ -511,6 +517,11 @@ _clutter_create_backend (void)
     retval = g_object_new (CLUTTER_TYPE_BACKEND_EGL_NATIVE, NULL);
   else
 #endif
+#ifdef CLUTTER_WINDOWING_MIR
+  if (backend == NULL || backend == I_(CLUTTER_WINDOWING_MIR))
+    retval = g_object_new (CLUTTER_TYPE_BACKEND_MIR, NULL);
+  else
+#endif
   if (backend == NULL)
     g_error ("No default Clutter backend found.");
   else
@@ -590,6 +601,14 @@ clutter_backend_real_init_events (ClutterBackend *backend)
     }
   else
 #endif
+#ifdef CLUTTER_INPUT_MIR
+  if (clutter_check_windowing_backend (CLUTTER_WINDOWING_MIR) &&
+      (input_backend == NULL || input_backend == I_(CLUTTER_INPUT_MIR)))
+    {
+      _clutter_events_mir_init (backend);
+    }
+  else
+#endif
   if (input_backend != NULL)
     {
       if (input_backend != I_(CLUTTER_INPUT_NULL))
diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c
index c21f897..5b84062 100644
--- a/clutter/clutter-main.c
+++ b/clutter/clutter-main.c
@@ -89,6 +89,9 @@
 #ifdef CLUTTER_WINDOWING_WAYLAND
 #include "wayland/clutter-backend-wayland.h"
 #endif
+#ifdef CLUTTER_WINDOWING_MIR
+#include "mir/clutter-backend-mir.h"
+#endif
 
 #include <cogl/cogl.h>
 #include <cogl-pango/cogl-pango.h>
@@ -3781,6 +3784,12 @@ clutter_check_windowing_backend (const char *backend_type)
     return TRUE;
   else
 #endif
+#ifdef CLUTTER_WINDOWING_MIR
+  if (backend_type == I_(CLUTTER_WINDOWING_MIR) &&
+      CLUTTER_IS_BACKEND_MIR (context->backend))
+    return TRUE;
+  else
+#endif
 #ifdef CLUTTER_WINDOWING_GDK
   if (backend_type == I_(CLUTTER_WINDOWING_GDK) &&
       CLUTTER_IS_BACKEND_GDK (context->backend))
diff --git a/clutter/mir/clutter-backend-mir-priv.h b/clutter/mir/clutter-backend-mir-priv.h
new file mode 100644
index 0000000..11ee162
--- /dev/null
+++ b/clutter/mir/clutter-backend-mir-priv.h
@@ -0,0 +1,46 @@
+/*
+ * 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>
+ */
+
+#ifndef __CLUTTER_BACKEND_MIR_PRIV_H__
+#define __CLUTTER_BACKEND_MIR_PRIV_H__
+
+#include <glib-object.h>
+#include <clutter/clutter-backend.h>
+#include <mir_toolkit/mir_client_library.h>
+
+#include "clutter-backend-private.h"
+
+G_BEGIN_DECLS
+
+struct _ClutterBackendMir
+{
+  ClutterBackend parent_instance;
+
+  MirConnection *mir_connection;
+  GSource *mir_source;
+};
+
+G_END_DECLS
+
+#endif /* __CLUTTER_BACKEND_MIR_PRIV_H__ */
diff --git a/clutter/mir/clutter-backend-mir.c b/clutter/mir/clutter-backend-mir.c
new file mode 100644
index 0000000..d537483
--- /dev/null
+++ b/clutter/mir/clutter-backend-mir.c
@@ -0,0 +1,231 @@
+/*
+ * 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-debug.h"
+#include "clutter-main.h"
+#include "clutter-stage-private.h"
+
+#include "mir/clutter-backend-mir-priv.h"
+#include "mir/clutter-backend-mir.h"
+#include "mir/clutter-device-manager-mir.h"
+#include "mir/clutter-event-mir.h"
+#include "mir/clutter-stage-mir.h"
+#include "mir/clutter-mir.h"
+
+#define clutter_backend_mir_get_type _clutter_backend_mir_get_type
+
+G_DEFINE_TYPE (ClutterBackendMir, clutter_backend_mir, CLUTTER_TYPE_BACKEND);
+
+static MirConnection *_foreign_connection = NULL;
+static gboolean _no_event_dispatch = FALSE;
+
+static gboolean
+clutter_backend_mir_post_parse (ClutterBackend  *backend,
+                                GError         **error)
+{
+  ClutterBackendMir *backend_mir = CLUTTER_BACKEND_MIR (backend);
+
+  backend_mir->mir_connection = _foreign_connection;
+  if (backend_mir->mir_connection == NULL)
+    backend_mir->mir_connection = mir_connect_sync (NULL, "Clutter");
+
+  if (!mir_connection_is_valid (backend_mir->mir_connection))
+    {
+      g_set_error (error, CLUTTER_INIT_ERROR,
+                   CLUTTER_INIT_ERROR_BACKEND,
+                   "Failed to open Mir display socket %s",
+                   mir_connection_get_error_message (backend_mir->mir_connection));
+      mir_connection_release (backend_mir->mir_connection);
+      return FALSE;
+    }
+
+  g_object_set (clutter_settings_get_default (), "font-dpi", 96 * 1024, NULL);
+
+  return TRUE;
+}
+
+static CoglRenderer *
+clutter_backend_mir_get_renderer (ClutterBackend  *backend,
+                                  GError         **error)
+{
+  ClutterBackendMir *backend_mir = CLUTTER_BACKEND_MIR (backend);
+  CoglRenderer *renderer;
+
+  CLUTTER_NOTE (BACKEND, "Creating a new Mir renderer");
+
+  renderer = cogl_renderer_new ();
+
+  cogl_renderer_set_winsys_id (renderer, COGL_WINSYS_ID_EGL_MIR);
+  cogl_mir_renderer_set_foreign_connection (renderer,
+                                            backend_mir->mir_connection);
+
+  return renderer;
+}
+
+static CoglDisplay *
+clutter_backend_mir_get_display (ClutterBackend  *backend,
+                                 CoglRenderer    *renderer,
+                                 CoglSwapChain   *swap_chain,
+                                 GError         **error)
+{
+  CoglOnscreenTemplate *onscreen_template = NULL;
+  CoglDisplay *display;
+
+  onscreen_template = cogl_onscreen_template_new (swap_chain);
+
+  if (!cogl_renderer_check_onscreen_template (renderer,
+                                              onscreen_template,
+                                              error))
+    goto error;
+
+  display = cogl_display_new (renderer, onscreen_template);
+
+  return display;
+
+error:
+  if (onscreen_template)
+    cogl_object_unref (onscreen_template);
+
+  return NULL;
+}
+
+static void
+on_mir_event_cb (CoglMirEvent *mir_event,
+                 void *data)
+{
+  ClutterBackend *backend = data;
+  _clutter_mir_handle_event (backend, mir_event->surface, mir_event->event);
+}
+
+void
+_clutter_events_mir_init (ClutterBackend *backend)
+{
+  ClutterBackendMir *backend_mir = CLUTTER_BACKEND_MIR (backend);
+  CoglRenderer *cogl_renderer = backend->cogl_renderer;
+
+  backend->device_manager = _clutter_device_manager_mir_new (backend);
+
+  if (_no_event_dispatch)
+    return;
+
+  cogl_mir_renderer_add_event_listener (cogl_renderer, on_mir_event_cb, backend);
+  backend_mir->mir_source = _clutter_event_source_mir_new ();
+}
+
+
+static void
+clutter_backend_mir_init (ClutterBackendMir *backend_mir)
+{
+}
+
+static void
+clutter_backend_mir_dispose (GObject *gobject)
+{
+  ClutterBackend *backend = CLUTTER_BACKEND (gobject);
+  ClutterBackendMir *backend_mir = CLUTTER_BACKEND_MIR (backend);
+  CoglRenderer *cogl_renderer = backend->cogl_renderer;
+
+  g_clear_object (&backend->device_manager);
+  g_clear_pointer (&backend_mir->mir_source, g_source_unref);
+  cogl_mir_renderer_remove_event_listener (cogl_renderer, on_mir_event_cb,
+                                           backend);
+
+  G_OBJECT_CLASS (clutter_backend_mir_parent_class)->dispose (gobject);
+}
+
+static void
+clutter_backend_mir_class_init (ClutterBackendMirClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
+
+  gobject_class->dispose = clutter_backend_mir_dispose;
+
+  backend_class->stage_window_type = CLUTTER_TYPE_STAGE_MIR;
+
+  backend_class->post_parse = clutter_backend_mir_post_parse;
+  backend_class->get_renderer = clutter_backend_mir_get_renderer;
+  backend_class->get_display = clutter_backend_mir_get_display;
+}
+
+/**
+ * clutter_mir_set_connection
+ * @connection: pointer to a mir connection
+ *
+ * Sets the display connection Clutter should use; must be called
+ * before clutter_init(), clutter_init_with_args() or other functions
+ * pertaining Clutter's initialization process.
+ *
+ * If you are parsing the command line arguments by retrieving Clutter's
+ * #GOptionGroup with clutter_get_option_group() and calling
+ * g_option_context_parse() yourself, you should also call
+ * clutter_mir_set_connection() before g_option_context_parse().
+ *
+ * Since: 1.22
+ */
+void
+clutter_mir_set_connection (MirConnection *connection)
+{
+  g_return_if_fail (mir_connection_is_valid (connection));
+
+  if (_clutter_context_is_initialized ())
+    {
+      g_warning ("%s() can only be used before calling clutter_init()",
+                 G_STRFUNC);
+      return;
+    }
+
+  _foreign_connection = connection;
+}
+
+/**
+ * clutter_mir_disable_event_retrieval:
+ *
+ * Disables the dispatch of the events in the main loop.
+ *
+ * This is useful for integrating Clutter with another library that will do the
+ * event dispatch;
+ *
+ * This function can only be called before calling clutter_init().
+ *
+ * This function should not be normally used by applications.
+ *
+ * Since: 1.22
+ */
+void
+clutter_mir_disable_event_retrieval (void)
+{
+  if (_clutter_context_is_initialized ())
+    {
+      g_warning ("%s() can only be used before calling clutter_init()",
+                 G_STRFUNC);
+      return;
+    }
+
+  _no_event_dispatch = TRUE;
+}
diff --git a/clutter/mir/clutter-backend-mir.h b/clutter/mir/clutter-backend-mir.h
new file mode 100644
index 0000000..beecf8a
--- /dev/null
+++ b/clutter/mir/clutter-backend-mir.h
@@ -0,0 +1,55 @@
+/*
+ * 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>
+ */
+
+#ifndef __CLUTTER_BACKEND_MIR_H__
+#define __CLUTTER_BACKEND_MIR_H__
+
+#include <glib-object.h>
+#include <clutter/clutter-backend.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_BACKEND_MIR                (_clutter_backend_mir_get_type ())
+#define CLUTTER_BACKEND_MIR(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
CLUTTER_TYPE_BACKEND_MIR, ClutterBackendMir))
+#define CLUTTER_IS_BACKEND_MIR(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
CLUTTER_TYPE_BACKEND_MIR))
+#define CLUTTER_BACKEND_MIR_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BACKEND_MIR, 
ClutterBackendMirClass))
+#define CLUTTER_IS_BACKEND_MIR_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BACKEND_MIR))
+#define CLUTTER_BACKEND_MIR_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BACKEND_MIR, 
ClutterBackendMirClass))
+
+typedef struct _ClutterBackendMir       ClutterBackendMir;
+typedef struct _ClutterBackendMirClass  ClutterBackendMirClass;
+
+struct _ClutterBackendMirClass
+{
+  ClutterBackendClass parent_class;
+};
+
+GType _clutter_backend_mir_get_type (void) G_GNUC_CONST;
+
+void
+_clutter_events_mir_init (ClutterBackend *backend);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_BACKEND_MIR_H__ */
diff --git a/clutter/mir/clutter-device-manager-mir.c b/clutter/mir/clutter-device-manager-mir.c
new file mode 100644
index 0000000..8fb87c5
--- /dev/null
+++ b/clutter/mir/clutter-device-manager-mir.c
@@ -0,0 +1,192 @@
+/*
+ * 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-device-manager-private.h"
+#include "clutter-input-device-mir.h"
+#include "clutter-device-manager-mir.h"
+
+static guint device_counter;
+
+G_DEFINE_TYPE (ClutterDeviceManagerMir, _clutter_device_manager_mir, CLUTTER_TYPE_DEVICE_MANAGER);
+
+static void
+clutter_device_manager_mir_add_device (ClutterDeviceManager *manager,
+                                       ClutterInputDevice   *device)
+{
+  ClutterDeviceManagerMir *manager_mir = CLUTTER_DEVICE_MANAGER_MIR (manager);
+  manager_mir->devices = g_slist_prepend (manager_mir->devices, device);
+}
+
+static void
+clutter_device_manager_mir_remove_device (ClutterDeviceManager *manager,
+                                          ClutterInputDevice   *device)
+{
+  ClutterDeviceManagerMir *manager_mir = CLUTTER_DEVICE_MANAGER_MIR (manager);
+  manager_mir->devices = g_slist_remove (manager_mir->devices, device);
+}
+
+static const GSList *
+clutter_device_manager_mir_get_devices (ClutterDeviceManager *manager)
+{
+  return CLUTTER_DEVICE_MANAGER_MIR (manager)->devices;
+}
+
+static ClutterInputDevice *
+clutter_device_manager_mir_get_core_device (ClutterDeviceManager *manager,
+                                            ClutterInputDeviceType type)
+{
+  ClutterDeviceManagerMir *manager_mir;
+
+  manager_mir = CLUTTER_DEVICE_MANAGER_MIR (manager);
+
+  switch (type)
+    {
+      case CLUTTER_POINTER_DEVICE:
+        return manager_mir->core_pointer;
+
+      case CLUTTER_KEYBOARD_DEVICE:
+        return manager_mir->core_keyboard;
+
+      case CLUTTER_EXTENSION_DEVICE:
+      default:
+        return NULL;
+    }
+
+  return NULL;
+}
+
+static ClutterInputDevice *
+clutter_device_manager_mir_get_device (ClutterDeviceManager *manager,
+                                       gint                  id)
+{
+  ClutterDeviceManagerMir *manager_mir =
+    CLUTTER_DEVICE_MANAGER_MIR (manager);
+  GSList *l;
+
+  for (l = manager_mir->devices; l != NULL; l = l->next)
+    {
+      ClutterInputDevice *device = l->data;
+
+      if (clutter_input_device_get_device_id (device) == id)
+        return device;
+    }
+
+  return NULL;
+}
+
+static void
+clutter_device_manager_mir_constructed (GObject *gobject)
+{
+  ClutterBackend *backend;
+  ClutterDeviceManager *manager;
+  ClutterDeviceManagerMir *manager_mir;
+  ClutterInputDevice *device;
+
+  manager = CLUTTER_DEVICE_MANAGER (gobject);
+  manager_mir = CLUTTER_DEVICE_MANAGER_MIR (manager);
+
+  g_object_get (manager, "backend", &backend, NULL);
+
+  device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_MIR,
+                         "id", device_counter++,
+                         "backend", backend,
+                         "device-manager", manager,
+                         "device-type", CLUTTER_POINTER_DEVICE,
+                         "device-mode", CLUTTER_INPUT_MODE_MASTER,
+                         "name", "Mir pointer",
+                         "enabled", TRUE,
+                         "has-cursor", TRUE,
+                         NULL);
+
+  manager_mir->core_pointer = device;
+  _clutter_device_manager_add_device (manager, CLUTTER_INPUT_DEVICE (device));
+
+  device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_MIR,
+                         "id", device_counter++,
+                         "backend", backend,
+                         "device-manager", manager,
+                         "device-type", CLUTTER_KEYBOARD_DEVICE,
+                         "device-mode", CLUTTER_INPUT_MODE_MASTER,
+                         "name", "Mir keyboard",
+                         "enabled", TRUE,
+                         "has-cursor", FALSE,
+                         NULL);
+
+  manager_mir->core_keyboard = device;
+  _clutter_device_manager_add_device (manager, CLUTTER_INPUT_DEVICE (device));
+
+  _clutter_input_device_set_associated_device (manager_mir->core_pointer,
+                                               manager_mir->core_keyboard);
+  _clutter_input_device_set_associated_device (manager_mir->core_keyboard,
+                                               manager_mir->core_pointer);
+
+  if (G_OBJECT_CLASS (_clutter_device_manager_mir_parent_class)->constructed)
+    G_OBJECT_CLASS (_clutter_device_manager_mir_parent_class)->constructed (gobject);
+}
+
+static void
+clutter_device_manager_mir_finalize (GObject *gobject)
+{
+  ClutterDeviceManagerMir *manager_mir;
+
+  manager_mir = CLUTTER_DEVICE_MANAGER_MIR (gobject);
+  g_slist_free_full (manager_mir->devices, g_object_unref);
+
+  G_OBJECT_CLASS (_clutter_device_manager_mir_parent_class)->finalize (gobject);
+}
+
+static void
+_clutter_device_manager_mir_class_init (ClutterDeviceManagerMirClass *klass)
+{
+  ClutterDeviceManagerClass *manager_class;
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->constructed = clutter_device_manager_mir_constructed;
+  gobject_class->finalize = clutter_device_manager_mir_finalize;
+
+  manager_class = CLUTTER_DEVICE_MANAGER_CLASS (klass);
+  manager_class->add_device = clutter_device_manager_mir_add_device;
+  manager_class->remove_device = clutter_device_manager_mir_remove_device;
+  manager_class->get_devices = clutter_device_manager_mir_get_devices;
+  manager_class->get_core_device = clutter_device_manager_mir_get_core_device;
+  manager_class->get_device = clutter_device_manager_mir_get_device;
+}
+
+static void
+_clutter_device_manager_mir_init (ClutterDeviceManagerMir *self)
+{
+}
+
+ClutterDeviceManager *
+_clutter_device_manager_mir_new (ClutterBackend *backend)
+{
+  return g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_MIR,
+                       "backend", backend,
+                       NULL);
+}
diff --git a/clutter/mir/clutter-device-manager-mir.h b/clutter/mir/clutter-device-manager-mir.h
new file mode 100644
index 0000000..f675bff
--- /dev/null
+++ b/clutter/mir/clutter-device-manager-mir.h
@@ -0,0 +1,64 @@
+/*
+ * 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>
+ */
+
+#ifndef __CLUTTER_DEVICE_MANAGER_MIR_H__
+#define __CLUTTER_DEVICE_MANAGER_MIR_H__
+
+#include <clutter/clutter-device-manager.h>
+#include <clutter/clutter-backend.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_DEVICE_MANAGER_MIR            (_clutter_device_manager_mir_get_type ())
+#define CLUTTER_DEVICE_MANAGER_MIR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
CLUTTER_TYPE_DEVICE_MANAGER_MIR, ClutterDeviceManagerMir))
+#define CLUTTER_IS_DEVICE_MANAGER_MIR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
CLUTTER_TYPE_DEVICE_MANAGER_MIR))
+#define CLUTTER_DEVICE_MANAGER_MIR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), 
CLUTTER_TYPE_DEVICE_MANAGER_MIR, ClutterDeviceManagerMirClass))
+#define CLUTTER_IS_DEVICE_MANAGER_MIR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), 
CLUTTER_TYPE_DEVICE_MANAGER_MIR))
+#define CLUTTER_DEVICE_MANAGER_MIR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), 
CLUTTER_TYPE_DEVICE_MANAGER_MIR, ClutterDeviceManagerMirClass))
+
+typedef struct _ClutterDeviceManagerMir         ClutterDeviceManagerMir;
+typedef struct _ClutterDeviceManagerMirClass    ClutterDeviceManagerMirClass;
+
+struct _ClutterDeviceManagerMir
+{
+  ClutterDeviceManager parent_instance;
+
+  GSList *devices;
+  ClutterInputDevice *core_pointer;
+  ClutterInputDevice *core_keyboard;
+};
+
+struct _ClutterDeviceManagerMirClass
+{
+  ClutterDeviceManagerClass parent_class;
+};
+
+GType _clutter_device_manager_mir_get_type (void) G_GNUC_CONST;
+
+ClutterDeviceManager *
+_clutter_device_manager_mir_new (ClutterBackend *backend);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_DEVICE_MANAGER_MIR_H__ */
diff --git a/clutter/mir/clutter-event-mir.c b/clutter/mir/clutter-event-mir.c
new file mode 100644
index 0000000..296430b
--- /dev/null
+++ b/clutter/mir/clutter-event-mir.c
@@ -0,0 +1,395 @@
+/*
+ * 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-private.h"
+#include "clutter-event-private.h"
+#include "clutter-stage-mir.h"
+#include "clutter-stage-private.h"
+#include "clutter-backend-mir-priv.h"
+#include "clutter-device-manager-private.h"
+#include "evdev/clutter-xkb-utils.h"
+
+#include "clutter-event-mir.h"
+
+#define NANO_TO_MILLI(x) ((x) / 1000000)
+
+/* Using the clutter threads lock would cause a dead-lock when resizing */
+static GMutex mir_event_lock;
+
+static gboolean
+clutter_event_source_mir_check (GSource *source)
+{
+  gboolean retval;
+
+  g_mutex_lock (&mir_event_lock);
+
+  retval = clutter_events_pending ();
+
+  g_mutex_unlock (&mir_event_lock);
+
+  return retval;
+}
+
+static gboolean
+clutter_event_source_mir_prepare (GSource *source, gint *timeout)
+{
+  *timeout = -1;
+  return clutter_event_source_mir_check (source);
+}
+
+static gboolean
+clutter_event_source_mir_dispatch (GSource *source,
+                                   GSourceFunc callback,
+                                   gpointer data)
+{
+  ClutterEvent *event;
+
+  g_mutex_lock (&mir_event_lock);
+  _clutter_threads_acquire_lock ();
+
+  event = clutter_event_get ();
+
+  if (event)
+    {
+      /* forward the event into clutter for emission etc. */
+      _clutter_stage_queue_event (event->any.stage, event, FALSE);
+    }
+
+  _clutter_threads_release_lock ();
+  g_mutex_unlock (&mir_event_lock);
+
+  return TRUE;
+}
+
+static void
+clutter_event_source_mir_finalize (GSource *source)
+{
+  g_mutex_clear (&mir_event_lock);
+}
+
+static GSourceFuncs clutter_event_source_mir_funcs = {
+    clutter_event_source_mir_prepare,
+    clutter_event_source_mir_check,
+    clutter_event_source_mir_dispatch,
+    clutter_event_source_mir_finalize
+};
+
+GSource *
+_clutter_event_source_mir_new (void)
+{
+  GSource *source;
+
+  source = g_source_new (&clutter_event_source_mir_funcs, sizeof (GSource));
+
+  g_mutex_init (&mir_event_lock);
+  g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS);
+  g_source_attach (source, NULL);
+
+  return source;
+}
+
+
+static ClutterModifierType
+translate_mir_modifier (unsigned int key_modifiers, MirMotionButton button_state)
+{
+  ClutterModifierType clutter_modifiers = 0;
+
+  if (key_modifiers == mir_key_modifier_none && button_state == 0)
+    return clutter_modifiers;
+
+  if (key_modifiers & mir_key_modifier_alt)
+    clutter_modifiers |= CLUTTER_MOD1_MASK;
+
+  if (key_modifiers & mir_key_modifier_shift)
+    clutter_modifiers |= CLUTTER_SHIFT_MASK;
+
+  if (key_modifiers & mir_key_modifier_ctrl)
+    clutter_modifiers |= CLUTTER_CONTROL_MASK;
+
+  if (key_modifiers & mir_key_modifier_meta)
+    clutter_modifiers |= CLUTTER_META_MASK;
+
+  if (key_modifiers & mir_key_modifier_caps_lock)
+    clutter_modifiers |= CLUTTER_LOCK_MASK;
+
+  if (button_state & mir_motion_button_primary)
+    clutter_modifiers |= CLUTTER_BUTTON1_MASK;
+
+  if (button_state & mir_motion_button_secondary)
+    clutter_modifiers |= CLUTTER_BUTTON3_MASK;
+
+  if (button_state & mir_motion_button_tertiary)
+    clutter_modifiers |= CLUTTER_BUTTON2_MASK;
+
+  return clutter_modifiers;
+}
+
+static gunichar
+get_unicode_value (int32_t key_code)
+{
+  gunichar unicode = '\0';
+  char text[8];
+  int size;
+
+  size = xkb_keysym_to_utf8 (key_code, text, sizeof (text));
+
+  if (size > 0)
+    {
+     unicode = g_utf8_get_char_validated (text, size);
+
+      if (unicode == -1 || unicode == -2)
+        unicode = '\0';
+    }
+
+  return unicode;
+}
+
+void
+_clutter_mir_handle_event (ClutterBackend *backend,
+                           MirSurface *surface,
+                           MirEvent *mir_event)
+{
+  ClutterStageManager *stage_manager;
+  ClutterInputDevice *device = NULL;
+  ClutterStage *stage = NULL;
+  ClutterEvent *event = NULL;
+  ClutterModifierType modifiers;
+  MirMotionButton button_state;
+  MirMotionPointer *pointer;
+  const GSList *l;
+
+  stage_manager = clutter_stage_manager_get_default ();
+
+  for (l = clutter_stage_manager_peek_stages (stage_manager); l; l = l->next)
+    {
+      ClutterStage* tmp_stage = l->data;
+
+      if (CLUTTER_IS_STAGE (tmp_stage) &&
+          clutter_mir_stage_get_mir_surface (tmp_stage) == surface)
+        {
+          stage = tmp_stage;
+          break;
+        }
+    }
+
+  if (!stage)
+    return;
+
+  g_mutex_lock (&mir_event_lock);
+
+  button_state = CLUTTER_STAGE_MIR (stage)->button_state;
+
+  switch (mir_event->type)
+    {
+      case mir_event_type_key:
+        if (mir_event->key.action == mir_key_action_multiple)
+          break;
+
+        device = clutter_device_manager_get_core_device (backend->device_manager,
+                                                         CLUTTER_KEYBOARD_DEVICE);
+
+        event = clutter_event_new (mir_event->key.action == mir_key_action_down ?
+                                   CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE);
+
+        modifiers = translate_mir_modifier (mir_event->key.modifiers, button_state);
+        event->key.time = NANO_TO_MILLI (mir_event->key.event_time);
+        event->key.modifier_state = modifiers;
+        event->key.keyval = mir_event->key.key_code;
+        event->key.hardware_keycode = mir_event->key.scan_code + 8;
+        event->key.unicode_value = get_unicode_value (mir_event->key.key_code);
+        break;
+
+      case mir_event_type_motion:
+        pointer = mir_event->motion.pointer_coordinates;
+        device = clutter_device_manager_get_core_device (backend->device_manager,
+                                                         CLUTTER_POINTER_DEVICE);
+
+        /* We need to send an ENTER event again if the stage is not focused anymore */
+        if (mir_event->motion.action != mir_motion_action_hover_enter &&
+            mir_event->motion.action != mir_motion_action_hover_exit &&
+            !_clutter_input_device_get_stage (device))
+          {
+            ClutterEvent *new_event = clutter_event_new (CLUTTER_ENTER);
+            modifiers = translate_mir_modifier (mir_event->motion.modifiers,
+                                                button_state);
+
+            clutter_event_set_time (new_event, NANO_TO_MILLI (mir_event->motion.event_time));
+            clutter_event_set_state (new_event, modifiers);
+            clutter_event_set_coords (new_event, pointer->x, pointer->y);
+
+            _clutter_input_device_set_stage (device, stage);
+
+            clutter_event_set_stage (new_event, stage);
+            clutter_event_set_device (new_event, device);
+            clutter_event_set_source_device (new_event, device);
+
+            _clutter_event_push (new_event, FALSE);
+          }
+
+        switch (mir_event->motion.action)
+          {
+            case mir_motion_action_down:
+            case mir_motion_action_pointer_down:
+            case mir_motion_action_up:
+            case mir_motion_action_pointer_up:
+              event = clutter_event_new ((mir_event->motion.action ==
+                                            mir_motion_action_down ||
+                                          mir_event->motion.action ==
+                                            mir_motion_action_pointer_down) ?
+                                          CLUTTER_BUTTON_PRESS :
+                                          CLUTTER_BUTTON_RELEASE);
+
+              event->button.button = 1;
+              event->button.click_count = 1;
+
+              button_state ^= mir_event->motion.button_state;
+
+              if (button_state == 0 || (button_state & mir_motion_button_primary))
+                event->button.button = 1;
+              else if (button_state & mir_motion_button_secondary)
+                event->button.button = 3;
+              else if (button_state & mir_motion_button_tertiary)
+                event->button.button = 2;
+              else if (button_state & mir_motion_button_back)
+                event->button.button = 8;
+              else if (button_state & mir_motion_button_forward)
+                event->button.button = 9;
+
+              button_state = mir_event->motion.button_state;
+              CLUTTER_STAGE_MIR (stage)->button_state = button_state;
+
+              break;
+            case mir_motion_action_scroll:
+              event = clutter_event_new (CLUTTER_SCROLL);
+              if (ABS (pointer->hscroll) == 1 && pointer->vscroll == 0)
+                {
+                  clutter_event_set_scroll_direction (event, pointer->hscroll < 0 ?
+                                                             CLUTTER_SCROLL_LEFT :
+                                                             CLUTTER_SCROLL_RIGHT);
+                }
+              else if (ABS (pointer->vscroll) == 1 && pointer->hscroll == 0)
+                {
+                  clutter_event_set_scroll_direction (event, pointer->vscroll < 0 ?
+                                                             CLUTTER_SCROLL_DOWN :
+                                                             CLUTTER_SCROLL_UP);
+                }
+              else
+                {
+                  clutter_event_set_scroll_delta (event, -pointer->hscroll, -pointer->vscroll);
+                }
+              break;
+
+            case mir_motion_action_move:
+            case mir_motion_action_hover_move:
+              event = clutter_event_new (CLUTTER_MOTION);
+              break;
+
+            case mir_motion_action_hover_enter:
+              event = clutter_event_new (CLUTTER_ENTER);
+              _clutter_input_device_set_stage (device, stage);
+              break;
+
+            case mir_motion_action_hover_exit:
+              event = clutter_event_new (CLUTTER_LEAVE);
+              _clutter_input_device_set_stage (device, NULL);
+              break;
+          }
+
+        if (event)
+          {
+            modifiers = translate_mir_modifier (mir_event->motion.modifiers,
+                                                button_state);
+
+            clutter_event_set_time (event, NANO_TO_MILLI (mir_event->motion.event_time));
+            clutter_event_set_state (event, modifiers);
+            clutter_event_set_coords (event, pointer->x, pointer->y);
+          }
+
+        break;
+
+      case mir_event_type_surface:
+        switch (mir_event->surface.attrib)
+          {
+            case mir_surface_attrib_state:
+              if (mir_event->surface.value == mir_surface_state_fullscreen)
+                {
+                  _clutter_stage_update_state (stage,
+                                               0,
+                                               CLUTTER_STAGE_STATE_FULLSCREEN);
+                }
+              else
+                {
+                  _clutter_stage_update_state (stage,
+                                               CLUTTER_STAGE_STATE_FULLSCREEN,
+                                               0);
+                }
+              break;
+
+            case mir_surface_attrib_focus:
+              if (mir_event->surface.value == mir_surface_focused)
+                {
+                  _clutter_stage_update_state (stage,
+                                               0,
+                                               CLUTTER_STAGE_STATE_ACTIVATED);
+                }
+              else /* if (mir_event->surface.value == mir_surface_unfocused) */
+                {
+                  _clutter_stage_update_state (stage,
+                                               CLUTTER_STAGE_STATE_ACTIVATED,
+                                               0);
+                }
+              break;
+
+            default:
+              break;
+          }
+        break;
+
+      case mir_event_type_close_surface:
+          event = clutter_event_new (CLUTTER_DESTROY_NOTIFY);
+        break;
+
+      default:
+        break;
+    }
+
+  if (event)
+    {
+      clutter_event_set_stage (event, stage);
+      clutter_event_set_device (event, device);
+      clutter_event_set_source_device (event, device);
+
+      _clutter_event_push (event, FALSE);
+    }
+
+    g_mutex_unlock (&mir_event_lock);
+
+    if (event)
+      g_main_context_wakeup (NULL);
+}
diff --git a/clutter/mir/clutter-event-mir.h b/clutter/mir/clutter-event-mir.h
new file mode 100644
index 0000000..f537dbb
--- /dev/null
+++ b/clutter/mir/clutter-event-mir.h
@@ -0,0 +1,40 @@
+/*
+ * 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>
+ */
+
+#ifndef __CLUTTER_EVENT_MIR_H__
+#define __CLUTTER_EVENT_MIR_H__
+
+#include <glib-object.h>
+#include <clutter/clutter-event.h>
+
+#include <mir_toolkit/event.h>
+
+GSource *
+_clutter_event_source_mir_new (void);
+
+void
+_clutter_mir_handle_event (ClutterBackend *backend, MirSurface *surface, MirEvent *event);
+
+#endif /* __CLUTTER_EVENT_MIR_H__ */
diff --git a/clutter/mir/clutter-input-device-mir.c b/clutter/mir/clutter-input-device-mir.c
new file mode 100644
index 0000000..3e5f8fa
--- /dev/null
+++ b/clutter/mir/clutter-input-device-mir.c
@@ -0,0 +1,55 @@
+/*
+ * 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-device-manager-private.h"
+#include "clutter-input-device-mir.h"
+
+typedef struct _ClutterInputDeviceClass ClutterInputDeviceMirClass;
+
+#define clutter_input_device_mir_get_type _clutter_input_device_mir_get_type
+G_DEFINE_TYPE (ClutterInputDeviceMir, clutter_input_device_mir, CLUTTER_TYPE_INPUT_DEVICE);
+
+static gboolean
+clutter_input_device_mir_keycode_to_evdev (ClutterInputDevice *device,
+                                           guint hardware_keycode,
+                                           guint *evdev_keycode)
+{
+  *evdev_keycode = hardware_keycode - 8;
+  return TRUE;
+}
+
+static void
+clutter_input_device_mir_class_init (ClutterInputDeviceMirClass *klass)
+{
+  klass->keycode_to_evdev = clutter_input_device_mir_keycode_to_evdev;
+}
+
+static void
+clutter_input_device_mir_init (ClutterInputDeviceMir *self)
+{
+}
diff --git a/clutter/mir/clutter-input-device-mir.h b/clutter/mir/clutter-input-device-mir.h
new file mode 100644
index 0000000..a8ee662
--- /dev/null
+++ b/clutter/mir/clutter-input-device-mir.h
@@ -0,0 +1,45 @@
+/*
+ * 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>
+ */
+
+#ifndef __CLUTTER_INPUT_DEVICE_MIR_H__
+#define __CLUTTER_INPUT_DEVICE_MIR_H__
+
+#include <glib-object.h>
+#include <clutter/clutter-event.h>
+
+#define CLUTTER_TYPE_INPUT_DEVICE_MIR       (_clutter_input_device_mir_get_type ())
+#define CLUTTER_INPUT_DEVICE_MIR(obj)       (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
CLUTTER_TYPE_INPUT_DEVICE_MIR, ClutterInputDeviceMir))
+#define CLUTTER_IS_INPUT_DEVICE_MIR(obj)    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
CLUTTER_TYPE_INPUT_DEVICE_MIR))
+
+typedef struct _ClutterInputDeviceMir ClutterInputDeviceMir;
+
+struct _ClutterInputDeviceMir
+{
+  ClutterInputDevice parent_device;
+};
+
+GType _clutter_input_device_mir_get_type (void) G_GNUC_CONST;
+
+#endif /* __CLUTTER_INPUT_DEVICE_MIR_H__ */
diff --git a/clutter/mir/clutter-mir.h b/clutter/mir/clutter-mir.h
new file mode 100644
index 0000000..cecc3e3
--- /dev/null
+++ b/clutter/mir/clutter-mir.h
@@ -0,0 +1,57 @@
+/*
+ * 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>
+ */
+
+/**
+ * SECTION:clutter-mir
+ * @short_description: Mir specific API
+ *
+ * The Mir backend for Clutter provides some specific API, allowing
+ * integration with the Mir client API for acessing the underlying data
+ * structures
+ *
+ * The Clutter Mir API is available since Clutter 1.22
+ */
+
+#ifndef __CLUTTER_MIR_H__
+#define __CLUTTER_MIR_H__
+
+#include <glib.h>
+#include <mir_toolkit/mir_client_library.h>
+#include <clutter/clutter.h>
+G_BEGIN_DECLS
+
+CLUTTER_AVAILABLE_IN_1_22
+MirSurface *clutter_mir_stage_get_mir_surface (ClutterStage *stage);
+
+CLUTTER_AVAILABLE_IN_1_22
+void clutter_mir_stage_set_mir_surface (ClutterStage *stage, MirSurface *surface);
+
+CLUTTER_AVAILABLE_IN_1_22
+void clutter_mir_set_connection (MirConnection *connection);
+
+CLUTTER_AVAILABLE_IN_1_22
+void clutter_mir_disable_event_retrieval (void);
+
+G_END_DECLS
+#endif /* __CLUTTER_MIR_H__ */
diff --git a/clutter/mir/clutter-stage-mir.c b/clutter/mir/clutter-stage-mir.c
new file mode 100644
index 0000000..9ca0225
--- /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");
+}
diff --git a/clutter/mir/clutter-stage-mir.h b/clutter/mir/clutter-stage-mir.h
new file mode 100644
index 0000000..187322b
--- /dev/null
+++ b/clutter/mir/clutter-stage-mir.h
@@ -0,0 +1,64 @@
+/*
+ * 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>
+ */
+
+#ifndef __CLUTTER_STAGE_MIR_H__
+#define __CLUTTER_STAGE_MIR_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib-object.h>
+#include <clutter/clutter-stage.h>
+#include "cogl/clutter-stage-cogl.h"
+
+#define CLUTTER_TYPE_STAGE_MIR                  (_clutter_stage_mir_get_type ())
+#define CLUTTER_STAGE_MIR(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_MIR, 
ClutterStageMir))
+#define CLUTTER_IS_STAGE_MIR(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STAGE_MIR))
+#define CLUTTER_STAGE_MIR_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_STAGE_MIR, 
ClutterStageMirClass))
+#define CLUTTER_IS_STAGE_MIR_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_STAGE_MIR))
+#define CLUTTER_STAGE_MIR_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_STAGE_MIR, 
ClutterStageMirClass))
+
+typedef struct _ClutterStageMir         ClutterStageMir;
+typedef struct _ClutterStageMirClass    ClutterStageMirClass;
+
+struct _ClutterStageMir
+{
+  ClutterStageCogl parent_instance;
+
+  MirSurfaceState surface_state;
+  MirMotionButton button_state;
+
+  gboolean foreign_mir_surface;
+  gboolean cursor_visible;
+};
+
+struct _ClutterStageMirClass
+{
+  ClutterStageCoglClass parent_class;
+};
+
+GType _clutter_stage_mir_get_type (void) G_GNUC_CONST;
+
+#endif /* __CLUTTER_STAGE_MIR_H__ */
diff --git a/configure.ac b/configure.ac
index e8c7262..f8ca4e3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -274,6 +274,10 @@ AC_ARG_ENABLE([egl-backend],
               [AS_HELP_STRING([--enable-egl-backend=@<:@yes/no@:>@], [Enable the EGL framebuffer backend 
(default=no)])],
               [enable_egl=$enableval],
               [enable_egl=no])
+AC_ARG_ENABLE([mir-backend],
+              [AS_HELP_STRING([--enable-mir-backend=@<:@yes/no@:>@], [Enable the Mir client backend 
(default=no)])],
+              [enable_mir=$enableval],
+              [enable_mir=no])
 AC_ARG_ENABLE([cex100-backend],
               [AS_HELP_STRING([--enable-cex100-backend=@<:@yes/no@:>@], [Enable the CEx100 backend 
(default=no)])],
               [enable_cex100=$enableval],
@@ -465,6 +469,45 @@ AS_IF([test "x$enable_win32" = "xyes"],
         SUPPORT_WIN32=1
       ])
 
+AS_IF([test "x$enable_mir" = "xyes"],
+      [
+        CLUTTER_BACKENDS="$CLUTTER_BACKENDS mir"
+        CLUTTER_INPUT_BACKENDS="$CLUTTER_INPUT_BACKENDS mir"
+
+        SUPPORT_MIR=1
+        SUPPORT_COGL=1
+
+        have_cogl_mir=no
+        SAVED_CFLAGS="${CFLAGS}"
+        CFLAGS="`$PKG_CONFIG --cflags $CLUTTER_BASE_PC_FILES`"
+
+        # Manually check whether cogl has Mir support, as we can't rely on
+        # versioning yet.
+        AC_MSG_CHECKING([for Mir Cogl backend])
+        AC_TRY_COMPILE([#include <cogl/cogl.h>],
+                       [
+                        #ifndef COGL_HAS_EGL_PLATFORM_MIR_SUPPORT
+                        #error "No Mir support in Cogl"
+                        #endif
+                        int main (void) { return 0; }
+                       ],
+                       AC_MSG_RESULT(yes)
+                       have_cogl_mir=yes,
+                       AC_MSG_RESULT(no)
+                       have_cogl_mir=no)
+
+        CFLAGS="${SAVED_CFLAGS}"
+
+        AS_IF([test "x$have_cogl_mir" = "xno"],
+              [AC_MSG_ERROR([COGL_HAS_EGL_PLATFORM_MIR_SUPPORT not defined but the Mir backend has been 
explicitly enabled])])
+
+        PKG_CHECK_EXISTS([mirclient],
+                         [BACKEND_PC_FILES="$BACKEND_PC_FILES mirclient"],
+                         [])
+
+        AC_DEFINE([HAVE_CLUTTER_MIR], [1], [Have the mir client backend])
+      ])
+
 AS_IF([test "x$CLUTTER_BACKENDS" = "x"],
       [
         AC_MSG_ERROR([No backend enabled. You need to enable at least one backend.])
@@ -519,6 +562,7 @@ AM_CONDITIONAL(SUPPORT_OSX,     [test "x$SUPPORT_OSX" = "x1"])
 AM_CONDITIONAL(SUPPORT_WIN32,   [test "x$SUPPORT_WIN32" = "x1"])
 AM_CONDITIONAL(SUPPORT_CEX100,  [test "x$SUPPORT_CEX100" = "x1"])
 AM_CONDITIONAL(SUPPORT_WAYLAND, [test "x$SUPPORT_WAYLAND" = "x1"])
+AM_CONDITIONAL(SUPPORT_MIR,     [test "x$SUPPORT_MIR" = "x1"])
 
 AM_CONDITIONAL(USE_COGL,  [test "x$SUPPORT_COGL" = "x1"])
 AM_CONDITIONAL(USE_TSLIB, [test "x$have_tslib" = "xyes"])
@@ -563,6 +607,10 @@ AS_IF([test "x$SUPPORT_EGL" = "x1"],
 AS_IF([test "x$SUPPORT_WAYLAND" = "x1"],
       [CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES
 #define CLUTTER_WINDOWING_WAYLAND \"wayland\""])
+AS_IF([test "x$SUPPORT_MIR" = "x1"],
+      [CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES
+#define CLUTTER_WINDOWING_MIR \"mir\"
+#define CLUTTER_INPUT_MIR \"mir\""])
 AS_IF([test "x$SUPPORT_OSX" = "x1"],
       [CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES
 #define CLUTTER_WINDOWING_OSX \"osx\"


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]