Kirill K. Smirnov : systray: Correctly handle icon addition/deletion.

Alexandre Julliard julliard at winehq.org
Fri Feb 15 05:36:04 CST 2008


Module: wine
Branch: master
Commit: be2911a180236344abc6ad112c91972d7e6a300e
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=be2911a180236344abc6ad112c91972d7e6a300e

Author: Kirill K. Smirnov <lich at math.spbu.ru>
Date:   Thu Feb  7 15:23:54 2008 +0000

systray: Correctly handle icon addition/deletion.

---

 programs/explorer/systray.c |  202 +++++++++++++++++++++++--------------------
 1 files changed, 108 insertions(+), 94 deletions(-)

diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c
index 8fa7447..28a440f 100644
--- a/programs/explorer/systray.c
+++ b/programs/explorer/systray.c
@@ -77,80 +77,6 @@ static BOOL hide_systray;
 /* space around icon (forces icon to center of KDE systray area) */
 #define ICON_BORDER  4
 
-static LRESULT WINAPI adaptor_wndproc(HWND window, UINT msg,
-                                      WPARAM wparam, LPARAM lparam)
-{
-    struct icon *icon = NULL;
-    BOOL ret;
-
-    WINE_TRACE("hwnd=%p, msg=0x%x\n", window, msg);
-
-    /* set the icon data for the window from the data passed into CreateWindow */
-    if (msg == WM_NCCREATE)
-        SetWindowLongPtrW(window, GWLP_USERDATA, (LPARAM)((const CREATESTRUCT *)lparam)->lpCreateParams);
-
-    icon = (struct icon *) GetWindowLongPtr(window, GWLP_USERDATA);
-
-    switch (msg)
-    {
-        case WM_PAINT:
-        {
-            RECT rc;
-            int top;
-            PAINTSTRUCT  ps;
-            HDC          hdc;
-
-            WINE_TRACE("painting\n");
-
-            hdc = BeginPaint(window, &ps);
-            GetClientRect(window, &rc);
-
-            /* calculate top so we can deal with arbitrary sized trays */
-            top = ((rc.bottom-rc.top)/2) - ((ICON_SIZE)/2);
-
-            DrawIconEx(hdc, (ICON_BORDER/2), top, icon->image,
-                       ICON_SIZE, ICON_SIZE, 0, 0, DI_DEFAULTSIZE|DI_NORMAL);
-
-            EndPaint(window, &ps);
-            break;
-        }
-
-        case WM_MOUSEMOVE:
-        case WM_LBUTTONDOWN:
-        case WM_LBUTTONUP:
-        case WM_RBUTTONDOWN:
-        case WM_RBUTTONUP:
-        case WM_MBUTTONDOWN:
-        case WM_MBUTTONUP:
-        case WM_LBUTTONDBLCLK:
-        case WM_RBUTTONDBLCLK:
-        case WM_MBUTTONDBLCLK:
-            /* notify the owner hwnd of the message */
-            WINE_TRACE("relaying 0x%x\n", msg);
-            ret = PostMessage(icon->owner, icon->callback_message, (WPARAM) icon->id, (LPARAM) msg);
-            if (!ret && (GetLastError() == ERROR_INVALID_HANDLE))
-            {
-                WINE_WARN("application window was destroyed without removing "
-                          "notification icon, removing automatically\n");
-                DestroyWindow(window);
-            }
-            break;
-
-        case WM_NCDESTROY:
-            SetWindowLongPtr(window, GWLP_USERDATA, 0);
-
-            list_remove(&icon->entry);
-            DestroyIcon(icon->image);
-            HeapFree(GetProcessHeap(), 0, icon);
-            break;
-
-        default:
-            return DefWindowProc(window, msg, wparam, lparam);
-    }
-
-    return 0;
-}
-
 
 /* Retrieves icon record by owner window and ID */
 static struct icon *get_icon(HWND owner, UINT id)
@@ -226,12 +152,19 @@ static BOOL display_icon(struct icon *icon, BOOL hide)
 
     WINE_TRACE("id=0x%x, hwnd=%p, hide=%d\n", icon->id, icon->owner, hide);
 
-    if (icon->hidden == hide || (!icon->hidden) == (!hide)) return TRUE;
+    /* not a startup case and nothing to do */
+    if (icon->window && !icon->hidden == !hide)
+        return TRUE;
+
     icon->hidden = hide;
     if (hide)
     {
-        DestroyWindow(icon->window);
-        DestroyWindow(icon->tooltip);
+        /* At startup icon->hidden == FALSE and icon->window == NULL */
+        if (icon->window)
+        {
+            DestroyWindow(icon->window);
+            DestroyWindow(icon->tooltip);
+        }
         return TRUE;
     }
 
@@ -264,7 +197,7 @@ static BOOL display_icon(struct icon *icon, BOOL hide)
 }
 
 /* Modifies an existing icon record */
-static BOOL modify_icon(NOTIFYICONDATAW *nid, BOOL modify_tooltip)
+static BOOL modify_icon(NOTIFYICONDATAW *nid)
 {
     struct icon    *icon;
 
@@ -278,14 +211,11 @@ static BOOL modify_icon(NOTIFYICONDATAW *nid, BOOL modify_tooltip)
         return FALSE;
     }
 
-    if (nid->uFlags & NIF_STATE)
-    {
-        if (nid->dwStateMask & NIS_HIDDEN)
-            display_icon(icon, !!(nid->dwState & NIS_HIDDEN));
-        else
-            display_icon(icon, FALSE);
-    }
-    else
+    if ((nid->uFlags & NIF_STATE) && (nid->dwStateMask & NIS_HIDDEN))
+        display_icon(icon, !!(nid->dwState & NIS_HIDDEN));
+
+    /* startup case*/
+    if ((!icon->window) && (!icon->hidden))
         display_icon(icon, FALSE);
 
     if (nid->uFlags & NIF_ICON)
@@ -333,31 +263,45 @@ static BOOL add_icon(NOTIFYICONDATAW *nid)
         return FALSE;
     }
 
+    ZeroMemory(icon, sizeof(struct icon));
     icon->id     = nid->uID;
     icon->owner  = nid->hWnd;
-    icon->image  = NULL;
-    icon->window = NULL;
-    icon->hidden = TRUE;
 
     list_add_tail(&tray.icons, &icon->entry);
 
-    return modify_icon(nid, FALSE);
+    /*
+     * Both icon->window and icon->hidden are zero. modify_icon function
+     * will treat this case as a startup, i.e. icon window will be created if
+     * NIS_HIDDEN flag is not set.
+     */
+
+    return modify_icon(nid);
 }
 
+/* Deletes tray icon window and icon record */
+static BOOL delete_icon_directly(struct icon *icon)
+{
+    display_icon(icon, TRUE);
+    list_remove(&icon->entry);
+    DestroyIcon(icon->image);
+    HeapFree(GetProcessHeap(), 0, icon);
+    return TRUE;
+}
+
+/* Deletes tray icon window and icon structure */
 static BOOL delete_icon(const NOTIFYICONDATAW *nid)
 {
     struct icon *icon = get_icon(nid->hWnd, nid->uID);
 
     WINE_TRACE("id=0x%x, hwnd=%p\n", nid->uID, nid->hWnd);
-   
+
     if (!icon)
     {
         WINE_WARN("invalid tray icon ID specified: %u\n", nid->uID);
         return FALSE;
     }
 
-    display_icon(icon, TRUE);
-    return TRUE;
+    return delete_icon_directly(icon);
 }
 
 static BOOL handle_incoming(HWND hwndSource, COPYDATASTRUCT *cds)
@@ -420,7 +364,7 @@ static BOOL handle_incoming(HWND hwndSource, COPYDATASTRUCT *cds)
         ret = delete_icon(&nid);
         break;
     case NIM_MODIFY:
-        ret = modify_icon(&nid, TRUE);
+        ret = modify_icon(&nid);
         break;
     default:
         WINE_FIXME("unhandled tray message: %ld\n", cds->dwData);
@@ -444,6 +388,76 @@ static LRESULT WINAPI listener_wndproc(HWND window, UINT msg,
     return DefWindowProc(window, msg, wparam, lparam);
 }
 
+static LRESULT WINAPI adaptor_wndproc(HWND window, UINT msg,
+                                      WPARAM wparam, LPARAM lparam)
+{
+    struct icon *icon = NULL;
+    BOOL ret;
+
+    WINE_TRACE("hwnd=%p, msg=0x%x\n", window, msg);
+
+    /* set the icon data for the window from the data passed into CreateWindow */
+    if (msg == WM_NCCREATE)
+        SetWindowLongPtrW(window, GWLP_USERDATA, (LPARAM)((const CREATESTRUCT *)lparam)->lpCreateParams);
+
+    icon = (struct icon *) GetWindowLongPtr(window, GWLP_USERDATA);
+
+    switch (msg)
+    {
+        case WM_PAINT:
+        {
+            RECT rc;
+            int top;
+            PAINTSTRUCT  ps;
+            HDC          hdc;
+
+            WINE_TRACE("painting\n");
+
+            hdc = BeginPaint(window, &ps);
+            GetClientRect(window, &rc);
+
+            /* calculate top so we can deal with arbitrary sized trays */
+            top = ((rc.bottom-rc.top)/2) - ((ICON_SIZE)/2);
+
+            DrawIconEx(hdc, (ICON_BORDER/2), top, icon->image,
+                       ICON_SIZE, ICON_SIZE, 0, 0, DI_DEFAULTSIZE|DI_NORMAL);
+
+            EndPaint(window, &ps);
+            break;
+        }
+
+        case WM_MOUSEMOVE:
+        case WM_LBUTTONDOWN:
+        case WM_LBUTTONUP:
+        case WM_RBUTTONDOWN:
+        case WM_RBUTTONUP:
+        case WM_MBUTTONDOWN:
+        case WM_MBUTTONUP:
+        case WM_LBUTTONDBLCLK:
+        case WM_RBUTTONDBLCLK:
+        case WM_MBUTTONDBLCLK:
+            /* notify the owner hwnd of the message */
+            WINE_TRACE("relaying 0x%x\n", msg);
+            ret = PostMessage(icon->owner, icon->callback_message, (WPARAM) icon->id, (LPARAM) msg);
+            if (!ret && (GetLastError() == ERROR_INVALID_HANDLE))
+            {
+                WINE_WARN("application window was destroyed without removing "
+                          "notification icon, removing automatically\n");
+                delete_icon_directly(icon);
+            }
+            break;
+
+        case WM_NCDESTROY:
+            SetWindowLongPtr(window, GWLP_USERDATA, 0);
+            break;
+
+        default:
+            return DefWindowProc(window, msg, wparam, lparam);
+    }
+
+    return 0;
+}
+
 
 static BOOL is_systray_hidden(void)
 {




More information about the wine-cvs mailing list