1 /////////////////////////////////////////////////////////////////////////
2 // File: src/osx/cocoa/taskbar.mm
3 // Purpose: Implements wxTaskBarIcon class
4 // Author: David Elliott, Stefan Csomor
8 // Copyright: (c) 2004 David Elliott, Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
16 #include "wx/toplevel.h"
20 #include "wx/dcclient.h"
23 #include "wx/taskbar.h"
25 #include "wx/osx/private.h"
27 class wxTaskBarIconWindow;
29 //-----------------------------------------------------------------------------
31 // wxTaskBarIconWindow
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 //-----------------------------------------------------------------------------
38 class wxTaskBarIconWindow : public wxTopLevelWindow
41 wxTaskBarIconWindow(wxTaskBarIconImpl *impl);
43 void OnMenuEvent(wxCommandEvent& event);
44 void OnUpdateUIEvent(wxUpdateUIEvent& event);
47 wxTaskBarIconImpl *m_impl;
51 // ============================================================================
53 // Base class for the various Cocoa implementations.
54 // ============================================================================
55 class wxTaskBarIconImpl
58 wxTaskBarIconImpl(wxTaskBarIcon *taskBarIcon);
60 virtual bool IsStatusItem() const { return false; }
62 virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString) = 0;
63 virtual bool RemoveIcon() = 0;
65 bool IsIconInstalled() const { return m_icon.IsOk(); }
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(); }
73 wxDECLARE_NO_COPY_CLASS(wxTaskBarIconImpl);
76 wxTaskBarIcon *m_taskBarIcon;
78 wxTaskBarIconWindow *m_eventWindow;
83 // ============================================================================
84 // wxTaskBarIconDockImpl
85 // An implementation using the Dock icon.
86 // ============================================================================
87 class wxTaskBarIconDockImpl: public wxTaskBarIconImpl
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);
96 static WX_NSMenu OSXGetDockHMenu();
98 WX_NSMenu OSXDoGetDockHMenu();
99 // There can be only one Dock icon, so make sure we keep it that way
100 static wxTaskBarIconDockImpl *sm_dockIcon;
102 wxTaskBarIconDockImpl();
106 class wxTaskBarIconCustomStatusItemImpl;
108 @interface wxOSXStatusItemTarget : NSObject
110 wxTaskBarIconCustomStatusItemImpl* impl;
114 // ============================================================================
115 // wxTaskBarIconCustomStatusItemImpl
116 // An implementation using an NSStatusItem with a custom NSView
117 // ============================================================================
118 class wxTaskBarIconCustomStatusItemImpl: public wxTaskBarIconImpl
121 wxTaskBarIconCustomStatusItemImpl(wxTaskBarIcon *taskBarIcon);
122 virtual ~wxTaskBarIconCustomStatusItemImpl();
124 virtual bool IsStatusItem() const { return true; }
126 virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString);
127 virtual bool RemoveIcon();
128 virtual bool PopupMenu(wxMenu *menu);
130 NSStatusItem *m_statusItem;
131 wxOSXStatusItemTarget *m_target;
133 wxTaskBarIconCustomStatusItemImpl();
136 // ============================================================================
137 // wxTaskBarIcon implementation
139 // ============================================================================
140 IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler)
142 wxTaskBarIcon::wxTaskBarIcon(wxTaskBarIconType iconType)
144 if(iconType == wxTBI_DOCK)
145 m_impl = new wxTaskBarIconDockImpl(this);
146 else if(iconType == wxTBI_CUSTOM_STATUSITEM)
147 m_impl = new wxTaskBarIconCustomStatusItemImpl(this);
150 wxFAIL_MSG(wxT("Invalid wxTaskBarIcon type"));
154 wxTaskBarIcon::~wxTaskBarIcon()
158 if ( m_impl->IsIconInstalled() )
159 m_impl->RemoveIcon();
165 bool wxTaskBarIcon::OSXIsStatusItem()
168 return m_impl->IsStatusItem();
175 bool wxTaskBarIcon::IsIconInstalled() const
178 return m_impl->IsIconInstalled();
183 bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
186 return m_impl->SetIcon(icon,tooltip);
191 bool wxTaskBarIcon::RemoveIcon()
194 return m_impl->RemoveIcon();
199 bool wxTaskBarIcon::PopupMenu(wxMenu *menu)
202 return m_impl->PopupMenu(menu);
207 // ============================================================================
209 // ============================================================================
211 wxTaskBarIconImpl::wxTaskBarIconImpl(wxTaskBarIcon* taskBarIcon)
212 : m_taskBarIcon(taskBarIcon), m_eventWindow(new wxTaskBarIconWindow(this))
216 wxTaskBarIconImpl::~wxTaskBarIconImpl()
218 delete m_eventWindow;
221 // ============================================================================
222 // wxTaskBarIconDockImpl
223 // ============================================================================
224 wxTaskBarIconDockImpl *wxTaskBarIconDockImpl::sm_dockIcon = NULL;
226 wxTaskBarIconDockImpl::wxTaskBarIconDockImpl(wxTaskBarIcon *taskBarIcon)
227 : wxTaskBarIconImpl(taskBarIcon)
229 wxASSERT_MSG(!sm_dockIcon, wxT("You should never have more than one dock icon!"));
234 wxTaskBarIconDockImpl::~wxTaskBarIconDockImpl()
236 if(sm_dockIcon == this)
240 WX_NSMenu wxTaskBarIconDockImpl::OSXGetDockHMenu()
243 return sm_dockIcon->OSXDoGetDockHMenu();
248 WX_NSMenu wxTaskBarIconDockImpl::OSXDoGetDockHMenu()
250 wxMenu *dockMenu = CreatePopupMenu();
259 m_pMenu->SetInvokingWindow(m_eventWindow);
263 return (WX_NSMenu)dockMenu->GetHMenu();
266 bool wxTaskBarIconDockImpl::SetIcon(const wxIcon& icon, const wxString& WXUNUSED(tooltip))
268 m_icon.CopyFromIcon(icon);
269 [[NSApplication sharedApplication] setApplicationIconImage:m_icon.GetNSImage()];
273 bool wxTaskBarIconDockImpl::RemoveIcon()
277 [[NSApplication sharedApplication] setApplicationIconImage:nil];
281 bool wxTaskBarIconDockImpl::PopupMenu(wxMenu *WXUNUSED(menu))
283 wxFAIL_MSG(wxT("You cannot force the Dock icon menu to popup"));
287 @interface wxNSAppController(wxTaskBarIconNSApplicationDelegateCategory)
288 - (NSMenu*)applicationDockMenu:(NSApplication *)sender;
291 @implementation wxNSAppController(wxTaskBarIconNSApplicationDelegateCategory)
292 - (NSMenu*)applicationDockMenu:(NSApplication *)sender
296 return wxTaskBarIconDockImpl::OSXGetDockHMenu();
300 // ============================================================================
301 // wxTaskBarIconCustomStatusItemImpl
302 // ============================================================================
304 @implementation wxOSXStatusItemTarget
306 - (void) clickedAction: (id) sender
309 wxMenu *menu = impl->CreatePopupMenu();
312 impl->PopupMenu(menu);
317 - (void)setImplementation: (wxTaskBarIconCustomStatusItemImpl *) theImplementation
319 impl = theImplementation;
322 - (wxTaskBarIconCustomStatusItemImpl*) implementation
330 wxTaskBarIconCustomStatusItemImpl::wxTaskBarIconCustomStatusItemImpl(wxTaskBarIcon *taskBarIcon)
331 : wxTaskBarIconImpl(taskBarIcon)
337 wxTaskBarIconCustomStatusItemImpl::~wxTaskBarIconCustomStatusItemImpl()
341 bool wxTaskBarIconCustomStatusItemImpl::SetIcon(const wxIcon& icon, const wxString& tooltip)
345 m_statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
346 [m_statusItem retain];
348 m_target = [[wxOSXStatusItemTarget alloc] init];
349 [m_target setImplementation:this];
350 [m_statusItem setHighlightMode:YES];
351 [m_statusItem setTarget:m_target];
352 [m_statusItem setAction:@selector(clickedAction:)];
353 [m_statusItem sendActionOn:NSLeftMouseDownMask];
356 m_icon.CopyFromIcon(icon);
358 // status item doesn't scale automatically
360 int dimension = m_icon.GetHeight();
361 if ( m_icon.GetWidth() > dimension )
362 dimension = m_icon.GetWidth();
363 if ( dimension > 16 )
365 wxImage img = m_icon.ConvertToImage();
366 int factor = (dimension+15)/16;
367 m_icon = img.ShrinkBy(factor, factor);
370 [m_statusItem setImage:m_icon.GetNSImage()];
371 wxCFStringRef cfTooltip(tooltip);
372 [m_statusItem setToolTip:cfTooltip.AsNSString()];
376 bool wxTaskBarIconCustomStatusItemImpl::RemoveIcon()
378 [m_statusItem release];
388 bool wxTaskBarIconCustomStatusItemImpl::PopupMenu(wxMenu *menu)
392 menu->SetInvokingWindow(m_eventWindow);
395 [m_statusItem popUpStatusItemMenu:(NSMenu*)menu->GetHMenu()];
397 menu->SetInvokingWindow(NULL);
401 // ============================================================================
402 // wxTaskBarIconWindow
403 // ============================================================================
405 BEGIN_EVENT_TABLE(wxTaskBarIconWindow, wxWindow)
406 EVT_MENU(-1, wxTaskBarIconWindow::OnMenuEvent)
407 EVT_UPDATE_UI(-1, wxTaskBarIconWindow::OnUpdateUIEvent)
410 wxTaskBarIconWindow::wxTaskBarIconWindow(wxTaskBarIconImpl *impl)
415 void wxTaskBarIconWindow::OnMenuEvent(wxCommandEvent& event)
417 m_impl->GetTaskBarIcon()->ProcessEvent(event);
420 void wxTaskBarIconWindow::OnUpdateUIEvent(wxUpdateUIEvent& event)
422 m_impl->GetTaskBarIcon()->ProcessEvent(event);
425 #endif //def wxHAS_TASK_BAR_ICON