[PATCH v10 0/1] MR11178: winewayland: Implement xdg-popup for unmanaged windows.
This patch significantly improves compositor behavior across various compositors, as popups are guaranteed not to get clipped at the window boundary. In addition, it enables server-side decorations to be implemented on the winewayland driver. To achieve this, I attempted to reuse as much of the exsisting xdg-toplevel code as possible. -- v10: winewayland: Implement xdg-popup for unmanaged windows. https://gitlab.winehq.org/wine/wine/-/merge_requests/11178
From: Etaash Mathamsetty <etaash.mathamsetty@gmail.com> --- dlls/winewayland.drv/wayland.c | 8 +- dlls/winewayland.drv/wayland_surface.c | 287 ++++++++++++++++++------- dlls/winewayland.drv/waylanddrv.h | 25 ++- dlls/winewayland.drv/window.c | 47 ++-- 4 files changed, 255 insertions(+), 112 deletions(-) diff --git a/dlls/winewayland.drv/wayland.c b/dlls/winewayland.drv/wayland.c index 5b2b0c5b25b..7f56e1cfd20 100644 --- a/dlls/winewayland.drv/wayland.c +++ b/dlls/winewayland.drv/wayland.c @@ -120,11 +120,9 @@ static void registry_handle_global(void *data, struct wl_registry *registry, } else if (strcmp(interface, "xdg_wm_base") == 0) { - /* Bind version 2 so that compositors (e.g., sway) can properly send tiled - * states, instead of falling back to (ab)using the maximized state. */ - process_wayland.xdg_wm_base = - wl_registry_bind(registry, id, &xdg_wm_base_interface, - version < 2 ? version : 2); + /* version 3 is required for xdg_popup::reposition */ + if (version < 3) return; + process_wayland.xdg_wm_base = wl_registry_bind(registry, id, &xdg_wm_base_interface, 3); xdg_wm_base_add_listener(process_wayland.xdg_wm_base, &xdg_wm_base_listener, NULL); } else if (strcmp(interface, "wl_shm") == 0) diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index b28072331d6..30181706d84 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -48,8 +48,13 @@ static void xdg_surface_handle_configure(void *private, struct xdg_surface *xdg_ /* Handle this event only if wayland_surface is still associated with * the target xdg_surface. */ - if ((surface = data->wayland_surface) && wayland_surface_is_toplevel(surface) && - surface->xdg_surface == xdg_surface) + if (!(surface = data->wayland_surface) || surface->xdg_surface != xdg_surface) + { + wayland_win_data_release(data); + return; + } + + if (wayland_surface_is_toplevel(surface)) { /* If we have a previously requested config, we have already sent a * WM_WAYLAND_CONFIGURE which hasn't been handled yet. In that case, @@ -60,6 +65,18 @@ static void xdg_surface_handle_configure(void *private, struct xdg_surface *xdg_ surface->requested = surface->pending; memset(&surface->pending, 0, sizeof(surface->pending)); } + else if (wayland_surface_is_popup(surface)) + { + /* expose the surface to ensure that the new config is ack-ed + * and the popup can move if needed */ + initial_configure = surface->current.serial == 0 || + wayland_surface_popup_config_changed(&surface->current, + &surface->pending); + surface->pending.serial = serial; + surface->processing = surface->pending; + surface->processing.processed = 1; + memset(&surface->pending, 0, sizeof(surface->pending)); + } wayland_win_data_release(data); @@ -138,11 +155,88 @@ static const struct xdg_toplevel_listener xdg_toplevel_listener = xdg_toplevel_handle_close }; +static void xdg_popup_handle_configure(void *private, struct xdg_popup *xdg_popup, + int32_t x, int32_t y, int32_t width, int32_t height) +{ + HWND hwnd = private; + struct wayland_win_data *data; + struct wayland_surface *surface; + + TRACE("hwnd=%p (%d,%d) %dx%d\n", hwnd, x, y, width, height); + + if (!(data = wayland_win_data_get(hwnd))) return; + + if ((surface = data->wayland_surface) && wayland_surface_is_popup(surface)) + { + surface->pending.x = x; + surface->pending.y = y; + surface->pending.width = width; + surface->pending.height = height; + surface->pending.state = 0; + } + + wayland_win_data_release(data); +} + +static void xdg_popup_handle_done(void *private, struct xdg_popup *xdg_popup) +{ + struct wayland_win_data *data, *owner_data; + struct wayland_surface *surface = NULL, *owner_surface = NULL; + HWND hwnd = private; + + if (!xdg_popup) return; + + /* Recreate the popup if the compositor dismissed it for some reason. + * The protocol does not explicitly prohibit this from occuring on ungrabbed popups. */ + WARN("Compositor dismissed popup hwnd=%p\n", private); + + if (!(data = wayland_win_data_get(hwnd)) || !(surface = data->wayland_surface)) + { + ERR("Failed to recreate popup!\n"); + xdg_popup_destroy(xdg_popup); + goto done; + } + + /* this is a stale event */ + if (!wayland_surface_is_popup(surface)) goto done; + if (surface->xdg_popup != xdg_popup) goto done; + + /* the protocol requires us to destroy the xdg_popup */ + wayland_surface_clear_role(surface); + + if (!(owner_data = wayland_win_data_get_nolock(surface->owner_hwnd)) || + !(owner_surface = owner_data->wayland_surface) || !owner_surface->xdg_surface) + { + ERR("Failed to recreate popup!\n"); + goto done; + } + + wayland_surface_make_popup(surface, owner_surface); + +done: + if (data) wayland_win_data_release(data); + if (surface && owner_surface && owner_surface->xdg_surface) + NtUserExposeWindowSurface(hwnd, 0, NULL, 0); +} + +static void xdg_popup_handle_reposition(void *private, struct xdg_popup *xdg_popup, uint32_t token) +{ + /* we also get a configure event in this case */ + TRACE("hwnd=%p\n", private); +} + +static const struct xdg_popup_listener xdg_popup_listener = +{ + xdg_popup_handle_configure, + xdg_popup_handle_done, + xdg_popup_handle_reposition, +}; + void wp_fractional_scale_handle_scale(void* user_data, struct wp_fractional_scale_v1 *fractional_scale_v1, uint32_t scale_fixed) { - struct wayland_win_data *data; + struct wayland_win_data *data, *owner_data; struct wayland_client_surface *client; struct wayland_surface *surface; double scale = scale_fixed / 120.0; @@ -163,11 +257,12 @@ void wp_fractional_scale_handle_scale(void* user_data, if ((client = data->client_surface)) wayland_client_surface_attach(client, client->toplevel); - /* the subsurface rect has changed */ - if (surface->role == WAYLAND_SURFACE_ROLE_SUBSURFACE) + /* the popup x,y position has changed */ + if (wayland_surface_is_popup(surface) && + (owner_data = wayland_win_data_get_nolock(surface->owner_hwnd)) && + owner_data->wayland_surface) { - surface->processing.serial = 1; - surface->processing.processed = TRUE; + wayland_surface_make_popup(surface, owner_data->wayland_surface); } wayland_win_data_release(data); @@ -370,47 +465,108 @@ err: ERR("Failed to assign toplevel role to wayland surface\n"); } +/* helper to intialize the positioner using a given surface config */ +static struct xdg_positioner *wayland_surface_create_positioner(struct wayland_surface *surface, + struct wayland_surface *owner, + struct wayland_surface_config *config) +{ + struct xdg_positioner *xdg_positioner = + xdg_wm_base_create_positioner(process_wayland.xdg_wm_base); + + if (!xdg_positioner) return NULL; + + if (!config->width) config->width = 1; + if (!config->height) config->height = 1; + + /* this anchor rect is always valid */ + xdg_positioner_set_anchor_rect(xdg_positioner, 0, 0, 1, 1); + xdg_positioner_set_anchor(xdg_positioner, XDG_POSITIONER_ANCHOR_TOP_LEFT); + xdg_positioner_set_gravity(xdg_positioner, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT); + /* then we offset by the requested amount */ + xdg_positioner_set_offset(xdg_positioner, config->x, config->y); + xdg_positioner_set_size(xdg_positioner, config->width, config->height); + + return xdg_positioner; +} + /********************************************************************** - * wayland_surface_make_subsurface + * wayland_surface_make_popup * - * Gives the subsurface role to a plain wayland surface. + * Gives the popup role to a plain wayland surface. */ -void wayland_surface_make_subsurface(struct wayland_surface *surface, - struct wayland_surface *parent) +void wayland_surface_make_popup(struct wayland_surface *surface, + struct wayland_surface *owner) { - assert(!surface->role || surface->role == WAYLAND_SURFACE_ROLE_SUBSURFACE); - if (surface->wl_subsurface && surface->toplevel_hwnd == parent->hwnd) return; + struct wayland_surface_config config; + struct xdg_positioner *xdg_positioner = NULL; + const RECT *rect = &surface->window.rect; - wayland_surface_clear_role(surface); - surface->role = WAYLAND_SURFACE_ROLE_SUBSURFACE; + config.x = rect->left - owner->window.rect.left; + config.y = rect->top - owner->window.rect.top; + config.width = rect->right - rect->left; + config.height = rect->bottom - rect->top; - TRACE("surface=%p parent=%p\n", surface, parent); + assert(owner->xdg_surface); + assert(!surface->role || surface->role == WAYLAND_SURFACE_ROLE_POPUP); - surface->wl_subsurface = - wl_subcompositor_get_subsurface(process_wayland.wl_subcompositor, - surface->wl_surface, - parent->wl_surface); - if (!surface->wl_subsurface) + if (surface->xdg_popup && surface->owner_hwnd == owner->hwnd) { - ERR("Failed to create client wl_subsurface\n"); - goto err; + if (!surface->current.serial) return; + + wayland_surface_coords_from_window(surface, config.x, config.y, + &config.x, &config.y); + wayland_surface_coords_from_window(surface, config.width, config.height, + &config.width, &config.height); + + /* reposition the popup if needed */ + if (!wayland_surface_popup_config_changed(&surface->current, &config)) + return; + + xdg_positioner = wayland_surface_create_positioner(surface, owner, &config); + if (!xdg_positioner) + { + ERR("Failed to create positioner!\n"); + return; + } + + xdg_popup_reposition(surface->xdg_popup, xdg_positioner, 0); + xdg_positioner_destroy(xdg_positioner); + wl_surface_commit(surface->wl_surface); + wl_display_flush(process_wayland.wl_display); + return; } - wayland_surface_init_fractional_scale(surface, parent->window.scale); + wayland_surface_clear_role(surface); + surface->role = WAYLAND_SURFACE_ROLE_POPUP; - surface->role = WAYLAND_SURFACE_ROLE_SUBSURFACE; - surface->toplevel_hwnd = parent->hwnd; + wayland_surface_init_fractional_scale(surface, owner->window.scale); - /* Present contents independently of the parent surface. */ - wl_subsurface_set_desync(surface->wl_subsurface); + surface->xdg_surface = xdg_wm_base_get_xdg_surface(process_wayland.xdg_wm_base, + surface->wl_surface); + if (!surface->xdg_surface) goto err; + xdg_surface_add_listener(surface->xdg_surface, &xdg_surface_listener, surface->hwnd); + + wayland_surface_coords_from_window(surface, config.x, config.y, &config.x, &config.y); + wayland_surface_coords_from_window(surface, config.width, config.height, + &config.width, &config.height); + + xdg_positioner = wayland_surface_create_positioner(surface, owner, &config); + if (!xdg_positioner) goto err; + + surface->xdg_popup = xdg_surface_get_popup(surface->xdg_surface, owner->xdg_surface, + xdg_positioner); + xdg_positioner_destroy(xdg_positioner); + if (!surface->xdg_popup) goto err; + xdg_popup_add_listener(surface->xdg_popup, &xdg_popup_listener, surface->hwnd); + surface->owner_hwnd = owner->hwnd; + wl_surface_commit(surface->wl_surface); wl_display_flush(process_wayland.wl_display); return; - err: wayland_surface_clear_role(surface); - ERR("Failed to assign subsurface role to wayland surface\n"); + ERR("Failed to assign popup role to wayland surface\n"); } /********************************************************************** @@ -437,6 +593,23 @@ void wayland_surface_clear_role(struct wayland_surface *surface) case WAYLAND_SURFACE_ROLE_NONE: break; + case WAYLAND_SURFACE_ROLE_POPUP: + + if (surface->xdg_popup) + { + xdg_popup_destroy(surface->xdg_popup); + surface->xdg_popup = NULL; + } + + if (surface->xdg_surface) + { + xdg_surface_destroy(surface->xdg_surface); + surface->xdg_surface = NULL; + } + + surface->owner_hwnd = NULL; + break; + case WAYLAND_SURFACE_ROLE_TOPLEVEL: if (surface->xdg_toplevel_icon) { @@ -459,23 +632,12 @@ void wayland_surface_clear_role(struct wayland_surface *surface) surface->xdg_surface = NULL; } break; - - case WAYLAND_SURFACE_ROLE_SUBSURFACE: - if (surface->wl_subsurface) - { - wl_subsurface_destroy(surface->wl_subsurface); - surface->wl_subsurface = NULL; - } - - surface->toplevel_hwnd = 0; - break; } memset(&surface->pending, 0, sizeof(surface->pending)); memset(&surface->requested, 0, sizeof(surface->requested)); memset(&surface->processing, 0, sizeof(surface->processing)); memset(&surface->current, 0, sizeof(surface->current)); - surface->toplevel_hwnd = 0; /* Ensure no buffer is attached, otherwise future role assignments may fail. */ wl_surface_attach(surface->wl_surface, NULL, 0, 0); @@ -657,8 +819,8 @@ static void wayland_surface_reconfigure_geometry(struct wayland_surface *surface { int width = rect.right - rect.left, height = rect.bottom - rect.top; xdg_surface_set_window_geometry(surface->xdg_surface, - rect.left, rect.top, - width, height); + 0, 0, width, height); + if (!wayland_surface_is_toplevel(surface)) return; if (surface->window.resizeable) { xdg_toplevel_set_min_size(surface->xdg_toplevel, 0, 0); @@ -772,40 +934,6 @@ static BOOL wayland_surface_reconfigure_xdg(struct wayland_surface *surface, return TRUE; } -/********************************************************************** - * wayland_surface_reconfigure_subsurface - * - * Reconfigures the subsurface as needed to match the latest requested - * state. - */ -static void wayland_surface_reconfigure_subsurface(struct wayland_surface *surface) -{ - struct wayland_win_data *toplevel_data; - struct wayland_surface *toplevel_surface; - int local_x, local_y, x, y; - - if (surface->processing.serial && surface->processing.processed && - (toplevel_data = wayland_win_data_get_nolock(surface->toplevel_hwnd)) && - (toplevel_surface = toplevel_data->wayland_surface)) - { - local_x = surface->window.rect.left - toplevel_surface->window.rect.left; - local_y = surface->window.rect.top - toplevel_surface->window.rect.top; - - wayland_surface_coords_from_window(surface, local_x, local_y, &x, &y); - - TRACE("hwnd=%p pos=%d,%d\n", surface->hwnd, x, y); - - wl_subsurface_set_position(surface->wl_subsurface, x, y); - if (toplevel_data->client_surface && toplevel_data->client_surface->wl_subsurface) - wl_subsurface_place_above(surface->wl_subsurface, toplevel_data->client_surface->wl_surface); - else - wl_subsurface_place_above(surface->wl_subsurface, toplevel_surface->wl_surface); - wl_surface_commit(toplevel_surface->wl_surface); - - memset(&surface->processing, 0, sizeof(surface->processing)); - } -} - /********************************************************************** * wayland_surface_reconfigure * @@ -833,14 +961,11 @@ BOOL wayland_surface_reconfigure(struct wayland_surface *surface) { case WAYLAND_SURFACE_ROLE_NONE: break; + case WAYLAND_SURFACE_ROLE_POPUP: case WAYLAND_SURFACE_ROLE_TOPLEVEL: if (!surface->xdg_surface) break; /* surface role has been cleared */ if (!wayland_surface_reconfigure_xdg(surface, width, height)) return FALSE; break; - case WAYLAND_SURFACE_ROLE_SUBSURFACE: - if (!surface->wl_subsurface) break; /* surface role has been cleared */ - wayland_surface_reconfigure_subsurface(surface); - break; } wayland_surface_reconfigure_size(surface, width, height); diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 07ac10e9f9e..15696f7b2da 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -84,7 +84,7 @@ enum wayland_surface_role { WAYLAND_SURFACE_ROLE_NONE, WAYLAND_SURFACE_ROLE_TOPLEVEL, - WAYLAND_SURFACE_ROLE_SUBSURFACE, + WAYLAND_SURFACE_ROLE_POPUP, }; struct wayland_keyboard @@ -226,6 +226,7 @@ struct wayland_output struct wayland_surface_config { + int32_t x, y; int32_t width, height; enum wayland_surface_config_state state; uint32_t serial; @@ -280,18 +281,20 @@ struct wayland_surface struct wayland_shm_buffer *big_icon_buffer; enum wayland_surface_role role; + + struct xdg_surface *xdg_surface; + union { struct { - struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; struct xdg_toplevel_icon_v1 *xdg_toplevel_icon; }; struct { - struct wl_subsurface *wl_subsurface; - HWND toplevel_hwnd; + struct xdg_popup *xdg_popup; + HWND owner_hwnd; }; }; struct wp_alpha_modifier_surface_v1 *wp_alpha_modifier_surface_v1; @@ -326,6 +329,8 @@ void wayland_surface_destroy(struct wayland_surface *surface); void wayland_surface_make_toplevel(struct wayland_surface *surface); void wayland_surface_make_subsurface(struct wayland_surface *surface, struct wayland_surface *parent); +void wayland_surface_make_popup(struct wayland_surface *surface, + struct wayland_surface *owner); void wayland_surface_clear_role(struct wayland_surface *surface); void wayland_surface_attach_shm(struct wayland_surface *surface, struct wayland_shm_buffer *shm_buffer, @@ -352,6 +357,18 @@ static inline BOOL wayland_surface_is_toplevel(struct wayland_surface *surface) return surface->role == WAYLAND_SURFACE_ROLE_TOPLEVEL && surface->xdg_toplevel; } +static inline BOOL wayland_surface_is_popup(struct wayland_surface *surface) +{ + return surface->role == WAYLAND_SURFACE_ROLE_POPUP && surface->xdg_popup; +} + +static inline BOOL wayland_surface_popup_config_changed(struct wayland_surface_config *c1, + struct wayland_surface_config *c2) +{ + return c1->height != c2->height || c1->width != c2->width || + c1->x != c2->x || c1->y != c2->y; +} + /********************************************************************** * Wayland SHM buffer */ diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index 8e05292cb62..8872f5a79a3 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -188,7 +188,8 @@ static void reapply_cursor_clipping(void) NtUserSetThreadDpiAwarenessContext(context); } -static BOOL wayland_win_data_create_wayland_surface(struct wayland_win_data *data, struct wayland_surface *toplevel_surface) +static BOOL wayland_win_data_create_wayland_surface(struct wayland_win_data *data, HWND toplevel, + struct wayland_surface *owner_surface) { struct wayland_client_surface *client = data->client_surface; struct wayland_surface *surface; @@ -203,7 +204,9 @@ static BOOL wayland_win_data_create_wayland_surface(struct wayland_win_data *dat (!(exstyle & WS_EX_LAYERED) || data->layered_attribs_set); if (!visible) role = WAYLAND_SURFACE_ROLE_NONE; - else if (toplevel_surface) role = WAYLAND_SURFACE_ROLE_SUBSURFACE; + else if (owner_surface) role = WAYLAND_SURFACE_ROLE_POPUP; + /* avoid initializing a toplevel for child windows */ + else if (toplevel) role = WAYLAND_SURFACE_ROLE_NONE; else role = WAYLAND_SURFACE_ROLE_TOPLEVEL; /* we can temporarily clear the role of a surface but cannot assign a different one after it's set */ @@ -224,6 +227,8 @@ static BOOL wayland_win_data_create_wayland_surface(struct wayland_win_data *dat wl_surface_set_input_region(surface->wl_surface, input_region); if (input_region) wl_region_destroy(input_region); + wayland_win_data_get_config(data, &surface->window); + /* If the window is a visible toplevel make it a wayland * xdg_toplevel. Otherwise keep it role-less to avoid polluting the * compositor with empty xdg_toplevels. */ @@ -232,16 +237,15 @@ static BOOL wayland_win_data_create_wayland_surface(struct wayland_win_data *dat case WAYLAND_SURFACE_ROLE_NONE: wayland_surface_clear_role(surface); break; + case WAYLAND_SURFACE_ROLE_POPUP: + wayland_surface_make_popup(surface, owner_surface); + break; case WAYLAND_SURFACE_ROLE_TOPLEVEL: wayland_surface_make_toplevel(surface); break; - case WAYLAND_SURFACE_ROLE_SUBSURFACE: - wayland_surface_make_subsurface(surface, toplevel_surface); - break; } if (visible && client) wayland_client_surface_attach(client, data->hwnd); - wayland_win_data_get_config(data, &surface->window); /* Size/position changes affect the effective pointer constraint, so update * it as needed. */ @@ -309,18 +313,13 @@ static void wayland_win_data_update_wayland_state(struct wayland_win_data *data) switch (surface->role) { case WAYLAND_SURFACE_ROLE_NONE: + /* popups do not have any state to update */ + case WAYLAND_SURFACE_ROLE_POPUP: break; case WAYLAND_SURFACE_ROLE_TOPLEVEL: if (!surface->xdg_surface) break; /* surface role has been cleared */ wayland_surface_update_state_toplevel(surface); break; - case WAYLAND_SURFACE_ROLE_SUBSURFACE: - TRACE("hwnd=%p subsurface parent=%p\n", surface->hwnd, surface->toplevel_hwnd); - /* Although subsurfaces don't have a dedicated surface config mechanism, - * we use the config fields to mark them as updated. */ - surface->processing.serial = 1; - surface->processing.processed = TRUE; - break; } wl_display_flush(process_wayland.wl_display); @@ -446,22 +445,26 @@ BOOL WAYLAND_WindowPosChanging(HWND hwnd, UINT swp_flags, BOOL shaped, const str void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, const struct window_rects *new_rects, struct window_surface *surface) { - HWND toplevel = NtUserGetAncestor(hwnd, GA_ROOT); - struct wayland_surface *toplevel_surface; + HWND toplevel = NtUserGetAncestor(hwnd, GA_ROOT), owner = NULL; + struct wayland_surface *owner_surface = NULL; struct wayland_client_surface *client; - struct wayland_win_data *data, *toplevel_data; + struct wayland_win_data *data, *owner_data; BOOL managed, fullscreen = swp_flags & WINE_SWP_FULLSCREEN; - TRACE("hwnd %p new_rects %s after %p flags %08x\n", hwnd, debugstr_window_rects(new_rects), insert_after, swp_flags); - /* Get the managed state with win_data unlocked, as is_window_managed * may need to query win_data information about other HWNDs and thus * acquire the lock itself internally. */ - if (!(managed = is_window_managed(hwnd, swp_flags, fullscreen)) && surface) toplevel = owner_hint; + if (!(managed = is_window_managed(hwnd, swp_flags, fullscreen)) && surface) owner = owner_hint; + if (toplevel == hwnd) toplevel = NULL; + + TRACE("hwnd %p owner %p toplevel %p new_rects %s after %p flags %08x\n", hwnd, + owner, toplevel, debugstr_window_rects(new_rects), insert_after, swp_flags); if (!(data = wayland_win_data_get(hwnd))) return; - toplevel_data = toplevel && toplevel != hwnd ? wayland_win_data_get_nolock(toplevel) : NULL; - toplevel_surface = toplevel_data ? toplevel_data->wayland_surface : NULL; + owner_data = owner && owner != hwnd ? wayland_win_data_get_nolock(owner) : NULL; + owner_surface = owner_data ? owner_data->wayland_surface : NULL; + /* for it to be a popup, we need a valid xdg surface. */ + if (owner_surface && !owner_surface->xdg_surface) owner_surface = NULL; data->rects = *new_rects; data->is_fullscreen = fullscreen; @@ -484,7 +487,7 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UIN data->wayland_surface = NULL; } } - else if (wayland_win_data_create_wayland_surface(data, toplevel_surface)) + else if (wayland_win_data_create_wayland_surface(data, toplevel, owner_surface)) { wayland_win_data_update_wayland_state(data); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11178
On Tue Jun 23 20:43:56 2026 +0000, Etaash Mathamsetty wrote:
Posting a configure message doesn't work since the popup can be mapped before the message is sent. Instead, I adjusted the viewporter destination coordinates to ensure they are not outside the window geometry for popups. This ensures we use the requested size for win32u side, but if the compositor overrides the size wp_viewporter will just scale the surface contents so it fits what the compositor requested. It turns out that we still have full control of the size of the window. Since we technically do not need to follow the size reported by the compositor when we call xdg_surface::set_window_geometry. The protocol does not say that we are required to follow the size requested by xdg_popup::configure although that would be needed for certain constraint types like resize_x/y to function correctly (We don't use any constraints so no issues for us).
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/11178#note_144039
participants (2)
-
Etaash Mathamsetty -
Etaash Mathamsetty (@etaash.mathamsetty)