The point here is to make the default implementation similar to winex11, supporting a standalone systray window. Later, we could refactor the interface to remove the duplicated systray code from the user drivers.
-- v4: explorer: Cache the balloon window position. explorer: Support standalone systray window mode. explorer: Use an explicit display constant for hidden icons. explorer: Handle balloon timer in the icons window proc. explorer: Position the balloons relative to the icon windows. explorer: Use the icon windows for their tooltips. explorer: Display the individual systray icon windows. explorer: Create individual windows for the systray icons. explorer: Split systray add/remove from show/hide_icon. explorer: Remove unnecessary displayed icon array.
From: Rémi Bernon rbernon@codeweavers.com
--- programs/explorer/systray.c | 49 +++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 27 deletions(-)
diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c index 6253b65cf35..cf1457eca43 100644 --- a/programs/explorer/systray.c +++ b/programs/explorer/systray.c @@ -93,9 +93,7 @@ static struct list taskbar_buttons = LIST_INIT( taskbar_buttons );
static HWND tray_window;
-static unsigned int alloc_displayed; static unsigned int nb_displayed; -static struct icon **displayed; /* array of currently displayed icons */
static BOOL hide_systray, enable_shell; static int icon_cx, icon_cy, tray_width, tray_height; @@ -298,10 +296,16 @@ static void update_tooltip_position( struct icon *icon ) /* find the icon located at a certain point in the tray window */ static struct icon *icon_from_point( int x, int y ) { - if (y < 0 || y >= icon_cy) return NULL; - x = tray_width - x; - if (x < 0 || x >= icon_cx * nb_displayed) return NULL; - return displayed[x / icon_cx]; + struct icon *icon; + POINT pt = {x, y}; + + LIST_FOR_EACH_ENTRY(icon, &icon_list, struct icon, entry) + { + RECT rect = get_icon_rect( icon ); + if (PtInRect(&rect, pt)) return icon; + } + + return NULL; }
/* invalidate the portion of the tray window that contains the specified icons */ @@ -323,17 +327,7 @@ static BOOL show_icon(struct icon *icon)
if (icon->display != -1) return TRUE; /* already displayed */
- if (nb_displayed >= alloc_displayed) - { - unsigned int new_count = max( alloc_displayed * 2, 32 ); - struct icon **ptr; - if (!(ptr = realloc( displayed, new_count * sizeof(*ptr) ))) return FALSE; - displayed = ptr; - alloc_displayed = new_count; - } - - icon->display = nb_displayed; - displayed[nb_displayed++] = icon; + icon->display = nb_displayed++; update_tooltip_position( icon ); invalidate_icons( nb_displayed-1, nb_displayed-1 );
@@ -347,18 +341,19 @@ static BOOL show_icon(struct icon *icon) /* make an icon invisible */ static BOOL hide_icon(struct icon *icon) { - unsigned int i; + struct icon *ptr;
TRACE( "id=0x%x, hwnd=%p\n", icon->id, icon->owner );
if (icon->display == -1) return TRUE; /* already hidden */
assert( nb_displayed ); - for (i = icon->display; i < nb_displayed - 1; i++) + LIST_FOR_EACH_ENTRY( ptr, &icon_list, struct icon, entry ) { - displayed[i] = displayed[i + 1]; - displayed[i]->display = i; - update_tooltip_position( displayed[i] ); + if (ptr == icon) continue; + if (ptr->display < icon->display) continue; + ptr->display--; + update_tooltip_position( ptr ); } nb_displayed--; invalidate_icons( icon->display, nb_displayed ); @@ -786,16 +781,16 @@ static LRESULT WINAPI tray_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
case WM_PAINT: { - unsigned int i; + struct icon *icon; PAINTSTRUCT ps; HDC hdc;
hdc = BeginPaint( hwnd, &ps ); - for (i = 0; i < nb_displayed; i++) + LIST_FOR_EACH_ENTRY( icon, &icon_list, struct icon, entry ) { - RECT dummy, rect = get_icon_rect( displayed[i] ); - if (IntersectRect( &dummy, &rect, &ps.rcPaint )) - DrawIconEx( hdc, rect.left + ICON_BORDER, rect.top + ICON_BORDER, displayed[i]->image, + RECT dummy, rect = get_icon_rect( icon ); + if (icon->display != -1 && IntersectRect( &dummy, &rect, &ps.rcPaint )) + DrawIconEx( hdc, rect.left + ICON_BORDER, rect.top + ICON_BORDER, icon->image, icon_cx - 2*ICON_BORDER, icon_cy - 2*ICON_BORDER, 0, 0, DI_DEFAULTSIZE|DI_NORMAL); }
From: Rémi Bernon rbernon@codeweavers.com
--- programs/explorer/systray.c | 54 ++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 18 deletions(-)
diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c index cf1457eca43..8a1b6a8ea3c 100644 --- a/programs/explorer/systray.c +++ b/programs/explorer/systray.c @@ -320,32 +320,24 @@ static void invalidate_icons( unsigned int start, unsigned int end ) InvalidateRect( tray_window, &rect, TRUE ); }
-/* make an icon visible */ -static BOOL show_icon(struct icon *icon) +/* add an icon to the system tray window */ +static void systray_add_icon( struct icon *icon ) { - TRACE( "id=0x%x, hwnd=%p\n", icon->id, icon->owner ); - - if (icon->display != -1) return TRUE; /* already displayed */ + if (icon->display != -1) return; /* already added */
icon->display = nb_displayed++; - update_tooltip_position( icon ); - invalidate_icons( nb_displayed-1, nb_displayed-1 ); + invalidate_icons( icon->display, icon->display );
if (nb_displayed == 1 && !hide_systray) do_show_systray(); - - create_tooltip(icon); - update_balloon( icon ); - return TRUE; + TRACE( "added %u now %d icons\n", icon->id, nb_displayed ); }
-/* make an icon invisible */ -static BOOL hide_icon(struct icon *icon) +/* remove an icon from the stand-alone tray */ +static void systray_remove_icon( struct icon *icon ) { struct icon *ptr;
- TRACE( "id=0x%x, hwnd=%p\n", icon->id, icon->owner ); - - if (icon->display == -1) return TRUE; /* already hidden */ + if (icon->display == -1) return; /* already removed */
assert( nb_displayed ); LIST_FOR_EACH_ENTRY( ptr, &icon_list, struct icon, entry ) @@ -355,11 +347,37 @@ static BOOL hide_icon(struct icon *icon) ptr->display--; update_tooltip_position( ptr ); } - nb_displayed--; + + if (!--nb_displayed && !enable_shell) do_hide_systray(); + TRACE( "removed %u now %d icons\n", icon->id, nb_displayed ); + invalidate_icons( icon->display, nb_displayed ); icon->display = -1; +} + +/* make an icon visible */ +static BOOL show_icon(struct icon *icon) +{ + TRACE( "id=0x%x, hwnd=%p\n", icon->id, icon->owner ); + + if (icon->display != -1) return TRUE; /* already displayed */ + + systray_add_icon( icon ); + + update_tooltip_position( icon ); + create_tooltip( icon ); + update_balloon( icon ); + return TRUE; +} + +/* make an icon invisible */ +static BOOL hide_icon(struct icon *icon) +{ + TRACE( "id=0x%x, hwnd=%p\n", icon->id, icon->owner ); + + if (icon->display == -1) return TRUE; /* already hidden */
- if (!nb_displayed && !enable_shell) do_hide_systray(); + systray_remove_icon( icon );
update_balloon( icon ); update_tooltip_position( icon );
From: Rémi Bernon rbernon@codeweavers.com
--- programs/explorer/systray.c | 99 ++++++++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 19 deletions(-)
diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c index 8a1b6a8ea3c..a36aa101525 100644 --- a/programs/explorer/systray.c +++ b/programs/explorer/systray.c @@ -64,6 +64,7 @@ struct icon struct list entry; HICON image; /* the image to render */ HWND owner; /* the HWND passed in to the Shell_NotifyIcon call */ + HWND window; /* the adaptor window */ HWND tooltip; /* Icon tooltip */ UINT state; /* state flags */ UINT id; /* the unique id given by the app */ @@ -115,6 +116,25 @@ static HWND balloon_window;
#define WM_POPUPSYSTEMMENU 0x0313
+static LRESULT WINAPI shell_traywnd_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ); +static LRESULT WINAPI tray_icon_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ); + +static WNDCLASSEXW shell_traywnd_class = +{ + .cbSize = sizeof(WNDCLASSEXW), + .style = CS_DBLCLKS | CS_HREDRAW, + .lpfnWndProc = shell_traywnd_proc, + .hbrBackground = (HBRUSH)COLOR_WINDOW, + .lpszClassName = L"Shell_TrayWnd", +}; +static WNDCLASSEXW tray_icon_class = +{ + .cbSize = sizeof(WNDCLASSEXW), + .style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, + .lpfnWndProc = tray_icon_wndproc, + .lpszClassName = L"__wine_tray_icon", +}; + static void do_hide_systray(void); static void do_show_systray(void);
@@ -280,6 +300,13 @@ static void update_tooltip_text(struct icon *icon) SendMessageW(icon->tooltip, TTM_UPDATETIPTEXTW, 0, (LPARAM)&ti); }
+/* get the position of an icon in the stand-alone tray */ +static POINT get_icon_pos( struct icon *icon ) +{ + RECT rect = get_icon_rect( icon ); + return *(POINT *)▭ +} + /* synchronize tooltip position with tooltip window */ static void update_tooltip_position( struct icon *icon ) { @@ -293,6 +320,33 @@ static void update_tooltip_position( struct icon *icon ) if (balloon_icon == icon) set_balloon_position( icon ); }
+/* window procedure for the individual tray icon window */ +static LRESULT WINAPI tray_icon_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + struct icon *icon = (struct icon *)GetWindowLongPtrW( hwnd, GWLP_USERDATA ); + + TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); + + switch (msg) + { + case WM_NCCREATE: + { + /* set the icon data for the window from the data passed into CreateWindow */ + const CREATESTRUCTW *info = (const CREATESTRUCTW *)lparam; + icon = info->lpCreateParams; + SetWindowLongPtrW( hwnd, GWLP_USERDATA, (LONG_PTR)icon ); + break; + } + + case WM_CREATE: + icon->window = hwnd; + create_tooltip( icon ); + break; + } + + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + /* find the icon located at a certain point in the tray window */ static struct icon *icon_from_point( int x, int y ) { @@ -336,6 +390,7 @@ static void systray_add_icon( struct icon *icon ) static void systray_remove_icon( struct icon *icon ) { struct icon *ptr; + POINT pos;
if (icon->display == -1) return; /* already removed */
@@ -346,6 +401,8 @@ static void systray_remove_icon( struct icon *icon ) if (ptr->display < icon->display) continue; ptr->display--; update_tooltip_position( ptr ); + pos = get_icon_pos( ptr ); + SetWindowPos( ptr->window, 0, pos.x, pos.y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER ); }
if (!--nb_displayed && !enable_shell) do_hide_systray(); @@ -365,7 +422,6 @@ static BOOL show_icon(struct icon *icon) systray_add_icon( icon );
update_tooltip_position( icon ); - create_tooltip( icon ); update_balloon( icon ); return TRUE; } @@ -455,17 +511,23 @@ static BOOL add_icon(NOTIFYICONDATAW *nid) icon->owner = nid->hWnd; icon->display = -1;
+ CreateWindowW( tray_icon_class.lpszClassName, NULL, WS_CHILD, + 0, 0, icon_cx, icon_cy, tray_window, NULL, NULL, icon ); + if (!icon->window) ERR( "Failed to create systray icon window\n" ); + list_add_tail(&icon_list, &icon->entry);
return modify_icon( icon, nid ); }
/* Deletes tray icon window and icon record */ -static BOOL delete_icon(struct icon *icon) +static BOOL delete_icon( struct icon *icon ) { - hide_icon(icon); - list_remove(&icon->entry); - DestroyIcon(icon->image); + hide_icon( icon ); + list_remove( &icon->entry ); + DestroyWindow( icon->tooltip ); + DestroyWindow( icon->window ); + DestroyIcon( icon->image ); free( icon ); return TRUE; } @@ -777,7 +839,7 @@ static void do_show_systray(void) sync_taskbar_buttons(); }
-static LRESULT WINAPI tray_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +static LRESULT WINAPI shell_traywnd_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { switch (msg) { @@ -904,38 +966,37 @@ void handle_parent_notify( HWND hwnd, WPARAM wp ) /* this function creates the listener window */ void initialize_systray( HMODULE graphics_driver, BOOL using_root, BOOL arg_enable_shell ) { - WNDCLASSEXW class; RECT work_rect, primary_rect, taskbar_rect;
if (using_root && graphics_driver) wine_notify_icon = (void *)GetProcAddress( graphics_driver, "wine_notify_icon" );
+ shell_traywnd_class.hIcon = LoadIconW( 0, (const WCHAR *)IDI_WINLOGO ); + shell_traywnd_class.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW ); + tray_icon_class.hIcon = shell_traywnd_class.hIcon; + tray_icon_class.hCursor = shell_traywnd_class.hCursor; + icon_cx = GetSystemMetrics( SM_CXSMICON ) + 2*ICON_BORDER; icon_cy = GetSystemMetrics( SM_CYSMICON ) + 2*ICON_BORDER; hide_systray = using_root; enable_shell = arg_enable_shell;
/* register the systray listener window class */ - ZeroMemory(&class, sizeof(class)); - class.cbSize = sizeof(class); - class.style = CS_DBLCLKS | CS_HREDRAW; - class.lpfnWndProc = tray_wndproc; - class.hInstance = NULL; - class.hIcon = LoadIconW(0, (LPCWSTR)IDI_WINLOGO); - class.hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW); - class.hbrBackground = (HBRUSH) COLOR_WINDOW; - class.lpszClassName = L"Shell_TrayWnd"; - - if (!RegisterClassExW(&class)) + if (!RegisterClassExW( &shell_traywnd_class )) { ERR( "Could not register SysTray window class\n" ); return; } + if (!wine_notify_icon && !RegisterClassExW( &tray_icon_class )) + { + ERR( "Could not register Wine SysTray window classes\n" ); + return; + }
SystemParametersInfoW( SPI_GETWORKAREA, 0, &work_rect, 0 ); SetRect( &primary_rect, 0, 0, GetSystemMetrics( SM_CXSCREEN ), GetSystemMetrics( SM_CYSCREEN ) ); SubtractRect( &taskbar_rect, &primary_rect, &work_rect );
- tray_window = CreateWindowExW( WS_EX_NOACTIVATE, class.lpszClassName, NULL, WS_POPUP, taskbar_rect.left, + tray_window = CreateWindowExW( WS_EX_NOACTIVATE, shell_traywnd_class.lpszClassName, NULL, WS_POPUP, taskbar_rect.left, taskbar_rect.top, taskbar_rect.right - taskbar_rect.left, taskbar_rect.bottom - taskbar_rect.top, 0, 0, 0, 0 ); if (!tray_window)
From: Rémi Bernon rbernon@codeweavers.com
--- programs/explorer/systray.c | 180 ++++++++++++++---------------------- 1 file changed, 71 insertions(+), 109 deletions(-)
diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c index a36aa101525..60b407afa6c 100644 --- a/programs/explorer/systray.c +++ b/programs/explorer/systray.c @@ -119,6 +119,10 @@ static HWND balloon_window; static LRESULT WINAPI shell_traywnd_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ); static LRESULT WINAPI tray_icon_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam );
+static BOOL show_icon( struct icon *icon ); +static BOOL hide_icon( struct icon *icon ); +static BOOL delete_icon( struct icon *icon ); + static WNDCLASSEXW shell_traywnd_class = { .cbSize = sizeof(WNDCLASSEXW), @@ -320,6 +324,30 @@ static void update_tooltip_position( struct icon *icon ) if (balloon_icon == icon) set_balloon_position( icon ); }
+static BOOL notify_owner( struct icon *icon, UINT msg, LPARAM lparam ) +{ + WPARAM wp = icon->id; + LPARAM lp = msg; + + if (icon->version >= NOTIFYICON_VERSION_4) + { + POINT pt = {.x = (short)LOWORD(lparam), .y = (short)HIWORD(lparam)}; + ClientToScreen( icon->window, &pt ); + wp = MAKEWPARAM( pt.x, pt.y ); + lp = MAKELPARAM( msg, icon->id ); + } + + TRACE( "relaying 0x%x\n", msg ); + if (!SendNotifyMessageW( icon->owner, icon->callback_message, wp, lp ) && + (GetLastError() == ERROR_INVALID_WINDOW_HANDLE)) + { + WARN( "application window was destroyed, removing icon %u\n", icon->id ); + delete_icon( icon ); + return FALSE; + } + return TRUE; +} + /* window procedure for the individual tray icon window */ static LRESULT WINAPI tray_icon_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { @@ -342,45 +370,60 @@ static LRESULT WINAPI tray_icon_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPA icon->window = hwnd; create_tooltip( icon ); break; - }
- return DefWindowProcW( hwnd, msg, wparam, lparam ); -} - -/* find the icon located at a certain point in the tray window */ -static struct icon *icon_from_point( int x, int y ) -{ - struct icon *icon; - POINT pt = {x, y}; - - LIST_FOR_EACH_ENTRY(icon, &icon_list, struct icon, entry) + case WM_PAINT: { - RECT rect = get_icon_rect( icon ); - if (PtInRect(&rect, pt)) return icon; + PAINTSTRUCT ps; + RECT rc; + HDC hdc; + int cx = GetSystemMetrics( SM_CXSMICON ); + int cy = GetSystemMetrics( SM_CYSMICON ); + + hdc = BeginPaint( hwnd, &ps ); + GetClientRect( hwnd, &rc ); + TRACE( "painting rect %s\n", wine_dbgstr_rect( &rc ) ); + DrawIconEx( hdc, (rc.left + rc.right - cx) / 2, (rc.top + rc.bottom - cy) / 2, + icon->image, cx, cy, 0, 0, DI_DEFAULTSIZE | DI_NORMAL ); + EndPaint( hwnd, &ps ); + return 0; }
- return NULL; -} - -/* invalidate the portion of the tray window that contains the specified icons */ -static void invalidate_icons( unsigned int start, unsigned int end ) -{ - RECT rect; + 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: + { + MSG message = {.hwnd = hwnd, .message = msg, .wParam = wparam, .lParam = lparam}; + SendMessageW( icon->tooltip, TTM_RELAYEVENT, 0, (LPARAM)&message ); + if (!notify_owner( icon, msg, lparam )) break; + if (icon->version > 0) + { + if (msg == WM_LBUTTONUP) notify_owner( icon, NIN_SELECT, lparam ); + if (msg == WM_RBUTTONUP) notify_owner( icon, WM_CONTEXTMENU, lparam ); + } + break; + } + }
- rect.left = tray_width - (end + 1) * icon_cx; - rect.top = (tray_height - icon_cy) / 2; - rect.right = tray_width - start * icon_cx; - rect.bottom = rect.top + icon_cy; - InvalidateRect( tray_window, &rect, TRUE ); + return DefWindowProcW( hwnd, msg, wparam, lparam ); }
/* add an icon to the system tray window */ static void systray_add_icon( struct icon *icon ) { + POINT pos; + if (icon->display != -1) return; /* already added */
icon->display = nb_displayed++; - invalidate_icons( icon->display, icon->display ); + pos = get_icon_pos( icon ); + SetWindowPos( icon->window, 0, pos.x, pos.y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_SHOWWINDOW );
if (nb_displayed == 1 && !hide_systray) do_show_systray(); TRACE( "added %u now %d icons\n", icon->id, nb_displayed ); @@ -408,7 +451,6 @@ static void systray_remove_icon( struct icon *icon ) if (!--nb_displayed && !enable_shell) do_hide_systray(); TRACE( "removed %u now %d icons\n", icon->id, nb_displayed );
- invalidate_icons( icon->display, nb_displayed ); icon->display = -1; }
@@ -433,6 +475,7 @@ static BOOL hide_icon(struct icon *icon)
if (icon->display == -1) return TRUE; /* already hidden */
+ ShowWindow( icon->window, SW_HIDE ); systray_remove_icon( icon );
update_balloon( icon ); @@ -461,7 +504,7 @@ static BOOL modify_icon( struct icon *icon, NOTIFYICONDATAW *nid ) { if (icon->image) DestroyIcon(icon->image); icon->image = CopyIcon(nid->hIcon); - if (icon->display != -1) invalidate_icons( icon->display, icon->display ); + if (icon->display != -1) InvalidateRect( icon->window, NULL, TRUE ); }
if (nid->uFlags & NIF_MESSAGE) @@ -787,29 +830,6 @@ static void do_hide_systray(void) ShowWindow( tray_window, SW_HIDE ); }
-static BOOL notify_owner( struct icon *icon, UINT msg, POINT pt ) -{ - WPARAM wp = icon->id; - LPARAM lp = msg; - - if (icon->version >= NOTIFYICON_VERSION_4) - { - ClientToScreen( tray_window, &pt ); - wp = MAKEWPARAM( pt.x, pt.y ); - lp = MAKELPARAM( msg, icon->id ); - } - - TRACE( "relaying 0x%x\n", msg ); - if (!SendNotifyMessageW( icon->owner, icon->callback_message, wp, lp ) && - (GetLastError() == ERROR_INVALID_WINDOW_HANDLE)) - { - WARN( "application window was destroyed, removing icon %u\n", icon->id ); - delete_icon( icon ); - return FALSE; - } - return TRUE; -} - static void do_show_systray(void) { SIZE size; @@ -859,64 +879,6 @@ static LRESULT WINAPI shell_traywnd_proc( HWND hwnd, UINT msg, WPARAM wparam, LP } break;
- case WM_PAINT: - { - struct icon *icon; - PAINTSTRUCT ps; - HDC hdc; - - hdc = BeginPaint( hwnd, &ps ); - LIST_FOR_EACH_ENTRY( icon, &icon_list, struct icon, entry ) - { - RECT dummy, rect = get_icon_rect( icon ); - if (icon->display != -1 && IntersectRect( &dummy, &rect, &ps.rcPaint )) - DrawIconEx( hdc, rect.left + ICON_BORDER, rect.top + ICON_BORDER, icon->image, - icon_cx - 2*ICON_BORDER, icon_cy - 2*ICON_BORDER, - 0, 0, DI_DEFAULTSIZE|DI_NORMAL); - } - EndPaint( hwnd, &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: - { - MSG message; - POINT pt = { (short)LOWORD(lparam), (short)HIWORD(lparam) }; - struct icon *icon = icon_from_point( pt.x, pt.y ); - if (!icon) break; - - message.hwnd = hwnd; - message.message = msg; - message.wParam = wparam; - message.lParam = lparam; - SendMessageW( icon->tooltip, TTM_RELAYEVENT, 0, (LPARAM)&message ); - - if (!notify_owner( icon, msg, pt )) break; - - if (icon->version > 0) - { - switch (msg) - { - case WM_RBUTTONUP: - notify_owner( icon, WM_CONTEXTMENU, pt ); - break; - case WM_LBUTTONUP: - notify_owner( icon, NIN_SELECT, pt ); - break; - } - } - break; - } - case WM_CLOSE: /* don't destroy the tray window, just hide it */ ShowWindow( hwnd, SW_HIDE );
From: Rémi Bernon rbernon@codeweavers.com
--- programs/explorer/systray.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-)
diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c index 60b407afa6c..e35962486b3 100644 --- a/programs/explorer/systray.c +++ b/programs/explorer/systray.c @@ -187,17 +187,16 @@ static void create_tooltip(struct icon *icon) TTTOOLINFOW ti;
init_common_controls(); - icon->tooltip = CreateWindowExW(WS_EX_TOPMOST, TOOLTIPS_CLASSW, NULL, - WS_POPUP | TTS_ALWAYSTIP, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - tray_window, NULL, NULL, NULL); + icon->tooltip = CreateWindowExW( WS_EX_TOPMOST, TOOLTIPS_CLASSW, NULL, WS_POPUP | TTS_ALWAYSTIP, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + icon->window, NULL, NULL, NULL );
ZeroMemory(&ti, sizeof(ti)); ti.cbSize = sizeof(TTTOOLINFOW); - ti.hwnd = tray_window; + ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND; + ti.hwnd = icon->window; + ti.uId = (UINT_PTR)icon->window; ti.lpszText = icon->tiptext; - if (icon->display != -1) ti.rect = get_icon_rect( icon ); SendMessageW(icon->tooltip, TTM_ADDTOOLW, 0, (LPARAM)&ti); }
@@ -298,7 +297,9 @@ static void update_tooltip_text(struct icon *icon)
ZeroMemory(&ti, sizeof(ti)); ti.cbSize = sizeof(TTTOOLINFOW); - ti.hwnd = tray_window; + ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND; + ti.hwnd = icon->window; + ti.uId = (UINT_PTR)icon->window; ti.lpszText = icon->tiptext;
SendMessageW(icon->tooltip, TTM_UPDATETIPTEXTW, 0, (LPARAM)&ti); @@ -318,8 +319,10 @@ static void update_tooltip_position( struct icon *icon )
ZeroMemory(&ti, sizeof(ti)); ti.cbSize = sizeof(TTTOOLINFOW); - ti.hwnd = tray_window; - if (icon->display != -1) ti.rect = get_icon_rect( icon ); + ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND; + ti.hwnd = icon->window; + ti.uId = (UINT_PTR)icon->window; + ti.lpszText = icon->tiptext; SendMessageW( icon->tooltip, TTM_NEWTOOLRECTW, 0, (LPARAM)&ti ); if (balloon_icon == icon) set_balloon_position( icon ); }
From: Rémi Bernon rbernon@codeweavers.com
--- programs/explorer/systray.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-)
diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c index e35962486b3..cc2f6440115 100644 --- a/programs/explorer/systray.c +++ b/programs/explorer/systray.c @@ -154,17 +154,6 @@ static struct icon *get_icon(HWND owner, UINT id) return NULL; }
-static RECT get_icon_rect( struct icon *icon ) -{ - RECT rect; - - rect.right = tray_width - icon_cx * icon->display; - rect.left = rect.right - icon_cx; - rect.top = (tray_height - icon_cy) / 2; - rect.bottom = rect.top + icon_cy; - return rect; -} - static void init_common_controls(void) { static BOOL initialized = FALSE; @@ -202,10 +191,10 @@ static void create_tooltip(struct icon *icon)
static void set_balloon_position( struct icon *icon ) { - RECT rect = get_icon_rect( icon ); + RECT rect; POINT pos;
- MapWindowPoints( tray_window, 0, (POINT *)&rect, 2 ); + GetWindowRect( icon->window, &rect ); pos.x = (rect.left + rect.right) / 2; pos.y = (rect.top + rect.bottom) / 2; SendMessageW( balloon_window, TTM_TRACKPOSITION, 0, MAKELONG( pos.x, pos.y )); @@ -308,8 +297,12 @@ static void update_tooltip_text(struct icon *icon) /* get the position of an icon in the stand-alone tray */ static POINT get_icon_pos( struct icon *icon ) { - RECT rect = get_icon_rect( icon ); - return *(POINT *)▭ + POINT pos; + + pos.x = tray_width - icon_cx * (icon->display + 1); + pos.y = (tray_height - icon_cy) / 2; + + return pos; }
/* synchronize tooltip position with tooltip window */
From: Rémi Bernon rbernon@codeweavers.com
--- programs/explorer/systray.c | 77 +++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 29 deletions(-)
diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c index cc2f6440115..623abcd03a3 100644 --- a/programs/explorer/systray.c +++ b/programs/explorer/systray.c @@ -200,7 +200,19 @@ static void set_balloon_position( struct icon *icon ) SendMessageW( balloon_window, TTM_TRACKPOSITION, 0, MAKELONG( pos.x, pos.y )); }
-static void balloon_create_timer(void) +static void update_systray_balloon_position(void) +{ + RECT rect; + POINT pos; + + if (!balloon_icon) return; + GetWindowRect( balloon_icon->window, &rect ); + pos.x = (rect.left + rect.right) / 2; + pos.y = (rect.top + rect.bottom) / 2; + SendMessageW( balloon_window, TTM_TRACKPOSITION, 0, MAKELONG( pos.x, pos.y )); +} + +static void balloon_create_timer( struct icon *icon ) { TTTOOLINFOW ti;
@@ -208,24 +220,24 @@ static void balloon_create_timer(void) balloon_window = CreateWindowExW( WS_EX_TOPMOST, TOOLTIPS_CLASSW, NULL, WS_POPUP | TTS_ALWAYSTIP | TTS_NOPREFIX | TTS_BALLOON | TTS_CLOSE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - tray_window, NULL, NULL, NULL); + icon->window, NULL, NULL, NULL );
memset( &ti, 0, sizeof(ti) ); ti.cbSize = sizeof(TTTOOLINFOW); - ti.hwnd = tray_window; - ti.uFlags = TTF_TRACK; - ti.lpszText = balloon_icon->info_text; + ti.hwnd = icon->window; + ti.uId = (UINT_PTR)icon->window; + ti.uFlags = TTF_TRACK | TTF_IDISHWND; + ti.lpszText = icon->info_text; SendMessageW( balloon_window, TTM_ADDTOOLW, 0, (LPARAM)&ti ); - if ((balloon_icon->info_flags & NIIF_ICONMASK) == NIIF_USER) - SendMessageW( balloon_window, TTM_SETTITLEW, (WPARAM)balloon_icon->info_icon, - (LPARAM)balloon_icon->info_title ); + if ((icon->info_flags & NIIF_ICONMASK) == NIIF_USER) + SendMessageW( balloon_window, TTM_SETTITLEW, (WPARAM)icon->info_icon, (LPARAM)icon->info_title ); else - SendMessageW( balloon_window, TTM_SETTITLEW, balloon_icon->info_flags, - (LPARAM)balloon_icon->info_title ); - set_balloon_position( balloon_icon ); + SendMessageW( balloon_window, TTM_SETTITLEW, icon->info_flags, (LPARAM)icon->info_title ); + balloon_icon = icon; + update_systray_balloon_position(); SendMessageW( balloon_window, TTM_TRACKACTIVATE, TRUE, (LPARAM)&ti ); - KillTimer( tray_window, BALLOON_CREATE_TIMER ); - SetTimer( tray_window, BALLOON_SHOW_TIMER, balloon_icon->info_timeout, NULL ); + KillTimer( icon->window, BALLOON_CREATE_TIMER ); + SetTimer( icon->window, BALLOON_SHOW_TIMER, icon->info_timeout, NULL ); }
static BOOL show_balloon( struct icon *icon ) @@ -233,20 +245,20 @@ static BOOL show_balloon( struct icon *icon ) if (icon->display == -1) return FALSE; /* not displayed */ if (!icon->info_text[0]) return FALSE; /* no balloon */ balloon_icon = icon; - SetTimer( tray_window, BALLOON_CREATE_TIMER, BALLOON_CREATE_TIMEOUT, NULL ); + SetTimer( icon->window, BALLOON_CREATE_TIMER, BALLOON_CREATE_TIMEOUT, NULL ); return TRUE; }
-static void hide_balloon(void) +static void hide_balloon( struct icon *icon ) { if (!balloon_icon) return; if (balloon_window) { - KillTimer( tray_window, BALLOON_SHOW_TIMER ); + KillTimer( balloon_icon->window, BALLOON_SHOW_TIMER ); DestroyWindow( balloon_window ); balloon_window = 0; } - else KillTimer( tray_window, BALLOON_CREATE_TIMER ); + else KillTimer( balloon_icon->window, BALLOON_CREATE_TIMER ); balloon_icon = NULL; }
@@ -262,20 +274,19 @@ static void update_balloon( struct icon *icon ) { if (balloon_icon == icon) { - hide_balloon(); + hide_balloon( icon ); show_balloon( icon ); } else if (!balloon_icon) { - if (!show_balloon( icon )) return; + show_balloon( icon ); } - if (!balloon_icon) show_next_balloon(); }
-static void balloon_timer(void) +static void balloon_timer( struct icon *icon ) { - if (balloon_icon) balloon_icon->info_text[0] = 0; /* clear text now that balloon has been shown */ - hide_balloon(); + icon->info_text[0] = 0; /* clear text now that balloon has been shown */ + hide_balloon( icon ); show_next_balloon(); }
@@ -405,6 +416,18 @@ static LRESULT WINAPI tray_icon_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPA } break; } + + case WM_WINDOWPOSCHANGED: + update_systray_balloon_position(); + break; + + case WM_TIMER: + switch (wparam) + { + case BALLOON_CREATE_TIMER: balloon_create_timer( icon ); break; + case BALLOON_SHOW_TIMER: balloon_timer( icon ); break; + } + return 0; }
return DefWindowProcW( hwnd, msg, wparam, lparam ); @@ -867,12 +890,8 @@ static LRESULT WINAPI shell_traywnd_proc( HWND hwnd, UINT msg, WPARAM wparam, LP else do_show_systray(); break;
- case WM_TIMER: - switch (wparam) - { - case BALLOON_CREATE_TIMER: balloon_create_timer(); break; - case BALLOON_SHOW_TIMER: balloon_timer(); break; - } + case WM_MOVE: + update_systray_balloon_position(); break;
case WM_CLOSE:
From: Rémi Bernon rbernon@codeweavers.com
--- programs/explorer/systray.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c index 623abcd03a3..b2581c90840 100644 --- a/programs/explorer/systray.c +++ b/programs/explorer/systray.c @@ -58,6 +58,8 @@ struct notify_data /* platform-independent format for NOTIFYICONDATA */
static int (CDECL *wine_notify_icon)(DWORD,NOTIFYICONDATAW *);
+#define ICON_DISPLAY_HIDDEN -1 + /* an individual systray icon, unpacked from the NOTIFYICONDATA and always in unicode */ struct icon { @@ -242,7 +244,7 @@ static void balloon_create_timer( struct icon *icon )
static BOOL show_balloon( struct icon *icon ) { - if (icon->display == -1) return FALSE; /* not displayed */ + if (icon->display == ICON_DISPLAY_HIDDEN) return FALSE; /* not displayed */ if (!icon->info_text[0]) return FALSE; /* no balloon */ balloon_icon = icon; SetTimer( icon->window, BALLOON_CREATE_TIMER, BALLOON_CREATE_TIMEOUT, NULL ); @@ -438,7 +440,7 @@ static void systray_add_icon( struct icon *icon ) { POINT pos;
- if (icon->display != -1) return; /* already added */ + if (icon->display != ICON_DISPLAY_HIDDEN) return; /* already added */
icon->display = nb_displayed++; pos = get_icon_pos( icon ); @@ -454,7 +456,7 @@ static void systray_remove_icon( struct icon *icon ) struct icon *ptr; POINT pos;
- if (icon->display == -1) return; /* already removed */ + if (icon->display == ICON_DISPLAY_HIDDEN) return; /* already removed */
assert( nb_displayed ); LIST_FOR_EACH_ENTRY( ptr, &icon_list, struct icon, entry ) @@ -470,7 +472,7 @@ static void systray_remove_icon( struct icon *icon ) if (!--nb_displayed && !enable_shell) do_hide_systray(); TRACE( "removed %u now %d icons\n", icon->id, nb_displayed );
- icon->display = -1; + icon->display = ICON_DISPLAY_HIDDEN; }
/* make an icon visible */ @@ -478,7 +480,7 @@ static BOOL show_icon(struct icon *icon) { TRACE( "id=0x%x, hwnd=%p\n", icon->id, icon->owner );
- if (icon->display != -1) return TRUE; /* already displayed */ + if (icon->display != ICON_DISPLAY_HIDDEN) return TRUE; /* already displayed */
systray_add_icon( icon );
@@ -492,7 +494,7 @@ static BOOL hide_icon(struct icon *icon) { TRACE( "id=0x%x, hwnd=%p\n", icon->id, icon->owner );
- if (icon->display == -1) return TRUE; /* already hidden */ + if (icon->display == ICON_DISPLAY_HIDDEN) return TRUE; /* already hidden */
ShowWindow( icon->window, SW_HIDE ); systray_remove_icon( icon ); @@ -523,7 +525,7 @@ static BOOL modify_icon( struct icon *icon, NOTIFYICONDATAW *nid ) { if (icon->image) DestroyIcon(icon->image); icon->image = CopyIcon(nid->hIcon); - if (icon->display != -1) InvalidateRect( icon->window, NULL, TRUE ); + if (icon->display >= 0) InvalidateRect( icon->window, NULL, TRUE ); }
if (nid->uFlags & NIF_MESSAGE) @@ -533,7 +535,7 @@ static BOOL modify_icon( struct icon *icon, NOTIFYICONDATAW *nid ) if (nid->uFlags & NIF_TIP) { lstrcpynW( icon->tiptext, nid->szTip, ARRAY_SIZE( icon->tiptext )); - if (icon->display != -1) update_tooltip_text(icon); + if (icon->display != ICON_DISPLAY_HIDDEN) update_tooltip_text(icon); } if (nid->uFlags & NIF_INFO && nid->cbSize >= NOTIFYICONDATAA_V2_SIZE) { @@ -571,7 +573,7 @@ static BOOL add_icon(NOTIFYICONDATAW *nid) ZeroMemory(icon, sizeof(struct icon)); icon->id = nid->uID; icon->owner = nid->hWnd; - icon->display = -1; + icon->display = ICON_DISPLAY_HIDDEN;
CreateWindowW( tray_icon_class.lpszClassName, NULL, WS_CHILD, 0, 0, icon_cx, icon_cy, tray_window, NULL, NULL, icon );
From: Rémi Bernon rbernon@codeweavers.com
--- programs/explorer/systray.c | 77 +++++++++++++++++++++++------- programs/explorer/tests/explorer.c | 3 ++ 2 files changed, 64 insertions(+), 16 deletions(-)
diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c index b2581c90840..c684608ee4e 100644 --- a/programs/explorer/systray.c +++ b/programs/explorer/systray.c @@ -98,7 +98,7 @@ static HWND tray_window;
static unsigned int nb_displayed;
-static BOOL hide_systray, enable_shell; +static BOOL show_systray = TRUE, enable_shell, enable_taskbar; static int icon_cx, icon_cy, tray_width, tray_height; static int start_button_width, taskbar_button_width; static WCHAR start_label[50]; @@ -312,12 +312,36 @@ static POINT get_icon_pos( struct icon *icon ) { POINT pos;
- pos.x = tray_width - icon_cx * (icon->display + 1); - pos.y = (tray_height - icon_cy) / 2; + if (enable_taskbar) + { + pos.x = tray_width - icon_cx * (icon->display + 1); + pos.y = (tray_height - icon_cy) / 2; + } + else + { + pos.x = icon_cx * icon->display; + pos.y = 0; + }
return pos; }
+/* get the size of the stand-alone tray window */ +static SIZE get_window_size(void) +{ + SIZE size; + RECT rect; + + rect.left = 0; + rect.top = 0; + rect.right = icon_cx * max( nb_displayed, MIN_DISPLAYED ); + rect.bottom = icon_cy; + AdjustWindowRect( &rect, WS_CAPTION, FALSE ); + size.cx = rect.right - rect.left; + size.cy = rect.bottom - rect.top; + return size; +} + /* synchronize tooltip position with tooltip window */ static void update_tooltip_position( struct icon *icon ) { @@ -446,7 +470,7 @@ static void systray_add_icon( struct icon *icon ) pos = get_icon_pos( icon ); SetWindowPos( icon->window, 0, pos.x, pos.y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_SHOWWINDOW );
- if (nb_displayed == 1 && !hide_systray) do_show_systray(); + if (nb_displayed == 1 && show_systray) do_show_systray(); TRACE( "added %u now %d icons\n", icon->id, nb_displayed ); }
@@ -620,6 +644,7 @@ static void sync_taskbar_buttons(void) int right = tray_width - nb_displayed * icon_cx; HWND foreground = GetAncestor( GetForegroundWindow(), GA_ROOTOWNER );
+ if (!enable_taskbar) return; if (!IsWindowVisible( tray_window )) return;
LIST_FOR_EACH_ENTRY( win, &taskbar_buttons, struct taskbar_button, entry ) @@ -743,7 +768,7 @@ static void add_taskbar_button( HWND hwnd ) { struct taskbar_button *win;
- if (hide_systray) return; + if (!enable_taskbar || !show_systray) return;
/* ignore our own windows */ if (hwnd) @@ -856,7 +881,16 @@ static void do_show_systray(void) SIZE size; NONCLIENTMETRICSW ncm; HFONT font; - HDC hdc = GetDC( 0 ); + HDC hdc; + + if (!enable_taskbar) + { + size = get_window_size(); + SetWindowPos( tray_window, 0, 0, 0, size.cx, size.cy, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_SHOWWINDOW ); + return; + } + + hdc = GetDC( 0 );
ncm.cbSize = sizeof(NONCLIENTMETRICSW); SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &ncm, 0 ); @@ -888,7 +922,8 @@ static LRESULT WINAPI shell_traywnd_proc( HWND hwnd, UINT msg, WPARAM wparam, LP return handle_incoming((HWND)wparam, (COPYDATASTRUCT *)lparam);
case WM_DISPLAYCHANGE: - if (hide_systray || (!nb_displayed && !enable_shell)) do_hide_systray(); + if (!show_systray) do_hide_systray(); + else if (!nb_displayed && !enable_shell) do_hide_systray(); else do_show_systray(); break;
@@ -956,8 +991,8 @@ void initialize_systray( HMODULE graphics_driver, BOOL using_root, BOOL arg_enab
icon_cx = GetSystemMetrics( SM_CXSMICON ) + 2*ICON_BORDER; icon_cy = GetSystemMetrics( SM_CYSMICON ) + 2*ICON_BORDER; - hide_systray = using_root; enable_shell = arg_enable_shell; + enable_taskbar = enable_shell || !using_root;
/* register the systray listener window class */ if (!RegisterClassExW( &shell_traywnd_class )) @@ -971,13 +1006,23 @@ void initialize_systray( HMODULE graphics_driver, BOOL using_root, BOOL arg_enab return; }
- SystemParametersInfoW( SPI_GETWORKAREA, 0, &work_rect, 0 ); - SetRect( &primary_rect, 0, 0, GetSystemMetrics( SM_CXSCREEN ), GetSystemMetrics( SM_CYSCREEN ) ); - SubtractRect( &taskbar_rect, &primary_rect, &work_rect ); + if (enable_taskbar) + { + SystemParametersInfoW( SPI_GETWORKAREA, 0, &work_rect, 0 ); + SetRect( &primary_rect, 0, 0, GetSystemMetrics( SM_CXSCREEN ), GetSystemMetrics( SM_CYSCREEN ) ); + SubtractRect( &taskbar_rect, &primary_rect, &work_rect ); + + tray_window = CreateWindowExW( WS_EX_NOACTIVATE, shell_traywnd_class.lpszClassName, NULL, WS_POPUP, + taskbar_rect.left, taskbar_rect.top, taskbar_rect.right - taskbar_rect.left, + taskbar_rect.bottom - taskbar_rect.top, 0, 0, 0, 0 ); + } + else + { + SIZE size = get_window_size(); + tray_window = CreateWindowExW( 0, shell_traywnd_class.lpszClassName, L"", WS_CAPTION | WS_SYSMENU, + CW_USEDEFAULT, CW_USEDEFAULT, size.cx, size.cy, 0, 0, 0, 0 ); + }
- tray_window = CreateWindowExW( WS_EX_NOACTIVATE, shell_traywnd_class.lpszClassName, NULL, WS_POPUP, taskbar_rect.left, - taskbar_rect.top, taskbar_rect.right - taskbar_rect.left, - taskbar_rect.bottom - taskbar_rect.top, 0, 0, 0, 0 ); if (!tray_window) { ERR( "Could not create tray window\n" ); @@ -988,6 +1033,6 @@ void initialize_systray( HMODULE graphics_driver, BOOL using_root, BOOL arg_enab
add_taskbar_button( 0 );
- if (hide_systray) do_hide_systray(); - else if (enable_shell) do_show_systray(); + if (enable_taskbar) do_show_systray(); + else do_hide_systray(); } diff --git a/programs/explorer/tests/explorer.c b/programs/explorer/tests/explorer.c index 3882027ae46..f1243c14622 100644 --- a/programs/explorer/tests/explorer.c +++ b/programs/explorer/tests/explorer.c @@ -40,6 +40,9 @@ static void test_taskbar(void) SystemParametersInfoW(SPI_GETWORKAREA, 0, &work_rect, 0); SetRect(&primary_rect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); SubtractRect(&expected_rect, &primary_rect, &work_rect); + + /* In standalone mode, the systray window is floating */ + todo_wine_if(!(GetWindowLongW(hwnd, GWL_STYLE) & WS_POPUP)) ok(EqualRect(&taskbar_rect, &expected_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&expected_rect), wine_dbgstr_rect(&taskbar_rect)); }
From: Rémi Bernon rbernon@codeweavers.com
--- programs/explorer/systray.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c index c684608ee4e..eb844a45003 100644 --- a/programs/explorer/systray.c +++ b/programs/explorer/systray.c @@ -105,6 +105,7 @@ static WCHAR start_label[50];
static struct icon *balloon_icon; static HWND balloon_window; +static POINT balloon_pos;
#define MIN_DISPLAYED 8 #define ICON_BORDER 2 @@ -211,6 +212,8 @@ static void update_systray_balloon_position(void) GetWindowRect( balloon_icon->window, &rect ); pos.x = (rect.left + rect.right) / 2; pos.y = (rect.top + rect.bottom) / 2; + if (pos.x == balloon_pos.x && pos.y == balloon_pos.y) return; /* nothing changed */ + balloon_pos = pos; SendMessageW( balloon_window, TTM_TRACKPOSITION, 0, MAKELONG( pos.x, pos.y )); }
@@ -236,6 +239,7 @@ static void balloon_create_timer( struct icon *icon ) else SendMessageW( balloon_window, TTM_SETTITLEW, icon->info_flags, (LPARAM)icon->info_title ); balloon_icon = icon; + balloon_pos.x = balloon_pos.y = MAXLONG; update_systray_balloon_position(); SendMessageW( balloon_window, TTM_TRACKACTIVATE, TRUE, (LPARAM)&ti ); KillTimer( icon->window, BALLOON_CREATE_TIMER );
v4: Remove the title from the standalone systray window to avoid breaking some user32:win tests.