From be2911a180236344abc6ad112c91972d7e6a300e Mon Sep 17 00:00:00 2001 From: "Kirill K. Smirnov" Date: Thu, 7 Feb 2008 15:23:54 +0000 Subject: [PATCH] systray: Correctly handle icon addition/deletion. --- programs/explorer/systray.c | 202 +++++++++++++++++++----------------- 1 file changed, 108 insertions(+), 94 deletions(-) diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c index 8fa7447556a..28a440f9a32 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) {