wined3d: Use a separate STATE_VDECL state handler in the GLSL pipeline.
[wine/multimedia.git] / dlls / winemac.drv / systray.c
blob6bae0eda1d14e7721b959711552da0f5ad240ef4
1 /*
2 * Mac driver system tray management
4 * Copyright (C) 2004 Mike Hearn, for CodeWeavers
5 * Copyright (C) 2005 Robert Shearman
6 * Copyright (C) 2008 Alexandre Julliard
7 * Copyright (C) 2012, 2013 Ken Thomases for CodeWeavers Inc.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
26 #include "macdrv.h"
28 #include "windef.h"
29 #include "winuser.h"
30 #include "shellapi.h"
32 #include "wine/list.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(systray);
38 #define CHECK_SYSTRAY_TIMER 1
39 #define CHECK_SYSTRAY_INTERVAL_MS 2000
42 /* an individual systray icon */
43 struct tray_icon
45 struct list entry;
46 HWND owner; /* the HWND passed in to the Shell_NotifyIcon call */
47 UINT id; /* the unique id given by the app */
48 UINT callback_message;
49 HICON image; /* the image to render */
50 WCHAR tiptext[128]; /* tooltip text */
51 DWORD state; /* state flags */
52 macdrv_status_item status_item;
55 static struct list icon_list = LIST_INIT(icon_list);
58 static BOOL delete_icon(struct tray_icon *icon);
61 /***********************************************************************
62 * check_icons
64 * Timer procedure for periodically checking that the systray icons are
65 * still valid (their owning windows still exist).
67 static VOID CALLBACK check_icons(HWND hwnd, UINT msg, UINT_PTR timer, DWORD time)
69 struct tray_icon *icon, *next;
71 LIST_FOR_EACH_ENTRY_SAFE(icon, next, &icon_list, struct tray_icon, entry)
72 if (!IsWindow(icon->owner)) delete_icon(icon);
76 /***********************************************************************
77 * setup_check_icons_timer
79 * Set up a window with a timer to check that tray icons are still valid
80 * (their owning windows still exist).
82 static void setup_check_icons_timer(void)
84 static BOOL done;
86 if (!done)
88 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
89 HWND timer_window;
91 /* Whether we succeed or not, don't try again. */
92 done = TRUE;
94 timer_window = CreateWindowW(messageW, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE,
95 NULL, NULL, NULL);
96 if (!timer_window)
98 WARN("Could not create systray checking message window\n");
99 return;
102 if (!SetTimer(timer_window, CHECK_SYSTRAY_TIMER, CHECK_SYSTRAY_INTERVAL_MS, check_icons))
103 WARN("Could not create systray checking timer\n");
108 /***********************************************************************
109 * get_icon
111 * Retrieves an icon record by owner window and ID.
113 static struct tray_icon *get_icon(HWND owner, UINT id)
115 struct tray_icon *this;
117 LIST_FOR_EACH_ENTRY(this, &icon_list, struct tray_icon, entry)
118 if ((this->id == id) && (this->owner == owner)) return this;
119 return NULL;
123 /***********************************************************************
124 * modify_icon
126 * Modifies an existing tray icon and updates its status item as needed.
128 static BOOL modify_icon(struct tray_icon *icon, NOTIFYICONDATAW *nid)
130 BOOL update_image = FALSE, update_tooltip = FALSE;
132 TRACE("hwnd %p id 0x%x flags %x\n", nid->hWnd, nid->uID, nid->uFlags);
134 if (nid->uFlags & NIF_STATE)
136 DWORD changed = (icon->state ^ nid->dwState) & nid->dwStateMask;
137 icon->state = (icon->state & ~nid->dwStateMask) | (nid->dwState & nid->dwStateMask);
138 if (changed & NIS_HIDDEN)
140 if (icon->state & NIS_HIDDEN)
142 if (icon->status_item)
144 TRACE("destroying status item %p\n", icon->status_item);
145 macdrv_destroy_status_item(icon->status_item);
146 icon->status_item = NULL;
149 else
151 if (!icon->status_item)
153 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
155 icon->status_item = macdrv_create_status_item(thread_data->queue);
156 if (icon->status_item)
158 TRACE("created status item %p\n", icon->status_item);
160 if (icon->image)
161 update_image = TRUE;
162 if (lstrlenW(icon->tiptext))
163 update_tooltip = TRUE;
165 else
166 WARN("failed to create status item\n");
172 if (nid->uFlags & NIF_ICON)
174 if (icon->image) DestroyIcon(icon->image);
175 icon->image = CopyIcon(nid->hIcon);
176 if (icon->status_item)
177 update_image = TRUE;
180 if (nid->uFlags & NIF_MESSAGE)
182 icon->callback_message = nid->uCallbackMessage;
184 if (nid->uFlags & NIF_TIP)
186 lstrcpynW(icon->tiptext, nid->szTip, sizeof(icon->tiptext)/sizeof(WCHAR));
187 if (icon->status_item)
188 update_tooltip = TRUE;
191 if (update_image)
193 CGImageRef cgimage = NULL;
194 if (icon->image)
195 cgimage = create_cgimage_from_icon(icon->image, 0, 0);
196 macdrv_set_status_item_image(icon->status_item, cgimage);
197 CGImageRelease(cgimage);
200 if (update_tooltip)
202 CFStringRef s;
204 TRACE("setting tooltip text for status item %p to %s\n", icon->status_item,
205 debugstr_w(icon->tiptext));
206 s = CFStringCreateWithCharacters(NULL, (UniChar*)icon->tiptext,
207 lstrlenW(icon->tiptext));
208 macdrv_set_status_item_tooltip(icon->status_item, s);
209 CFRelease(s);
212 return TRUE;
216 /***********************************************************************
217 * add_icon
219 * Creates a new tray icon structure and adds it to the list.
221 static BOOL add_icon(NOTIFYICONDATAW *nid)
223 NOTIFYICONDATAW new_nid;
224 struct tray_icon *icon;
226 TRACE("hwnd %p id 0x%x\n", nid->hWnd, nid->uID);
228 if ((icon = get_icon(nid->hWnd, nid->uID)))
230 WARN("duplicate tray icon add, buggy app?\n");
231 return FALSE;
234 setup_check_icons_timer();
236 if (!(icon = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*icon))))
238 ERR("out of memory\n");
239 return FALSE;
242 icon->id = nid->uID;
243 icon->owner = nid->hWnd;
244 icon->state = NIS_HIDDEN;
246 list_add_tail(&icon_list, &icon->entry);
248 if (!(nid->uFlags & NIF_STATE) || !(nid->dwStateMask & NIS_HIDDEN))
250 new_nid = *nid;
251 new_nid.uFlags |= NIF_STATE;
252 new_nid.dwState &= ~NIS_HIDDEN;
253 new_nid.dwStateMask |= NIS_HIDDEN;
254 nid = &new_nid;
256 return modify_icon(icon, nid);
260 /***********************************************************************
261 * delete_icon
263 * Destroy tray icon status item and delete structure.
265 static BOOL delete_icon(struct tray_icon *icon)
267 TRACE("hwnd %p id 0x%x\n", icon->owner, icon->id);
269 if (icon->status_item)
271 TRACE("destroying status item %p\n", icon->status_item);
272 macdrv_destroy_status_item(icon->status_item);
274 list_remove(&icon->entry);
275 DestroyIcon(icon->image);
276 HeapFree(GetProcessHeap(), 0, icon);
277 return TRUE;
281 /***********************************************************************
282 * wine_notify_icon (MACDRV.@)
284 * Driver-side implementation of Shell_NotifyIcon.
286 int CDECL wine_notify_icon(DWORD msg, NOTIFYICONDATAW *data)
288 BOOL ret = FALSE;
289 struct tray_icon *icon;
291 switch (msg)
293 case NIM_ADD:
294 ret = add_icon(data);
295 break;
296 case NIM_DELETE:
297 if ((icon = get_icon(data->hWnd, data->uID))) ret = delete_icon(icon);
298 break;
299 case NIM_MODIFY:
300 if ((icon = get_icon(data->hWnd, data->uID))) ret = modify_icon(icon, data);
301 break;
302 default:
303 FIXME("unhandled tray message: %u\n", msg);
304 break;
306 return ret;
310 /***********************************************************************
311 * macdrv_status_item_mouse_button
313 * Handle STATUS_ITEM_MOUSE_BUTTON events.
315 void macdrv_status_item_mouse_button(const macdrv_event *event)
317 struct tray_icon *icon;
319 TRACE("item %p button %d down %d count %d\n", event->status_item_mouse_button.item,
320 event->status_item_mouse_button.button, event->status_item_mouse_button.down,
321 event->status_item_mouse_button.count);
323 LIST_FOR_EACH_ENTRY(icon, &icon_list, struct tray_icon, entry)
325 if (icon->status_item == event->status_item_mouse_button.item)
327 UINT msg;
329 switch (event->status_item_mouse_button.button)
331 case 0: msg = WM_LBUTTONDOWN; break;
332 case 1: msg = WM_RBUTTONDOWN; break;
333 case 2: msg = WM_MBUTTONDOWN; break;
334 default:
335 TRACE("ignoring button beyond the third\n");
336 return;
339 if (!event->status_item_mouse_button.down)
340 msg += WM_LBUTTONUP - WM_LBUTTONDOWN;
341 else if (event->status_item_mouse_button.count % 2 == 0)
342 msg += WM_LBUTTONDBLCLK - WM_LBUTTONDOWN;
344 if (!SendMessageW(icon->owner, WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS, 0, 0) &&
345 GetLastError() == ERROR_INVALID_WINDOW_HANDLE)
347 WARN("window %p was destroyed, removing icon 0x%x\n", icon->owner, icon->id);
348 delete_icon(icon);
349 return;
352 TRACE("posting msg 0x%04x to hwnd %p id 0x%x\n", msg, icon->owner, icon->id);
353 if (!PostMessageW(icon->owner, icon->callback_message, icon->id, msg) &&
354 GetLastError() == ERROR_INVALID_WINDOW_HANDLE)
356 WARN("window %p was destroyed, removing icon 0x%x\n", icon->owner, icon->id);
357 delete_icon(icon);
358 return;
361 break;
367 /***********************************************************************
368 * macdrv_status_item_mouse_move
370 * Handle STATUS_ITEM_MOUSE_MOVE events.
372 void macdrv_status_item_mouse_move(const macdrv_event *event)
374 struct tray_icon *icon;
376 TRACE("item %p\n", event->status_item_mouse_move.item);
378 LIST_FOR_EACH_ENTRY(icon, &icon_list, struct tray_icon, entry)
380 if (icon->status_item == event->status_item_mouse_move.item)
382 if (!PostMessageW(icon->owner, icon->callback_message, icon->id, WM_MOUSEMOVE) &&
383 GetLastError() == ERROR_INVALID_WINDOW_HANDLE)
385 WARN("window %p was destroyed, removing icon 0x%x\n", icon->owner, icon->id);
386 delete_icon(icon);
387 return;
390 break;