X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/7ac5e1c9088dedba495f5af5dbfb23ca89487a78..ab67e8874db324fab5223cc8d5dff8a8de3e2b77:/src/osx/cocoa/taskbar.mm diff --git a/src/osx/cocoa/taskbar.mm b/src/osx/cocoa/taskbar.mm index b6d327b863..20d09701ac 100644 --- a/src/osx/cocoa/taskbar.mm +++ b/src/osx/cocoa/taskbar.mm @@ -1,18 +1,19 @@ ///////////////////////////////////////////////////////////////////////// // File: src/osx/cocoa/taskbar.mm // Purpose: Implements wxTaskBarIcon class -// Author: David Elliott +// Author: David Elliott, Stefan Csomor // Modified by: // Created: 2004/01/24 -// RCS-ID: $Id: taskbar.mm 35650 2005-09-23 12:56:45Z MR $ -// Copyright: (c) 2004 David Elliott +// RCS-ID: $Id$ +// Copyright: (c) 2004 David Elliott, Stefan Csomor // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////// #include "wx/wxprec.h" -#ifdef wxUSE_TASKBARICON +#if wxUSE_TASKBARICON #ifndef WX_PRECOMP + #include "wx/toplevel.h" #include "wx/menu.h" #include "wx/icon.h" #include "wx/log.h" @@ -23,13 +24,30 @@ #include "wx/osx/private.h" -// A category for methods that are only present in Panther's SDK -@interface NSStatusItem(wxNSStatusItemPrePantherCompatibility) -- (void)popUpStatusItemMenu:(NSMenu *)menu; -@end - class wxTaskBarIconWindow; +//----------------------------------------------------------------------------- +// +// wxTaskBarIconWindow +// +// Event handler for menus +// NB: Since wxWindows in Mac HAVE to have parents we need this to be +// a top level window... +//----------------------------------------------------------------------------- + +class wxTaskBarIconWindow : public wxTopLevelWindow +{ +public: + wxTaskBarIconWindow(wxTaskBarIconImpl *impl); + + void OnMenuEvent(wxCommandEvent& event); + void OnUpdateUIEvent(wxUpdateUIEvent& event); + +private: + wxTaskBarIconImpl *m_impl; + DECLARE_EVENT_TABLE() +}; + // ============================================================================ // wxTaskBarIconImpl // Base class for the various Cocoa implementations. @@ -37,23 +55,27 @@ class wxTaskBarIconWindow; class wxTaskBarIconImpl { public: - wxTaskBarIconImpl(wxTaskBarIcon *taskBarIcon) - : m_taskBarIcon(taskBarIcon) - , m_iconWindow(NULL) - {} + wxTaskBarIconImpl(wxTaskBarIcon *taskBarIcon); + + virtual bool IsStatusItem() const { return false; } + virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString) = 0; virtual bool RemoveIcon() = 0; + + bool IsIconInstalled() const { return m_icon.IsOk(); } + virtual bool PopupMenu(wxMenu *menu) = 0; virtual ~wxTaskBarIconImpl(); inline wxTaskBarIcon* GetTaskBarIcon() { return m_taskBarIcon; } wxMenu * CreatePopupMenu() { return m_taskBarIcon->CreatePopupMenu(); } - - DECLARE_NO_COPY_CLASS(wxTaskBarIconImpl) - + + wxDECLARE_NO_COPY_CLASS(wxTaskBarIconImpl); + protected: wxTaskBarIcon *m_taskBarIcon; - wxTaskBarIconWindow *m_iconWindow; + wxBitmap m_icon; + wxTaskBarIconWindow *m_eventWindow; private: wxTaskBarIconImpl(); }; @@ -71,16 +93,24 @@ public: virtual bool RemoveIcon(); virtual bool PopupMenu(wxMenu *menu); - static WX_NSMenu CocoaGetDockNSMenu(); + static WX_NSMenu OSXGetDockHMenu(); protected: - WX_NSMenu CocoaDoGetDockNSMenu(); - WX_NSImage m_originalDockIcon; + WX_NSMenu OSXDoGetDockHMenu(); // There can be only one Dock icon, so make sure we keep it that way static wxTaskBarIconDockImpl *sm_dockIcon; private: wxTaskBarIconDockImpl(); + wxMenu *m_pMenu; }; +class wxTaskBarIconCustomStatusItemImpl; + +@interface wxOSXStatusItemTarget : NSObject +{ + wxTaskBarIconCustomStatusItemImpl* impl; +} +@end + // ============================================================================ // wxTaskBarIconCustomStatusItemImpl // An implementation using an NSStatusItem with a custom NSView @@ -90,52 +120,19 @@ class wxTaskBarIconCustomStatusItemImpl: public wxTaskBarIconImpl public: wxTaskBarIconCustomStatusItemImpl(wxTaskBarIcon *taskBarIcon); virtual ~wxTaskBarIconCustomStatusItemImpl(); + + virtual bool IsStatusItem() const { return true; } + virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString); virtual bool RemoveIcon(); virtual bool PopupMenu(wxMenu *menu); protected: - NSStatusItem *m_cocoaNSStatusItem; + NSStatusItem *m_statusItem; + wxOSXStatusItemTarget *m_target; private: wxTaskBarIconCustomStatusItemImpl(); }; -// ============================================================================ -// wxTaskBarIconWindow -// Used by all implementations to forward events from the wxMenu -// ============================================================================ -class wxTaskBarIconWindow: public wxWindow -{ - DECLARE_EVENT_TABLE() -public: - wxTaskBarIconWindow(wxTaskBarIconImpl *taskBarIconImpl) - : wxWindow(NULL,-1) - , m_taskBarIconImpl(taskBarIconImpl) - { wxASSERT(m_taskBarIconImpl); } - - void OnMenuEvent(wxCommandEvent& event); -protected: - wxTaskBarIconImpl *m_taskBarIconImpl; -}; - -// ============================================================================ -// wxTaskBarIconWindowCustom -// Used by the CustomStatusIcon implementation for the custom NSView. -// ============================================================================ -class wxTaskBarIconWindowCustom: public wxTaskBarIconWindow -{ - DECLARE_EVENT_TABLE() -public: - wxTaskBarIconWindowCustom(wxTaskBarIconImpl *taskBarIconImpl) - : wxTaskBarIconWindow(taskBarIconImpl) - {} - void SetIcon(const wxIcon& icon) - { m_icon = icon; } - void OnMouseEvent(wxMouseEvent &event); - void OnPaint(wxPaintEvent &event); -protected: - wxIcon m_icon; -}; - // ============================================================================ // wxTaskBarIcon implementation // The facade class. @@ -144,9 +141,9 @@ IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler) wxTaskBarIcon::wxTaskBarIcon(wxTaskBarIconType iconType) { - if(iconType == DOCK) + if(iconType == wxTBI_DOCK) m_impl = new wxTaskBarIconDockImpl(this); - else if(iconType == CUSTOM_STATUSITEM) + else if(iconType == wxTBI_CUSTOM_STATUSITEM) m_impl = new wxTaskBarIconCustomStatusItemImpl(this); else { m_impl = NULL; @@ -156,39 +153,69 @@ wxTaskBarIcon::wxTaskBarIcon(wxTaskBarIconType iconType) wxTaskBarIcon::~wxTaskBarIcon() { - delete m_impl; + if ( m_impl ) + { + if ( m_impl->IsIconInstalled() ) + m_impl->RemoveIcon(); + delete m_impl; + m_impl = NULL; + } +} + +bool wxTaskBarIcon::OSXIsStatusItem() +{ + if ( m_impl ) + return m_impl->IsStatusItem(); + + return false; } // Operations bool wxTaskBarIcon::IsIconInstalled() const -{ +{ + if ( m_impl ) + return m_impl->IsIconInstalled(); + return false; } bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip) { - return m_impl->SetIcon(icon,tooltip); + if ( m_impl ) + return m_impl->SetIcon(icon,tooltip); + + return false; } bool wxTaskBarIcon::RemoveIcon() { - return m_impl->RemoveIcon(); + if ( m_impl ) + return m_impl->RemoveIcon(); + + return false; } bool wxTaskBarIcon::PopupMenu(wxMenu *menu) { - return m_impl->PopupMenu(menu); + if ( m_impl ) + return m_impl->PopupMenu(menu); + + return false; } // ============================================================================ // wxTaskBarIconImpl // ============================================================================ +wxTaskBarIconImpl::wxTaskBarIconImpl(wxTaskBarIcon* taskBarIcon) + : m_taskBarIcon(taskBarIcon), m_eventWindow(new wxTaskBarIconWindow(this)) +{ +} + wxTaskBarIconImpl::~wxTaskBarIconImpl() { -// wxAutoNSAutoreleasePool pool; - delete m_iconWindow; + delete m_eventWindow; } // ============================================================================ @@ -199,67 +226,112 @@ wxTaskBarIconDockImpl *wxTaskBarIconDockImpl::sm_dockIcon = NULL; wxTaskBarIconDockImpl::wxTaskBarIconDockImpl(wxTaskBarIcon *taskBarIcon) : wxTaskBarIconImpl(taskBarIcon) { - m_originalDockIcon = nil; wxASSERT_MSG(!sm_dockIcon, wxT("You should never have more than one dock icon!")); sm_dockIcon = this; + m_pMenu = NULL; } wxTaskBarIconDockImpl::~wxTaskBarIconDockImpl() { -// wxAutoNSAutoreleasePool pool; if(sm_dockIcon == this) sm_dockIcon = NULL; } -WX_NSMenu wxTaskBarIconDockImpl::CocoaGetDockNSMenu() +WX_NSMenu wxTaskBarIconDockImpl::OSXGetDockHMenu() { if(sm_dockIcon) - return sm_dockIcon->CocoaDoGetDockNSMenu(); + return sm_dockIcon->OSXDoGetDockHMenu(); + return nil; } -WX_NSMenu wxTaskBarIconDockImpl::CocoaDoGetDockNSMenu() +WX_NSMenu wxTaskBarIconDockImpl::OSXDoGetDockHMenu() { wxMenu *dockMenu = CreatePopupMenu(); + if(!dockMenu) return nil; - if(!m_iconWindow) - m_iconWindow = new wxTaskBarIconWindow(this); - dockMenu->SetInvokingWindow(m_iconWindow); - dockMenu->UpdateUI(); - //dockMenu->SetCocoaDeletes(true); + + wxDELETE(m_pMenu); + + m_pMenu = dockMenu; + + m_pMenu->SetInvokingWindow(m_eventWindow); + + m_pMenu->UpdateUI(); + return (WX_NSMenu)dockMenu->GetHMenu(); } -bool wxTaskBarIconDockImpl::SetIcon(const wxIcon& icon, const wxString& tooltip) +bool wxTaskBarIconDockImpl::SetIcon(const wxIcon& icon, const wxString& WXUNUSED(tooltip)) { - wxMacAutoreleasePool pool; - m_originalDockIcon = [[[NSApplication sharedApplication] applicationIconImage] retain]; - //[[NSApplication sharedApplication] setApplicationIconImage:icon.GetNSImage()]; + m_icon.CopyFromIcon(icon); + [[NSApplication sharedApplication] setApplicationIconImage:m_icon.GetNSImage()]; return true; } bool wxTaskBarIconDockImpl::RemoveIcon() { - [[NSApplication sharedApplication] setApplicationIconImage:m_originalDockIcon]; - [m_originalDockIcon release]; + wxDELETE(m_pMenu); + m_icon = wxBitmap(); + [[NSApplication sharedApplication] setApplicationIconImage:nil]; return true; } -bool wxTaskBarIconDockImpl::PopupMenu(wxMenu *menu) +bool wxTaskBarIconDockImpl::PopupMenu(wxMenu *WXUNUSED(menu)) { wxFAIL_MSG(wxT("You cannot force the Dock icon menu to popup")); return false; } +@interface wxNSAppController(wxTaskBarIconNSApplicationDelegateCategory) +- (NSMenu*)applicationDockMenu:(NSApplication *)sender; +@end + +@implementation wxNSAppController(wxTaskBarIconNSApplicationDelegateCategory) +- (NSMenu*)applicationDockMenu:(NSApplication *)sender +{ + wxUnusedVar(sender); + + return wxTaskBarIconDockImpl::OSXGetDockHMenu(); +} +@end // ============================================================================ // wxTaskBarIconCustomStatusItemImpl // ============================================================================ + +@implementation wxOSXStatusItemTarget + +- (void) clickedAction: (id) sender +{ + wxUnusedVar(sender); + wxMenu *menu = impl->CreatePopupMenu(); + if (menu) + { + impl->PopupMenu(menu); + delete menu; + } +} + +- (void)setImplementation: (wxTaskBarIconCustomStatusItemImpl *) theImplementation +{ + impl = theImplementation; +} + +- (wxTaskBarIconCustomStatusItemImpl*) implementation +{ + return impl; +} + +@end + + wxTaskBarIconCustomStatusItemImpl::wxTaskBarIconCustomStatusItemImpl(wxTaskBarIcon *taskBarIcon) : wxTaskBarIconImpl(taskBarIcon) { - m_cocoaNSStatusItem = nil; + m_statusItem = nil; + m_target = nil; } wxTaskBarIconCustomStatusItemImpl::~wxTaskBarIconCustomStatusItemImpl() @@ -268,50 +340,60 @@ wxTaskBarIconCustomStatusItemImpl::~wxTaskBarIconCustomStatusItemImpl() bool wxTaskBarIconCustomStatusItemImpl::SetIcon(const wxIcon& icon, const wxString& tooltip) { - wxMacAutoreleasePool pool; - if(!m_cocoaNSStatusItem) + if(!m_statusItem) { - m_cocoaNSStatusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; - [m_cocoaNSStatusItem retain]; + m_statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; + [m_statusItem retain]; + + m_target = [[wxOSXStatusItemTarget alloc] init]; + [m_target setImplementation:this]; + [m_statusItem setHighlightMode:YES]; + [m_statusItem setTarget:m_target]; + [m_statusItem setAction:@selector(clickedAction:)]; + [m_statusItem sendActionOn:NSLeftMouseDownMask]; } - if(!m_iconWindow) - m_iconWindow= new wxTaskBarIconWindowCustom(this); - static_cast(m_iconWindow)->SetIcon(icon); - // FIXME: no less than 10 because most icon types don't work yet - // and this allows us to see how task bar icons would work - [(NSView*)m_iconWindow->GetHandle() setFrame:NSMakeRect(0.0,0.0,wxMax(10,icon.GetWidth()),[[NSStatusBar systemStatusBar] thickness])]; - [m_cocoaNSStatusItem setView:(NSView*)m_iconWindow->GetHandle()]; + + m_icon.CopyFromIcon(icon); + + // status item doesn't scale automatically + + int dimension = m_icon.GetHeight(); + if ( m_icon.GetWidth() > dimension ) + dimension = m_icon.GetWidth(); + if ( dimension > 16 ) + { + wxImage img = m_icon.ConvertToImage(); + int factor = (dimension+15)/16; + m_icon = img.ShrinkBy(factor, factor); + } + + [m_statusItem setImage:m_icon.GetNSImage()]; + wxCFStringRef cfTooltip(tooltip); + [m_statusItem setToolTip:cfTooltip.AsNSString()]; return true; } bool wxTaskBarIconCustomStatusItemImpl::RemoveIcon() { - [m_cocoaNSStatusItem release]; - m_cocoaNSStatusItem = nil; - delete m_iconWindow; - m_iconWindow = NULL; + [m_statusItem release]; + m_statusItem = nil; + [m_target release]; + m_target = nil; + + m_icon = wxBitmap(); + return true; } bool wxTaskBarIconCustomStatusItemImpl::PopupMenu(wxMenu *menu) { wxASSERT(menu); - menu->SetInvokingWindow(m_iconWindow); + + menu->SetInvokingWindow(m_eventWindow); menu->UpdateUI(); - if([m_cocoaNSStatusItem respondsToSelector:@selector(popUpStatusItemMenu:)]) - { // OS X >= 10.3 - [m_cocoaNSStatusItem popUpStatusItemMenu:(NSMenu*)menu->GetHMenu()]; - } - else - { // pretty good fake for OS X < 10.3 - NSEvent *nsevent = [NSEvent mouseEventWithType:NSLeftMouseDown - location:NSMakePoint(-1.0,-4.0) modifierFlags:0 timestamp:0 - windowNumber:[[(NSView*)m_iconWindow->GetHandle() window] windowNumber] - context:[NSGraphicsContext currentContext] - eventNumber:0 clickCount:1 pressure:0.0]; - [NSMenu popUpContextMenu:menu->GetHMenu() withEvent:nsevent forView:(NSView*)m_iconWindow->GetHandle()]; - } + [m_statusItem popUpStatusItemMenu:(NSMenu*)menu->GetHMenu()]; + menu->SetInvokingWindow(NULL); return true; } @@ -319,53 +401,25 @@ bool wxTaskBarIconCustomStatusItemImpl::PopupMenu(wxMenu *menu) // ============================================================================ // wxTaskBarIconWindow // ============================================================================ + BEGIN_EVENT_TABLE(wxTaskBarIconWindow, wxWindow) - EVT_MENU(-1, wxTaskBarIconWindow::OnMenuEvent) +EVT_MENU(-1, wxTaskBarIconWindow::OnMenuEvent) +EVT_UPDATE_UI(-1, wxTaskBarIconWindow::OnUpdateUIEvent) END_EVENT_TABLE() -void wxTaskBarIconWindow::OnMenuEvent(wxCommandEvent &event) +wxTaskBarIconWindow::wxTaskBarIconWindow(wxTaskBarIconImpl *impl) +: m_impl(impl) { - m_taskBarIconImpl->GetTaskBarIcon()->ProcessEvent(event); } -// ============================================================================ -// wxTaskBarIconWindowCustom -// ============================================================================ -BEGIN_EVENT_TABLE(wxTaskBarIconWindowCustom, wxTaskBarIconWindow) - EVT_MOUSE_EVENTS(wxTaskBarIconWindowCustom::OnMouseEvent) - EVT_PAINT(wxTaskBarIconWindowCustom::OnPaint) -END_EVENT_TABLE() - -void wxTaskBarIconWindowCustom::OnMouseEvent(wxMouseEvent &event) -{ - wxEventType tbEventType = 0; - if(event.GetEventType() == wxEVT_MOTION) - tbEventType = wxEVT_TASKBAR_MOVE; - else if(event.GetEventType() == wxEVT_LEFT_DOWN) - tbEventType = wxEVT_TASKBAR_LEFT_DOWN; - else if(event.GetEventType() == wxEVT_LEFT_UP) - tbEventType = wxEVT_TASKBAR_LEFT_UP; - else if(event.GetEventType() == wxEVT_RIGHT_DOWN) - tbEventType = wxEVT_TASKBAR_RIGHT_DOWN; - else if(event.GetEventType() == wxEVT_RIGHT_UP) - tbEventType = wxEVT_TASKBAR_RIGHT_UP; - else if(event.GetEventType() == wxEVT_LEFT_DCLICK) - tbEventType = wxEVT_TASKBAR_LEFT_DCLICK; - else if(event.GetEventType() == wxEVT_RIGHT_DCLICK) - tbEventType = wxEVT_TASKBAR_RIGHT_DCLICK; - else - return; - wxTaskBarIconEvent tbiEvent(tbEventType,m_taskBarIconImpl->GetTaskBarIcon()); - m_taskBarIconImpl->GetTaskBarIcon()->ProcessEvent(tbiEvent); +void wxTaskBarIconWindow::OnMenuEvent(wxCommandEvent& event) +{ + m_impl->GetTaskBarIcon()->ProcessEvent(event); } -void wxTaskBarIconWindowCustom::OnPaint(wxPaintEvent &event) +void wxTaskBarIconWindow::OnUpdateUIEvent(wxUpdateUIEvent& event) { - wxPaintDC dc(this); - // FIXME: This is a temporary hack until we can see real icons - dc.SetBackground(wxBrush(*wxBLUE)); - dc.Clear(); - dc.DrawIcon(m_icon,0,0); + m_impl->GetTaskBarIcon()->ProcessEvent(event); } #endif //def wxHAS_TASK_BAR_ICON