systray: Correctly handle icon addition/deletion.

This commit is contained in:
Kirill K. Smirnov 2008-02-07 15:23:54 +00:00 committed by Alexandre Julliard
parent 7515f312f9
commit be2911a180
1 changed files with 108 additions and 94 deletions

View File

@ -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)
{