[mutter/wip/wayland-work: 17/25] wayland: implement resizing and maximization for wayland clients



commit 93cde06f2fb870be627e42a7b0f89b89b95e2835
Author: Giovanni Campagna <gcampagn redhat com>
Date:   Tue Sep 3 12:00:29 2013 +0200

    wayland: implement resizing and maximization for wayland clients
    
    To properly resize clients, we need to send them configure events
    with the size we computed from the constraint system.
    Also, once the sizing is properly wired up, we need to make
    sure that the size at the initial map is correct, and not
    always 0, 0 (because the buffer is not yet converted into
    a CoglTexture by MetaShapedTexture), otherwise we end up sending
    out configure events at 1 x 1. To do so, we cache the surface
    type in the initial state until the first commit.
    
    Note that this does not handle interactive resizing yet, it
    merely makes the API calls work for wayland clients.
    
    While we're there, let's implement transient hints too.
    (I may have to separate this out...)
    
    https://bugzilla.gnome.org/show_bug.cgi?id=707401

 configure.ac                         |    2 +-
 src/compositor/meta-shaped-texture.c |   23 +-
 src/core/constraints.h               |    3 +-
 src/core/window-private.h            |   15 +
 src/core/window-props.c              |   47 +--
 src/core/window.c                    |  742 +++++++++++++++++++++-------------
 src/wayland/meta-wayland-surface.c   |  254 ++++++++----
 src/wayland/meta-wayland-surface.h   |   40 ++-
 src/wayland/meta-wayland.c           |    5 +-
 src/wayland/meta-xwayland.c          |    4 -
 10 files changed, 687 insertions(+), 448 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index efd8fb8..432f74c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@ AC_PREREQ(2.50)
 
 m4_define([mutter_major_version], [3])
 m4_define([mutter_minor_version], [9])
-m4_define([mutter_micro_version], [90])
+m4_define([mutter_micro_version], [91])
 
 m4_define([mutter_version],
           [mutter_major_version.mutter_minor_version.mutter_micro_version])
diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c
index 2dc75f8..0928a2f 100644
--- a/src/compositor/meta-shaped-texture.c
+++ b/src/compositor/meta-shaped-texture.c
@@ -236,7 +236,7 @@ set_cogl_texture (MetaShapedTexture *stex,
   if (priv->texture)
     cogl_object_unref (priv->texture);
 
-  priv->texture = cogl_tex;
+  priv->texture = cogl_object_ref (cogl_tex);
 
   if (cogl_tex != NULL)
     {
@@ -870,26 +870,7 @@ meta_shaped_texture_attach_wayland_buffer (MetaShapedTexture  *stex,
   g_return_if_fail (priv->wayland.surface->buffer_ref.buffer == buffer);
 
   if (buffer)
-    {
-      CoglContext *ctx =
-        clutter_backend_get_cogl_context (clutter_get_default_backend ());
-      CoglError *catch_error = NULL;
-      CoglTexture *texture =
-        COGL_TEXTURE (cogl_wayland_texture_2d_new_from_buffer (ctx,
-                                                               buffer->resource,
-                                                               &catch_error));
-      if (!texture)
-        {
-          cogl_error_free (catch_error);
-        }
-      else
-        {
-          buffer->width = cogl_texture_get_width (texture);
-          buffer->height = cogl_texture_get_height (texture);
-        }
-
-      set_cogl_texture (stex, texture);
-    }
+    set_cogl_texture (stex, buffer->texture);
   else
     set_cogl_texture (stex, NULL);
 
diff --git a/src/core/constraints.h b/src/core/constraints.h
index 5fa1e4e..0bea43d 100644
--- a/src/core/constraints.h
+++ b/src/core/constraints.h
@@ -35,7 +35,8 @@ typedef enum
   META_DO_GRAVITY_ADJUST    = 1 << 1,
   META_IS_USER_ACTION       = 1 << 2,
   META_IS_MOVE_ACTION       = 1 << 3,
-  META_IS_RESIZE_ACTION     = 1 << 4
+  META_IS_RESIZE_ACTION     = 1 << 4,
+  META_IS_WAYLAND_RESIZE    = 1 << 5
 } MetaMoveResizeFlags;
 
 void meta_window_constrain (MetaWindow          *window,
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 3ca2b0a..9504bca 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -127,6 +127,7 @@ struct _MetaWindow
   Window xtransient_for;
   Window xgroup_leader;
   Window xclient_leader;
+  MetaWindow *transient_for;
 
   /* Initial workspace property */
   int initial_workspace;  
@@ -403,6 +404,12 @@ struct _MetaWindow
    */
   MetaRectangle rect;
 
+  /* The size we want the window to be (i.e. what we last asked
+   * the client to configure).
+   * This is only used for wayland clients.
+   */
+  MetaRectangle expected_rect;
+
   gboolean has_custom_frame_extents;
   GtkBorder custom_frame_extents;
 
@@ -600,6 +607,11 @@ void     meta_window_move_resize_request(MetaWindow *window,
                                          int         y,
                                          int         width,
                                          int         height);
+void     meta_window_move_resize_wayland (MetaWindow *window,
+                                          int         width,
+                                          int         height,
+                                          int         dx,
+                                          int         dy);
 gboolean meta_window_configure_request (MetaWindow *window,
                                         XEvent     *event);
 gboolean meta_window_property_notify   (MetaWindow *window,
@@ -716,4 +728,7 @@ void meta_window_set_gtk_dbus_properties  (MetaWindow *window,
                                            const char *application_object_path,
                                            const char *window_object_path);
 
+void meta_window_set_transient_for        (MetaWindow *window,
+                                           MetaWindow *parent);
+
 #endif
diff --git a/src/core/window-props.c b/src/core/window-props.c
index 73452cc..1ac5239 100644
--- a/src/core/window-props.c
+++ b/src/core/window-props.c
@@ -1554,9 +1554,6 @@ reload_transient_for (MetaWindow    *window,
   if (transient_for == window->xtransient_for)
     return;
 
-  if (meta_window_appears_focused (window) && window->xtransient_for != None)
-    meta_window_propagate_focus_appearance (window, FALSE);
-
   old_transient_for = window->xtransient_for;
   window->xtransient_for = transient_for;
 
@@ -1569,46 +1566,14 @@ reload_transient_for (MetaWindow    *window,
   else
     meta_verbose ("Window %s is not transient\n", window->desc);
 
-  /* may now be a dialog */
-  meta_window_recalc_window_type (window);
-
-  if (!window->constructing)
+  if (window->transient_parent_is_root_window || window->xtransient_for == None)
+    meta_window_set_transient_for (window, NULL);
+  else
     {
-      /* If the window attaches, detaches, or changes attached
-       * parents, we need to destroy the MetaWindow and let a new one
-       * be created (which happens as a side effect of
-       * meta_window_unmanage()). The condition below is correct
-       * because we know window->xtransient_for has changed.
-       */
-      if (window->attached || meta_window_should_attach_to_parent (window))
-        {
-          guint32 timestamp;
-
-          window->xtransient_for = old_transient_for;
-          timestamp = meta_display_get_current_time_roundtrip (window->display);
-          meta_window_unmanage (window, timestamp);
-          return;
-        }
+      parent = meta_display_lookup_x_window (window->display,
+                                             window->xtransient_for);
+      meta_window_set_transient_for (window, parent);
     }
-
-  /* update stacking constraints */
-  if (!window->override_redirect)
-    meta_stack_update_transient (window->screen->stack, window);
-
-  /* possibly change its group. We treat being a window's transient as
-   * equivalent to making it your group leader, to work around shortcomings
-   * in programs such as xmms-- see #328211.
-   */
-  if (window->xtransient_for != None &&
-      window->xgroup_leader != None &&
-      window->xtransient_for != window->xgroup_leader)
-    meta_window_group_leader_changed (window);
-
-  if (!window->constructing && !window->override_redirect)
-    meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
-
-  if (meta_window_appears_focused (window) && window->xtransient_for != None)
-    meta_window_propagate_focus_appearance (window, TRUE);
 }
 
 static void
diff --git a/src/core/window.c b/src/core/window.c
index 199799d..9505d28 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -239,6 +239,9 @@ meta_window_finalize (GObject *object)
   if (window->opaque_region)
     cairo_region_destroy (window->opaque_region);
 
+  if (window->transient_for)
+    g_object_unref (window->transient_for);
+
   meta_icon_cache_free (&window->icon_cache);
 
   g_free (window->sm_client_id);
@@ -1114,11 +1117,6 @@ meta_window_new_shared (MetaDisplay         *display,
    * can use this time as a fallback.
    */
   if (!window->override_redirect && !window->net_wm_user_time_set) {
-    MetaWindow *parent = NULL;
-    if (window->xtransient_for)
-      parent = meta_display_lookup_x_window (window->display,
-                                             window->xtransient_for);
-
     /* First, maybe the app was launched with startup notification using an
      * obsolete version of the spec; use that timestamp if it exists.
      */
@@ -1127,8 +1125,8 @@ meta_window_new_shared (MetaDisplay         *display,
        * being recorded as a fallback for potential transients
        */
       window->net_wm_user_time = window->initial_timestamp;
-    else if (parent != NULL)
-      meta_window_set_user_time(window, parent->net_wm_user_time);
+    else if (window->transient_for != NULL)
+      meta_window_set_user_time(window, window->transient_for->net_wm_user_time);
     else
       /* NOTE: Do NOT toggle net_wm_user_time_set to true; this is just
        * being recorded as a fallback for potential transients
@@ -1218,21 +1216,16 @@ meta_window_new_shared (MetaDisplay         *display,
   if (!window->override_redirect)
     {
       if (window->workspace == NULL &&
-          window->xtransient_for != None)
+          window->transient_for != NULL)
         {
           /* Try putting dialog on parent's workspace */
-          MetaWindow *parent;
-
-          parent = meta_display_lookup_x_window (window->display,
-                                                 window->xtransient_for);
-
-          if (parent && parent->workspace)
+          if (window->transient_for->workspace)
             {
               meta_topic (META_DEBUG_PLACEMENT,
                           "Putting window %s on same workspace as parent %s\n",
-                          window->desc, parent->desc);
+                          window->desc, window->transient_for->desc);
 
-              if (parent->on_all_workspaces_requested)
+              if (window->transient_for->on_all_workspaces_requested)
                 {
                   window->on_all_workspaces_requested = TRUE;
                   window->on_all_workspaces = TRUE;
@@ -1240,7 +1233,7 @@ meta_window_new_shared (MetaDisplay         *display,
 
               /* this will implicitly add to the appropriate MRU lists
                */
-              meta_workspace_add_window (parent->workspace, window);
+              meta_workspace_add_window (window->transient_for->workspace, window);
             }
         }
 
@@ -4456,14 +4449,14 @@ window_activate (MetaWindow     *window,
   /* For non-transient windows, we just set up a pulsing indicator,
      rather than move windows or workspaces.
      See http://bugzilla.gnome.org/show_bug.cgi?id=482354 */
-  if (window->xtransient_for == None &&
+  if (window->transient_for == NULL &&
       !meta_window_located_on_workspace (window, workspace))
     {
       meta_window_set_demands_attention (window);
       /* We've marked it as demanding, don't need to do anything else. */
       return;
     }
-  else if (window->xtransient_for != None)
+  else if (window->transient_for != NULL)
     {
       /* Move transients to current workspace - preference dialogs should appear over
          the source window.  */
@@ -5001,6 +4994,7 @@ meta_window_move_resize_internal (MetaWindow          *window,
    *    2   | A not-resize-only ConfigureRequest/net_moveresize_window request
    *    3   | meta_window_move
    *    3   | meta_window_move_resize
+   *    4   | meta_window_move_resize_wayland
    *
    * For each of the cases, root_x_nw and root_y_nw must be treated as follows:
    *
@@ -5011,8 +5005,12 @@ meta_window_move_resize_internal (MetaWindow          *window,
    *       coordinates are relative to some corner or side of the outer
    *       window (except for the case of StaticGravity) and we want to
    *       know the location of the upper left corner of the inner window.
-   *   (3) These values are already the desired positon of the NW corner
+   *   (3) These values are already the desired position of the NW corner
    *       of the inner window
+   *   (4) These values are already the desired position of the NW corner
+   *       of the inner window (which is also the outer window, because
+   *       we don't decorate wayland clients), and the client has acknowledged
+   *       the window size change.
    */
   XWindowChanges values;
   unsigned int mask;
@@ -5028,6 +5026,7 @@ meta_window_move_resize_internal (MetaWindow          *window,
   gboolean is_configure_request;
   gboolean do_gravity_adjust;
   gboolean is_user_action;
+  gboolean is_wayland_resize;
   gboolean did_placement;
   gboolean configure_frame_first;
   gboolean use_static_gravity;
@@ -5044,9 +5043,12 @@ meta_window_move_resize_internal (MetaWindow          *window,
   is_configure_request = (flags & META_IS_CONFIGURE_REQUEST) != 0;
   do_gravity_adjust = (flags & META_DO_GRAVITY_ADJUST) != 0;
   is_user_action = (flags & META_IS_USER_ACTION) != 0;
+  is_wayland_resize = (flags & META_IS_WAYLAND_RESIZE) != 0;
 
-  /* The action has to be a move or a resize or both... */
-  g_assert (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION));
+  /* The action has to be a move, a resize or the wayland client
+   * acking our choice of size.
+   */
+  g_assert (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION | META_IS_WAYLAND_RESIZE));
 
   /* We don't need it in the idle queue anymore. */
   meta_window_unqueue (window, META_QUEUE_MOVE_RESIZE);
@@ -5104,309 +5106,404 @@ meta_window_move_resize_internal (MetaWindow          *window,
 
   did_placement = !window->placed && window->calc_placement;
 
-  meta_window_constrain (window,
-                         window->frame ? &borders : NULL,
-                         flags,
-                         gravity,
-                         &old_rect,
-                         &new_rect);
+  if (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION))
+    {
+      meta_window_constrain (window,
+                             window->frame ? &borders : NULL,
+                             flags,
+                             gravity,
+                             &old_rect,
+                             &new_rect);
+    }
 
-  w = new_rect.width;
-  h = new_rect.height;
-  root_x_nw = new_rect.x;
-  root_y_nw = new_rect.y;
+  if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
+    {
+      g_assert (window->frame == NULL);
 
-  if (w != window->rect.width ||
-      h != window->rect.height)
-    need_resize_client = TRUE;
+      /* For wayland clients, the size is completely determined by the client,
+       * and while this allows to avoid some trickery with frames and the resulting
+       * lagging, we also need to insist a bit when the constraints would apply
+       * a different size than the client decides.
+       *
+       * Note that this is not generally a problem for normal toplevel windows (the
+       * constraints don't see the size hints, or just change the position), but
+       * it can be for maximized or fullscreen.
+       *
+       */
+      root_x_nw = new_rect.x;
+      root_y_nw = new_rect.y;
 
-  window->rect.width = w;
-  window->rect.height = h;
+      /* First, save where we would like the client to be. This is used by the next
+       * attach to determine if the client is really moving/resizing or not.
+       */
+      window->expected_rect = new_rect;
 
-  if (window->frame)
-    {
-      int frame_size_dx, frame_size_dy;
-      int new_w, new_h;
+      if (is_wayland_resize)
+        {
+          /* This is a call to wl_surface_commit(), ignore the new_rect and
+           * update the real client size to match the buffer size.
+           */
 
-      new_w = window->rect.width + borders.total.left + borders.total.right;
+          window->rect.width = w;
+          window->rect.height = h;
+        }
 
-      if (window->shaded)
-        new_h = borders.total.top;
+      if (new_rect.width != window->rect.width ||
+          new_rect.height != window->rect.height)
+        {
+          /* We need to resize the client. Resizing is in two parts:
+           * some of the movement happens immediately, and some happens as part
+           * of the resizing (through dx/dy in wl_surface_attach).
+           *
+           * To do so, we need to compute the resize from the point of the view
+           * of the client, and then adjust the immediate resize to match.
+           *
+           * dx/dy are the values we expect from the new attach(), while deltax/
+           * deltay reflect the overall movement.
+           */
+          MetaRectangle client_rect;
+          int dx, dy;
+          int deltax, deltay;
+
+          meta_rectangle_resize_with_gravity (&old_rect,
+                                              &client_rect,
+                                              gravity,
+                                              new_rect.width,
+                                              new_rect.height);
+
+          deltax = new_rect.x - old_rect.x;
+          deltay = new_rect.y - old_rect.y;
+          dx = client_rect.x - old_rect.x;
+          dy = client_rect.y - old_rect.y;
+
+          if ((deltax - dx) != 0 ||
+              (deltay - dy) != 0)
+            need_move_client = TRUE;
+
+          window->rect.x += (deltax - dx);
+          window->rect.y += (deltay - dy);
+
+          need_resize_client = TRUE;
+          meta_wayland_surface_configure_notify (window->surface,
+                                                 new_rect.width,
+                                                 new_rect.height,
+                                                 (dx != 0 ? WL_SHELL_SURFACE_RESIZE_LEFT : 0) |
+                                                 (dy != 0 ? WL_SHELL_SURFACE_RESIZE_TOP : 0));
+        }
       else
-        new_h = window->rect.height + borders.total.top + borders.total.bottom;
+        {
+          /* No resize happening, we can just move the window and live with it. */
+          if (window->rect.x != new_rect.x ||
+              window->rect.y != new_rect.y)
+            need_move_client = TRUE;
 
-      frame_size_dx = new_w - window->frame->rect.width;
-      frame_size_dy = new_h - window->frame->rect.height;
+          window->rect.x = new_rect.x;
+          window->rect.y = new_rect.y;
+        }
+    }
+  else
+    {
+      /* Everything else is the old X11 code, including weird gravities,
+       * the interaction with frames and the synthetic configure notifies.
+       */
 
-      need_resize_frame = (frame_size_dx != 0 || frame_size_dy != 0);
+      root_x_nw = new_rect.x;
+      root_y_nw = new_rect.y;
+      w = new_rect.width;
+      h = new_rect.height;
 
-      window->frame->rect.width = new_w;
-      window->frame->rect.height = new_h;
+      if (w != window->rect.width ||
+          h != window->rect.height)
+        need_resize_client = TRUE;
 
-      meta_topic (META_DEBUG_GEOMETRY,
-                  "Calculated frame size %dx%d\n",
-                  window->frame->rect.width,
-                  window->frame->rect.height);
-    }
+      window->rect.width = w;
+      window->rect.height = h;
 
-  /* For nice effect, when growing the window we want to move/resize
-   * the frame first, when shrinking the window we want to move/resize
-   * the client first. If we grow one way and shrink the other,
-   * see which way we're moving "more"
-   *
-   * Mail from Owen subject "Suggestion: Gravity and resizing from the left"
-   * http://mail.gnome.org/archives/wm-spec-list/1999-November/msg00088.html
-   *
-   * An annoying fact you need to know in this code is that StaticGravity
-   * does nothing if you _only_ resize or _only_ move the frame;
-   * it must move _and_ resize, otherwise you get NorthWestGravity
-   * behavior. The move and resize must actually occur, it is not
-   * enough to set CWX | CWWidth but pass in the current size/pos.
-   */
+      if (window->frame)
+        {
+          int frame_size_dx, frame_size_dy;
+          int new_w, new_h;
 
-  if (window->frame)
-    {
-      int new_x, new_y;
-      int frame_pos_dx, frame_pos_dy;
+          new_w = window->rect.width + borders.total.left + borders.total.right;
 
-      /* Compute new frame coords */
-      new_x = root_x_nw - borders.total.left;
-      new_y = root_y_nw - borders.total.top;
+          if (window->shaded)
+            new_h = borders.total.top;
+          else
+            new_h = window->rect.height + borders.total.top + borders.total.bottom;
 
-      frame_pos_dx = new_x - window->frame->rect.x;
-      frame_pos_dy = new_y - window->frame->rect.y;
+          frame_size_dx = new_w - window->frame->rect.width;
+          frame_size_dy = new_h - window->frame->rect.height;
 
-      need_move_frame = (frame_pos_dx != 0 || frame_pos_dy != 0);
+          need_resize_frame = (frame_size_dx != 0 || frame_size_dy != 0);
 
-      window->frame->rect.x = new_x;
-      window->frame->rect.y = new_y;
+          window->frame->rect.width = new_w;
+          window->frame->rect.height = new_h;
 
-      /* If frame will both move and resize, then StaticGravity
-       * on the child window will kick in and implicitly move
-       * the child with respect to the frame. The implicit
-       * move will keep the child in the same place with
-       * respect to the root window. If frame only moves
-       * or only resizes, then the child will just move along
-       * with the frame.
-       */
+          meta_topic (META_DEBUG_GEOMETRY,
+                      "Calculated frame size %dx%d\n",
+                      window->frame->rect.width,
+                      window->frame->rect.height);
+        }
 
-      /* window->rect.x, window->rect.y are relative to frame,
-       * remember they are the server coords
+      /* For nice effect, when growing the window we want to move/resize
+       * the frame first, when shrinking the window we want to move/resize
+       * the client first. If we grow one way and shrink the other,
+       * see which way we're moving "more"
+       *
+       * Mail from Owen subject "Suggestion: Gravity and resizing from the left"
+       * http://mail.gnome.org/archives/wm-spec-list/1999-November/msg00088.html
+       *
+       * An annoying fact you need to know in this code is that StaticGravity
+       * does nothing if you _only_ resize or _only_ move the frame;
+       * it must move _and_ resize, otherwise you get NorthWestGravity
+       * behavior. The move and resize must actually occur, it is not
+       * enough to set CWX | CWWidth but pass in the current size/pos.
        */
 
-      new_x = borders.total.left;
-      new_y = borders.total.top;
-
-      if (need_resize_frame && need_move_frame &&
-          static_gravity_works (window->display))
+      if (window->frame)
         {
-          /* static gravity kicks in because frame
-           * is both moved and resized
-           */
-          /* when we move the frame by frame_pos_dx, frame_pos_dy the
-           * client will implicitly move relative to frame by the
-           * inverse delta.
-           *
-           * When moving client then frame, we move the client by the
-           * frame delta, to be canceled out by the implicit move by
-           * the inverse frame delta, resulting in a client at new_x,
-           * new_y.
-           *
-           * When moving frame then client, we move the client
-           * by the same delta as the frame, because the client
-           * was "left behind" by the frame - resulting in a client
-           * at new_x, new_y.
-           *
-           * In both cases we need to move the client window
-           * in all cases where we had to move the frame window.
-           */
+          int new_x, new_y;
+          int frame_pos_dx, frame_pos_dy;
 
-          client_move_x = new_x + frame_pos_dx;
-          client_move_y = new_y + frame_pos_dy;
+          /* Compute new frame coords */
+          new_x = root_x_nw - borders.total.left;
+          new_y = root_y_nw - borders.total.top;
 
-          if (need_move_frame)
-            need_move_client = TRUE;
+          frame_pos_dx = new_x - window->frame->rect.x;
+          frame_pos_dy = new_y - window->frame->rect.y;
 
-          use_static_gravity = TRUE;
-        }
-      else
-        {
-          client_move_x = new_x;
-          client_move_y = new_y;
+          need_move_frame = (frame_pos_dx != 0 || frame_pos_dy != 0);
 
-          if (client_move_x != window->rect.x ||
-              client_move_y != window->rect.y)
-            need_move_client = TRUE;
+          window->frame->rect.x = new_x;
+          window->frame->rect.y = new_y;
 
-          use_static_gravity = FALSE;
-        }
+          /* If frame will both move and resize, then StaticGravity
+           * on the child window will kick in and implicitly move
+           * the child with respect to the frame. The implicit
+           * move will keep the child in the same place with
+           * respect to the root window. If frame only moves
+           * or only resizes, then the child will just move along
+           * with the frame.
+           */
 
-      /* This is the final target position, but not necessarily what
-       * we pass to XConfigureWindow, due to StaticGravity implicit
-       * movement.
-       */
-      window->rect.x = new_x;
-      window->rect.y = new_y;
-    }
-  else
-    {
-      if (root_x_nw != window->rect.x ||
-          root_y_nw != window->rect.y)
-        need_move_client = TRUE;
+          /* window->rect.x, window->rect.y are relative to frame,
+           * remember they are the server coords
+           */
 
-      window->rect.x = root_x_nw;
-      window->rect.y = root_y_nw;
+          new_x = borders.total.left;
+          new_y = borders.total.top;
 
-      client_move_x = window->rect.x;
-      client_move_y = window->rect.y;
+          if (need_resize_frame && need_move_frame &&
+              static_gravity_works (window->display))
+            {
+              /* static gravity kicks in because frame
+               * is both moved and resized
+               */
+              /* when we move the frame by frame_pos_dx, frame_pos_dy the
+               * client will implicitly move relative to frame by the
+               * inverse delta.
+               *
+               * When moving client then frame, we move the client by the
+               * frame delta, to be canceled out by the implicit move by
+               * the inverse frame delta, resulting in a client at new_x,
+               * new_y.
+               *
+               * When moving frame then client, we move the client
+               * by the same delta as the frame, because the client
+               * was "left behind" by the frame - resulting in a client
+               * at new_x, new_y.
+               *
+               * In both cases we need to move the client window
+               * in all cases where we had to move the frame window.
+               */
 
-      use_static_gravity = FALSE;
-    }
+              client_move_x = new_x + frame_pos_dx;
+              client_move_y = new_y + frame_pos_dy;
 
-  /* If frame extents have changed, fill in other frame fields and
-     change frame's extents property. */
-  if (window->frame &&
-      (window->frame->child_x != borders.total.left ||
-       window->frame->child_y != borders.total.top ||
-       window->frame->right_width != borders.total.right ||
-       window->frame->bottom_height != borders.total.bottom))
-    {
-      window->frame->child_x = borders.total.left;
-      window->frame->child_y = borders.total.top;
-      window->frame->right_width = borders.total.right;
-      window->frame->bottom_height = borders.total.bottom;
+              if (need_move_frame)
+                need_move_client = TRUE;
 
-      update_net_frame_extents (window);
-    }
+              use_static_gravity = TRUE;
+            }
+          else
+            {
+              client_move_x = new_x;
+              client_move_y = new_y;
 
-  /* See ICCCM 4.1.5 for when to send ConfigureNotify */
+              if (client_move_x != window->rect.x ||
+                  client_move_y != window->rect.y)
+                need_move_client = TRUE;
 
-  need_configure_notify = FALSE;
+              use_static_gravity = FALSE;
+            }
 
-  /* If this is a configure request and we change nothing, then we
-   * must send configure notify.
-   */
-  if  (is_configure_request &&
-       !(need_move_client || need_move_frame ||
-         need_resize_client || need_resize_frame ||
-         window->border_width != 0))
-    need_configure_notify = TRUE;
-
-  /* We must send configure notify if we move but don't resize, since
-   * the client window may not get a real event
-   */
-  if ((need_move_client || need_move_frame) &&
-      !(need_resize_client || need_resize_frame))
-    need_configure_notify = TRUE;
-
-  /* MapRequest events with a PPosition or UPosition hint with a frame
-   * are moved by mutter without resizing; send a configure notify
-   * in such cases.  See #322840.  (Note that window->constructing is
-   * only true iff this call is due to a MapRequest, and when
-   * PPosition/UPosition hints aren't set, mutter seems to send a
-   * ConfigureNotify anyway due to the above code.)
-   */
-  if (window->constructing && window->frame &&
-      ((window->size_hints.flags & PPosition) ||
-       (window->size_hints.flags & USPosition)))
-    need_configure_notify = TRUE;
+          /* This is the final target position, but not necessarily what
+           * we pass to XConfigureWindow, due to StaticGravity implicit
+           * movement.
+           */
+          window->rect.x = new_x;
+          window->rect.y = new_y;
+        }
+      else
+        {
+          if (root_x_nw != window->rect.x ||
+              root_y_nw != window->rect.y)
+            need_move_client = TRUE;
 
-  /* The rest of this function syncs our new size/pos with X as
-   * efficiently as possible
-   */
+          window->rect.x = root_x_nw;
+          window->rect.y = root_y_nw;
 
-  /* Normally, we configure the frame first depending on whether
-   * we grow the frame more than we shrink. The idea is to avoid
-   * messing up the window contents by having a temporary situation
-   * where the frame is smaller than the window. However, if we're
-   * cooperating with the client to create an atomic frame upate,
-   * and the window is redirected, then we should always update
-   * the frame first, since updating the frame will force a new
-   * backing pixmap to be allocated, and the old backing pixmap
-   * will be left undisturbed for us to paint to the screen until
-   * the client finishes redrawing.
-   */
-  if (window->extended_sync_request_counter)
-    {
-      configure_frame_first = TRUE;
-    }
-  else
-    {
-      size_dx = w - window->rect.width;
-      size_dy = h - window->rect.height;
+          client_move_x = window->rect.x;
+          client_move_y = window->rect.y;
 
-      configure_frame_first = size_dx + size_dy >= 0;
-    }
+          use_static_gravity = FALSE;
+        }
 
-  if (use_static_gravity)
-    meta_window_set_gravity (window, StaticGravity);
+      /* If frame extents have changed, fill in other frame fields and
+         change frame's extents property. */
+      if (window->frame &&
+          (window->frame->child_x != borders.total.left ||
+           window->frame->child_y != borders.total.top ||
+           window->frame->right_width != borders.total.right ||
+           window->frame->bottom_height != borders.total.bottom))
+        {
+          window->frame->child_x = borders.total.left;
+          window->frame->child_y = borders.total.top;
+          window->frame->right_width = borders.total.right;
+          window->frame->bottom_height = borders.total.bottom;
 
-  if (configure_frame_first && window->frame)
-    frame_shape_changed = meta_frame_sync_to_window (window->frame,
-                                                     gravity,
-                                                     need_move_frame, need_resize_frame);
+          update_net_frame_extents (window);
+        }
 
-  values.border_width = 0;
-  values.x = client_move_x;
-  values.y = client_move_y;
-  values.width = window->rect.width;
-  values.height = window->rect.height;
+      /* See ICCCM 4.1.5 for when to send ConfigureNotify */
 
-  mask = 0;
-  if (is_configure_request && window->border_width != 0)
-    mask |= CWBorderWidth; /* must force to 0 */
-  if (need_move_client)
-    mask |= (CWX | CWY);
-  if (need_resize_client)
-    mask |= (CWWidth | CWHeight);
+      need_configure_notify = FALSE;
 
-  if (mask != 0)
-    {
-      {
-        int newx, newy;
-        meta_window_get_position (window, &newx, &newy);
-        meta_topic (META_DEBUG_GEOMETRY,
-                    "Syncing new client geometry %d,%d %dx%d, border: %s pos: %s size: %s\n",
-                    newx, newy,
-                    window->rect.width, window->rect.height,
-                    mask & CWBorderWidth ? "true" : "false",
-                    need_move_client ? "true" : "false",
-                    need_resize_client ? "true" : "false");
-      }
+      /* If this is a configure request and we change nothing, then we
+       * must send configure notify.
+       */
+      if  (is_configure_request &&
+           !(need_move_client || need_move_frame ||
+             need_resize_client || need_resize_frame ||
+             window->border_width != 0))
+        need_configure_notify = TRUE;
+
+      /* We must send configure notify if we move but don't resize, since
+       * the client window may not get a real event
+       */
+      if ((need_move_client || need_move_frame) &&
+          !(need_resize_client || need_resize_frame))
+        need_configure_notify = TRUE;
+
+      /* MapRequest events with a PPosition or UPosition hint with a frame
+       * are moved by mutter without resizing; send a configure notify
+       * in such cases.  See #322840.  (Note that window->constructing is
+       * only true iff this call is due to a MapRequest, and when
+       * PPosition/UPosition hints aren't set, mutter seems to send a
+       * ConfigureNotify anyway due to the above code.)
+       */
+      if (window->constructing && window->frame &&
+          ((window->size_hints.flags & PPosition) ||
+           (window->size_hints.flags & USPosition)))
+        need_configure_notify = TRUE;
 
-      meta_error_trap_push (window->display);
+      /* The rest of this function syncs our new size/pos with X as
+       * efficiently as possible
+       */
+
+      /* Normally, we configure the frame first depending on whether
+       * we grow the frame more than we shrink. The idea is to avoid
+       * messing up the window contents by having a temporary situation
+       * where the frame is smaller than the window. However, if we're
+       * cooperating with the client to create an atomic frame upate,
+       * and the window is redirected, then we should always update
+       * the frame first, since updating the frame will force a new
+       * backing pixmap to be allocated, and the old backing pixmap
+       * will be left undisturbed for us to paint to the screen until
+       * the client finishes redrawing.
+       */
+      if (window->extended_sync_request_counter)
+        {
+          configure_frame_first = TRUE;
+        }
+      else
+        {
+          size_dx = w - window->rect.width;
+          size_dy = h - window->rect.height;
+
+          configure_frame_first = size_dx + size_dy >= 0;
+        }
+
+      if (use_static_gravity)
+        meta_window_set_gravity (window, StaticGravity);
+
+      if (configure_frame_first && window->frame)
+        frame_shape_changed = meta_frame_sync_to_window (window->frame,
+                                                         gravity,
+                                                         need_move_frame, need_resize_frame);
+
+      values.border_width = 0;
+      values.x = client_move_x;
+      values.y = client_move_y;
+      values.width = window->rect.width;
+      values.height = window->rect.height;
+
+      mask = 0;
+      if (is_configure_request && window->border_width != 0)
+        mask |= CWBorderWidth; /* must force to 0 */
+      if (need_move_client)
+        mask |= (CWX | CWY);
+      if (need_resize_client)
+        mask |= (CWWidth | CWHeight);
+
+      if (mask != 0)
+        {
+          {
+            int newx, newy;
+            meta_window_get_position (window, &newx, &newy);
+            meta_topic (META_DEBUG_GEOMETRY,
+                        "Syncing new client geometry %d,%d %dx%d, border: %s pos: %s size: %s\n",
+                        newx, newy,
+                        window->rect.width, window->rect.height,
+                        mask & CWBorderWidth ? "true" : "false",
+                        need_move_client ? "true" : "false",
+                        need_resize_client ? "true" : "false");
+          }
+
+          meta_error_trap_push (window->display);
 
 #ifdef HAVE_XSYNC
-      if (window == window->display->grab_window &&
-          meta_grab_op_is_resizing (window->display->grab_op) &&
-          !window->disable_sync &&
-          window->sync_request_counter != None &&
-         window->sync_request_alarm != None &&
-          window->sync_request_timeout_id == 0)
-       {
-         send_sync_request (window);
-       }
+          if (window == window->display->grab_window &&
+              meta_grab_op_is_resizing (window->display->grab_op) &&
+              !window->disable_sync &&
+              window->sync_request_counter != None &&
+              window->sync_request_alarm != None &&
+              window->sync_request_timeout_id == 0)
+            {
+              send_sync_request (window);
+            }
 #endif
 
-      XConfigureWindow (window->display->xdisplay,
-                        window->xwindow,
-                        mask,
-                        &values);
+          XConfigureWindow (window->display->xdisplay,
+                            window->xwindow,
+                            mask,
+                            &values);
 
-      meta_error_trap_pop (window->display);
-    }
+          meta_error_trap_pop (window->display);
+        }
 
-  if (!configure_frame_first && window->frame)
-    frame_shape_changed = meta_frame_sync_to_window (window->frame,
-                                                     gravity,
-                                                     need_move_frame, need_resize_frame);
+      if (!configure_frame_first && window->frame)
+        frame_shape_changed = meta_frame_sync_to_window (window->frame,
+                                                         gravity,
+                                                         need_move_frame, need_resize_frame);
 
-  /* Put gravity back to be nice to lesser window managers */
-  if (use_static_gravity)
-    meta_window_set_gravity (window, NorthWestGravity);
+      /* Put gravity back to be nice to lesser window managers */
+      if (use_static_gravity)
+        meta_window_set_gravity (window, NorthWestGravity);
 
-  if (need_configure_notify)
-    send_configure_notify (window);
+      if (need_configure_notify)
+        send_configure_notify (window);
+    }
 
   if (!window->placed && window->force_save_user_rect && !window->fullscreen)
     force_save_user_window_placement (window);
@@ -5415,7 +5512,7 @@ meta_window_move_resize_internal (MetaWindow          *window,
 
   if (need_move_frame || need_resize_frame ||
       need_move_client || need_resize_client ||
-      did_placement)
+      did_placement || is_wayland_resize)
     {
       int newx, newy;
       meta_window_get_position (window, &newx, &newy);
@@ -5485,6 +5582,37 @@ meta_window_resize (MetaWindow  *window,
                                     x, y, w, h);
 }
 
+/*
+ * meta_window_move_resize_wayland:
+ *
+ * Complete a resize operation from a wayland client.
+ *
+ */
+void
+meta_window_move_resize_wayland (MetaWindow *window,
+                                 int         width,
+                                 int         height,
+                                 int         dx,
+                                 int         dy)
+{
+  int x, y;
+  MetaMoveResizeFlags flags;
+
+  flags = META_IS_WAYLAND_RESIZE;
+
+  meta_window_get_position (window, &x, &y);
+  x += dx; y += dy;
+
+  if (x != window->expected_rect.x || y != window->expected_rect.y)
+    flags |= META_IS_MOVE_ACTION;
+  if (width != window->expected_rect.width ||
+      height != window->expected_rect.height)
+    flags |= META_IS_RESIZE_ACTION;
+
+  meta_window_move_resize_internal (window, flags, NorthWestGravity,
+                                    x, y, width, height);
+}
+
 /**
  * meta_window_move:
  * @window: a #MetaWindow
@@ -5995,7 +6123,7 @@ get_modal_transient (MetaWindow *window)
     {
       MetaWindow *transient = tmp->data;
 
-      if (transient->xtransient_for == modal_transient->xwindow &&
+      if (transient->transient_for == modal_transient &&
           transient->wm_state_modal)
         {
           modal_transient = transient;
@@ -8365,7 +8493,7 @@ recalc_window_type (MetaWindow *window)
             XFree (atom_name);
         }
     }
-  else if (window->xtransient_for != None)
+  else if (window->transient_for != NULL)
     {
       window->type = META_WINDOW_DIALOG;
     }
@@ -8708,8 +8836,7 @@ recalc_window_features (MetaWindow *window)
     case META_WINDOW_MODAL_DIALOG:
       /* only skip taskbar if we have a real transient parent
          (and ignore the application hints) */
-      if (window->xtransient_for != None &&
-          window->xtransient_for != window->screen->xroot)
+      if (window->transient_for != NULL)
         window->skip_taskbar = TRUE;
       else
         window->skip_taskbar = FALSE;
@@ -10313,11 +10440,10 @@ meta_window_foreach_ancestor (MetaWindow            *window,
   w = window;
   do
     {
-      if (w->xtransient_for == None ||
-          w->transient_parent_is_root_window)
+      if (w->transient_for == NULL)
         break;
 
-      w = meta_display_lookup_x_window (w->display, w->xtransient_for);
+      w = w->transient_for;
     }
   while (w && (* func) (w, user_data));
 }
@@ -11140,7 +11266,9 @@ meta_window_get_transient_for (MetaWindow *window)
 {
   g_return_val_if_fail (META_IS_WINDOW (window), NULL);
 
-  if (window->xtransient_for)
+  if (window->transient_for)
+    return window->transient_for;
+  else if (window->xtransient_for)
     return meta_display_lookup_x_window (window->display,
                                          window->xtransient_for);
   else
@@ -11545,3 +11673,55 @@ meta_window_set_gtk_dbus_properties (MetaWindow *window,
 
   g_object_thaw_notify (G_OBJECT (window));
 }
+
+void
+meta_window_set_transient_for (MetaWindow *window,
+                               MetaWindow *parent)
+{
+  if (meta_window_appears_focused (window) && window->transient_for != None)
+    meta_window_propagate_focus_appearance (window, FALSE);
+
+  /* may now be a dialog */
+  meta_window_recalc_window_type (window);
+
+  if (!window->constructing)
+    {
+      /* If the window attaches, detaches, or changes attached
+       * parents, we need to destroy the MetaWindow and let a new one
+       * be created (which happens as a side effect of
+       * meta_window_unmanage()). The condition below is correct
+       * because we know window->transient_for has changed.
+       */
+      if (window->attached || meta_window_should_attach_to_parent (window))
+        {
+          guint32 timestamp;
+
+          timestamp = meta_display_get_current_time_roundtrip (window->display);
+          meta_window_unmanage (window, timestamp);
+          return;
+        }
+    }
+
+  /* update stacking constraints */
+  if (!window->override_redirect)
+    meta_stack_update_transient (window->screen->stack, window);
+
+  /* We know this won't create a reference cycle because we check for loops */
+  g_clear_object (&window->transient_for);
+  window->transient_for = parent ? g_object_ref (parent) : NULL;
+
+  /* possibly change its group. We treat being a window's transient as
+   * equivalent to making it your group leader, to work around shortcomings
+   * in programs such as xmms-- see #328211.
+   */
+  if (window->xtransient_for != None &&
+      window->xgroup_leader != None &&
+      window->xtransient_for != window->xgroup_leader)
+    meta_window_group_leader_changed (window);
+
+  if (!window->constructing && !window->override_redirect)
+    meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
+
+  if (meta_window_appears_focused (window) && window->transient_for != None)
+    meta_window_propagate_focus_appearance (window, TRUE);
+}
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index 1ce77f7..3f82a69 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -25,6 +25,7 @@
 #include <clutter/clutter.h>
 #include <clutter/wayland/clutter-wayland-compositor.h>
 #include <clutter/wayland/clutter-wayland-surface.h>
+#include <cogl/cogl-wayland-server.h>
 
 #include <glib.h>
 #include <sys/time.h>
@@ -64,8 +65,9 @@ static void
 surface_process_damage (MetaWaylandSurface *surface,
                         cairo_region_t *region)
 {
-  if (surface->window &&
-      surface->buffer_ref.buffer)
+  g_assert (surface->window);
+
+  if (surface->buffer_ref.buffer)
     {
       MetaWindowActor *window_actor =
         META_WINDOW_ACTOR (meta_window_get_compositor_private (surface->window));
@@ -111,7 +113,7 @@ 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)
+                             gint32 dx, gint32 dy)
 {
   MetaWaylandSurface *surface =
     wl_resource_get_user_data (wayland_surface_resource);
@@ -130,8 +132,8 @@ meta_wayland_surface_attach (struct wl_client *wayland_client,
   if (surface->pending.buffer)
     wl_list_remove (&surface->pending.buffer_destroy_listener.link);
 
-  surface->pending.sx = sx;
-  surface->pending.sy = sy;
+  surface->pending.dx = dx;
+  surface->pending.dy = dy;
   surface->pending.buffer = buffer;
   surface->pending.newly_attached = TRUE;
 
@@ -247,36 +249,86 @@ meta_wayland_surface_commit (struct wl_client *client,
   if (surface->pending.newly_attached &&
       surface->buffer_ref.buffer != surface->pending.buffer)
     {
+      MetaWaylandBuffer *buffer = surface->pending.buffer;
+      CoglContext *ctx =
+        clutter_backend_get_cogl_context (clutter_get_default_backend ());
+      CoglError *catch_error = NULL;
+      CoglTexture *texture =
+        COGL_TEXTURE (cogl_wayland_texture_2d_new_from_buffer (ctx,
+                                                               buffer->resource,
+                                                               &catch_error));
+      if (!texture)
+        {
+          cogl_error_free (catch_error);
+         meta_warning ("Could not import pending buffer, ignoring commit\n");
+         return;
+        }
+      else
+        {
+         buffer->texture = texture;
+          buffer->width = cogl_texture_get_width (texture);
+          buffer->height = cogl_texture_get_height (texture);
+        }
+
       /* 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->buffer_ref.buffer)
+    {
+      meta_warning ("Commit without a buffer? Ignoring\n");
+      return;
+    }
 
-          if (surface->window)
-            {
-              MetaWindow *window = surface->window;
-              MetaWindowActor *window_actor =
-                META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
-              MetaRectangle rect;
+  if (surface->initial_state)
+    {
+      MetaDisplay *display = meta_get_display ();
+      int width;
+      int height;
 
-              meta_window_get_input_rect (surface->window, &rect);
+      width = surface->buffer_ref.buffer->width;
+      height = surface->buffer_ref.buffer->height;
 
-              if (window_actor)
-                meta_window_actor_attach_wayland_buffer (window_actor, buffer);
+      /* This will free and clear initial_state */
+      surface->window = meta_window_new_for_wayland (display, width, height, surface);
+    }
 
-              /* 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 == compositor->seat->sprite)
+    meta_wayland_seat_update_sprite (compositor->seat);
+  else if (surface->window)
+    {
+      MetaWindow *window = surface->window;
+
+      if (surface->pending.buffer)
+       {
+         MetaWaylandBuffer *buffer = surface->pending.buffer;
+         MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
+
+         meta_window_actor_attach_wayland_buffer (window_actor, buffer);
+       }
+
+      /* We resize X based surfaces according to X events */
+      if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
+       {
+         int new_width;
+         int new_height;
+
+         new_width = surface->buffer_ref.buffer->width;
+         new_height = surface->buffer_ref.buffer->height;
+         if (new_width != window->rect.width ||
+             new_height != window->rect.height ||
+             surface->pending.dx != 0 ||
+             surface->pending.dy != 0)
+           meta_window_move_resize_wayland (surface->window, new_width, new_height,
+                                            surface->pending.dx, surface->pending.dy);
+       }
+
+      meta_window_set_opaque_region (surface->window, surface->pending.opaque_region);
+      meta_window_set_input_region (surface->window, surface->pending.input_region);
+      surface_process_damage (surface, surface->pending.damage);
     }
 
   if (surface->pending.buffer)
@@ -284,20 +336,11 @@ meta_wayland_surface_commit (struct wl_client *client,
       wl_list_remove (&surface->pending.buffer_destroy_listener.link);
       surface->pending.buffer = NULL;
     }
-  surface->pending.sx = 0;
-  surface->pending.sy = 0;
+  surface->pending.dx = 0;
+  surface->pending.dy = 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);
+  g_clear_pointer (&surface->pending.opaque_region, cairo_region_destroy);
+  g_clear_pointer (&surface->pending.input_region, cairo_region_destroy);
   empty_region (surface->pending.damage);
 
   /* wl_surface.frame */
@@ -633,34 +676,6 @@ shell_surface_resize (struct wl_client *client,
 }
 
 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)
 {
@@ -672,9 +687,19 @@ shell_surface_set_toplevel (struct wl_client *client,
   if (client == compositor->xwayland_client)
     return;
 
-  ensure_surface_window (surface);
+  if (surface->window)
+    {
+      if (surface->window->fullscreen)
+       meta_window_unmake_fullscreen (surface->window);
+      if (meta_window_get_maximized (surface->window) != 0)
+       meta_window_unmaximize (surface->window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
+    }
+  else
+    {
+      ensure_initial_state (surface);
 
-  meta_window_unmake_fullscreen (surface->window);
+      surface->initial_state->initial_type = META_WAYLAND_SURFACE_TOPLEVEL;
+    }
 }
 
 static void
@@ -687,13 +712,22 @@ shell_surface_set_transient (struct wl_client *client,
 {
   MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource);
   MetaWaylandSurface *surface = shell_surface->surface;
+  MetaWaylandSurface *parent_surface = wl_resource_get_user_data (parent);
   MetaWaylandCompositor *compositor = surface->compositor;
 
   /* NB: Surfaces from xwayland become managed based on X events. */
   if (client == compositor->xwayland_client)
     return;
 
-  ensure_surface_window (surface);
+  if (surface->window)
+    meta_window_set_transient_for (surface->window, parent_surface->window);
+  else
+    {
+      ensure_initial_state (surface);
+
+      surface->initial_state->initial_type = META_WAYLAND_SURFACE_TOPLEVEL;
+      surface->initial_state->transient_for = parent;
+    }
 }
 
 static void
@@ -711,9 +745,14 @@ shell_surface_set_fullscreen (struct wl_client *client,
   if (client == compositor->xwayland_client)
     return;
 
-  ensure_surface_window (surface);
+  if (surface->window)
+    meta_window_make_fullscreen (surface->window);
+  else
+    {
+      ensure_initial_state (surface);
 
-  meta_window_make_fullscreen (surface->window);
+      surface->initial_state->initial_type = META_WAYLAND_SURFACE_FULLSCREEN;
+    }
 }
 
 static void
@@ -733,7 +772,22 @@ 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");
+  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;
+
+  if (surface->window)
+    meta_window_maximize (surface->window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
+  else
+    {
+      ensure_initial_state (surface);
+
+      surface->initial_state->initial_type = META_WAYLAND_SURFACE_MAXIMIZED;
+    }
 }
 
 static void
@@ -813,7 +867,7 @@ destroy_surface_extension (struct wl_resource *resource)
   g_free (extension);
 }
 
-static void
+static MetaWaylandSurfaceExtension *
 create_surface_extension (struct wl_client          *client,
                          struct wl_resource        *master_resource,
                          guint32                    id,
@@ -834,6 +888,8 @@ create_surface_extension (struct wl_client          *client,
   extension->surface_destroy_listener.notify = extension_handle_surface_destroy;
   wl_resource_add_destroy_listener (surface->resource,
                                     &extension->surface_destroy_listener);
+
+  return extension;
 }
 
 static void
@@ -844,7 +900,7 @@ get_shell_surface (struct wl_client *client,
 {
   MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
 
-  if (surface->has_shell_surface)
+  if (surface->shell_surface)
     {
       wl_resource_post_error (surface_resource,
                               WL_DISPLAY_ERROR_INVALID_OBJECT,
@@ -852,10 +908,9 @@ get_shell_surface (struct wl_client *client,
       return;
     }
 
-  create_surface_extension (client, resource, id, surface,
-                           &wl_shell_surface_interface,
-                           &meta_wayland_shell_surface_interface);
-  surface->has_shell_surface = TRUE;
+  surface->shell_surface = create_surface_extension (client, resource, id, surface,
+                                                    &wl_shell_surface_interface,
+                                                    &meta_wayland_shell_surface_interface);
 }
 
 static const struct wl_shell_interface meta_wayland_shell_interface =
@@ -946,7 +1001,7 @@ get_gtk_surface (struct wl_client *client,
 {
   MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
 
-  if (surface->has_gtk_surface)
+  if (surface->gtk_surface)
     {
       wl_resource_post_error (surface_resource,
                               WL_DISPLAY_ERROR_INVALID_OBJECT,
@@ -954,10 +1009,9 @@ get_gtk_surface (struct wl_client *client,
       return;
     }
 
-  create_surface_extension (client, resource, id, surface,
-                           &gtk_surface_interface,
-                           &meta_wayland_gtk_surface_interface);
-  surface->has_gtk_surface = TRUE;
+  surface->gtk_surface = create_surface_extension (client, resource, id, surface,
+                                                  &gtk_surface_interface,
+                                                  &meta_wayland_gtk_surface_interface);
 }
 
 static const struct gtk_shell_interface meta_wayland_gtk_shell_interface =
@@ -1003,6 +1057,29 @@ meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface,
   if (initial == NULL)
     return;
 
+  /* Note that we poke at the bits directly here, because we're
+     in the middle of meta_window_new_shared() */
+  switch (initial->initial_type)
+    {
+    case META_WAYLAND_SURFACE_TOPLEVEL:
+      break;
+    case META_WAYLAND_SURFACE_FULLSCREEN:
+      window->fullscreen = TRUE;
+      break;
+    case META_WAYLAND_SURFACE_MAXIMIZED:
+      window->maximized_horizontally = window->maximized_vertically = TRUE;
+      break;
+    default:
+      g_assert_not_reached ();
+    }
+
+  if (initial->transient_for)
+    {
+      MetaWaylandSurface *parent = wl_resource_get_user_data (initial->transient_for);
+      if (parent)
+       window->transient_for = g_object_ref (parent->window);
+    }
+
   if (initial->title)
     meta_window_set_title (window, initial->title);
 
@@ -1045,3 +1122,14 @@ free_initial_state (MetaWaylandSurfaceInitialState *initial)
 
   g_slice_free (MetaWaylandSurfaceInitialState, initial);
 }
+
+void
+meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
+                                      int                 new_width,
+                                      int                 new_height,
+                                      int                 edges)
+{
+  if (surface->shell_surface)
+    wl_shell_surface_send_configure (surface->shell_surface->resource,
+                                    edges, new_width, new_height);
+}
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index 5957bce..dab4124 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -36,6 +36,7 @@ struct _MetaWaylandBuffer
   struct wl_signal destroy_signal;
   struct wl_listener destroy_listener;
 
+  CoglTexture *texture;
   int32_t width, height;
   uint32_t busy_count;
 };
@@ -52,8 +53,8 @@ typedef struct
   gboolean newly_attached;
   MetaWaylandBuffer *buffer;
   struct wl_listener buffer_destroy_listener;
-  int32_t sx;
-  int32_t sy;
+  int32_t dx;
+  int32_t dy;
 
   /* wl_surface.damage */
   cairo_region_t *damage;
@@ -65,8 +66,17 @@ typedef struct
   struct wl_list frame_callback_list;
 } MetaWaylandDoubleBufferedState;
 
+typedef enum {
+  META_WAYLAND_SURFACE_TOPLEVEL = 0,
+  META_WAYLAND_SURFACE_MAXIMIZED,
+  META_WAYLAND_SURFACE_FULLSCREEN
+} MetaWaylandSurfaceType;
+
 typedef struct
 {
+  MetaWaylandSurfaceType initial_type;
+  struct wl_resource *transient_for;
+
   char *title;
   char *wm_class;
 
@@ -78,17 +88,21 @@ typedef struct
   char *gtk_window_object_path;
 } MetaWaylandSurfaceInitialState;
 
+typedef struct
+{
+  MetaWaylandSurface *surface;
+  struct wl_resource *resource;
+  struct wl_listener surface_destroy_listener;
+} MetaWaylandSurfaceExtension;
+
 struct _MetaWaylandSurface
 {
   struct wl_resource *resource;
   MetaWaylandCompositor *compositor;
-  guint32 xid;
-  int x;
-  int y;
   MetaWaylandBufferReference buffer_ref;
   MetaWindow *window;
-  gboolean has_shell_surface;
-  gboolean has_gtk_surface;
+  MetaWaylandSurfaceExtension *shell_surface;
+  MetaWaylandSurfaceExtension *gtk_surface;
 
   /* All the pending state, that wl_surface.commit will apply. */
   MetaWaylandDoubleBufferedState pending;
@@ -98,13 +112,6 @@ struct _MetaWaylandSurface
   MetaWaylandSurfaceInitialState *initial_state;
 };
 
-typedef struct
-{
-  MetaWaylandSurface *surface;
-  struct wl_resource *resource;
-  struct wl_listener surface_destroy_listener;
-} MetaWaylandSurfaceExtension;
-
 void                meta_wayland_init_shell     (MetaWaylandCompositor *compositor);
 
 MetaWaylandSurface *meta_wayland_surface_create (MetaWaylandCompositor *compositor,
@@ -116,4 +123,9 @@ void                meta_wayland_surface_free   (MetaWaylandSurface    *surface)
 void                meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface,
                                                            MetaWindow         *window);
 
+void                meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
+                                                          int                 width,
+                                                          int                 height,
+                                                          int                 edges);
+
 #endif
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 5259025..90030ff 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -187,6 +187,7 @@ meta_wayland_buffer_reference (MetaWaylandBufferReference *ref,
 
       if (ref->buffer->busy_count == 0)
         {
+         g_clear_pointer (&ref->buffer->texture, cogl_object_unref);
           g_assert (wl_resource_get_client (ref->buffer->resource));
           wl_resource_queue_event (ref->buffer->resource, WL_BUFFER_RELEASE);
         }
@@ -609,8 +610,8 @@ synthesize_motion_event (MetaWaylandCompositor *compositor,
       device_event.event_y = wl_fixed_to_double (pointer->y);
     }
 
-  if (surface && surface->xid != None)
-    device_event.event = surface->xid;
+  if (surface && surface->window != NULL)
+    device_event.event = surface->window->xwindow;
   else
     device_event.event = device_event.root;
 
diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c
index 49cc51d..0e67c6d 100644
--- a/src/wayland/meta-xwayland.c
+++ b/src/wayland/meta-xwayland.c
@@ -45,10 +45,6 @@ xserver_set_window_id (struct wl_client *client,
   MetaDisplay *display = meta_get_display ();
   MetaWindow *window;
 
-  g_return_if_fail (surface->xid == None);
-
-  surface->xid = xid;
-
   window  = meta_display_lookup_x_window (display, xid);
   if (window)
     {


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