[mutter] wayland/xdg-shell: Add support for explicit popup repositioning



commit f97804f4f469753806a51dec02ca9042a515609d
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Fri Feb 14 11:13:24 2020 +0100

    wayland/xdg-shell: Add support for explicit popup repositioning
    
    This commit completes the implementation of `xdg_wm_base` version 3,
    which introduces support for synchronized implicit and explicit popup
    repositioning.
    
    Explicit repositioning works by the client providing a new
    `xdg_positioner` object via a new request `xdg_popup.reposition`. If the
    repositioning is done in combination with the parent itself being
    reconfigured, the to be committed state of the parent is provided by the
    client via the `xdg_positioner` object, using
    `xdg_positioner.set__parent_configure`.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/705

 src/wayland/meta-wayland-versions.h  |   2 +-
 src/wayland/meta-wayland-xdg-shell.c | 126 +++++++++++++++++++++++++++++++++++
 src/wayland/meta-window-wayland.c    |  17 +++++
 src/wayland/meta-window-wayland.h    |   4 ++
 4 files changed, 148 insertions(+), 1 deletion(-)
---
diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h
index f5dc10484..2d6ce5ace 100644
--- a/src/wayland/meta-wayland-versions.h
+++ b/src/wayland/meta-wayland-versions.h
@@ -37,7 +37,7 @@
 /* Global/master objects (version exported by wl_registry and negotiated through bind) */
 #define META_WL_COMPOSITOR_VERSION          4
 #define META_WL_DATA_DEVICE_MANAGER_VERSION 3
-#define META_XDG_WM_BASE_VERSION            2
+#define META_XDG_WM_BASE_VERSION            3
 #define META_ZXDG_SHELL_V6_VERSION          1
 #define META_WL_SHELL_VERSION               1
 #define META_WL_SEAT_VERSION                5
diff --git a/src/wayland/meta-wayland-xdg-shell.c b/src/wayland/meta-wayland-xdg-shell.c
index 3aad9fe5b..fefed4596 100644
--- a/src/wayland/meta-wayland-xdg-shell.c
+++ b/src/wayland/meta-wayland-xdg-shell.c
@@ -68,6 +68,13 @@ typedef struct _MetaWaylandXdgPositioner
   int32_t offset_y;
 
   gboolean is_reactive;
+
+  gboolean has_parent_size;
+  int32_t parent_width;
+  int32_t parent_height;
+
+  gboolean acked_parent_configure;
+  uint32_t parent_configure_serial;
 } MetaWaylandXdgPositioner;
 
 typedef struct _MetaWaylandXdgSurfaceConstructor
@@ -112,6 +119,9 @@ struct _MetaWaylandXdgPopup
   MetaWaylandSurface *parent_surface;
   gulong parent_surface_unmapped_handler_id;
 
+  uint32_t pending_reposition_token;
+  gboolean pending_repositioned;
+
   MetaWaylandPopup *popup;
 
   gboolean dismissed_by_client;
@@ -153,6 +163,10 @@ static void
 meta_wayland_xdg_surface_send_configure (MetaWaylandXdgSurface          *xdg_surface,
                                          MetaWaylandWindowConfiguration *configuration);
 
+static void
+scale_placement_rule (MetaPlacementRule  *placement_rule,
+                      MetaWaylandSurface *surface);
+
 static MetaWaylandSurface *
 surface_from_xdg_surface_resource (struct wl_resource *resource)
 {
@@ -566,9 +580,45 @@ xdg_popup_grab (struct wl_client   *client,
   xdg_popup->setup.grab_serial = serial;
 }
 
+static void
+xdg_popup_reposition (struct wl_client   *client,
+                      struct wl_resource *resource,
+                      struct wl_resource *positioner_resource,
+                      uint32_t            token)
+{
+  MetaWaylandXdgPopup *xdg_popup =
+    META_WAYLAND_XDG_POPUP (wl_resource_get_user_data (resource));
+  MetaWaylandSurfaceRole *surface_role =
+    META_WAYLAND_SURFACE_ROLE (xdg_popup);
+  MetaWaylandSurface *surface =
+    meta_wayland_surface_role_get_surface (surface_role);
+  MetaWindow *window;
+  MetaWindow *parent_window;
+  MetaWaylandXdgPositioner *xdg_positioner;
+  MetaPlacementRule placement_rule;
+
+  window = meta_wayland_surface_get_window (surface);
+  if (!window)
+    return;
+
+  parent_window = meta_wayland_surface_get_window (xdg_popup->parent_surface);
+
+  xdg_positioner = wl_resource_get_user_data (positioner_resource);
+  placement_rule = meta_wayland_xdg_positioner_to_placement (xdg_positioner,
+                                                             parent_window);
+
+  xdg_popup->pending_reposition_token = token;
+  xdg_popup->pending_repositioned = TRUE;
+
+  scale_placement_rule (&placement_rule, surface);
+
+  meta_window_update_placement_rule (window, &placement_rule);
+}
+
 static const struct xdg_popup_interface meta_wayland_xdg_popup_interface = {
   xdg_popup_destroy,
   xdg_popup_grab,
+  xdg_popup_reposition,
 };
 
 static void
@@ -1150,6 +1200,12 @@ meta_wayland_xdg_popup_configure (MetaWaylandShellSurface        *shell_surface,
   geometry_scale = meta_window_wayland_get_geometry_scale (parent_window);
   x = configuration->rel_x / geometry_scale;
   y = configuration->rel_y / geometry_scale;
+  if (xdg_popup->pending_repositioned)
+    {
+      xdg_popup_send_repositioned (xdg_popup->resource,
+                                   xdg_popup->pending_reposition_token);
+      xdg_popup->pending_repositioned = FALSE;
+    }
   xdg_popup_send_configure (xdg_popup->resource,
                             x, y,
                             configuration->width, configuration->height);
@@ -1905,6 +1961,50 @@ meta_wayland_xdg_positioner_to_placement (MetaWaylandXdgPositioner *xdg_position
 
   meta_window_get_frame_rect (parent_window, &parent_rect);
 
+  if (xdg_positioner->acked_parent_configure)
+    {
+      MetaWindowWayland *parent_wl_window = META_WINDOW_WAYLAND (parent_window);
+      uint32_t serial;
+      MetaWaylandWindowConfiguration *configuration;
+
+      serial = xdg_positioner->parent_configure_serial;
+      configuration = meta_window_wayland_peek_configuration (parent_wl_window,
+                                                              serial);
+
+      if (configuration)
+        {
+          if (configuration->flags & META_MOVE_RESIZE_STATE_CHANGED)
+            {
+              if (configuration->has_position)
+                {
+                  parent_rect.x = configuration->x;
+                  parent_rect.y = configuration->y;
+                }
+              if (configuration->has_size)
+                {
+                  parent_rect.width = configuration->width;
+                  parent_rect.height = configuration->height;
+                }
+            }
+          else if (xdg_positioner->has_parent_size)
+            {
+              meta_rectangle_resize_with_gravity (&parent_rect,
+                                                  &parent_rect,
+                                                  configuration->gravity,
+                                                  xdg_positioner->parent_width,
+                                                  xdg_positioner->parent_height);
+            }
+        }
+    }
+  else if (xdg_positioner->has_parent_size)
+    {
+      meta_rectangle_resize_with_gravity (&parent_rect,
+                                          &parent_rect,
+                                          META_GRAVITY_SOUTH_EAST,
+                                          xdg_positioner->parent_width,
+                                          xdg_positioner->parent_height);
+    }
+
   return (MetaPlacementRule) {
     .anchor_rect = xdg_positioner->anchor_rect,
     .gravity = positioner_gravity_to_placement_gravity (xdg_positioner->gravity),
@@ -2050,6 +2150,30 @@ xdg_positioner_set_reactive (struct wl_client   *client,
   positioner->is_reactive = TRUE;
 }
 
+static void
+xdg_positioner_set_parent_size (struct wl_client   *client,
+                                struct wl_resource *resource,
+                                int32_t             parent_width,
+                                int32_t             parent_height)
+{
+  MetaWaylandXdgPositioner *positioner = wl_resource_get_user_data (resource);
+
+  positioner->has_parent_size = TRUE;
+  positioner->parent_width = parent_width;
+  positioner->parent_height = parent_height;
+}
+
+static void
+xdg_positioner_set_parent_configure (struct wl_client   *client,
+                                     struct wl_resource *resource,
+                                     uint32_t            serial)
+{
+  MetaWaylandXdgPositioner *positioner = wl_resource_get_user_data (resource);
+
+  positioner->acked_parent_configure = TRUE;
+  positioner->parent_configure_serial = serial;
+}
+
 static const struct xdg_positioner_interface meta_wayland_xdg_positioner_interface = {
   xdg_positioner_destroy,
   xdg_positioner_set_size,
@@ -2059,6 +2183,8 @@ static const struct xdg_positioner_interface meta_wayland_xdg_positioner_interfa
   xdg_positioner_set_constraint_adjustment,
   xdg_positioner_set_offset,
   xdg_positioner_set_reactive,
+  xdg_positioner_set_parent_size,
+  xdg_positioner_set_parent_configure,
 };
 
 static void
diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c
index 80be4b7a3..9864d2fd4 100644
--- a/src/wayland/meta-window-wayland.c
+++ b/src/wayland/meta-window-wayland.c
@@ -800,6 +800,23 @@ meta_window_wayland_new (MetaDisplay        *display,
   return window;
 }
 
+MetaWaylandWindowConfiguration *
+meta_window_wayland_peek_configuration (MetaWindowWayland *wl_window,
+                                        uint32_t           serial)
+{
+  GList *l;
+
+  for (l = wl_window->pending_configurations; l; l = l->next)
+    {
+      MetaWaylandWindowConfiguration *configuration = l->data;
+
+      if (configuration->serial == serial)
+        return configuration;
+    }
+
+  return NULL;
+}
+
 static MetaWaylandWindowConfiguration *
 acquire_acked_configuration (MetaWindowWayland       *wl_window,
                              MetaWaylandSurfaceState *pending)
diff --git a/src/wayland/meta-window-wayland.h b/src/wayland/meta-window-wayland.h
index 22824a6ae..db152daaa 100644
--- a/src/wayland/meta-window-wayland.h
+++ b/src/wayland/meta-window-wayland.h
@@ -56,6 +56,10 @@ void meta_window_place_with_placement_rule (MetaWindow        *window,
 void meta_window_update_placement_rule (MetaWindow        *window,
                                         MetaPlacementRule *placement_rule);
 
+MetaWaylandWindowConfiguration *
+  meta_window_wayland_peek_configuration (MetaWindowWayland *wl_window,
+                                          uint32_t           serial);
+
 void meta_window_wayland_set_min_size (MetaWindow *window,
                                        int         width,
                                        int         height);


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