-- v5: winewayland: Attach client client surfaces to their toplevel surface. winewayland: Pass the client surface rect to wayland_surface_reconfigure_client. winewayland: Split wayland_win_data_update_wayland_surface helper. winewayland: Update the client separately from the window surface updates. winewayland: Keep the toplevel hwnd on the wayland_client_surface. winewayland: Call ensure_window_surface_contents with the toplevel window. winewayland: Use window DPI for the OpenGL client surface size. win32u: Notify drivers of the child surfaces state when their ancestor moves.
From: Rémi Bernon rbernon@codeweavers.com
Since changes in a parent window state may affect the children state in the driver, ensure the driver gets a chance to update its internal state. --- dlls/win32u/window.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index ab58cabb40e..fe39dd11183 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -1483,6 +1483,18 @@ int win32u_get_window_pixel_format( HWND hwnd ) return ret; }
+static int window_has_client_surface( HWND hwnd ) +{ + WND *win = get_win_ptr( hwnd ); + BOOL ret; + + if (!win || win == WND_DESKTOP || win == WND_OTHER_PROCESS) return FALSE; + ret = win->pixel_format || win->internal_pixel_format || !list_empty(&win->vulkan_surfaces); + release_win_ptr( win ); + + return ret; +} + /*********************************************************************** * NtUserGetProp (win32u.@) * @@ -1962,6 +1974,22 @@ static struct window_surface *get_window_surface( HWND hwnd, UINT swp_flags, BOO return new_surface; }
+static void update_children_window_state( HWND hwnd ) +{ + HWND *children; + int i; + + if (!(children = list_window_children( 0, hwnd, NULL, 0 ))) return; + + for (i = 0; children[i]; i++) + { + if (!window_has_client_surface( children[i] )) continue; + update_window_state( children[i] ); + } + + free( children ); +} + /*********************************************************************** * apply_window_pos * @@ -2109,6 +2137,7 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru }
user_driver->pWindowPosChanged( hwnd, insert_after, swp_flags, &monitor_rects, get_driver_window_surface( new_surface, monitor_dpi ) ); + update_children_window_state( hwnd ); }
return ret;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winewayland.drv/opengl.c | 35 ++++++++++++------------------- dlls/winewayland.drv/vulkan.c | 3 +-- dlls/winewayland.drv/waylanddrv.h | 2 +- dlls/winewayland.drv/window.c | 6 +----- 4 files changed, 16 insertions(+), 30 deletions(-)
diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index ecb1a65c38c..9515b5a10cd 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -192,7 +192,7 @@ static inline EGLConfig egl_config_for_format(int format) static struct wayland_gl_drawable *wayland_gl_drawable_create(HWND hwnd, int format) { struct wayland_gl_drawable *gl; - int client_width = 0, client_height = 0; + int client_width, client_height; RECT client_rect;
TRACE("hwnd=%p format=%d\n", hwnd, format); @@ -204,14 +204,15 @@ static struct wayland_gl_drawable *wayland_gl_drawable_create(HWND hwnd, int for gl->hwnd = hwnd; gl->swap_interval = 1;
+ NtUserGetClientRect(gl->hwnd, &client_rect, NtUserGetDpiForWindow(gl->hwnd)); + client_width = client_rect.right - client_rect.left; + client_height = client_rect.bottom - client_rect.top; + if (client_width == 0 || client_height == 0) client_width = client_height = 1; + /* Get the client surface for the HWND. If don't have a wayland surface * (e.g., HWND_MESSAGE windows) just create a dummy surface to act as the * target render surface. */ - if (!(gl->client = get_client_surface(hwnd, &client_rect))) goto err; - client_width = client_rect.right - client_rect.left; - client_height = client_rect.bottom - client_rect.top; - if (client_width == 0 || client_height == 0) - client_width = client_height = 1; + if (!(gl->client = get_client_surface(hwnd))) goto err;
gl->wl_egl_window = wl_egl_window_create(gl->client->wl_surface, client_width, client_height); @@ -273,25 +274,15 @@ static void wayland_update_gl_drawable(HWND hwnd, struct wayland_gl_drawable *ne
static void wayland_gl_drawable_sync_size(struct wayland_gl_drawable *gl) { - int client_width = 0, client_height = 0; - struct wayland_surface *wayland_surface; - struct wayland_win_data *data; + int client_width, client_height; + RECT client_rect;
if (InterlockedCompareExchange(&gl->resized, FALSE, TRUE)) { - if (!(data = wayland_win_data_get(gl->hwnd))) return; - - if ((wayland_surface = data->wayland_surface)) - { - client_width = wayland_surface->window.client_rect.right - - wayland_surface->window.client_rect.left; - client_height = wayland_surface->window.client_rect.bottom - - wayland_surface->window.client_rect.top; - } - - if (client_width == 0 || client_height == 0) - client_width = client_height = 1; - wayland_win_data_release(data); + NtUserGetClientRect(gl->hwnd, &client_rect, NtUserGetDpiForWindow(gl->hwnd)); + client_width = client_rect.right - client_rect.left; + client_height = client_rect.bottom - client_rect.top; + if (client_width == 0 || client_height == 0) client_width = client_height = 1;
wl_egl_window_resize(gl->wl_egl_window, client_width, client_height, 0, 0); } diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index 2874ae339d3..6e794a88cf7 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -74,11 +74,10 @@ static VkResult wayland_vulkan_surface_create(HWND hwnd, VkInstance instance, Vk VkResult res; VkWaylandSurfaceCreateInfoKHR create_info_host; struct wayland_client_surface *client; - RECT client_rect;
TRACE("%p %p %p %p\n", hwnd, instance, surface, private);
- if (!(client = get_client_surface(hwnd, &client_rect))) + if (!(client = get_client_surface(hwnd))) { ERR("Failed to create client surface for hwnd=%p\n", hwnd); return VK_ERROR_OUT_OF_HOST_MEMORY; diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 9de42758aa1..043d17f7cd0 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -292,7 +292,7 @@ struct wayland_win_data struct wayland_win_data *wayland_win_data_get(HWND hwnd); void wayland_win_data_release(struct wayland_win_data *data);
-struct wayland_client_surface *get_client_surface(HWND hwnd, RECT *client_rect); +struct wayland_client_surface *get_client_surface(HWND hwnd); BOOL set_window_surface_contents(HWND hwnd, struct wayland_shm_buffer *shm_buffer, HRGN damage_region); struct wayland_shm_buffer *get_window_surface_contents(HWND hwnd); void ensure_window_surface_contents(HWND hwnd); diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index d27a16456d2..cd382799715 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -695,7 +695,7 @@ LRESULT WAYLAND_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam) /********************************************************************** * get_client_surface */ -struct wayland_client_surface *get_client_surface(HWND hwnd, RECT *client_rect) +struct wayland_client_surface *get_client_surface(HWND hwnd) { struct wayland_client_surface *client; struct wayland_surface *surface; @@ -708,15 +708,11 @@ struct wayland_client_surface *get_client_surface(HWND hwnd, RECT *client_rect) /* ownership is shared with one of the callers, the last caller to release * its reference will also destroy it and clear our pointer. */ if ((client = data->client_surface)) InterlockedIncrement(&client->ref); - - if (!data->wayland_surface) *client_rect = data->rects.client; - else *client_rect = data->wayland_surface->window.client_rect; } else { surface = NULL; client = NULL; - SetRectEmpty(client_rect); }
if (!client && !(client = wayland_client_surface_create(hwnd)))
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winewayland.drv/opengl.c | 3 ++- dlls/winewayland.drv/vulkan.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index 9515b5a10cd..51278f6986f 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -708,12 +708,13 @@ static BOOL wayland_wglShareLists(struct wgl_context *orig, struct wgl_context * static BOOL wayland_wglSwapBuffers(HDC hdc) { struct wgl_context *ctx = NtCurrentTeb()->glContext; + HWND hwnd = NtUserWindowFromDC(hdc), toplevel = NtUserGetAncestor(hwnd, GA_ROOT); struct wayland_gl_drawable *gl;
if (!(gl = wayland_gl_drawable_get(NtUserWindowFromDC(hdc), hdc))) return FALSE;
if (ctx) wgl_context_refresh(ctx); - ensure_window_surface_contents(gl->hwnd); + ensure_window_surface_contents(toplevel); /* Although all the EGL surfaces we create are double-buffered, we want to * use some as single-buffered, so avoid swapping those. */ if (gl->double_buffered) p_eglSwapBuffers(egl_display, gl->surface); diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index 6e794a88cf7..4398cad0558 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -120,7 +120,8 @@ static void wayland_vulkan_surface_detach(HWND hwnd, void *private)
static void wayland_vulkan_surface_presented(HWND hwnd, void *private, VkResult result) { - ensure_window_surface_contents(hwnd); + HWND toplevel = NtUserGetAncestor(hwnd, GA_ROOT); + ensure_window_surface_contents(toplevel); }
static VkBool32 wayland_vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice phys_dev,
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winewayland.drv/wayland_surface.c | 36 +++++++++++++++++++------- dlls/winewayland.drv/waylanddrv.h | 4 ++- dlls/winewayland.drv/window.c | 29 +++++++++++++++------ 3 files changed, 50 insertions(+), 19 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index 1cf5dd3f8ce..d526123b569 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -817,21 +817,35 @@ err: return NULL; }
-void wayland_client_surface_attach(struct wayland_client_surface *client, struct wayland_surface *surface) +void wayland_client_surface_attach(struct wayland_client_surface *client, HWND toplevel) { - wayland_client_surface_detach(client); + struct wayland_win_data *toplevel_data = wayland_win_data_get_nolock(toplevel); + struct wayland_surface *surface;
- client->wl_subsurface = - wl_subcompositor_get_subsurface(process_wayland.wl_subcompositor, - client->wl_surface, - surface->wl_surface); - if (!client->wl_subsurface) + if (!toplevel_data || !(surface = toplevel_data->wayland_surface)) { - ERR("Failed to create client wl_subsurface\n"); + wayland_client_surface_detach(client); return; } - /* Present contents independently of the parent surface. */ - wl_subsurface_set_desync(client->wl_subsurface); + + if (client->toplevel != toplevel) + { + wayland_client_surface_detach(client); + + client->wl_subsurface = + wl_subcompositor_get_subsurface(process_wayland.wl_subcompositor, + client->wl_surface, + surface->wl_surface); + if (!client->wl_subsurface) + { + ERR("Failed to create client wl_subsurface\n"); + return; + } + /* Present contents independently of the parent surface. */ + wl_subsurface_set_desync(client->wl_subsurface); + + client->toplevel = toplevel; + }
wayland_surface_reconfigure_client(surface, client); /* Commit to apply subsurface positioning. */ @@ -845,6 +859,8 @@ void wayland_client_surface_detach(struct wayland_client_surface *client) wl_subsurface_destroy(client->wl_subsurface); client->wl_subsurface = NULL; } + + client->toplevel = 0; }
static void dummy_buffer_release(void *data, struct wl_buffer *buffer) diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 043d17f7cd0..73ab767506a 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -185,6 +185,7 @@ struct wayland_client_surface { LONG ref; HWND hwnd; + HWND toplevel; struct wl_surface *wl_surface; struct wl_subsurface *wl_subsurface; struct wp_viewport *wp_viewport; @@ -254,7 +255,7 @@ void wayland_surface_coords_to_window(struct wayland_surface *surface, int *window_x, int *window_y); struct wayland_client_surface *wayland_client_surface_create(HWND hwnd); BOOL wayland_client_surface_release(struct wayland_client_surface *client); -void wayland_client_surface_attach(struct wayland_client_surface *client, struct wayland_surface *surface); +void wayland_client_surface_attach(struct wayland_client_surface *client, HWND toplevel); void wayland_client_surface_detach(struct wayland_client_surface *client); void wayland_surface_ensure_contents(struct wayland_surface *surface, struct wayland_client_surface *client); void wayland_surface_set_title(struct wayland_surface *surface, LPCWSTR title); @@ -290,6 +291,7 @@ struct wayland_win_data };
struct wayland_win_data *wayland_win_data_get(HWND hwnd); +struct wayland_win_data *wayland_win_data_get_nolock(HWND hwnd); void wayland_win_data_release(struct wayland_win_data *data);
struct wayland_client_surface *get_client_surface(HWND hwnd); diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index cd382799715..dda5e00fc29 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -125,19 +125,32 @@ static void wayland_win_data_destroy(struct wayland_win_data *data) }
/*********************************************************************** - * wayland_win_data_get + * wayland_win_data_get_nolock * - * Lock and return the data structure associated with a window. + * Return the data structure associated with a window. This function does + * not lock the win_data_mutex, so it must be externally synchronized. */ -struct wayland_win_data *wayland_win_data_get(HWND hwnd) +struct wayland_win_data *wayland_win_data_get_nolock(HWND hwnd) { struct rb_entry *rb_entry;
- pthread_mutex_lock(&win_data_mutex); - if ((rb_entry = rb_get(&win_data_rb, hwnd))) return RB_ENTRY_VALUE(rb_entry, struct wayland_win_data, entry);
+ return NULL; +} + +/*********************************************************************** + * wayland_win_data_get + * + * Lock and return the data structure associated with a window. + */ +struct wayland_win_data *wayland_win_data_get(HWND hwnd) +{ + struct wayland_win_data *data; + + pthread_mutex_lock(&win_data_mutex); + if ((data = wayland_win_data_get_nolock(hwnd))) return data; pthread_mutex_unlock(&win_data_mutex);
return NULL; @@ -208,7 +221,7 @@ static void wayland_win_data_update_wayland_surface(struct wayland_win_data *dat { if (surface) { - if (client) wayland_client_surface_attach(client, surface); + if (client) wayland_client_surface_detach(client); wayland_surface_destroy(surface); } surface = NULL; @@ -235,7 +248,7 @@ static void wayland_win_data_update_wayland_surface(struct wayland_win_data *dat if (visible) { wayland_surface_make_toplevel(surface); - if (client) wayland_client_surface_attach(client, surface); + if (client) wayland_client_surface_attach(client, data->hwnd); if (surface->xdg_toplevel) { if (!NtUserInternalGetWindowText(data->hwnd, text, ARRAY_SIZE(text))) @@ -723,7 +736,7 @@ struct wayland_client_surface *get_client_surface(HWND hwnd) if (!data) return client;
if (surface && NtUserIsWindowVisible(hwnd)) - wayland_client_surface_attach(client, surface); + wayland_client_surface_attach(client, data->hwnd); else wayland_client_surface_detach(client);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winewayland.drv/wayland_surface.c | 7 +++---- dlls/winewayland.drv/waylanddrv.h | 4 ++-- dlls/winewayland.drv/window.c | 19 ++++++++----------- 3 files changed, 13 insertions(+), 17 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index d526123b569..4dc3101de76 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -535,7 +535,7 @@ void wayland_surface_reconfigure_client(struct wayland_surface *surface, struct * Reconfigures the wayland surface as needed to match the latest requested * state. */ -BOOL wayland_surface_reconfigure(struct wayland_surface *surface, struct wayland_client_surface *client) +BOOL wayland_surface_reconfigure(struct wayland_surface *surface) { struct wayland_window_config *window = &surface->window; int win_width, win_height, width, height; @@ -586,7 +586,6 @@ BOOL wayland_surface_reconfigure(struct wayland_surface *surface, struct wayland
wayland_surface_reconfigure_geometry(surface, width, height); wayland_surface_reconfigure_size(surface, width, height); - if (client) wayland_surface_reconfigure_client(surface, client);
return TRUE; } @@ -881,7 +880,7 @@ static const struct wl_buffer_listener dummy_buffer_listener = * Ensure that the wayland surface has up-to-date contents, by committing * a dummy buffer if necessary. */ -void wayland_surface_ensure_contents(struct wayland_surface *surface, struct wayland_client_surface *client) +void wayland_surface_ensure_contents(struct wayland_surface *surface) { struct wayland_shm_buffer *dummy_shm_buffer; HRGN damage; @@ -912,7 +911,7 @@ void wayland_surface_ensure_contents(struct wayland_surface *surface, struct way if (!(damage = NtGdiCreateRectRgn(0, 0, width, height))) WARN("Failed to create damage region for dummy buffer\n");
- if (wayland_surface_reconfigure(surface, client)) + if (wayland_surface_reconfigure(surface)) { wayland_surface_attach_shm(surface, dummy_shm_buffer, damage); wl_surface_commit(surface->wl_surface); diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 73ab767506a..bd599f2291b 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -242,7 +242,7 @@ void wayland_surface_clear_role(struct wayland_surface *surface); void wayland_surface_attach_shm(struct wayland_surface *surface, struct wayland_shm_buffer *shm_buffer, HRGN surface_damage_region); -BOOL wayland_surface_reconfigure(struct wayland_surface *surface, struct wayland_client_surface *client); +BOOL wayland_surface_reconfigure(struct wayland_surface *surface); void wayland_surface_reconfigure_client(struct wayland_surface *surface, struct wayland_client_surface *client); BOOL wayland_surface_config_is_compatible(struct wayland_surface_config *conf, int width, int height, @@ -257,7 +257,7 @@ struct wayland_client_surface *wayland_client_surface_create(HWND hwnd); BOOL wayland_client_surface_release(struct wayland_client_surface *client); void wayland_client_surface_attach(struct wayland_client_surface *client, HWND toplevel); void wayland_client_surface_detach(struct wayland_client_surface *client); -void wayland_surface_ensure_contents(struct wayland_surface *surface, struct wayland_client_surface *client); +void wayland_surface_ensure_contents(struct wayland_surface *surface); void wayland_surface_set_title(struct wayland_surface *surface, LPCWSTR title);
/********************************************************************** diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index dda5e00fc29..e6d1761663c 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -228,27 +228,23 @@ static void wayland_win_data_update_wayland_surface(struct wayland_win_data *dat goto out; }
+ visible = (NtUserGetWindowLongW(data->hwnd, GWL_STYLE) & WS_VISIBLE) == WS_VISIBLE; + if (!visible && client) wayland_client_surface_detach(client); + /* Otherwise ensure that we have a wayland surface. */ if (!surface && !(surface = wayland_surface_create(data->hwnd))) return; - - visible = (NtUserGetWindowLongW(data->hwnd, GWL_STYLE) & WS_VISIBLE) == WS_VISIBLE; xdg_visible = surface->xdg_toplevel != NULL;
if (visible != xdg_visible) { /* If we have a pre-existing surface ensure it has no role. */ - if (data->wayland_surface) - { - if (client) wayland_client_surface_detach(client); - wayland_surface_clear_role(surface); - } + if (data->wayland_surface) wayland_surface_clear_role(surface); /* 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. */ if (visible) { wayland_surface_make_toplevel(surface); - if (client) wayland_client_surface_attach(client, data->hwnd); if (surface->xdg_toplevel) { if (!NtUserInternalGetWindowText(data->hwnd, text, ARRAY_SIZE(text))) @@ -258,6 +254,7 @@ static void wayland_win_data_update_wayland_surface(struct wayland_win_data *dat } }
+ 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 @@ -756,7 +753,7 @@ BOOL set_window_surface_contents(HWND hwnd, struct wayland_shm_buffer *shm_buffe
if ((wayland_surface = data->wayland_surface)) { - if (wayland_surface_reconfigure(wayland_surface, data->client_surface)) + if (wayland_surface_reconfigure(wayland_surface)) { wayland_surface_attach_shm(wayland_surface, shm_buffer, damage_region); wl_surface_commit(wayland_surface->wl_surface); @@ -801,13 +798,13 @@ void ensure_window_surface_contents(HWND hwnd)
if ((wayland_surface = data->wayland_surface)) { - wayland_surface_ensure_contents(wayland_surface, data->client_surface); + wayland_surface_ensure_contents(wayland_surface);
/* Handle any processed configure request, to ensure the related * surface state is applied by the compositor. */ if (wayland_surface->processing.serial && wayland_surface->processing.processed && - wayland_surface_reconfigure(wayland_surface, data->client_surface)) + wayland_surface_reconfigure(wayland_surface)) { wl_surface_commit(wayland_surface->wl_surface); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winewayland.drv/window.c | 42 ++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 20 deletions(-)
diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index e6d1761663c..1f219760790 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -206,33 +206,19 @@ static void reapply_cursor_clipping(void) NtUserSetThreadDpiAwarenessContext(context); }
-static void wayland_win_data_update_wayland_surface(struct wayland_win_data *data) +static BOOL wayland_win_data_update_wayland_surface(struct wayland_win_data *data) { struct wayland_client_surface *client = data->client_surface; - struct wayland_surface *surface = data->wayland_surface; - HWND parent = NtUserGetAncestor(data->hwnd, GA_PARENT); + struct wayland_surface *surface; BOOL visible, xdg_visible; WCHAR text[1024];
TRACE("hwnd=%p\n", data->hwnd);
- /* We don't want wayland surfaces for child windows. */ - if (parent != NtUserGetDesktopWindow() && parent != 0) - { - if (surface) - { - if (client) wayland_client_surface_detach(client); - wayland_surface_destroy(surface); - } - surface = NULL; - goto out; - } - visible = (NtUserGetWindowLongW(data->hwnd, GWL_STYLE) & WS_VISIBLE) == WS_VISIBLE; if (!visible && client) wayland_client_surface_detach(client);
- /* Otherwise ensure that we have a wayland surface. */ - if (!surface && !(surface = wayland_surface_create(data->hwnd))) return; + if (!(surface = data->wayland_surface) && !(surface = wayland_surface_create(data->hwnd))) return FALSE; xdg_visible = surface->xdg_toplevel != NULL;
if (visible != xdg_visible) @@ -261,9 +247,9 @@ static void wayland_win_data_update_wayland_surface(struct wayland_win_data *dat * it as needed. */ if (data->hwnd == NtUserGetForegroundWindow()) reapply_cursor_clipping();
-out: TRACE("hwnd=%p surface=%p=>%p\n", data->hwnd, data->wayland_surface, surface); data->wayland_surface = surface; + return TRUE; }
static void wayland_win_data_update_wayland_state(struct wayland_win_data *data) @@ -448,6 +434,7 @@ BOOL WAYLAND_WindowPosChanging(HWND hwnd, UINT swp_flags, BOOL shaped, const str void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, const struct window_rects *new_rects, struct window_surface *surface) { + struct wayland_client_surface *client; struct wayland_win_data *data; BOOL managed;
@@ -463,8 +450,23 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, cons data->rects = *new_rects; data->managed = managed;
- wayland_win_data_update_wayland_surface(data); - if (data->wayland_surface) wayland_win_data_update_wayland_state(data); + if (!surface) + { + if ((client = data->client_surface)) + { + wayland_client_surface_detach(client); + } + + if (data->wayland_surface) + { + wayland_surface_destroy(data->wayland_surface); + data->wayland_surface = NULL; + } + } + else if (wayland_win_data_update_wayland_surface(data)) + { + wayland_win_data_update_wayland_state(data); + }
wayland_win_data_release(data); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winewayland.drv/wayland_surface.c | 16 ++++++++++------ dlls/winewayland.drv/waylanddrv.h | 4 +++- dlls/winewayland.drv/window.c | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index 4dc3101de76..9ac95454cfa 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -494,18 +494,19 @@ static void wayland_surface_reconfigure_size(struct wayland_surface *surface, * * Reconfigures the subsurface covering the client area. */ -void wayland_surface_reconfigure_client(struct wayland_surface *surface, struct wayland_client_surface *client) +void wayland_surface_reconfigure_client(struct wayland_surface *surface, struct wayland_client_surface *client, + const RECT *client_rect) { struct wayland_window_config *window = &surface->window; int client_x, client_y, x, y; int client_width, client_height, width, height;
/* The offset of the client area origin relatively to the window origin. */ - client_x = window->client_rect.left - window->rect.left; - client_y = window->client_rect.top - window->rect.top; + client_x = client_rect->left + window->client_rect.left - window->rect.left; + client_y = client_rect->top + window->client_rect.top - window->rect.top;
- client_width = window->client_rect.right - window->client_rect.left; - client_height = window->client_rect.bottom - window->client_rect.top; + client_width = client_rect->right - client_rect->left; + client_height = client_rect->bottom - client_rect->top;
wayland_surface_coords_from_window(surface, client_x, client_y, &x, &y); wayland_surface_coords_from_window(surface, client_width, client_height, @@ -820,6 +821,7 @@ void wayland_client_surface_attach(struct wayland_client_surface *client, HWND t { struct wayland_win_data *toplevel_data = wayland_win_data_get_nolock(toplevel); struct wayland_surface *surface; + RECT client_rect;
if (!toplevel_data || !(surface = toplevel_data->wayland_surface)) { @@ -846,7 +848,9 @@ void wayland_client_surface_attach(struct wayland_client_surface *client, HWND t client->toplevel = toplevel; }
- wayland_surface_reconfigure_client(surface, client); + NtUserGetClientRect(client->hwnd, &client_rect, get_win_monitor_dpi(client->hwnd)); + + wayland_surface_reconfigure_client(surface, client, &client_rect); /* Commit to apply subsurface positioning. */ wl_surface_commit(surface->wl_surface); } diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index bd599f2291b..ec13e76c1cf 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -243,7 +243,8 @@ void wayland_surface_attach_shm(struct wayland_surface *surface, struct wayland_shm_buffer *shm_buffer, HRGN surface_damage_region); BOOL wayland_surface_reconfigure(struct wayland_surface *surface); -void wayland_surface_reconfigure_client(struct wayland_surface *surface, struct wayland_client_surface *client); +void wayland_surface_reconfigure_client(struct wayland_surface *surface, struct wayland_client_surface *client, + const RECT *client_rect); BOOL wayland_surface_config_is_compatible(struct wayland_surface_config *conf, int width, int height, enum wayland_surface_config_state state); @@ -290,6 +291,7 @@ struct wayland_win_data BOOL managed; };
+UINT get_win_monitor_dpi(HWND hwnd); struct wayland_win_data *wayland_win_data_get(HWND hwnd); struct wayland_win_data *wayland_win_data_get_nolock(HWND hwnd); void wayland_win_data_release(struct wayland_win_data *data); diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index 1f219760790..f3072e6d487 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -40,7 +40,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv); /********************************************************************** * get_win_monitor_dpi */ -static UINT get_win_monitor_dpi(HWND hwnd) +UINT get_win_monitor_dpi(HWND hwnd) { return NtUserGetSystemDpiForProcess(NULL); /* FIXME: get monitor dpi */ }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winewayland.drv/wayland_surface.c | 1 + dlls/winewayland.drv/window.c | 18 +++++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index 9ac95454cfa..be54e818219 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -849,6 +849,7 @@ void wayland_client_surface_attach(struct wayland_client_surface *client, HWND t }
NtUserGetClientRect(client->hwnd, &client_rect, get_win_monitor_dpi(client->hwnd)); + NtUserMapWindowPoints(client->hwnd, toplevel, (POINT *)&client_rect, 2, get_win_monitor_dpi(client->hwnd));
wayland_surface_reconfigure_client(surface, client, &client_rect); /* Commit to apply subsurface positioning. */ diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index f3072e6d487..e73b5c4fb48 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -436,10 +436,12 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, cons { struct wayland_client_surface *client; struct wayland_win_data *data; + HWND toplevel; BOOL managed;
TRACE("hwnd %p new_rects %s after %p flags %08x\n", hwnd, debugstr_window_rects(new_rects), insert_after, swp_flags);
+ if ((toplevel = NtUserGetAncestor(hwnd, GA_ROOT)) == hwnd) toplevel = 0; /* 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. */ @@ -454,7 +456,10 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, cons { if ((client = data->client_surface)) { - wayland_client_surface_detach(client); + if (toplevel && NtUserIsWindowVisible(hwnd)) + wayland_client_surface_attach(client, toplevel); + else + wayland_client_surface_detach(client); }
if (data->wayland_surface) @@ -710,20 +715,19 @@ LRESULT WAYLAND_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam) struct wayland_client_surface *get_client_surface(HWND hwnd) { struct wayland_client_surface *client; - struct wayland_surface *surface; struct wayland_win_data *data; + HWND toplevel; + + if ((toplevel = NtUserGetAncestor(hwnd, GA_ROOT)) == hwnd) toplevel = 0;
if ((data = wayland_win_data_get(hwnd))) { - surface = data->wayland_surface; - /* ownership is shared with one of the callers, the last caller to release * its reference will also destroy it and clear our pointer. */ if ((client = data->client_surface)) InterlockedIncrement(&client->ref); } else { - surface = NULL; client = NULL; }
@@ -734,8 +738,8 @@ struct wayland_client_surface *get_client_surface(HWND hwnd) } if (!data) return client;
- if (surface && NtUserIsWindowVisible(hwnd)) - wayland_client_surface_attach(client, data->hwnd); + if (toplevel && NtUserIsWindowVisible(hwnd)) + wayland_client_surface_attach(client, toplevel); else wayland_client_surface_detach(client);
I've reworked a bit of everything, moving more of the attachment logic to the client surface, I think it isolates a bit more the details of how client windows are presented from the top-level windowing logic.
On Tue Sep 17 14:08:43 2024 +0000, Rémi Bernon wrote:
I've reworked a bit of everything, moving more of the attachment logic to the client surface, I think it isolates a bit more the details of how client windows are presented from the top-level windowing logic.
Thanks, I have done some preliminary testing/review and it looks good so far. However, I am hitting (what I believe to be) a pre-existing bug which I filed at https://bugs.winehq.org/show_bug.cgi?id=57199 and which is preventing me from running (with more confidence) some more extensive stress tests on this MR.
On Tue Sep 17 14:08:43 2024 +0000, Alexandros Frantzis wrote:
Thanks, I have done some preliminary testing/review and it looks good so far. However, I am hitting (what I believe to be) a pre-existing bug which I filed at https://bugs.winehq.org/show_bug.cgi?id=57199 and which is preventing me from running (with more confidence) some more extensive stress tests on this MR.
https://gitlab.winehq.org/wine/wine/-/merge_requests/6512 should fix the leak, thanks for the report!
Alexandros Frantzis (@afrantzis) commented about dlls/winewayland.drv/window.c:
struct wayland_client_surface *get_client_surface(HWND hwnd) { struct wayland_client_surface *client;
- struct wayland_surface *surface; struct wayland_win_data *data;
- HWND toplevel;
- if ((toplevel = NtUserGetAncestor(hwnd, GA_ROOT)) == hwnd) toplevel = 0;
This prevents attaching a (non-child) client surface to its window surface. The client surface may be eventually attached during `wayland_win_data_update_wayland_surface`, but depending on the application this may not happen at the right time (or ever unless there is some user interaction).
Alexandros Frantzis (@afrantzis) commented about dlls/winewayland.drv/window.c:
{ struct wayland_client_surface *client; struct wayland_win_data *data;
HWND toplevel; BOOL managed;
TRACE("hwnd %p new_rects %s after %p flags %08x\n", hwnd, debugstr_window_rects(new_rects), insert_after, swp_flags);
if ((toplevel = NtUserGetAncestor(hwnd, GA_ROOT)) == hwnd) toplevel = 0;
Similarly to my other comment, this seems a bit suspicious, but perhaps it's actually what we want in this particular case, since the toplevel is only used in the `!surface` case below.
I guess if `hwnd` is a toplevel itself and it doesn't have a window_surface (how can that happen?), it wouldn't make sense to attach the client surface either?
On Fri Aug 23 11:16:48 2024 +0000, Alexandros Frantzis wrote:
Maybe it's a matter of avoiding unnecesary client window attach/detach
operations, I didn't try to be very careful about that. I guess it could help, but even if it does, it would just be a workaround for (what seems to me to be) a compositor issue. That being said, we may still want to do reduce attach/detach operations for efficiency rather than correctness reasons. In any case, I will try to chase this with upstream kwin.
Or can we also maybe detach buffers from the surface ourselves?
This is what I did to test my hypothesis for kwin, but I wouldn't want to have it there normally, because, like the `client->wl_surface` commit that we want to avoid, it can also lead to interleaving problems with GL/VK. If the worst case for this was just a transient visual glitch, perhaps it would be acceptable, but there are in fact scenarios where the compositor would disconnect us with a protocol error (see https://gitlab.freedesktop.org/mesa/mesa/-/blob/421c42170e1abda849ea19c07f61... and https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/d1d185c61f68...).
Since this MR is now moving all client surface reconfiguration to the window thread, the chances of unfortunate interactions with the (possibly different) render thread (as discussed above) are increased. So, I would propose removing the `wl_surface_commit(client->wl_surface)` from `wayland_surface_reconfigure_client()`. The trade-off is that the client surface viewport will be applied at render time, which may increase sizing related artifacts when resizing and the GL/VK redraw is slow.
With the above, if an application resizes but doesn't render again the viewport will not be applied, but I think that's quite an edge case.