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