[gtk+/wip/mir] mir: do proper event dispatching



commit bfeb03a63c2ed6e06cf24541c9adf5e49473c9b5
Author: Ryan Lortie <desrt desrt ca>
Date:   Wed May 28 11:25:55 2014 +0200

    mir: do proper event dispatching
    
    We had a race where destroying a window while an event is being
    dispatched to it could result in a crash.  We can't just hold a ref on
    the window because the object is externally visible and we could end up
    running a binding's toggle ref handler in the mir thread.
    
    Add a proper source type with a queue and try to do this properly by
    dispatching the event back to the main thread before we check if the
    window still exists (through use of a weak ref).
    
    This commit also moves all of the event translation code out of
    gdkmirwindowimpl.c (which is getting a bit big...).

 gdk/mir/Makefile.am         |    1 +
 gdk/mir/gdkmir-private.h    |   49 +++
 gdk/mir/gdkmirdisplay.c     |   12 +
 gdk/mir/gdkmireventsource.c |  793 +++++++++++++++++++++++++++++++++++++++++++
 gdk/mir/gdkmirwindowimpl.c  |  617 +--------------------------------
 5 files changed, 871 insertions(+), 601 deletions(-)
---
diff --git a/gdk/mir/Makefile.am b/gdk/mir/Makefile.am
index 1bfb5f4..f3f908c 100644
--- a/gdk/mir/Makefile.am
+++ b/gdk/mir/Makefile.am
@@ -23,6 +23,7 @@ libgdk_mir_la_SOURCES =       \
        gdkmircursor.c \
        gdkmirdevicemanager.c \
        gdkmirdisplay.c \
+       gdkmireventsource.c     \
        gdkmirkeyboard.c \
        gdkmirkeymap.c \
        gdkmirpointer.c \
diff --git a/gdk/mir/gdkmir-private.h b/gdk/mir/gdkmir-private.h
index 95a5af6..8309edf 100644
--- a/gdk/mir/gdkmir-private.h
+++ b/gdk/mir/gdkmir-private.h
@@ -36,12 +36,51 @@
 
 #include "config.h"
 
+#include "gdkmir.h"
 #include "gdkdisplay.h"
 #include "gdkscreen.h"
 #include "gdkdevicemanager.h"
 #include "gdkkeys.h"
 #include "gdkwindowimpl.h"
 
+typedef struct _GdkMirWindowImpl GdkMirWindowImpl;
+typedef struct _GdkMirWindowReference GdkMirWindowReference;
+typedef struct _GdkMirEventSource GdkMirEventSource;
+
+#define GDK_TYPE_MIR_WINDOW_IMPL              (gdk_mir_window_impl_get_type ())
+#define GDK_MIR_WINDOW_IMPL(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), 
GDK_TYPE_WINDOW_IMPL_MIR, GdkMirWindowImpl))
+#define GDK_IS_WINDOW_IMPL_MIR(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), 
GDK_TYPE_WINDOW_IMPL_MIR))
+
+struct _GdkMirWindowImpl
+{
+  GdkWindowImpl parent_instance;
+
+  /* Desired surface attributes */
+  MirSurfaceType surface_type; // FIXME
+  MirSurfaceState surface_state;
+
+  /* Pattern for background */
+  cairo_pattern_t *background;
+
+  /* Current button state for checking which buttons are being pressed / released */
+  gdouble x;
+  gdouble y;
+  MirMotionButton button_state;
+
+  /* Surface being rendered to (only exists when window visible) */
+  MirSurface *surface;
+
+  /* Cairo context for current frame */
+  cairo_surface_t *cairo_surface;
+
+  /* TRUE if the window can be seen */
+  gboolean visible;
+
+  /* TRUE if cursor is inside this window */
+  gboolean cursor_inside;
+};
+
+
 GdkDisplay *_gdk_mir_display_open (const gchar *display_name);
 
 GdkScreen *_gdk_mir_screen_new (GdkDisplay *display);
@@ -62,4 +101,14 @@ GdkCursor *_gdk_mir_cursor_new (GdkDisplay *display, GdkCursorType type);
 
 GdkWindowImpl *_gdk_mir_window_impl_new (void);
 
+GdkMirEventSource *_gdk_mir_display_get_event_source (GdkDisplay *display);
+
+GdkMirEventSource *_gdk_mir_event_source_new (GdkDisplay *display);
+
+GdkMirWindowReference *_gdk_mir_event_source_get_window_reference (GdkWindow *window);
+
+void _gdk_mir_window_reference_unref (GdkMirWindowReference *ref);
+
+void _gdk_mir_event_source_queue (GdkMirWindowReference *window_ref, const MirEvent *event);
+
 #endif /* __GDK_PRIVATE_MIR_H__ */
diff --git a/gdk/mir/gdkmirdisplay.c b/gdk/mir/gdkmirdisplay.c
index dc6ed1f..67af65d 100644
--- a/gdk/mir/gdkmirdisplay.c
+++ b/gdk/mir/gdkmirdisplay.c
@@ -35,6 +35,9 @@ typedef struct GdkMirDisplay
   /* Connection to Mir server */
   MirConnection *connection;
 
+  /* Event source */
+  GdkMirEventSource *event_source;
+
   /* Serial number? */
   gulong serial;
 
@@ -133,6 +136,14 @@ gdk_mir_display_get_mir_connection (GdkDisplay *display)
   return GDK_MIR_DISPLAY (display)->connection;
 }
 
+GdkMirEventSource *
+_gdk_mir_display_get_event_source (GdkDisplay *display)
+{
+  g_return_val_if_fail (GDK_IS_MIR_DISPLAY (display), NULL);
+
+  return GDK_MIR_DISPLAY (display)->event_source;
+}
+
 static void
 gdk_mir_display_dispose (GObject *object)
 {
@@ -493,6 +504,7 @@ gdk_mir_display_utf8_to_string_target (GdkDisplay  *display,
 static void
 gdk_mir_display_init (GdkMirDisplay *display)
 {
+  display->event_source = _gdk_mir_event_source_new (GDK_DISPLAY (display));
   display->cursor = _gdk_mir_cursor_new (GDK_DISPLAY (display), GDK_ARROW);
   display->keymap = _gdk_mir_keymap_new ();
 }
diff --git a/gdk/mir/gdkmireventsource.c b/gdk/mir/gdkmireventsource.c
new file mode 100644
index 0000000..f7908fc
--- /dev/null
+++ b/gdk/mir/gdkmireventsource.c
@@ -0,0 +1,793 @@
+/*
+ * Copyright © 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/>.
+ */
+
+#include "config.h"
+
+#include "gdkinternals.h"
+#include "gdkdisplayprivate.h"
+#include "gdkmir.h"
+#include "gdkmir-private.h"
+
+struct _GdkMirWindowReference {
+  GdkMirEventSource *source;
+  GdkWindow         *window;
+  gint               ref_count;
+};
+
+typedef struct {
+  GdkMirWindowReference *window_ref;
+  MirEvent               event;
+} GdkMirQueuedEvent;
+
+struct _GdkMirEventSource
+{
+  GSource parent_instance;
+
+  GMutex mir_event_lock;
+  GQueue mir_events;
+
+  GdkDisplay *display;
+};
+
+static void
+print_modifiers (unsigned int modifiers)
+{
+  g_printerr (" Modifiers");
+  if ((modifiers & mir_key_modifier_alt) != 0)
+    g_printerr (" alt");
+  if ((modifiers & mir_key_modifier_alt_left) != 0)
+    g_printerr (" alt-left");
+  if ((modifiers & mir_key_modifier_alt_right) != 0)
+    g_printerr (" alt-right");
+  if ((modifiers & mir_key_modifier_shift) != 0)
+    g_printerr (" shift");
+  if ((modifiers & mir_key_modifier_shift_left) != 0)
+    g_printerr (" shift-left");
+  if ((modifiers & mir_key_modifier_shift_right) != 0)
+    g_printerr (" shift-right");
+  if ((modifiers & mir_key_modifier_sym) != 0)
+    g_printerr (" sym");
+  if ((modifiers & mir_key_modifier_function) != 0)
+    g_printerr (" function");
+  if ((modifiers & mir_key_modifier_ctrl) != 0)
+    g_printerr (" ctrl");
+  if ((modifiers & mir_key_modifier_ctrl_left) != 0)
+    g_printerr (" ctrl-left");
+  if ((modifiers & mir_key_modifier_ctrl_right) != 0)
+    g_printerr (" ctrl-right");
+  if ((modifiers & mir_key_modifier_meta) != 0)
+    g_printerr (" meta");
+  if ((modifiers & mir_key_modifier_meta_left) != 0)
+    g_printerr (" meta-left");
+  if ((modifiers & mir_key_modifier_meta_right) != 0)
+    g_printerr (" meta-right");
+  if ((modifiers & mir_key_modifier_caps_lock) != 0)
+    g_printerr (" caps-lock");
+  if ((modifiers & mir_key_modifier_num_lock) != 0)
+    g_printerr (" num-lock");
+  if ((modifiers & mir_key_modifier_scroll_lock) != 0)
+    g_printerr (" scroll-lock");
+  g_printerr ("\n");
+}
+
+static void
+print_key_event (const MirKeyEvent *event)
+{
+  g_printerr ("KEY\n");
+  g_printerr (" Device %i\n", event->device_id);
+  g_printerr (" Source %i\n", event->source_id);
+  g_printerr (" Action ");
+  switch (event->action)
+    {
+    case mir_key_action_down:
+      g_printerr ("down");
+      break;
+    case mir_key_action_up:
+      g_printerr ("up");
+      break;
+    case mir_key_action_multiple:
+      g_printerr ("multiple");
+      break;
+    default:
+      g_printerr ("%u", event->action);
+      break;
+    }
+  g_printerr ("\n");
+  g_printerr (" Flags");
+  if ((event->flags & mir_key_flag_woke_here) != 0)
+    g_printerr (" woke-here");
+  if ((event->flags & mir_key_flag_soft_keyboard) != 0)
+    g_printerr (" soft-keyboard");
+  if ((event->flags & mir_key_flag_keep_touch_mode) != 0)
+    g_printerr (" keep-touch-mode");
+  if ((event->flags & mir_key_flag_from_system) != 0)
+    g_printerr (" from-system");
+  if ((event->flags & mir_key_flag_editor_action) != 0)
+    g_printerr (" editor-action");
+  if ((event->flags & mir_key_flag_canceled) != 0)
+    g_printerr (" canceled");
+  if ((event->flags & mir_key_flag_virtual_hard_key) != 0)
+    g_printerr (" virtual-hard-key");
+  if ((event->flags & mir_key_flag_long_press) != 0)
+    g_printerr (" long-press");
+  if ((event->flags & mir_key_flag_canceled_long_press) != 0)
+    g_printerr (" canceled-long-press");
+  if ((event->flags & mir_key_flag_tracking) != 0)
+    g_printerr (" tracking");
+  if ((event->flags & mir_key_flag_fallback) != 0)
+    g_printerr (" fallback");
+  g_printerr ("\n");
+  print_modifiers (event->modifiers);
+  g_printerr (" Key Code %i\n", event->key_code);
+  g_printerr (" Scan Code %i\n", event->scan_code);
+  g_printerr (" Repeat Count %i\n", event->repeat_count);
+  g_printerr (" Down Time %lli\n", (long long int) event->down_time);
+  g_printerr (" Event Time %lli\n", (long long int) event->event_time);
+  g_printerr (" Is System Key %s\n", event->is_system_key ? "true" : "false");
+}
+
+static void
+print_motion_event (const MirMotionEvent *event)
+{
+  size_t i;
+
+  g_printerr ("MOTION\n");
+  g_printerr (" Device %i\n", event->device_id);
+  g_printerr (" Source %i\n", event->source_id);
+  g_printerr (" Action ");
+  switch (event->action)
+    {
+    case mir_motion_action_down:
+      g_printerr ("down");
+      break;
+    case mir_motion_action_up:
+      g_printerr ("up");
+      break;
+    case mir_motion_action_move:
+      g_printerr ("move");
+      break;
+    case mir_motion_action_cancel:
+      g_printerr ("cancel");
+      break;
+    case mir_motion_action_outside:
+      g_printerr ("outside");
+      break;
+    case mir_motion_action_pointer_down:
+      g_printerr ("pointer-down");
+      break;
+    case mir_motion_action_pointer_up:
+      g_printerr ("pointer-up");
+      break;
+    case mir_motion_action_hover_move:
+      g_printerr ("hover-move");
+      break;
+    case mir_motion_action_scroll:
+      g_printerr ("scroll");
+      break;
+    case mir_motion_action_hover_enter:
+      g_printerr ("hover-enter");
+      break;
+    case mir_motion_action_hover_exit:
+      g_printerr ("hover-exit");
+      break;
+    default:
+      g_printerr ("%u", event->action);
+    }
+  g_printerr ("\n");
+  g_printerr (" Flags");
+  switch (event->flags)
+    {
+    case mir_motion_flag_window_is_obscured:
+      g_printerr (" window-is-obscured");
+      break;
+    }
+  g_printerr ("\n");
+  print_modifiers (event->modifiers);
+  g_printerr (" Edge Flags %i\n", event->edge_flags);
+  g_printerr (" Button State");
+  switch (event->button_state)
+    {
+    case mir_motion_button_primary:
+      g_printerr (" primary");
+      break;
+    case mir_motion_button_secondary:
+      g_printerr (" secondary");
+      break;
+    case mir_motion_button_tertiary:
+      g_printerr (" tertiary");
+      break;
+    case mir_motion_button_back:
+      g_printerr (" back");
+      break;
+    case mir_motion_button_forward:
+      g_printerr (" forward");
+      break;
+    }
+  g_printerr ("\n");
+  g_printerr (" Offset (%f, %f)\n", event->x_offset, event->y_offset);
+  g_printerr (" Precision (%f, %f)\n", event->x_precision, event->y_precision);
+  g_printerr (" Down Time %lli\n", (long long int) event->down_time);
+  g_printerr (" Event Time %lli\n", (long long int) event->event_time);
+  g_printerr (" Pointer Coordinates\n");
+  for (i = 0; i < event->pointer_count; i++)
+    {
+      g_printerr ("  ID=%i location=(%f, %f) raw=(%f, %f) touch=(%f, %f) size=%f pressure=%f orientation=%f 
scroll=(%f, %f) tool=",
+                  event->pointer_coordinates[i].id,
+                  event->pointer_coordinates[i].x, event->pointer_coordinates[i].y,
+                  event->pointer_coordinates[i].raw_x, event->pointer_coordinates[i].raw_y,
+                  event->pointer_coordinates[i].touch_major, event->pointer_coordinates[i].touch_minor,
+                  event->pointer_coordinates[i].size,
+                  event->pointer_coordinates[i].pressure,
+                  event->pointer_coordinates[i].orientation,
+                  event->pointer_coordinates[i].hscroll, event->pointer_coordinates[i].vscroll);
+      switch (event->pointer_coordinates[i].tool_type)
+        {
+        case mir_motion_tool_type_unknown:
+          g_printerr ("unknown");
+          break;
+        case mir_motion_tool_type_finger:
+          g_printerr ("finger");
+          break;
+        case mir_motion_tool_type_stylus:
+          g_printerr ("stylus");
+          break;
+        case mir_motion_tool_type_mouse:
+          g_printerr ("mouse");
+          break;
+        case mir_motion_tool_type_eraser:
+          g_printerr ("eraser");
+          break;
+        default:
+          g_printerr ("%u", event->pointer_coordinates[i].tool_type);
+          break;
+        }
+      g_printerr ("\n");
+    }
+}
+
+static void
+print_surface_event (const MirSurfaceEvent *event)
+{
+  g_printerr ("SURFACE\n");
+  g_printerr (" Surface %i\n", event->id);
+  g_printerr (" Attribute ");
+  switch (event->attrib)
+    {
+    case mir_surface_attrib_type:
+      g_printerr ("type");
+      break;
+    case mir_surface_attrib_state:
+      g_printerr ("state");
+      break;
+    case mir_surface_attrib_swapinterval:
+      g_printerr ("swapinterval");
+      break;
+    case mir_surface_attrib_focus:
+      g_printerr ("focus");
+      break;
+    default:
+      g_printerr ("%u", event->attrib);
+      break;
+    }
+  g_printerr ("\n");
+  g_printerr (" Value %i\n", event->value);
+}
+
+static void
+print_resize_event (const MirResizeEvent *event)
+{
+  g_printerr ("RESIZE\n");
+  g_printerr (" Surface %i\n", event->surface_id);
+  g_printerr (" Size (%i, %i)\n", event->width, event->height);
+}
+
+static void
+print_event (const MirEvent *event)
+{
+  switch (event->type)
+    {
+    case mir_event_type_key:
+      print_key_event (&event->key);
+      break;
+    case mir_event_type_motion:
+      print_motion_event (&event->motion);
+      break;
+    case mir_event_type_surface:
+      print_surface_event (&event->surface);
+      break;
+    case mir_event_type_resize:
+      print_resize_event (&event->resize);
+      break;
+    default:
+      g_printerr ("EVENT %u\n", event->type);
+      break;
+    }
+}
+
+static void
+send_event (GdkWindow *window, GdkDevice *device, GdkEvent *event)
+{
+  GdkDisplay *display;
+  GList *node;
+
+  gdk_event_set_device (event, device);
+  gdk_event_set_screen (event, gdk_display_get_screen (gdk_window_get_display (window), 0));
+  event->any.window = g_object_ref (window);
+
+  display = gdk_window_get_display (window);
+  node = _gdk_event_queue_append (display, event);
+  _gdk_windowing_got_event (display, node, event, _gdk_display_get_next_serial (display));
+}
+
+static void
+generate_key_event (GdkWindow *window, GdkEventType type, guint state, guint keyval, guint16 keycode, 
gboolean is_modifier)
+{
+  GdkEvent *event;
+
+  event = gdk_event_new (type);
+  event->key.state = state;
+  event->key.keyval = keyval;
+  event->key.length = 0;
+  event->key.string = NULL; // FIXME: Is this still needed?
+  event->key.hardware_keycode = keycode;
+  event->key.group = 0; // FIXME
+  event->key.is_modifier = is_modifier;
+
+  send_event (window, _gdk_mir_device_manager_get_keyboard (gdk_display_get_device_manager 
(gdk_window_get_display (window))), event);
+}
+
+static GdkDevice *
+get_pointer (GdkWindow *window)
+{
+  return gdk_device_manager_get_client_pointer (gdk_display_get_device_manager (gdk_window_get_display 
(window)));
+}
+
+static void
+generate_button_event (GdkWindow *window, GdkEventType type, gdouble x, gdouble y, guint button, guint state)
+{
+  GdkEvent *event;
+
+  event = gdk_event_new (type);
+  event->button.x = x;
+  event->button.y = y;
+  event->button.state = state;
+  event->button.button = button;
+
+  send_event (window, get_pointer (window), event);
+}
+
+static void
+generate_scroll_event (GdkWindow *window, gdouble x, gdouble y, gdouble delta_x, gdouble delta_y, guint 
state)
+{
+  GdkEvent *event;
+
+  event = gdk_event_new (GDK_SCROLL);
+  event->scroll.x = x;
+  event->scroll.y = y;
+  event->scroll.state = state;
+  event->scroll.direction = GDK_SCROLL_SMOOTH;
+  event->scroll.delta_x = delta_x;
+  event->scroll.delta_y = delta_y;
+
+  send_event (window, get_pointer (window), event);
+}
+
+static void
+generate_motion_event (GdkWindow *window, gdouble x, gdouble y, guint state)
+{
+  GdkEvent *event;
+
+  event = gdk_event_new (GDK_MOTION_NOTIFY);
+  event->motion.x = x;
+  event->motion.y = y;
+  event->motion.state = state;
+  event->motion.is_hint = FALSE;
+
+  send_event (window, get_pointer (window), event);
+}
+
+static void
+generate_crossing_event (GdkWindow *window, GdkEventType type, gdouble x, gdouble y)
+{
+  GdkEvent *event;
+
+  event = gdk_event_new (type);
+  event->crossing.x = x;
+  event->crossing.y = y;
+  event->crossing.mode = GDK_CROSSING_NORMAL;
+  event->crossing.detail = GDK_NOTIFY_ANCESTOR;
+  event->crossing.focus = TRUE;
+
+  send_event (window, get_pointer (window), event);
+}
+
+static guint
+get_modifier_state (unsigned int modifiers, unsigned int button_state)
+{
+  guint modifier_state = 0;
+
+  if ((modifiers & mir_key_modifier_alt) != 0)
+    modifier_state |= GDK_MOD1_MASK;
+  if ((modifiers & mir_key_modifier_shift) != 0)
+    modifier_state |= GDK_SHIFT_MASK;
+  if ((modifiers & mir_key_modifier_ctrl) != 0)
+    modifier_state |= GDK_CONTROL_MASK;
+  if ((modifiers & mir_key_modifier_meta) != 0)
+    modifier_state |= GDK_SUPER_MASK;
+  if ((modifiers & mir_key_modifier_caps_lock) != 0)
+    modifier_state |= GDK_LOCK_MASK;
+  if ((button_state & mir_motion_button_primary) != 0)
+    modifier_state |= GDK_BUTTON1_MASK;
+  if ((button_state & mir_motion_button_secondary) != 0)
+    modifier_state |= GDK_BUTTON3_MASK;
+  if ((button_state & mir_motion_button_tertiary) != 0)
+    modifier_state |= GDK_BUTTON2_MASK;
+
+  return modifier_state;
+}
+
+/*
+  GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (event_data->window->impl);
+  MirMotionButton changed_button_state;
+  GdkEventType event_type;
+  gdouble x, y;
+  guint modifier_state;
+  gboolean is_modifier = FALSE;
+*/
+
+static void
+handle_key_event (GdkWindow *window, const MirKeyEvent *event)
+{
+  guint modifier_state;
+  gboolean is_modifier = FALSE;
+
+  modifier_state = get_modifier_state (event->modifiers, 0); // FIXME: Need to track button state
+
+  switch (event->action)
+    {
+    case mir_key_action_down:
+    case mir_key_action_up:
+      // FIXME: Convert keycode
+      // FIXME: is_modifier
+      generate_key_event (window,
+                          event->action == mir_key_action_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE,
+                          modifier_state,
+                          event->key_code,
+                          event->scan_code,
+                          is_modifier);
+      break;
+    default:
+    //case mir_key_action_multiple:
+      // FIXME
+      break;
+    }
+}
+
+static void
+handle_motion_event (GdkWindow *window, const MirMotionEvent *event)
+{
+  GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
+  guint modifier_state;
+  GdkEventType event_type;
+  MirMotionButton changed_button_state;
+
+  if (event->pointer_count > 0)
+    {
+      impl->x = event->pointer_coordinates[0].x;
+      impl->y = event->pointer_coordinates[0].y;
+    }
+  modifier_state = get_modifier_state (event->modifiers, event->button_state);
+
+  /* The Mir events generate hover-exits even while inside the window so
+     counteract this by always generating an enter notify on all other events */
+  if (!impl->cursor_inside && event->action != mir_motion_action_hover_exit)
+    {
+      impl->cursor_inside = TRUE;
+      generate_crossing_event (window, GDK_ENTER_NOTIFY, impl->x, impl->y);
+    }
+
+  /* Update which window has focus */
+  _gdk_mir_pointer_set_location (get_pointer (window), impl->x, impl->y, window, modifier_state);
+  switch (event->action)
+    {
+    case mir_motion_action_down:
+    case mir_motion_action_up:
+      event_type = event->action == mir_motion_action_down ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
+      changed_button_state = impl->button_state ^ event->button_state;
+      if ((changed_button_state & mir_motion_button_primary) != 0)
+        generate_button_event (window, event_type, impl->x, impl->y, GDK_BUTTON_PRIMARY, modifier_state);
+      if ((changed_button_state & mir_motion_button_secondary) != 0)
+        generate_button_event (window, event_type, impl->x, impl->y, GDK_BUTTON_SECONDARY, modifier_state);
+      if ((changed_button_state & mir_motion_button_tertiary) != 0)
+        generate_button_event (window, event_type, impl->x, impl->y, GDK_BUTTON_MIDDLE, modifier_state);
+      impl->button_state = event->button_state;
+      break;
+    case mir_motion_action_scroll:
+      generate_scroll_event (window, impl->x, impl->y, event->pointer_coordinates[0].hscroll, 
event->pointer_coordinates[0].vscroll, modifier_state);
+      break;
+    case mir_motion_action_move: // move with button
+    case mir_motion_action_hover_move: // move without button
+      generate_motion_event (window, impl->x, impl->y, modifier_state);
+      break;
+    case mir_motion_action_hover_exit:
+      impl->cursor_inside = FALSE;
+      generate_crossing_event (window, GDK_LEAVE_NOTIFY, impl->x, impl->y);
+      break;
+    }
+}
+
+static void
+handle_surface_event (GdkWindow *window, const MirSurfaceEvent *event)
+{
+  GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
+
+  switch (event->attrib)
+    {
+    case mir_surface_attrib_type:
+      break;
+    case mir_surface_attrib_state:
+      impl->surface_state = event->value;
+      // FIXME: notify
+      break;
+    case mir_surface_attrib_swapinterval:
+      break;
+    case mir_surface_attrib_focus:
+      if (event->value)
+        gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_FOCUSED);
+      else
+        gdk_synthesize_window_state (window, GDK_WINDOW_STATE_FOCUSED, 0);
+      break;
+    default:
+      break;
+    }
+}
+
+typedef struct
+{
+  GdkWindow *window;
+  MirEvent event;
+} EventData;
+
+static void
+gdk_mir_event_source_queue_event (GdkDisplay     *display,
+                                  GdkWindow      *window,
+                                  const MirEvent *event)
+{
+  if (g_getenv ("GDK_MIR_LOG_EVENTS"))
+    print_event (event);
+
+  // FIXME: Only generate events if the window wanted them?
+  switch (event->type)
+    {
+    case mir_event_type_key:
+      handle_key_event (window, &event->key);
+      break;
+    case mir_event_type_motion:
+      handle_motion_event (window, &event->motion);
+      break;
+    case mir_event_type_surface:
+      handle_surface_event (window, &event->surface);
+      break;
+    case mir_event_type_resize:
+      // FIXME: Generate configure event
+      break;
+    default:
+      // FIXME?
+      break;
+    }
+}
+
+static GdkMirQueuedEvent *
+gdk_mir_event_source_take_queued_event (GdkMirEventSource *source)
+{
+  GdkMirQueuedEvent *queued_event;
+
+  g_mutex_lock (&source->mir_event_lock);
+  queued_event = g_queue_pop_head (&source->mir_events);
+  g_mutex_unlock (&source->mir_event_lock);
+
+  return queued_event;
+}
+
+static void
+gdk_mir_queued_event_free (GdkMirQueuedEvent *event)
+{
+  _gdk_mir_window_reference_unref (event->window_ref);
+  g_slice_free (GdkMirQueuedEvent, event);
+}
+
+static void
+gdk_mir_event_source_convert_events (GdkMirEventSource *source)
+{
+  GdkMirQueuedEvent *event;
+
+  while ((event = gdk_mir_event_source_take_queued_event (source)))
+    {
+      GdkWindow *window = event->window_ref->window;
+
+      /* The window may have been destroyed in the main thread while the
+       * event was being dispatched...
+       */
+      if (window != NULL)
+        gdk_mir_event_source_queue_event (source->display, window, &event->event);
+
+      gdk_mir_queued_event_free (event);
+    }
+}
+
+static gboolean
+gdk_mir_event_source_prepare (GSource *g_source,
+                              gint    *timeout)
+{
+  GdkMirEventSource *source = (GdkMirEventSource *) g_source;
+  gboolean mir_events_in_queue;
+
+  if (_gdk_event_queue_find_first (source->display))
+   return TRUE;
+
+  g_mutex_lock (&source->mir_event_lock);
+  mir_events_in_queue = g_queue_get_length (&source->mir_events) > 0;
+  g_mutex_unlock (&source->mir_event_lock);
+
+  return mir_events_in_queue;
+}
+
+static gboolean
+gdk_mir_event_source_check (GSource *g_source)
+{
+  return gdk_mir_event_source_prepare (g_source, NULL);
+}
+
+static gboolean
+gdk_mir_event_source_dispatch (GSource     *g_source,
+                               GSourceFunc  callback,
+                               gpointer     user_data)
+{
+  GdkMirEventSource *source = (GdkMirEventSource *) g_source;
+  GdkEvent *event;
+
+  /* First, run the queue of events from the thread */
+  gdk_mir_event_source_convert_events (source);
+
+  /* Next, dispatch one single event from the display's queue.
+   *
+   * If there is more than one event then we will soon find ourselves
+   * back here again.
+   */
+
+  gdk_threads_enter ();
+
+  event = gdk_display_get_event (source->display);
+
+  if (event)
+    {
+      _gdk_event_emit (event);
+
+      gdk_event_free (event);
+    }
+
+  gdk_threads_leave ();
+
+  return TRUE;
+}
+
+static void
+gdk_mir_event_source_finalize (GSource *g_source)
+{
+  GdkMirEventSource *source = (GdkMirEventSource *) g_source;
+  GdkMirQueuedEvent *event;
+
+  while ((event = gdk_mir_event_source_take_queued_event (source)))
+    gdk_mir_queued_event_free (event);
+
+  g_mutex_clear (&source->mir_event_lock);
+}
+
+static GSourceFuncs gdk_mir_event_source_funcs = {
+  gdk_mir_event_source_prepare,
+  gdk_mir_event_source_check,
+  gdk_mir_event_source_dispatch,
+  gdk_mir_event_source_finalize
+};
+
+GdkMirEventSource *
+_gdk_mir_event_source_new (GdkDisplay *display)
+{
+  GdkMirEventSource *source;
+  GSource *g_source;
+
+  g_source = g_source_new (&gdk_mir_event_source_funcs, sizeof (GdkMirEventSource));
+  g_source_attach (g_source, NULL);
+
+  source = (GdkMirEventSource *) g_source;
+  g_mutex_init (&source->mir_event_lock);
+  source->display = display;
+
+  return source;
+}
+
+GdkMirWindowReference *
+_gdk_mir_event_source_get_window_reference (GdkWindow *window)
+{
+  static GQuark win_ref_quark;
+  GdkMirWindowReference *ref;
+
+  if G_UNLIKELY (!win_ref_quark)
+    win_ref_quark = g_quark_from_string ("GdkMirEventSource window reference");
+
+  ref = g_object_get_qdata (G_OBJECT (window), win_ref_quark);
+
+  if (!ref)
+    {
+      GdkMirEventSource *source;
+
+      source = _gdk_mir_display_get_event_source (gdk_window_get_display (window));
+      g_source_ref ((GSource *) source);
+
+      ref = g_slice_new (GdkMirWindowReference);
+      ref->window = window;
+      ref->source = source;
+      ref->ref_count = 0;
+      g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &ref->window);
+
+      g_object_set_qdata_full (G_OBJECT (window), win_ref_quark,
+                               ref, (GDestroyNotify) _gdk_mir_window_reference_unref);
+    }
+
+  g_atomic_int_inc (&ref->ref_count);
+
+  return ref;
+}
+
+void
+_gdk_mir_window_reference_unref (GdkMirWindowReference *ref)
+{
+  if (g_atomic_int_dec_and_test (&ref->ref_count))
+    {
+      if (ref->window)
+        g_object_remove_weak_pointer (G_OBJECT (ref->window), (gpointer *) &ref->window);
+
+      g_source_unref ((GSource *) ref->source);
+
+      g_slice_free (GdkMirWindowReference, ref);
+    }
+}
+
+void
+_gdk_mir_event_source_queue (GdkMirWindowReference *window_ref,
+                             const MirEvent        *event)
+{
+  GdkMirEventSource *source = window_ref->source;
+  GdkMirQueuedEvent *queued_event;
+
+  /* We are in the wrong thread right now.  We absolutely cannot touch
+   * the window.
+   *
+   * We can do pretty much anything we want with the source, though...
+   */
+
+  queued_event = g_slice_new (GdkMirQueuedEvent);
+  g_atomic_int_inc (&window_ref->ref_count);
+  queued_event->window_ref = window_ref;
+  queued_event->event = *event;
+
+  g_mutex_lock (&source->mir_event_lock);
+  g_queue_push_tail (&source->mir_events, queued_event);
+  g_mutex_unlock (&source->mir_event_lock);
+
+  g_main_context_wakeup (NULL);
+}
diff --git a/gdk/mir/gdkmirwindowimpl.c b/gdk/mir/gdkmirwindowimpl.c
index 7d5ed79..5ed96db 100644
--- a/gdk/mir/gdkmirwindowimpl.c
+++ b/gdk/mir/gdkmirwindowimpl.c
@@ -28,45 +28,12 @@
 #include "gdkdisplayprivate.h"
 #include "gdkdeviceprivate.h"
 
-#define GDK_TYPE_MIR_WINDOW_IMPL              (gdk_mir_window_impl_get_type ())
-#define GDK_MIR_WINDOW_IMPL(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), 
GDK_TYPE_WINDOW_IMPL_MIR, GdkMirWindowImpl))
 #define GDK_MIR_WINDOW_IMPL_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WINDOW_IMPL_MIR, 
GdkMirWindowImplClass))
-#define GDK_IS_WINDOW_IMPL_MIR(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), 
GDK_TYPE_WINDOW_IMPL_MIR))
 #define GDK_IS_WINDOW_IMPL_MIR_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WINDOW_IMPL_MIR))
 #define GDK_MIR_WINDOW_IMPL_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WINDOW_IMPL_MIR, 
GdkMirWindowImplClass))
 
-typedef struct _GdkMirWindowImpl GdkMirWindowImpl;
 typedef struct _GdkMirWindowImplClass GdkMirWindowImplClass;
 
-struct _GdkMirWindowImpl
-{
-  GdkWindowImpl parent_instance;
-
-  /* Desired surface attributes */
-  MirSurfaceType surface_type; // FIXME
-  MirSurfaceState surface_state;
-
-  /* Pattern for background */
-  cairo_pattern_t *background;
-
-  /* Current button state for checking which buttons are being pressed / released */
-  gdouble x;
-  gdouble y;
-  MirMotionButton button_state;
-
-  /* Surface being rendered to (only exists when window visible) */
-  MirSurface *surface;
-
-  /* Cairo context for current frame */
-  cairo_surface_t *cairo_surface;
-
-  /* TRUE if the window can be seen */
-  gboolean visible;
-
-  /* TRUE if cursor is inside this window */
-  gboolean cursor_inside;
-};
-
 struct _GdkMirWindowImplClass
 {
   GdkWindowImplClass parent_class;
@@ -100,574 +67,11 @@ set_surface_state (GdkMirWindowImpl *impl, MirSurfaceState state)
 }
 
 static void
-print_modifiers (unsigned int modifiers)
-{
-  g_printerr (" Modifiers");
-  if ((modifiers & mir_key_modifier_alt) != 0)
-    g_printerr (" alt");
-  if ((modifiers & mir_key_modifier_alt_left) != 0)
-    g_printerr (" alt-left");
-  if ((modifiers & mir_key_modifier_alt_right) != 0)
-    g_printerr (" alt-right");
-  if ((modifiers & mir_key_modifier_shift) != 0)
-    g_printerr (" shift");
-  if ((modifiers & mir_key_modifier_shift_left) != 0)
-    g_printerr (" shift-left");
-  if ((modifiers & mir_key_modifier_shift_right) != 0)
-    g_printerr (" shift-right");
-  if ((modifiers & mir_key_modifier_sym) != 0)
-    g_printerr (" sym");
-  if ((modifiers & mir_key_modifier_function) != 0)
-    g_printerr (" function");
-  if ((modifiers & mir_key_modifier_ctrl) != 0)
-    g_printerr (" ctrl");
-  if ((modifiers & mir_key_modifier_ctrl_left) != 0)
-    g_printerr (" ctrl-left");
-  if ((modifiers & mir_key_modifier_ctrl_right) != 0)
-    g_printerr (" ctrl-right");
-  if ((modifiers & mir_key_modifier_meta) != 0)
-    g_printerr (" meta");
-  if ((modifiers & mir_key_modifier_meta_left) != 0)
-    g_printerr (" meta-left");
-  if ((modifiers & mir_key_modifier_meta_right) != 0)
-    g_printerr (" meta-right");
-  if ((modifiers & mir_key_modifier_caps_lock) != 0)
-    g_printerr (" caps-lock");
-  if ((modifiers & mir_key_modifier_num_lock) != 0)
-    g_printerr (" num-lock");
-  if ((modifiers & mir_key_modifier_scroll_lock) != 0)
-    g_printerr (" scroll-lock");
-  g_printerr ("\n");
-}
-
-static void
-print_key_event (const MirKeyEvent *event)
-{
-  g_printerr ("KEY\n");
-  g_printerr (" Device %i\n", event->device_id);
-  g_printerr (" Source %i\n", event->source_id);
-  g_printerr (" Action ");
-  switch (event->action)
-    {
-    case mir_key_action_down:
-      g_printerr ("down");
-      break;
-    case mir_key_action_up:
-      g_printerr ("up");
-      break;
-    case mir_key_action_multiple:
-      g_printerr ("multiple");
-      break;
-    default:
-      g_printerr ("%u", event->action);
-      break;
-    }
-  g_printerr ("\n");
-  g_printerr (" Flags");
-  if ((event->flags & mir_key_flag_woke_here) != 0)
-    g_printerr (" woke-here");
-  if ((event->flags & mir_key_flag_soft_keyboard) != 0)
-    g_printerr (" soft-keyboard");
-  if ((event->flags & mir_key_flag_keep_touch_mode) != 0)
-    g_printerr (" keep-touch-mode");
-  if ((event->flags & mir_key_flag_from_system) != 0)
-    g_printerr (" from-system");
-  if ((event->flags & mir_key_flag_editor_action) != 0)
-    g_printerr (" editor-action");
-  if ((event->flags & mir_key_flag_canceled) != 0)
-    g_printerr (" canceled");
-  if ((event->flags & mir_key_flag_virtual_hard_key) != 0)
-    g_printerr (" virtual-hard-key");
-  if ((event->flags & mir_key_flag_long_press) != 0)
-    g_printerr (" long-press");
-  if ((event->flags & mir_key_flag_canceled_long_press) != 0)
-    g_printerr (" canceled-long-press");
-  if ((event->flags & mir_key_flag_tracking) != 0)
-    g_printerr (" tracking");
-  if ((event->flags & mir_key_flag_fallback) != 0)
-    g_printerr (" fallback");
-  g_printerr ("\n");
-  print_modifiers (event->modifiers);
-  g_printerr (" Key Code %i\n", event->key_code);
-  g_printerr (" Scan Code %i\n", event->scan_code);
-  g_printerr (" Repeat Count %i\n", event->repeat_count);
-  g_printerr (" Down Time %lli\n", (long long int) event->down_time);
-  g_printerr (" Event Time %lli\n", (long long int) event->event_time);
-  g_printerr (" Is System Key %s\n", event->is_system_key ? "true" : "false");
-}
-
-static void
-print_motion_event (const MirMotionEvent *event)
-{
-  size_t i;
-
-  g_printerr ("MOTION\n");
-  g_printerr (" Device %i\n", event->device_id);
-  g_printerr (" Source %i\n", event->source_id);
-  g_printerr (" Action ");
-  switch (event->action)
-    {
-    case mir_motion_action_down:
-      g_printerr ("down");
-      break;
-    case mir_motion_action_up:
-      g_printerr ("up");
-      break;
-    case mir_motion_action_move:
-      g_printerr ("move");
-      break;
-    case mir_motion_action_cancel:
-      g_printerr ("cancel");
-      break;
-    case mir_motion_action_outside:
-      g_printerr ("outside");
-      break;
-    case mir_motion_action_pointer_down:
-      g_printerr ("pointer-down");
-      break;
-    case mir_motion_action_pointer_up:
-      g_printerr ("pointer-up");
-      break;
-    case mir_motion_action_hover_move:
-      g_printerr ("hover-move");
-      break;
-    case mir_motion_action_scroll:
-      g_printerr ("scroll");
-      break;
-    case mir_motion_action_hover_enter:
-      g_printerr ("hover-enter");
-      break;
-    case mir_motion_action_hover_exit:
-      g_printerr ("hover-exit");
-      break;
-    default:
-      g_printerr ("%u", event->action);
-    }
-  g_printerr ("\n");
-  g_printerr (" Flags");
-  switch (event->flags)
-    {
-    case mir_motion_flag_window_is_obscured:
-      g_printerr (" window-is-obscured");
-      break;
-    }
-  g_printerr ("\n");
-  print_modifiers (event->modifiers);
-  g_printerr (" Edge Flags %i\n", event->edge_flags);
-  g_printerr (" Button State");
-  switch (event->button_state)
-    {
-    case mir_motion_button_primary:
-      g_printerr (" primary");
-      break;
-    case mir_motion_button_secondary:
-      g_printerr (" secondary");
-      break;
-    case mir_motion_button_tertiary:
-      g_printerr (" tertiary");
-      break;
-    case mir_motion_button_back:
-      g_printerr (" back");
-      break;
-    case mir_motion_button_forward:
-      g_printerr (" forward");
-      break;
-    }
-  g_printerr ("\n");
-  g_printerr (" Offset (%f, %f)\n", event->x_offset, event->y_offset);
-  g_printerr (" Precision (%f, %f)\n", event->x_precision, event->y_precision);
-  g_printerr (" Down Time %lli\n", (long long int) event->down_time);
-  g_printerr (" Event Time %lli\n", (long long int) event->event_time);
-  g_printerr (" Pointer Coordinates\n");
-  for (i = 0; i < event->pointer_count; i++)
-    {
-      g_printerr ("  ID=%i location=(%f, %f) raw=(%f, %f) touch=(%f, %f) size=%f pressure=%f orientation=%f 
scroll=(%f, %f) tool=",
-                  event->pointer_coordinates[i].id,
-                  event->pointer_coordinates[i].x, event->pointer_coordinates[i].y,
-                  event->pointer_coordinates[i].raw_x, event->pointer_coordinates[i].raw_y,
-                  event->pointer_coordinates[i].touch_major, event->pointer_coordinates[i].touch_minor,
-                  event->pointer_coordinates[i].size,
-                  event->pointer_coordinates[i].pressure,
-                  event->pointer_coordinates[i].orientation,
-                  event->pointer_coordinates[i].hscroll, event->pointer_coordinates[i].vscroll);
-      switch (event->pointer_coordinates[i].tool_type)
-        {
-        case mir_motion_tool_type_unknown:
-          g_printerr ("unknown");
-          break;
-        case mir_motion_tool_type_finger:
-          g_printerr ("finger");
-          break;
-        case mir_motion_tool_type_stylus:
-          g_printerr ("stylus");
-          break;
-        case mir_motion_tool_type_mouse:
-          g_printerr ("mouse");
-          break;
-        case mir_motion_tool_type_eraser:
-          g_printerr ("eraser");
-          break;
-        default:
-          g_printerr ("%u", event->pointer_coordinates[i].tool_type);
-          break;
-        }
-      g_printerr ("\n");
-    }
-}
-
-static void
-print_surface_event (const MirSurfaceEvent *event)
+event_cb (MirSurface     *surface,
+          const MirEvent *event,
+          void           *context)
 {
-  g_printerr ("SURFACE\n");
-  g_printerr (" Surface %i\n", event->id);
-  g_printerr (" Attribute ");
-  switch (event->attrib)
-    {
-    case mir_surface_attrib_type:
-      g_printerr ("type");
-      break;
-    case mir_surface_attrib_state:
-      g_printerr ("state");
-      break;
-    case mir_surface_attrib_swapinterval:
-      g_printerr ("swapinterval");
-      break;
-    case mir_surface_attrib_focus:
-      g_printerr ("focus");
-      break;
-    default:
-      g_printerr ("%u", event->attrib);
-      break;
-    }
-  g_printerr ("\n");
-  g_printerr (" Value %i\n", event->value);
-}
-
-static void
-print_resize_event (const MirResizeEvent *event)
-{
-  g_printerr ("RESIZE\n");
-  g_printerr (" Surface %i\n", event->surface_id);
-  g_printerr (" Size (%i, %i)\n", event->width, event->height);
-}
-
-static void
-print_event (const MirEvent *event)
-{
-  switch (event->type)
-    {
-    case mir_event_type_key:
-      print_key_event (&event->key);
-      break;
-    case mir_event_type_motion:
-      print_motion_event (&event->motion);
-      break;
-    case mir_event_type_surface:
-      print_surface_event (&event->surface);
-      break;
-    case mir_event_type_resize:
-      print_resize_event (&event->resize);
-      break;
-    default:
-      g_printerr ("EVENT %u\n", event->type);
-      break;
-    }
-}
-
-static void
-send_event (GdkWindow *window, GdkDevice *device, GdkEvent *event)
-{
-  GdkDisplay *display;
-  GList *node;
-
-  gdk_event_set_device (event, device);
-  gdk_event_set_screen (event, gdk_display_get_screen (gdk_window_get_display (window), 0));
-  event->any.window = g_object_ref (window);
-
-  display = gdk_window_get_display (window);
-  node = _gdk_event_queue_append (display, event);
-  _gdk_windowing_got_event (display, node, event, _gdk_display_get_next_serial (display));
-  while (TRUE)
-    {
-      GdkEvent *e;
-
-      e = gdk_display_get_event (display);
-      if (!e)
-        break;
-      _gdk_event_emit (e);
-      gdk_event_free (e);
-    }
-}
-
-static void
-generate_key_event (GdkWindow *window, GdkEventType type, guint state, guint keyval, guint16 keycode, 
gboolean is_modifier)
-{
-  GdkEvent *event;
-
-  event = gdk_event_new (type);
-  event->key.state = state;
-  event->key.keyval = keyval;
-  event->key.length = 0;
-  event->key.string = NULL; // FIXME: Is this still needed?
-  event->key.hardware_keycode = keycode;
-  event->key.group = 0; // FIXME
-  event->key.is_modifier = is_modifier;
-
-  send_event (window, _gdk_mir_device_manager_get_keyboard (gdk_display_get_device_manager 
(gdk_window_get_display (window))), event);
-}
-
-static GdkDevice *
-get_pointer (GdkWindow *window)
-{
-  return gdk_device_manager_get_client_pointer (gdk_display_get_device_manager (gdk_window_get_display 
(window)));
-}
-
-static void
-generate_button_event (GdkWindow *window, GdkEventType type, gdouble x, gdouble y, guint button, guint state)
-{
-  GdkEvent *event;
-
-  event = gdk_event_new (type);
-  event->button.x = x;
-  event->button.y = y;
-  event->button.state = state;
-  event->button.button = button;
-
-  send_event (window, get_pointer (window), event);
-}
-
-static void
-generate_scroll_event (GdkWindow *window, gdouble x, gdouble y, gdouble delta_x, gdouble delta_y, guint 
state)
-{
-  GdkEvent *event;
-
-  event = gdk_event_new (GDK_SCROLL);
-  event->scroll.x = x;
-  event->scroll.y = y;
-  event->scroll.state = state;
-  event->scroll.direction = GDK_SCROLL_SMOOTH;
-  event->scroll.delta_x = delta_x;
-  event->scroll.delta_y = delta_y;
-
-  send_event (window, get_pointer (window), event);
-}
-
-static void
-generate_motion_event (GdkWindow *window, gdouble x, gdouble y, guint state)
-{
-  GdkEvent *event;
-
-  event = gdk_event_new (GDK_MOTION_NOTIFY);
-  event->motion.x = x;
-  event->motion.y = y;
-  event->motion.state = state;
-  event->motion.is_hint = FALSE;
-
-  send_event (window, get_pointer (window), event);
-}
-
-static void
-generate_crossing_event (GdkWindow *window, GdkEventType type, gdouble x, gdouble y)
-{
-  GdkEvent *event;
-
-  event = gdk_event_new (type);
-  event->crossing.x = x;
-  event->crossing.y = y;
-  event->crossing.mode = GDK_CROSSING_NORMAL;
-  event->crossing.detail = GDK_NOTIFY_ANCESTOR;
-  event->crossing.focus = TRUE;
-
-  send_event (window, get_pointer (window), event);
-}
-
-static guint
-get_modifier_state (unsigned int modifiers, unsigned int button_state)
-{
-  guint modifier_state = 0;
-
-  if ((modifiers & mir_key_modifier_alt) != 0)
-    modifier_state |= GDK_MOD1_MASK;
-  if ((modifiers & mir_key_modifier_shift) != 0)
-    modifier_state |= GDK_SHIFT_MASK;
-  if ((modifiers & mir_key_modifier_ctrl) != 0)
-    modifier_state |= GDK_CONTROL_MASK;
-  if ((modifiers & mir_key_modifier_meta) != 0)
-    modifier_state |= GDK_SUPER_MASK;
-  if ((modifiers & mir_key_modifier_caps_lock) != 0)
-    modifier_state |= GDK_LOCK_MASK;
-  if ((button_state & mir_motion_button_primary) != 0)
-    modifier_state |= GDK_BUTTON1_MASK;
-  if ((button_state & mir_motion_button_secondary) != 0)
-    modifier_state |= GDK_BUTTON3_MASK;
-  if ((button_state & mir_motion_button_tertiary) != 0)
-    modifier_state |= GDK_BUTTON2_MASK;
-
-  return modifier_state;
-}
-
-/*
-  GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (event_data->window->impl);
-  MirMotionButton changed_button_state;
-  GdkEventType event_type;
-  gdouble x, y;
-  guint modifier_state;
-  gboolean is_modifier = FALSE;
-*/
-
-static void
-handle_key_event (GdkWindow *window, MirKeyEvent *event)
-{
-  guint modifier_state;
-  gboolean is_modifier = FALSE;
-
-  modifier_state = get_modifier_state (event->modifiers, 0); // FIXME: Need to track button state
-
-  switch (event->action)
-    {
-    case mir_key_action_down:
-    case mir_key_action_up:
-      // FIXME: Convert keycode
-      // FIXME: is_modifier
-      generate_key_event (window,
-                          event->action == mir_key_action_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE,
-                          modifier_state,
-                          event->key_code,
-                          event->scan_code,
-                          is_modifier);
-      break;
-    default:
-    //case mir_key_action_multiple:
-      // FIXME
-      break;
-    }
-}
-
-static void
-handle_motion_event (GdkWindow *window, MirMotionEvent *event)
-{
-  GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
-  guint modifier_state;
-  GdkEventType event_type;
-  MirMotionButton changed_button_state;
-
-  if (event->pointer_count > 0)
-    {
-      impl->x = event->pointer_coordinates[0].x;
-      impl->y = event->pointer_coordinates[0].y;
-    }
-  modifier_state = get_modifier_state (event->modifiers, event->button_state);
-
-  /* The Mir events generate hover-exits even while inside the window so
-     counteract this by always generating an enter notify on all other events */
-  if (!impl->cursor_inside && event->action != mir_motion_action_hover_exit)
-    {
-      impl->cursor_inside = TRUE;
-      generate_crossing_event (window, GDK_ENTER_NOTIFY, impl->x, impl->y);
-    }
-
-  /* Update which window has focus */
-  _gdk_mir_pointer_set_location (get_pointer (window), impl->x, impl->y, window, modifier_state);
-  switch (event->action)
-    {
-    case mir_motion_action_down:
-    case mir_motion_action_up:
-      event_type = event->action == mir_motion_action_down ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
-      changed_button_state = impl->button_state ^ event->button_state;
-      if ((changed_button_state & mir_motion_button_primary) != 0)
-        generate_button_event (window, event_type, impl->x, impl->y, GDK_BUTTON_PRIMARY, modifier_state);
-      if ((changed_button_state & mir_motion_button_secondary) != 0)
-        generate_button_event (window, event_type, impl->x, impl->y, GDK_BUTTON_SECONDARY, modifier_state);
-      if ((changed_button_state & mir_motion_button_tertiary) != 0)
-        generate_button_event (window, event_type, impl->x, impl->y, GDK_BUTTON_MIDDLE, modifier_state);
-      impl->button_state = event->button_state;
-      break;
-    case mir_motion_action_scroll:
-      generate_scroll_event (window, impl->x, impl->y, event->pointer_coordinates[0].hscroll, 
event->pointer_coordinates[0].vscroll, modifier_state);
-      break;
-    case mir_motion_action_move: // move with button
-    case mir_motion_action_hover_move: // move without button
-      generate_motion_event (window, impl->x, impl->y, modifier_state);
-      break;
-    case mir_motion_action_hover_exit:
-      impl->cursor_inside = FALSE;
-      generate_crossing_event (window, GDK_LEAVE_NOTIFY, impl->x, impl->y);
-      break;
-    }
-}
-
-static void
-handle_surface_event (GdkWindow *window, MirSurfaceEvent *event)
-{
-  GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
-
-  switch (event->attrib)
-    {
-    case mir_surface_attrib_type:
-      break;
-    case mir_surface_attrib_state:
-      impl->surface_state = event->value;
-      // FIXME: notify
-      break;
-    case mir_surface_attrib_swapinterval:
-      break;
-    case mir_surface_attrib_focus:
-      if (event->value)
-        gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_FOCUSED);
-      else
-        gdk_synthesize_window_state (window, GDK_WINDOW_STATE_FOCUSED, 0);
-      break;
-    default:
-      break;
-    }
-}
-
-typedef struct
-{
-  GdkWindow *window;
-  MirEvent event;
-} EventData;
-
-static gboolean
-handle_event (gpointer data)
-{
-  EventData *event_data = data;
-  MirEvent *event = &event_data->event;
-
-  if (g_getenv ("GDK_MIR_LOG_EVENTS"))
-    print_event (&event_data->event);
-
-  // FIXME: Only generate events if the window wanted them?
-  switch (event->type)
-    {
-    case mir_event_type_key:
-      handle_key_event (event_data->window, &event->key);
-      break;
-    case mir_event_type_motion:
-      handle_motion_event (event_data->window, &event->motion);
-      break;
-    case mir_event_type_surface:
-      handle_surface_event (event_data->window, &event->surface);
-      break;
-    case mir_event_type_resize:
-      // FIXME: Generate configure event
-      break;
-    default:
-      // FIXME?
-      break;
-    }
-
-  return FALSE;
-}
-
-static void
-event_cb (MirSurface *surface, const MirEvent *event, void *context)
-{
-  EventData *data = g_new (EventData, 1);
-  data->window = context; // FIXME: ref?
-  data->event = *event;
-  gdk_threads_add_idle (handle_event, data);
-  return;
+  _gdk_mir_event_source_queue (context, event);
 }
 
 static void
@@ -677,11 +81,14 @@ ensure_surface (GdkWindow *window)
   MirPixelFormat formats[100], pixel_format = mir_pixel_format_invalid;
   unsigned int n_formats, i;
   MirSurfaceParameters parameters;
-  MirEventDelegate event_delegate = { event_cb, window };
+  MirEventDelegate event_delegate = { event_cb, NULL };
 
   if (impl->surface)
     return;
 
+  /* no destroy notify: see below... */
+  event_delegate.context = _gdk_mir_event_source_get_window_reference (window);
+
   // Should probably calculate this once?
   // Should prefer certain formats over others
   mir_connection_get_available_surface_formats (get_connection (window), formats, 100, &n_formats);
@@ -707,6 +114,14 @@ static void
 ensure_no_surface (GdkWindow *window)
 {
   GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
+  GdkMirWindowReference *window_ref;
+
+  /* hack: no destroy notify on the mir surface, so we have to grab it
+   * from ourselves again...
+   */
+  window_ref = _gdk_mir_event_source_get_window_reference (window);
+  _gdk_mir_window_reference_unref (window_ref);
+  _gdk_mir_window_reference_unref (window_ref);
 
   if (impl->cairo_surface)
     {


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