Update OpenVMS makefile
[wxWidgets.git] / src / osx / cocoa / taskbar.mm
1 /////////////////////////////////////////////////////////////////////////
2 // File:        src/osx/cocoa/taskbar.mm
3 // Purpose:     Implements wxTaskBarIcon class
4 // Author:      David Elliott, Stefan Csomor
5 // Modified by:
6 // Created:     2004/01/24
7 // Copyright:   (c) 2004 David Elliott, Stefan Csomor
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////
10
11 #include "wx/wxprec.h"
12 #if wxUSE_TASKBARICON
13
14 #ifndef WX_PRECOMP
15     #include "wx/toplevel.h"
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 class wxTaskBarIconWindow;
27
28 //-----------------------------------------------------------------------------
29 //
30 //  wxTaskBarIconWindow
31 //
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 //-----------------------------------------------------------------------------
36
37 class wxTaskBarIconWindow : public wxTopLevelWindow
38 {
39 public:
40     wxTaskBarIconWindow(wxTaskBarIconImpl *impl);
41
42     void OnMenuEvent(wxCommandEvent& event);
43     void OnUpdateUIEvent(wxUpdateUIEvent& event);
44     
45 private:
46     wxTaskBarIconImpl *m_impl;
47     DECLARE_EVENT_TABLE()
48 };
49
50 // ============================================================================
51 // wxTaskBarIconImpl
52 //     Base class for the various Cocoa implementations.
53 // ============================================================================
54 class wxTaskBarIconImpl
55 {
56 public:
57     wxTaskBarIconImpl(wxTaskBarIcon *taskBarIcon);
58     
59     virtual bool IsStatusItem() const { return false; }
60
61     virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString) = 0;
62     virtual bool RemoveIcon() = 0;
63     
64     bool IsIconInstalled() const { return m_icon.IsOk(); }
65         
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(); }
71
72     wxDECLARE_NO_COPY_CLASS(wxTaskBarIconImpl);
73
74 protected:
75     wxTaskBarIcon *m_taskBarIcon;
76     wxBitmap m_icon;
77     wxTaskBarIconWindow *m_eventWindow;
78 private:
79     wxTaskBarIconImpl();
80 };
81
82 // ============================================================================
83 // wxTaskBarIconDockImpl
84 //     An implementation using the Dock icon.
85 // ============================================================================
86 class wxTaskBarIconDockImpl: public wxTaskBarIconImpl
87 {
88 public:
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);
94
95     static WX_NSMenu OSXGetDockHMenu();
96 protected:
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;
100 private:
101     wxTaskBarIconDockImpl();
102     wxMenu             *m_pMenu;
103 };
104
105 class wxTaskBarIconCustomStatusItemImpl;
106
107 @interface wxOSXStatusItemTarget : NSObject
108 {
109     wxTaskBarIconCustomStatusItemImpl* impl;
110 }
111 @end
112
113 // ============================================================================
114 // wxTaskBarIconCustomStatusItemImpl
115 //     An implementation using an NSStatusItem with a custom NSView
116 // ============================================================================
117 class wxTaskBarIconCustomStatusItemImpl: public wxTaskBarIconImpl
118 {
119 public:
120     wxTaskBarIconCustomStatusItemImpl(wxTaskBarIcon *taskBarIcon);
121     virtual ~wxTaskBarIconCustomStatusItemImpl();
122     
123     virtual bool IsStatusItem() const { return true; }
124
125     virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString);
126     virtual bool RemoveIcon();
127     virtual bool PopupMenu(wxMenu *menu);
128 protected:
129     NSStatusItem *m_statusItem;
130     wxOSXStatusItemTarget *m_target;
131 private:
132     wxTaskBarIconCustomStatusItemImpl();
133 };
134
135 // ============================================================================
136 // wxTaskBarIcon implementation
137 //     The facade class.
138 // ============================================================================
139 IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler)
140
141 wxTaskBarIcon::wxTaskBarIcon(wxTaskBarIconType iconType)
142 {
143     if(iconType == wxTBI_DOCK)
144         m_impl = new wxTaskBarIconDockImpl(this);
145     else if(iconType == wxTBI_CUSTOM_STATUSITEM)
146         m_impl = new wxTaskBarIconCustomStatusItemImpl(this);
147     else
148     {   m_impl = NULL;
149         wxFAIL_MSG(wxT("Invalid wxTaskBarIcon type"));
150     }
151 }
152
153 wxTaskBarIcon::~wxTaskBarIcon()
154 {
155     if ( m_impl )
156     {
157         if ( m_impl->IsIconInstalled() )
158             m_impl->RemoveIcon();
159         delete m_impl;
160         m_impl = NULL;
161     }
162 }
163
164 bool wxTaskBarIcon::OSXIsStatusItem()
165 {
166     if ( m_impl )
167         return m_impl->IsStatusItem();
168
169     return false;
170 }
171
172 // Operations
173
174 bool wxTaskBarIcon::IsIconInstalled() const
175 {
176     if ( m_impl )
177         return m_impl->IsIconInstalled();
178     
179     return false;
180 }
181
182 bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
183 {
184     if ( m_impl )
185         return m_impl->SetIcon(icon,tooltip);
186
187     return false;
188 }
189
190 bool wxTaskBarIcon::RemoveIcon()
191 {
192     if ( m_impl )
193         return m_impl->RemoveIcon();
194
195     return false;
196 }
197
198 bool wxTaskBarIcon::PopupMenu(wxMenu *menu)
199 {
200     if ( m_impl )
201         return m_impl->PopupMenu(menu);
202
203     return false;
204 }
205
206 // ============================================================================
207 // wxTaskBarIconImpl
208 // ============================================================================
209
210 wxTaskBarIconImpl::wxTaskBarIconImpl(wxTaskBarIcon* taskBarIcon)
211  : m_taskBarIcon(taskBarIcon), m_eventWindow(new wxTaskBarIconWindow(this))
212 {
213 }
214
215 wxTaskBarIconImpl::~wxTaskBarIconImpl()
216 {
217     delete m_eventWindow;
218 }
219
220 // ============================================================================
221 // wxTaskBarIconDockImpl
222 // ============================================================================
223 wxTaskBarIconDockImpl *wxTaskBarIconDockImpl::sm_dockIcon = NULL;
224
225 wxTaskBarIconDockImpl::wxTaskBarIconDockImpl(wxTaskBarIcon *taskBarIcon)
226 :   wxTaskBarIconImpl(taskBarIcon)
227 {
228     wxASSERT_MSG(!sm_dockIcon, wxT("You should never have more than one dock icon!"));
229     sm_dockIcon = this;
230     m_pMenu = NULL;
231 }
232
233 wxTaskBarIconDockImpl::~wxTaskBarIconDockImpl()
234 {
235     if(sm_dockIcon == this)
236         sm_dockIcon = NULL;
237 }
238
239 WX_NSMenu wxTaskBarIconDockImpl::OSXGetDockHMenu()
240 {
241     if(sm_dockIcon)
242         return sm_dockIcon->OSXDoGetDockHMenu();
243     
244     return nil;
245 }
246
247 WX_NSMenu wxTaskBarIconDockImpl::OSXDoGetDockHMenu()
248 {
249     wxMenu *dockMenu = CreatePopupMenu();
250
251     if(!dockMenu)
252         return nil;
253     
254     wxDELETE(m_pMenu);
255
256     m_pMenu = dockMenu;
257     
258     m_pMenu->SetInvokingWindow(m_eventWindow);
259     
260     m_pMenu->UpdateUI();
261     
262     return (WX_NSMenu)dockMenu->GetHMenu();
263 }
264
265 bool wxTaskBarIconDockImpl::SetIcon(const wxIcon& icon, const wxString& WXUNUSED(tooltip))
266 {
267     m_icon.CopyFromIcon(icon);
268     [[NSApplication sharedApplication] setApplicationIconImage:m_icon.GetNSImage()];
269     return true;
270 }
271
272 bool wxTaskBarIconDockImpl::RemoveIcon()
273 {
274     wxDELETE(m_pMenu);
275     m_icon = wxBitmap();
276     [[NSApplication sharedApplication] setApplicationIconImage:nil];
277     return true;
278 }
279
280 bool wxTaskBarIconDockImpl::PopupMenu(wxMenu *WXUNUSED(menu))
281 {
282     wxFAIL_MSG(wxT("You cannot force the Dock icon menu to popup"));
283     return false;
284 }
285
286 @interface wxNSAppController(wxTaskBarIconNSApplicationDelegateCategory)
287 - (NSMenu*)applicationDockMenu:(NSApplication *)sender;
288 @end
289
290 @implementation wxNSAppController(wxTaskBarIconNSApplicationDelegateCategory)
291 - (NSMenu*)applicationDockMenu:(NSApplication *)sender
292 {
293     wxUnusedVar(sender);
294     
295     return wxTaskBarIconDockImpl::OSXGetDockHMenu();
296 }
297 @end
298
299 // ============================================================================
300 // wxTaskBarIconCustomStatusItemImpl
301 // ============================================================================
302
303 @implementation wxOSXStatusItemTarget
304
305 - (void) clickedAction: (id) sender
306 {
307     wxUnusedVar(sender);
308     wxMenu *menu = impl->CreatePopupMenu();
309     if (menu)
310     {
311         impl->PopupMenu(menu);
312         delete menu;
313     }    
314 }
315
316 - (void)setImplementation: (wxTaskBarIconCustomStatusItemImpl *) theImplementation
317 {
318     impl = theImplementation;
319 }
320
321 - (wxTaskBarIconCustomStatusItemImpl*) implementation
322 {
323     return impl;
324 }
325
326 @end
327
328
329 wxTaskBarIconCustomStatusItemImpl::wxTaskBarIconCustomStatusItemImpl(wxTaskBarIcon *taskBarIcon)
330 :   wxTaskBarIconImpl(taskBarIcon)
331 {
332     m_statusItem = nil;
333     m_target = nil;
334 }
335
336 wxTaskBarIconCustomStatusItemImpl::~wxTaskBarIconCustomStatusItemImpl()
337 {
338 }
339
340 bool wxTaskBarIconCustomStatusItemImpl::SetIcon(const wxIcon& icon, const wxString& tooltip)
341 {
342     if(!m_statusItem)
343     {
344         m_statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
345         [m_statusItem retain];
346
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];
353     }
354
355     m_icon.CopyFromIcon(icon);
356     
357     // status item doesn't scale automatically
358     
359     int dimension = m_icon.GetHeight();
360     if ( m_icon.GetWidth() > dimension )
361         dimension = m_icon.GetWidth();
362     if ( dimension > 16 )
363     {
364         wxImage img = m_icon.ConvertToImage();
365         int factor = (dimension+15)/16;
366         m_icon = img.ShrinkBy(factor, factor);
367     }
368
369     [m_statusItem setImage:m_icon.GetNSImage()];
370     wxCFStringRef cfTooltip(tooltip);
371     [m_statusItem setToolTip:cfTooltip.AsNSString()];
372     return true;
373 }
374
375 bool wxTaskBarIconCustomStatusItemImpl::RemoveIcon()
376 {
377     [m_statusItem release];
378     m_statusItem = nil;
379     [m_target release];
380     m_target = nil;
381     
382     m_icon = wxBitmap();
383     
384     return true;
385 }
386
387 bool wxTaskBarIconCustomStatusItemImpl::PopupMenu(wxMenu *menu)
388 {
389     wxASSERT(menu);
390
391     menu->SetInvokingWindow(m_eventWindow);
392     menu->UpdateUI();
393
394     [m_statusItem popUpStatusItemMenu:(NSMenu*)menu->GetHMenu()];
395
396     menu->SetInvokingWindow(NULL);
397     return true;
398 }
399
400 // ============================================================================
401 // wxTaskBarIconWindow
402 // ============================================================================
403
404 BEGIN_EVENT_TABLE(wxTaskBarIconWindow, wxWindow)
405 EVT_MENU(-1, wxTaskBarIconWindow::OnMenuEvent)
406 EVT_UPDATE_UI(-1, wxTaskBarIconWindow::OnUpdateUIEvent)
407 END_EVENT_TABLE()
408
409 wxTaskBarIconWindow::wxTaskBarIconWindow(wxTaskBarIconImpl *impl) 
410 : m_impl(impl)
411 {
412 }
413
414 void wxTaskBarIconWindow::OnMenuEvent(wxCommandEvent& event)
415 {
416     m_impl->GetTaskBarIcon()->ProcessEvent(event);
417 }
418
419 void wxTaskBarIconWindow::OnUpdateUIEvent(wxUpdateUIEvent& event)
420 {
421     m_impl->GetTaskBarIcon()->ProcessEvent(event);
422 }
423
424 #endif //def wxHAS_TASK_BAR_ICON