[mutter/wayland] Move surface state tracking and surface interface to a separate file



commit cad9e14463ed2599a1d3034021c6417527e3ea65
Author: Giovanni Campagna <gcampagn redhat com>
Date:   Fri Aug 30 18:26:18 2013 +0200

    Move surface state tracking and surface interface to a separate file
    
    Move everything surface related from meta-wayland.c to meta-wayland-surface.c
    
    https://bugzilla.gnome.org/show_bug.cgi?id=707128

 src/Makefile.am                    |    1 +
 src/wayland/meta-wayland-private.h |    6 +-
 src/wayland/meta-wayland-surface.c |  863 ++++++++++++++++++++++++++++++++++++
 src/wayland/meta-wayland-surface.h |    8 +
 src/wayland/meta-wayland.c         |  798 +--------------------------------
 5 files changed, 887 insertions(+), 789 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 0a7bc37..c07e443 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -196,6 +196,7 @@ libmutter_wayland_la_SOURCES +=                     \
        wayland/meta-wayland-seat.h             \
        wayland/meta-wayland-stage.h            \
        wayland/meta-wayland-stage.c            \
+       wayland/meta-wayland-surface.c          \
        wayland/meta-wayland-surface.h          \
        wayland/meta-wayland-types.h            \
        wayland/meta-weston-launch.c            \
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
index ebc066b..79ff6fd 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -105,6 +105,10 @@ void                    meta_wayland_compositor_set_input_focus (MetaWaylandComp
 
 MetaLauncher           *meta_wayland_compositor_get_launcher    (MetaWaylandCompositor *compositor);
 
-void                    meta_wayland_surface_free               (MetaWaylandSurface    *surface);
+MetaWaylandBuffer *     meta_wayland_buffer_from_resource       (struct wl_resource *resource);
+
+void                    meta_wayland_buffer_reference           (MetaWaylandBufferReference *ref,
+                                                                MetaWaylandBuffer          *buffer);
+
 
 #endif /* META_WAYLAND_PRIVATE_H */
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
new file mode 100644
index 0000000..deccf34
--- /dev/null
+++ b/src/wayland/meta-wayland-surface.c
@@ -0,0 +1,863 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2012,2013 Intel Corporation
+ *               2013 Red Hat, Inc.
+ *
+ * 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 <glib.h>
+#include <sys/time.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <wayland-server.h>
+
+#include "meta-wayland-private.h"
+#include "meta-xwayland-private.h"
+#include "meta-wayland-stage.h"
+#include "meta-window-actor-private.h"
+#include "meta-wayland-seat.h"
+#include "meta-wayland-keyboard.h"
+#include "meta-wayland-pointer.h"
+#include "meta-wayland-data-device.h"
+#include "meta-cursor-tracker-private.h"
+#include "display-private.h"
+#include "window-private.h"
+#include <meta/types.h>
+#include <meta/main.h>
+#include "frame.h"
+#include "meta-idle-monitor-private.h"
+#include "meta-weston-launch.h"
+#include "monitor-private.h"
+
+static void
+surface_process_damage (MetaWaylandSurface *surface,
+                        cairo_region_t *region)
+{
+  if (surface->window &&
+      surface->buffer_ref.buffer)
+    {
+      MetaWindowActor *window_actor =
+        META_WINDOW_ACTOR (meta_window_get_compositor_private (surface->window));
+      MetaRectangle rect;
+      cairo_rectangle_int_t cairo_rect;
+
+      meta_window_get_input_rect (surface->window, &rect);
+      cairo_rect.x = 0;
+      cairo_rect.y = 0;
+      cairo_rect.width = rect.width;
+      cairo_rect.height = rect.height;
+
+      cairo_region_intersect_rectangle (region, &cairo_rect);
+
+      if (window_actor)
+        {
+          int i, n_rectangles = cairo_region_num_rectangles (region);
+
+          for (i = 0; i < n_rectangles; i++)
+            {
+              cairo_rectangle_int_t rectangle;
+
+              cairo_region_get_rectangle (region, i, &rectangle);
+
+              meta_window_actor_process_wayland_damage (window_actor,
+                                                        rectangle.x,
+                                                        rectangle.y,
+                                                        rectangle.width,
+                                                        rectangle.height);
+            }
+        }
+    }
+}
+
+static void
+meta_wayland_surface_destroy (struct wl_client *wayland_client,
+                              struct wl_resource *wayland_resource)
+{
+  wl_resource_destroy (wayland_resource);
+}
+
+static void
+meta_wayland_surface_attach (struct wl_client *wayland_client,
+                             struct wl_resource *wayland_surface_resource,
+                             struct wl_resource *wayland_buffer_resource,
+                             gint32 sx, gint32 sy)
+{
+  MetaWaylandSurface *surface =
+    wl_resource_get_user_data (wayland_surface_resource);
+  MetaWaylandBuffer *buffer;
+
+  /* X11 unmanaged window */
+  if (!surface)
+    return;
+
+  if (wayland_buffer_resource)
+    buffer = meta_wayland_buffer_from_resource (wayland_buffer_resource);
+  else
+    buffer = NULL;
+
+  /* Attach without commit in between does not send wl_buffer.release */
+  if (surface->pending.buffer)
+    wl_list_remove (&surface->pending.buffer_destroy_listener.link);
+
+  surface->pending.sx = sx;
+  surface->pending.sy = sy;
+  surface->pending.buffer = buffer;
+  surface->pending.newly_attached = TRUE;
+
+  if (buffer)
+    wl_signal_add (&buffer->destroy_signal,
+                   &surface->pending.buffer_destroy_listener);
+}
+
+static void
+meta_wayland_surface_damage (struct wl_client *client,
+                             struct wl_resource *surface_resource,
+                             gint32 x,
+                             gint32 y,
+                             gint32 width,
+                             gint32 height)
+{
+  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
+  cairo_rectangle_int_t rectangle = { x, y, width, height };
+
+  /* X11 unmanaged window */
+  if (!surface)
+    return;
+
+  cairo_region_union_rectangle (surface->pending.damage, &rectangle);
+}
+
+static void
+destroy_frame_callback (struct wl_resource *callback_resource)
+{
+  MetaWaylandFrameCallback *callback =
+    wl_resource_get_user_data (callback_resource);
+
+  wl_list_remove (&callback->link);
+  g_slice_free (MetaWaylandFrameCallback, callback);
+}
+
+static void
+meta_wayland_surface_frame (struct wl_client *client,
+                            struct wl_resource *surface_resource,
+                            guint32 callback_id)
+{
+  MetaWaylandFrameCallback *callback;
+  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
+
+  /* X11 unmanaged window */
+  if (!surface)
+    return;
+
+  callback = g_slice_new0 (MetaWaylandFrameCallback);
+  callback->compositor = surface->compositor;
+  callback->resource = wl_resource_create (client,
+                                          &wl_callback_interface, 1,
+                                          callback_id);
+  wl_resource_set_user_data (callback->resource, callback);
+  wl_resource_set_destructor (callback->resource, destroy_frame_callback);
+
+  wl_list_insert (surface->pending.frame_callback_list.prev, &callback->link);
+}
+
+static void
+meta_wayland_surface_set_opaque_region (struct wl_client *client,
+                                        struct wl_resource *surface_resource,
+                                        struct wl_resource *region_resource)
+{
+  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
+  MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
+
+  /* X11 unmanaged window */
+  if (!surface)
+    return;
+
+  g_clear_pointer (&surface->pending.opaque_region, cairo_region_destroy);
+  surface->pending.opaque_region = cairo_region_copy (region->region);
+}
+
+static void
+meta_wayland_surface_set_input_region (struct wl_client *client,
+                                       struct wl_resource *surface_resource,
+                                       struct wl_resource *region_resource)
+{
+  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
+  MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
+
+  /* X11 unmanaged window */
+  if (!surface)
+    return;
+
+  g_clear_pointer (&surface->pending.input_region, cairo_region_destroy);
+  surface->pending.input_region = cairo_region_copy (region->region);
+}
+
+static void
+empty_region (cairo_region_t *region)
+{
+  cairo_rectangle_int_t rectangle = { 0, 0, 0, 0 };
+  cairo_region_intersect_rectangle (region, &rectangle);
+}
+
+static void
+meta_wayland_surface_commit (struct wl_client *client,
+                             struct wl_resource *resource)
+{
+  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
+  MetaWaylandCompositor *compositor;
+
+  /* X11 unmanaged window */
+  if (!surface)
+    return;
+
+  compositor = surface->compositor;
+
+  /* wl_surface.attach */
+  if (surface->pending.newly_attached &&
+      surface->buffer_ref.buffer != surface->pending.buffer)
+    {
+      /* Note: we set this before informing any window-actor since the
+       * window actor will expect to find the new buffer within the
+       * surface. */
+      meta_wayland_buffer_reference (&surface->buffer_ref,
+                                     surface->pending.buffer);
+
+      if (surface->pending.buffer)
+        {
+          MetaWaylandBuffer *buffer = surface->pending.buffer;
+
+          if (surface->window)
+            {
+              MetaWindow *window = surface->window;
+              MetaWindowActor *window_actor =
+                META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
+              MetaRectangle rect;
+
+              meta_window_get_input_rect (surface->window, &rect);
+
+              if (window_actor)
+                meta_window_actor_attach_wayland_buffer (window_actor, buffer);
+
+              /* XXX: we resize X based surfaces according to X events */
+              if (surface->xid == 0 &&
+                  (buffer->width != rect.width || buffer->height != rect.height))
+                meta_window_resize (surface->window, FALSE, buffer->width, buffer->height);
+            }
+          else if (surface == compositor->seat->sprite)
+            meta_wayland_seat_update_sprite (compositor->seat);
+        }
+    }
+
+  if (surface->pending.buffer)
+    {
+      wl_list_remove (&surface->pending.buffer_destroy_listener.link);
+      surface->pending.buffer = NULL;
+    }
+  surface->pending.sx = 0;
+  surface->pending.sy = 0;
+  surface->pending.newly_attached = FALSE;
+
+  if (surface->window)
+    {
+      meta_window_set_opaque_region (surface->window, surface->pending.opaque_region);
+      g_clear_pointer (&surface->pending.opaque_region, cairo_region_destroy);
+
+      meta_window_set_input_region (surface->window, surface->pending.input_region);
+      g_clear_pointer (&surface->pending.input_region, cairo_region_destroy);
+    }
+
+  surface_process_damage (surface, surface->pending.damage);
+  empty_region (surface->pending.damage);
+
+  /* wl_surface.frame */
+  wl_list_insert_list (&compositor->frame_callbacks,
+                       &surface->pending.frame_callback_list);
+  wl_list_init (&surface->pending.frame_callback_list);
+}
+
+static void
+meta_wayland_surface_set_buffer_transform (struct wl_client *client,
+                                           struct wl_resource *resource,
+                                           int32_t transform)
+{
+  g_warning ("TODO: support set_buffer_transform request");
+}
+
+static void
+meta_wayland_surface_set_buffer_scale (struct wl_client *client,
+                                       struct wl_resource *resource,
+                                       int scale)
+{
+  g_warning ("TODO: support set_buffer_scale request");
+}
+
+const struct wl_surface_interface meta_wayland_surface_interface = {
+  meta_wayland_surface_destroy,
+  meta_wayland_surface_attach,
+  meta_wayland_surface_damage,
+  meta_wayland_surface_frame,
+  meta_wayland_surface_set_opaque_region,
+  meta_wayland_surface_set_input_region,
+  meta_wayland_surface_commit,
+  meta_wayland_surface_set_buffer_transform,
+  meta_wayland_surface_set_buffer_scale
+};
+
+void
+meta_wayland_surface_free (MetaWaylandSurface *surface)
+{
+  MetaWaylandCompositor *compositor = surface->compositor;
+  MetaWaylandFrameCallback *cb, *next;
+
+  compositor->surfaces = g_list_remove (compositor->surfaces, surface);
+
+  meta_wayland_buffer_reference (&surface->buffer_ref, NULL);
+
+  if (surface->pending.buffer)
+    wl_list_remove (&surface->pending.buffer_destroy_listener.link);
+
+  cairo_region_destroy (surface->pending.damage);
+
+  wl_list_for_each_safe (cb, next,
+                         &surface->pending.frame_callback_list, link)
+    wl_resource_destroy (cb->resource);
+
+  meta_wayland_compositor_repick (compositor);
+
+  g_assert (surface != compositor->seat->keyboard.focus);
+  if (surface == compositor->seat->pointer.focus)
+    {
+      meta_wayland_pointer_destroy_focus (&compositor->seat->pointer);
+
+      g_assert (surface != compositor->seat->pointer.focus);
+      g_assert (surface != compositor->seat->pointer.grab->focus);
+    }
+
+ if (compositor->implicit_grab_surface == surface)
+   compositor->implicit_grab_surface = compositor->seat->pointer.current;
+
+  if (surface->resource)
+    wl_resource_set_user_data (surface->resource, NULL);
+  g_slice_free (MetaWaylandSurface, surface);
+}
+
+static void
+meta_wayland_surface_resource_destroy_cb (struct wl_resource *resource)
+{
+  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
+
+  /* There are four cases here:
+     - An X11 unmanaged window -> surface is NULL, nothing to do
+     - An X11 unmanaged window, but we got the wayland event first ->
+       just clear the resource pointer
+     - A wayland surface without window (destroyed before set_toplevel) ->
+       need to free the surface itself
+     - A wayland window -> need to unmanage
+  */
+
+  if (surface)
+    {
+      surface->resource = NULL;
+
+      /* NB: If the surface corresponds to an X window then we will be
+       * sure to free the MetaWindow according to some X event. */
+      if (surface->window &&
+         surface->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
+       {
+         MetaDisplay *display = meta_get_display ();
+         guint32 timestamp = meta_display_get_current_time_roundtrip (display);
+
+         meta_window_unmanage (surface->window, timestamp);
+       }
+      else if (!surface->window)
+       meta_wayland_surface_free (surface);
+    }
+}
+
+static void
+surface_handle_pending_buffer_destroy (struct wl_listener *listener,
+                                       void *data)
+{
+  MetaWaylandSurface *surface =
+    wl_container_of (listener, surface, pending.buffer_destroy_listener);
+
+  surface->pending.buffer = NULL;
+}
+
+MetaWaylandSurface *
+meta_wayland_surface_create (MetaWaylandCompositor *compositor,
+                            struct wl_client      *wayland_client,
+                            guint32                id,
+                            guint32                version)
+{
+  MetaWaylandSurface *surface = g_slice_new0 (MetaWaylandSurface);
+
+  surface->compositor = compositor;
+
+  surface->resource = wl_resource_create (wayland_client,
+                                         &wl_surface_interface,
+                                         version, id);
+  wl_resource_set_implementation (surface->resource, &meta_wayland_surface_interface, surface,
+                                 meta_wayland_surface_resource_destroy_cb);
+
+  surface->pending.damage = cairo_region_create ();
+
+  surface->pending.buffer_destroy_listener.notify =
+    surface_handle_pending_buffer_destroy;
+  wl_list_init (&surface->pending.frame_callback_list);
+
+  return surface;
+}
+
+static void
+shell_surface_pong (struct wl_client *client,
+                    struct wl_resource *resource,
+                    guint32 serial)
+{
+}
+
+typedef struct _MetaWaylandGrab
+{
+  MetaWaylandPointerGrab grab;
+  MetaWaylandSurfaceExtension *shell_surface;
+  struct wl_listener shell_surface_destroy_listener;
+  MetaWaylandPointer *pointer;
+} MetaWaylandGrab;
+
+typedef struct _MetaWaylandMoveGrab
+{
+  MetaWaylandGrab base;
+  wl_fixed_t dx, dy;
+} MetaWaylandMoveGrab;
+
+static void
+destroy_shell_surface_grab_listener (struct wl_listener *listener,
+                                     void *data)
+{
+  MetaWaylandGrab *grab = wl_container_of (listener, grab,
+                                           shell_surface_destroy_listener);
+  grab->shell_surface = NULL;
+
+  /* XXX: Could we perhaps just stop the grab here so we don't have
+   * to consider grab->shell_surface becoming NULL in grab interface
+   * callbacks? */
+}
+
+typedef enum _GrabCursor
+{
+  GRAB_CURSOR_MOVE,
+} GrabCursor;
+
+static void
+grab_pointer (MetaWaylandGrab *grab,
+              const MetaWaylandPointerGrabInterface *interface,
+              MetaWaylandSurfaceExtension *shell_surface,
+              MetaWaylandPointer *pointer,
+              GrabCursor cursor)
+{
+  /* TODO: popup_grab_end (pointer); */
+
+  grab->grab.interface = interface;
+  grab->shell_surface = shell_surface;
+  grab->shell_surface_destroy_listener.notify =
+    destroy_shell_surface_grab_listener;
+  wl_resource_add_destroy_listener (shell_surface->resource,
+                                    &grab->shell_surface_destroy_listener);
+
+  grab->pointer = pointer;
+  grab->grab.focus = shell_surface->surface;
+
+  meta_wayland_pointer_start_grab (pointer, &grab->grab);
+
+  /* TODO: send_grab_cursor (cursor); */
+
+  /* XXX: In Weston there is a desktop shell protocol which has
+   * a set_grab_surface request that's used to specify the surface
+   * that's focused here.
+   *
+   * TODO: understand why.
+   *
+   * XXX: For now we just focus the surface directly associated with
+   * the grab.
+   */
+  meta_wayland_pointer_set_focus (pointer,
+                                  grab->shell_surface->surface,
+                                  wl_fixed_from_int (0),
+                                  wl_fixed_from_int (0));
+}
+
+static void
+release_pointer (MetaWaylandGrab *grab)
+{
+  if (grab->shell_surface)
+    wl_list_remove (&grab->shell_surface_destroy_listener.link);
+
+  meta_wayland_pointer_end_grab (grab->pointer);
+}
+
+static void
+noop_grab_focus (MetaWaylandPointerGrab *grab,
+                 MetaWaylandSurface *surface,
+                 wl_fixed_t x,
+                 wl_fixed_t y)
+{
+  grab->focus = NULL;
+}
+
+static void
+move_grab_motion (MetaWaylandPointerGrab *grab,
+                  uint32_t time,
+                  wl_fixed_t x,
+                  wl_fixed_t y)
+{
+  MetaWaylandMoveGrab *move = (MetaWaylandMoveGrab *)grab;
+  MetaWaylandPointer *pointer = move->base.pointer;
+  MetaWaylandSurfaceExtension *shell_surface = move->base.shell_surface;
+
+  if (!shell_surface)
+    return;
+
+  meta_window_move (shell_surface->surface->window,
+                    TRUE,
+                    wl_fixed_to_int (pointer->x + move->dx),
+                    wl_fixed_to_int (pointer->y + move->dy));
+}
+
+static void
+move_grab_button (MetaWaylandPointerGrab *pointer_grab,
+                  uint32_t time,
+                  uint32_t button,
+                  uint32_t state_w)
+{
+  MetaWaylandGrab *grab =
+    wl_container_of (pointer_grab, grab, grab);
+  MetaWaylandMoveGrab *move = (MetaWaylandMoveGrab *)grab;
+  MetaWaylandPointer *pointer = grab->pointer;
+  enum wl_pointer_button_state state = state_w;
+
+  if (pointer->button_count == 0 && state == WL_POINTER_BUTTON_STATE_RELEASED)
+    {
+      release_pointer (grab);
+      g_slice_free (MetaWaylandMoveGrab, move);
+    }
+}
+
+static const MetaWaylandPointerGrabInterface move_grab_interface = {
+    noop_grab_focus,
+    move_grab_motion,
+    move_grab_button,
+};
+
+static void
+start_surface_move (MetaWaylandSurfaceExtension *shell_surface,
+                    MetaWaylandSeat *seat)
+{
+  MetaWaylandMoveGrab *move;
+  MetaRectangle rect;
+
+  g_return_if_fail (shell_surface != NULL);
+
+  /* TODO: check if the surface is fullscreen when we support fullscreen */
+
+  move = g_slice_new (MetaWaylandMoveGrab);
+
+  meta_window_get_input_rect (shell_surface->surface->window,
+                              &rect);
+
+  move->dx = wl_fixed_from_int (rect.x) - seat->pointer.grab_x;
+  move->dy = wl_fixed_from_int (rect.y) - seat->pointer.grab_y;
+
+  grab_pointer (&move->base, &move_grab_interface, shell_surface,
+                &seat->pointer, GRAB_CURSOR_MOVE);
+}
+
+static void
+shell_surface_move (struct wl_client *client,
+                    struct wl_resource *resource,
+                    struct wl_resource *seat_resource,
+                    guint32 serial)
+{
+  MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
+  MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource);
+
+  if (seat->pointer.button_count == 0 ||
+      seat->pointer.grab_serial != serial ||
+      seat->pointer.focus != shell_surface->surface)
+    return;
+
+  start_surface_move (shell_surface, seat);
+}
+
+static void
+shell_surface_resize (struct wl_client *client,
+                      struct wl_resource *resource,
+                      struct wl_resource *seat,
+                      guint32 serial,
+                      guint32 edges)
+{
+  g_warning ("TODO: support shell_surface_resize request");
+}
+
+static void
+ensure_surface_window (MetaWaylandSurface *surface)
+{
+  MetaDisplay *display = meta_get_display ();
+
+  if (!surface->window)
+    {
+      int width, height;
+
+      if (surface->buffer_ref.buffer)
+        {
+          MetaWaylandBuffer *buffer = surface->buffer_ref.buffer;
+          width = buffer->width;
+          height = buffer->width;
+        }
+      else
+        {
+          width = 0;
+          height = 0;
+        }
+
+      surface->window =
+        meta_window_new_for_wayland (display, width, height, surface);
+
+      meta_window_calc_showing (surface->window);
+    }
+}
+
+static void
+shell_surface_set_toplevel (struct wl_client *client,
+                            struct wl_resource *resource)
+{
+  MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource);
+  MetaWaylandSurface *surface = shell_surface->surface;
+  MetaWaylandCompositor *compositor = surface->compositor;
+
+  /* NB: Surfaces from xwayland become managed based on X events. */
+  if (client == compositor->xwayland_client)
+    return;
+
+  ensure_surface_window (surface);
+
+  meta_window_unmake_fullscreen (surface->window);
+}
+
+static void
+shell_surface_set_transient (struct wl_client *client,
+                             struct wl_resource *resource,
+                             struct wl_resource *parent,
+                             int x,
+                             int y,
+                             guint32 flags)
+{
+  MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource);
+  MetaWaylandSurface *surface = shell_surface->surface;
+  MetaWaylandCompositor *compositor = surface->compositor;
+
+  /* NB: Surfaces from xwayland become managed based on X events. */
+  if (client == compositor->xwayland_client)
+    return;
+
+  ensure_surface_window (surface);
+}
+
+static void
+shell_surface_set_fullscreen (struct wl_client *client,
+                              struct wl_resource *resource,
+                              guint32 method,
+                              guint32 framerate,
+                              struct wl_resource *output)
+{
+  MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource);
+  MetaWaylandSurface *surface = shell_surface->surface;
+  MetaWaylandCompositor *compositor = surface->compositor;
+
+  /* NB: Surfaces from xwayland become managed based on X events. */
+  if (client == compositor->xwayland_client)
+    return;
+
+  ensure_surface_window (surface);
+
+  meta_window_make_fullscreen (surface->window);
+}
+
+static void
+shell_surface_set_popup (struct wl_client *client,
+                         struct wl_resource *resource,
+                         struct wl_resource *seat,
+                         guint32 serial,
+                         struct wl_resource *parent,
+                         gint32 x,
+                         gint32 y,
+                         guint32 flags)
+{
+}
+
+static void
+shell_surface_set_maximized (struct wl_client *client,
+                             struct wl_resource *resource,
+                             struct wl_resource *output)
+{
+  g_warning ("TODO: support shell_surface_set_maximized request");
+}
+
+static void
+shell_surface_set_title (struct wl_client *client,
+                         struct wl_resource *resource,
+                         const char *title)
+{
+  MetaWaylandSurfaceExtension *extension = wl_resource_get_user_data (resource);
+  MetaWaylandSurface *surface = extension->surface;
+
+  g_warning ("TODO: support shell_surface_set_title request");
+}
+
+static void
+shell_surface_set_class (struct wl_client *client,
+                         struct wl_resource *resource,
+                         const char *class_)
+{
+  MetaWaylandSurfaceExtension *extension = wl_resource_get_user_data (resource);
+  MetaWaylandSurface *surface = extension->surface;
+
+  g_warning ("TODO: support shell_surface_set_class request");
+}
+
+static const struct wl_shell_surface_interface meta_wayland_shell_surface_interface =
+{
+  shell_surface_pong,
+  shell_surface_move,
+  shell_surface_resize,
+  shell_surface_set_toplevel,
+  shell_surface_set_transient,
+  shell_surface_set_fullscreen,
+  shell_surface_set_popup,
+  shell_surface_set_maximized,
+  shell_surface_set_title,
+  shell_surface_set_class
+};
+
+static void
+extension_handle_surface_destroy (struct wl_listener *listener,
+                                 void *data)
+{
+  MetaWaylandSurfaceExtension *extension =
+    wl_container_of (listener, extension, surface_destroy_listener);
+
+  extension->surface = NULL;
+  wl_resource_destroy (extension->resource);
+}
+
+static void
+destroy_surface_extension (struct wl_resource *resource)
+{
+  MetaWaylandSurfaceExtension *extension = wl_resource_get_user_data (resource);
+
+  /* In case cleaning up a dead client destroys extension first */
+  if (extension->surface)
+    {
+      wl_list_remove (&extension->surface_destroy_listener.link);
+    }
+
+  g_free (extension);
+}
+
+static void
+create_surface_extension (struct wl_client          *client,
+                         struct wl_resource        *master_resource,
+                         guint32                    id,
+                         MetaWaylandSurface        *surface,
+                         const struct wl_interface *interface,
+                         const void                *implementation)
+{
+  MetaWaylandSurfaceExtension *extension;
+
+  extension = g_new0 (MetaWaylandSurfaceExtension, 1);
+
+  extension->resource = wl_resource_create (client, interface,
+                                           wl_resource_get_version (master_resource), id);
+  wl_resource_set_implementation (extension->resource, implementation,
+                                 extension, destroy_surface_extension);
+
+  extension->surface = surface;
+  extension->surface_destroy_listener.notify = extension_handle_surface_destroy;
+  wl_resource_add_destroy_listener (surface->resource,
+                                    &extension->surface_destroy_listener);
+}
+
+static void
+get_shell_surface (struct wl_client *client,
+                   struct wl_resource *resource,
+                   guint32 id,
+                   struct wl_resource *surface_resource)
+{
+  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
+
+  if (surface->has_shell_surface)
+    {
+      wl_resource_post_error (surface_resource,
+                              WL_DISPLAY_ERROR_INVALID_OBJECT,
+                              "wl_shell::get_shell_surface already requested");
+      return;
+    }
+
+  create_surface_extension (client, resource, id, surface,
+                           &wl_shell_surface_interface,
+                           &meta_wayland_shell_surface_interface);
+  surface->has_shell_surface = TRUE;
+}
+
+static const struct wl_shell_interface meta_wayland_shell_interface =
+{
+  get_shell_surface
+};
+
+static void
+bind_shell (struct wl_client *client,
+            void *data,
+            guint32 version,
+            guint32 id)
+{
+  struct wl_resource *resource;
+
+  resource = wl_resource_create (client, &wl_shell_interface, version, id);
+  wl_resource_set_implementation (resource, &meta_wayland_shell_interface, data, NULL);
+}
+
+void
+meta_wayland_init_shell (MetaWaylandCompositor *compositor)
+{
+  if (wl_global_create (compositor->wayland_display,
+                       &wl_shell_interface, 1,
+                       compositor, bind_shell) == NULL)
+    g_error ("Failed to register a global shell object");
+}
+
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index ec6f849..3926091 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -87,4 +87,12 @@ typedef struct
   struct wl_listener surface_destroy_listener;
 } MetaWaylandSurfaceExtension;
 
+void                meta_wayland_init_shell     (MetaWaylandCompositor *compositor);
+
+MetaWaylandSurface *meta_wayland_surface_create (MetaWaylandCompositor *compositor,
+                                                struct wl_client      *client,
+                                                guint32                id,
+                                                guint32                version);
+void                meta_wayland_surface_free   (MetaWaylandSurface    *surface);
+
 #endif
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 2398e04..43c7d95 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -136,7 +136,7 @@ meta_wayland_buffer_destroy_handler (struct wl_listener *listener,
   g_slice_free (MetaWaylandBuffer, buffer);
 }
 
-static MetaWaylandBuffer *
+MetaWaylandBuffer *
 meta_wayland_buffer_from_resource (struct wl_resource *resource)
 {
   MetaWaylandBuffer *buffer;
@@ -165,7 +165,7 @@ meta_wayland_buffer_from_resource (struct wl_resource *resource)
 
 static void
 meta_wayland_buffer_reference_handle_destroy (struct wl_listener *listener,
-                                          void *data)
+                                              void *data)
 {
   MetaWaylandBufferReference *ref =
     wl_container_of (listener, ref, destroy_listener);
@@ -175,7 +175,7 @@ meta_wayland_buffer_reference_handle_destroy (struct wl_listener *listener,
   ref->buffer = NULL;
 }
 
-static void
+void
 meta_wayland_buffer_reference (MetaWaylandBufferReference *ref,
                                MetaWaylandBuffer *buffer)
 {
@@ -202,280 +202,6 @@ meta_wayland_buffer_reference (MetaWaylandBufferReference *ref,
   ref->destroy_listener.notify = meta_wayland_buffer_reference_handle_destroy;
 }
 
-static void
-surface_process_damage (MetaWaylandSurface *surface,
-                        cairo_region_t *region)
-{
-  if (surface->window &&
-      surface->buffer_ref.buffer)
-    {
-      MetaWindowActor *window_actor =
-        META_WINDOW_ACTOR (meta_window_get_compositor_private (surface->window));
-      MetaRectangle rect;
-      cairo_rectangle_int_t cairo_rect;
-
-      meta_window_get_input_rect (surface->window, &rect);
-      cairo_rect.x = 0;
-      cairo_rect.y = 0;
-      cairo_rect.width = rect.width;
-      cairo_rect.height = rect.height;
-
-      cairo_region_intersect_rectangle (region, &cairo_rect);
-
-      if (window_actor)
-        {
-          int i, n_rectangles = cairo_region_num_rectangles (region);
-
-          for (i = 0; i < n_rectangles; i++)
-            {
-              cairo_rectangle_int_t rectangle;
-
-              cairo_region_get_rectangle (region, i, &rectangle);
-
-              meta_window_actor_process_wayland_damage (window_actor,
-                                                        rectangle.x,
-                                                        rectangle.y,
-                                                        rectangle.width,
-                                                        rectangle.height);
-            }
-        }
-    }
-}
-
-static void
-meta_wayland_surface_destroy (struct wl_client *wayland_client,
-                              struct wl_resource *wayland_resource)
-{
-  wl_resource_destroy (wayland_resource);
-}
-
-static void
-meta_wayland_surface_attach (struct wl_client *wayland_client,
-                             struct wl_resource *wayland_surface_resource,
-                             struct wl_resource *wayland_buffer_resource,
-                             gint32 sx, gint32 sy)
-{
-  MetaWaylandSurface *surface =
-    wl_resource_get_user_data (wayland_surface_resource);
-  MetaWaylandBuffer *buffer;
-
-  /* X11 unmanaged window */
-  if (!surface)
-    return;
-
-  if (wayland_buffer_resource)
-    buffer = meta_wayland_buffer_from_resource (wayland_buffer_resource);
-  else
-    buffer = NULL;
-
-  /* Attach without commit in between does not send wl_buffer.release */
-  if (surface->pending.buffer)
-    wl_list_remove (&surface->pending.buffer_destroy_listener.link);
-
-  surface->pending.sx = sx;
-  surface->pending.sy = sy;
-  surface->pending.buffer = buffer;
-  surface->pending.newly_attached = TRUE;
-
-  if (buffer)
-    wl_signal_add (&buffer->destroy_signal,
-                   &surface->pending.buffer_destroy_listener);
-}
-
-static void
-meta_wayland_surface_damage (struct wl_client *client,
-                             struct wl_resource *surface_resource,
-                             gint32 x,
-                             gint32 y,
-                             gint32 width,
-                             gint32 height)
-{
-  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
-  cairo_rectangle_int_t rectangle = { x, y, width, height };
-
-  /* X11 unmanaged window */
-  if (!surface)
-    return;
-
-  cairo_region_union_rectangle (surface->pending.damage, &rectangle);
-}
-
-static void
-destroy_frame_callback (struct wl_resource *callback_resource)
-{
-  MetaWaylandFrameCallback *callback =
-    wl_resource_get_user_data (callback_resource);
-
-  wl_list_remove (&callback->link);
-  g_slice_free (MetaWaylandFrameCallback, callback);
-}
-
-static void
-meta_wayland_surface_frame (struct wl_client *client,
-                            struct wl_resource *surface_resource,
-                            guint32 callback_id)
-{
-  MetaWaylandFrameCallback *callback;
-  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
-
-  /* X11 unmanaged window */
-  if (!surface)
-    return;
-
-  callback = g_slice_new0 (MetaWaylandFrameCallback);
-  callback->compositor = surface->compositor;
-  callback->resource = wl_resource_create (client,
-                                          &wl_callback_interface, 1,
-                                          callback_id);
-  wl_resource_set_user_data (callback->resource, callback);
-  wl_resource_set_destructor (callback->resource, destroy_frame_callback);
-
-  wl_list_insert (surface->pending.frame_callback_list.prev, &callback->link);
-}
-
-static void
-meta_wayland_surface_set_opaque_region (struct wl_client *client,
-                                        struct wl_resource *surface_resource,
-                                        struct wl_resource *region_resource)
-{
-  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
-  MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
-
-  /* X11 unmanaged window */
-  if (!surface)
-    return;
-
-  g_clear_pointer (&surface->pending.opaque_region, cairo_region_destroy);
-  surface->pending.opaque_region = cairo_region_copy (region->region);
-}
-
-static void
-meta_wayland_surface_set_input_region (struct wl_client *client,
-                                       struct wl_resource *surface_resource,
-                                       struct wl_resource *region_resource)
-{
-  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
-  MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
-
-  /* X11 unmanaged window */
-  if (!surface)
-    return;
-
-  g_clear_pointer (&surface->pending.input_region, cairo_region_destroy);
-  surface->pending.input_region = cairo_region_copy (region->region);
-}
-
-static void
-empty_region (cairo_region_t *region)
-{
-  cairo_rectangle_int_t rectangle = { 0, 0, 0, 0 };
-  cairo_region_intersect_rectangle (region, &rectangle);
-}
-
-static void
-meta_wayland_surface_commit (struct wl_client *client,
-                             struct wl_resource *resource)
-{
-  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
-  MetaWaylandCompositor *compositor;
-
-  /* X11 unmanaged window */
-  if (!surface)
-    return;
-
-  compositor = surface->compositor;
-
-  /* wl_surface.attach */
-  if (surface->pending.newly_attached &&
-      surface->buffer_ref.buffer != surface->pending.buffer)
-    {
-      /* Note: we set this before informing any window-actor since the
-       * window actor will expect to find the new buffer within the
-       * surface. */
-      meta_wayland_buffer_reference (&surface->buffer_ref,
-                                     surface->pending.buffer);
-
-      if (surface->pending.buffer)
-        {
-          MetaWaylandBuffer *buffer = surface->pending.buffer;
-
-          if (surface->window)
-            {
-              MetaWindow *window = surface->window;
-              MetaWindowActor *window_actor =
-                META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
-              MetaRectangle rect;
-
-              meta_window_get_input_rect (surface->window, &rect);
-
-              if (window_actor)
-                meta_window_actor_attach_wayland_buffer (window_actor, buffer);
-
-              /* XXX: we resize X based surfaces according to X events */
-              if (surface->xid == 0 &&
-                  (buffer->width != rect.width || buffer->height != rect.height))
-                meta_window_resize (surface->window, FALSE, buffer->width, buffer->height);
-            }
-          else if (surface == compositor->seat->sprite)
-            meta_wayland_seat_update_sprite (compositor->seat);
-        }
-    }
-
-  if (surface->pending.buffer)
-    {
-      wl_list_remove (&surface->pending.buffer_destroy_listener.link);
-      surface->pending.buffer = NULL;
-    }
-  surface->pending.sx = 0;
-  surface->pending.sy = 0;
-  surface->pending.newly_attached = FALSE;
-
-  if (surface->window)
-    {
-      meta_window_set_opaque_region (surface->window, surface->pending.opaque_region);
-      g_clear_pointer (&surface->pending.opaque_region, cairo_region_destroy);
-
-      meta_window_set_input_region (surface->window, surface->pending.input_region);
-      g_clear_pointer (&surface->pending.input_region, cairo_region_destroy);
-    }
-
-  surface_process_damage (surface, surface->pending.damage);
-  empty_region (surface->pending.damage);
-
-  /* wl_surface.frame */
-  wl_list_insert_list (&compositor->frame_callbacks,
-                       &surface->pending.frame_callback_list);
-  wl_list_init (&surface->pending.frame_callback_list);
-}
-
-static void
-meta_wayland_surface_set_buffer_transform (struct wl_client *client,
-                                           struct wl_resource *resource,
-                                           int32_t transform)
-{
-  g_warning ("TODO: support set_buffer_transform request");
-}
-
-static void
-meta_wayland_surface_set_buffer_scale (struct wl_client *client,
-                                       struct wl_resource *resource,
-                                       int scale)
-{
-  g_warning ("TODO: support set_buffer_scale request");
-}
-
-const struct wl_surface_interface meta_wayland_surface_interface = {
-  meta_wayland_surface_destroy,
-  meta_wayland_surface_attach,
-  meta_wayland_surface_damage,
-  meta_wayland_surface_frame,
-  meta_wayland_surface_set_opaque_region,
-  meta_wayland_surface_set_input_region,
-  meta_wayland_surface_commit,
-  meta_wayland_surface_set_buffer_transform,
-  meta_wayland_surface_set_buffer_scale
-};
-
 void
 meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
                                          MetaWindow            *window)
@@ -495,87 +221,6 @@ meta_wayland_compositor_repick (MetaWaylandCompositor *compositor)
                             NULL);
 }
 
-void
-meta_wayland_surface_free (MetaWaylandSurface *surface)
-{
-  MetaWaylandCompositor *compositor = surface->compositor;
-  MetaWaylandFrameCallback *cb, *next;
-
-  compositor->surfaces = g_list_remove (compositor->surfaces, surface);
-
-  meta_wayland_buffer_reference (&surface->buffer_ref, NULL);
-
-  if (surface->pending.buffer)
-    wl_list_remove (&surface->pending.buffer_destroy_listener.link);
-
-  cairo_region_destroy (surface->pending.damage);
-
-  wl_list_for_each_safe (cb, next,
-                         &surface->pending.frame_callback_list, link)
-    wl_resource_destroy (cb->resource);
-
-  meta_wayland_compositor_repick (compositor);
-
-  g_assert (surface != compositor->seat->keyboard.focus);
-  if (surface == compositor->seat->pointer.focus)
-    {
-      meta_wayland_pointer_destroy_focus (&compositor->seat->pointer);
-
-      g_assert (surface != compositor->seat->pointer.focus);
-      g_assert (surface != compositor->seat->pointer.grab->focus);
-    }
-
- if (compositor->implicit_grab_surface == surface)
-   compositor->implicit_grab_surface = compositor->seat->pointer.current;
-
-  if (surface->resource)
-    wl_resource_set_user_data (surface->resource, NULL);
-  g_slice_free (MetaWaylandSurface, surface);
-}
-
-static void
-meta_wayland_surface_resource_destroy_cb (struct wl_resource *resource)
-{
-  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
-
-  /* There are four cases here:
-     - An X11 unmanaged window -> surface is NULL, nothing to do
-     - An X11 unmanaged window, but we got the wayland event first ->
-       just clear the resource pointer
-     - A wayland surface without window (destroyed before set_toplevel) ->
-       need to free the surface itself
-     - A wayland window -> need to unmanage
-  */
-
-  if (surface)
-    {
-      surface->resource = NULL;
-
-      /* NB: If the surface corresponds to an X window then we will be
-       * sure to free the MetaWindow according to some X event. */
-      if (surface->window &&
-         surface->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
-       {
-         MetaDisplay *display = meta_get_display ();
-         guint32 timestamp = meta_display_get_current_time_roundtrip (display);
-
-         meta_window_unmanage (surface->window, timestamp);
-       }
-      else if (!surface->window)
-       meta_wayland_surface_free (surface);
-    }
-}
-
-static void
-surface_handle_pending_buffer_destroy (struct wl_listener *listener,
-                                       void *data)
-{
-  MetaWaylandSurface *surface =
-    wl_container_of (listener, surface, pending.buffer_destroy_listener);
-
-  surface->pending.buffer = NULL;
-}
-
 static void
 meta_wayland_compositor_create_surface (struct wl_client *wayland_client,
                                         struct wl_resource *wayland_compositor_resource,
@@ -583,24 +228,14 @@ meta_wayland_compositor_create_surface (struct wl_client *wayland_client,
 {
   MetaWaylandCompositor *compositor =
     wl_resource_get_user_data (wayland_compositor_resource);
-  MetaWaylandSurface *surface = g_slice_new0 (MetaWaylandSurface);
-
-  surface->compositor = compositor;
+  MetaWaylandSurface *surface;
 
   /* a surface inherits the version from the compositor */
-  surface->resource = wl_resource_create (wayland_client,
-                                         &wl_surface_interface,
-                                         wl_resource_get_version (wayland_compositor_resource),
-                                         id);
-  wl_resource_set_implementation (surface->resource, &meta_wayland_surface_interface, surface,
-                                 meta_wayland_surface_resource_destroy_cb);
-
-  surface->pending.damage = cairo_region_create ();
-
-  surface->pending.buffer_destroy_listener.notify =
-    surface_handle_pending_buffer_destroy;
-  wl_list_init (&surface->pending.frame_callback_list);
-
+  surface = meta_wayland_surface_create (compositor,
+                                        wayland_client,
+                                        id,
+                                        wl_resource_get_version (wayland_compositor_resource));
+  
   compositor->surfaces = g_list_prepend (compositor->surfaces, surface);
 }
 
@@ -888,416 +523,6 @@ compositor_bind (struct wl_client *client,
 }
 
 static void
-shell_surface_pong (struct wl_client *client,
-                    struct wl_resource *resource,
-                    guint32 serial)
-{
-}
-
-typedef struct _MetaWaylandGrab
-{
-  MetaWaylandPointerGrab grab;
-  MetaWaylandSurfaceExtension *shell_surface;
-  struct wl_listener shell_surface_destroy_listener;
-  MetaWaylandPointer *pointer;
-} MetaWaylandGrab;
-
-typedef struct _MetaWaylandMoveGrab
-{
-  MetaWaylandGrab base;
-  wl_fixed_t dx, dy;
-} MetaWaylandMoveGrab;
-
-static void
-destroy_shell_surface_grab_listener (struct wl_listener *listener,
-                                     void *data)
-{
-  MetaWaylandGrab *grab = wl_container_of (listener, grab,
-                                           shell_surface_destroy_listener);
-  grab->shell_surface = NULL;
-
-  /* XXX: Could we perhaps just stop the grab here so we don't have
-   * to consider grab->shell_surface becoming NULL in grab interface
-   * callbacks? */
-}
-
-typedef enum _GrabCursor
-{
-  GRAB_CURSOR_MOVE,
-} GrabCursor;
-
-static void
-grab_pointer (MetaWaylandGrab *grab,
-              const MetaWaylandPointerGrabInterface *interface,
-              MetaWaylandSurfaceExtension *shell_surface,
-              MetaWaylandPointer *pointer,
-              GrabCursor cursor)
-{
-  /* TODO: popup_grab_end (pointer); */
-
-  grab->grab.interface = interface;
-  grab->shell_surface = shell_surface;
-  grab->shell_surface_destroy_listener.notify =
-    destroy_shell_surface_grab_listener;
-  wl_resource_add_destroy_listener (shell_surface->resource,
-                                    &grab->shell_surface_destroy_listener);
-
-  grab->pointer = pointer;
-  grab->grab.focus = shell_surface->surface;
-
-  meta_wayland_pointer_start_grab (pointer, &grab->grab);
-
-  /* TODO: send_grab_cursor (cursor); */
-
-  /* XXX: In Weston there is a desktop shell protocol which has
-   * a set_grab_surface request that's used to specify the surface
-   * that's focused here.
-   *
-   * TODO: understand why.
-   *
-   * XXX: For now we just focus the surface directly associated with
-   * the grab.
-   */
-  meta_wayland_pointer_set_focus (pointer,
-                                  grab->shell_surface->surface,
-                                  wl_fixed_from_int (0),
-                                  wl_fixed_from_int (0));
-}
-
-static void
-release_pointer (MetaWaylandGrab *grab)
-{
-  if (grab->shell_surface)
-    wl_list_remove (&grab->shell_surface_destroy_listener.link);
-
-  meta_wayland_pointer_end_grab (grab->pointer);
-}
-
-static void
-noop_grab_focus (MetaWaylandPointerGrab *grab,
-                 MetaWaylandSurface *surface,
-                 wl_fixed_t x,
-                 wl_fixed_t y)
-{
-  grab->focus = NULL;
-}
-
-static void
-move_grab_motion (MetaWaylandPointerGrab *grab,
-                  uint32_t time,
-                  wl_fixed_t x,
-                  wl_fixed_t y)
-{
-  MetaWaylandMoveGrab *move = (MetaWaylandMoveGrab *)grab;
-  MetaWaylandPointer *pointer = move->base.pointer;
-  MetaWaylandSurfaceExtension *shell_surface = move->base.shell_surface;
-
-  if (!shell_surface)
-    return;
-
-  meta_window_move (shell_surface->surface->window,
-                    TRUE,
-                    wl_fixed_to_int (pointer->x + move->dx),
-                    wl_fixed_to_int (pointer->y + move->dy));
-}
-
-static void
-move_grab_button (MetaWaylandPointerGrab *pointer_grab,
-                  uint32_t time,
-                  uint32_t button,
-                  uint32_t state_w)
-{
-  MetaWaylandGrab *grab =
-    wl_container_of (pointer_grab, grab, grab);
-  MetaWaylandMoveGrab *move = (MetaWaylandMoveGrab *)grab;
-  MetaWaylandPointer *pointer = grab->pointer;
-  enum wl_pointer_button_state state = state_w;
-
-  if (pointer->button_count == 0 && state == WL_POINTER_BUTTON_STATE_RELEASED)
-    {
-      release_pointer (grab);
-      g_slice_free (MetaWaylandMoveGrab, move);
-    }
-}
-
-static const MetaWaylandPointerGrabInterface move_grab_interface = {
-    noop_grab_focus,
-    move_grab_motion,
-    move_grab_button,
-};
-
-static void
-start_surface_move (MetaWaylandSurfaceExtension *shell_surface,
-                    MetaWaylandSeat *seat)
-{
-  MetaWaylandMoveGrab *move;
-  MetaRectangle rect;
-
-  g_return_if_fail (shell_surface != NULL);
-
-  /* TODO: check if the surface is fullscreen when we support fullscreen */
-
-  move = g_slice_new (MetaWaylandMoveGrab);
-
-  meta_window_get_input_rect (shell_surface->surface->window,
-                              &rect);
-
-  move->dx = wl_fixed_from_int (rect.x) - seat->pointer.grab_x;
-  move->dy = wl_fixed_from_int (rect.y) - seat->pointer.grab_y;
-
-  grab_pointer (&move->base, &move_grab_interface, shell_surface,
-                &seat->pointer, GRAB_CURSOR_MOVE);
-}
-
-static void
-shell_surface_move (struct wl_client *client,
-                    struct wl_resource *resource,
-                    struct wl_resource *seat_resource,
-                    guint32 serial)
-{
-  MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
-  MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource);
-
-  if (seat->pointer.button_count == 0 ||
-      seat->pointer.grab_serial != serial ||
-      seat->pointer.focus != shell_surface->surface)
-    return;
-
-  start_surface_move (shell_surface, seat);
-}
-
-static void
-shell_surface_resize (struct wl_client *client,
-                      struct wl_resource *resource,
-                      struct wl_resource *seat,
-                      guint32 serial,
-                      guint32 edges)
-{
-  g_warning ("TODO: support shell_surface_resize request");
-}
-
-static void
-ensure_surface_window (MetaWaylandSurface *surface)
-{
-  MetaDisplay *display = meta_get_display ();
-
-  if (!surface->window)
-    {
-      int width, height;
-
-      if (surface->buffer_ref.buffer)
-        {
-          MetaWaylandBuffer *buffer = surface->buffer_ref.buffer;
-          width = buffer->width;
-          height = buffer->width;
-        }
-      else
-        {
-          width = 0;
-          height = 0;
-        }
-
-      surface->window =
-        meta_window_new_for_wayland (display, width, height, surface);
-
-      meta_window_calc_showing (surface->window);
-    }
-}
-
-static void
-shell_surface_set_toplevel (struct wl_client *client,
-                            struct wl_resource *resource)
-{
-  MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
-  MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource);
-  MetaWaylandSurface *surface = shell_surface->surface;
-
-  /* NB: Surfaces from xwayland become managed based on X events. */
-  if (client == compositor->xwayland_client)
-    return;
-
-  ensure_surface_window (surface);
-
-  meta_window_unmake_fullscreen (surface->window);
-}
-
-static void
-shell_surface_set_transient (struct wl_client *client,
-                             struct wl_resource *resource,
-                             struct wl_resource *parent,
-                             int x,
-                             int y,
-                             guint32 flags)
-{
-  MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
-  MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource);
-  MetaWaylandSurface *surface = shell_surface->surface;
-
-  /* NB: Surfaces from xwayland become managed based on X events. */
-  if (client == compositor->xwayland_client)
-    return;
-
-  ensure_surface_window (surface);
-}
-
-static void
-shell_surface_set_fullscreen (struct wl_client *client,
-                              struct wl_resource *resource,
-                              guint32 method,
-                              guint32 framerate,
-                              struct wl_resource *output)
-{
-  MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
-  MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource);
-  MetaWaylandSurface *surface = shell_surface->surface;
-
-  /* NB: Surfaces from xwayland become managed based on X events. */
-  if (client == compositor->xwayland_client)
-    return;
-
-  ensure_surface_window (surface);
-
-  meta_window_make_fullscreen (surface->window);
-}
-
-static void
-shell_surface_set_popup (struct wl_client *client,
-                         struct wl_resource *resource,
-                         struct wl_resource *seat,
-                         guint32 serial,
-                         struct wl_resource *parent,
-                         gint32 x,
-                         gint32 y,
-                         guint32 flags)
-{
-}
-
-static void
-shell_surface_set_maximized (struct wl_client *client,
-                             struct wl_resource *resource,
-                             struct wl_resource *output)
-{
-  g_warning ("TODO: support shell_surface_set_maximized request");
-}
-
-static void
-shell_surface_set_title (struct wl_client *client,
-                         struct wl_resource *resource,
-                         const char *title)
-{
-  g_warning ("TODO: support shell_surface_set_title request");
-}
-
-static void
-shell_surface_set_class (struct wl_client *client,
-                         struct wl_resource *resource,
-                         const char *class_)
-{
-  g_warning ("TODO: support shell_surface_set_class request");
-}
-
-static const struct wl_shell_surface_interface meta_wayland_shell_surface_interface =
-{
-  shell_surface_pong,
-  shell_surface_move,
-  shell_surface_resize,
-  shell_surface_set_toplevel,
-  shell_surface_set_transient,
-  shell_surface_set_fullscreen,
-  shell_surface_set_popup,
-  shell_surface_set_maximized,
-  shell_surface_set_title,
-  shell_surface_set_class
-};
-
-static void
-extension_handle_surface_destroy (struct wl_listener *listener,
-                                 void *data)
-{
-  MetaWaylandSurfaceExtension *extension =
-    wl_container_of (listener, extension, surface_destroy_listener);
-
-  extension->surface = NULL;
-  wl_resource_destroy (extension->resource);
-}
-
-static void
-destroy_surface_extension (struct wl_resource *resource)
-{
-  MetaWaylandSurfaceExtension *extension = wl_resource_get_user_data (resource);
-
-  /* In case cleaning up a dead client destroys extension first */
-  if (extension->surface)
-    {
-      wl_list_remove (&extension->surface_destroy_listener.link);
-    }
-
-  g_free (extension);
-}
-
-static void
-create_surface_extension (struct wl_client          *client,
-                         struct wl_resource        *master_resource,
-                         guint32                    id,
-                         MetaWaylandSurface        *surface,
-                         const struct wl_interface *interface,
-                         const void                *implementation)
-{
-  MetaWaylandSurfaceExtension *extension;
-
-  extension = g_new0 (MetaWaylandSurfaceExtension, 1);
-
-  extension->resource = wl_resource_create (client, interface,
-                                           wl_resource_get_version (master_resource), id);
-  wl_resource_set_implementation (extension->resource, implementation,
-                                 extension, destroy_surface_extension);
-
-  extension->surface = surface;
-  extension->surface_destroy_listener.notify = extension_handle_surface_destroy;
-  wl_resource_add_destroy_listener (surface->resource,
-                                    &extension->surface_destroy_listener);
-}
-
-static void
-get_shell_surface (struct wl_client *client,
-                   struct wl_resource *resource,
-                   guint32 id,
-                   struct wl_resource *surface_resource)
-{
-  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
-
-  if (surface->has_shell_surface)
-    {
-      wl_resource_post_error (surface_resource,
-                              WL_DISPLAY_ERROR_INVALID_OBJECT,
-                              "wl_shell::get_shell_surface already requested");
-      return;
-    }
-
-  create_surface_extension (client, resource, id, surface,
-                           &wl_shell_surface_interface,
-                           &meta_wayland_shell_surface_interface);
-  surface->has_shell_surface = TRUE;
-}
-
-static const struct wl_shell_interface meta_wayland_shell_interface =
-{
-  get_shell_surface
-};
-
-static void
-bind_shell (struct wl_client *client,
-            void *data,
-            guint32 version,
-            guint32 id)
-{
-  struct wl_resource *resource;
-
-  resource = wl_resource_create (client, &wl_shell_interface, version, id);
-  wl_resource_set_implementation (resource, &meta_wayland_shell_interface, data, NULL);
-}
-
-static void
 stage_destroy_cb (void)
 {
   meta_quit (META_EXIT_SUCCESS);
@@ -1681,10 +906,7 @@ meta_wayland_init (void)
                               compositor, /* hook_data */
                               NULL /* data_destroy */);
 
-  if (wl_global_create (compositor->wayland_display,
-                       &wl_shell_interface, 1,
-                       compositor, bind_shell) == NULL)
-    g_error ("Failed to register a global shell object");
+  meta_wayland_init_shell (compositor);
 
   clutter_actor_show (compositor->stage);
 


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