From: chenzhengyong <chenzhengyong@uniontech.com> Some compositors support server-side decorated windows. Adding support for SSD will make some window style better match the system. Signed-off-by: chenzhengyong <chenzhengyong@uniontech.com> --- dlls/winewayland.drv/Makefile.in | 1 + dlls/winewayland.drv/wayland.c | 5 ++ dlls/winewayland.drv/wayland_surface.c | 57 ++++++++++++++- dlls/winewayland.drv/waylanddrv.h | 7 +- dlls/winewayland.drv/waylanddrv_main.c | 1 + dlls/winewayland.drv/window.c | 97 +++++++++++++++++++++++++- 6 files changed, 163 insertions(+), 5 deletions(-) diff --git a/dlls/winewayland.drv/Makefile.in b/dlls/winewayland.drv/Makefile.in index 1f1b2ccf8af..da238941d25 100644 --- a/dlls/winewayland.drv/Makefile.in +++ b/dlls/winewayland.drv/Makefile.in @@ -27,6 +27,7 @@ SOURCES = \ window.c \ window_surface.c \ wlr-data-control-unstable-v1.xml \ + xdg-decoration-unstable-v1.xml \ xdg-output-unstable-v1.xml \ xdg-shell.xml \ xdg-toplevel-icon-v1.xml diff --git a/dlls/winewayland.drv/wayland.c b/dlls/winewayland.drv/wayland.c index b164210adf0..9e14d49115f 100644 --- a/dlls/winewayland.drv/wayland.c +++ b/dlls/winewayland.drv/wayland.c @@ -200,6 +200,11 @@ static void registry_handle_global(void *data, struct wl_registry *registry, wl_registry_bind(registry, id, &wp_cursor_shape_manager_v1_interface, version < 2 ? version : 2); } + else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0) + { + process_wayland.zxdg_decoration_manager_v1 = + wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1); + } } static void registry_handle_global_remove(void *data, struct wl_registry *registry, diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index 2f8275ddb52..f1aeb5d93a2 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -138,6 +138,30 @@ static const struct xdg_toplevel_listener xdg_toplevel_listener = xdg_toplevel_handle_close }; +static void xdg_decoration_handle_configure(void *private, + struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, + uint32_t mode) +{ + struct wayland_surface *surface; + HWND hwnd = private; + struct wayland_win_data *data; + + TRACE("hwnd=%p mode=%u\n", hwnd, mode); + if (!(data = wayland_win_data_get(hwnd))) return; + + if ((surface = data->wayland_surface) && wayland_surface_is_toplevel(surface)) + { + surface->decoration_mode = mode; + } + + wayland_win_data_release(data); +} + +static const struct zxdg_toplevel_decoration_v1_listener zxdg_decoration_listener = +{ + xdg_decoration_handle_configure +}; + /********************************************************************** * wayland_surface_create * @@ -246,7 +270,7 @@ void wayland_surface_destroy(struct wayland_surface *surface) * * Gives the toplevel role to a plain wayland surface. */ -void wayland_surface_make_toplevel(struct wayland_surface *surface) +void wayland_surface_make_toplevel(struct wayland_surface *surface, BOOL decorated) { WCHAR text[1024]; @@ -267,6 +291,31 @@ void wayland_surface_make_toplevel(struct wayland_surface *surface) if (!surface->xdg_toplevel) goto err; xdg_toplevel_add_listener(surface->xdg_toplevel, &xdg_toplevel_listener, surface->hwnd); + if (process_wayland.zxdg_decoration_manager_v1) + { + surface->zxdg_toplevel_decoration = + zxdg_decoration_manager_v1_get_toplevel_decoration(process_wayland.zxdg_decoration_manager_v1, + surface->xdg_toplevel); + if (surface->zxdg_toplevel_decoration) { + if (decorated) + { + zxdg_toplevel_decoration_v1_set_mode(surface->zxdg_toplevel_decoration, + ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + surface->decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; + } + else + { + zxdg_toplevel_decoration_v1_set_mode(surface->zxdg_toplevel_decoration, + ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); + surface->decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; + + } + zxdg_toplevel_decoration_v1_add_listener(surface->zxdg_toplevel_decoration, + &zxdg_decoration_listener, + surface->hwnd); + } + } + if (process_name) xdg_toplevel_set_app_id(surface->xdg_toplevel, process_name); @@ -353,6 +402,12 @@ void wayland_surface_clear_role(struct wayland_surface *surface) surface->xdg_toplevel_icon = NULL; } + if (surface->zxdg_toplevel_decoration) + { + zxdg_toplevel_decoration_v1_destroy(surface->zxdg_toplevel_decoration); + surface->zxdg_toplevel_decoration = NULL; + } + if (surface->xdg_toplevel) { xdg_toplevel_destroy(surface->xdg_toplevel); diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index ad41a1b474e..92ed9940be8 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -38,6 +38,7 @@ #include "xdg-shell-client-protocol.h" #include "wlr-data-control-unstable-v1-client-protocol.h" #include "xdg-toplevel-icon-v1-client-protocol.h" +#include "xdg-decoration-unstable-v1-client-protocol.h" #include "windef.h" #include "winbase.h" @@ -178,6 +179,7 @@ struct wayland struct wl_data_device_manager *wl_data_device_manager; struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager_v1; struct wp_cursor_shape_manager_v1 *wp_cursor_shape_manager_v1; + struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1; struct wayland_seat seat; struct wayland_keyboard keyboard; struct wayland_pointer pointer; @@ -283,6 +285,8 @@ struct wayland_surface HWND toplevel_hwnd; }; }; + struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration; + enum zxdg_toplevel_decoration_v1_mode decoration_mode; struct wayland_surface_config pending, requested, processing, current; BOOL resizing; @@ -311,7 +315,7 @@ void wayland_output_use_xdg_extension(struct wayland_output *output); struct wayland_surface *wayland_surface_create(HWND hwnd); void wayland_surface_destroy(struct wayland_surface *surface); -void wayland_surface_make_toplevel(struct wayland_surface *surface); +void wayland_surface_make_toplevel(struct wayland_surface *surface, BOOL decorated); void wayland_surface_make_subsurface(struct wayland_surface *surface, struct wayland_surface *parent); void wayland_surface_clear_role(struct wayland_surface *surface); @@ -458,5 +462,6 @@ BOOL WAYLAND_WindowPosChanging(HWND hwnd, UINT swp_flags, BOOL shaped, const str BOOL WAYLAND_CreateWindowSurface(HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface); UINT WAYLAND_VulkanInit(UINT version, void *vulkan_handle, const struct vulkan_driver_funcs **driver_funcs); UINT WAYLAND_OpenGLInit(UINT version, const struct opengl_funcs *opengl_funcs, const struct opengl_driver_funcs **driver_funcs); +BOOL WAYLAND_GetWindowStyleMasks( HWND hwnd, UINT style, UINT ex_style, UINT *style_mask, UINT *ex_style_mask ); #endif /* __WINE_WAYLANDDRV_H */ diff --git a/dlls/winewayland.drv/waylanddrv_main.c b/dlls/winewayland.drv/waylanddrv_main.c index cdb5dd8a956..e7b52e5b2f0 100644 --- a/dlls/winewayland.drv/waylanddrv_main.c +++ b/dlls/winewayland.drv/waylanddrv_main.c @@ -56,6 +56,7 @@ static const struct user_driver_funcs waylanddrv_funcs = .pCreateWindowSurface = WAYLAND_CreateWindowSurface, .pVulkanInit = WAYLAND_VulkanInit, .pOpenGLInit = WAYLAND_OpenGLInit, + .pGetWindowStyleMasks = WAYLAND_GetWindowStyleMasks, }; static void wayland_init_process_name(void) diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index 07e0858fb39..fb352ff019a 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -148,6 +148,48 @@ void wayland_win_data_release(struct wayland_win_data *data) pthread_mutex_unlock(&win_data_mutex); } +/*********************************************************************** + * get_mwm_decoration_for_style + */ +static BOOL get_mwm_decoration_for_style( DWORD style, DWORD ex_style ) +{ + if (ex_style & WS_EX_TOOLWINDOW) return FALSE; + if (ex_style & WS_EX_LAYERED) return FALSE; + + if ((style & WS_CAPTION) == WS_CAPTION) + { + return TRUE; + } + return FALSE; +} + +/*********************************************************************** + * get_mwm_decoration + * get window should have decoration + */ +static BOOL get_mwm_decoration( struct wayland_win_data *data ) +{ + DWORD style, ex_style; + + if (data->hwnd == NtUserGetDesktopWindow()) + { + /* force some styles for the desktop to get the correct decorations */ + style = WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; + ex_style = WS_EX_APPWINDOW; + } + else + { + style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); + ex_style = NtUserGetWindowLongW( data->hwnd, GWL_EXSTYLE ); + } + + if (EqualRect( &data->rects.window, &data->rects.visible )) + { + return FALSE; + } + return get_mwm_decoration_for_style( style, ex_style ); +} + static void wayland_win_data_get_config(struct wayland_win_data *data, struct wayland_window_config *conf) { @@ -232,7 +274,7 @@ static BOOL wayland_win_data_create_wayland_surface(struct wayland_win_data *dat wayland_surface_clear_role(surface); break; case WAYLAND_SURFACE_ROLE_TOPLEVEL: - wayland_surface_make_toplevel(surface); + wayland_surface_make_toplevel(surface, get_mwm_decoration(data)); break; case WAYLAND_SURFACE_ROLE_SUBSURFACE: wayland_surface_make_subsurface(surface, toplevel_surface); @@ -491,7 +533,7 @@ static void wayland_configure_window(HWND hwnd) INT window_surf_width, window_surf_height; UINT flags = 0; uint32_t state; - DWORD style; + DWORD style, flip_style = 0; BOOL needs_enter_size_move = FALSE; BOOL needs_exit_size_move = FALSE; struct wayland_win_data *data; @@ -588,7 +630,20 @@ static void wayland_configure_window(HWND hwnd) style = NtUserGetWindowLongW(hwnd, GWL_STYLE); if (!(state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED) != !(style & WS_MAXIMIZE)) - NtUserSetWindowLong(hwnd, GWL_STYLE, style ^ WS_MAXIMIZE, FALSE); + flip_style |= WS_MAXIMIZE; + + if (surface->decoration_mode) { + if (surface->decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE) + flip_style |= style & WS_CAPTION; + else + flip_style |= ~style & WS_CAPTION; + } + + if (flip_style & WS_CAPTION) + flags |= SWP_FRAMECHANGED; + + if (flip_style) + NtUserSetWindowLong(hwnd, GWL_STYLE, style ^ flip_style, FALSE); /* The Wayland maximized and fullscreen states are very strict about * surface size, so don't let the application override it. The tiled state @@ -874,3 +929,39 @@ void ensure_window_surface_contents(HWND hwnd) wayland_win_data_release(data); } + +BOOL WAYLAND_GetWindowStyleMasks( HWND hwnd, UINT style, UINT ex_style, UINT *style_mask, UINT *ex_style_mask ) +{ + BOOL decor = get_mwm_decoration_for_style( style, ex_style ); + struct wayland_win_data *data; + struct wayland_surface *wayland_surface; + + if ((data = wayland_win_data_get( hwnd ))) + { + if (!data->managed) + { + decor = FALSE; + } + /* compositor don't support xdg-decoration-unstable-v1 */ + else if (!process_wayland.zxdg_decoration_manager_v1) + { + decor = FALSE; + } + else if ((wayland_surface = data->wayland_surface)) + { + /* compositor support xdg-decoration-unstable-v1 but client-side decoration */ + if (wayland_surface->decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE) + decor = FALSE; + } + wayland_win_data_release( data ); + } + + *style_mask = *ex_style_mask = 0; + if (decor) + { + *style_mask |= WS_CAPTION | WS_DLGFRAME | WS_THICKFRAME; + *ex_style_mask |= WS_EX_DLGMODALFRAME; + } + + return TRUE; +} -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10257