2 * Copyright (C) 2004 Mike Hearn, for CodeWeavers
3 * Copyright (C) 2005 Robert Shearman
4 * Copyright (C) 2008 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define NONAMELESSUNION
24 #define _WIN32_IE 0x500
29 #include <wine/debug.h>
30 #include <wine/list.h>
32 #include "explorer_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(systray
);
37 struct notify_data
/* platform-independent format for NOTIFYICONDATA */
42 UINT uCallbackMessage
;
51 WCHAR szInfoTitle
[64];
54 /* data for the icon bitmap */
61 static int (CDECL
*wine_notify_icon
)(DWORD
,NOTIFYICONDATAW
*);
63 /* an individual systray icon, unpacked from the NOTIFYICONDATA and always in unicode */
67 HICON image
; /* the image to render */
68 HWND owner
; /* the HWND passed in to the Shell_NotifyIcon call */
69 HWND tooltip
; /* Icon tooltip */
70 UINT state
; /* state flags */
71 UINT id
; /* the unique id given by the app */
72 UINT callback_message
;
73 int display
; /* index in display list, or -1 if hidden */
74 WCHAR tiptext
[128]; /* Tooltip text. If empty => tooltip disabled */
75 WCHAR info_text
[256]; /* info balloon text */
76 WCHAR info_title
[64]; /* info balloon title */
77 UINT info_flags
; /* flags for info balloon */
78 UINT info_timeout
; /* timeout for info balloon */
79 HICON info_icon
; /* info balloon icon */
82 static struct list icon_list
= LIST_INIT( icon_list
);
83 static HWND tray_window
;
85 static unsigned int alloc_displayed
;
86 static unsigned int nb_displayed
;
87 static struct icon
**displayed
; /* array of currently displayed icons */
89 static BOOL hide_systray
, enable_shell
;
90 static int icon_cx
, icon_cy
, tray_width
;
92 static struct icon
*balloon_icon
;
93 static HWND balloon_window
;
95 static HWND start_button
;
97 #define MIN_DISPLAYED 8
100 #define VALID_WIN_TIMER 1
101 #define BALLOON_CREATE_TIMER 2
102 #define BALLOON_SHOW_TIMER 3
104 #define VALID_WIN_TIMEOUT 2000
105 #define BALLOON_CREATE_TIMEOUT 2000
106 #define BALLOON_SHOW_MIN_TIMEOUT 10000
107 #define BALLOON_SHOW_MAX_TIMEOUT 30000
109 /* Retrieves icon record by owner window and ID */
110 static struct icon
*get_icon(HWND owner
, UINT id
)
114 /* search for the icon */
115 LIST_FOR_EACH_ENTRY( this, &icon_list
, struct icon
, entry
)
116 if ((this->id
== id
) && (this->owner
== owner
)) return this;
121 static RECT
get_icon_rect( struct icon
*icon
)
125 rect
.right
= tray_width
- icon_cx
* icon
->display
;
126 rect
.left
= rect
.right
- icon_cx
;
128 rect
.bottom
= icon_cy
;
132 static void init_common_controls(void)
134 static BOOL initialized
= FALSE
;
138 INITCOMMONCONTROLSEX init_tooltip
;
140 init_tooltip
.dwSize
= sizeof(INITCOMMONCONTROLSEX
);
141 init_tooltip
.dwICC
= ICC_TAB_CLASSES
|ICC_STANDARD_CLASSES
;
143 InitCommonControlsEx(&init_tooltip
);
148 /* Creates tooltip window for icon. */
149 static void create_tooltip(struct icon
*icon
)
153 init_common_controls();
154 icon
->tooltip
= CreateWindowExW(WS_EX_TOPMOST
, TOOLTIPS_CLASSW
, NULL
,
155 WS_POPUP
| TTS_ALWAYSTIP
,
156 CW_USEDEFAULT
, CW_USEDEFAULT
,
157 CW_USEDEFAULT
, CW_USEDEFAULT
,
158 tray_window
, NULL
, NULL
, NULL
);
160 ZeroMemory(&ti
, sizeof(ti
));
161 ti
.cbSize
= sizeof(TTTOOLINFOW
);
162 ti
.hwnd
= tray_window
;
163 ti
.lpszText
= icon
->tiptext
;
164 if (icon
->display
!= -1) ti
.rect
= get_icon_rect( icon
);
165 SendMessageW(icon
->tooltip
, TTM_ADDTOOLW
, 0, (LPARAM
)&ti
);
168 static void set_balloon_position( struct icon
*icon
)
170 RECT rect
= get_icon_rect( icon
);
173 MapWindowPoints( tray_window
, 0, (POINT
*)&rect
, 2 );
174 pos
.x
= (rect
.left
+ rect
.right
) / 2;
175 pos
.y
= (rect
.top
+ rect
.bottom
) / 2;
176 SendMessageW( balloon_window
, TTM_TRACKPOSITION
, 0, MAKELONG( pos
.x
, pos
.y
));
179 static void balloon_create_timer(void)
183 init_common_controls();
184 balloon_window
= CreateWindowExW( WS_EX_TOPMOST
, TOOLTIPS_CLASSW
, NULL
,
185 WS_POPUP
| TTS_ALWAYSTIP
| TTS_NOPREFIX
| TTS_BALLOON
| TTS_CLOSE
,
186 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
187 tray_window
, NULL
, NULL
, NULL
);
189 memset( &ti
, 0, sizeof(ti
) );
190 ti
.cbSize
= sizeof(TTTOOLINFOW
);
191 ti
.hwnd
= tray_window
;
192 ti
.uFlags
= TTF_TRACK
;
193 ti
.lpszText
= balloon_icon
->info_text
;
194 SendMessageW( balloon_window
, TTM_ADDTOOLW
, 0, (LPARAM
)&ti
);
195 if ((balloon_icon
->info_flags
& NIIF_ICONMASK
) == NIIF_USER
)
196 SendMessageW( balloon_window
, TTM_SETTITLEW
, (WPARAM
)balloon_icon
->info_icon
,
197 (LPARAM
)balloon_icon
->info_title
);
199 SendMessageW( balloon_window
, TTM_SETTITLEW
, balloon_icon
->info_flags
,
200 (LPARAM
)balloon_icon
->info_title
);
201 set_balloon_position( balloon_icon
);
202 SendMessageW( balloon_window
, TTM_TRACKACTIVATE
, TRUE
, (LPARAM
)&ti
);
203 KillTimer( tray_window
, BALLOON_CREATE_TIMER
);
204 SetTimer( tray_window
, BALLOON_SHOW_TIMER
, balloon_icon
->info_timeout
, NULL
);
207 static BOOL
show_balloon( struct icon
*icon
)
209 if (icon
->display
== -1) return FALSE
; /* not displayed */
210 if (!icon
->info_text
[0]) return FALSE
; /* no balloon */
212 SetTimer( tray_window
, BALLOON_CREATE_TIMER
, BALLOON_CREATE_TIMEOUT
, NULL
);
216 static void hide_balloon(void)
218 if (!balloon_icon
) return;
221 KillTimer( tray_window
, BALLOON_SHOW_TIMER
);
222 DestroyWindow( balloon_window
);
225 else KillTimer( tray_window
, BALLOON_CREATE_TIMER
);
229 static void show_next_balloon(void)
233 LIST_FOR_EACH_ENTRY( icon
, &icon_list
, struct icon
, entry
)
234 if (show_balloon( icon
)) break;
237 static void update_balloon( struct icon
*icon
)
239 if (balloon_icon
== icon
)
242 show_balloon( icon
);
244 else if (!balloon_icon
)
246 if (!show_balloon( icon
)) return;
248 if (!balloon_icon
) show_next_balloon();
251 static void balloon_timer(void)
253 if (balloon_icon
) balloon_icon
->info_text
[0] = 0; /* clear text now that balloon has been shown */
258 /* Synchronize tooltip text with tooltip window */
259 static void update_tooltip_text(struct icon
*icon
)
263 ZeroMemory(&ti
, sizeof(ti
));
264 ti
.cbSize
= sizeof(TTTOOLINFOW
);
265 ti
.hwnd
= tray_window
;
266 ti
.lpszText
= icon
->tiptext
;
268 SendMessageW(icon
->tooltip
, TTM_UPDATETIPTEXTW
, 0, (LPARAM
)&ti
);
271 /* synchronize tooltip position with tooltip window */
272 static void update_tooltip_position( struct icon
*icon
)
276 ZeroMemory(&ti
, sizeof(ti
));
277 ti
.cbSize
= sizeof(TTTOOLINFOW
);
278 ti
.hwnd
= tray_window
;
279 if (icon
->display
!= -1) ti
.rect
= get_icon_rect( icon
);
280 SendMessageW( icon
->tooltip
, TTM_NEWTOOLRECTW
, 0, (LPARAM
)&ti
);
281 if (balloon_icon
== icon
) set_balloon_position( icon
);
284 /* find the icon located at a certain point in the tray window */
285 static struct icon
*icon_from_point( int x
, int y
)
287 if (y
< 0 || y
>= icon_cy
) return NULL
;
289 if (x
< 0 || x
>= icon_cx
* nb_displayed
) return NULL
;
290 return displayed
[x
/ icon_cx
];
293 /* invalidate the portion of the tray window that contains the specified icons */
294 static void invalidate_icons( unsigned int start
, unsigned int end
)
298 rect
.left
= tray_width
- (end
+ 1) * icon_cx
;
300 rect
.right
= tray_width
- start
* icon_cx
;
301 rect
.bottom
= icon_cy
;
302 InvalidateRect( tray_window
, &rect
, TRUE
);
305 /* make an icon visible */
306 static BOOL
show_icon(struct icon
*icon
)
308 WINE_TRACE("id=0x%x, hwnd=%p\n", icon
->id
, icon
->owner
);
310 if (icon
->display
!= -1) return TRUE
; /* already displayed */
312 if (nb_displayed
>= alloc_displayed
)
314 unsigned int new_count
= max( alloc_displayed
* 2, 32 );
316 if (displayed
) ptr
= HeapReAlloc( GetProcessHeap(), 0, displayed
, new_count
* sizeof(*ptr
) );
317 else ptr
= HeapAlloc( GetProcessHeap(), 0, new_count
* sizeof(*ptr
) );
318 if (!ptr
) return FALSE
;
320 alloc_displayed
= new_count
;
323 icon
->display
= nb_displayed
;
324 displayed
[nb_displayed
++] = icon
;
325 update_tooltip_position( icon
);
326 invalidate_icons( nb_displayed
-1, nb_displayed
-1 );
328 if (nb_displayed
== 1 && !hide_systray
) ShowWindow( tray_window
, SW_SHOWNA
);
330 create_tooltip(icon
);
331 update_balloon( icon
);
335 /* make an icon invisible */
336 static BOOL
hide_icon(struct icon
*icon
)
340 WINE_TRACE("id=0x%x, hwnd=%p\n", icon
->id
, icon
->owner
);
342 if (icon
->display
== -1) return TRUE
; /* already hidden */
344 assert( nb_displayed
);
345 for (i
= icon
->display
; i
< nb_displayed
- 1; i
++)
347 displayed
[i
] = displayed
[i
+ 1];
348 displayed
[i
]->display
= i
;
349 update_tooltip_position( displayed
[i
] );
352 invalidate_icons( icon
->display
, nb_displayed
);
355 if (!nb_displayed
&& !enable_shell
) ShowWindow( tray_window
, SW_HIDE
);
357 update_balloon( icon
);
358 update_tooltip_position( icon
);
362 /* Modifies an existing icon record */
363 static BOOL
modify_icon( struct icon
*icon
, NOTIFYICONDATAW
*nid
)
365 WINE_TRACE("id=0x%x, hwnd=%p\n", nid
->uID
, nid
->hWnd
);
367 /* demarshal the request from the NID */
370 WINE_WARN("Invalid icon ID (0x%x) for HWND %p\n", nid
->uID
, nid
->hWnd
);
374 if (nid
->uFlags
& NIF_STATE
)
376 icon
->state
= (icon
->state
& ~nid
->dwStateMask
) | (nid
->dwState
& nid
->dwStateMask
);
379 if (nid
->uFlags
& NIF_ICON
)
381 if (icon
->image
) DestroyIcon(icon
->image
);
382 icon
->image
= CopyIcon(nid
->hIcon
);
383 if (icon
->display
!= -1) invalidate_icons( icon
->display
, icon
->display
);
386 if (nid
->uFlags
& NIF_MESSAGE
)
388 icon
->callback_message
= nid
->uCallbackMessage
;
390 if (nid
->uFlags
& NIF_TIP
)
392 lstrcpynW(icon
->tiptext
, nid
->szTip
, sizeof(icon
->tiptext
)/sizeof(WCHAR
));
393 if (icon
->display
!= -1) update_tooltip_text(icon
);
395 if (nid
->uFlags
& NIF_INFO
&& nid
->cbSize
>= NOTIFYICONDATAA_V2_SIZE
)
397 lstrcpynW( icon
->info_text
, nid
->szInfo
, sizeof(icon
->info_text
)/sizeof(WCHAR
) );
398 lstrcpynW( icon
->info_title
, nid
->szInfoTitle
, sizeof(icon
->info_title
)/sizeof(WCHAR
) );
399 icon
->info_flags
= nid
->dwInfoFlags
;
400 icon
->info_timeout
= max(min(nid
->u
.uTimeout
, BALLOON_SHOW_MAX_TIMEOUT
), BALLOON_SHOW_MIN_TIMEOUT
);
401 icon
->info_icon
= nid
->hBalloonIcon
;
402 update_balloon( icon
);
404 if (icon
->state
& NIS_HIDDEN
) hide_icon( icon
);
405 else show_icon( icon
);
409 /* Adds a new icon record to the list */
410 static BOOL
add_icon(NOTIFYICONDATAW
*nid
)
414 WINE_TRACE("id=0x%x, hwnd=%p\n", nid
->uID
, nid
->hWnd
);
416 if ((icon
= get_icon(nid
->hWnd
, nid
->uID
)))
418 WINE_WARN("duplicate tray icon add, buggy app?\n");
422 if (!(icon
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*icon
))))
424 WINE_ERR("out of memory\n");
428 ZeroMemory(icon
, sizeof(struct icon
));
430 icon
->owner
= nid
->hWnd
;
433 if (list_empty( &icon_list
)) SetTimer( tray_window
, VALID_WIN_TIMER
, VALID_WIN_TIMEOUT
, NULL
);
434 list_add_tail(&icon_list
, &icon
->entry
);
436 return modify_icon( icon
, nid
);
439 /* Deletes tray icon window and icon record */
440 static BOOL
delete_icon(struct icon
*icon
)
443 list_remove(&icon
->entry
);
444 DestroyIcon(icon
->image
);
445 HeapFree(GetProcessHeap(), 0, icon
);
446 if (list_empty( &icon_list
)) KillTimer( tray_window
, VALID_WIN_TIMER
);
450 /* cleanup icons belonging to windows that have been destroyed */
451 static void cleanup_destroyed_windows(void)
453 struct icon
*icon
, *next
;
455 LIST_FOR_EACH_ENTRY_SAFE( icon
, next
, &icon_list
, struct icon
, entry
)
456 if (!IsWindow( icon
->owner
)) delete_icon( icon
);
459 static BOOL
handle_incoming(HWND hwndSource
, COPYDATASTRUCT
*cds
)
461 struct icon
*icon
= NULL
;
462 const struct notify_data
*data
;
466 if (cds
->cbData
< sizeof(*data
)) return FALSE
;
469 nid
.cbSize
= sizeof(nid
);
470 nid
.hWnd
= LongToHandle( data
->hWnd
);
472 nid
.uFlags
= data
->uFlags
;
473 nid
.uCallbackMessage
= data
->uCallbackMessage
;
475 nid
.dwState
= data
->dwState
;
476 nid
.dwStateMask
= data
->dwStateMask
;
477 nid
.u
.uTimeout
= data
->u
.uTimeout
;
478 nid
.dwInfoFlags
= data
->dwInfoFlags
;
479 nid
.guidItem
= data
->guidItem
;
480 lstrcpyW( nid
.szTip
, data
->szTip
);
481 lstrcpyW( nid
.szInfo
, data
->szInfo
);
482 lstrcpyW( nid
.szInfoTitle
, data
->szInfoTitle
);
483 nid
.hBalloonIcon
= 0;
485 /* FIXME: if statement only needed because we don't support interprocess
487 if ((nid
.uFlags
& NIF_ICON
) && cds
->cbData
> sizeof(*data
))
491 const char *buffer
= (const char *)(data
+ 1);
493 cbMaskBits
= (data
->width
* data
->height
+ 15) / 16 * 2;
494 cbColourBits
= (data
->planes
* data
->width
* data
->height
* data
->bpp
+ 15) / 16 * 2;
496 if (cds
->cbData
< sizeof(*data
) + cbMaskBits
+ cbColourBits
)
498 WINE_ERR("buffer underflow\n");
501 nid
.hIcon
= CreateIcon(NULL
, data
->width
, data
->height
, data
->planes
, data
->bpp
,
502 buffer
, buffer
+ cbMaskBits
);
505 /* try forward to x11drv first */
506 if (cds
->dwData
== NIM_ADD
|| !(icon
= get_icon( nid
.hWnd
, nid
.uID
)))
508 if (wine_notify_icon
&& ((ret
= wine_notify_icon( cds
->dwData
, &nid
)) != -1))
510 if (nid
.hIcon
) DestroyIcon( nid
.hIcon
);
519 ret
= add_icon(&nid
);
522 if (icon
) ret
= delete_icon( icon
);
525 if (icon
) ret
= modify_icon( icon
, &nid
);
528 WINE_FIXME("unhandled tray message: %ld\n", cds
->dwData
);
532 if (nid
.hIcon
) DestroyIcon( nid
.hIcon
);
536 static void do_hide_systray(void)
538 SetWindowPos( tray_window
, 0,
539 GetSystemMetrics(SM_XVIRTUALSCREEN
) + GetSystemMetrics(SM_CXVIRTUALSCREEN
),
540 GetSystemMetrics(SM_YVIRTUALSCREEN
) + GetSystemMetrics(SM_CYVIRTUALSCREEN
),
541 0, 0, SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
544 static LRESULT WINAPI
tray_wndproc( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
549 return handle_incoming((HWND
)wparam
, (COPYDATASTRUCT
*)lparam
);
551 case WM_DISPLAYCHANGE
:
552 if (hide_systray
) do_hide_systray();
555 tray_width
= GetSystemMetrics( SM_CXSCREEN
);
556 SetWindowPos( tray_window
, 0, 0, GetSystemMetrics( SM_CYSCREEN
) - icon_cy
,
557 tray_width
, icon_cy
, SWP_NOZORDER
| SWP_NOACTIVATE
);
564 case VALID_WIN_TIMER
: cleanup_destroyed_windows(); break;
565 case BALLOON_CREATE_TIMER
: balloon_create_timer(); break;
566 case BALLOON_SHOW_TIMER
: balloon_timer(); break;
576 hdc
= BeginPaint( hwnd
, &ps
);
577 for (i
= 0; i
< nb_displayed
; i
++)
579 RECT dummy
, rect
= get_icon_rect( displayed
[i
] );
580 if (IntersectRect( &dummy
, &rect
, &ps
.rcPaint
))
581 DrawIconEx( hdc
, rect
.left
+ ICON_BORDER
, rect
.top
+ ICON_BORDER
, displayed
[i
]->image
,
582 icon_cx
- 2*ICON_BORDER
, icon_cy
- 2*ICON_BORDER
,
583 0, 0, DI_DEFAULTSIZE
|DI_NORMAL
);
585 EndPaint( hwnd
, &ps
);
596 case WM_LBUTTONDBLCLK
:
597 case WM_RBUTTONDBLCLK
:
598 case WM_MBUTTONDBLCLK
:
601 struct icon
*icon
= icon_from_point( (short)LOWORD(lparam
), (short)HIWORD(lparam
) );
604 /* notify the owner hwnd of the message */
605 WINE_TRACE("relaying 0x%x\n", msg
);
608 message
.message
= msg
;
609 message
.wParam
= wparam
;
610 message
.lParam
= lparam
;
611 SendMessageW( icon
->tooltip
, TTM_RELAYEVENT
, 0, (LPARAM
)&message
);
613 if (!PostMessageW( icon
->owner
, icon
->callback_message
, (WPARAM
) icon
->id
, (LPARAM
) msg
) &&
614 GetLastError() == ERROR_INVALID_WINDOW_HANDLE
)
616 WINE_WARN("application window was destroyed without removing "
617 "notification icon, removing automatically\n");
624 /* don't destroy the tray window, just hide it */
625 ShowWindow( hwnd
, SW_HIDE
);
629 if ((HWND
)lparam
== start_button
&& HIWORD(wparam
) == BN_CLICKED
)
633 case WM_INITMENUPOPUP
:
635 return menu_wndproc(hwnd
, msg
, wparam
, lparam
);
638 return DefWindowProcW( hwnd
, msg
, wparam
, lparam
);
643 static void get_system_text_size( const WCHAR
*text
, SIZE
*size
)
645 /* FIXME: Implement BCM_GETIDEALSIZE and use that instead. */
646 HDC hdc
= GetDC( 0 );
648 GetTextExtentPointW(hdc
, text
, lstrlenW(text
), size
);
653 /* this function creates the listener window */
654 void initialize_systray( HMODULE graphics_driver
, BOOL using_root
, BOOL arg_enable_shell
)
657 static const WCHAR classname
[] = {'S','h','e','l','l','_','T','r','a','y','W','n','d',0};
658 static const WCHAR button_class
[] = {'B','u','t','t','o','n',0};
659 WCHAR start_label
[50];
660 SIZE start_text_size
;
662 wine_notify_icon
= (void *)GetProcAddress( graphics_driver
, "wine_notify_icon" );
664 icon_cx
= GetSystemMetrics( SM_CXSMICON
) + 2*ICON_BORDER
;
665 icon_cy
= GetSystemMetrics( SM_CYSMICON
) + 2*ICON_BORDER
;
666 hide_systray
= using_root
;
667 enable_shell
= arg_enable_shell
;
669 /* register the systray listener window class */
670 ZeroMemory(&class, sizeof(class));
671 class.cbSize
= sizeof(class);
672 class.style
= CS_DBLCLKS
| CS_HREDRAW
;
673 class.lpfnWndProc
= tray_wndproc
;
674 class.hInstance
= NULL
;
675 class.hIcon
= LoadIconW(0, (LPCWSTR
)IDI_WINLOGO
);
676 class.hCursor
= LoadCursorW(0, (LPCWSTR
)IDC_ARROW
);
677 class.hbrBackground
= (HBRUSH
) COLOR_WINDOW
;
678 class.lpszClassName
= classname
;
680 if (!RegisterClassExW(&class))
682 WINE_ERR("Could not register SysTray window class\n");
686 tray_width
= GetSystemMetrics( SM_CXSCREEN
);
687 tray_window
= CreateWindowExW( WS_EX_NOACTIVATE
, classname
, NULL
, WS_POPUP
,
688 0, GetSystemMetrics( SM_CYSCREEN
) - icon_cy
,
689 tray_width
, icon_cy
, 0, 0, 0, 0 );
692 WINE_ERR("Could not create tray window\n");
696 LoadStringW( NULL
, IDS_START_LABEL
, start_label
, sizeof(start_label
)/sizeof(WCHAR
) );
698 get_system_text_size( start_label
, &start_text_size
);
700 start_button
= CreateWindowW( button_class
, start_label
, WS_CHILD
|WS_VISIBLE
|BS_PUSHBUTTON
,
701 0, 0, start_text_size
.cx
+ 8, icon_cy
, tray_window
, 0, 0, 0 );
703 if (enable_shell
&& !hide_systray
) ShowWindow( tray_window
, SW_SHOWNA
);
705 if (hide_systray
) do_hide_systray();