Currently shell32 only transfers the plain icon for `Shell_NotifyIcon` calls, ignoring balloon icons. This patch allows transferring both images to explorer.exe tray.
-- v6: shell32: add support for balloon icon copying shell32: refactor notify_icon to allow copying multiple icons
From: Sergei Chernyadyev serg.cherniadjev@gmail.com
--- dlls/shell32/systray.c | 41 +++++++++++++++++++++---------------- programs/explorer/systray.c | 31 ++++++++++++++++++---------- 2 files changed, 43 insertions(+), 29 deletions(-)
diff --git a/dlls/shell32/systray.c b/dlls/shell32/systray.c index 78717cfcdca..ab1a772c1c2 100644 --- a/dlls/shell32/systray.c +++ b/dlls/shell32/systray.c @@ -34,6 +34,16 @@
WINE_DEFAULT_DEBUG_CHANNEL(systray);
+struct notify_data_icon +{ + /* data for the icon bitmap */ + UINT width; + UINT height; + UINT planes; + UINT bpp; + char buffer[]; +}; + struct notify_data /* platform-independent format for NOTIFYICONDATA */ { LONG hWnd; @@ -51,13 +61,10 @@ struct notify_data /* platform-independent format for NOTIFYICONDATA */ WCHAR szInfoTitle[64]; DWORD dwInfoFlags; GUID guidItem; - /* data for the icon bitmap */ - UINT width; - UINT height; - UINT planes; - UINT bpp; + struct notify_data_icon icons[]; };
+ /************************************************************************* * Shell_NotifyIcon [SHELL32.296] * Shell_NotifyIconA [SHELL32.297] @@ -180,7 +187,7 @@ BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW nid) cbMaskBits = (bmMask.bmPlanes * bmMask.bmWidth * bmMask.bmHeight * bmMask.bmBitsPixel + 15) / 16 * 2; if (iconinfo.hbmColor) cbColourBits = (bmColour.bmPlanes * bmColour.bmWidth * bmColour.bmHeight * bmColour.bmBitsPixel + 15) / 16 * 2; - cds.cbData = sizeof(*data) + cbMaskBits + cbColourBits; + cds.cbData = sizeof(*data) + sizeof(struct notify_data_icon) + cbMaskBits + cbColourBits; buffer = malloc(cds.cbData); if (!buffer) { @@ -192,23 +199,21 @@ BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW nid)
data = (struct notify_data *)buffer; memset( data, 0, sizeof(*data) ); - buffer += sizeof(*data); - GetBitmapBits(iconinfo.hbmMask, cbMaskBits, buffer); + GetBitmapBits(iconinfo.hbmMask, cbMaskBits, &data->icons[0].buffer); if (!iconinfo.hbmColor) { - data->width = bmMask.bmWidth; - data->height = bmMask.bmHeight / 2; - data->planes = 1; - data->bpp = 1; + data->icons[0].width = bmMask.bmWidth; + data->icons[0].height = bmMask.bmHeight / 2; + data->icons[0].planes = 1; + data->icons[0].bpp = 1; } else { - data->width = bmColour.bmWidth; - data->height = bmColour.bmHeight; - data->planes = bmColour.bmPlanes; - data->bpp = bmColour.bmBitsPixel; - buffer += cbMaskBits; - GetBitmapBits(iconinfo.hbmColor, cbColourBits, buffer); + data->icons[0].width = bmColour.bmWidth; + data->icons[0].height = bmColour.bmHeight; + data->icons[0].planes = bmColour.bmPlanes; + data->icons[0].bpp = bmColour.bmBitsPixel; + GetBitmapBits(iconinfo.hbmColor, cbColourBits, &data->icons[0].buffer[cbMaskBits]); DeleteObject(iconinfo.hbmColor); } DeleteObject(iconinfo.hbmMask); diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c index 275c683e3ff..92fafce5d7a 100644 --- a/programs/explorer/systray.c +++ b/programs/explorer/systray.c @@ -36,6 +36,16 @@ WINE_DEFAULT_DEBUG_CHANNEL(systray); #define TRAY_MINIMIZE_ALL 419 #define TRAY_MINIMIZE_ALL_UNDO 416
+struct notify_data_icon +{ + /* data for the icon bitmap */ + UINT width; + UINT height; + UINT planes; + UINT bpp; + char buffer[]; +}; + struct notify_data /* platform-independent format for NOTIFYICONDATA */ { LONG hWnd; @@ -54,10 +64,7 @@ struct notify_data /* platform-independent format for NOTIFYICONDATA */ DWORD dwInfoFlags; GUID guidItem; /* data for the icon bitmap */ - UINT width; - UINT height; - UINT planes; - UINT bpp; + struct notify_data_icon icons[]; };
#define ICON_DISPLAY_HIDDEN -1 @@ -825,6 +832,7 @@ static BOOL handle_incoming(HWND hwndSource, COPYDATASTRUCT *cds) { struct icon *icon = NULL; const struct notify_data *data; + const struct notify_data_icon *data_icon; NOTIFYICONDATAW nid; int ret = FALSE;
@@ -849,22 +857,23 @@ static BOOL handle_incoming(HWND hwndSource, COPYDATASTRUCT *cds)
/* FIXME: if statement only needed because we don't support interprocess * icon handles */ - if ((nid.uFlags & NIF_ICON) && cds->cbData > sizeof(*data)) + if ((nid.uFlags & NIF_ICON) && cds->cbData > (sizeof(*data) + sizeof(struct notify_data_icon))) { LONG cbMaskBits; LONG cbColourBits; - const char *buffer = (const char *)(data + 1); + data_icon = &data->icons[0];
- cbMaskBits = (data->width * data->height + 15) / 16 * 2; - cbColourBits = (data->planes * data->width * data->height * data->bpp + 15) / 16 * 2; + cbMaskBits = (data_icon->width * data_icon->height + 15) / 16 * 2; + cbColourBits = (data_icon->planes * data_icon->width * data_icon->height * data_icon->bpp + 15) / 16 * 2;
- if (cds->cbData < sizeof(*data) + cbMaskBits + cbColourBits) + if (cds->cbData < sizeof(*data) + sizeof(*data_icon) + cbMaskBits + cbColourBits) { ERR( "buffer underflow\n" ); return FALSE; } - nid.hIcon = CreateIcon(NULL, data->width, data->height, data->planes, data->bpp, - buffer, buffer + cbMaskBits); + nid.hIcon = CreateIcon(NULL, data_icon->width, data_icon->height, data_icon->planes, data_icon->bpp, + &data_icon->buffer[0], &data_icon->buffer[cbMaskBits]); + data_icon = (const struct notify_data_icon*)&data_icon->buffer[cbMaskBits + cbColourBits]; }
/* try forwarding to the display driver first */
From: Sergei Chernyadyev serg.cherniadjev@gmail.com
--- dlls/shell32/systray.c | 100 +++++++++++++++++++++++------------- programs/explorer/systray.c | 22 +++++++- 2 files changed, 85 insertions(+), 37 deletions(-)
diff --git a/dlls/shell32/systray.c b/dlls/shell32/systray.c index ab1a772c1c2..2524c23202c 100644 --- a/dlls/shell32/systray.c +++ b/dlls/shell32/systray.c @@ -132,6 +132,12 @@ BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW nid) COPYDATASTRUCT cds; struct notify_data data_buffer; struct notify_data *data = &data_buffer; + ICONINFO iconinfo[2] = { { 0 }, { 0 } }; + BITMAP bmMask[2]; + BITMAP bmColour[2]; + LONG cbMaskBits[2] = { 0, 0}; + LONG cbColourBits[2] = { 0, 0 }; + LONG iconCount = 0; BOOL ret;
TRACE("dwMessage = %ld, nid->cbSize=%ld\n", dwMessage, nid->cbSize); @@ -166,60 +172,84 @@ BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW nid) * icon handles */ if (nid->uFlags & NIF_ICON) { - ICONINFO iconinfo; - BITMAP bmMask; - BITMAP bmColour; - LONG cbMaskBits; - LONG cbColourBits = 0; - char *buffer; - - if (!GetIconInfo(nid->hIcon, &iconinfo)) + if (!GetIconInfo(nid->hIcon, &iconinfo[iconCount])) goto noicon;
- if (!GetObjectW(iconinfo.hbmMask, sizeof(bmMask), &bmMask) || - (iconinfo.hbmColor && !GetObjectW(iconinfo.hbmColor, sizeof(bmColour), &bmColour))) + if (!GetObjectW(iconinfo[iconCount].hbmMask, sizeof(bmMask), &bmMask[iconCount]) || + (iconinfo[iconCount].hbmColor && !GetObjectW(iconinfo[iconCount].hbmColor, sizeof(bmColour), &bmColour[iconCount]))) { - DeleteObject(iconinfo.hbmMask); - if (iconinfo.hbmColor) DeleteObject(iconinfo.hbmColor); + DeleteObject(iconinfo[iconCount].hbmMask); + if (iconinfo[iconCount].hbmColor) DeleteObject(iconinfo[iconCount].hbmColor); goto noicon; } + cbMaskBits[iconCount] = (bmMask[iconCount].bmPlanes * bmMask[iconCount].bmWidth * bmMask[iconCount].bmHeight * bmMask[iconCount].bmBitsPixel + 15) / 16 * 2; + if (iconinfo[iconCount].hbmColor) + cbColourBits[iconCount] = (bmColour[iconCount].bmPlanes * bmColour[iconCount].bmWidth * bmColour[iconCount].bmHeight * bmColour[iconCount].bmBitsPixel + 15) / 16 * 2; + iconCount++; + } +noicon: + if (nid->uFlags & NIF_INFO) + { + if (!GetIconInfo(nid->hBalloonIcon, &iconinfo[iconCount])) + goto noballoon;
- cbMaskBits = (bmMask.bmPlanes * bmMask.bmWidth * bmMask.bmHeight * bmMask.bmBitsPixel + 15) / 16 * 2; - if (iconinfo.hbmColor) - cbColourBits = (bmColour.bmPlanes * bmColour.bmWidth * bmColour.bmHeight * bmColour.bmBitsPixel + 15) / 16 * 2; - cds.cbData = sizeof(*data) + sizeof(struct notify_data_icon) + cbMaskBits + cbColourBits; + if (!GetObjectW(iconinfo[iconCount].hbmMask, sizeof(bmMask), &bmMask[iconCount]) || + (iconinfo[iconCount].hbmColor && !GetObjectW(iconinfo[iconCount].hbmColor, sizeof(bmColour), &bmColour[iconCount]))) + { + DeleteObject(iconinfo[iconCount].hbmMask); + if (iconinfo[iconCount].hbmColor) DeleteObject(iconinfo[iconCount].hbmColor); + goto noballoon; + } + cbMaskBits[iconCount] = (bmMask[iconCount].bmPlanes * bmMask[iconCount].bmWidth * bmMask[iconCount].bmHeight * bmMask[iconCount].bmBitsPixel + 15) / 16 * 2; + if (iconinfo[iconCount].hbmColor) + cbColourBits[iconCount] = (bmColour[iconCount].bmPlanes * bmColour[iconCount].bmWidth * bmColour[iconCount].bmHeight * bmColour[iconCount].bmBitsPixel + 15) / 16 * 2; + iconCount++; + } +noballoon: + if (iconCount > 0) + { + char *buffer; + struct notify_data_icon *data_icon; + cds.cbData = sizeof(*data) + sizeof(struct notify_data_icon) * iconCount + cbMaskBits[0] + cbMaskBits[1] + cbColourBits[0] + cbColourBits[1]; buffer = malloc(cds.cbData); if (!buffer) { - DeleteObject(iconinfo.hbmMask); - if (iconinfo.hbmColor) DeleteObject(iconinfo.hbmColor); + for (unsigned int i = 0; i < iconCount; i++) + { + if (iconinfo[i].hbmMask) DeleteObject(iconinfo[i].hbmMask); + if (iconinfo[i].hbmColor) DeleteObject(iconinfo[i].hbmColor); + } SetLastError(E_OUTOFMEMORY); return FALSE; }
data = (struct notify_data *)buffer; + data_icon = &data->icons[0]; memset( data, 0, sizeof(*data) ); - GetBitmapBits(iconinfo.hbmMask, cbMaskBits, &data->icons[0].buffer); - if (!iconinfo.hbmColor) + for (unsigned int i = 0; i < iconCount; i++) { - data->icons[0].width = bmMask.bmWidth; - data->icons[0].height = bmMask.bmHeight / 2; - data->icons[0].planes = 1; - data->icons[0].bpp = 1; + GetBitmapBits(iconinfo[i].hbmMask, cbMaskBits[i], &data_icon->buffer); + if (!iconinfo[i].hbmColor) + { + data_icon->width = bmMask[i].bmWidth; + data_icon->height = bmMask[i].bmHeight / 2; + data_icon->planes = 1; + data_icon->bpp = 1; + } + else + { + data_icon->width = bmColour[i].bmWidth; + data_icon->height = bmColour[i].bmHeight; + data_icon->planes = bmColour[i].bmPlanes; + data_icon->bpp = bmColour[i].bmBitsPixel; + GetBitmapBits(iconinfo[i].hbmColor, cbColourBits[i], &data_icon->buffer[cbMaskBits[i]]); + DeleteObject(iconinfo[i].hbmColor); + } + DeleteObject(iconinfo[i].hbmMask); + data_icon = (struct notify_data_icon*)&data_icon->buffer[cbMaskBits[i] + cbColourBits[i]]; } - else - { - data->icons[0].width = bmColour.bmWidth; - data->icons[0].height = bmColour.bmHeight; - data->icons[0].planes = bmColour.bmPlanes; - data->icons[0].bpp = bmColour.bmBitsPixel; - GetBitmapBits(iconinfo.hbmColor, cbColourBits, &data->icons[0].buffer[cbMaskBits]); - DeleteObject(iconinfo.hbmColor); - } - DeleteObject(iconinfo.hbmMask); }
-noicon: data->hWnd = HandleToLong( nid->hWnd ); data->uID = nid->uID; data->uFlags = nid->uFlags; diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c index 92fafce5d7a..6de8ca49582 100644 --- a/programs/explorer/systray.c +++ b/programs/explorer/systray.c @@ -838,6 +838,7 @@ static BOOL handle_incoming(HWND hwndSource, COPYDATASTRUCT *cds)
if (cds->cbData < sizeof(*data)) return FALSE; data = cds->lpData; + data_icon = &data->icons[0];
nid.cbSize = sizeof(nid); nid.hWnd = LongToHandle( data->hWnd ); @@ -857,11 +858,10 @@ static BOOL handle_incoming(HWND hwndSource, COPYDATASTRUCT *cds)
/* FIXME: if statement only needed because we don't support interprocess * icon handles */ - if ((nid.uFlags & NIF_ICON) && cds->cbData > (sizeof(*data) + sizeof(struct notify_data_icon))) + if ((nid.uFlags & NIF_ICON) && cds->cbData > ((char*)data_icon - (char*)data) + sizeof(struct notify_data_icon)) { LONG cbMaskBits; LONG cbColourBits; - data_icon = &data->icons[0];
cbMaskBits = (data_icon->width * data_icon->height + 15) / 16 * 2; cbColourBits = (data_icon->planes * data_icon->width * data_icon->height * data_icon->bpp + 15) / 16 * 2; @@ -876,6 +876,23 @@ static BOOL handle_incoming(HWND hwndSource, COPYDATASTRUCT *cds) data_icon = (const struct notify_data_icon*)&data_icon->buffer[cbMaskBits + cbColourBits]; }
+ if ((nid.uFlags & NIF_INFO) && cds->cbData > ((char*)data_icon - (char*)data) + sizeof(struct notify_data_icon)) + { + /* Balloon icon */ + LONG cbMaskBits; + LONG cbColourBits; + + cbMaskBits = (data_icon->width * data_icon->height + 15) / 16 * 2; + cbColourBits = (data_icon->planes * data_icon->width * data_icon->height * data_icon->bpp + 15) / 16 * 2; + + if (cds->cbData < sizeof(*data) + sizeof(*data_icon) + cbMaskBits + cbColourBits) + { + WINE_ERR("buffer underflow\n"); + return FALSE; + } + nid.hBalloonIcon = CreateIcon(NULL, data_icon->width, data_icon->height, data_icon->planes, data_icon->bpp, + &data_icon->buffer[0], &data_icon->buffer[cbMaskBits]); + } /* try forwarding to the display driver first */ if (cds->dwData == NIM_ADD || !(icon = get_icon( nid.hWnd, nid.uID ))) { @@ -910,6 +927,7 @@ static BOOL handle_incoming(HWND hwndSource, COPYDATASTRUCT *cds)
done: if (nid.hIcon) DestroyIcon( nid.hIcon ); + if (nid.hBalloonIcon) DestroyIcon( nid.hBalloonIcon ); sync_taskbar_buttons(); return ret; }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=147489
Your paranoid android.
=== debian11b (64 bit WoW report) ===
user32: input.c:4305: Test succeeded inside todo block: button_down_hwnd_todo 1: got MSG_TEST_WIN hwnd 0000000000FF00C6, msg WM_LBUTTONDOWN, wparam 0x1, lparam 0x320032