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