]> git.saurik.com Git - wxWidgets.git/blob - src/osx/cocoa/taskbar.mm
Support mouse click through as otherwise clicking inside an inactive window causes...
[wxWidgets.git] / src / osx / cocoa / taskbar.mm
1 /////////////////////////////////////////////////////////////////////////
2 // File: src/osx/cocoa/taskbar.mm
3 // Purpose: Implements wxTaskBarIcon class
4 // Author: David Elliott
5 // Modified by:
6 // Created: 2004/01/24
7 // RCS-ID: $Id: taskbar.mm 35650 2005-09-23 12:56:45Z MR $
8 // Copyright: (c) 2004 David Elliott
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13 #if wxUSE_TASKBARICON
14
15 #ifndef WX_PRECOMP
16 #include "wx/menu.h"
17 #include "wx/icon.h"
18 #include "wx/log.h"
19 #include "wx/dcclient.h"
20 #endif
21
22 #include "wx/taskbar.h"
23
24 #include "wx/osx/private.h"
25
26 // A category for methods that are only present in Panther's SDK
27 @interface NSStatusItem(wxNSStatusItemPrePantherCompatibility)
28 - (void)popUpStatusItemMenu:(NSMenu *)menu;
29 @end
30
31 class wxTaskBarIconWindow;
32
33 // ============================================================================
34 // wxTaskBarIconImpl
35 // Base class for the various Cocoa implementations.
36 // ============================================================================
37 class wxTaskBarIconImpl
38 {
39 public:
40 wxTaskBarIconImpl(wxTaskBarIcon *taskBarIcon)
41 : m_taskBarIcon(taskBarIcon)
42 , m_iconWindow(NULL)
43 {}
44 virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString) = 0;
45 virtual bool RemoveIcon() = 0;
46 virtual bool PopupMenu(wxMenu *menu) = 0;
47 virtual ~wxTaskBarIconImpl();
48 inline wxTaskBarIcon* GetTaskBarIcon() { return m_taskBarIcon; }
49 wxMenu * CreatePopupMenu()
50 { return m_taskBarIcon->CreatePopupMenu(); }
51
52 wxDECLARE_NO_COPY_CLASS(wxTaskBarIconImpl);
53
54 protected:
55 wxTaskBarIcon *m_taskBarIcon;
56 wxTaskBarIconWindow *m_iconWindow;
57 private:
58 wxTaskBarIconImpl();
59 };
60
61 // ============================================================================
62 // wxTaskBarIconDockImpl
63 // An implementation using the Dock icon.
64 // ============================================================================
65 class wxTaskBarIconDockImpl: public wxTaskBarIconImpl
66 {
67 public:
68 wxTaskBarIconDockImpl(wxTaskBarIcon *taskBarIcon);
69 virtual ~wxTaskBarIconDockImpl();
70 virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString);
71 virtual bool RemoveIcon();
72 virtual bool PopupMenu(wxMenu *menu);
73
74 static WX_NSMenu CocoaGetDockNSMenu();
75 protected:
76 WX_NSMenu CocoaDoGetDockNSMenu();
77 WX_NSImage m_originalDockIcon;
78 // There can be only one Dock icon, so make sure we keep it that way
79 static wxTaskBarIconDockImpl *sm_dockIcon;
80 private:
81 wxTaskBarIconDockImpl();
82 };
83
84 // ============================================================================
85 // wxTaskBarIconCustomStatusItemImpl
86 // An implementation using an NSStatusItem with a custom NSView
87 // ============================================================================
88 class wxTaskBarIconCustomStatusItemImpl: public wxTaskBarIconImpl
89 {
90 public:
91 wxTaskBarIconCustomStatusItemImpl(wxTaskBarIcon *taskBarIcon);
92 virtual ~wxTaskBarIconCustomStatusItemImpl();
93 virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString);
94 virtual bool RemoveIcon();
95 virtual bool PopupMenu(wxMenu *menu);
96 protected:
97 NSStatusItem *m_cocoaNSStatusItem;
98 private:
99 wxTaskBarIconCustomStatusItemImpl();
100 };
101
102 // ============================================================================
103 // wxTaskBarIconWindow
104 // Used by all implementations to forward events from the wxMenu
105 // ============================================================================
106 class wxTaskBarIconWindow: public wxWindow
107 {
108 DECLARE_EVENT_TABLE()
109 public:
110 wxTaskBarIconWindow(wxTaskBarIconImpl *taskBarIconImpl)
111 : wxWindow(NULL,-1)
112 , m_taskBarIconImpl(taskBarIconImpl)
113 { wxASSERT(m_taskBarIconImpl); }
114
115 void OnMenuEvent(wxCommandEvent& event);
116 protected:
117 wxTaskBarIconImpl *m_taskBarIconImpl;
118 };
119
120 // ============================================================================
121 // wxTaskBarIconWindowCustom
122 // Used by the CustomStatusIcon implementation for the custom NSView.
123 // ============================================================================
124 class wxTaskBarIconWindowCustom: public wxTaskBarIconWindow
125 {
126 DECLARE_EVENT_TABLE()
127 public:
128 wxTaskBarIconWindowCustom(wxTaskBarIconImpl *taskBarIconImpl)
129 : wxTaskBarIconWindow(taskBarIconImpl)
130 {}
131 void SetIcon(const wxIcon& icon)
132 { m_icon = icon; }
133 void OnMouseEvent(wxMouseEvent &event);
134 void OnPaint(wxPaintEvent &event);
135 protected:
136 wxIcon m_icon;
137 };
138
139 // ============================================================================
140 // wxTaskBarIcon implementation
141 // The facade class.
142 // ============================================================================
143 IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler)
144
145 wxTaskBarIcon::wxTaskBarIcon(wxTaskBarIconType iconType)
146 {
147 if(iconType == DOCK)
148 m_impl = new wxTaskBarIconDockImpl(this);
149 else if(iconType == CUSTOM_STATUSITEM)
150 m_impl = new wxTaskBarIconCustomStatusItemImpl(this);
151 else
152 { m_impl = NULL;
153 wxFAIL_MSG(wxT("Invalid wxTaskBarIcon type"));
154 }
155 }
156
157 wxTaskBarIcon::~wxTaskBarIcon()
158 {
159 delete m_impl;
160 }
161
162 // Operations
163
164 bool wxTaskBarIcon::IsIconInstalled() const
165 {
166 return false;
167 }
168
169 bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
170 {
171 return m_impl->SetIcon(icon,tooltip);
172 }
173
174 bool wxTaskBarIcon::RemoveIcon()
175 {
176 return m_impl->RemoveIcon();
177 }
178
179 bool wxTaskBarIcon::PopupMenu(wxMenu *menu)
180 {
181 return m_impl->PopupMenu(menu);
182 }
183
184 // ============================================================================
185 // wxTaskBarIconImpl
186 // ============================================================================
187
188 wxTaskBarIconImpl::~wxTaskBarIconImpl()
189 {
190 // wxAutoNSAutoreleasePool pool;
191 delete m_iconWindow;
192 }
193
194 // ============================================================================
195 // wxTaskBarIconDockImpl
196 // ============================================================================
197 wxTaskBarIconDockImpl *wxTaskBarIconDockImpl::sm_dockIcon = NULL;
198
199 wxTaskBarIconDockImpl::wxTaskBarIconDockImpl(wxTaskBarIcon *taskBarIcon)
200 : wxTaskBarIconImpl(taskBarIcon)
201 {
202 m_originalDockIcon = nil;
203 wxASSERT_MSG(!sm_dockIcon, wxT("You should never have more than one dock icon!"));
204 sm_dockIcon = this;
205 }
206
207 wxTaskBarIconDockImpl::~wxTaskBarIconDockImpl()
208 {
209 // wxAutoNSAutoreleasePool pool;
210 if(sm_dockIcon == this)
211 sm_dockIcon = NULL;
212 }
213
214 WX_NSMenu wxTaskBarIconDockImpl::CocoaGetDockNSMenu()
215 {
216 if(sm_dockIcon)
217 return sm_dockIcon->CocoaDoGetDockNSMenu();
218 return nil;
219 }
220
221 WX_NSMenu wxTaskBarIconDockImpl::CocoaDoGetDockNSMenu()
222 {
223 wxMenu *dockMenu = CreatePopupMenu();
224 if(!dockMenu)
225 return nil;
226 if(!m_iconWindow)
227 m_iconWindow = new wxTaskBarIconWindow(this);
228 dockMenu->SetInvokingWindow(m_iconWindow);
229 dockMenu->UpdateUI();
230 //dockMenu->SetCocoaDeletes(true);
231 return (WX_NSMenu)dockMenu->GetHMenu();
232 }
233
234 bool wxTaskBarIconDockImpl::SetIcon(const wxIcon& WXUNUSED(icon), const wxString& WXUNUSED(tooltip))
235 {
236 wxMacAutoreleasePool pool;
237 m_originalDockIcon = [[[NSApplication sharedApplication] applicationIconImage] retain];
238 //[[NSApplication sharedApplication] setApplicationIconImage:icon.GetNSImage()];
239 return true;
240 }
241
242 bool wxTaskBarIconDockImpl::RemoveIcon()
243 {
244 [[NSApplication sharedApplication] setApplicationIconImage:m_originalDockIcon];
245 [m_originalDockIcon release];
246 return true;
247 }
248
249 bool wxTaskBarIconDockImpl::PopupMenu(wxMenu *WXUNUSED(menu))
250 {
251 wxFAIL_MSG(wxT("You cannot force the Dock icon menu to popup"));
252 return false;
253 }
254
255
256 // ============================================================================
257 // wxTaskBarIconCustomStatusItemImpl
258 // ============================================================================
259 wxTaskBarIconCustomStatusItemImpl::wxTaskBarIconCustomStatusItemImpl(wxTaskBarIcon *taskBarIcon)
260 : wxTaskBarIconImpl(taskBarIcon)
261 {
262 m_cocoaNSStatusItem = nil;
263 }
264
265 wxTaskBarIconCustomStatusItemImpl::~wxTaskBarIconCustomStatusItemImpl()
266 {
267 }
268
269 bool wxTaskBarIconCustomStatusItemImpl::SetIcon(const wxIcon& icon, const wxString& WXUNUSED(tooltip))
270 {
271 wxMacAutoreleasePool pool;
272 if(!m_cocoaNSStatusItem)
273 {
274 m_cocoaNSStatusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
275 [m_cocoaNSStatusItem retain];
276 }
277 if(!m_iconWindow)
278 m_iconWindow= new wxTaskBarIconWindowCustom(this);
279 static_cast<wxTaskBarIconWindowCustom*>(m_iconWindow)->SetIcon(icon);
280 // FIXME: no less than 10 because most icon types don't work yet
281 // and this allows us to see how task bar icons would work
282 [(NSView*)m_iconWindow->GetHandle() setFrame:NSMakeRect(0.0,0.0,wxMax(10,icon.GetWidth()),[[NSStatusBar systemStatusBar] thickness])];
283 [m_cocoaNSStatusItem setView:(NSView*)m_iconWindow->GetHandle()];
284 return true;
285 }
286
287 bool wxTaskBarIconCustomStatusItemImpl::RemoveIcon()
288 {
289 [m_cocoaNSStatusItem release];
290 m_cocoaNSStatusItem = nil;
291 delete m_iconWindow;
292 m_iconWindow = NULL;
293 return true;
294 }
295
296 bool wxTaskBarIconCustomStatusItemImpl::PopupMenu(wxMenu *menu)
297 {
298 wxASSERT(menu);
299 menu->SetInvokingWindow(m_iconWindow);
300 menu->UpdateUI();
301
302 if([m_cocoaNSStatusItem respondsToSelector:@selector(popUpStatusItemMenu:)])
303 { // OS X >= 10.3
304 [m_cocoaNSStatusItem popUpStatusItemMenu:(NSMenu*)menu->GetHMenu()];
305 }
306 else
307 { // pretty good fake for OS X < 10.3
308 NSEvent *nsevent = [NSEvent mouseEventWithType:NSLeftMouseDown
309 location:NSMakePoint(-1.0,-4.0) modifierFlags:0 timestamp:0
310 windowNumber:[[(NSView*)m_iconWindow->GetHandle() window] windowNumber]
311 context:[NSGraphicsContext currentContext]
312 eventNumber:0 clickCount:1 pressure:0.0];
313 [NSMenu popUpContextMenu:menu->GetHMenu() withEvent:nsevent forView:(NSView*)m_iconWindow->GetHandle()];
314 }
315 menu->SetInvokingWindow(NULL);
316 return true;
317 }
318
319 // ============================================================================
320 // wxTaskBarIconWindow
321 // ============================================================================
322 BEGIN_EVENT_TABLE(wxTaskBarIconWindow, wxWindow)
323 EVT_MENU(-1, wxTaskBarIconWindow::OnMenuEvent)
324 END_EVENT_TABLE()
325
326 void wxTaskBarIconWindow::OnMenuEvent(wxCommandEvent &event)
327 {
328 m_taskBarIconImpl->GetTaskBarIcon()->ProcessEvent(event);
329 }
330
331 // ============================================================================
332 // wxTaskBarIconWindowCustom
333 // ============================================================================
334 BEGIN_EVENT_TABLE(wxTaskBarIconWindowCustom, wxTaskBarIconWindow)
335 EVT_MOUSE_EVENTS(wxTaskBarIconWindowCustom::OnMouseEvent)
336 EVT_PAINT(wxTaskBarIconWindowCustom::OnPaint)
337 END_EVENT_TABLE()
338
339 void wxTaskBarIconWindowCustom::OnMouseEvent(wxMouseEvent &event)
340 {
341 wxEventType tbEventType = 0;
342 if(event.GetEventType() == wxEVT_MOTION)
343 tbEventType = wxEVT_TASKBAR_MOVE;
344 else if(event.GetEventType() == wxEVT_LEFT_DOWN)
345 tbEventType = wxEVT_TASKBAR_LEFT_DOWN;
346 else if(event.GetEventType() == wxEVT_LEFT_UP)
347 tbEventType = wxEVT_TASKBAR_LEFT_UP;
348 else if(event.GetEventType() == wxEVT_RIGHT_DOWN)
349 tbEventType = wxEVT_TASKBAR_RIGHT_DOWN;
350 else if(event.GetEventType() == wxEVT_RIGHT_UP)
351 tbEventType = wxEVT_TASKBAR_RIGHT_UP;
352 else if(event.GetEventType() == wxEVT_LEFT_DCLICK)
353 tbEventType = wxEVT_TASKBAR_LEFT_DCLICK;
354 else if(event.GetEventType() == wxEVT_RIGHT_DCLICK)
355 tbEventType = wxEVT_TASKBAR_RIGHT_DCLICK;
356 else
357 return;
358 wxTaskBarIconEvent tbiEvent(tbEventType,m_taskBarIconImpl->GetTaskBarIcon());
359 m_taskBarIconImpl->GetTaskBarIcon()->ProcessEvent(tbiEvent);
360 }
361
362 void wxTaskBarIconWindowCustom::OnPaint(wxPaintEvent &WXUNUSED(event))
363 {
364 wxPaintDC dc(this);
365 // FIXME: This is a temporary hack until we can see real icons
366 dc.SetBackground(wxBrush(*wxBLUE));
367 dc.Clear();
368 dc.DrawIcon(m_icon,0,0);
369 }
370
371 #endif //def wxHAS_TASK_BAR_ICON