From f97804f4f469753806a51dec02ca9042a515609d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 14 Feb 2020 11:13:24 +0100 Subject: [PATCH] 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);