[PATCH v11 0/2] MR9832: win32u: Fix xdg-toplevel-icon Wayland protocol.
Fixes https://bugs.winehq.org/show_bug.cgi?id=59149 -- v11: winewayland: Fix non-square icons with xdg-toplevel-icon protocol. https://gitlab.winehq.org/wine/wine/-/merge_requests/9832
From: Alex Schwartz <alexschwartz01@gmail.com> --- dlls/win32u/defwnd.c | 6 ++-- dlls/win32u/driver.c | 7 +++++ dlls/win32u/window.c | 2 +- dlls/winewayland.drv/waylanddrv.h | 1 + dlls/winewayland.drv/waylanddrv_main.c | 1 + dlls/winewayland.drv/window.c | 38 ++++++++++++++++++-------- dlls/winex11.drv/init.c | 1 + dlls/winex11.drv/window.c | 9 ++++++ dlls/winex11.drv/x11drv.h | 1 + include/wine/gdi_driver.h | 3 +- 10 files changed, 52 insertions(+), 17 deletions(-) diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c index 885af182657..72e4e27856b 100644 --- a/dlls/win32u/defwnd.c +++ b/dlls/win32u/defwnd.c @@ -376,7 +376,7 @@ static HICON get_window_icon( HWND hwnd, WPARAM type ) static HICON set_window_icon( HWND hwnd, WPARAM type, HICON icon ) { HWND parent = NtUserGetAncestor( hwnd, GA_PARENT ); - BOOL is_child = parent && parent != NtUserGetDesktopWindow(); + BOOL is_child = parent && parent != NtUserGetDesktopWindow(), need_icons; HICON icon_small, ret = 0; ICONINFO ii, ii_small; WND *win; @@ -420,10 +420,10 @@ static HICON set_window_icon( HWND hwnd, WPARAM type, HICON icon ) icon = win->hIcon; icon_small = win->hIconSmall2 ? win->hIconSmall2 : win->hIconSmall; - win->has_icons = !is_child; + need_icons = win->has_icons = !is_child && user_driver->pAllowsToplevelIcon(hwnd); release_win_ptr( win ); - if (!is_child && (icon = get_window_icon_info( hwnd, ICON_BIG, icon, &ii ))) + if (need_icons && (icon = get_window_icon_info( hwnd, ICON_BIG, icon, &ii ))) { icon_small = get_window_icon_info( hwnd, ICON_SMALL, icon_small, &ii_small ); user_driver->pSetWindowIcons( hwnd, icon, &ii, icon_small, &ii_small ); diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 60aba702d1a..5a0e2a64d92 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -834,6 +834,11 @@ static void nulldrv_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw ) { } +static BOOL nulldrv_AllowsToplevelIcon( HWND hwnd ) +{ + return FALSE; +} + static void nulldrv_SetWindowIcons( HWND hwnd, HICON icon, const ICONINFO *ii, HICON icon_small, const ICONINFO *ii_small ) { } @@ -1293,6 +1298,7 @@ static const struct user_driver_funcs lazy_load_driver = loaderdrv_SetLayeredWindowAttributes, nulldrv_SetParent, loaderdrv_SetWindowRgn, + nulldrv_AllowsToplevelIcon, nulldrv_SetWindowIcons, nulldrv_SetWindowStyle, nulldrv_SetWindowText, @@ -1392,6 +1398,7 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version SET_USER_FUNC(SetLayeredWindowAttributes); SET_USER_FUNC(SetParent); SET_USER_FUNC(SetWindowRgn); + SET_USER_FUNC(AllowsToplevelIcon); SET_USER_FUNC(SetWindowIcons); SET_USER_FUNC(SetWindowStyle); SET_USER_FUNC(SetWindowText); diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 1464d45697e..5429054cadd 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -2252,7 +2252,7 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru (swp_flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW | SWP_STATECHANGED | SWP_FRAMECHANGED))) invalidate_dce( win, &old_rects.window ); - if (win->dwStyle & WS_VISIBLE && !is_child && !win->has_icons) + if (win->dwStyle & WS_VISIBLE && !is_child && !win->has_icons && user_driver->pAllowsToplevelIcon(hwnd)) { icon = win->hIcon; icon_small = win->hIconSmall2 ? win->hIconSmall2 : win->hIconSmall; diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 7ab1f58ba64..a0e99b13011 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -445,6 +445,7 @@ BOOL WAYLAND_SetIMECompositionRect(HWND hwnd, RECT rect); void WAYLAND_SetCursor(HWND hwnd, HCURSOR hcursor); BOOL WAYLAND_SetCursorPos(INT x, INT y); void WAYLAND_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags); +BOOL WAYLAND_AllowsToplevelIcon(HWND hwnd); void WAYLAND_SetWindowIcons(HWND hwnd, HICON icon, const ICONINFO *ii, HICON icon_small, const ICONINFO *ii_small); void WAYLAND_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style); void WAYLAND_SetWindowText(HWND hwnd, LPCWSTR text); diff --git a/dlls/winewayland.drv/waylanddrv_main.c b/dlls/winewayland.drv/waylanddrv_main.c index cdb5dd8a956..90826f46f7a 100644 --- a/dlls/winewayland.drv/waylanddrv_main.c +++ b/dlls/winewayland.drv/waylanddrv_main.c @@ -45,6 +45,7 @@ static const struct user_driver_funcs waylanddrv_funcs = .pSetCursor = WAYLAND_SetCursor, .pSetCursorPos = WAYLAND_SetCursorPos, .pSetLayeredWindowAttributes = WAYLAND_SetLayeredWindowAttributes, + .pAllowsToplevelIcon = WAYLAND_AllowsToplevelIcon, .pSetWindowIcons = WAYLAND_SetWindowIcons, .pSetWindowStyle = WAYLAND_SetWindowStyle, .pSetWindowText = WAYLAND_SetWindowText, diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index b838fd84191..d2b0dd84a43 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -664,6 +664,26 @@ static enum xdg_toplevel_resize_edge hittest_to_resize_edge(WPARAM hittest) } } +/***************************************************************** + * WAYLAND_AllowsToplevelIcon + */ +BOOL WAYLAND_AllowsToplevelIcon(HWND hwnd) +{ + BOOL allows_toplevel_icon; + + struct wayland_win_data *data; + + if (!(data = wayland_win_data_get(hwnd))) return FALSE; + + allows_toplevel_icon = data->wayland_surface && + wayland_surface_is_toplevel(data->wayland_surface) && + process_wayland.xdg_toplevel_icon_manager_v1; + + wayland_win_data_release(data); + + return allows_toplevel_icon; +} + /***************************************************************** * WAYLAND_SetWindowIcons */ @@ -673,18 +693,12 @@ void WAYLAND_SetWindowIcons(HWND hwnd, HICON icon, const ICONINFO *ii, HICON ico TRACE("hwnd=%p icon=%p ii=%p icon_small=%p ii_small=%p\n", hwnd, icon, ii, icon_small, ii_small); - if (process_wayland.xdg_toplevel_icon_manager_v1) - { - if ((data = wayland_win_data_get(hwnd))) - { - if (data->wayland_surface && wayland_surface_is_toplevel(data->wayland_surface)) - { - wayland_surface_set_icon(data->wayland_surface, ICON_BIG, ii); - wayland_surface_set_icon(data->wayland_surface, ICON_SMALL, ii_small); - } - wayland_win_data_release(data); - } - } + if (!(data = wayland_win_data_get(hwnd))) return; + + if (icon) wayland_surface_set_icon(data->wayland_surface, ICON_BIG, ii); + if (icon_small) wayland_surface_set_icon(data->wayland_surface, ICON_SMALL, ii_small); + + wayland_win_data_release(data); } /*********************************************************************** diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index 09ef2bf8664..23343642006 100644 --- a/dlls/winex11.drv/init.c +++ b/dlls/winex11.drv/init.c @@ -698,6 +698,7 @@ static const struct user_driver_funcs x11drv_funcs = .pActivateWindow = X11DRV_ActivateWindow, .pSetLayeredWindowAttributes = X11DRV_SetLayeredWindowAttributes, .pSetParent = X11DRV_SetParent, + .pAllowsToplevelIcon = X11DRV_AllowsToplevelIcon, .pSetWindowIcons = X11DRV_SetWindowIcons, .pSetWindowRgn = X11DRV_SetWindowRgn, .pSetWindowStyle = X11DRV_SetWindowStyle, diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index d256674c9c1..c9d6c8e662a 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -3393,6 +3393,15 @@ done: } +/********************************************************************** + * AllowsToplevelIcon (X11DRV.@) + */ +BOOL X11DRV_AllowsToplevelIcon(HWND hwnd) +{ + return TRUE; +} + + /********************************************************************** * SetWindowIcons (X11DRV.@) */ diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 9232988c9c7..81e786b85e2 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -238,6 +238,7 @@ extern void X11DRV_SetDesktopWindow( HWND hwnd ); extern void X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags ); extern void X11DRV_SetParent( HWND hwnd, HWND parent, HWND old_parent ); +extern BOOL X11DRV_AllowsToplevelIcon( HWND hwnd ); extern void X11DRV_SetWindowIcons( HWND hwnd, HICON icon, const ICONINFO *ii, HICON icon_small, const ICONINFO *ii_small ); extern void X11DRV_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw ); extern void X11DRV_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style ); diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 81932436963..067fc0d63cf 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -218,7 +218,7 @@ struct gdi_dc_funcs }; /* increment this when you change the DC function table */ -#define WINE_GDI_DRIVER_VERSION 108 +#define WINE_GDI_DRIVER_VERSION 109 #define GDI_PRIORITY_NULL_DRV 0 /* null driver */ #define GDI_PRIORITY_FONT_DRV 100 /* any font driver */ @@ -415,6 +415,7 @@ struct user_driver_funcs void (*pSetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD); void (*pSetParent)(HWND,HWND,HWND); void (*pSetWindowRgn)(HWND,HRGN,BOOL); + BOOL (*pAllowsToplevelIcon)(HWND); void (*pSetWindowIcons)(HWND,HICON,const ICONINFO*,HICON,const ICONINFO*); void (*pSetWindowStyle)(HWND,INT,STYLESTRUCT*); void (*pSetWindowText)(HWND,LPCWSTR); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9832
From: Alex Schwartz <alexschwartz01@gmail.com> --- dlls/winewayland.drv/wayland_surface.c | 55 ++++++++++++++++++++------ 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index 14171cfb911..31c110acd02 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -866,6 +866,28 @@ err: return NULL; } +/*********************************************************************** + * wayland_shm_buffer_copy_center_square + * + * Copies src into the center of bits. + */ +static void wayland_shm_buffer_copy_center_square(const unsigned int *src, + int src_w, int src_h, + int dst_edge, + unsigned int *bits) +{ + const int off_x = (dst_edge - src_w) / 2; + const int off_y = (dst_edge - src_h) / 2; + + /* Copy the original image into the centered square */ + for (int y = 0; y < src_h; ++y) + { + const unsigned int *s = src + y * src_w; + unsigned int *d = bits + (off_y + y) * dst_edge + off_x; + memcpy(d, s, src_w * 4); + } +} + /*********************************************************************** * wayland_shm_buffer_from_color_bitmaps * @@ -880,14 +902,17 @@ struct wayland_shm_buffer *wayland_shm_buffer_from_color_bitmaps(HDC hdc, HBITMA char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])]; BITMAPINFO *info = (BITMAPINFO *)buffer; BITMAP bm; - unsigned int *ptr, *bits = NULL; + unsigned int *ptr, *bits = NULL, *tmp; unsigned char *mask_bits = NULL; - int i, j; + int i, j, dst_edge; BOOL has_alpha = FALSE; if (!NtGdiExtGetObjectW(color, sizeof(bm), &bm)) goto failed; - shm_buffer = wayland_shm_buffer_create(bm.bmWidth, bm.bmHeight, + /* Make the buffer square - edge length is the larger side */ + dst_edge = (bm.bmWidth > bm.bmHeight) ? bm.bmWidth : bm.bmHeight; + + shm_buffer = wayland_shm_buffer_create(dst_edge, dst_edge, WL_SHM_FORMAT_ARGB8888); if (!shm_buffer) goto failed; bits = shm_buffer->map_data; @@ -904,27 +929,35 @@ struct wayland_shm_buffer *wayland_shm_buffer_from_color_bitmaps(HDC hdc, HBITMA info->bmiHeader.biClrUsed = 0; info->bmiHeader.biClrImportant = 0; - if (!NtGdiGetDIBitsInternal(hdc, color, 0, bm.bmHeight, bits, info, + if (!(tmp = malloc(bm.bmWidth * bm.bmHeight * 4))) goto failed; + + if (!NtGdiGetDIBitsInternal(hdc, color, 0, bm.bmHeight, tmp, info, DIB_RGB_COLORS, 0, 0)) goto failed; - for (i = 0; i < bm.bmWidth * bm.bmHeight; i++) + wayland_shm_buffer_copy_center_square(tmp, bm.bmWidth, bm.bmHeight, dst_edge, bits); + + free(tmp); + + for (i = 0; i < dst_edge * dst_edge; i++) + { if ((has_alpha = (bits[i] & 0xff000000) != 0)) break; + } if (!has_alpha) { - unsigned int width_bytes = (bm.bmWidth + 31) / 32 * 4; + unsigned int width_bytes = (dst_edge + 31) / 32 * 4; /* generate alpha channel from the mask */ info->bmiHeader.biBitCount = 1; - info->bmiHeader.biSizeImage = width_bytes * bm.bmHeight; + info->bmiHeader.biSizeImage = width_bytes * dst_edge; if (!(mask_bits = malloc(info->bmiHeader.biSizeImage))) goto failed; - if (!NtGdiGetDIBitsInternal(hdc, mask, 0, bm.bmHeight, mask_bits, + if (!NtGdiGetDIBitsInternal(hdc, mask, 0, dst_edge, mask_bits, info, DIB_RGB_COLORS, 0, 0)) goto failed; ptr = bits; - for (i = 0; i < bm.bmHeight; i++) + for (i = 0; i < dst_edge; i++) { - for (j = 0; j < bm.bmWidth; j++, ptr++) + for (j = 0; j < dst_edge; j++, ptr++) { if (!((mask_bits[i * width_bytes + j / 8] << (j % 8)) & 0x80)) *ptr |= 0xff000000; @@ -934,7 +967,7 @@ struct wayland_shm_buffer *wayland_shm_buffer_from_color_bitmaps(HDC hdc, HBITMA } /* Wayland requires pre-multiplied alpha values */ - for (ptr = bits, i = 0; i < bm.bmWidth * bm.bmHeight; ptr++, i++) + for (ptr = bits, i = 0; i < dst_edge * dst_edge; ptr++, i++) { unsigned char alpha = *ptr >> 24; if (alpha == 0) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9832
participants (2)
-
Alex Schwartz -
Alex Schwartz (@alexschwartz01)