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