-- v6: winewayland: Let the render threads commit changes to client surfaces. 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 | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index c325f9438d3..cf073fb9fcf 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.@) * @@ -1960,6 +1972,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 * @@ -2105,6 +2133,8 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru }
user_driver->pWindowPosChanged( hwnd, insert_after, swp_flags, is_fullscreen, &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 3dee8e432df..9c98fdb1586 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -293,7 +293,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 66e34d4f5bc..077c7576825 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -696,7 +696,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; @@ -709,15 +709,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 9c98fdb1586..a0d5deb5fab 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); @@ -291,6 +292,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 077c7576825..0cc5f323b24 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))) @@ -724,7 +737,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 a0d5deb5fab..ec15e5d5394 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 0cc5f323b24..82dae28c4f3 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 @@ -757,7 +754,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); @@ -802,13 +799,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 82dae28c4f3..afa5b917fbb 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, BOOL fullscreen, const struct window_rects *new_rects, struct window_surface *surface) { + struct wayland_client_surface *client; struct wayland_win_data *data; BOOL managed;
@@ -464,8 +451,23 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, BOOL data->is_fullscreen = fullscreen; 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 | 17 +++++++++++------ dlls/winewayland.drv/waylanddrv.h | 2 +- dlls/winewayland.drv/window.c | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index 4dc3101de76..c58aeca7286 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -494,18 +494,20 @@ 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) +static 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 +822,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 +849,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 ec15e5d5394..4b49b4fbb2f 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -243,7 +243,6 @@ 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); BOOL wayland_surface_config_is_compatible(struct wayland_surface_config *conf, int width, int height, enum wayland_surface_config_state state); @@ -291,6 +290,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 afa5b917fbb..b0b8f1a549b 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 | 15 ++++++++------- 2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index c58aeca7286..4f72150949b 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -850,6 +850,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 b0b8f1a549b..2a9f4ff8036 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -434,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, BOOL fullscreen, const struct window_rects *new_rects, struct window_surface *surface) { + HWND toplevel = NtUserGetAncestor(hwnd, GA_ROOT); struct wayland_client_surface *client; struct wayland_win_data *data; BOOL managed; @@ -455,7 +456,10 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, BOOL { 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,21 +714,18 @@ LRESULT WAYLAND_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam) */ struct wayland_client_surface *get_client_surface(HWND hwnd) { + HWND toplevel = NtUserGetAncestor(hwnd, GA_ROOT); struct wayland_client_surface *client; - struct wayland_surface *surface; struct wayland_win_data *data;
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; }
@@ -735,8 +736,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);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winewayland.drv/wayland_surface.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index 4f72150949b..e5794ee440f 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -526,8 +526,6 @@ static void wayland_surface_reconfigure_client(struct wayland_surface *surface, else /* We can't have a 0x0 destination, use 1x1 instead. */ wp_viewport_set_destination(client->wp_viewport, 1, 1);
- wl_surface_commit(client->wl_surface); - wayland_resize_gl_drawable(client->hwnd); }
On Thu Sep 19 22:02:23 2024 +0000, Rémi Bernon wrote:
changed this line in [version 6 of the diff](/wine/wine/-/merge_requests/6323/diffs?diff_id=133254&start_sha=711bcb31687a54318ca4c7f702c459205c5745cd#be6b1a6381414c8dae6f91e46942652a04a69f08_721_720)
Yeah, I made it unconditional. There's maybe some exotic corner cases where rendering is done on message windows and alike, but I think it should be handled by the surface presence check.
On Wed Sep 18 08:48:13 2024 +0000, Alexandros Frantzis wrote:
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.
I added a change to remove the client surface commit from our side.
Alexandros Frantzis (@afrantzis) commented about dlls/winewayland.drv/opengl.c:
gl->hwnd = hwnd; gl->swap_interval = 1;
- NtUserGetClientRect(gl->hwnd, &client_rect, NtUserGetDpiForWindow(gl->hwnd));
When creating pbuffers we have hwnd=0, which causes `NtUserGetClientRect` to fail and client_rect to remain uninitialized, leading to problems below.
One small fix needed, but otherwise looks good to me. Thanks!