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
This commit is contained in:
Jonas Ådahl 2020-02-14 11:13:24 +01:00 committed by Carlos Garnacho
parent 5c37f5104e
commit f97804f4f4
4 changed files with 148 additions and 1 deletions

View File

@ -37,7 +37,7 @@
/* Global/master objects (version exported by wl_registry and negotiated through bind) */ /* Global/master objects (version exported by wl_registry and negotiated through bind) */
#define META_WL_COMPOSITOR_VERSION 4 #define META_WL_COMPOSITOR_VERSION 4
#define META_WL_DATA_DEVICE_MANAGER_VERSION 3 #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_ZXDG_SHELL_V6_VERSION 1
#define META_WL_SHELL_VERSION 1 #define META_WL_SHELL_VERSION 1
#define META_WL_SEAT_VERSION 5 #define META_WL_SEAT_VERSION 5

View File

@ -68,6 +68,13 @@ typedef struct _MetaWaylandXdgPositioner
int32_t offset_y; int32_t offset_y;
gboolean is_reactive; 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; } MetaWaylandXdgPositioner;
typedef struct _MetaWaylandXdgSurfaceConstructor typedef struct _MetaWaylandXdgSurfaceConstructor
@ -112,6 +119,9 @@ struct _MetaWaylandXdgPopup
MetaWaylandSurface *parent_surface; MetaWaylandSurface *parent_surface;
gulong parent_surface_unmapped_handler_id; gulong parent_surface_unmapped_handler_id;
uint32_t pending_reposition_token;
gboolean pending_repositioned;
MetaWaylandPopup *popup; MetaWaylandPopup *popup;
gboolean dismissed_by_client; gboolean dismissed_by_client;
@ -153,6 +163,10 @@ static void
meta_wayland_xdg_surface_send_configure (MetaWaylandXdgSurface *xdg_surface, meta_wayland_xdg_surface_send_configure (MetaWaylandXdgSurface *xdg_surface,
MetaWaylandWindowConfiguration *configuration); MetaWaylandWindowConfiguration *configuration);
static void
scale_placement_rule (MetaPlacementRule *placement_rule,
MetaWaylandSurface *surface);
static MetaWaylandSurface * static MetaWaylandSurface *
surface_from_xdg_surface_resource (struct wl_resource *resource) 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; 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 = { static const struct xdg_popup_interface meta_wayland_xdg_popup_interface = {
xdg_popup_destroy, xdg_popup_destroy,
xdg_popup_grab, xdg_popup_grab,
xdg_popup_reposition,
}; };
static void static void
@ -1150,6 +1200,12 @@ meta_wayland_xdg_popup_configure (MetaWaylandShellSurface *shell_surface,
geometry_scale = meta_window_wayland_get_geometry_scale (parent_window); geometry_scale = meta_window_wayland_get_geometry_scale (parent_window);
x = configuration->rel_x / geometry_scale; x = configuration->rel_x / geometry_scale;
y = configuration->rel_y / 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, xdg_popup_send_configure (xdg_popup->resource,
x, y, x, y,
configuration->width, configuration->height); 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); 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) { return (MetaPlacementRule) {
.anchor_rect = xdg_positioner->anchor_rect, .anchor_rect = xdg_positioner->anchor_rect,
.gravity = positioner_gravity_to_placement_gravity (xdg_positioner->gravity), .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; 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 = { static const struct xdg_positioner_interface meta_wayland_xdg_positioner_interface = {
xdg_positioner_destroy, xdg_positioner_destroy,
xdg_positioner_set_size, 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_constraint_adjustment,
xdg_positioner_set_offset, xdg_positioner_set_offset,
xdg_positioner_set_reactive, xdg_positioner_set_reactive,
xdg_positioner_set_parent_size,
xdg_positioner_set_parent_configure,
}; };
static void static void

View File

@ -800,6 +800,23 @@ meta_window_wayland_new (MetaDisplay *display,
return window; 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 * static MetaWaylandWindowConfiguration *
acquire_acked_configuration (MetaWindowWayland *wl_window, acquire_acked_configuration (MetaWindowWayland *wl_window,
MetaWaylandSurfaceState *pending) MetaWaylandSurfaceState *pending)

View File

@ -56,6 +56,10 @@ void meta_window_place_with_placement_rule (MetaWindow *window,
void meta_window_update_placement_rule (MetaWindow *window, void meta_window_update_placement_rule (MetaWindow *window,
MetaPlacementRule *placement_rule); MetaPlacementRule *placement_rule);
MetaWaylandWindowConfiguration *
meta_window_wayland_peek_configuration (MetaWindowWayland *wl_window,
uint32_t serial);
void meta_window_wayland_set_min_size (MetaWindow *window, void meta_window_wayland_set_min_size (MetaWindow *window,
int width, int width,
int height); int height);