1 /////////////////////////////////////////////////////////////////////////
2 // File: src/osx/cocoa/taskbar.mm
3 // Purpose: Implements wxTaskBarIcon class
4 // Author: David Elliott, Stefan Csomor
7 // Copyright: (c) 2004 David Elliott, Stefan Csomor
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////
11 #include "wx/wxprec.h"
15 #include "wx/toplevel.h"
19 #include "wx/dcclient.h"
22 #include "wx/taskbar.h"
24 #include "wx/osx/private.h"
26 class wxTaskBarIconWindow;
28 //-----------------------------------------------------------------------------
30 // wxTaskBarIconWindow
32 // Event handler for menus
33 // NB: Since wxWindows in Mac HAVE to have parents we need this to be
34 // a top level window...
35 //-----------------------------------------------------------------------------
37 class wxTaskBarIconWindow : public wxTopLevelWindow
40 wxTaskBarIconWindow(wxTaskBarIconImpl *impl);
42 void OnMenuEvent(wxCommandEvent& event);
43 void OnUpdateUIEvent(wxUpdateUIEvent& event);
46 wxTaskBarIconImpl *m_impl;
50 // ============================================================================
52 // Base class for the various Cocoa implementations.
53 // ============================================================================
54 class wxTaskBarIconImpl
57 wxTaskBarIconImpl(wxTaskBarIcon *taskBarIcon);
59 virtual bool IsStatusItem() const { return false; }
61 virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString) = 0;
62 virtual bool RemoveIcon() = 0;
64 bool IsIconInstalled() const { return m_icon.IsOk(); }
66 virtual bool PopupMenu(wxMenu *menu) = 0;
67 virtual ~wxTaskBarIconImpl();
68 inline wxTaskBarIcon* GetTaskBarIcon() { return m_taskBarIcon; }
69 wxMenu * CreatePopupMenu()
70 { return m_taskBarIcon->CreatePopupMenu(); }
72 wxDECLARE_NO_COPY_CLASS(wxTaskBarIconImpl);
75 wxTaskBarIcon *m_taskBarIcon;
77 wxTaskBarIconWindow *m_eventWindow;
82 // ============================================================================
83 // wxTaskBarIconDockImpl
84 // An implementation using the Dock icon.
85 // ============================================================================
86 class wxTaskBarIconDockImpl: public wxTaskBarIconImpl
89 wxTaskBarIconDockImpl(wxTaskBarIcon *taskBarIcon);
90 virtual ~wxTaskBarIconDockImpl();
91 virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString);
92 virtual bool RemoveIcon();
93 virtual bool PopupMenu(wxMenu *menu);
95 static WX_NSMenu OSXGetDockHMenu();
97 WX_NSMenu OSXDoGetDockHMenu();
98 // There can be only one Dock icon, so make sure we keep it that way
99 static wxTaskBarIconDockImpl *sm_dockIcon;
101 wxTaskBarIconDockImpl();
105 class wxTaskBarIconCustomStatusItemImpl;
107 @interface wxOSXStatusItemTarget : NSObject
109 wxTaskBarIconCustomStatusItemImpl* impl;
113 // ============================================================================
114 // wxTaskBarIconCustomStatusItemImpl
115 // An implementation using an NSStatusItem with a custom NSView
116 // ============================================================================
117 class wxTaskBarIconCustomStatusItemImpl: public wxTaskBarIconImpl
120 wxTaskBarIconCustomStatusItemImpl(wxTaskBarIcon *taskBarIcon);
121 virtual ~wxTaskBarIconCustomStatusItemImpl();
123 virtual bool IsStatusItem() const { return true; }
125 virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString);
126 virtual bool RemoveIcon();
127 virtual bool PopupMenu(wxMenu *menu);
129 NSStatusItem *m_statusItem;
130 wxOSXStatusItemTarget *m_target;
132 wxTaskBarIconCustomStatusItemImpl();
135 // ============================================================================
136 // wxTaskBarIcon implementation
138 // ============================================================================
139 IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler)
141 wxTaskBarIcon::wxTaskBarIcon(wxTaskBarIconType iconType)
143 if(iconType == wxTBI_DOCK)
144 m_impl = new wxTaskBarIconDockImpl(this);
145 else if(iconType == wxTBI_CUSTOM_STATUSITEM)
146 m_impl = new wxTaskBarIconCustomStatusItemImpl(this);
149 wxFAIL_MSG(wxT("Invalid wxTaskBarIcon type"));
153 wxTaskBarIcon::~wxTaskBarIcon()
157 if ( m_impl->IsIconInstalled() )
158 m_impl->RemoveIcon();
164 bool wxTaskBarIcon::OSXIsStatusItem()
167 return m_impl->IsStatusItem();
174 bool wxTaskBarIcon::IsIconInstalled() const
177 return m_impl->IsIconInstalled();
182 bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
185 return m_impl->SetIcon(icon,tooltip);
190 bool wxTaskBarIcon::RemoveIcon()
193 return m_impl->RemoveIcon();
198 bool wxTaskBarIcon::PopupMenu(wxMenu *menu)
201 return m_impl->PopupMenu(menu);
206 // ============================================================================
208 // ============================================================================
210 wxTaskBarIconImpl::wxTaskBarIconImpl(wxTaskBarIcon* taskBarIcon)
211 : m_taskBarIcon(taskBarIcon), m_eventWindow(new wxTaskBarIconWindow(this))
215 wxTaskBarIconImpl::~wxTaskBarIconImpl()
217 delete m_eventWindow;
220 // ============================================================================
221 // wxTaskBarIconDockImpl
222 // ============================================================================
223 wxTaskBarIconDockImpl *wxTaskBarIconDockImpl::sm_dockIcon = NULL;
225 wxTaskBarIconDockImpl::wxTaskBarIconDockImpl(wxTaskBarIcon *taskBarIcon)
226 : wxTaskBarIconImpl(taskBarIcon)
228 wxASSERT_MSG(!sm_dockIcon, wxT("You should never have more than one dock icon!"));
233 wxTaskBarIconDockImpl::~wxTaskBarIconDockImpl()
235 if(sm_dockIcon == this)
239 WX_NSMenu wxTaskBarIconDockImpl::OSXGetDockHMenu()
242 return sm_dockIcon->OSXDoGetDockHMenu();
247 WX_NSMenu wxTaskBarIconDockImpl::OSXDoGetDockHMenu()
249 wxMenu *dockMenu = CreatePopupMenu();
258 m_pMenu->SetInvokingWindow(m_eventWindow);
262 return (WX_NSMenu)dockMenu->GetHMenu();
265 bool wxTaskBarIconDockImpl::SetIcon(const wxIcon& icon, const wxString& WXUNUSED(tooltip))
267 m_icon.CopyFromIcon(icon);
268 [[NSApplication sharedApplication] setApplicationIconImage:m_icon.GetNSImage()];
272 bool wxTaskBarIconDockImpl::RemoveIcon()
276 [[NSApplication sharedApplication] setApplicationIconImage:nil];
280 bool wxTaskBarIconDockImpl::PopupMenu(wxMenu *WXUNUSED(menu))
282 wxFAIL_MSG(wxT("You cannot force the Dock icon menu to popup"));
286 @interface wxNSAppController(wxTaskBarIconNSApplicationDelegateCategory)
287 - (NSMenu*)applicationDockMenu:(NSApplication *)sender;
290 @implementation wxNSAppController(wxTaskBarIconNSApplicationDelegateCategory)
291 - (NSMenu*)applicationDockMenu:(NSApplication *)sender
295 return wxTaskBarIconDockImpl::OSXGetDockHMenu();
299 // ============================================================================
300 // wxTaskBarIconCustomStatusItemImpl
301 // ============================================================================
303 @implementation wxOSXStatusItemTarget
305 - (void) clickedAction: (id) sender
308 wxMenu *menu = impl->CreatePopupMenu();
311 impl->PopupMenu(menu);
316 - (void)setImplementation: (wxTaskBarIconCustomStatusItemImpl *) theImplementation
318 impl = theImplementation;
321 - (wxTaskBarIconCustomStatusItemImpl*) implementation
329 wxTaskBarIconCustomStatusItemImpl::wxTaskBarIconCustomStatusItemImpl(wxTaskBarIcon *taskBarIcon)
330 : wxTaskBarIconImpl(taskBarIcon)
336 wxTaskBarIconCustomStatusItemImpl::~wxTaskBarIconCustomStatusItemImpl()
340 bool wxTaskBarIconCustomStatusItemImpl::SetIcon(const wxIcon& icon, const wxString& tooltip)
344 m_statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
345 [m_statusItem retain];
347 m_target = [[wxOSXStatusItemTarget alloc] init];
348 [m_target setImplementation:this];
349 [m_statusItem setHighlightMode:YES];
350 [m_statusItem setTarget:m_target];
351 [m_statusItem setAction:@selector(clickedAction:)];
352 [m_statusItem sendActionOn:NSLeftMouseDownMask];
355 m_icon.CopyFromIcon(icon);
357 // status item doesn't scale automatically
359 int dimension = m_icon.GetHeight();
360 if ( m_icon.GetWidth() > dimension )
361 dimension = m_icon.GetWidth();
362 if ( dimension > 16 )
364 wxImage img = m_icon.ConvertToImage();
365 int factor = (dimension+15)/16;
366 m_icon = img.ShrinkBy(factor, factor);
369 [m_statusItem setImage:m_icon.GetNSImage()];
370 wxCFStringRef cfTooltip(tooltip);
371 [m_statusItem setToolTip:cfTooltip.AsNSString()];
375 bool wxTaskBarIconCustomStatusItemImpl::RemoveIcon()
377 [m_statusItem release];
387 bool wxTaskBarIconCustomStatusItemImpl::PopupMenu(wxMenu *menu)
391 menu->SetInvokingWindow(m_eventWindow);
394 [m_statusItem popUpStatusItemMenu:(NSMenu*)menu->GetHMenu()];
396 menu->SetInvokingWindow(NULL);
400 // ============================================================================
401 // wxTaskBarIconWindow
402 // ============================================================================
404 BEGIN_EVENT_TABLE(wxTaskBarIconWindow, wxWindow)
405 EVT_MENU(-1, wxTaskBarIconWindow::OnMenuEvent)
406 EVT_UPDATE_UI(-1, wxTaskBarIconWindow::OnUpdateUIEvent)
409 wxTaskBarIconWindow::wxTaskBarIconWindow(wxTaskBarIconImpl *impl)
414 void wxTaskBarIconWindow::OnMenuEvent(wxCommandEvent& event)
416 m_impl->GetTaskBarIcon()->ProcessEvent(event);
419 void wxTaskBarIconWindow::OnUpdateUIEvent(wxUpdateUIEvent& event)
421 m_impl->GetTaskBarIcon()->ProcessEvent(event);
424 #endif //def wxHAS_TASK_BAR_ICON