[mutter] wayland: Restructure surface role building blocks code



commit 704b73b04125a11e5bb004b1857975f252dc029c
Author: Jonas Ådahl <jadahl gmail com>
Date:   Wed Dec 20 17:40:22 2017 +0800

    wayland: Restructure surface role building blocks code
    
    This commit moves out non-core wl_surface related code into separate
    code units, while renaming types to fit a common scheme. The changes
    done are:
    
     * ClutterActor based surface roles built upon
       MetaWalyandSurfaceRoleActorSurface. This object has been renamed to
       MetaWaylandActorSurface and related functionality has moved into
       meta-wayland-actor-surface.c.
    
     * The code related to roles backed by a MetaWindow (i.e. built upon
       MetaWaylandShellSurface) was moved into meta-wayland-shell-surface.c
    
     * The majority of subsurface related code was moved into into
       meta-wayland-subsurface.c and the object was renamed
       MetaWaylandSubsurface.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/5
    https://bugzilla.gnome.org/show_bug.cgi?id=791938

 src/Makefile.am                          |   6 +
 src/wayland/meta-wayland-actor-surface.c | 103 +++++
 src/wayland/meta-wayland-actor-surface.h |  37 ++
 src/wayland/meta-wayland-shell-surface.c | 127 +++++++
 src/wayland/meta-wayland-shell-surface.h |  64 ++++
 src/wayland/meta-wayland-subsurface.c    | 429 +++++++++++++++++++++
 src/wayland/meta-wayland-subsurface.h    |  36 ++
 src/wayland/meta-wayland-surface.c       | 629 ++-----------------------------
 src/wayland/meta-wayland-surface.h       |  45 +--
 src/wayland/meta-wayland-wl-shell.h      |   2 +-
 src/wayland/meta-wayland-xdg-shell.h     |   2 +-
 src/wayland/meta-wayland.c               |   2 +
 12 files changed, 834 insertions(+), 648 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index e89823180..617aada1e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -434,6 +434,12 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES +=    \
        wayland/meta-wayland-surface-role-cursor.h      \
        wayland/meta-wayland-surface-role-tablet-cursor.c       \
        wayland/meta-wayland-surface-role-tablet-cursor.h       \
+       wayland/meta-wayland-actor-surface.c    \
+       wayland/meta-wayland-actor-surface.h    \
+       wayland/meta-wayland-subsurface.c       \
+       wayland/meta-wayland-subsurface.h       \
+       wayland/meta-wayland-shell-surface.c    \
+       wayland/meta-wayland-shell-surface.h    \
        wayland/meta-wayland-text-input.c       \
        wayland/meta-wayland-text-input.h       \
        wayland/meta-wayland-types.h            \
diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c
new file mode 100644
index 000000000..a07d0d5e9
--- /dev/null
+++ b/src/wayland/meta-wayland-actor-surface.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2012,2013 Intel Corporation
+ * Copyright (C) 2013-2017 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 "wayland/meta-wayland-actor-surface.h"
+
+#include "compositor/meta-surface-actor-wayland.h"
+#include "wayland/meta-wayland-surface.h"
+
+G_DEFINE_TYPE (MetaWaylandActorSurface,
+               meta_wayland_actor_surface,
+               META_TYPE_WAYLAND_SURFACE_ROLE)
+
+static void
+meta_wayland_actor_surface_assigned (MetaWaylandSurfaceRole *surface_role)
+{
+  MetaWaylandSurface *surface =
+    meta_wayland_surface_role_get_surface (surface_role);
+  MetaSurfaceActorWayland *surface_actor =
+    META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
+
+  meta_surface_actor_wayland_add_frame_callbacks (surface_actor,
+                                                  &surface->pending_frame_callback_list);
+  wl_list_init (&surface->pending_frame_callback_list);
+}
+
+static void
+queue_surface_actor_frame_callbacks (MetaWaylandSurface      *surface,
+                                     MetaWaylandPendingState *pending)
+{
+  MetaSurfaceActorWayland *surface_actor =
+    META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
+
+  meta_surface_actor_wayland_add_frame_callbacks (surface_actor,
+                                                  &pending->frame_callback_list);
+  wl_list_init (&pending->frame_callback_list);
+}
+
+static void
+meta_wayland_actor_surface_commit (MetaWaylandSurfaceRole  *surface_role,
+                                   MetaWaylandPendingState *pending)
+{
+  MetaWaylandSurface *surface =
+    meta_wayland_surface_role_get_surface (surface_role);
+  MetaWaylandSurface *toplevel_surface;
+
+  queue_surface_actor_frame_callbacks (surface, pending);
+
+  toplevel_surface = meta_wayland_surface_get_toplevel (surface);
+  if (!toplevel_surface || !toplevel_surface->window)
+    return;
+
+  meta_surface_actor_wayland_sync_state (
+    META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
+}
+
+static gboolean
+meta_wayland_actor_surface_is_on_logical_monitor (MetaWaylandSurfaceRole *surface_role,
+                                                  MetaLogicalMonitor     *logical_monitor)
+{
+  MetaWaylandSurface *surface =
+    meta_wayland_surface_role_get_surface (surface_role);
+  MetaSurfaceActorWayland *actor =
+    META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
+
+  return meta_surface_actor_wayland_is_on_monitor (actor, logical_monitor);
+}
+
+static void
+meta_wayland_actor_surface_init (MetaWaylandActorSurface *role)
+{
+}
+
+static void
+meta_wayland_actor_surface_class_init (MetaWaylandActorSurfaceClass *klass)
+{
+  MetaWaylandSurfaceRoleClass *surface_role_class =
+    META_WAYLAND_SURFACE_ROLE_CLASS (klass);
+
+  surface_role_class->assigned = meta_wayland_actor_surface_assigned;
+  surface_role_class->commit = meta_wayland_actor_surface_commit;
+  surface_role_class->is_on_logical_monitor =
+    meta_wayland_actor_surface_is_on_logical_monitor;
+}
diff --git a/src/wayland/meta-wayland-actor-surface.h b/src/wayland/meta-wayland-actor-surface.h
new file mode 100644
index 000000000..9f0f79e7b
--- /dev/null
+++ b/src/wayland/meta-wayland-actor-surface.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012,2013 Intel Corporation
+ * Copyright (C) 2013-2017 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.
+ */
+
+#ifndef META_WAYLAND_ACTOR_SURFACE_H
+#define META_WAYLAND_ACTOR_SURFACE_H
+
+#include "wayland/meta-wayland-surface.h"
+
+#define META_TYPE_WAYLAND_ACTOR_SURFACE (meta_wayland_actor_surface_get_type ())
+G_DECLARE_DERIVABLE_TYPE (MetaWaylandActorSurface,
+                          meta_wayland_actor_surface,
+                          META, WAYLAND_ACTOR_SURFACE,
+                          MetaWaylandSurfaceRole)
+
+struct _MetaWaylandActorSurfaceClass
+{
+  MetaWaylandSurfaceRoleClass parent_class;
+};
+
+#endif /* META_WAYLAND_ACTOR_SURFACE_H */
diff --git a/src/wayland/meta-wayland-shell-surface.c b/src/wayland/meta-wayland-shell-surface.c
new file mode 100644
index 000000000..023ece00a
--- /dev/null
+++ b/src/wayland/meta-wayland-shell-surface.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2012,2013 Intel Corporation
+ * Copyright (C) 2013-2017 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 "wayland/meta-wayland-shell-surface.h"
+
+#include "compositor/meta-surface-actor-wayland.h"
+#include "wayland/meta-wayland-actor-surface.h"
+#include "wayland/meta-wayland-buffer.h"
+
+G_DEFINE_TYPE (MetaWaylandShellSurface,
+               meta_wayland_shell_surface,
+               META_TYPE_WAYLAND_ACTOR_SURFACE)
+
+void
+meta_wayland_shell_surface_configure (MetaWaylandShellSurface *shell_surface,
+                                      int                      new_x,
+                                      int                      new_y,
+                                      int                      new_width,
+                                      int                      new_height,
+                                      MetaWaylandSerial       *sent_serial)
+{
+  MetaWaylandShellSurfaceClass *shell_surface_class =
+    META_WAYLAND_SHELL_SURFACE_GET_CLASS (shell_surface);
+
+  shell_surface_class->configure (shell_surface,
+                                  new_x,
+                                  new_y,
+                                  new_width,
+                                  new_height,
+                                  sent_serial);
+}
+
+void
+meta_wayland_shell_surface_ping (MetaWaylandShellSurface *shell_surface,
+                                 uint32_t                 serial)
+{
+  MetaWaylandShellSurfaceClass *shell_surface_class =
+    META_WAYLAND_SHELL_SURFACE_GET_CLASS (shell_surface);
+
+  shell_surface_class->ping (shell_surface, serial);
+}
+
+void
+meta_wayland_shell_surface_close (MetaWaylandShellSurface *shell_surface)
+{
+  MetaWaylandShellSurfaceClass *shell_surface_class =
+    META_WAYLAND_SHELL_SURFACE_GET_CLASS (shell_surface);
+
+  shell_surface_class->close (shell_surface);
+}
+
+void
+meta_wayland_shell_surface_managed (MetaWaylandShellSurface *shell_surface,
+                                    MetaWindow              *window)
+{
+  MetaWaylandShellSurfaceClass *shell_surface_class =
+    META_WAYLAND_SHELL_SURFACE_GET_CLASS (shell_surface);
+
+  shell_surface_class->managed (shell_surface, window);
+}
+
+static void
+meta_wayland_shell_surface_surface_commit (MetaWaylandSurfaceRole  *surface_role,
+                                           MetaWaylandPendingState *pending)
+{
+  MetaWaylandSurface *surface =
+    meta_wayland_surface_role_get_surface (surface_role);
+  MetaWaylandSurfaceRoleClass *surface_role_class;
+  MetaWindow *window;
+  MetaWaylandBuffer *buffer;
+  CoglTexture *texture;
+  MetaSurfaceActorWayland *surface_actor;
+  double scale;
+
+  surface_role_class =
+    META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_shell_surface_parent_class);
+  surface_role_class->commit (surface_role, pending);
+
+  buffer = surface->buffer_ref.buffer;
+  if (!buffer)
+    return;
+
+  window = surface->window;
+  if (!window)
+    return;
+
+  surface_actor = META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
+  scale = meta_surface_actor_wayland_get_scale (surface_actor);
+  texture = meta_wayland_buffer_get_texture (buffer);
+
+  window->buffer_rect.width = cogl_texture_get_width (texture) * scale;
+  window->buffer_rect.height = cogl_texture_get_height (texture) * scale;
+}
+
+static void
+meta_wayland_shell_surface_init (MetaWaylandShellSurface *role)
+{
+}
+
+static void
+meta_wayland_shell_surface_class_init (MetaWaylandShellSurfaceClass *klass)
+{
+  MetaWaylandSurfaceRoleClass *surface_role_class =
+    META_WAYLAND_SURFACE_ROLE_CLASS (klass);
+
+  surface_role_class->commit = meta_wayland_shell_surface_surface_commit;
+}
diff --git a/src/wayland/meta-wayland-shell-surface.h b/src/wayland/meta-wayland-shell-surface.h
new file mode 100644
index 000000000..72b0828b5
--- /dev/null
+++ b/src/wayland/meta-wayland-shell-surface.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012,2013 Intel Corporation
+ * Copyright (C) 2013-2017 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.
+ */
+
+#ifndef META_WAYLAND_SHELL_SURFACE_H
+#define META_WAYLAND_SHELL_SURFACE_H
+
+#include "wayland/meta-wayland-actor-surface.h"
+
+#define META_TYPE_WAYLAND_SHELL_SURFACE (meta_wayland_shell_surface_get_type ())
+G_DECLARE_DERIVABLE_TYPE (MetaWaylandShellSurface,
+                          meta_wayland_shell_surface,
+                          META, WAYLAND_SHELL_SURFACE,
+                          MetaWaylandActorSurface)
+
+struct _MetaWaylandShellSurfaceClass
+{
+  MetaWaylandActorSurfaceClass parent_class;
+
+  void (*configure) (MetaWaylandShellSurface *shell_surface,
+                     int                      new_x,
+                     int                      new_y,
+                     int                      new_width,
+                     int                      new_height,
+                     MetaWaylandSerial       *sent_serial);
+  void (*managed) (MetaWaylandShellSurface *shell_surface,
+                   MetaWindow              *window);
+  void (*ping) (MetaWaylandShellSurface *shell_surface,
+                uint32_t                 serial);
+  void (*close) (MetaWaylandShellSurface *shell_surface);
+};
+
+void meta_wayland_shell_surface_configure (MetaWaylandShellSurface *shell_surface,
+                                           int                      new_x,
+                                           int                      new_y,
+                                           int                      new_width,
+                                           int                      new_height,
+                                           MetaWaylandSerial       *sent_serial);
+
+void meta_wayland_shell_surface_ping (MetaWaylandShellSurface *shell_surface,
+                                      uint32_t                 serial);
+
+void meta_wayland_shell_surface_close (MetaWaylandShellSurface *shell_surface);
+
+void meta_wayland_shell_surface_managed (MetaWaylandShellSurface *shell_surface,
+                                         MetaWindow              *window);
+
+#endif /* META_WAYLAND_SHELL_SURFACE_H */
diff --git a/src/wayland/meta-wayland-subsurface.c b/src/wayland/meta-wayland-subsurface.c
new file mode 100644
index 000000000..1e630fa98
--- /dev/null
+++ b/src/wayland/meta-wayland-subsurface.c
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2012,2013 Intel Corporation
+ * Copyright (C) 2013-2017 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 "wayland/meta-wayland-subsurface.h"
+
+#include "compositor/meta-surface-actor-wayland.h"
+#include "wayland/meta-wayland.h"
+#include "wayland/meta-wayland-surface.h"
+
+typedef enum
+{
+  META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE,
+  META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW
+} MetaWaylandSubsurfacePlacement;
+
+typedef struct
+{
+  MetaWaylandSubsurfacePlacement placement;
+  MetaWaylandSurface *sibling;
+  struct wl_listener sibling_destroy_listener;
+} MetaWaylandSubsurfacePlacementOp;
+
+struct _MetaWaylandSubsurface
+{
+  MetaWaylandActorSurface parent;
+};
+
+G_DEFINE_TYPE (MetaWaylandSubsurface,
+               meta_wayland_subsurface,
+               META_TYPE_WAYLAND_ACTOR_SURFACE)
+
+void
+meta_wayland_subsurface_parent_state_applied (MetaWaylandSubsurface *subsurface)
+{
+  MetaWaylandSurfaceRole *surface_role = META_WAYLAND_SURFACE_ROLE (subsurface);
+  MetaWaylandSurface *surface =
+    meta_wayland_surface_role_get_surface (surface_role);
+
+  if (surface->sub.pending_pos)
+    {
+      surface->sub.x = surface->sub.pending_x;
+      surface->sub.y = surface->sub.pending_y;
+      surface->sub.pending_pos = FALSE;
+    }
+
+  if (surface->sub.pending_placement_ops)
+    {
+      GSList *it;
+      MetaWaylandSurface *parent = surface->sub.parent;
+      ClutterActor *parent_actor =
+        clutter_actor_get_parent (CLUTTER_ACTOR (parent->surface_actor));
+      ClutterActor *surface_actor = CLUTTER_ACTOR (surface->surface_actor);
+
+      for (it = surface->sub.pending_placement_ops; it; it = it->next)
+        {
+          MetaWaylandSubsurfacePlacementOp *op = it->data;
+          ClutterActor *sibling_actor;
+
+          if (!op->sibling)
+            {
+              g_slice_free (MetaWaylandSubsurfacePlacementOp, op);
+              continue;
+            }
+
+          sibling_actor = CLUTTER_ACTOR (op->sibling->surface_actor);
+
+          switch (op->placement)
+            {
+            case META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE:
+              clutter_actor_set_child_above_sibling (parent_actor,
+                                                     surface_actor,
+                                                     sibling_actor);
+              break;
+            case META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW:
+              clutter_actor_set_child_below_sibling (parent_actor,
+                                                     surface_actor,
+                                                     sibling_actor);
+              break;
+            }
+
+          wl_list_remove (&op->sibling_destroy_listener.link);
+          g_slice_free (MetaWaylandSubsurfacePlacementOp, op);
+        }
+
+      g_slist_free (surface->sub.pending_placement_ops);
+      surface->sub.pending_placement_ops = NULL;
+    }
+
+  if (meta_wayland_surface_is_effectively_synchronized (surface))
+    meta_wayland_surface_apply_pending_state (surface, surface->sub.pending);
+
+  meta_surface_actor_wayland_sync_subsurface_state (
+    META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
+}
+
+static void
+meta_wayland_subsurface_commit (MetaWaylandSurfaceRole  *surface_role,
+                                MetaWaylandPendingState *pending)
+{
+  MetaWaylandSurfaceRoleClass *surface_role_class;
+  MetaWaylandSurface *surface =
+    meta_wayland_surface_role_get_surface (surface_role);
+  ClutterActor *actor = CLUTTER_ACTOR (surface->surface_actor);
+
+  surface_role_class =
+    META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_subsurface_parent_class);
+  surface_role_class->commit (surface_role, pending);
+
+  if (surface->buffer_ref.buffer != NULL)
+    clutter_actor_show (actor);
+  else
+    clutter_actor_hide (actor);
+}
+
+static MetaWaylandSurface *
+meta_wayland_subsurface_get_toplevel (MetaWaylandSurfaceRole *surface_role)
+{
+  MetaWaylandSurface *surface =
+    meta_wayland_surface_role_get_surface (surface_role);
+  MetaWaylandSurface *parent = surface->sub.parent;
+
+  if (parent)
+    return meta_wayland_surface_get_toplevel (parent);
+  else
+    return NULL;
+}
+
+static void
+meta_wayland_subsurface_init (MetaWaylandSubsurface *role)
+{
+}
+
+static void
+meta_wayland_subsurface_class_init (MetaWaylandSubsurfaceClass *klass)
+{
+  MetaWaylandSurfaceRoleClass *surface_role_class =
+    META_WAYLAND_SURFACE_ROLE_CLASS (klass);
+
+  surface_role_class->commit = meta_wayland_subsurface_commit;
+  surface_role_class->get_toplevel = meta_wayland_subsurface_get_toplevel;
+}
+
+static void
+unparent_actor (MetaWaylandSurface *surface)
+{
+  ClutterActor *actor = CLUTTER_ACTOR (surface->surface_actor);
+  ClutterActor *parent_actor;
+
+  parent_actor = clutter_actor_get_parent (actor);
+  clutter_actor_remove_child (parent_actor, actor);
+}
+
+static void
+wl_subsurface_destructor (struct wl_resource *resource)
+{
+  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
+
+  meta_wayland_compositor_destroy_frame_callbacks (surface->compositor,
+                                                   surface);
+  if (surface->sub.parent)
+    {
+      wl_list_remove (&surface->sub.parent_destroy_listener.link);
+      surface->sub.parent->subsurfaces =
+        g_list_remove (surface->sub.parent->subsurfaces, surface);
+      unparent_actor (surface);
+      surface->sub.parent = NULL;
+    }
+
+  g_clear_object (&surface->sub.pending);
+  surface->wl_subsurface = NULL;
+}
+
+static void
+wl_subsurface_destroy (struct wl_client   *client,
+                       struct wl_resource *resource)
+{
+  wl_resource_destroy (resource);
+}
+
+static void
+wl_subsurface_set_position (struct wl_client   *client,
+                            struct wl_resource *resource,
+                            int32_t             x,
+                            int32_t             y)
+{
+  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
+
+  surface->sub.pending_x = x;
+  surface->sub.pending_y = y;
+  surface->sub.pending_pos = TRUE;
+}
+
+static gboolean
+is_valid_sibling (MetaWaylandSurface *surface,
+                  MetaWaylandSurface *sibling)
+{
+  if (surface->sub.parent == sibling)
+    return TRUE;
+  if (surface->sub.parent == sibling->sub.parent)
+    return TRUE;
+  return FALSE;
+}
+
+static void
+subsurface_handle_pending_sibling_destroyed (struct wl_listener *listener,
+                                             void               *data)
+{
+  MetaWaylandSubsurfacePlacementOp *op =
+    wl_container_of (listener, op, sibling_destroy_listener);
+
+  op->sibling = NULL;
+}
+
+static void
+queue_subsurface_placement (MetaWaylandSurface             *surface,
+                            MetaWaylandSurface             *sibling,
+                            MetaWaylandSubsurfacePlacement  placement)
+{
+  MetaWaylandSubsurfacePlacementOp *op =
+    g_slice_new (MetaWaylandSubsurfacePlacementOp);
+
+  op->placement = placement;
+  op->sibling = sibling;
+  op->sibling_destroy_listener.notify =
+    subsurface_handle_pending_sibling_destroyed;
+  wl_resource_add_destroy_listener (sibling->resource,
+                                    &op->sibling_destroy_listener);
+
+  surface->sub.pending_placement_ops =
+    g_slist_append (surface->sub.pending_placement_ops, op);
+}
+
+static void
+wl_subsurface_place_above (struct wl_client   *client,
+                           struct wl_resource *resource,
+                           struct wl_resource *sibling_resource)
+{
+  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
+  MetaWaylandSurface *sibling = wl_resource_get_user_data (sibling_resource);
+
+  if (!is_valid_sibling (surface, sibling))
+    {
+      wl_resource_post_error (resource, WL_SUBSURFACE_ERROR_BAD_SURFACE,
+                              "wl_subsurface::place_above: wl_surface@%d is "
+                              "not a valid parent or sibling",
+                              wl_resource_get_id (sibling->resource));
+      return;
+    }
+
+  queue_subsurface_placement (surface,
+                              sibling,
+                              META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE);
+}
+
+static void
+wl_subsurface_place_below (struct wl_client   *client,
+                           struct wl_resource *resource,
+                           struct wl_resource *sibling_resource)
+{
+  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
+  MetaWaylandSurface *sibling = wl_resource_get_user_data (sibling_resource);
+
+  if (!is_valid_sibling (surface, sibling))
+    {
+      wl_resource_post_error (resource, WL_SUBSURFACE_ERROR_BAD_SURFACE,
+                              "wl_subsurface::place_below: wl_surface@%d is "
+                              "not a valid parent or sibling",
+                              wl_resource_get_id (sibling->resource));
+      return;
+    }
+
+  queue_subsurface_placement (surface,
+                              sibling,
+                              META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW);
+}
+
+static void
+wl_subsurface_set_sync (struct wl_client   *client,
+                        struct wl_resource *resource)
+{
+  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
+
+  surface->sub.synchronous = TRUE;
+}
+
+static void
+wl_subsurface_set_desync (struct wl_client   *client,
+                          struct wl_resource *resource)
+{
+  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
+  gboolean was_effectively_synchronized;
+
+  was_effectively_synchronized =
+    meta_wayland_surface_is_effectively_synchronized (surface);
+  surface->sub.synchronous = FALSE;
+
+  if (was_effectively_synchronized &&
+      !meta_wayland_surface_is_effectively_synchronized (surface))
+    meta_wayland_surface_apply_pending_state (surface, surface->sub.pending);
+}
+
+static const struct wl_subsurface_interface meta_wayland_wl_subsurface_interface = {
+  wl_subsurface_destroy,
+  wl_subsurface_set_position,
+  wl_subsurface_place_above,
+  wl_subsurface_place_below,
+  wl_subsurface_set_sync,
+  wl_subsurface_set_desync,
+};
+
+static void
+wl_subcompositor_destroy (struct wl_client   *client,
+                          struct wl_resource *resource)
+{
+  wl_resource_destroy (resource);
+}
+
+static void
+surface_handle_parent_surface_destroyed (struct wl_listener *listener,
+                                         void               *data)
+{
+  MetaWaylandSurface *surface = wl_container_of (listener,
+                                                 surface,
+                                                 sub.parent_destroy_listener);
+
+  surface->sub.parent = NULL;
+  unparent_actor (surface);
+}
+
+static void
+wl_subcompositor_get_subsurface (struct wl_client   *client,
+                                 struct wl_resource *resource,
+                                 uint32_t            id,
+                                 struct wl_resource *surface_resource,
+                                 struct wl_resource *parent_resource)
+{
+  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
+  MetaWaylandSurface *parent = wl_resource_get_user_data (parent_resource);
+
+  if (surface->wl_subsurface)
+    {
+      wl_resource_post_error (surface_resource,
+                              WL_DISPLAY_ERROR_INVALID_OBJECT,
+                              "wl_subcompositor::get_subsurface already requested");
+      return;
+    }
+
+  if (!meta_wayland_surface_assign_role (surface,
+                                         META_TYPE_WAYLAND_SUBSURFACE,
+                                         NULL))
+    {
+      wl_resource_post_error (resource, WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
+                              "wl_surface@%d already has a different role",
+                              wl_resource_get_id (surface->resource));
+      return;
+    }
+
+  surface->wl_subsurface =
+    wl_resource_create (client,
+                        &wl_subsurface_interface,
+                        wl_resource_get_version (resource),
+                        id);
+  wl_resource_set_implementation (surface->wl_subsurface,
+                                  &meta_wayland_wl_subsurface_interface,
+                                  surface,
+                                  wl_subsurface_destructor);
+
+  surface->sub.pending = g_object_new (META_TYPE_WAYLAND_PENDING_STATE, NULL);
+  surface->sub.synchronous = TRUE;
+  surface->sub.parent = parent;
+  surface->sub.parent_destroy_listener.notify =
+    surface_handle_parent_surface_destroyed;
+  wl_resource_add_destroy_listener (parent->resource,
+                                    &surface->sub.parent_destroy_listener);
+  parent->subsurfaces = g_list_append (parent->subsurfaces, surface);
+
+  clutter_actor_add_child (CLUTTER_ACTOR (parent->surface_actor),
+                           CLUTTER_ACTOR (surface->surface_actor));
+
+  clutter_actor_set_reactive (CLUTTER_ACTOR (surface->surface_actor), TRUE);
+}
+
+static const struct wl_subcompositor_interface meta_wayland_subcompositor_interface = {
+  wl_subcompositor_destroy,
+  wl_subcompositor_get_subsurface,
+};
+
+static void
+bind_subcompositor (struct wl_client *client,
+                    void             *data,
+                    uint32_t          version,
+                    uint32_t          id)
+{
+  struct wl_resource *resource;
+
+  resource = wl_resource_create (client, &wl_subcompositor_interface,
+                                 version, id);
+  wl_resource_set_implementation (resource, &meta_wayland_subcompositor_interface,
+                                  data, NULL);
+}
+
+void
+meta_wayland_subsurfaces_init (MetaWaylandCompositor *compositor)
+{
+  if (wl_global_create (compositor->wayland_display,
+                        &wl_subcompositor_interface,
+                        META_WL_SUBCOMPOSITOR_VERSION,
+                        compositor, bind_subcompositor) == NULL)
+    g_error ("Failed to register a global wl-subcompositor object");
+}
diff --git a/src/wayland/meta-wayland-subsurface.h b/src/wayland/meta-wayland-subsurface.h
new file mode 100644
index 000000000..eac3c6c7b
--- /dev/null
+++ b/src/wayland/meta-wayland-subsurface.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012,2013 Intel Corporation
+ * Copyright (C) 2013-2017 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.
+ */
+
+#ifndef META_WAYLAND_SUBSURFACE_H
+#define META_WAYLAND_SUBSURFACE_H
+
+#include "wayland/meta-wayland-actor-surface.h"
+
+#define META_TYPE_WAYLAND_SUBSURFACE (meta_wayland_subsurface_get_type ())
+G_DECLARE_FINAL_TYPE (MetaWaylandSubsurface,
+                      meta_wayland_subsurface,
+                      META, WAYLAND_SUBSURFACE,
+                      MetaWaylandActorSurface)
+
+void meta_wayland_subsurface_parent_state_applied (MetaWaylandSubsurface *subsurface);
+
+void meta_wayland_subsurfaces_init (MetaWaylandCompositor *compositor);
+
+#endif /* META_WAYLAND_SUBSURFACE_H */
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index 7731d9926..301992627 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -2,7 +2,7 @@
  * Wayland Support
  *
  * Copyright (C) 2012,2013 Intel Corporation
- *               2013 Red Hat, Inc.
+ * Copyright (C) 2013-2017 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
@@ -36,6 +36,7 @@
 #include "meta-xwayland-private.h"
 #include "meta-wayland-buffer.h"
 #include "meta-wayland-region.h"
+#include "meta-wayland-subsurface.h"
 #include "meta-wayland-seat.h"
 #include "meta-wayland-keyboard.h"
 #include "meta-wayland-pointer.h"
@@ -77,46 +78,16 @@ typedef struct _MetaWaylandSurfaceRolePrivate
   MetaWaylandSurface *surface;
 } MetaWaylandSurfaceRolePrivate;
 
-typedef enum
-{
-  META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE,
-  META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW
-} MetaWaylandSubsurfacePlacement;
-
-typedef struct
-{
-  MetaWaylandSubsurfacePlacement placement;
-  MetaWaylandSurface *sibling;
-  struct wl_listener sibling_destroy_listener;
-} MetaWaylandSubsurfacePlacementOp;
-
 G_DEFINE_TYPE (MetaWaylandSurface, meta_wayland_surface, G_TYPE_OBJECT);
 
 G_DEFINE_TYPE_WITH_PRIVATE (MetaWaylandSurfaceRole,
                             meta_wayland_surface_role,
                             G_TYPE_OBJECT);
 
-G_DEFINE_TYPE (MetaWaylandSurfaceRoleActorSurface,
-               meta_wayland_surface_role_actor_surface,
-               META_TYPE_WAYLAND_SURFACE_ROLE);
-
-G_DEFINE_TYPE (MetaWaylandShellSurface,
-               meta_wayland_shell_surface,
-               META_TYPE_WAYLAND_SURFACE_ROLE_ACTOR_SURFACE);
-
 G_DEFINE_TYPE (MetaWaylandPendingState,
                meta_wayland_pending_state,
                G_TYPE_OBJECT);
 
-struct _MetaWaylandSurfaceRoleSubsurface
-{
-  MetaWaylandSurfaceRoleActorSurface parent;
-};
-
-G_DEFINE_TYPE (MetaWaylandSurfaceRoleSubsurface,
-               meta_wayland_surface_role_subsurface,
-               META_TYPE_WAYLAND_SURFACE_ROLE_ACTOR_SURFACE);
-
 struct _MetaWaylandSurfaceRoleDND
 {
   MetaWaylandSurfaceRole parent;
@@ -155,25 +126,6 @@ meta_wayland_surface_role_is_on_logical_monitor (MetaWaylandSurfaceRole *surface
 static MetaWaylandSurface *
 meta_wayland_surface_role_get_toplevel (MetaWaylandSurfaceRole *surface_role);
 
-static void
-meta_wayland_shell_surface_configure (MetaWaylandShellSurface *shell_surface,
-                                      int                      new_x,
-                                      int                      new_y,
-                                      int                      new_width,
-                                      int                      new_height,
-                                      MetaWaylandSerial       *sent_serial);
-
-static void
-meta_wayland_shell_surface_ping (MetaWaylandShellSurface *shell_surface,
-                                 uint32_t                 serial);
-
-static void
-meta_wayland_shell_surface_close (MetaWaylandShellSurface *shell_surface);
-
-static void
-meta_wayland_shell_surface_managed (MetaWaylandShellSurface *shell_surface,
-                                    MetaWindow              *window);
-
 static void
 surface_actor_mapped_notify (MetaSurfaceActorWayland *surface_actor,
                              GParamSpec              *pspec,
@@ -465,18 +417,6 @@ meta_wayland_surface_unref_buffer_use_count (MetaWaylandSurface *surface)
     wl_buffer_send_release (buffer->resource);
 }
 
-static void
-queue_surface_actor_frame_callbacks (MetaWaylandSurface      *surface,
-                                     MetaWaylandPendingState *pending)
-{
-  MetaSurfaceActorWayland *surface_actor =
-    META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
-
-  meta_surface_actor_wayland_add_frame_callbacks (surface_actor,
-                                                  &pending->frame_callback_list);
-  wl_list_init (&pending->frame_callback_list);
-}
-
 static void
 pending_buffer_resource_destroyed (MetaWaylandBuffer       *buffer,
                                    MetaWaylandPendingState *pending)
@@ -605,45 +545,12 @@ meta_wayland_pending_state_class_init (MetaWaylandPendingStateClass *klass)
                   G_TYPE_NONE, 0);
 }
 
-static void
-subsurface_role_commit (MetaWaylandSurfaceRole  *surface_role,
-                        MetaWaylandPendingState *pending)
-{
-  MetaWaylandSurfaceRoleClass *surface_role_class;
-  MetaWaylandSurface *surface =
-    meta_wayland_surface_role_get_surface (surface_role);
-  MetaSurfaceActorWayland *surface_actor =
-    META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
-
-  surface_role_class =
-    META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_surface_role_subsurface_parent_class);
-  surface_role_class->commit (surface_role, pending);
-
-  if (surface->buffer_ref.buffer != NULL)
-    clutter_actor_show (CLUTTER_ACTOR (surface_actor));
-  else
-    clutter_actor_hide (CLUTTER_ACTOR (surface_actor));
-}
-
-static MetaWaylandSurface *
-subsurface_role_get_toplevel (MetaWaylandSurfaceRole *surface_role)
-{
-  MetaWaylandSurface *surface =
-    meta_wayland_surface_role_get_surface (surface_role);
-  MetaWaylandSurface *parent = surface->sub.parent;
-
-  if (parent && parent->role)
-    return meta_wayland_surface_role_get_toplevel (parent->role);
-  else
-    return NULL;
-}
-
 /* A non-subsurface is always desynchronized.
  *
  * A subsurface is effectively synchronized if either its parent is
  * synchronized or itself is in synchronized mode. */
-static gboolean
-is_surface_effectively_synchronized (MetaWaylandSurface *surface)
+gboolean
+meta_wayland_surface_is_effectively_synchronized (MetaWaylandSurface *surface)
 {
   if (surface->wl_subsurface == NULL)
     {
@@ -652,81 +559,31 @@ is_surface_effectively_synchronized (MetaWaylandSurface *surface)
   else
     {
       if (surface->sub.synchronous)
-        return TRUE;
+        {
+          return TRUE;
+        }
       else
-        return is_surface_effectively_synchronized (surface->sub.parent);
+        {
+          MetaWaylandSurface *parent = surface->sub.parent;
+
+          return meta_wayland_surface_is_effectively_synchronized (parent);
+        }
     }
 }
 
 static void
-apply_pending_state (MetaWaylandSurface      *surface,
-                     MetaWaylandPendingState *pending);
-
-static void
-parent_surface_state_applied (gpointer data, gpointer user_data)
+parent_surface_state_applied (gpointer data,
+                              gpointer user_data)
 {
   MetaWaylandSurface *surface = data;
+  MetaWaylandSubsurface *subsurface = META_WAYLAND_SUBSURFACE (surface->role);
 
-  if (surface->sub.pending_pos)
-    {
-      surface->sub.x = surface->sub.pending_x;
-      surface->sub.y = surface->sub.pending_y;
-      surface->sub.pending_pos = FALSE;
-    }
-
-  if (surface->sub.pending_placement_ops)
-    {
-      GSList *it;
-      MetaWaylandSurface *parent = surface->sub.parent;
-      ClutterActor *parent_actor =
-        clutter_actor_get_parent (CLUTTER_ACTOR (parent->surface_actor));
-      ClutterActor *surface_actor = CLUTTER_ACTOR (surface->surface_actor);
-
-      for (it = surface->sub.pending_placement_ops; it; it = it->next)
-        {
-          MetaWaylandSubsurfacePlacementOp *op = it->data;
-          ClutterActor *sibling_actor;
-
-          if (!op->sibling)
-            {
-              g_slice_free (MetaWaylandSubsurfacePlacementOp, op);
-              continue;
-            }
-
-          sibling_actor = CLUTTER_ACTOR (op->sibling->surface_actor);
-
-          switch (op->placement)
-            {
-            case META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE:
-              clutter_actor_set_child_above_sibling (parent_actor,
-                                                     surface_actor,
-                                                     sibling_actor);
-              break;
-            case META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW:
-              clutter_actor_set_child_below_sibling (parent_actor,
-                                                     surface_actor,
-                                                     sibling_actor);
-              break;
-            }
-
-          wl_list_remove (&op->sibling_destroy_listener.link);
-          g_slice_free (MetaWaylandSubsurfacePlacementOp, op);
-        }
-
-      g_slist_free (surface->sub.pending_placement_ops);
-      surface->sub.pending_placement_ops = NULL;
-    }
-
-  if (is_surface_effectively_synchronized (surface))
-    apply_pending_state (surface, surface->sub.pending);
-
-  meta_surface_actor_wayland_sync_subsurface_state (
-    META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
+  meta_wayland_subsurface_parent_state_applied (subsurface);
 }
 
-static void
-apply_pending_state (MetaWaylandSurface      *surface,
-                     MetaWaylandPendingState *pending)
+void
+meta_wayland_surface_apply_pending_state (MetaWaylandSurface      *surface,
+                                          MetaWaylandPendingState *pending)
 {
   if (surface->role)
     {
@@ -892,10 +749,10 @@ meta_wayland_surface_commit (MetaWaylandSurface *surface)
    *  2) Its mode changes from synchronized to desynchronized and its parent
    *     surface is in effective desynchronized mode.
    */
-  if (is_surface_effectively_synchronized (surface))
+  if (meta_wayland_surface_is_effectively_synchronized (surface))
     move_pending_state (surface->pending, surface->sub.pending);
   else
-    apply_pending_state (surface, surface->pending);
+    meta_wayland_surface_apply_pending_state (surface, surface->pending);
 }
 
 static void
@@ -1110,27 +967,6 @@ static const struct wl_surface_interface meta_wayland_wl_surface_interface = {
   wl_surface_damage_buffer,
 };
 
-static gboolean
-surface_should_be_reactive (MetaWaylandSurface *surface)
-{
-  /* If we have a toplevel window, we should be reactive */
-  if (surface->window)
-    return TRUE;
-
-  /* If we're a subsurface, we should be reactive */
-  if (surface->wl_subsurface)
-    return TRUE;
-
-  return FALSE;
-}
-
-static void
-sync_reactive (MetaWaylandSurface *surface)
-{
-  clutter_actor_set_reactive (CLUTTER_ACTOR (surface->surface_actor),
-                              surface_should_be_reactive (surface));
-}
-
 static void
 sync_drag_dest_funcs (MetaWaylandSurface *surface)
 {
@@ -1220,18 +1056,6 @@ set_surface_is_on_output (MetaWaylandSurface *surface,
     }
 }
 
-static gboolean
-actor_surface_is_on_logical_monitor (MetaWaylandSurfaceRole *surface_role,
-                                     MetaLogicalMonitor     *logical_monitor)
-{
-  MetaWaylandSurface *surface =
-    meta_wayland_surface_role_get_surface (surface_role);
-  MetaSurfaceActorWayland *actor =
-    META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
-
-  return meta_surface_actor_wayland_is_on_monitor (actor, logical_monitor);
-}
-
 static void
 update_surface_output_state (gpointer key, gpointer value, gpointer user_data)
 {
@@ -1300,7 +1124,8 @@ meta_wayland_surface_set_window (MetaWaylandSurface *surface,
     }
 
   surface->window = window;
-  sync_reactive (surface);
+
+  clutter_actor_set_reactive (CLUTTER_ACTOR (surface->surface_actor), !!window);
   sync_drag_dest_funcs (surface);
 
   if (was_unmapped)
@@ -1479,263 +1304,12 @@ meta_wayland_surface_begin_grab_op (MetaWaylandSurface *surface,
                                      x, y);
 }
 
-static void
-unparent_actor (MetaWaylandSurface *surface)
-{
-  ClutterActor *parent_actor;
-  parent_actor = clutter_actor_get_parent (CLUTTER_ACTOR (surface->surface_actor));
-  clutter_actor_remove_child (parent_actor, CLUTTER_ACTOR (surface->surface_actor));
-}
-
-static void
-wl_subsurface_destructor (struct wl_resource *resource)
-{
-  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
-
-  meta_wayland_compositor_destroy_frame_callbacks (surface->compositor,
-                                                   surface);
-  if (surface->sub.parent)
-    {
-      wl_list_remove (&surface->sub.parent_destroy_listener.link);
-      surface->sub.parent->subsurfaces =
-        g_list_remove (surface->sub.parent->subsurfaces, surface);
-      unparent_actor (surface);
-      surface->sub.parent = NULL;
-    }
-
-  g_clear_object (&surface->sub.pending);
-  surface->wl_subsurface = NULL;
-}
-
-static void
-wl_subsurface_destroy (struct wl_client *client,
-                       struct wl_resource *resource)
-{
-  wl_resource_destroy (resource);
-}
-
-static void
-wl_subsurface_set_position (struct wl_client *client,
-                            struct wl_resource *resource,
-                            int32_t x,
-                            int32_t y)
-{
-  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
-
-  surface->sub.pending_x = x;
-  surface->sub.pending_y = y;
-  surface->sub.pending_pos = TRUE;
-}
-
-static gboolean
-is_valid_sibling (MetaWaylandSurface *surface, MetaWaylandSurface *sibling)
-{
-  if (surface->sub.parent == sibling)
-    return TRUE;
-  if (surface->sub.parent == sibling->sub.parent)
-    return TRUE;
-  return FALSE;
-}
-
-static void
-subsurface_handle_pending_sibling_destroyed (struct wl_listener *listener, void *data)
-{
-  MetaWaylandSubsurfacePlacementOp *op =
-    wl_container_of (listener, op, sibling_destroy_listener);
-
-  op->sibling = NULL;
-}
-
-static void
-queue_subsurface_placement (MetaWaylandSurface *surface,
-                            MetaWaylandSurface *sibling,
-                            MetaWaylandSubsurfacePlacement placement)
-{
-  MetaWaylandSubsurfacePlacementOp *op =
-    g_slice_new (MetaWaylandSubsurfacePlacementOp);
-
-  op->placement = placement;
-  op->sibling = sibling;
-  op->sibling_destroy_listener.notify =
-    subsurface_handle_pending_sibling_destroyed;
-  wl_resource_add_destroy_listener (sibling->resource,
-                                    &op->sibling_destroy_listener);
-
-  surface->sub.pending_placement_ops =
-    g_slist_append (surface->sub.pending_placement_ops, op);
-}
-
-static void
-wl_subsurface_place_above (struct wl_client *client,
-                           struct wl_resource *resource,
-                           struct wl_resource *sibling_resource)
-{
-  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
-  MetaWaylandSurface *sibling = wl_resource_get_user_data (sibling_resource);
-
-  if (!is_valid_sibling (surface, sibling))
-    {
-      wl_resource_post_error (resource, WL_SUBSURFACE_ERROR_BAD_SURFACE,
-                              "wl_subsurface::place_above: wl_surface@%d is "
-                              "not a valid parent or sibling",
-                              wl_resource_get_id (sibling->resource));
-      return;
-    }
-
-  queue_subsurface_placement (surface,
-                              sibling,
-                              META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE);
-}
-
-static void
-wl_subsurface_place_below (struct wl_client *client,
-                           struct wl_resource *resource,
-                           struct wl_resource *sibling_resource)
-{
-  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
-  MetaWaylandSurface *sibling = wl_resource_get_user_data (sibling_resource);
-
-  if (!is_valid_sibling (surface, sibling))
-    {
-      wl_resource_post_error (resource, WL_SUBSURFACE_ERROR_BAD_SURFACE,
-                              "wl_subsurface::place_below: wl_surface@%d is "
-                              "not a valid parent or sibling",
-                              wl_resource_get_id (sibling->resource));
-      return;
-    }
-
-  queue_subsurface_placement (surface,
-                              sibling,
-                              META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW);
-}
-
-static void
-wl_subsurface_set_sync (struct wl_client *client,
-                        struct wl_resource *resource)
-{
-  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
-
-  surface->sub.synchronous = TRUE;
-}
-
-static void
-wl_subsurface_set_desync (struct wl_client *client,
-                          struct wl_resource *resource)
-{
-  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
-  gboolean was_effectively_synchronized;
-
-  was_effectively_synchronized = is_surface_effectively_synchronized (surface);
-  surface->sub.synchronous = FALSE;
-  if (was_effectively_synchronized &&
-      !is_surface_effectively_synchronized (surface))
-    apply_pending_state (surface, surface->sub.pending);
-}
-
-static const struct wl_subsurface_interface meta_wayland_wl_subsurface_interface = {
-  wl_subsurface_destroy,
-  wl_subsurface_set_position,
-  wl_subsurface_place_above,
-  wl_subsurface_place_below,
-  wl_subsurface_set_sync,
-  wl_subsurface_set_desync,
-};
-
-static void
-wl_subcompositor_destroy (struct wl_client *client,
-                          struct wl_resource *resource)
-{
-  wl_resource_destroy (resource);
-}
-
-static void
-surface_handle_parent_surface_destroyed (struct wl_listener *listener,
-                                         void *data)
-{
-  MetaWaylandSurface *surface = wl_container_of (listener,
-                                                 surface,
-                                                 sub.parent_destroy_listener);
-
-  surface->sub.parent = NULL;
-  unparent_actor (surface);
-}
-
-static void
-wl_subcompositor_get_subsurface (struct wl_client *client,
-                                 struct wl_resource *resource,
-                                 guint32 id,
-                                 struct wl_resource *surface_resource,
-                                 struct wl_resource *parent_resource)
-{
-  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
-  MetaWaylandSurface *parent = wl_resource_get_user_data (parent_resource);
-
-  if (surface->wl_subsurface != NULL)
-    {
-      wl_resource_post_error (surface_resource,
-                              WL_DISPLAY_ERROR_INVALID_OBJECT,
-                              "wl_subcompositor::get_subsurface already requested");
-      return;
-    }
-
-  if (!meta_wayland_surface_assign_role (surface,
-                                         META_TYPE_WAYLAND_SURFACE_ROLE_SUBSURFACE,
-                                         NULL))
-    {
-      /* FIXME: There is no subcompositor "role" error yet, so lets just use something
-       * similar until there is.
-       */
-      wl_resource_post_error (resource, WL_SHELL_ERROR_ROLE,
-                              "wl_surface@%d already has a different role",
-                              wl_resource_get_id (surface->resource));
-      return;
-    }
-
-  surface->wl_subsurface = wl_resource_create (client, &wl_subsurface_interface, wl_resource_get_version 
(resource), id);
-  wl_resource_set_implementation (surface->wl_subsurface, &meta_wayland_wl_subsurface_interface, surface, 
wl_subsurface_destructor);
-
-  surface->sub.pending = g_object_new (META_TYPE_WAYLAND_PENDING_STATE, NULL);
-  surface->sub.synchronous = TRUE;
-  surface->sub.parent = parent;
-  surface->sub.parent_destroy_listener.notify = surface_handle_parent_surface_destroyed;
-  wl_resource_add_destroy_listener (parent->resource, &surface->sub.parent_destroy_listener);
-  parent->subsurfaces = g_list_append (parent->subsurfaces, surface);
-
-  clutter_actor_add_child (CLUTTER_ACTOR (parent->surface_actor),
-                           CLUTTER_ACTOR (surface->surface_actor));
-
-  sync_reactive (surface);
-}
-
-static const struct wl_subcompositor_interface meta_wayland_subcompositor_interface = {
-  wl_subcompositor_destroy,
-  wl_subcompositor_get_subsurface,
-};
-
-static void
-bind_subcompositor (struct wl_client *client,
-                    void             *data,
-                    guint32           version,
-                    guint32           id)
-{
-  struct wl_resource *resource;
-
-  resource = wl_resource_create (client, &wl_subcompositor_interface, version, id);
-  wl_resource_set_implementation (resource, &meta_wayland_subcompositor_interface, data, NULL);
-}
-
 void
 meta_wayland_shell_init (MetaWaylandCompositor *compositor)
 {
   meta_wayland_xdg_shell_init (compositor);
   meta_wayland_wl_shell_init (compositor);
   meta_wayland_gtk_shell_init (compositor);
-
-  if (wl_global_create (compositor->wayland_display,
-                        &wl_subcompositor_interface,
-                        META_WL_SUBCOMPOSITOR_VERSION,
-                        compositor, bind_subcompositor) == NULL)
-    g_error ("Failed to register a global wl-subcompositor object");
 }
 
 void
@@ -2087,54 +1661,6 @@ meta_wayland_surface_role_get_surface (MetaWaylandSurfaceRole *role)
   return priv->surface;
 }
 
-static void
-meta_wayland_shell_surface_configure (MetaWaylandShellSurface *shell_surface,
-                                      int                      new_x,
-                                      int                      new_y,
-                                      int                      new_width,
-                                      int                      new_height,
-                                      MetaWaylandSerial       *sent_serial)
-{
-  MetaWaylandShellSurfaceClass *shell_surface_class =
-    META_WAYLAND_SHELL_SURFACE_GET_CLASS (shell_surface);
-
-  shell_surface_class->configure (shell_surface,
-                                  new_x,
-                                  new_y,
-                                  new_width,
-                                  new_height,
-                                  sent_serial);
-}
-
-static void
-meta_wayland_shell_surface_ping (MetaWaylandShellSurface *shell_surface,
-                                 uint32_t                 serial)
-{
-  MetaWaylandShellSurfaceClass *shell_surface_class =
-    META_WAYLAND_SHELL_SURFACE_GET_CLASS (shell_surface);
-
-  shell_surface_class->ping (shell_surface, serial);
-}
-
-static void
-meta_wayland_shell_surface_close (MetaWaylandShellSurface *shell_surface)
-{
-  MetaWaylandShellSurfaceClass *shell_surface_class =
-    META_WAYLAND_SHELL_SURFACE_GET_CLASS (shell_surface);
-
-  shell_surface_class->close (shell_surface);
-}
-
-static void
-meta_wayland_shell_surface_managed (MetaWaylandShellSurface *shell_surface,
-                                    MetaWindow              *window)
-{
-  MetaWaylandShellSurfaceClass *shell_surface_class =
-    META_WAYLAND_SHELL_SURFACE_GET_CLASS (shell_surface);
-
-  shell_surface_class->managed (shell_surface, window);
-}
-
 void
 meta_wayland_surface_queue_pending_frame_callbacks (MetaWaylandSurface *surface)
 {
@@ -2152,100 +1678,6 @@ default_role_assigned (MetaWaylandSurfaceRole *surface_role)
   meta_wayland_surface_queue_pending_frame_callbacks (surface);
 }
 
-static void
-actor_surface_assigned (MetaWaylandSurfaceRole *surface_role)
-{
-  MetaWaylandSurface *surface =
-    meta_wayland_surface_role_get_surface (surface_role);
-  MetaSurfaceActorWayland *surface_actor =
-    META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
-
-  meta_surface_actor_wayland_add_frame_callbacks (surface_actor,
-                                                  &surface->pending_frame_callback_list);
-  wl_list_init (&surface->pending_frame_callback_list);
-}
-
-static void
-actor_surface_commit (MetaWaylandSurfaceRole  *surface_role,
-                      MetaWaylandPendingState *pending)
-{
-  MetaWaylandSurface *surface =
-    meta_wayland_surface_role_get_surface (surface_role);
-  MetaWaylandSurface *toplevel_surface;
-
-  queue_surface_actor_frame_callbacks (surface, pending);
-
-  toplevel_surface = meta_wayland_surface_get_toplevel (surface);
-  if (!toplevel_surface || !toplevel_surface->window)
-    return;
-
-  meta_surface_actor_wayland_sync_state (
-    META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
-}
-
-static void
-meta_wayland_surface_role_actor_surface_init (MetaWaylandSurfaceRoleActorSurface *role)
-{
-}
-
-static void
-meta_wayland_surface_role_actor_surface_class_init (MetaWaylandSurfaceRoleActorSurfaceClass *klass)
-{
-  MetaWaylandSurfaceRoleClass *surface_role_class =
-    META_WAYLAND_SURFACE_ROLE_CLASS (klass);
-
-  surface_role_class->assigned = actor_surface_assigned;
-  surface_role_class->commit = actor_surface_commit;
-  surface_role_class->is_on_logical_monitor = actor_surface_is_on_logical_monitor;
-}
-
-static void
-meta_wayland_shell_surface_surface_commit (MetaWaylandSurfaceRole  *surface_role,
-                                           MetaWaylandPendingState *pending)
-{
-  MetaWaylandSurface *surface =
-    meta_wayland_surface_role_get_surface (surface_role);
-  MetaWaylandSurfaceRoleClass *surface_role_class;
-  MetaWindow *window;
-  MetaWaylandBuffer *buffer;
-  CoglTexture *texture;
-  MetaSurfaceActorWayland *actor;
-  double scale;
-
-  surface_role_class =
-    META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_shell_surface_parent_class);
-  surface_role_class->commit (surface_role, pending);
-
-  buffer = surface->buffer_ref.buffer;
-  if (!buffer)
-    return;
-
-  window = surface->window;
-  if (!window)
-    return;
-
-  actor = META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
-  scale = meta_surface_actor_wayland_get_scale (actor);
-  texture = buffer->texture;
-
-  window->buffer_rect.width = cogl_texture_get_width (texture) * scale;
-  window->buffer_rect.height = cogl_texture_get_height (texture) * scale;
-}
-
-static void
-meta_wayland_shell_surface_init (MetaWaylandShellSurface *role)
-{
-}
-
-static void
-meta_wayland_shell_surface_class_init (MetaWaylandShellSurfaceClass *klass)
-{
-  MetaWaylandSurfaceRoleClass *surface_role_class =
-    META_WAYLAND_SURFACE_ROLE_CLASS (klass);
-
-  surface_role_class->commit = meta_wayland_shell_surface_surface_commit;
-}
-
 static void
 meta_wayland_surface_role_dnd_init (MetaWaylandSurfaceRoleDND *role)
 {
@@ -2261,21 +1693,6 @@ meta_wayland_surface_role_dnd_class_init (MetaWaylandSurfaceRoleDNDClass *klass)
   surface_role_class->commit = dnd_surface_commit;
 }
 
-static void
-meta_wayland_surface_role_subsurface_init (MetaWaylandSurfaceRoleSubsurface *role)
-{
-}
-
-static void
-meta_wayland_surface_role_subsurface_class_init (MetaWaylandSurfaceRoleSubsurfaceClass *klass)
-{
-  MetaWaylandSurfaceRoleClass *surface_role_class =
-    META_WAYLAND_SURFACE_ROLE_CLASS (klass);
-
-  surface_role_class->commit = subsurface_role_commit;
-  surface_role_class->get_toplevel = subsurface_role_get_toplevel;
-}
-
 cairo_region_t *
 meta_wayland_surface_calculate_input_region (MetaWaylandSurface *surface)
 {
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index 026aeb2a0..92e385030 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -70,46 +70,6 @@ struct _MetaWaylandSerial {
   uint32_t value;
 };
 
-#define META_TYPE_WAYLAND_SURFACE_ROLE_ACTOR_SURFACE (meta_wayland_surface_role_actor_surface_get_type ())
-G_DECLARE_DERIVABLE_TYPE (MetaWaylandSurfaceRoleActorSurface,
-                          meta_wayland_surface_role_actor_surface,
-                          META, WAYLAND_SURFACE_ROLE_ACTOR_SURFACE,
-                          MetaWaylandSurfaceRole);
-
-struct _MetaWaylandSurfaceRoleActorSurfaceClass
-{
-  MetaWaylandSurfaceRoleClass parent_class;
-};
-
-#define META_TYPE_WAYLAND_SHELL_SURFACE (meta_wayland_shell_surface_get_type ())
-G_DECLARE_DERIVABLE_TYPE (MetaWaylandShellSurface,
-                          meta_wayland_shell_surface,
-                          META, WAYLAND_SHELL_SURFACE,
-                          MetaWaylandSurfaceRoleActorSurface);
-
-struct _MetaWaylandShellSurfaceClass
-{
-  MetaWaylandSurfaceRoleActorSurfaceClass parent_class;
-
-  void (*configure) (MetaWaylandShellSurface *shell_surface,
-                     int                      new_x,
-                     int                      new_y,
-                     int                      new_width,
-                     int                      new_height,
-                     MetaWaylandSerial       *sent_serial);
-  void (*managed) (MetaWaylandShellSurface *shell_surface,
-                   MetaWindow              *window);
-  void (*ping) (MetaWaylandShellSurface *shell_surface,
-                uint32_t                 serial);
-  void (*close) (MetaWaylandShellSurface *shell_surface);
-};
-
-#define META_TYPE_WAYLAND_SURFACE_ROLE_SUBSURFACE (meta_wayland_surface_role_subsurface_get_type ())
-G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleSubsurface,
-                      meta_wayland_surface_role_subsurface,
-                      META, WAYLAND_SURFACE_ROLE_SUBSURFACE,
-                      MetaWaylandSurfaceRoleActorSurface);
-
 #define META_TYPE_WAYLAND_SURFACE_ROLE_DND (meta_wayland_surface_role_dnd_get_type ())
 G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleDND,
                       meta_wayland_surface_role_dnd,
@@ -252,6 +212,11 @@ MetaWaylandSurface *meta_wayland_surface_create (MetaWaylandCompositor *composit
                                                  struct wl_resource    *compositor_resource,
                                                  guint32                id);
 
+void                meta_wayland_surface_apply_pending_state (MetaWaylandSurface      *surface,
+                                                              MetaWaylandPendingState *pending);
+
+gboolean            meta_wayland_surface_is_effectively_synchronized (MetaWaylandSurface *surface);
+
 gboolean            meta_wayland_surface_assign_role (MetaWaylandSurface *surface,
                                                       GType               role_type,
                                                       const char         *first_property_name,
diff --git a/src/wayland/meta-wayland-wl-shell.h b/src/wayland/meta-wayland-wl-shell.h
index fab997285..4a62d8a72 100644
--- a/src/wayland/meta-wayland-wl-shell.h
+++ b/src/wayland/meta-wayland-wl-shell.h
@@ -20,7 +20,7 @@
 #ifndef META_WAYLAND_WL_SHELL_H
 #define META_WAYLAND_WL_SHELL_H
 
-#include "wayland/meta-wayland-surface.h"
+#include "wayland/meta-wayland-shell-surface.h"
 
 #define META_TYPE_WAYLAND_WL_SHELL_SURFACE (meta_wayland_wl_shell_surface_get_type ())
 G_DECLARE_FINAL_TYPE (MetaWaylandWlShellSurface,
diff --git a/src/wayland/meta-wayland-xdg-shell.h b/src/wayland/meta-wayland-xdg-shell.h
index 4d56eb24a..aa36a94c2 100644
--- a/src/wayland/meta-wayland-xdg-shell.h
+++ b/src/wayland/meta-wayland-xdg-shell.h
@@ -20,7 +20,7 @@
 #ifndef META_WAYLAND_XDG_SHELL_H
 #define META_WAYLAND_XDG_SHELL_H
 
-#include "wayland/meta-wayland-surface.h"
+#include "wayland/meta-wayland-shell-surface.h"
 
 #define META_TYPE_WAYLAND_XDG_SURFACE (meta_wayland_xdg_surface_get_type ())
 G_DECLARE_DERIVABLE_TYPE (MetaWaylandXdgSurface,
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 6cd7d3c7c..bab6b4ac4 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -39,6 +39,7 @@
 #include "meta-wayland-seat.h"
 #include "meta-wayland-outputs.h"
 #include "meta-wayland-data-device.h"
+#include "meta-wayland-subsurface.h"
 #include "meta-wayland-tablet-manager.h"
 #include "meta-wayland-xdg-foreign.h"
 #include "meta-wayland-dma-buf.h"
@@ -374,6 +375,7 @@ meta_wayland_init (void)
 
   meta_wayland_outputs_init (compositor);
   meta_wayland_data_device_manager_init (compositor);
+  meta_wayland_subsurfaces_init (compositor);
   meta_wayland_shell_init (compositor);
   meta_wayland_pointer_gestures_init (compositor);
   meta_wayland_tablet_manager_init (compositor);


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