[mutter/wip/wayland-input] wayland: Add basic input support



commit bfe4a73d361c6553e3f6adfe449fbab635ecb545
Author: Neil Roberts <neil linux intel com>
Date:   Fri May 3 18:51:22 2013 +0100

    wayland: Add basic input support
    
    This copies the basic input support from the Clayland demo compositor.
    It adds a basic wl_seat implementation which can convert Clutter mouse
    events to Wayland events. For this to work all of the wayland surface
    actors need to be made reactive.
    
    The wayland keyboard input focus surface is updated whenever Mutter
    sees a FocusIn event so that it will stay in synch with whatever
    surface Mutter wants as the focus. Wayland surfaces don't get this
    event so for now it will just give them focus whenever they are
    clicked as a hack to test the code.

 configure.ac                        |    2 +
 src/Makefile.am                     |    6 +-
 src/compositor/meta-window-actor.c  |    8 +
 src/core/display-private.h          |    3 +
 src/core/display.c                  |   46 +++-
 src/wayland/meta-wayland-keyboard.c |  395 +++++++++++++++++++++++++++++++
 src/wayland/meta-wayland-keyboard.h |   97 ++++++++
 src/wayland/meta-wayland-private.h  |   27 ++-
 src/wayland/meta-wayland-seat.c     |  444 +++++++++++++++++++++++++++++++++++
 src/wayland/meta-wayland-seat.h     |   44 ++++
 src/wayland/meta-wayland.c          |  233 ++++++++++++++++++
 11 files changed, 1290 insertions(+), 15 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 5ee5384..71d438e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -139,6 +139,8 @@ AC_ARG_WITH([xwayland-path],
             [XWAYLAND_PATH="$withval"],
             [XWAYLAND_PATH="$bindir/Xorg"])
 
+AC_CHECK_FUNCS([mkostemp])
+
 AM_GLIB_GNU_GETTEXT
 
 ## here we get the flags we'll actually use
diff --git a/src/Makefile.am b/src/Makefile.am
index b0eb79f..9b03be5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -178,7 +178,11 @@ libmutter_la_SOURCES =                             \
 if HAVE_WAYLAND
 libmutter_la_SOURCES +=                                \
        wayland/meta-wayland.c                  \
-       wayland/meta-wayland-private.h
+       wayland/meta-wayland-private.h          \
+       wayland/meta-wayland-keyboard.c         \
+       wayland/meta-wayland-keyboard.h         \
+       wayland/meta-wayland-seat.c             \
+       wayland/meta-wayland-seat.h
 endif
 
 libmutter_la_LDFLAGS = -no-undefined
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index 5605e27..7603b82 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -2687,3 +2687,11 @@ meta_window_actor_set_updates_frozen (MetaWindowActor *self,
         }
     }
 }
+
+#ifdef HAVE_WAYLAND
+ClutterActor *
+meta_window_actor_get_shaped_texture (MetaWindowActor *self)
+{
+  return self->priv->actor;
+}
+#endif
diff --git a/src/core/display-private.h b/src/core/display-private.h
index 1f73fc3..2a111a0 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -462,6 +462,9 @@ void meta_display_accelerator_activate (MetaDisplay *display,
 /* In above-tab-keycode.c */
 guint meta_display_get_above_tab_keycode (MetaDisplay *display);
 
+gboolean meta_display_handle_event (MetaDisplay *display,
+                                    XEvent      *event);
+
 #ifdef HAVE_XI23
 gboolean meta_display_process_barrier_event (MetaDisplay    *display,
                                              XIBarrierEvent *event);
diff --git a/src/core/display.c b/src/core/display.c
index 6f11182..1aec6ee 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -1868,10 +1868,9 @@ get_input_event (MetaDisplay *display,
 }
 
 /**
- * event_callback:
+ * meta_display_handle_event:
+ * @display: The MetaDisplay that events are coming from
  * @event: The event that just happened
- * @data: The #MetaDisplay that events are coming from, cast to a gpointer
- *        so that it can be sent to a callback
  *
  * This is the most important function in the whole program. It is the heart,
  * it is the nexus, it is the Grand Central Station of Mutter's world.
@@ -1881,21 +1880,18 @@ get_input_event (MetaDisplay *display,
  * busy around here. Most of this function is a ginormous switch statement
  * dealing with all the kinds of events that might turn up.
  */
-static gboolean
-event_callback (XEvent   *event,
-                gpointer  data)
+gboolean
+meta_display_handle_event (MetaDisplay *display,
+                           XEvent   *event)
 {
   MetaWindow *window;
   MetaWindow *property_for_window;
-  MetaDisplay *display;
   Window modified;
   gboolean frame_was_receiver;
   gboolean bypass_compositor;
   gboolean filter_out_event;
   XIEvent *input_event;
 
-  display = data;
-  
 #ifdef WITH_VERBOSE_MODE
   if (dump_events)
     meta_spew_event (display, event);
@@ -2392,6 +2388,14 @@ event_callback (XEvent   *event,
             }
           break;
         case XI_FocusIn:
+#ifdef HAVE_WAYLAND
+          {
+            MetaWaylandCompositor *compositor =
+              meta_wayland_compositor_get_default ();
+            meta_wayland_compositor_set_input_focus (compositor, window);
+          }
+#endif
+          /* fall through */
         case XI_FocusOut:
           if (window)
             {
@@ -2967,6 +2971,30 @@ event_callback (XEvent   *event,
   return filter_out_event;
 }
 
+static gboolean
+event_callback (XEvent  *event,
+                gpointer data)
+{
+  MetaDisplay *display = data;
+
+  /* Under Wayland we want to filter out mouse motion events so we can
+     synthesize them from the Clutter events instead. This is
+     necessary because the position in the mouse events is passed to
+     the X server relative to the position of the surface. The X
+     server then translates these back to screen coordinates based on
+     the window position. If we rely on this translatation when
+     dragging a window around then the window will jump around
+     erratically because of the lag between updating the window
+     position from the surface position. Instead we bypass the
+     translation altogether by directly using the Clutter events */
+#ifdef HAVE_WAYLAND
+  if (event->type == MotionNotify)
+    return FALSE;
+#endif
+
+  return meta_display_handle_event (display, event);
+}
+
 /* Return the window this has to do with, if any, rather
  * than the frame or root window that was selecting
  * for substructure
diff --git a/src/wayland/meta-wayland-keyboard.c b/src/wayland/meta-wayland-keyboard.c
new file mode 100644
index 0000000..533d5ae
--- /dev/null
+++ b/src/wayland/meta-wayland-keyboard.c
@@ -0,0 +1,395 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+/*
+ * Copyright © 2010-2011 Intel Corporation
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+
+#include "config.h"
+
+#include <glib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "meta-wayland-keyboard.h"
+
+#ifndef HAVE_MKOSTEMP
+
+static int
+set_cloexec_or_close (int fd)
+{
+  long flags;
+
+  if (fd == -1)
+    return -1;
+
+  flags = fcntl (fd, F_GETFD);
+  if (flags == -1)
+    goto err;
+
+  if (fcntl (fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+    goto err;
+
+  return fd;
+
+err:
+  close (fd);
+  return -1;
+}
+
+#endif /* HAVE_MKOSTEMP */
+
+static int
+create_tmpfile_cloexec (char *tmpname)
+{
+  int fd;
+
+#ifdef HAVE_MKOSTEMP
+  fd = mkostemp (tmpname, O_CLOEXEC);
+  if (fd >= 0)
+    unlink (tmpname);
+#else
+  fd = mkstemp (tmpname);
+  if (fd >= 0)
+    {
+      fd = set_cloexec_or_close (fd);
+      unlink (tmpname);
+    }
+#endif
+
+  return fd;
+}
+
+static int
+create_anonymous_file (off_t size,
+                       GError **error)
+{
+  static const char template[] = "weston-shared-XXXXXX";
+  const char *path;
+  char *name;
+  int fd;
+
+  path = g_getenv ("XDG_RUNTIME_DIR");
+  if (!path)
+    {
+      errno = ENOENT;
+      return -1;
+    }
+
+  name = g_build_filename (path, template, NULL);
+
+  fd = create_tmpfile_cloexec (name);
+
+  free (name);
+
+  if (fd < 0)
+    return -1;
+
+  if (ftruncate (fd, size) < 0)
+    {
+      close (fd);
+      return -1;
+    }
+
+  return fd;
+}
+
+static gboolean
+meta_wayland_xkb_info_new_keymap (MetaWaylandXkbInfo *xkb_info)
+{
+  GError *error = NULL;
+  char *keymap_str;
+
+  xkb_info->shift_mod =
+    xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_SHIFT);
+  xkb_info->caps_mod =
+    xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_CAPS);
+  xkb_info->ctrl_mod =
+    xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_CTRL);
+  xkb_info->alt_mod =
+    xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_ALT);
+  xkb_info->mod2_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod2");
+  xkb_info->mod3_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod3");
+  xkb_info->super_mod =
+    xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_LOGO);
+  xkb_info->mod5_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod5");
+
+  keymap_str = xkb_map_get_as_string (xkb_info->keymap);
+  if (keymap_str == NULL)
+    {
+      g_warning ("failed to get string version of keymap\n");
+      return FALSE;
+    }
+  xkb_info->keymap_size = strlen (keymap_str) + 1;
+
+  xkb_info->keymap_fd = create_anonymous_file (xkb_info->keymap_size, &error);
+  if (xkb_info->keymap_fd < 0)
+    {
+      g_warning ("creating a keymap file for %lu bytes failed: %s\n",
+                 (unsigned long) xkb_info->keymap_size,
+                 error->message);
+      g_clear_error (&error);
+      goto err_keymap_str;
+    }
+
+  xkb_info->keymap_area = mmap (NULL, xkb_info->keymap_size,
+                                PROT_READ | PROT_WRITE,
+                                MAP_SHARED, xkb_info->keymap_fd, 0);
+  if (xkb_info->keymap_area == MAP_FAILED)
+    {
+      g_warning ("failed to mmap() %lu bytes\n",
+                 (unsigned long) xkb_info->keymap_size);
+      goto err_dev_zero;
+    }
+  strcpy (xkb_info->keymap_area, keymap_str);
+  free (keymap_str);
+
+  return TRUE;
+
+err_dev_zero:
+  close (xkb_info->keymap_fd);
+  xkb_info->keymap_fd = -1;
+err_keymap_str:
+  free (keymap_str);
+  return FALSE;
+}
+
+static gboolean
+meta_wayland_keyboard_build_global_keymap (struct xkb_context *xkb_context,
+                                           struct xkb_rule_names *xkb_names,
+                                           MetaWaylandXkbInfo *xkb_info)
+{
+  xkb_info->keymap = xkb_map_new_from_names (xkb_context,
+                                             xkb_names,
+                                             0 /* flags */);
+  if (xkb_info->keymap == NULL)
+    {
+      g_warning ("failed to compile global XKB keymap\n"
+                 "  tried rules %s, model %s, layout %s, variant %s, "
+                 "options %s\n",
+                 xkb_names->rules,
+                 xkb_names->model,
+                 xkb_names->layout,
+                 xkb_names->variant,
+                 xkb_names->options);
+      return FALSE;
+    }
+
+  if (!meta_wayland_xkb_info_new_keymap (xkb_info))
+    return FALSE;
+
+  return TRUE;
+}
+
+gboolean
+meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
+                            struct wl_display *display)
+{
+  wl_keyboard_init (&keyboard->parent);
+
+  keyboard->display = display;
+
+  memset (&keyboard->xkb_names, 0, sizeof (keyboard->xkb_names));
+
+  keyboard->xkb_context = xkb_context_new (0 /* flags */);
+
+  meta_wayland_keyboard_build_global_keymap (keyboard->xkb_context,
+                                             &keyboard->xkb_names,
+                                             &keyboard->xkb_info);
+
+  return TRUE;
+}
+
+static void
+meta_wayland_xkb_info_destroy (MetaWaylandXkbInfo *xkb_info)
+{
+  if (xkb_info->keymap)
+    xkb_map_unref (xkb_info->keymap);
+
+  if (xkb_info->keymap_area)
+    munmap (xkb_info->keymap_area, xkb_info->keymap_size);
+  if (xkb_info->keymap_fd >= 0)
+    close (xkb_info->keymap_fd);
+}
+
+static void
+set_modifiers (MetaWaylandKeyboard *meta_wayland_keyboard,
+               guint32 serial,
+               ClutterModifierType modifier_state)
+{
+  struct wl_keyboard *keyboard = &meta_wayland_keyboard->parent;
+  struct wl_keyboard_grab *grab = keyboard->grab;
+  uint32_t depressed_mods = 0;
+  uint32_t locked_mods = 0;
+
+  if (meta_wayland_keyboard->last_modifier_state == modifier_state)
+    return;
+
+  if ((modifier_state & CLUTTER_SHIFT_MASK) &&
+      meta_wayland_keyboard->xkb_info.shift_mod != XKB_MOD_INVALID)
+    depressed_mods |= (1 << meta_wayland_keyboard->xkb_info.shift_mod);
+
+  if ((modifier_state & CLUTTER_LOCK_MASK) &&
+      meta_wayland_keyboard->xkb_info.caps_mod != XKB_MOD_INVALID)
+    locked_mods |= (1 << meta_wayland_keyboard->xkb_info.caps_mod);
+
+  if ((modifier_state & CLUTTER_CONTROL_MASK) &&
+      meta_wayland_keyboard->xkb_info.ctrl_mod != XKB_MOD_INVALID)
+    depressed_mods |= (1 << meta_wayland_keyboard->xkb_info.ctrl_mod);
+
+  if ((modifier_state & CLUTTER_MOD1_MASK) &&
+      meta_wayland_keyboard->xkb_info.alt_mod != XKB_MOD_INVALID)
+    depressed_mods |= (1 << meta_wayland_keyboard->xkb_info.alt_mod);
+
+  if ((modifier_state & CLUTTER_MOD2_MASK) &&
+      meta_wayland_keyboard->xkb_info.mod2_mod != XKB_MOD_INVALID)
+    depressed_mods |= (1 << meta_wayland_keyboard->xkb_info.mod2_mod);
+
+  if ((modifier_state & CLUTTER_MOD3_MASK) &&
+      meta_wayland_keyboard->xkb_info.mod3_mod != XKB_MOD_INVALID)
+    depressed_mods |= (1 << meta_wayland_keyboard->xkb_info.mod3_mod);
+
+  if ((modifier_state & CLUTTER_SUPER_MASK) &&
+      meta_wayland_keyboard->xkb_info.super_mod != XKB_MOD_INVALID)
+    depressed_mods |= (1 << meta_wayland_keyboard->xkb_info.super_mod);
+
+  if ((modifier_state & CLUTTER_MOD5_MASK) &&
+      meta_wayland_keyboard->xkb_info.mod5_mod != XKB_MOD_INVALID)
+    depressed_mods |= (1 << meta_wayland_keyboard->xkb_info.mod5_mod);
+
+  meta_wayland_keyboard->last_modifier_state = modifier_state;
+
+  grab->interface->modifiers (grab,
+                              serial,
+                              depressed_mods,
+                              0, /* latched_modes */
+                              locked_mods,
+                              0 /* group */);
+}
+
+void
+meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *meta_wayland_keyboard,
+                                    const ClutterKeyEvent *event)
+{
+  struct wl_keyboard *keyboard = &meta_wayland_keyboard->parent;
+  gboolean state = event->type == CLUTTER_KEY_PRESS;
+  guint evdev_code;
+  uint32_t serial;
+
+  /* We can't do anything with the event if we can't get an evdev
+     keycode for it */
+  if (event->device == NULL ||
+      !clutter_input_device_keycode_to_evdev (event->device,
+                                              event->hardware_keycode,
+                                              &evdev_code))
+    return;
+
+  /* We want to ignore events that are sent because of auto-repeat. In
+     the Clutter event stream these appear as a single key press
+     event. We can detect that because the key will already have been
+     pressed */
+  if (state)
+    {
+      uint32_t *end = (void *) ((char *) keyboard->keys.data +
+                                keyboard->keys.size);
+      uint32_t *k;
+
+      /* Ignore the event if the key is already down */
+      for (k = keyboard->keys.data; k < end; k++)
+        if (*k == evdev_code)
+          return;
+
+      /* Otherwise add the key to the list of pressed keys */
+      k = wl_array_add (&keyboard->keys, sizeof (*k));
+      *k = evdev_code;
+    }
+  else
+    {
+      uint32_t *end = (void *) ((char *) keyboard->keys.data +
+                                keyboard->keys.size);
+      uint32_t *k;
+
+      /* Remove the key from the array */
+      for (k = keyboard->keys.data; k < end; k++)
+        if (*k == evdev_code)
+          {
+            *k = *(end - 1);
+            keyboard->keys.size -= sizeof (*k);
+
+            goto found;
+          }
+
+      g_warning ("unexpected key release event for key 0x%x", evdev_code);
+
+    found:
+      (void) 0;
+    }
+
+  serial = wl_display_next_serial (meta_wayland_keyboard->display);
+
+  set_modifiers (meta_wayland_keyboard, serial, event->modifier_state);
+
+  keyboard->grab->interface->key (keyboard->grab,
+                                  event->time,
+                                  evdev_code,
+                                  state);
+}
+
+void
+meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard)
+{
+  g_free ((char *) keyboard->xkb_names.rules);
+  g_free ((char *) keyboard->xkb_names.model);
+  g_free ((char *) keyboard->xkb_names.layout);
+  g_free ((char *) keyboard->xkb_names.variant);
+  g_free ((char *) keyboard->xkb_names.options);
+
+  meta_wayland_xkb_info_destroy (&keyboard->xkb_info);
+  xkb_context_unref (keyboard->xkb_context);
+
+  wl_keyboard_release (&keyboard->parent);
+}
diff --git a/src/wayland/meta-wayland-keyboard.h b/src/wayland/meta-wayland-keyboard.h
new file mode 100644
index 0000000..3bf6bcc
--- /dev/null
+++ b/src/wayland/meta-wayland-keyboard.h
@@ -0,0 +1,97 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __META_WAYLAND_KEYBOARD_H__
+#define __META_WAYLAND_KEYBOARD_H__
+
+#include <clutter/clutter.h>
+#include <wayland-server.h>
+
+#include <xkbcommon/xkbcommon.h>
+
+typedef struct
+{
+  struct xkb_keymap *keymap;
+  int keymap_fd;
+  size_t keymap_size;
+  char *keymap_area;
+  xkb_mod_index_t shift_mod;
+  xkb_mod_index_t caps_mod;
+  xkb_mod_index_t ctrl_mod;
+  xkb_mod_index_t alt_mod;
+  xkb_mod_index_t mod2_mod;
+  xkb_mod_index_t mod3_mod;
+  xkb_mod_index_t super_mod;
+  xkb_mod_index_t mod5_mod;
+} MetaWaylandXkbInfo;
+
+typedef struct
+{
+  struct wl_keyboard parent;
+
+  struct wl_display *display;
+
+  struct xkb_context *xkb_context;
+
+  MetaWaylandXkbInfo xkb_info;
+  struct xkb_rule_names xkb_names;
+
+  struct wl_keyboard_grab input_method_grab;
+  struct wl_resource *input_method_resource;
+
+  ClutterModifierType last_modifier_state;
+} MetaWaylandKeyboard;
+
+gboolean
+meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
+                            struct wl_display *display);
+
+void
+meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
+                                    const ClutterKeyEvent *event);
+
+void
+meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard);
+
+#endif /* __META_WAYLAND_KEYBOARD_H__ */
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
index 5b7e8e1..905f732 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -29,6 +29,8 @@
 
 #include "window-private.h"
 
+#include "meta-wayland-seat.h"
+
 typedef struct _MetaWaylandCompositor MetaWaylandCompositor;
 
 typedef struct
@@ -135,17 +137,32 @@ struct _MetaWaylandCompositor
   struct wl_client *xwayland_client;
   struct wl_resource *xserver_resource;
   GHashTable *window_surfaces;
+
+  MetaWaylandSeat *seat;
+
+  /* This surface is only used to keep drag of the implicit grab when
+     synthesizing XEvents for Mutter */
+  struct wl_surface *implicit_grab_surface;
+  /* Button that was pressed to initiate an implicit grab. The
+     implicit grab will only be released when this button is
+     released */
+  guint32 implicit_grab_button;
 };
 
-void                    meta_wayland_init                   (void);
-void                    meta_wayland_finalize               (void);
+void                    meta_wayland_init                       (void);
+void                    meta_wayland_finalize                   (void);
 
 /* We maintain a singleton MetaWaylandCompositor which can be got at via this
  * API after meta_wayland_init() has been called. */
-MetaWaylandCompositor  *meta_wayland_compositor_get_default (void);
+MetaWaylandCompositor  *meta_wayland_compositor_get_default     (void);
+
+void                    meta_wayland_handle_sig_child           (void);
+
+MetaWaylandSurface     *meta_wayland_lookup_surface_for_xid     (guint32 xid);
 
-void                    meta_wayland_handle_sig_child       (void);
+void                    meta_wayland_compositor_repick          (MetaWaylandCompositor *compositor);
 
-MetaWaylandSurface     *meta_wayland_lookup_surface_for_xid (guint32 xid);
+void                    meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
+                                                                 MetaWindow            *window);
 
 #endif /* META_WAYLAND_PRIVATE_H */
diff --git a/src/wayland/meta-wayland-seat.c b/src/wayland/meta-wayland-seat.c
new file mode 100644
index 0000000..e536379
--- /dev/null
+++ b/src/wayland/meta-wayland-seat.c
@@ -0,0 +1,444 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <clutter/clutter.h>
+#include <clutter/wayland/clutter-wayland-compositor.h>
+#include <clutter/wayland/clutter-wayland-surface.h>
+#include <linux/input.h>
+#include <stdlib.h>
+#include <string.h>
+#include "meta-wayland-seat.h"
+#include "meta-wayland-keyboard.h"
+#include "meta-wayland-private.h"
+
+struct _MetaWaylandSeat
+{
+  struct wl_seat parent;
+
+  struct wl_pointer pointer;
+  MetaWaylandKeyboard keyboard;
+
+  struct wl_display *display;
+
+  MetaWaylandSurface *sprite;
+  int hotspot_x, hotspot_y;
+  struct wl_listener sprite_destroy_listener;
+
+  ClutterActor *current_stage;
+};
+
+static void
+unbind_resource (struct wl_resource *resource)
+{
+  wl_list_remove (&resource->link);
+  free (resource);
+}
+
+static void
+transform_stage_point_fixed (MetaWaylandSurface *surface,
+                             wl_fixed_t x,
+                             wl_fixed_t y,
+                             wl_fixed_t *sx,
+                             wl_fixed_t *sy)
+{
+  float xf, yf;
+
+  clutter_actor_transform_stage_point (surface->actor,
+                                       wl_fixed_to_double (x),
+                                       wl_fixed_to_double (y),
+                                       &xf, &yf);
+
+  *sx = wl_fixed_from_double (xf);
+  *sy = wl_fixed_from_double (yf);
+}
+
+static void
+pointer_unmap_sprite (MetaWaylandSeat *seat)
+{
+  if (seat->sprite)
+    {
+      if (seat->sprite->actor)
+        clutter_actor_hide (seat->sprite->actor);
+      wl_list_remove (&seat->sprite_destroy_listener.link);
+      seat->sprite = NULL;
+    }
+}
+
+static void
+pointer_set_cursor (struct wl_client *client,
+                    struct wl_resource *resource,
+                    uint32_t serial,
+                    struct wl_resource *surface_resource,
+                    int32_t x, int32_t y)
+{
+  MetaWaylandSeat *seat = resource->data;
+  MetaWaylandSurface *surface;
+
+  surface = surface_resource ? surface_resource->data : NULL;
+
+  if (seat->parent.pointer->focus == NULL)
+    return;
+  if (seat->parent.pointer->focus->resource.client != client)
+    return;
+  if (seat->parent.pointer->focus_serial - serial > G_MAXUINT32 / 2)
+    return;
+
+  pointer_unmap_sprite (seat);
+
+  if (!surface)
+    return;
+
+  wl_signal_add (&surface->wayland_surface.resource.destroy_signal,
+                 &seat->sprite_destroy_listener);
+
+  seat->sprite = surface;
+  seat->hotspot_x = x;
+  seat->hotspot_y = y;
+}
+
+static const struct wl_pointer_interface
+pointer_interface =
+  {
+    pointer_set_cursor
+  };
+
+static void
+seat_get_pointer (struct wl_client *client,
+                  struct wl_resource *resource,
+                  uint32_t id)
+{
+  MetaWaylandSeat *seat = resource->data;
+  struct wl_resource *cr;
+
+  if (!seat->parent.pointer)
+    return;
+
+  cr = wl_client_add_object (client, &wl_pointer_interface,
+                             &pointer_interface, id, seat);
+  wl_list_insert (&seat->parent.pointer->resource_list, &cr->link);
+  cr->destroy = unbind_resource;
+
+  if (seat->parent.pointer->focus &&
+      seat->parent.pointer->focus->resource.client == client)
+    {
+      MetaWaylandSurface *surface;
+      wl_fixed_t sx, sy;
+
+      surface = (MetaWaylandSurface *) seat->parent.pointer->focus;
+      transform_stage_point_fixed (surface,
+                                   seat->parent.pointer->x,
+                                   seat->parent.pointer->y,
+                                   &sx, &sy);
+      wl_pointer_set_focus (seat->parent.pointer,
+                            seat->parent.pointer->focus,
+                            sx, sy);
+    }
+}
+
+static void
+seat_get_keyboard (struct wl_client *client,
+                   struct wl_resource *resource,
+                   uint32_t id)
+{
+  MetaWaylandSeat *seat = resource->data;
+  struct wl_resource *cr;
+
+  if (!seat->parent.keyboard)
+    return;
+
+  cr = wl_client_add_object (client, &wl_keyboard_interface, NULL, id, seat);
+  wl_list_insert (&seat->parent.keyboard->resource_list, &cr->link);
+  cr->destroy = unbind_resource;
+
+  wl_keyboard_send_keymap (cr,
+                           WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
+                           seat->keyboard.xkb_info.keymap_fd,
+                           seat->keyboard.xkb_info.keymap_size);
+
+  if (seat->parent.keyboard->focus &&
+      seat->parent.keyboard->focus->resource.client == client)
+    {
+      wl_keyboard_set_focus (seat->parent.keyboard,
+                             seat->parent.keyboard->focus);
+      wl_data_device_set_keyboard_focus (&seat->parent);
+    }
+}
+
+static void
+seat_get_touch (struct wl_client *client,
+                struct wl_resource *resource,
+                uint32_t id)
+{
+  /* Touch not supported */
+}
+
+static const struct wl_seat_interface
+seat_interface =
+  {
+    seat_get_pointer,
+    seat_get_keyboard,
+    seat_get_touch
+  };
+
+static void
+bind_seat (struct wl_client *client,
+           void *data,
+           guint32 version,
+           guint32 id)
+{
+  struct wl_seat *seat = data;
+  struct wl_resource *resource;
+
+  resource = wl_client_add_object (client,
+                                   &wl_seat_interface,
+                                   &seat_interface,
+                                   id,
+                                   data);
+  wl_list_insert (&seat->base_resource_list, &resource->link);
+  resource->destroy = unbind_resource;
+
+  wl_seat_send_capabilities (resource,
+                             WL_SEAT_CAPABILITY_POINTER |
+                             WL_SEAT_CAPABILITY_KEYBOARD);
+}
+
+static void
+pointer_handle_sprite_destroy (struct wl_listener *listener, void *data)
+{
+  MetaWaylandSeat *seat =
+    wl_container_of (listener, seat, sprite_destroy_listener);
+
+  seat->sprite = NULL;
+}
+
+MetaWaylandSeat *
+meta_wayland_seat_new (struct wl_display *display)
+{
+  MetaWaylandSeat *seat = g_new (MetaWaylandSeat, 1);
+
+  wl_seat_init (&seat->parent);
+
+  wl_pointer_init (&seat->pointer);
+  wl_seat_set_pointer (&seat->parent, &seat->pointer);
+
+  meta_wayland_keyboard_init (&seat->keyboard, display);
+  wl_seat_set_keyboard (&seat->parent, &seat->keyboard.parent);
+
+  seat->display = display;
+
+  seat->current_stage = 0;
+
+  seat->sprite = NULL;
+  seat->sprite_destroy_listener.notify = pointer_handle_sprite_destroy;
+  seat->hotspot_x = 16;
+  seat->hotspot_y = 16;
+
+  wl_display_add_global (display, &wl_seat_interface, seat, bind_seat);
+
+  return seat;
+}
+
+static void
+notify_motion (MetaWaylandSeat *seat,
+               const ClutterEvent *event)
+{
+  struct wl_pointer *pointer = seat->parent.pointer;
+  float x, y;
+
+  clutter_event_get_coords (event, &x, &y);
+  pointer->x = wl_fixed_from_double (x);
+  pointer->y = wl_fixed_from_double (y);
+
+  meta_wayland_seat_repick (seat,
+                            clutter_event_get_time (event),
+                            clutter_event_get_source (event));
+
+  pointer->grab->interface->motion (pointer->grab,
+                                    clutter_event_get_time (event),
+                                    pointer->grab->x,
+                                    pointer->grab->y);
+}
+
+static void
+handle_motion_event (MetaWaylandSeat *seat,
+                     const ClutterMotionEvent *event)
+{
+  notify_motion (seat, (const ClutterEvent *) event);
+}
+
+static void
+handle_button_event (MetaWaylandSeat *seat,
+                     const ClutterButtonEvent *event)
+{
+  struct wl_pointer *pointer = seat->parent.pointer;
+  gboolean state = event->type == CLUTTER_BUTTON_PRESS;
+  uint32_t button;
+
+  notify_motion (seat, (const ClutterEvent *) event);
+
+  switch (event->button)
+    {
+      /* The evdev input right and middle button numbers are swapped
+         relative to how Clutter numbers them */
+    case 2:
+      button = BTN_MIDDLE;
+      break;
+
+    case 3:
+      button = BTN_RIGHT;
+      break;
+
+    default:
+      button = event->button + BTN_LEFT - 1;
+      break;
+    }
+
+  if (state)
+    {
+      if (pointer->button_count == 0)
+        {
+          pointer->grab_button = button;
+          pointer->grab_time = event->time;
+          pointer->grab_x = pointer->x;
+          pointer->grab_y = pointer->y;
+        }
+
+      pointer->button_count++;
+    }
+  else
+    pointer->button_count--;
+
+  pointer->grab->interface->button (pointer->grab, event->time, button, state);
+
+  if (pointer->button_count == 1)
+    pointer->grab_serial = wl_display_get_serial (seat->display);
+}
+
+void
+meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
+                                const ClutterEvent *event)
+{
+  switch (event->type)
+    {
+    case CLUTTER_MOTION:
+      handle_motion_event (seat,
+                           (const ClutterMotionEvent *) event);
+      break;
+
+    case CLUTTER_BUTTON_PRESS:
+    case CLUTTER_BUTTON_RELEASE:
+      handle_button_event (seat,
+                           (const ClutterButtonEvent *) event);
+      break;
+
+    case CLUTTER_KEY_PRESS:
+    case CLUTTER_KEY_RELEASE:
+      meta_wayland_keyboard_handle_event (&seat->keyboard,
+                                          (const ClutterKeyEvent *) event);
+      break;
+
+    default:
+      break;
+    }
+}
+
+/* The actor argument can be NULL in which case a Clutter pick will be
+   performed to determine the right actor. An actor should only be
+   passed if the repick is being performed due to an event in which
+   case Clutter will have already performed a pick so we can avoid
+   redundantly doing another one */
+void
+meta_wayland_seat_repick (MetaWaylandSeat *seat,
+                          uint32_t time,
+                          ClutterActor *actor)
+{
+  struct wl_pointer *pointer = seat->parent.pointer;
+  struct wl_surface *surface;
+  MetaWaylandSurface *focus;
+
+  if (actor == NULL && seat->current_stage)
+    {
+      ClutterStage *stage = CLUTTER_STAGE (seat->current_stage);
+      actor = clutter_stage_get_actor_at_pos (stage,
+                                              CLUTTER_PICK_REACTIVE,
+                                              wl_fixed_to_double (pointer->x),
+                                              wl_fixed_to_double (pointer->y));
+    }
+
+  if (actor)
+    seat->current_stage = clutter_actor_get_stage (actor);
+  else
+    seat->current_stage = NULL;
+
+  if (CLUTTER_WAYLAND_IS_SURFACE (actor))
+    {
+      ClutterWaylandSurface *wl_surface = CLUTTER_WAYLAND_SURFACE (actor);
+      float ax, ay;
+
+      clutter_actor_transform_stage_point (actor,
+                                           wl_fixed_to_double (pointer->x),
+                                           wl_fixed_to_double (pointer->y),
+                                           &ax, &ay);
+      pointer->current_x = wl_fixed_from_double (ax);
+      pointer->current_y = wl_fixed_from_double (ay);
+
+      surface = clutter_wayland_surface_get_surface (wl_surface);
+    }
+  else
+    surface = NULL;
+
+  if (surface != pointer->current)
+    {
+      const struct wl_pointer_grab_interface *interface =
+        pointer->grab->interface;
+      interface->focus (pointer->grab,
+                        surface,
+                        pointer->current_x, pointer->current_y);
+      pointer->current = surface;
+    }
+
+  focus = (MetaWaylandSurface *) pointer->grab->focus;
+  if (focus)
+    {
+      float ax, ay;
+
+      clutter_actor_transform_stage_point (focus->actor,
+                                           wl_fixed_to_double (pointer->x),
+                                           wl_fixed_to_double (pointer->y),
+                                           &ax, &ay);
+      pointer->grab->x = wl_fixed_from_double (ax);
+      pointer->grab->y = wl_fixed_from_double (ay);
+    }
+}
+
+void
+meta_wayland_seat_free (MetaWaylandSeat *seat)
+{
+  pointer_unmap_sprite (seat);
+
+  wl_pointer_release (&seat->pointer);
+  meta_wayland_keyboard_release (&seat->keyboard);
+  wl_seat_release (&seat->parent);
+
+  g_slice_free (MetaWaylandSeat, seat);
+}
diff --git a/src/wayland/meta-wayland-seat.h b/src/wayland/meta-wayland-seat.h
new file mode 100644
index 0000000..0f175f7
--- /dev/null
+++ b/src/wayland/meta-wayland-seat.h
@@ -0,0 +1,44 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __META_WAYLAND_SEAT_H__
+#define __META_WAYLAND_SEAT_H__
+
+#include <wayland-server.h>
+
+typedef struct _MetaWaylandSeat MetaWaylandSeat;
+
+MetaWaylandSeat *
+meta_wayland_seat_new (struct wl_display *display);
+
+void
+meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
+                                const ClutterEvent *event);
+
+void
+meta_wayland_seat_repick (MetaWaylandSeat *seat,
+                          uint32_t time,
+                          ClutterActor *actor);
+
+void
+meta_wayland_seat_free (MetaWaylandSeat *seat);
+
+#endif /* __META_WAYLAND_SEAT_H__ */
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 5f48186..673189d 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -44,6 +44,7 @@
 
 #include "meta-wayland-private.h"
 #include "meta-window-actor-private.h"
+#include "meta-wayland-seat.h"
 #include "display-private.h"
 #include "window-private.h"
 #include <meta/types.h>
@@ -316,6 +317,8 @@ meta_wayland_surface_commit (struct wl_client *client,
             {
               surface_actor = CLUTTER_WAYLAND_SURFACE (surface->actor);
 
+              clutter_actor_set_reactive (surface->actor, TRUE);
+
               if (!clutter_wayland_surface_attach_buffer (surface_actor,
                                                           buffer,
                                                           &error))
@@ -381,6 +384,33 @@ const struct wl_surface_interface meta_wayland_surface_interface = {
   meta_wayland_surface_set_buffer_transform
 };
 
+void
+meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
+                                         MetaWindow            *window)
+{
+  struct wl_surface *surface = NULL;
+
+  if (window)
+    {
+      MetaWindowActor *window_actor =
+        META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
+      ClutterActor *shaped_texture =
+        meta_window_actor_get_shaped_texture (window_actor);
+
+      if (CLUTTER_WAYLAND_IS_SURFACE (shaped_texture))
+        {
+          ClutterWaylandSurface *surface_actor =
+            CLUTTER_WAYLAND_SURFACE (shaped_texture);
+
+          surface = clutter_wayland_surface_get_surface (surface_actor);
+        }
+    }
+
+  wl_keyboard_set_focus (((struct wl_seat *) compositor->seat)->keyboard,
+                         surface);
+  wl_data_device_set_keyboard_focus ((struct wl_seat *) compositor->seat);
+}
+
 static void
 surface_actor_destroyed_cb (void *user_data,
                             GObject *old_object)
@@ -391,6 +421,14 @@ surface_actor_destroyed_cb (void *user_data,
   surface->window = NULL;
 }
 
+void
+meta_wayland_compositor_repick (MetaWaylandCompositor *compositor)
+{
+  meta_wayland_seat_repick (compositor->seat,
+                            get_time (),
+                            NULL);
+}
+
 static void
 meta_wayland_surface_free (MetaWaylandSurface *surface)
 {
@@ -425,6 +463,12 @@ meta_wayland_surface_free (MetaWaylandSurface *surface)
     wl_resource_destroy (&cb->resource);
 
   g_slice_free (MetaWaylandSurface, surface);
+
+  meta_wayland_compositor_repick (compositor);
+
+ if (compositor->implicit_grab_surface == (struct wl_surface *) surface)
+   compositor->implicit_grab_surface =
+     ((struct wl_seat *) compositor->seat)->pointer->current;
 }
 
 static void
@@ -1281,10 +1325,180 @@ stage_destroy_cb (void)
   meta_quit (META_EXIT_SUCCESS);
 }
 
+static gboolean
+event_cb (ClutterActor *stage,
+          const ClutterEvent *event,
+          MetaWaylandCompositor *compositor)
+{
+  struct wl_seat *seat = (struct wl_seat *) compositor->seat;
+  struct wl_pointer *pointer = seat->pointer;
+  MetaWaylandSurface *surface;
+  MetaDisplay *display;
+  XMotionEvent xevent;
+
+  meta_wayland_seat_handle_event (compositor->seat, event);
+
+  /* HACK: for now, the surfaces from Wayland clients aren't
+     integrated into Mutter's stacking and Mutter won't give them
+     focus on mouse clicks. As a hack to work around this we can just
+     give them input focus on mouse clicks so we can at least test the
+     keyboard support */
+  if (event->type == CLUTTER_BUTTON_PRESS)
+    {
+      MetaWaylandSurface *surface = (MetaWaylandSurface *) pointer->current;
+
+      /* Only focus surfaces that wouldn't be handled by the
+         corresponding X events */
+      if (surface && surface->xid == 0)
+        {
+          wl_keyboard_set_focus (seat->keyboard, &surface->wayland_surface);
+          wl_data_device_set_keyboard_focus (seat);
+        }
+    }
+
+  display = meta_get_display ();
+  if (!display)
+    return FALSE;
+
+  /* We want to synthesize X events for mouse motion events so that we
+     don't have to rely on the X server's window position being
+     synched with the surface positoin. See the comment in
+     event_callback() in display.c */
+
+  switch (event->type)
+    {
+    case CLUTTER_BUTTON_PRESS:
+      if (compositor->implicit_grab_surface == NULL)
+        {
+          compositor->implicit_grab_button = event->button.button;
+          compositor->implicit_grab_surface = pointer->current;
+        }
+      return FALSE;
+
+    case CLUTTER_BUTTON_RELEASE:
+      if (event->type == CLUTTER_BUTTON_RELEASE &&
+          compositor->implicit_grab_surface &&
+          event->button.button == compositor->implicit_grab_button)
+        compositor->implicit_grab_surface = NULL;
+      return FALSE;
+
+    case CLUTTER_MOTION:
+      break;
+
+    default:
+      return FALSE;
+    }
+
+  xevent.type = MotionNotify;
+  xevent.is_hint = NotifyNormal;
+  xevent.same_screen = TRUE;
+  xevent.serial = 0;
+  xevent.send_event = False;
+  xevent.display = display->xdisplay;
+  xevent.root = DefaultRootWindow (display->xdisplay);
+
+  if (compositor->implicit_grab_surface)
+    surface = (MetaWaylandSurface *) compositor->implicit_grab_surface;
+  else
+    surface = (MetaWaylandSurface *) pointer->current;
+
+  if (surface == (MetaWaylandSurface *) pointer->current)
+    {
+      xevent.x = pointer->current_x;
+      xevent.y = pointer->current_y;
+    }
+  else if (surface)
+    {
+      float ax, ay;
+
+      clutter_actor_transform_stage_point (surface->actor,
+                                           pointer->x, pointer->y,
+                                           &ax, &ay);
+      xevent.x = ax;
+      xevent.y = ay;
+    }
+  else
+    {
+      xevent.x = pointer->x;
+      xevent.y = pointer->y;
+    }
+
+  if (surface && surface->xid != None)
+    xevent.window = surface->xid;
+  else
+    xevent.window = xevent.root;
+
+  /* Mutter doesn't really know about the sub-windows. This assumes it
+     doesn't care either */
+  xevent.subwindow = xevent.window;
+  xevent.time = event->any.time;
+  xevent.x_root = pointer->x;
+  xevent.y_root = pointer->y;
+  /* The Clutter state flags exactly match the X values */
+  xevent.state = clutter_event_get_state (event);
+
+  meta_display_handle_event (display, (XEvent *) &xevent);
+
+  return FALSE;
+}
+
+static gboolean
+event_emission_hook_cb (GSignalInvocationHint *ihint,
+                        guint n_param_values,
+                        const GValue *param_values,
+                        gpointer data)
+{
+  MetaWaylandCompositor *compositor = data;
+  ClutterActor *actor;
+  ClutterEvent *event;
+
+  g_return_val_if_fail (n_param_values == 2, FALSE);
+
+  actor = g_value_get_object (param_values + 0);
+  event = g_value_get_boxed (param_values + 1);
+
+  if (actor == NULL)
+    return TRUE /* stay connected */;
+
+  /* If this event belongs to the corresponding grab for this event
+   * type then the captured-event signal won't be emitted so we have
+   * to manually forward it on */
+
+  switch (event->type)
+    {
+      /* Pointer events */
+    case CLUTTER_MOTION:
+    case CLUTTER_ENTER:
+    case CLUTTER_LEAVE:
+    case CLUTTER_BUTTON_PRESS:
+    case CLUTTER_BUTTON_RELEASE:
+    case CLUTTER_SCROLL:
+      if (actor == clutter_get_pointer_grab ())
+        event_cb (clutter_actor_get_stage (actor),
+                  event,
+                  compositor);
+      break;
+
+      /* Keyboard events */
+    case CLUTTER_KEY_PRESS:
+    case CLUTTER_KEY_RELEASE:
+      if (actor == clutter_get_keyboard_grab ())
+        event_cb (clutter_actor_get_stage (actor),
+                  event,
+                  compositor);
+
+    default:
+      break;
+    }
+
+  return TRUE /* stay connected */;
+}
+
 void
 meta_wayland_init (void)
 {
   MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
+  guint event_signal;
 
   memset (compositor, 0, sizeof (MetaWaylandCompositor));
 
@@ -1332,6 +1546,25 @@ meta_wayland_init (void)
   g_signal_connect (compositor->stage, "destroy",
                     G_CALLBACK (stage_destroy_cb), NULL);
 
+  wl_data_device_manager_init (compositor->wayland_display);
+
+  compositor->seat = meta_wayland_seat_new (compositor->wayland_display);
+
+  g_signal_connect (compositor->stage,
+                    "captured-event",
+                    G_CALLBACK (event_cb),
+                    compositor);
+  /* If something sets a grab on an actor then the captured event
+   * signal won't get emitted but we still want to see these events so
+   * we can update the cursor position. To make sure we see all events
+   * we also install an emission hook on the event signal */
+  event_signal = g_signal_lookup ("event", CLUTTER_TYPE_STAGE);
+  g_signal_add_emission_hook (event_signal,
+                              0 /* detail */,
+                              event_emission_hook_cb,
+                              compositor, /* hook_data */
+                              NULL /* data_destroy */);
+
   meta_wayland_compositor_create_output (compositor, 0, 0, 1024, 600, 222, 125);
 
   if (wl_display_add_global (compositor->wayland_display, &wl_shell_interface,



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