source: trunk/src/shell32/systray.cpp@ 3665

Last change on this file since 3665 was 3665, checked in by sandervl, 25 years ago

disabled system tray

File size: 14.1 KB
Line 
1/* $Id: systray.cpp,v 1.4 2000-06-07 21:47:36 sandervl Exp $ */
2/*
3 * Systray
4 *
5 * Copyright 2000 Christoph Bratschi (cbratschi@datacomm.ch)
6 *
7 * Copyright 1999 Kai Morich <kai.morich@bigfoot.de>
8 *
9 * Manage the systray window. That it actually appears in the docking
10 * area of KDE or GNOME is delegated to windows/x11drv/wnd.c,
11 * X11DRV_WND_DockWindow.
12 *
13 */
14
15//#include <unistd.h>
16#include <stdlib.h>
17#include <string.h>
18
19#define ICOM_CINTERFACE 1
20#define CINTERFACE 1
21
22#include "shellapi.h"
23#include "shell32_main.h"
24#include "windows.h"
25#include "commctrl.h"
26#include "debugtools.h"
27#include "config.h"
28#include "heapstring.h"
29#include "winversion.h"
30
31DEFAULT_DEBUG_CHANNEL(shell)
32
33typedef struct SystrayData {
34 HWND hWnd;
35 HWND hWndToolTip;
36 NOTIFYICONDATAW notifyIcon;
37 int nitem; /* number of current element = tooltip id */
38 struct SystrayData *nextTrayItem;
39} SystrayData;
40
41typedef struct Systray {
42 int hasCritSection;
43 CRITICAL_SECTION critSection;
44 SystrayData *systrayItemList;
45} Systray;
46
47static Systray systray;
48static int nNumberTrayElements;
49
50#define SYSTRAY_CLASS "OdinSysTray"
51
52static BOOL SYSTRAY_Delete(PNOTIFYICONDATAW pnid,BOOL unicode);
53
54
55/**************************************************************************
56* internal systray
57*
58*/
59
60#define SMALL_ICON_SIZE GetSystemMetrics(SM_CXSMICON)
61
62/* space between icons and frame */
63#define IBORDER 3
64#define OBORDER 2
65#define TBORDER (OBORDER+1+IBORDER)
66
67static LRESULT CALLBACK SYSTRAY_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
68{
69 HDC hdc;
70 PAINTSTRUCT ps;
71
72 switch (message) {
73 case WM_PAINT:
74 {
75 RECT rc;
76 SystrayData *ptrayItem = systray.systrayItemList;
77
78 while (ptrayItem)
79 {
80 if (ptrayItem->hWnd == hWnd)
81 {
82 hdc = BeginPaint(hWnd, &ps);
83 GetClientRect(hWnd, &rc);
84
85 if (!DrawIconEx(hdc, rc.left, rc.top, ptrayItem->notifyIcon.hIcon,
86 SMALL_ICON_SIZE, SMALL_ICON_SIZE, 0, 0, DI_DEFAULTSIZE|DI_NORMAL))
87 SYSTRAY_Delete(&ptrayItem->notifyIcon,TRUE);
88 }
89 ptrayItem = ptrayItem->nextTrayItem;
90 }
91 EndPaint(hWnd, &ps);
92 }
93 break;
94
95 case WM_MOUSEMOVE:
96 case WM_LBUTTONDOWN:
97 case WM_LBUTTONUP:
98 case WM_RBUTTONDOWN:
99 case WM_RBUTTONUP:
100 case WM_MBUTTONDOWN:
101 case WM_MBUTTONUP:
102 {
103 MSG msg;
104 SystrayData *ptrayItem = systray.systrayItemList;
105
106 while ( ptrayItem )
107 {
108 if (ptrayItem->hWnd == hWnd)
109 {
110 msg.hwnd=hWnd;
111 msg.message=message;
112 msg.wParam=wParam;
113 msg.lParam=lParam;
114 msg.time = GetMessageTime ();
115 msg.pt.x = LOWORD(GetMessagePos ());
116 msg.pt.y = HIWORD(GetMessagePos ());
117
118 SendMessageA(ptrayItem->hWndToolTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
119 }
120 ptrayItem = ptrayItem->nextTrayItem;
121 }
122 }
123
124 case WM_LBUTTONDBLCLK:
125 case WM_RBUTTONDBLCLK:
126 case WM_MBUTTONDBLCLK:
127 {
128 int xPos;
129 SystrayData *ptrayItem = systray.systrayItemList;
130
131 while (ptrayItem)
132 {
133 if (ptrayItem->hWnd == hWnd)
134 {
135 xPos = LOWORD(lParam);
136 if( (xPos >= TBORDER) &&
137 (xPos < (TBORDER+SMALL_ICON_SIZE)) )
138 {
139 if (!PostMessageA(ptrayItem->notifyIcon.hWnd, ptrayItem->notifyIcon.uCallbackMessage,
140 (WPARAM)ptrayItem->notifyIcon.uID, (LPARAM)message))
141 SYSTRAY_Delete(&ptrayItem->notifyIcon,TRUE);
142 break;
143 }
144 }
145 ptrayItem = ptrayItem->nextTrayItem;
146 }
147 }
148 break;
149
150 default:
151 return (DefWindowProcA(hWnd, message, wParam, lParam));
152 }
153 return (0);
154
155}
156
157BOOL SYSTRAY_RegisterClass(void)
158{
159 WNDCLASSA wc;
160
161 wc.style = CS_SAVEBITS;
162 wc.lpfnWndProc = (WNDPROC)SYSTRAY_WndProc;
163 wc.cbClsExtra = 0;
164 wc.cbWndExtra = 0;
165 wc.hInstance = 0;
166 wc.hIcon = 0; /* LoadIcon (NULL, IDI_EXCLAMATION); */
167 wc.hCursor = LoadCursorA(0, IDC_ARROWA);
168 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
169 wc.lpszMenuName = NULL;
170 wc.lpszClassName = SYSTRAY_CLASS;
171
172 if (!RegisterClassA(&wc)) {
173 ERR("RegisterClass(WineSystray) failed\n");
174 return FALSE;
175 }
176 return TRUE;
177}
178
179
180BOOL SYSTRAY_Create(SystrayData *ptrayItem)
181{
182 RECT rect;
183
184 /* Register the class if this is our first tray item. */
185 if ( nNumberTrayElements == 1 )
186 {
187 if ( !SYSTRAY_RegisterClass() )
188 {
189 ERR( "RegisterClass(WineSystray) failed\n" );
190 return FALSE;
191 }
192 }
193
194 /* Initialize the window size. */
195 rect.left = 0;
196 rect.top = 0;
197 rect.right = SMALL_ICON_SIZE+2*TBORDER;
198 rect.bottom = SMALL_ICON_SIZE+2*TBORDER;
199
200#if 1
201 //SvL: Disabled system tray for now
202 // Integrate with OS/2 WPS (WarpCenter tray?)
203 return FALSE;
204#else
205 /* Create tray window for icon. */
206 ptrayItem->hWnd = CreateWindowExA( WS_EX_TRAYWINDOW,
207 SYSTRAY_CLASS, "Odin-Systray",
208 WS_VISIBLE | WS_POPUP,
209 CW_USEDEFAULT, CW_USEDEFAULT,
210 rect.right-rect.left, rect.bottom-rect.top,
211 0, 0, 0, 0 );
212 if ( !ptrayItem->hWnd )
213 {
214 ERR( "CreateWindow(OdinSystray) failed\n" );
215 return FALSE;
216 }
217#endif
218
219 /* Create tooltip for icon. */
220 ptrayItem->hWndToolTip = CreateWindowA( TOOLTIPS_CLASSA,NULL,TTS_ALWAYSTIP,
221 CW_USEDEFAULT, CW_USEDEFAULT,
222 CW_USEDEFAULT, CW_USEDEFAULT,
223 ptrayItem->hWnd, 0, 0, 0 );
224 if ( ptrayItem->hWndToolTip==0 )
225 {
226 ERR( "CreateWindow(TOOLTIP) failed\n" );
227 return FALSE;
228 }
229 return TRUE;
230}
231
232static void SYSTRAY_RepaintAll(void)
233{
234 SystrayData *ptrayItem = systray.systrayItemList;
235
236 while(ptrayItem)
237 {
238 InvalidateRect(ptrayItem->hWnd, NULL, TRUE);
239 ptrayItem = ptrayItem->nextTrayItem;
240 }
241
242}
243
244static void SYSTRAY_RepaintItem(int nitem)
245{
246
247 SystrayData *ptrayItem = systray.systrayItemList;
248
249 while(ptrayItem)
250 {
251 if (ptrayItem->nitem == nitem)
252 InvalidateRect(ptrayItem->hWnd, NULL, TRUE);
253
254 ptrayItem = ptrayItem->nextTrayItem;
255 }
256}
257
258void SYSTRAY_InitItem(SystrayData *ptrayItem)
259{
260 ptrayItem->nitem = nNumberTrayElements++;
261 SYSTRAY_Create(ptrayItem);
262}
263
264void SYSTRAY_SetIcon(SystrayData *ptrayItem, HICON hIcon)
265{
266 ptrayItem->notifyIcon.hIcon = hIcon;
267}
268
269void SYSTRAY_SetTip(SystrayData *ptrayItem,WCHAR* szTip,BOOL unicode)
270{
271 TTTOOLINFOW ti;
272
273 if (unicode)
274 lstrcpynW(ptrayItem->notifyIcon.szTip, szTip, sizeof(ptrayItem->notifyIcon.szTip)/sizeof(WCHAR));
275 else
276 lstrcpynAtoW(ptrayItem->notifyIcon.szTip,(LPSTR)szTip,sizeof(ptrayItem->notifyIcon.szTip)/sizeof(WCHAR));
277 ptrayItem->notifyIcon.szTip[sizeof(ptrayItem->notifyIcon.szTip)/sizeof(WCHAR)-1]=0;
278
279 ti.cbSize = sizeof(TTTOOLINFOW);
280 ti.uFlags = 0;
281 ti.hwnd = ptrayItem->hWnd;
282 ti.hinst = 0;
283 ti.uId = ptrayItem->nitem;
284 ti.lpszText = ptrayItem->notifyIcon.szTip;
285 ti.rect.left = 0;
286 ti.rect.top = 0;
287 ti.rect.right = SMALL_ICON_SIZE+2*TBORDER;
288 ti.rect.bottom = SMALL_ICON_SIZE+2*TBORDER;
289
290 SendMessageA(ptrayItem->hWndToolTip, TTM_ADDTOOLW, 0, (LPARAM)&ti);
291}
292
293static void SYSTRAY_ModifyTip(SystrayData *ptrayItem,WCHAR* szTip,BOOL unicode)
294{
295 TTTOOLINFOW ti;
296
297 if (unicode)
298 lstrcpynW(ptrayItem->notifyIcon.szTip, szTip, sizeof(ptrayItem->notifyIcon.szTip)/sizeof(WCHAR));
299 else
300 lstrcpynAtoW(ptrayItem->notifyIcon.szTip,(LPSTR)szTip,sizeof(ptrayItem->notifyIcon.szTip)/sizeof(WCHAR));
301 ptrayItem->notifyIcon.szTip[sizeof(ptrayItem->notifyIcon.szTip)/sizeof(WCHAR)-1]=0;
302
303 ti.cbSize = sizeof(TTTOOLINFOW);
304 ti.uFlags = 0;
305 ti.hwnd = ptrayItem->hWnd;
306 ti.hinst = 0;
307 ti.uId = ptrayItem->nitem;
308 ti.lpszText = ptrayItem->notifyIcon.szTip;
309 ti.rect.left = 0;
310 ti.rect.top = 0;
311 ti.rect.right = SMALL_ICON_SIZE+2*TBORDER;
312 ti.rect.bottom = SMALL_ICON_SIZE+2*TBORDER;
313
314 SendMessageA(ptrayItem->hWndToolTip, TTM_UPDATETIPTEXTW, 0, (LPARAM)&ti);
315}
316
317static void SYSTRAY_TermItem(SystrayData *removeItem)
318{
319 int nitem;
320 SystrayData **trayItem;
321 TTTOOLINFOW ti;
322 ti.cbSize = sizeof(TTTOOLINFOA);
323 ti.uFlags = 0;
324 ti.hinst = 0;
325
326 /* delete all tooltips ...*/
327 trayItem = &systray.systrayItemList;
328 while (*trayItem) {
329 ti.uId = (*trayItem)->nitem;
330 ti.hwnd = (*trayItem)->hWnd;
331 SendMessageA((*trayItem)->hWndToolTip, TTM_DELTOOLW, 0, (LPARAM)&ti);
332 trayItem = &((*trayItem)->nextTrayItem);
333 }
334 /* ... and add them again, because uID may shift */
335 nitem=0;
336 trayItem = &systray.systrayItemList;
337 while (*trayItem)
338 {
339 if (*trayItem != removeItem)
340 {
341 (*trayItem)->nitem = nitem;
342 ti.uId = nitem;
343 ti.hwnd = (*trayItem)->hWnd;
344 ti.lpszText = (*trayItem)->notifyIcon.szTip;
345 ti.rect.left = 0;
346 ti.rect.top = 0;
347 ti.rect.right = SMALL_ICON_SIZE+2*TBORDER;
348 ti.rect.bottom = SMALL_ICON_SIZE+2*TBORDER;
349 SendMessageA((*trayItem)->hWndToolTip, TTM_ADDTOOLW, 0, (LPARAM)&ti);
350 nitem++;
351 }
352 trayItem = &((*trayItem)->nextTrayItem);
353 }
354 nNumberTrayElements--;
355}
356
357
358/**************************************************************************
359* helperfunctions
360*
361*/
362void SYSTRAY_SetMessage(SystrayData *ptrayItem, UINT uCallbackMessage)
363{
364 ptrayItem->notifyIcon.uCallbackMessage = uCallbackMessage;
365}
366
367static BOOL SYSTRAY_IsEqual(PNOTIFYICONDATAW pnid1, PNOTIFYICONDATAW pnid2)
368{
369 if (pnid1->hWnd != pnid2->hWnd) return FALSE;
370 if (pnid1->uID != pnid2->uID) return FALSE;
371 return TRUE;
372}
373
374static BOOL SYSTRAY_Add(PNOTIFYICONDATAW pnid,BOOL unicode)
375{
376 SystrayData **ptrayItem = &systray.systrayItemList;
377
378 /* Find empty space for new element. */
379 while( *ptrayItem )
380 {
381 if ( SYSTRAY_IsEqual(pnid, &(*ptrayItem)->notifyIcon) )
382 return FALSE;
383 ptrayItem = &((*ptrayItem)->nextTrayItem);
384 }
385
386 /* Allocate SystrayData for element and zero memory. */
387 (*ptrayItem) = ( SystrayData *)malloc( sizeof(SystrayData) );
388 ZeroMemory( (*ptrayItem), sizeof(SystrayData) );
389
390 /* Copy notification data */
391 memcpy( &(*ptrayItem)->notifyIcon, pnid, sizeof(NOTIFYICONDATAW) );
392
393 /* Initialize and set data for the tray element. */
394 SYSTRAY_InitItem( (*ptrayItem) );
395
396 SYSTRAY_SetIcon (*ptrayItem, (pnid->uFlags&NIF_ICON) ?pnid->hIcon :0);
397 SYSTRAY_SetMessage(*ptrayItem, (pnid->uFlags&NIF_MESSAGE)?pnid->uCallbackMessage:0);
398 SYSTRAY_SetTip (*ptrayItem, (pnid->uFlags & NIF_TIP) ? ((WCHAR*)pnid->szTip):((WCHAR*)L""),unicode && pnid->szTip);
399
400 (*ptrayItem)->nextTrayItem = NULL; /* may be overkill after the ZeroMemory call. */
401
402 /* Repaint all system tray icons as we have added one. */
403 SYSTRAY_RepaintAll();
404
405 TRACE("%p: 0x%08x %d %s\n", (*ptrayItem), (*ptrayItem)->notifyIcon.hWnd,
406 (*ptrayItem)->notifyIcon.uID,
407 (*ptrayItem)->notifyIcon.szTip);
408 return TRUE;
409}
410
411static BOOL SYSTRAY_Modify(PNOTIFYICONDATAW pnid,BOOL unicode)
412{
413 SystrayData *ptrayItem = systray.systrayItemList;
414
415 while ( ptrayItem )
416 {
417 if ( SYSTRAY_IsEqual(pnid, &ptrayItem->notifyIcon) )
418 {
419 if (pnid->uFlags & NIF_ICON)
420 {
421 SYSTRAY_SetIcon(ptrayItem, pnid->hIcon);
422 SYSTRAY_RepaintItem(ptrayItem->nitem);
423 }
424
425 if (pnid->uFlags & NIF_MESSAGE)
426 SYSTRAY_SetMessage(ptrayItem, pnid->uCallbackMessage);
427
428 if (pnid->uFlags & NIF_TIP)
429 SYSTRAY_ModifyTip(ptrayItem,pnid->szTip,unicode);
430
431 TRACE("%p: 0x%08x %d %s\n", ptrayItem, ptrayItem->notifyIcon.hWnd,
432 ptrayItem->notifyIcon.uID, ptrayItem->notifyIcon.szTip);
433 return TRUE;
434 }
435 ptrayItem = ptrayItem->nextTrayItem;
436 }
437 return FALSE; /* not found */
438}
439
440static BOOL SYSTRAY_Delete(PNOTIFYICONDATAW pnid,BOOL unicode)
441{
442 SystrayData **ptrayItem = &systray.systrayItemList;
443
444 while (*ptrayItem)
445 {
446 if (SYSTRAY_IsEqual(pnid, &(*ptrayItem)->notifyIcon))
447 {
448 SystrayData *next = (*ptrayItem)->nextTrayItem;
449 TRACE("%p: 0x%08x %d %s\n", *ptrayItem, (*ptrayItem)->notifyIcon.hWnd,
450 (*ptrayItem)->notifyIcon.uID, (*ptrayItem)->notifyIcon.szTip);
451 SYSTRAY_TermItem(*ptrayItem);
452
453 DestroyWindow((*ptrayItem)->hWndToolTip);
454 DestroyWindow((*ptrayItem)->hWnd);
455
456 free(*ptrayItem);
457 *ptrayItem = next;
458
459 SYSTRAY_RepaintAll();
460
461 return TRUE;
462 }
463 ptrayItem = &((*ptrayItem)->nextTrayItem);
464 }
465
466 return FALSE; /* not found */
467}
468
469/*************************************************************************
470 *
471 */
472BOOL SYSTRAY_Init(void)
473{
474 if (!systray.hasCritSection)
475 {
476 systray.hasCritSection=1;
477 InitializeCriticalSection(&systray.critSection);
478 MakeCriticalSectionGlobal(&systray.critSection);
479 //RegisterDebugptr(&systray.critSection, "SYSTRAY");
480 TRACE(" =%p\n", &systray.critSection);
481 }
482 return TRUE;
483}
484
485BOOL InternalNotifyIcon(DWORD dwMessage,PNOTIFYICONDATAW pnid,BOOL unicode)
486{
487 BOOL flag=FALSE;
488 TRACE("wait %d %d %ld\n", pnid->hWnd, pnid->uID, dwMessage);
489 /* must be serialized because all apps access same systray */
490 EnterCriticalSection(&systray.critSection);
491 TRACE("enter %d %d %ld\n", pnid->hWnd, pnid->uID, dwMessage);
492
493
494 switch(dwMessage) {
495 case NIM_ADD:
496 TRACE("Calling systray add\n");
497 flag = SYSTRAY_Add(pnid,unicode);
498 break;
499 case NIM_MODIFY:
500 flag = SYSTRAY_Modify(pnid,unicode);
501 break;
502 case NIM_DELETE:
503 flag = SYSTRAY_Delete(pnid,unicode);
504 break;
505 }
506
507 LeaveCriticalSection(&systray.critSection);
508 TRACE("leave %d %d %ld\n", pnid->hWnd, pnid->uID, dwMessage);
509 return flag;
510}
511
512/*************************************************************************
513 * Shell_NotifyIconA [SHELL32.297]
514 */
515ODINFUNCTION2(BOOL,Shell_NotifyIconA,DWORD,dwMessage,PNOTIFYICONDATAA,pnid )
516{
517 return InternalNotifyIcon(dwMessage,(PNOTIFYICONDATAW)pnid,FALSE);
518}
519
520/*************************************************************************
521 * Shell_NotifyIconW [SHELL32.???]
522 */
523ODINFUNCTION2(BOOL,Shell_NotifyIconW,DWORD,dwMessage,PNOTIFYICONDATAW,pnid )
524{
525 return InternalNotifyIcon(dwMessage,pnid,TRUE);
526}
527
528/*************************************************************************
529 * Shell_NotifyIcon [SHELL32.296]
530 */
531ODINFUNCTION2(BOOL,Shell_NotifyIcon,DWORD,dwMessage,PNOTIFYICONDATAW,pnid)
532{
533 return InternalNotifyIcon(dwMessage,pnid,VERSION_OsIsUnicode());
534}
Note: See TracBrowser for help on using the repository browser.