[mutter] window: Implement asynchronous popup moving



commit d08a8de2657c8a305847d625908eea0dd7bc8404
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Fri Feb 14 10:41:38 2020 +0100

    window: Implement asynchronous popup moving
    
    This commits adds support on the MetaWindow and constraints engine side
    for asynchronously repositioning a window with a placement rule, either
    due to environmental changes (e.g. parent moved) or explicitly done so
    via `meta_window_update_placement_rule()`.
    
    This is so far unused, as placement rules where this functionality is
    triggered are not yet constructed by the xdg-shell implementation, and
    no users of `meta_window_update_placement_rule()` exists yet.
    
    To summarize, it works by making it possible to produce placement rules
    with the parent rectangle a window should be placed against, while
    creating a pending configuration that is not applied until acknowledged
    by the client using the xdg-shell configure/ack_configure mechanisms.
    
    An "temporary" constrain result is added to deal with situations
    where the client window *must* move immediately even though it has not yet
    acknowledged a new configuration that was sent. This happens for example
    when the parent window is moved, causing the popup window to change its
    relative position e.g. because it ended up partially off-screen. In this
    situation, the temporary position corresponds to the result of the
    movement of the parent, while the pending (asynchronously configured)
    position is the relative one given the new constraining result.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/705

 src/core/constraints.c               | 129 ++++++++++++++++++------
 src/core/constraints.h               |   1 +
 src/core/window-private.h            |  18 +++-
 src/core/window.c                    |   8 +-
 src/wayland/meta-wayland-xdg-shell.c |  17 +++-
 src/wayland/meta-window-wayland.c    | 187 +++++++++++++++++++++++++----------
 src/wayland/meta-window-wayland.h    |   3 +
 src/x11/window-x11.c                 |   1 +
 8 files changed, 275 insertions(+), 89 deletions(-)
---
diff --git a/src/core/constraints.c b/src/core/constraints.c
index 79019b902..51006614f 100644
--- a/src/core/constraints.c
+++ b/src/core/constraints.c
@@ -123,6 +123,7 @@ typedef struct
 {
   MetaRectangle        orig;
   MetaRectangle        current;
+  MetaRectangle        temporary;
   int                  rel_x;
   int                  rel_y;
   ActionType           action_type;
@@ -147,6 +148,8 @@ typedef struct
    */
   GList  *usable_screen_region;
   GList  *usable_monitor_region;
+
+  MetaMoveResizeFlags  flags;
 } ConstraintInfo;
 
 static gboolean do_screen_and_monitor_relative_constraints (MetaWindow     *window,
@@ -284,6 +287,7 @@ meta_window_constrain (MetaWindow          *window,
                        MetaGravity          resize_gravity,
                        const MetaRectangle *orig,
                        MetaRectangle       *new,
+                       MetaRectangle       *temporary,
                        int                 *rel_x,
                        int                 *rel_y)
 {
@@ -322,6 +326,7 @@ meta_window_constrain (MetaWindow          *window,
 
   /* Make sure we use the constrained position */
   *new = info.current;
+  *temporary = info.temporary;
   *rel_x = info.rel_x;
   *rel_y = info.rel_y;
 
@@ -348,8 +353,10 @@ setup_constraint_info (ConstraintInfo      *info,
 
   info->orig    = *orig;
   info->current = *new;
+  info->temporary = *orig;
   info->rel_x = 0;
   info->rel_y = 0;
+  info->flags = flags;
 
   if (info->current.width < 1)
     info->current.width = 1;
@@ -500,16 +507,11 @@ place_window_if_needed(MetaWindow     *window,
 
       if (window->placement.rule)
         {
-          MetaWindow *parent = meta_window_get_transient_for (window);
-          MetaRectangle parent_rect;
-
           meta_window_process_placement (window,
                                          window->placement.rule,
                                          &info->rel_x, &info->rel_y);
-          meta_window_get_frame_rect (parent, &parent_rect);
-
-          placed_rect.x = parent_rect.x + info->rel_x;
-          placed_rect.y = parent_rect.y + info->rel_y;
+          placed_rect.x = window->placement.rule->parent_rect.x + info->rel_x;
+          placed_rect.y = window->placement.rule->parent_rect.y + info->rel_y;
         }
       else
         {
@@ -825,12 +827,13 @@ constrain_custom_rule (MetaWindow         *window,
   MetaPlacementRule *placement_rule;
   MetaRectangle intersection;
   gboolean constraint_satisfied;
+  MetaRectangle temporary_rect;
   MetaRectangle adjusted_unconstrained;
   int adjusted_rel_x;
   int adjusted_rel_y;
   MetaPlacementRule current_rule;
   MetaWindow *parent;
-  MetaRectangle parent_rect;
+  int parent_x, parent_y;
 
   if (priority > PRIORITY_CUSTOM_RULE)
     return TRUE;
@@ -839,25 +842,72 @@ constrain_custom_rule (MetaWindow         *window,
   if (!placement_rule)
     return TRUE;
 
-  adjusted_unconstrained = info->current;
-
   parent = meta_window_get_transient_for (window);
-  meta_window_get_frame_rect (parent, &parent_rect);
+  if (window->placement.state == META_PLACEMENT_STATE_CONSTRAINED_FINISHED)
+    {
+      placement_rule->parent_rect.x = parent->rect.x;
+      placement_rule->parent_rect.y = parent->rect.y;
+    }
+  parent_x = placement_rule->parent_rect.x;
+  parent_y = placement_rule->parent_rect.y;
+
+  /*
+   * Calculate the temporary position, meaning a position that will be
+   * applied if the new constrained position requires asynchronous
+   * configuration of the window. This happens for example when the parent
+   * moves, causing this window to change relative position, meaning it can
+   * only have its newly constrained position applied when the configuration is
+   * acknowledged.
+   */
 
   switch (window->placement.state)
     {
     case META_PLACEMENT_STATE_UNCONSTRAINED:
-      adjusted_rel_x = window->rect.x - parent->rect.x;
-      adjusted_rel_y = window->rect.y - parent->rect.y;
+      temporary_rect = info->current;
       break;
-    case META_PLACEMENT_STATE_CONSTRAINED:
-      adjusted_unconstrained.x =
-        parent->rect.x + window->placement.current.rel_x;
-      adjusted_unconstrained.y =
-        parent->rect.y + window->placement.current.rel_y;
+    case META_PLACEMENT_STATE_CONSTRAINED_CONFIGURED:
+    case META_PLACEMENT_STATE_CONSTRAINED_PENDING:
+    case META_PLACEMENT_STATE_CONSTRAINED_FINISHED:
+    case META_PLACEMENT_STATE_INVALIDATED:
+      temporary_rect = (MetaRectangle) {
+        .x = parent->rect.x + window->placement.current.rel_x,
+        .y = parent->rect.y + window->placement.current.rel_y,
+        .width = info->current.width,
+        .height = info->current.height,
+      };
+      break;
+    }
+
+  /*
+   * Calculate an adjusted current position. Depending on the rule
+   * configuration and placement state, this may result in window being
+   * reconstrained.
+   */
+
+  adjusted_unconstrained = temporary_rect;
+
+  if (window->placement.state == META_PLACEMENT_STATE_INVALIDATED ||
+      window->placement.state == META_PLACEMENT_STATE_UNCONSTRAINED ||
+      (window->placement.state == META_PLACEMENT_STATE_CONSTRAINED_FINISHED &&
+       placement_rule->is_reactive))
+    {
+      meta_window_process_placement (window, placement_rule,
+                                     &adjusted_rel_x,
+                                     &adjusted_rel_y);
+      adjusted_unconstrained.x = parent_x + adjusted_rel_x;
+      adjusted_unconstrained.y = parent_y + adjusted_rel_y;
+    }
+  else if (window->placement.state == META_PLACEMENT_STATE_CONSTRAINED_PENDING)
+    {
+      adjusted_rel_x = window->placement.pending.rel_x;
+      adjusted_rel_y = window->placement.pending.rel_y;
+      adjusted_unconstrained.x = window->placement.pending.x;
+      adjusted_unconstrained.y = window->placement.pending.y;
+    }
+  else
+    {
       adjusted_rel_x = window->placement.current.rel_x;
       adjusted_rel_y = window->placement.current.rel_y;
-      break;
     }
 
   meta_rectangle_intersect (&adjusted_unconstrained, &info->work_area_monitor,
@@ -872,30 +922,43 @@ constrain_custom_rule (MetaWindow         *window,
   if (check_only)
     return constraint_satisfied;
 
-  current_rule = *placement_rule;
+  info->current = adjusted_unconstrained;
+  info->rel_x = adjusted_rel_x;
+  info->rel_y = adjusted_rel_y;
+  info->temporary = temporary_rect;
 
   switch (window->placement.state)
     {
-    case META_PLACEMENT_STATE_CONSTRAINED:
-      info->current = adjusted_unconstrained;
-      info->rel_x = adjusted_rel_x;
-      info->rel_y = adjusted_rel_y;
-      goto done;
+    case META_PLACEMENT_STATE_CONSTRAINED_FINISHED:
+      if (!placement_rule->is_reactive)
+        return TRUE;
+      break;
+    case META_PLACEMENT_STATE_CONSTRAINED_PENDING:
+    case META_PLACEMENT_STATE_CONSTRAINED_CONFIGURED:
+      return TRUE;
     case META_PLACEMENT_STATE_UNCONSTRAINED:
+    case META_PLACEMENT_STATE_INVALIDATED:
       break;
     }
 
   if (constraint_satisfied)
     goto done;
 
+  /*
+   * Process the placement rule in order either until constraints are
+   * satisfied, or there are no more rules to process.
+   */
+
+  current_rule = *placement_rule;
+
   if (info->current.width != intersection.width &&
       (current_rule.constraint_adjustment &
        META_PLACEMENT_CONSTRAINT_ADJUSTMENT_FLIP_X))
     {
       try_flip_window_position (window, info, &current_rule,
                                 META_PLACEMENT_CONSTRAINT_ADJUSTMENT_FLIP_X,
-                                parent_rect.x,
-                                parent_rect.y,
+                                parent_x,
+                                parent_y,
                                 &info->current,
                                 &info->rel_x,
                                 &info->rel_y,
@@ -907,8 +970,8 @@ constrain_custom_rule (MetaWindow         *window,
     {
       try_flip_window_position (window, info, &current_rule,
                                 META_PLACEMENT_CONSTRAINT_ADJUSTMENT_FLIP_Y,
-                                parent_rect.x,
-                                parent_rect.y,
+                                parent_x,
+                                parent_y,
                                 &info->current,
                                 &info->rel_x,
                                 &info->rel_y,
@@ -1010,10 +1073,12 @@ constrain_custom_rule (MetaWindow         *window,
     }
 
 done:
-  window->placement.state = META_PLACEMENT_STATE_CONSTRAINED;
+  window->placement.state = META_PLACEMENT_STATE_CONSTRAINED_PENDING;
 
-  window->placement.current.rel_x = info->rel_x;
-  window->placement.current.rel_y = info->rel_y;
+  window->placement.pending.rel_x = info->rel_x;
+  window->placement.pending.rel_y = info->rel_y;
+  window->placement.pending.x = info->current.x;
+  window->placement.pending.y = info->current.y;
 
   return TRUE;
 }
diff --git a/src/core/constraints.h b/src/core/constraints.h
index 1517aa060..eaa4e4594 100644
--- a/src/core/constraints.h
+++ b/src/core/constraints.h
@@ -32,6 +32,7 @@ void meta_window_constrain (MetaWindow          *window,
                             MetaGravity          resize_gravity,
                             const MetaRectangle *orig,
                             MetaRectangle       *new,
+                            MetaRectangle       *intermediate,
                             int                 *rel_x,
                             int                 *rel_y);
 
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 04216113e..07f316e90 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -85,6 +85,7 @@ typedef enum
   META_MOVE_RESIZE_FORCE_MOVE = 1 << 8,
   META_MOVE_RESIZE_WAYLAND_STATE_CHANGED = 1 << 9,
   META_MOVE_RESIZE_FORCE_UPDATE_MONITOR = 1 << 10,
+  META_MOVE_RESIZE_PLACEMENT_CHANGED = 1 << 11,
 } MetaMoveResizeFlags;
 
 typedef enum
@@ -141,12 +142,19 @@ typedef struct _MetaPlacementRule
   int offset_y;
   int width;
   int height;
+
+  gboolean is_reactive;
+
+  MetaRectangle parent_rect;
 } MetaPlacementRule;
 
 typedef enum _MetaPlacementState
 {
   META_PLACEMENT_STATE_UNCONSTRAINED,
-  META_PLACEMENT_STATE_CONSTRAINED,
+  META_PLACEMENT_STATE_CONSTRAINED_PENDING,
+  META_PLACEMENT_STATE_CONSTRAINED_CONFIGURED,
+  META_PLACEMENT_STATE_CONSTRAINED_FINISHED,
+  META_PLACEMENT_STATE_INVALIDATED,
 } MetaPlacementState;
 
 typedef enum
@@ -538,6 +546,13 @@ struct _MetaWindow
     MetaPlacementRule *rule;
     MetaPlacementState state;
 
+    struct {
+      int x;
+      int y;
+      int rel_x;
+      int rel_y;
+    } pending;
+
     struct {
       int rel_x;
       int rel_y;
@@ -569,6 +584,7 @@ struct _MetaWindowClass
                                   MetaGravity                gravity,
                                   MetaRectangle              unconstrained_rect,
                                   MetaRectangle              constrained_rect,
+                                  MetaRectangle              temporary_rect,
                                   int                        rel_x,
                                   int                        rel_y,
                                   MetaMoveResizeFlags        flags,
diff --git a/src/core/window.c b/src/core/window.c
index 6573c217e..5a9341578 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -4001,6 +4001,7 @@ meta_window_move_resize_internal (MetaWindow          *window,
   gboolean did_placement;
   MetaRectangle unconstrained_rect;
   MetaRectangle constrained_rect;
+  MetaRectangle temporary_rect;
   int rel_x = 0;
   int rel_y = 0;
   MetaMoveResizeResultFlags result = 0;
@@ -4057,6 +4058,7 @@ meta_window_move_resize_internal (MetaWindow          *window,
     g_assert_not_reached ();
 
   constrained_rect = unconstrained_rect;
+  temporary_rect = window->rect;
   if (flags & (META_MOVE_RESIZE_MOVE_ACTION | META_MOVE_RESIZE_RESIZE_ACTION) &&
       !(flags & META_MOVE_RESIZE_WAYLAND_FINISH_MOVE_RESIZE) &&
       window->monitor)
@@ -4069,13 +4071,14 @@ meta_window_move_resize_internal (MetaWindow          *window,
                              gravity,
                              &old_rect,
                              &constrained_rect,
+                             &temporary_rect,
                              &rel_x,
                              &rel_y);
     }
   else if (window->placement.rule)
     {
-      rel_x = window->placement.current.rel_x;
-      rel_y = window->placement.current.rel_y;
+      rel_x = window->placement.pending.rel_x;
+      rel_y = window->placement.pending.rel_y;
     }
 
   /* If we did placement, then we need to save the position that the window
@@ -4093,6 +4096,7 @@ meta_window_move_resize_internal (MetaWindow          *window,
                                                         gravity,
                                                         unconstrained_rect,
                                                         constrained_rect,
+                                                        temporary_rect,
                                                         rel_x,
                                                         rel_y,
                                                         flags, &result);
diff --git a/src/wayland/meta-wayland-xdg-shell.c b/src/wayland/meta-wayland-xdg-shell.c
index 89e33d5d3..8f4b7a0e7 100644
--- a/src/wayland/meta-wayland-xdg-shell.c
+++ b/src/wayland/meta-wayland-xdg-shell.c
@@ -138,7 +138,8 @@ G_DEFINE_TYPE_WITH_CODE (MetaWaylandXdgPopup,
                                                 popup_surface_iface_init));
 
 static MetaPlacementRule
-meta_wayland_xdg_positioner_to_placement (MetaWaylandXdgPositioner *xdg_positioner);
+meta_wayland_xdg_positioner_to_placement (MetaWaylandXdgPositioner *xdg_positioner,
+                                          MetaWindow               *parent_window);
 
 static struct wl_resource *
 meta_wayland_xdg_surface_get_wm_base_resource (MetaWaylandXdgSurface *xdg_surface);
@@ -1745,6 +1746,7 @@ xdg_surface_constructor_get_popup (struct wl_client   *client,
   struct wl_resource *xdg_surface_resource = constructor->resource;
   MetaWaylandSurface *parent_surface =
     surface_from_xdg_surface_resource (parent_resource);
+  MetaWindow *parent_window;
   MetaWaylandXdgPositioner *xdg_positioner;
   MetaWaylandXdgPopup *xdg_popup;
   MetaWaylandXdgSurface *xdg_surface;
@@ -1783,9 +1785,11 @@ xdg_surface_constructor_get_popup (struct wl_client   *client,
   xdg_surface = META_WAYLAND_XDG_SURFACE (xdg_popup);
   meta_wayland_xdg_surface_constructor_finalize (constructor, xdg_surface);
 
+  parent_window = meta_wayland_surface_get_window (parent_surface);
+
   xdg_positioner = wl_resource_get_user_data (positioner_resource);
   xdg_popup->setup.placement_rule =
-    meta_wayland_xdg_positioner_to_placement (xdg_positioner);
+    meta_wayland_xdg_positioner_to_placement (xdg_positioner, parent_window);
   xdg_popup->setup.parent_surface = parent_surface;
 }
 
@@ -1892,8 +1896,13 @@ positioner_gravity_to_placement_gravity (uint32_t gravity)
 }
 
 static MetaPlacementRule
-meta_wayland_xdg_positioner_to_placement (MetaWaylandXdgPositioner *xdg_positioner)
+meta_wayland_xdg_positioner_to_placement (MetaWaylandXdgPositioner *xdg_positioner,
+                                          MetaWindow               *parent_window)
 {
+  MetaRectangle parent_rect;
+
+  meta_window_get_frame_rect (parent_window, &parent_rect);
+
   return (MetaPlacementRule) {
     .anchor_rect = xdg_positioner->anchor_rect,
     .gravity = positioner_gravity_to_placement_gravity (xdg_positioner->gravity),
@@ -1903,6 +1912,8 @@ meta_wayland_xdg_positioner_to_placement (MetaWaylandXdgPositioner *xdg_position
     .offset_y = xdg_positioner->offset_y,
     .width = xdg_positioner->width,
     .height = xdg_positioner->height,
+
+    .parent_rect = parent_rect,
   };
 }
 
diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c
index e86378995..80be4b7a3 100644
--- a/src/wayland/meta-window-wayland.c
+++ b/src/wayland/meta-window-wayland.c
@@ -222,18 +222,23 @@ meta_window_wayland_move_resize_internal (MetaWindow                *window,
                                           MetaGravity                gravity,
                                           MetaRectangle              unconstrained_rect,
                                           MetaRectangle              constrained_rect,
+                                          MetaRectangle              temporary_rect,
                                           int                        rel_x,
                                           int                        rel_y,
                                           MetaMoveResizeFlags        flags,
                                           MetaMoveResizeResultFlags *result)
 {
   MetaWindowWayland *wl_window = META_WINDOW_WAYLAND (window);
-  gboolean can_move_now;
+  gboolean can_move_now = FALSE;
   int configured_x;
   int configured_y;
   int configured_width;
   int configured_height;
   int geometry_scale;
+  int new_x;
+  int new_y;
+  int new_buffer_x;
+  int new_buffer_y;
 
   g_assert (window->frame == NULL);
 
@@ -300,14 +305,61 @@ meta_window_wayland_move_resize_internal (MetaWindow                *window,
       /* This is a commit of an attach. We should move the window to match the
        * new position the client wants. */
       can_move_now = TRUE;
+      if (window->placement.state == META_PLACEMENT_STATE_CONSTRAINED_CONFIGURED)
+        window->placement.state = META_PLACEMENT_STATE_CONSTRAINED_FINISHED;
     }
   else
     {
-      /* If the size changed, or the state changed, then we have to wait until
-       * the client acks our configure before moving the window. */
-      if (constrained_rect.width != window->rect.width ||
-          constrained_rect.height != window->rect.height ||
-          (flags & META_MOVE_RESIZE_STATE_CHANGED))
+      if (window->placement.rule)
+        {
+          switch (window->placement.state)
+            {
+            case META_PLACEMENT_STATE_UNCONSTRAINED:
+            case META_PLACEMENT_STATE_CONSTRAINED_CONFIGURED:
+            case META_PLACEMENT_STATE_INVALIDATED:
+              can_move_now = FALSE;
+              break;
+            case META_PLACEMENT_STATE_CONSTRAINED_PENDING:
+              {
+                if (flags & META_MOVE_RESIZE_PLACEMENT_CHANGED ||
+                    rel_x != wl_window->last_sent_rel_x ||
+                    rel_y != wl_window->last_sent_rel_y ||
+                    constrained_rect.width != window->rect.width ||
+                    constrained_rect.height != window->rect.height)
+                  {
+                    MetaWaylandWindowConfiguration *configuration;
+
+                    configuration =
+                      meta_wayland_window_configuration_new_relative (rel_x,
+                                                                      rel_y,
+                                                                      configured_width,
+                                                                      configured_height);
+                    meta_window_wayland_configure (wl_window, configuration);
+
+                    wl_window->last_sent_rel_x = rel_x;
+                    wl_window->last_sent_rel_y = rel_y;
+
+                    window->placement.state = META_PLACEMENT_STATE_CONSTRAINED_CONFIGURED;
+
+                    can_move_now = FALSE;
+                  }
+                else
+                  {
+                    window->placement.state =
+                      META_PLACEMENT_STATE_CONSTRAINED_FINISHED;
+
+                    can_move_now = TRUE;
+                  }
+                break;
+              }
+            case META_PLACEMENT_STATE_CONSTRAINED_FINISHED:
+              can_move_now = TRUE;
+              break;
+            }
+        }
+      else if (constrained_rect.width != window->rect.width ||
+               constrained_rect.height != window->rect.height ||
+               flags & META_MOVE_RESIZE_STATE_CHANGED)
         {
           MetaWaylandWindowConfiguration *configuration;
 
@@ -328,32 +380,18 @@ meta_window_wayland_move_resize_internal (MetaWindow                *window,
               constrained_rect.height == 1)
             return;
 
-          if (window->placement.rule)
-            {
-              configuration =
-                meta_wayland_window_configuration_new_relative (rel_x,
-                                                                rel_y,
-                                                                configured_width,
-                                                                configured_height);
-            }
-          else
-            {
-              configuration =
-                meta_wayland_window_configuration_new (configured_x,
-                                                       configured_y,
-                                                       configured_width,
-                                                       configured_height,
-                                                       flags,
-                                                       gravity);
-            }
-
+          configuration =
+            meta_wayland_window_configuration_new (configured_x,
+                                                   configured_y,
+                                                   configured_width,
+                                                   configured_height,
+                                                   flags,
+                                                   gravity);
           meta_window_wayland_configure (wl_window, configuration);
           can_move_now = FALSE;
         }
       else
         {
-          /* We're just moving the window, so we don't need to wait for a configure
-           * and then ack to simply move the window. */
           can_move_now = TRUE;
         }
     }
@@ -365,33 +403,46 @@ meta_window_wayland_move_resize_internal (MetaWindow                *window,
 
   if (can_move_now)
     {
-      int new_x = constrained_rect.x;
-      int new_y = constrained_rect.y;
-
-      if (new_x != window->rect.x || new_y != window->rect.y)
-        {
-          *result |= META_MOVE_RESIZE_RESULT_MOVED;
-          window->rect.x = new_x;
-          window->rect.y = new_y;
-        }
+      new_x = constrained_rect.x;
+      new_y = constrained_rect.y;
+    }
+  else
+    {
+      new_x = temporary_rect.x;
+      new_y = temporary_rect.y;
 
-      int new_buffer_x = new_x - window->custom_frame_extents.left;
-      int new_buffer_y = new_y - window->custom_frame_extents.top;
+      wl_window->has_pending_state_change |=
+        !!(flags & META_MOVE_RESIZE_STATE_CHANGED);
+    }
 
-      if (new_buffer_x != window->buffer_rect.x || new_buffer_y != window->buffer_rect.y)
-        {
-          *result |= META_MOVE_RESIZE_RESULT_MOVED;
-          window->buffer_rect.x = new_buffer_x;
-          window->buffer_rect.y = new_buffer_y;
-        }
+  if (new_x != window->rect.x || new_y != window->rect.y)
+    {
+      *result |= META_MOVE_RESIZE_RESULT_MOVED;
+      window->rect.x = new_x;
+      window->rect.y = new_y;
+    }
 
-      if (flags & META_MOVE_RESIZE_WAYLAND_STATE_CHANGED)
-        *result |= META_MOVE_RESIZE_RESULT_STATE_CHANGED;
+  if (window->placement.rule &&
+      window->placement.state == META_PLACEMENT_STATE_CONSTRAINED_FINISHED)
+    {
+      window->placement.current.rel_x = rel_x;
+      window->placement.current.rel_y = rel_y;
     }
-  else
+
+  new_buffer_x = new_x - window->custom_frame_extents.left;
+  new_buffer_y = new_y - window->custom_frame_extents.top;
+
+  if (new_buffer_x != window->buffer_rect.x ||
+      new_buffer_y != window->buffer_rect.y)
     {
-      wl_window->has_pending_state_change = (flags & META_MOVE_RESIZE_STATE_CHANGED) != 0;
+      *result |= META_MOVE_RESIZE_RESULT_MOVED;
+      window->buffer_rect.x = new_buffer_x;
+      window->buffer_rect.y = new_buffer_y;
     }
+
+  if (can_move_now &&
+      flags & META_MOVE_RESIZE_WAYLAND_STATE_CHANGED)
+    *result |= META_MOVE_RESIZE_RESULT_STATE_CHANGED;
 }
 
 static void
@@ -857,8 +908,19 @@ meta_window_wayland_finish_move_resize (MetaWindow              *window,
     {
       if (acked_configuration)
         {
-          rect.x = acked_configuration->x;
-          rect.y = acked_configuration->y;
+          if (window->placement.rule)
+            {
+              MetaWindow *parent;
+
+              parent = meta_window_get_transient_for (window);
+              rect.x = parent->rect.x + acked_configuration->rel_x;
+              rect.y = parent->rect.y + acked_configuration->rel_y;
+            }
+          else
+            {
+              rect.x = acked_configuration->x;
+              rect.y = acked_configuration->y;
+            }
         }
       else
         {
@@ -872,6 +934,14 @@ meta_window_wayland_finish_move_resize (MetaWindow              *window,
       if (rect.x != window->rect.x || rect.y != window->rect.y)
         flags |= META_MOVE_RESIZE_MOVE_ACTION;
     }
+  else
+    {
+      if (acked_configuration)
+        {
+          rect.x = acked_configuration->x;
+          rect.y = acked_configuration->y;
+        }
+    }
 
   if (wl_window->has_pending_state_change && acked_configuration)
     {
@@ -918,9 +988,24 @@ meta_window_place_with_placement_rule (MetaWindow        *window,
   window->placement.rule = g_new0 (MetaPlacementRule, 1);
   *window->placement.rule = *placement_rule;
 
+  window->unconstrained_rect.x = window->rect.x;
+  window->unconstrained_rect.y = window->rect.y;
   window->unconstrained_rect.width = placement_rule->width;
   window->unconstrained_rect.height = placement_rule->height;
-  meta_window_force_placement (window, FALSE);
+  meta_window_move_resize_internal (window,
+                                    (META_MOVE_RESIZE_MOVE_ACTION |
+                                     META_MOVE_RESIZE_RESIZE_ACTION |
+                                     META_MOVE_RESIZE_PLACEMENT_CHANGED),
+                                    META_GRAVITY_NORTH_WEST,
+                                    window->unconstrained_rect);
+}
+
+void
+meta_window_update_placement_rule (MetaWindow        *window,
+                                   MetaPlacementRule *placement_rule)
+{
+  window->placement.state = META_PLACEMENT_STATE_INVALIDATED;
+  meta_window_place_with_placement_rule (window, placement_rule);
 }
 
 void
diff --git a/src/wayland/meta-window-wayland.h b/src/wayland/meta-window-wayland.h
index 0e18d4fe1..22824a6ae 100644
--- a/src/wayland/meta-window-wayland.h
+++ b/src/wayland/meta-window-wayland.h
@@ -53,6 +53,9 @@ void meta_window_wayland_place_relative_to (MetaWindow *window,
 void meta_window_place_with_placement_rule (MetaWindow        *window,
                                             MetaPlacementRule *placement_rule);
 
+void meta_window_update_placement_rule (MetaWindow        *window,
+                                        MetaPlacementRule *placement_rule);
+
 void meta_window_wayland_set_min_size (MetaWindow *window,
                                        int         width,
                                        int         height);
diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c
index fcd06f632..2c745f4aa 100644
--- a/src/x11/window-x11.c
+++ b/src/x11/window-x11.c
@@ -1312,6 +1312,7 @@ meta_window_x11_move_resize_internal (MetaWindow                *window,
                                       MetaGravity                gravity,
                                       MetaRectangle              unconstrained_rect,
                                       MetaRectangle              constrained_rect,
+                                      MetaRectangle              intermediate_rect,
                                       int                        rel_x,
                                       int                        rel_y,
                                       MetaMoveResizeFlags        flags,


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