wayland/xdg-shell: Defer meta_wayland_xdg_positioner_to_placement call

From xdg_surface_constructor_get_popup / xdg_popup_reposition (called
during Wayland protocol processing) to finish_popup_setup /
meta_wayland_xdg_popup_apply_state (called when the popup state is
applied).

This makes sure that the parent window frame rectangle is up to date in
meta_wayland_xdg_positioner_to_placement.

v2:
* Use meta_wayland_surface_state_new () in
  meta_wayland_transaction_add_xdg_popup_reposition.
v3:
* Move xdg_popup_repositioned handling to
  meta_wayland_xdg_popup_apply_state.
v4:
* Do not steal pending->xdg_positioner in
  meta_wayland_xdg_popup_apply_state, fixes leaking the corresponding
  memory.
* Drop MetaWaylandSurfaceState::xdg_popup_repositioned, just use
  ::xdg_positioner.
v5:
* Reformat meta_wayland_xdg_positioner_to_placement calls to stay within
  80 columns. (Jonas Ådahl)

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
This commit is contained in:
Michel Dänzer 2022-11-01 17:30:00 +01:00 committed by Michel Dänzer
parent 6c3879766d
commit b7599fb766
6 changed files with 80 additions and 28 deletions

View File

@ -502,6 +502,8 @@ meta_wayland_surface_state_set_default (MetaWaylandSurfaceState *state)
state->subsurface_placement_ops = NULL;
wl_list_init (&state->presentation_feedback_list);
state->xdg_popup_reposition_token = 0;
}
static void
@ -527,6 +529,7 @@ meta_wayland_surface_state_clear (MetaWaylandSurfaceState *state)
g_clear_pointer (&state->buffer_damage, cairo_region_destroy);
g_clear_pointer (&state->input_region, cairo_region_destroy);
g_clear_pointer (&state->opaque_region, cairo_region_destroy);
g_clear_pointer (&state->xdg_positioner, g_free);
if (state->buffer)
g_clear_signal_handler (&state->buffer_destroy_handler_id, state->buffer);
@ -675,6 +678,13 @@ meta_wayland_surface_state_merge_into (MetaWaylandSurfaceState *from,
wl_list_insert_list (&to->presentation_feedback_list,
&from->presentation_feedback_list);
wl_list_init (&from->presentation_feedback_list);
if (from->xdg_positioner)
{
g_clear_pointer (&to->xdg_positioner, g_free);
to->xdg_positioner = g_steal_pointer (&from->xdg_positioner);
to->xdg_popup_reposition_token = from->xdg_popup_reposition_token;
}
}
static void

View File

@ -133,6 +133,10 @@ struct _MetaWaylandSurfaceState
struct {
gboolean surface_size_changed;
} derived;
/* xdg_popup */
MetaWaylandXdgPositioner *xdg_positioner;
uint32_t xdg_popup_reposition_token;
};
struct _MetaWaylandDragDestFuncs

View File

@ -386,6 +386,27 @@ meta_wayland_transaction_add_subsurface_position (MetaWaylandTransaction *transa
entry->has_sub_pos = TRUE;
}
void
meta_wayland_transaction_add_xdg_popup_reposition (MetaWaylandTransaction *transaction,
MetaWaylandSurface *surface,
void *xdg_positioner,
uint32_t token)
{
MetaWaylandTransactionEntry *entry;
MetaWaylandSurfaceState *state;
entry = meta_wayland_transaction_ensure_entry (transaction, surface);
if (entry->state)
g_clear_pointer (&entry->state->xdg_positioner, g_free);
else
entry->state = meta_wayland_surface_state_new ();
state = entry->state;
state->xdg_positioner = xdg_positioner;
state->xdg_popup_reposition_token = token;
}
static void
meta_wayland_transaction_entry_merge_into (MetaWaylandTransactionEntry *from,
MetaWaylandTransactionEntry *to)

View File

@ -37,6 +37,11 @@ void meta_wayland_transaction_add_subsurface_position (MetaWaylandTransaction *t
int x,
int y);
void meta_wayland_transaction_add_xdg_popup_reposition (MetaWaylandTransaction *transaction,
MetaWaylandSurface *surface,
void *xdg_positioner,
uint32_t token);
void meta_wayland_transaction_merge_into (MetaWaylandTransaction *from,
MetaWaylandTransaction *to);

View File

@ -67,6 +67,8 @@ typedef struct _MetaWaylandActivation MetaWaylandActivation;
typedef struct _MetaWaylandDmaBufManager MetaWaylandDmaBufManager;
typedef struct _MetaWaylandXdgPositioner MetaWaylandXdgPositioner;
typedef struct _MetaXWaylandManager MetaXWaylandManager;
#endif

View File

@ -57,7 +57,7 @@ typedef struct _MetaWaylandXdgShellClient
GList *surface_constructors;
} MetaWaylandXdgShellClient;
typedef struct _MetaWaylandXdgPositioner
struct _MetaWaylandXdgPositioner
{
MetaRectangle anchor_rect;
int32_t width;
@ -76,7 +76,7 @@ typedef struct _MetaWaylandXdgPositioner
gboolean acked_parent_configure;
uint32_t parent_configure_serial;
} MetaWaylandXdgPositioner;
};
typedef struct _MetaWaylandXdgSurfaceConstructor
{
@ -130,11 +130,7 @@ struct _MetaWaylandXdgPopup
struct {
MetaWaylandSurface *parent_surface;
/*
* The coordinates/dimensions in the placement rule are in logical pixel
* coordinate space, i.e. not scaled given what monitor the popup is on.
*/
MetaPlacementRule placement_rule;
MetaWaylandXdgPositioner xdg_positioner;
MetaWaylandSeat *grab_seat;
uint32_t grab_serial;
@ -623,27 +619,17 @@ xdg_popup_reposition (struct wl_client *client,
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;
MetaWaylandTransaction *transaction;
window = meta_wayland_surface_get_window (surface);
if (!window)
return;
xdg_positioner = g_memdup2 (wl_resource_get_user_data (positioner_resource),
sizeof (MetaWaylandXdgPositioner));
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);
transaction = meta_wayland_transaction_new (surface->compositor);
meta_wayland_transaction_add_xdg_popup_reposition (transaction, surface,
xdg_positioner, token);
meta_wayland_transaction_ensure_entry (transaction, xdg_popup->parent_surface);
meta_wayland_transaction_commit (transaction);
}
static const struct xdg_popup_interface meta_wayland_xdg_popup_interface = {
@ -1080,6 +1066,8 @@ finish_popup_setup (MetaWaylandXdgPopup *xdg_popup)
uint32_t serial;
MetaDisplay *display = meta_get_display ();
MetaWindow *window;
MetaWindow *parent_window;
MetaPlacementRule placement_rule;
parent_surface = xdg_popup->setup.parent_surface;
seat = xdg_popup->setup.grab_seat;
@ -1124,7 +1112,11 @@ finish_popup_setup (MetaWaylandXdgPopup *xdg_popup)
window = meta_window_wayland_new (display, surface);
meta_wayland_shell_surface_set_window (shell_surface, window);
meta_wayland_xdg_popup_place (xdg_popup, &xdg_popup->setup.placement_rule);
parent_window = meta_wayland_surface_get_window (parent_surface);
placement_rule =
meta_wayland_xdg_positioner_to_placement (&xdg_popup->setup.xdg_positioner,
parent_window);
meta_wayland_xdg_popup_place (xdg_popup, &placement_rule);
if (seat)
{
@ -1219,6 +1211,25 @@ meta_wayland_xdg_popup_apply_state (MetaWaylandSurfaceRole *surface_role,
if (xdg_popup->setup.parent_surface)
finish_popup_setup (xdg_popup);
if (pending->xdg_positioner)
{
MetaWindow *window, *parent_window;
MetaPlacementRule placement_rule;
parent_window = meta_wayland_surface_get_window (xdg_popup->parent_surface);
placement_rule =
meta_wayland_xdg_positioner_to_placement (pending->xdg_positioner,
parent_window);
xdg_popup->pending_reposition_token = pending->xdg_popup_reposition_token;
xdg_popup->pending_repositioned = TRUE;
scale_placement_rule (&placement_rule, surface);
window = meta_wayland_surface_get_window (surface);
meta_window_update_placement_rule (window, &placement_rule);
}
if (!surface->buffer_ref->buffer && xdg_surface_priv->first_buffer_attached)
{
meta_wayland_xdg_surface_reset (xdg_surface);
@ -2040,8 +2051,7 @@ xdg_surface_constructor_get_popup (struct wl_client *client,
meta_wayland_xdg_surface_constructor_finalize (constructor, xdg_surface);
xdg_positioner = wl_resource_get_user_data (positioner_resource);
xdg_popup->setup.placement_rule =
meta_wayland_xdg_positioner_to_placement (xdg_positioner, parent_window);
xdg_popup->setup.xdg_positioner = *xdg_positioner;
xdg_popup->setup.parent_surface = parent_surface;
}