1 | /*
|
---|
2 | * Systray
|
---|
3 | *
|
---|
4 | * Copyright 1999 Kai Morich <kai.morich@bigfoot.de>
|
---|
5 | *
|
---|
6 | * Manage the systray window. That it actually appears in the docking
|
---|
7 | * area of KDE or GNOME is delegated to windows/x11drv/wnd.c,
|
---|
8 | * X11DRV_WND_DockWindow.
|
---|
9 | *
|
---|
10 | * Modified by ErOs2 and Dmitriy Kuminov for usage with systray_os2.c
|
---|
11 | *
|
---|
12 | */
|
---|
13 |
|
---|
14 | #ifndef __WIN32OS2__
|
---|
15 | #include <unistd.h>
|
---|
16 | #endif
|
---|
17 | #include <stdlib.h>
|
---|
18 | #include <string.h>
|
---|
19 |
|
---|
20 | #include "winnls.h"
|
---|
21 | #include "shlobj.h"
|
---|
22 | #include "shellapi.h"
|
---|
23 | #include "shell32_main.h"
|
---|
24 | #include "commctrl.h"
|
---|
25 | #include "debugtools.h"
|
---|
26 | #include "heap.h"
|
---|
27 | #include "config.h"
|
---|
28 | #include "winuser32.h"
|
---|
29 |
|
---|
30 | #include "systray.h"
|
---|
31 |
|
---|
32 | DEFAULT_DEBUG_CHANNEL(shell);
|
---|
33 |
|
---|
34 |
|
---|
35 | struct _SystrayItem {
|
---|
36 | HWND hWnd;
|
---|
37 | HWND hWndToolTip;
|
---|
38 | NOTIFYICONDATAA notifyIcon;
|
---|
39 | UINT uIdx;
|
---|
40 | struct _SystrayItem *nextTrayItem;
|
---|
41 | };
|
---|
42 |
|
---|
43 | static SystrayItem *systray = NULL;
|
---|
44 |
|
---|
45 | BOOL (*SYSTRAY_ItemInit)(SystrayItem *ptrayItem) = 0;
|
---|
46 | void (*SYSTRAY_ItemTerm)(SystrayItem *ptrayItem) = 0;
|
---|
47 | void (*SYSTRAY_ItemUpdate)(SystrayItem *ptrayItem, ULONG uFlags) = 0;
|
---|
48 |
|
---|
49 | static BOOL SYSTRAY_ItemIsEqual(PNOTIFYICONDATAA pnid1, PNOTIFYICONDATAA pnid2)
|
---|
50 | {
|
---|
51 | if (pnid1->hWnd != pnid2->hWnd) return FALSE;
|
---|
52 | if (pnid1->uID != pnid2->uID) return FALSE;
|
---|
53 | return TRUE;
|
---|
54 | }
|
---|
55 |
|
---|
56 | static BOOL SYSTRAY_Add(PNOTIFYICONDATAA pnid)
|
---|
57 | {
|
---|
58 | SystrayItem *pItem = systray, *pPrevItem = NULL, *ptrayItem;
|
---|
59 | ULONG uIdx = 0;
|
---|
60 |
|
---|
61 | /* Search for the first free index and also check if already in list */
|
---|
62 | while (pItem)
|
---|
63 | {
|
---|
64 | if (SYSTRAY_ItemIsEqual(pnid, &pItem->notifyIcon))
|
---|
65 | return FALSE;
|
---|
66 |
|
---|
67 | uIdx = pPrevItem->uIdx + 1;
|
---|
68 |
|
---|
69 | if (pPrevItem && pItem->uIdx - pPrevItem->uIdx > 1)
|
---|
70 | {
|
---|
71 | /* found a hole in the index row, will insert here */
|
---|
72 | break;
|
---|
73 | }
|
---|
74 |
|
---|
75 | pPrevItem = pItem;
|
---|
76 | pItem = pItem->nextTrayItem;
|
---|
77 | }
|
---|
78 |
|
---|
79 | /* check the rest (if any) for duplicates */
|
---|
80 | ptrayItem = pItem;
|
---|
81 | while (ptrayItem)
|
---|
82 | {
|
---|
83 | if (SYSTRAY_ItemIsEqual(pnid, &ptrayItem->notifyIcon))
|
---|
84 | return FALSE;
|
---|
85 | ptrayItem = ptrayItem->nextTrayItem;
|
---|
86 | }
|
---|
87 |
|
---|
88 | /* Allocate SystrayItem for the new element and insert it */
|
---|
89 | ptrayItem = ( SystrayItem *)malloc(sizeof(SystrayItem));
|
---|
90 | memset(ptrayItem, 0, sizeof(SystrayItem));
|
---|
91 | ptrayItem->nextTrayItem = pItem;
|
---|
92 |
|
---|
93 | if (pPrevItem)
|
---|
94 | {
|
---|
95 | pPrevItem->nextTrayItem = ptrayItem;
|
---|
96 | ptrayItem->uIdx = pPrevItem->uIdx + 1;
|
---|
97 | }
|
---|
98 | else
|
---|
99 | {
|
---|
100 | systray = ptrayItem;
|
---|
101 | ptrayItem->uIdx = 0;
|
---|
102 | }
|
---|
103 |
|
---|
104 | /* Initialize and set data for the tray element. */
|
---|
105 | ptrayItem->uIdx = uIdx;
|
---|
106 |
|
---|
107 | ptrayItem->notifyIcon.uID = pnid->uID;
|
---|
108 | ptrayItem->notifyIcon.hWnd = pnid->hWnd;
|
---|
109 |
|
---|
110 | ptrayItem->notifyIcon.hIcon =
|
---|
111 | (pnid->uFlags & NIF_ICON) ? GetOS2Icon(pnid->hIcon) : 0;
|
---|
112 | ptrayItem->notifyIcon.uCallbackMessage =
|
---|
113 | (pnid->uFlags & NIF_MESSAGE) ? pnid->uCallbackMessage : 0;
|
---|
114 |
|
---|
115 | if (pnid->uFlags & NIF_TIP)
|
---|
116 | CharToOemA(pnid->szTip, ptrayItem->notifyIcon.szTip);
|
---|
117 | else
|
---|
118 | ptrayItem->notifyIcon.szTip[0] = '\0';
|
---|
119 |
|
---|
120 | /* Implementation specific initialization */
|
---|
121 | if (!SYSTRAY_ItemInit(ptrayItem))
|
---|
122 | {
|
---|
123 | free(ptrayItem);
|
---|
124 | if (pPrevItem)
|
---|
125 | pPrevItem->nextTrayItem = pItem;
|
---|
126 | else
|
---|
127 | systray = NULL;
|
---|
128 | return FALSE;
|
---|
129 | }
|
---|
130 |
|
---|
131 | /* Trigger the data update (flags = 0 means it's the first time) */
|
---|
132 | SYSTRAY_ItemUpdate(ptrayItem, 0);
|
---|
133 |
|
---|
134 | TRACE("SYSTRAY_Add %p: uIdx %u, hWnd 0x%08x, uID %d, hIcon 0x%08x, "
|
---|
135 | "uCallbackMessage 0x%08x, szTip [%s]\n",
|
---|
136 | ptrayItem, ptrayItem->uIdx, ptrayItem->hWnd, ptrayItem->notifyIcon.uID,
|
---|
137 | ptrayItem->notifyIcon.hIcon,ptrayItem->notifyIcon.uCallbackMessage,
|
---|
138 | ptrayItem->notifyIcon.szTip);
|
---|
139 |
|
---|
140 | return TRUE;
|
---|
141 | }
|
---|
142 |
|
---|
143 | static BOOL SYSTRAY_Modify(PNOTIFYICONDATAA pnid)
|
---|
144 | {
|
---|
145 | SystrayItem *ptrayItem = systray;
|
---|
146 |
|
---|
147 | while (ptrayItem)
|
---|
148 | {
|
---|
149 | if (SYSTRAY_ItemIsEqual(pnid, &ptrayItem->notifyIcon))
|
---|
150 | {
|
---|
151 | if (pnid->uFlags & NIF_ICON)
|
---|
152 | ptrayItem->notifyIcon.hIcon = GetOS2Icon(pnid->hIcon);
|
---|
153 | if (pnid->uFlags & NIF_MESSAGE)
|
---|
154 | ptrayItem->notifyIcon.uCallbackMessage = pnid->uCallbackMessage;
|
---|
155 | if (pnid->uFlags & NIF_TIP)
|
---|
156 | CharToOemA(pnid->szTip, ptrayItem->notifyIcon.szTip);
|
---|
157 |
|
---|
158 | SYSTRAY_ItemUpdate(ptrayItem, pnid->uFlags);
|
---|
159 |
|
---|
160 | TRACE("SYSTRAY_Modify %p: uIdx %u, hWnd 0x%08x, uID %d, hIcon 0x%08x, "
|
---|
161 | "uCallbackMessage 0x%08x, szTip [%s]\n",
|
---|
162 | ptrayItem, ptrayItem->uIdx, ptrayItem->hWnd, ptrayItem->notifyIcon.uID,
|
---|
163 | ptrayItem->notifyIcon.hIcon,ptrayItem->notifyIcon.uCallbackMessage,
|
---|
164 | ptrayItem->notifyIcon.szTip);
|
---|
165 |
|
---|
166 | return TRUE;
|
---|
167 | }
|
---|
168 | ptrayItem = ptrayItem->nextTrayItem;
|
---|
169 | }
|
---|
170 |
|
---|
171 | return FALSE; /* not found */
|
---|
172 | }
|
---|
173 |
|
---|
174 | static BOOL SYSTRAY_Delete(PNOTIFYICONDATAA pnid)
|
---|
175 | {
|
---|
176 | SystrayItem **ptrayItem = &systray;
|
---|
177 |
|
---|
178 | while (*ptrayItem)
|
---|
179 | {
|
---|
180 | if (SYSTRAY_ItemIsEqual(pnid, &(*ptrayItem)->notifyIcon))
|
---|
181 | {
|
---|
182 | SystrayItem *next = (*ptrayItem)->nextTrayItem;
|
---|
183 |
|
---|
184 | TRACE("SYSTRAY_Delete %p: uIdx %u, hWnd 0x%08x, uID %d\n",
|
---|
185 | *ptrayItem, (*ptrayItem)->uIdx, (*ptrayItem)->notifyIcon.hWnd,
|
---|
186 | (*ptrayItem)->notifyIcon.uID);
|
---|
187 |
|
---|
188 | SYSTRAY_ItemTerm(*ptrayItem);
|
---|
189 |
|
---|
190 | free(*ptrayItem);
|
---|
191 | *ptrayItem = next;
|
---|
192 |
|
---|
193 | return TRUE;
|
---|
194 | }
|
---|
195 | ptrayItem = &((*ptrayItem)->nextTrayItem);
|
---|
196 | }
|
---|
197 |
|
---|
198 | return FALSE; /* not found */
|
---|
199 | }
|
---|
200 |
|
---|
201 | #ifndef __WIN32OS2__
|
---|
202 | /*************************************************************************
|
---|
203 | *
|
---|
204 | */
|
---|
205 | BOOL SYSTRAY_Init(void)
|
---|
206 | {
|
---|
207 | return TRUE;
|
---|
208 | }
|
---|
209 | #endif
|
---|
210 |
|
---|
211 | /*************************************************************************
|
---|
212 | *
|
---|
213 | */
|
---|
214 | SystrayItem *SYSTRAY_FindItem(ULONG uIdx)
|
---|
215 | {
|
---|
216 | SystrayItem *ptrayItem = systray;
|
---|
217 |
|
---|
218 | while (ptrayItem)
|
---|
219 | {
|
---|
220 | if (ptrayItem->uIdx == uIdx)
|
---|
221 | return ptrayItem;
|
---|
222 |
|
---|
223 | ptrayItem = ptrayItem->nextTrayItem;
|
---|
224 | }
|
---|
225 |
|
---|
226 | return NULL; /* not found */
|
---|
227 | }
|
---|
228 |
|
---|
229 | /*************************************************************************
|
---|
230 | * Shell_NotifyIconA [SHELL32.297][SHELL32.296]
|
---|
231 | */
|
---|
232 | BOOL WINAPI Shell_NotifyIconA(DWORD dwMessage, PNOTIFYICONDATAA pnid )
|
---|
233 | {
|
---|
234 | BOOL flag = FALSE;
|
---|
235 | switch(dwMessage)
|
---|
236 | {
|
---|
237 | case NIM_ADD:
|
---|
238 | flag = SYSTRAY_Add(pnid);
|
---|
239 | break;
|
---|
240 | case NIM_MODIFY:
|
---|
241 | flag = SYSTRAY_Modify(pnid);
|
---|
242 | break;
|
---|
243 | case NIM_DELETE:
|
---|
244 | flag = SYSTRAY_Delete(pnid);
|
---|
245 | break;
|
---|
246 | }
|
---|
247 | return flag;
|
---|
248 | }
|
---|
249 |
|
---|
250 | /*************************************************************************
|
---|
251 | * Shell_NotifyIconW [SHELL32.298]
|
---|
252 | */
|
---|
253 | BOOL WINAPI Shell_NotifyIconW (DWORD dwMessage, PNOTIFYICONDATAW pnid )
|
---|
254 | {
|
---|
255 | BOOL ret;
|
---|
256 |
|
---|
257 | PNOTIFYICONDATAA p = HeapAlloc(GetProcessHeap(),0,sizeof(NOTIFYICONDATAA));
|
---|
258 | memcpy(p, pnid, sizeof(NOTIFYICONDATAA));
|
---|
259 | WideCharToMultiByte( CP_ACP, 0, pnid->szTip, -1, p->szTip, sizeof(p->szTip), NULL, NULL );
|
---|
260 | p->szTip[sizeof(p->szTip)-1] = 0;
|
---|
261 |
|
---|
262 | ret = Shell_NotifyIconA(dwMessage, p );
|
---|
263 |
|
---|
264 | HeapFree(GetProcessHeap(),0,p);
|
---|
265 | return ret;
|
---|
266 | }
|
---|
267 |
|
---|
268 |
|
---|
269 | #ifdef __WIN32OS2__
|
---|
270 |
|
---|
271 | BOOL DoWin32PostMessage(HWND w, ULONG m, WPARAM mp1, LPARAM mp2 )
|
---|
272 | {
|
---|
273 | TRACE("DoWin32WinPostMsg: HWND 0x%08x MSG 0x%08x ID 0x%08x MMSG 0x%08x\n", w, m, mp1, mp2);
|
---|
274 | if ( w && m )
|
---|
275 | {
|
---|
276 | return PostMessageA( w, m, mp1, mp2 );
|
---|
277 | }
|
---|
278 | return FALSE;
|
---|
279 | }
|
---|
280 |
|
---|
281 | #endif
|
---|