]> git.saurik.com Git - wxWidgets.git/blame - src/osx/cocoa/taskbar.mm
notify the event loop that synthesized events are on the queue, wait for them to...
[wxWidgets.git] / src / osx / cocoa / taskbar.mm
CommitLineData
01250f9b 1/////////////////////////////////////////////////////////////////////////
7ac5e1c9 2// File: src/osx/cocoa/taskbar.mm
01250f9b 3// Purpose: Implements wxTaskBarIcon class
b59cd6c4 4// Author: David Elliott, Stefan Csomor
01250f9b
KO
5// Modified by:
6// Created: 2004/01/24
a9a4f229 7// RCS-ID: $Id$
b59cd6c4 8// Copyright: (c) 2004 David Elliott, Stefan Csomor
01250f9b
KO
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////
11
12#include "wx/wxprec.h"
f1d7af8f 13#if wxUSE_TASKBARICON
01250f9b
KO
14
15#ifndef WX_PRECOMP
127668fc 16 #include "wx/toplevel.h"
01250f9b
KO
17 #include "wx/menu.h"
18 #include "wx/icon.h"
19 #include "wx/log.h"
20 #include "wx/dcclient.h"
21#endif
22
23#include "wx/taskbar.h"
24
7ac5e1c9 25#include "wx/osx/private.h"
01250f9b 26
01250f9b
KO
27class wxTaskBarIconWindow;
28
b59cd6c4
SC
29//-----------------------------------------------------------------------------
30//
31// wxTaskBarIconWindow
32//
33// Event handler for menus
34// NB: Since wxWindows in Mac HAVE to have parents we need this to be
35// a top level window...
36//-----------------------------------------------------------------------------
37
38class wxTaskBarIconWindow : public wxTopLevelWindow
39{
40public:
41 wxTaskBarIconWindow(wxTaskBarIconImpl *impl);
42
43 void OnMenuEvent(wxCommandEvent& event);
44 void OnUpdateUIEvent(wxUpdateUIEvent& event);
45
46private:
47 wxTaskBarIconImpl *m_impl;
48 DECLARE_EVENT_TABLE()
49};
50
01250f9b
KO
51// ============================================================================
52// wxTaskBarIconImpl
53// Base class for the various Cocoa implementations.
54// ============================================================================
55class wxTaskBarIconImpl
56{
57public:
b59cd6c4
SC
58 wxTaskBarIconImpl(wxTaskBarIcon *taskBarIcon);
59
60 virtual bool IsStatusItem() const { return false; }
61
01250f9b
KO
62 virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString) = 0;
63 virtual bool RemoveIcon() = 0;
b59cd6c4 64
a1b806b9 65 bool IsIconInstalled() const { return m_icon.IsOk(); }
b59cd6c4 66
01250f9b
KO
67 virtual bool PopupMenu(wxMenu *menu) = 0;
68 virtual ~wxTaskBarIconImpl();
69 inline wxTaskBarIcon* GetTaskBarIcon() { return m_taskBarIcon; }
70 wxMenu * CreatePopupMenu()
71 { return m_taskBarIcon->CreatePopupMenu(); }
03647350 72
c0c133e1 73 wxDECLARE_NO_COPY_CLASS(wxTaskBarIconImpl);
03647350 74
01250f9b
KO
75protected:
76 wxTaskBarIcon *m_taskBarIcon;
b59cd6c4
SC
77 wxBitmap m_icon;
78 wxTaskBarIconWindow *m_eventWindow;
01250f9b
KO
79private:
80 wxTaskBarIconImpl();
81};
82
83// ============================================================================
84// wxTaskBarIconDockImpl
85// An implementation using the Dock icon.
86// ============================================================================
87class wxTaskBarIconDockImpl: public wxTaskBarIconImpl
88{
89public:
90 wxTaskBarIconDockImpl(wxTaskBarIcon *taskBarIcon);
91 virtual ~wxTaskBarIconDockImpl();
92 virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString);
93 virtual bool RemoveIcon();
94 virtual bool PopupMenu(wxMenu *menu);
95
b59cd6c4 96 static WX_NSMenu OSXGetDockHMenu();
01250f9b 97protected:
b59cd6c4 98 WX_NSMenu OSXDoGetDockHMenu();
01250f9b
KO
99 // There can be only one Dock icon, so make sure we keep it that way
100 static wxTaskBarIconDockImpl *sm_dockIcon;
101private:
102 wxTaskBarIconDockImpl();
b59cd6c4 103 wxMenu *m_pMenu;
01250f9b
KO
104};
105
b59cd6c4
SC
106class wxTaskBarIconCustomStatusItemImpl;
107
108@interface wxOSXStatusItemTarget : NSObject
109{
110 wxTaskBarIconCustomStatusItemImpl* impl;
111}
112@end
113
01250f9b
KO
114// ============================================================================
115// wxTaskBarIconCustomStatusItemImpl
116// An implementation using an NSStatusItem with a custom NSView
117// ============================================================================
118class wxTaskBarIconCustomStatusItemImpl: public wxTaskBarIconImpl
119{
120public:
121 wxTaskBarIconCustomStatusItemImpl(wxTaskBarIcon *taskBarIcon);
122 virtual ~wxTaskBarIconCustomStatusItemImpl();
b59cd6c4
SC
123
124 virtual bool IsStatusItem() const { return true; }
125
01250f9b
KO
126 virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString);
127 virtual bool RemoveIcon();
128 virtual bool PopupMenu(wxMenu *menu);
129protected:
b59cd6c4
SC
130 NSStatusItem *m_statusItem;
131 wxOSXStatusItemTarget *m_target;
01250f9b
KO
132private:
133 wxTaskBarIconCustomStatusItemImpl();
134};
135
01250f9b
KO
136// ============================================================================
137// wxTaskBarIcon implementation
138// The facade class.
139// ============================================================================
140IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler)
141
142wxTaskBarIcon::wxTaskBarIcon(wxTaskBarIconType iconType)
143{
70175534 144 if(iconType == wxTBI_DOCK)
01250f9b 145 m_impl = new wxTaskBarIconDockImpl(this);
70175534 146 else if(iconType == wxTBI_CUSTOM_STATUSITEM)
01250f9b
KO
147 m_impl = new wxTaskBarIconCustomStatusItemImpl(this);
148 else
149 { m_impl = NULL;
150 wxFAIL_MSG(wxT("Invalid wxTaskBarIcon type"));
151 }
152}
153
154wxTaskBarIcon::~wxTaskBarIcon()
155{
b59cd6c4
SC
156 if ( m_impl )
157 {
158 if ( m_impl->IsIconInstalled() )
159 m_impl->RemoveIcon();
160 delete m_impl;
161 m_impl = NULL;
162 }
163}
164
165bool wxTaskBarIcon::OSXIsStatusItem()
166{
167 if ( m_impl )
168 return m_impl->IsStatusItem();
169
170 return false;
01250f9b
KO
171}
172
173// Operations
174
175bool wxTaskBarIcon::IsIconInstalled() const
03647350 176{
b59cd6c4
SC
177 if ( m_impl )
178 return m_impl->IsIconInstalled();
179
01250f9b
KO
180 return false;
181}
182
183bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
184{
b59cd6c4
SC
185 if ( m_impl )
186 return m_impl->SetIcon(icon,tooltip);
187
188 return false;
01250f9b
KO
189}
190
191bool wxTaskBarIcon::RemoveIcon()
192{
b59cd6c4
SC
193 if ( m_impl )
194 return m_impl->RemoveIcon();
195
196 return false;
01250f9b
KO
197}
198
199bool wxTaskBarIcon::PopupMenu(wxMenu *menu)
200{
b59cd6c4
SC
201 if ( m_impl )
202 return m_impl->PopupMenu(menu);
203
204 return false;
01250f9b
KO
205}
206
207// ============================================================================
208// wxTaskBarIconImpl
209// ============================================================================
210
b59cd6c4
SC
211wxTaskBarIconImpl::wxTaskBarIconImpl(wxTaskBarIcon* taskBarIcon)
212 : m_taskBarIcon(taskBarIcon), m_eventWindow(new wxTaskBarIconWindow(this))
213{
214}
215
01250f9b
KO
216wxTaskBarIconImpl::~wxTaskBarIconImpl()
217{
b59cd6c4 218 delete m_eventWindow;
01250f9b
KO
219}
220
221// ============================================================================
222// wxTaskBarIconDockImpl
223// ============================================================================
224wxTaskBarIconDockImpl *wxTaskBarIconDockImpl::sm_dockIcon = NULL;
225
226wxTaskBarIconDockImpl::wxTaskBarIconDockImpl(wxTaskBarIcon *taskBarIcon)
227: wxTaskBarIconImpl(taskBarIcon)
228{
01250f9b
KO
229 wxASSERT_MSG(!sm_dockIcon, wxT("You should never have more than one dock icon!"));
230 sm_dockIcon = this;
b59cd6c4 231 m_pMenu = NULL;
01250f9b
KO
232}
233
234wxTaskBarIconDockImpl::~wxTaskBarIconDockImpl()
235{
01250f9b
KO
236 if(sm_dockIcon == this)
237 sm_dockIcon = NULL;
238}
239
b59cd6c4 240WX_NSMenu wxTaskBarIconDockImpl::OSXGetDockHMenu()
01250f9b
KO
241{
242 if(sm_dockIcon)
b59cd6c4
SC
243 return sm_dockIcon->OSXDoGetDockHMenu();
244
01250f9b
KO
245 return nil;
246}
247
b59cd6c4 248WX_NSMenu wxTaskBarIconDockImpl::OSXDoGetDockHMenu()
01250f9b
KO
249{
250 wxMenu *dockMenu = CreatePopupMenu();
b59cd6c4 251
01250f9b
KO
252 if(!dockMenu)
253 return nil;
b59cd6c4
SC
254
255 wxDELETE(m_pMenu);
256
257 m_pMenu = dockMenu;
258
259 m_pMenu->SetInvokingWindow(m_eventWindow);
260
261 m_pMenu->UpdateUI();
262
01250f9b
KO
263 return (WX_NSMenu)dockMenu->GetHMenu();
264}
265
b59cd6c4 266bool wxTaskBarIconDockImpl::SetIcon(const wxIcon& icon, const wxString& WXUNUSED(tooltip))
01250f9b 267{
b59cd6c4
SC
268 m_icon.CopyFromIcon(icon);
269 [[NSApplication sharedApplication] setApplicationIconImage:m_icon.GetNSImage()];
01250f9b
KO
270 return true;
271}
272
273bool wxTaskBarIconDockImpl::RemoveIcon()
274{
b59cd6c4
SC
275 wxDELETE(m_pMenu);
276 m_icon = wxBitmap();
277 [[NSApplication sharedApplication] setApplicationIconImage:nil];
01250f9b
KO
278 return true;
279}
280
d8207702 281bool wxTaskBarIconDockImpl::PopupMenu(wxMenu *WXUNUSED(menu))
01250f9b
KO
282{
283 wxFAIL_MSG(wxT("You cannot force the Dock icon menu to popup"));
284 return false;
285}
286
b59cd6c4
SC
287@interface wxNSAppController(wxTaskBarIconNSApplicationDelegateCategory)
288- (NSMenu*)applicationDockMenu:(NSApplication *)sender;
289@end
290
291@implementation wxNSAppController(wxTaskBarIconNSApplicationDelegateCategory)
292- (NSMenu*)applicationDockMenu:(NSApplication *)sender
293{
e7794cf2
SC
294 wxUnusedVar(sender);
295
b59cd6c4
SC
296 return wxTaskBarIconDockImpl::OSXGetDockHMenu();
297}
298@end
01250f9b
KO
299
300// ============================================================================
301// wxTaskBarIconCustomStatusItemImpl
302// ============================================================================
b59cd6c4
SC
303
304@implementation wxOSXStatusItemTarget
305
306- (void) clickedAction: (id) sender
307{
e7794cf2 308 wxUnusedVar(sender);
b59cd6c4
SC
309 wxMenu *menu = impl->CreatePopupMenu();
310 if (menu)
311 {
312 impl->PopupMenu(menu);
313 delete menu;
314 }
315}
316
317- (void)setImplementation: (wxTaskBarIconCustomStatusItemImpl *) theImplementation
318{
319 impl = theImplementation;
320}
321
322- (wxTaskBarIconCustomStatusItemImpl*) implementation
323{
324 return impl;
325}
326
327@end
328
329
01250f9b
KO
330wxTaskBarIconCustomStatusItemImpl::wxTaskBarIconCustomStatusItemImpl(wxTaskBarIcon *taskBarIcon)
331: wxTaskBarIconImpl(taskBarIcon)
332{
b59cd6c4
SC
333 m_statusItem = nil;
334 m_target = nil;
01250f9b
KO
335}
336
337wxTaskBarIconCustomStatusItemImpl::~wxTaskBarIconCustomStatusItemImpl()
338{
339}
340
445eaabd 341bool wxTaskBarIconCustomStatusItemImpl::SetIcon(const wxIcon& icon, const wxString& tooltip)
01250f9b 342{
b59cd6c4 343 if(!m_statusItem)
01250f9b 344 {
b59cd6c4
SC
345 m_statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
346 [m_statusItem retain];
347
348 m_target = [[wxOSXStatusItemTarget alloc] init];
349 [m_target setImplementation:this];
4e30a4ce 350 [m_statusItem setHighlightMode:YES];
b59cd6c4
SC
351 [m_statusItem setTarget:m_target];
352 [m_statusItem setAction:@selector(clickedAction:)];
353 [m_statusItem sendActionOn:NSLeftMouseDownMask];
01250f9b 354 }
b59cd6c4
SC
355
356 m_icon.CopyFromIcon(icon);
357
358 // status item doesn't scale automatically
359
360 int dimension = m_icon.GetHeight();
361 if ( m_icon.GetWidth() > dimension )
362 dimension = m_icon.GetWidth();
363 if ( dimension > 16 )
364 {
365 wxImage img = m_icon.ConvertToImage();
366 int factor = (dimension+15)/16;
367 m_icon = img.ShrinkBy(factor, factor);
368 }
369
370 [m_statusItem setImage:m_icon.GetNSImage()];
445eaabd
VZ
371 wxCFStringRef cfTooltip(tooltip);
372 [m_statusItem setToolTip:cfTooltip.AsNSString()];
01250f9b
KO
373 return true;
374}
375
376bool wxTaskBarIconCustomStatusItemImpl::RemoveIcon()
377{
b59cd6c4
SC
378 [m_statusItem release];
379 m_statusItem = nil;
380 [m_target release];
381 m_target = nil;
382
383 m_icon = wxBitmap();
384
01250f9b
KO
385 return true;
386}
387
388bool wxTaskBarIconCustomStatusItemImpl::PopupMenu(wxMenu *menu)
389{
390 wxASSERT(menu);
b59cd6c4
SC
391
392 menu->SetInvokingWindow(m_eventWindow);
01250f9b
KO
393 menu->UpdateUI();
394
b59cd6c4
SC
395 [m_statusItem popUpStatusItemMenu:(NSMenu*)menu->GetHMenu()];
396
01250f9b
KO
397 menu->SetInvokingWindow(NULL);
398 return true;
399}
400
401// ============================================================================
402// wxTaskBarIconWindow
403// ============================================================================
b59cd6c4 404
01250f9b 405BEGIN_EVENT_TABLE(wxTaskBarIconWindow, wxWindow)
b59cd6c4
SC
406EVT_MENU(-1, wxTaskBarIconWindow::OnMenuEvent)
407EVT_UPDATE_UI(-1, wxTaskBarIconWindow::OnUpdateUIEvent)
01250f9b
KO
408END_EVENT_TABLE()
409
b59cd6c4
SC
410wxTaskBarIconWindow::wxTaskBarIconWindow(wxTaskBarIconImpl *impl)
411: m_impl(impl)
01250f9b 412{
01250f9b
KO
413}
414
b59cd6c4
SC
415void wxTaskBarIconWindow::OnMenuEvent(wxCommandEvent& event)
416{
417 m_impl->GetTaskBarIcon()->ProcessEvent(event);
01250f9b
KO
418}
419
b59cd6c4 420void wxTaskBarIconWindow::OnUpdateUIEvent(wxUpdateUIEvent& event)
01250f9b 421{
b59cd6c4 422 m_impl->GetTaskBarIcon()->ProcessEvent(event);
01250f9b
KO
423}
424
01250f9b 425#endif //def wxHAS_TASK_BAR_ICON