[PATCH v8 0/1] MR9868: winewayland: Fix non-square icons with xdg-toplevel-icon protocol.
Currently, it will stop the app that is running that has a non-square icon This PR fixes that -- v8: winewayland: Fix non-square icons with xdg-toplevel-icon protocol. https://gitlab.winehq.org/wine/wine/-/merge_requests/9868
From: Alex Schwartz <alexschwartz01@gmail.com> --- dlls/winewayland.drv/wayland_pointer.c | 2 +- dlls/winewayland.drv/wayland_surface.c | 59 ++++++++++++++++++++++---- dlls/winewayland.drv/waylanddrv.h | 2 +- 3 files changed, 53 insertions(+), 10 deletions(-) diff --git a/dlls/winewayland.drv/wayland_pointer.c b/dlls/winewayland.drv/wayland_pointer.c index c4fdb33a766..2959351b389 100644 --- a/dlls/winewayland.drv/wayland_pointer.c +++ b/dlls/winewayland.drv/wayland_pointer.c @@ -545,7 +545,7 @@ static void wayland_pointer_update_cursor_buffer(HCURSOR hcursor, double scale) { HDC hdc = NtGdiCreateCompatibleDC(0); cursor->shm_buffer = - wayland_shm_buffer_from_color_bitmaps(hdc, info.hbmColor, info.hbmMask); + wayland_shm_buffer_from_color_bitmaps(hdc, info.hbmColor, info.hbmMask, TRUE); NtGdiDeleteObjectApp(hdc); } else diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index b0b51212ec6..62f6fcd344e 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -874,6 +874,28 @@ err: return NULL; } +/*********************************************************************** + * copy_rectangle_into_center_of_square + * + * Copies non-square rectangle src to the center of square dest. + */ +static void copy_rectangle_into_center_of_square(const unsigned int *src, + int src_w, int src_h, + int square_length, + unsigned int *dest) +{ + const int off_x = (square_length - src_w) / 2; + const int off_y = (square_length - 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 = dest + (off_y + y) * square_length + off_x; + memcpy(d, s, src_w * 4); + } +} + /*********************************************************************** * wayland_shm_buffer_from_color_bitmaps * @@ -882,20 +904,23 @@ err: * Adapted from wineandroid.drv code. */ struct wayland_shm_buffer *wayland_shm_buffer_from_color_bitmaps(HDC hdc, HBITMAP color, - HBITMAP mask) + HBITMAP mask, BOOL isCursor) { struct wayland_shm_buffer *shm_buffer = NULL; char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])]; BITMAPINFO *info = (BITMAPINFO *)buffer; BITMAP bm; - unsigned int *ptr, *bits = NULL; + unsigned int *ptr, *bits = NULL, *non_square_bits; unsigned char *mask_bits = NULL; - int i, j; + int i, j, square_length; 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 - length is the larger side */ + square_length = (bm.bmWidth > bm.bmHeight) ? bm.bmWidth : bm.bmHeight; + + shm_buffer = wayland_shm_buffer_create(square_length, square_length, WL_SHM_FORMAT_ARGB8888); if (!shm_buffer) goto failed; bits = shm_buffer->map_data; @@ -912,9 +937,27 @@ 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, - DIB_RGB_COLORS, 0, 0)) - goto failed; + if (bm.bmWidth == bm.bmHeight || isCursor) + { + if (!NtGdiGetDIBitsInternal(hdc, color, 0, bm.bmHeight, bits, info, + DIB_RGB_COLORS, 0, 0)) + goto failed; + } + else + { + if (!(non_square_bits = malloc(bm.bmWidth * bm.bmHeight * 4))) goto failed; + + if (!NtGdiGetDIBitsInternal(hdc, color, 0, bm.bmHeight, non_square_bits, info, + DIB_RGB_COLORS, 0, 0)) + { + free(non_square_bits); + goto failed; + } + + copy_rectangle_into_center_of_square(non_square_bits, bm.bmWidth, bm.bmHeight, square_length, bits); + + free(non_square_bits); + } for (i = 0; i < bm.bmWidth * bm.bmHeight; i++) if ((has_alpha = (bits[i] & 0xff000000) != 0)) break; @@ -1253,7 +1296,7 @@ void wayland_surface_set_icon_buffer(struct wayland_surface *surface, UINT type, TRACE("surface=%p type=%x ii=%p\n", surface, type, ii); hDC = NtGdiCreateCompatibleDC(0); - icon_buf = wayland_shm_buffer_from_color_bitmaps(hDC, ii->hbmColor, ii->hbmMask); + icon_buf = wayland_shm_buffer_from_color_bitmaps(hDC, ii->hbmColor, ii->hbmMask, FALSE); NtGdiDeleteObjectApp(hDC); if (surface->big_icon_buffer && type == ICON_BIG) diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 9452d237fa3..99bc228f186 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -347,7 +347,7 @@ static inline BOOL wayland_surface_is_toplevel(struct wayland_surface *surface) struct wayland_shm_buffer *wayland_shm_buffer_create(int width, int height, enum wl_shm_format format); struct wayland_shm_buffer *wayland_shm_buffer_from_color_bitmaps(HDC hdc, HBITMAP color, - HBITMAP mask); + HBITMAP mask, BOOL isCursor); void wayland_shm_buffer_ref(struct wayland_shm_buffer *shm_buffer); void wayland_shm_buffer_unref(struct wayland_shm_buffer *shm_buffer); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9868
On Sat Jan 10 01:53:01 2026 +0000, Etaash Mathamsetty wrote:
Since this function is also used for loading the cursor shm buffer, it would be better if we can keep the image rectangular for the cursor and make it square for xdg-toplevel-icon. Just changed it to bypass the non-square logic if it's from the cursor/pointer path
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9868#note_126595
Etaash Mathamsetty (@etaash.mathamsetty) commented about dlls/winewayland.drv/wayland_surface.c:
BITMAPINFO *info = (BITMAPINFO *)buffer; BITMAP bm; - unsigned int *ptr, *bits = NULL; + unsigned int *ptr, *bits = NULL, *non_square_bits; unsigned char *mask_bits = NULL; - int i, j; + int i, j, square_length; 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 - length is the larger side */ + square_length = (bm.bmWidth > bm.bmHeight) ? bm.bmWidth : bm.bmHeight; + + shm_buffer = wayland_shm_buffer_create(square_length, square_length,
This would also need a check for if we want to create a square or not. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9868#note_126664
Etaash Mathamsetty (@etaash.mathamsetty) commented about dlls/winewayland.drv/wayland_surface.c:
* Adapted from wineandroid.drv code. */ struct wayland_shm_buffer *wayland_shm_buffer_from_color_bitmaps(HDC hdc, HBITMAP color, - HBITMAP mask) + HBITMAP mask, BOOL isCursor) Maybe something like force_square would be better instead of isCursor? Not too sure what to call it either, but at least should be more general
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9868#note_126665
Etaash Mathamsetty (@etaash.mathamsetty) commented about dlls/winewayland.drv/wayland_surface.c:
struct wayland_shm_buffer *shm_buffer = NULL; char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])]; BITMAPINFO *info = (BITMAPINFO *)buffer; BITMAP bm; - unsigned int *ptr, *bits = NULL; + unsigned int *ptr, *bits = NULL, *non_square_bits; unsigned char *mask_bits = NULL; - int i, j; + int i, j, square_length; 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 - length is the larger side */ + square_length = (bm.bmWidth > bm.bmHeight) ? bm.bmWidth : bm.bmHeight;
using something like max() would be more clear IMO -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9868#note_126666
participants (3)
-
Alex Schwartz -
Alex Schwartz (@alexschwartz01) -
Etaash Mathamsetty (@etaash.mathamsetty)