/////////////////////////////////////////////////////////////////////////
-// File: src/cocoa/taskbar.mm
+// 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"
#include "wx/taskbar.h"
-#import <AppKit/NSApplication.h>
-#import <AppKit/NSImage.h>
-#import <AppKit/NSMenu.h>
-#import <AppKit/NSMenuItem.h>
-#import <AppKit/NSStatusBar.h>
-#import <AppKit/NSStatusItem.h>
-#import <AppKit/NSView.h>
-#import <Foundation/NSArray.h>
-#import <Foundation/NSEnumerator.h>
-
-#import <AppKit/NSEvent.h>
-#import <AppKit/NSWindow.h>
-#import <AppKit/NSGraphicsContext.h>
-
-#include "wx/cocoa/autorelease.h"
-
-// A category for methods that are only present in Panther's SDK
-@interface NSStatusItem(wxNSStatusItemPrePantherCompatibility)
-- (void)popUpStatusItemMenu:(NSMenu *)menu;
-@end
+#include "wx/osx/private.h"
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.
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();
};
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
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.
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;
}
// ============================================================================
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))
{
- wxAutoNSAutoreleasePool 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()
{
}
-bool wxTaskBarIconCustomStatusItemImpl::SetIcon(const wxIcon& icon, const wxString& tooltip)
+bool wxTaskBarIconCustomStatusItemImpl::SetIcon(const wxIcon& icon, const wxString& WXUNUSED(tooltip))
{
- wxAutoNSAutoreleasePool 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 setTarget:m_target];
+ [m_statusItem setAction:@selector(clickedAction:)];
+ [m_statusItem sendActionOn:NSLeftMouseDownMask];
}
- if(!m_iconWindow)
- m_iconWindow= new wxTaskBarIconWindowCustom(this);
- static_cast<wxTaskBarIconWindowCustom*>(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()];
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;
}
// ============================================================================
// 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