[PATCH] shell32: Implement NIM_SETVERSION in Shell_NotifyIcon()

Roman Pisl rpisl at seznam.cz
Tue Mar 1 09:26:50 CST 2016


Fixes https://bugs.winehq.org/show_bug.cgi?id=29412

The patch adds support for different versions of Shell_NotifyIcon() API
function by implementing NIM_SETVERSION and fixes Qt programs that use
tray icon in wine.

Tested on Gentoo Linux and Qt 4.8/5.5.

Signed-off-by: Roman Pisl <rpisl at seznam.cz>
---
 dlls/shell32/systray.c      |  2 ++
 dlls/winex11.drv/systray.c  | 64 ++++++++++++++++++++++++++++++++++++++++-----
 programs/explorer/systray.c | 51 ++++++++++++++++++++++++++++++++++--
 3 files changed, 108 insertions(+), 9 deletions(-)

diff --git a/dlls/shell32/systray.c b/dlls/shell32/systray.c
index dfa30ff..a043912 100644
--- a/dlls/shell32/systray.c
+++ b/dlls/shell32/systray.c
@@ -234,6 +234,8 @@ noicon:
     }
     if (data->uFlags & NIF_GUID)
         data->guidItem = nid->guidItem;
+    if (dwMessage == NIM_SETVERSION)
+        data->u.uVersion = nid->u.uVersion;
     /* FIXME: balloon icon */
 
     cds.lpData = data;
diff --git a/dlls/winex11.drv/systray.c b/dlls/winex11.drv/systray.c
index c7e7013..78cba87 100644
--- a/dlls/winex11.drv/systray.c
+++ b/dlls/winex11.drv/systray.c
@@ -65,6 +65,7 @@ struct tray_icon
     UINT           info_flags;      /* flags for info balloon */
     UINT           info_timeout;    /* timeout for info balloon */
     HICON          info_icon;       /* info balloon icon */
+    UINT           version;         /* notify icon api version */
 };
 
 static struct list icon_list = LIST_INIT( icon_list );
@@ -484,15 +485,56 @@ static LRESULT WINAPI tray_icon_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPAR
     case WM_LBUTTONDBLCLK:
     case WM_RBUTTONDBLCLK:
     case WM_MBUTTONDBLCLK:
-        /* notify the owner hwnd of the message */
-        TRACE("relaying 0x%x\n", msg);
-        ret = PostMessageW(icon->owner, icon->callback_message, icon->id, msg);
-        if (!ret && (GetLastError() == ERROR_INVALID_WINDOW_HANDLE))
         {
-            WARN( "application window was destroyed, removing icon %u\n", icon->id );
-            delete_icon( icon );
+            WPARAM wpar;
+            BOOL oldver;
+
+            oldver = icon->version <= NOTIFY_VERSION;
+            if (oldver) {
+                /* 0 up to NOTIFYICON_VERSION (=3) */
+                wpar = icon->id;
+            } else {
+                /* NOTIFYICON_VERSION_4 */
+                RECT rect;
+                WORD x, y;
+
+                GetWindowRect( icon->window, &rect );
+                x = rect.left + LOWORD(lparam);
+                y = rect.top + HIWORD(lparam);
+                wpar = MAKEWPARAM(x, y);
+            }
+
+            /* notify the owner hwnd of the message */
+            TRACE("relaying 0x%x\n", msg);
+            ret = PostMessageW(icon->owner, icon->callback_message, wpar,
+                               oldver ? msg : MAKELPARAM(msg, icon->id));
+
+            if (ret && icon->version > 0) {
+                switch (msg) {
+                    case WM_RBUTTONUP:
+                        /* notify the owner hwnd of the message */
+                        TRACE("relaying 0x%x\n", WM_CONTEXTMENU);
+                        ret = PostMessageW(icon->owner, icon->callback_message, wpar,
+                                           oldver ? WM_CONTEXTMENU : MAKELPARAM(WM_CONTEXTMENU, icon->id));
+                        break;
+                    case WM_LBUTTONUP:
+                        /* notify the owner hwnd of the message */
+                        TRACE("relaying 0x%x\n", NIN_SELECT);
+                        ret = PostMessageW(icon->owner, icon->callback_message, wpar,
+                                           oldver ? NIN_SELECT : MAKELPARAM(NIN_SELECT, icon->id));
+                        break;
+                    default:
+                        break;
+                }
+            }
+
+            if (!ret && (GetLastError() == ERROR_INVALID_WINDOW_HANDLE))
+            {
+                WARN( "application window was destroyed, removing icon %u\n", icon->id );
+                delete_icon( icon );
+            }
+            return 0;
         }
-        return 0;
 
     case WM_WINDOWPOSCHANGED:
         update_systray_balloon_position();
@@ -834,6 +876,14 @@ int CDECL wine_notify_icon( DWORD msg, NOTIFYICONDATAW *data )
     case NIM_MODIFY:
         if ((icon = get_icon( data->hWnd, data->uID ))) ret = modify_icon( icon, data );
         break;
+    case NIM_SETVERSION:
+        if (data->u.uVersion <= NOTIFY_VERSION_4) {
+            if ((icon = get_icon( data->hWnd, data->uID ))) {
+                icon->version = data->u.uVersion;
+                ret = TRUE;
+            }
+        }
+        break;
     case 0xdead:  /* Wine extension: owner window has died */
         cleanup_icons( data->hWnd );
         break;
diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c
index beb0a88..8806e34 100644
--- a/programs/explorer/systray.c
+++ b/programs/explorer/systray.c
@@ -77,6 +77,7 @@ struct icon
     UINT           info_flags;      /* flags for info balloon */
     UINT           info_timeout;    /* timeout for info balloon */
     HICON          info_icon;       /* info balloon icon */
+    UINT           version;         /* notify icon api version */
 };
 
 static struct list icon_list = LIST_INIT( icon_list );
@@ -526,6 +527,12 @@ static BOOL handle_incoming(HWND hwndSource, COPYDATASTRUCT *cds)
     case NIM_MODIFY:
         if (icon) ret = modify_icon( icon, &nid );
         break;
+    case NIM_SETVERSION:
+        if (nid.u.uVersion <= NOTIFY_VERSION_4) {
+            icon->version = nid.u.uVersion;
+            ret = TRUE;
+        }
+        break;
     default:
         WINE_FIXME("unhandled tray message: %ld\n", cds->dwData);
         break;
@@ -598,6 +605,9 @@ static LRESULT WINAPI tray_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
     case WM_RBUTTONDBLCLK:
     case WM_MBUTTONDBLCLK:
         {
+            WPARAM wpar;
+            BOOL oldver;
+            BOOL ret;
             MSG message;
             struct icon *icon = icon_from_point( (short)LOWORD(lparam), (short)HIWORD(lparam) );
             if (!icon) break;
@@ -611,8 +621,45 @@ static LRESULT WINAPI tray_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
             message.lParam = lparam;
             SendMessageW( icon->tooltip, TTM_RELAYEVENT, 0, (LPARAM)&message );
 
-            if (!PostMessageW( icon->owner, icon->callback_message, (WPARAM) icon->id, (LPARAM) msg ) &&
-                GetLastError() == ERROR_INVALID_WINDOW_HANDLE)
+            oldver = icon->version <= NOTIFY_VERSION;
+            if (oldver) {
+                /* 0 up to NOTIFYICON_VERSION (=3) */
+                wpar = icon->id;
+            } else {
+                /* NOTIFYICON_VERSION_4 */
+                RECT rect;
+                WORD x, y;
+
+                rect = get_icon_rect( icon );
+                MapWindowPoints( tray_window, 0, (POINT *)&rect, 2 );
+                x = rect.left + LOWORD(lparam);
+                y = rect.top + HIWORD(lparam);
+                wpar = MAKEWPARAM(x, y);
+            }
+
+            ret = PostMessageW(icon->owner, icon->callback_message, wpar,
+                               oldver ? msg : MAKELPARAM(msg, icon->id));
+
+            if (ret && icon->version > 0) {
+                switch (msg) {
+                    case WM_RBUTTONUP:
+                        /* notify the owner hwnd of the message */
+                        WINE_TRACE("relaying 0x%x\n", WM_CONTEXTMENU);
+                        ret = PostMessageW(icon->owner, icon->callback_message, wpar,
+                                           oldver ? WM_CONTEXTMENU : MAKELPARAM(WM_CONTEXTMENU, icon->id));
+                        break;
+                    case WM_LBUTTONUP:
+                        /* notify the owner hwnd of the message */
+                        WINE_TRACE("relaying 0x%x\n", NIN_SELECT);
+                        ret = PostMessageW(icon->owner, icon->callback_message, wpar,
+                                          oldver ? NIN_SELECT : MAKELPARAM(NIN_SELECT, icon->id));
+                        break;
+                    default:
+                        break;
+                }
+            }
+
+            if (!ret && (GetLastError() == ERROR_INVALID_WINDOW_HANDLE))
             {
                 WINE_WARN("application window was destroyed without removing "
                           "notification icon, removing automatically\n");
-- 
2.4.10




More information about the wine-patches mailing list