From f1d9e1ec6b596ec336e8e68fdec78244088d5c25 Mon Sep 17 00:00:00 2001 From: David Elliott Date: Fri, 15 Oct 2004 22:52:28 +0000 Subject: [PATCH] wxCocoa: Added wxTaskBarIcon git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@29901 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- build/bakefiles/files.bkl | 10 + configure.in | 2 +- include/wx/cocoa/taskbar.h | 53 +++++ include/wx/features.h | 5 +- include/wx/taskbar.h | 4 +- src/cocoa/taskbar.mm | 402 +++++++++++++++++++++++++++++++++++++ 6 files changed, 472 insertions(+), 4 deletions(-) create mode 100644 include/wx/cocoa/taskbar.h create mode 100644 src/cocoa/taskbar.mm diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index 02bdec6126..9c9ebcda16 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -2200,6 +2200,14 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! wx/mac/carbon/taskbarosx.h + + src/cocoa/taskbar.mm + src/common/taskbarcmn.cpp + + + include/wx/cocoa/taskbar.h + + src/os2/joystick.cpp src/os2/sound.cpp @@ -2580,6 +2588,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! $(ADVANCED_MSW_SRC) $(ADVANCED_MSW_ONLY_SRC) $(ADVANCED_MSW_SRC) $(ADVANCED_MAC_SRC) + $(ADVANCED_COCOA_SRC) $(ADVANCED_UNIX_SRC) $(ADVANCED_UNIX_SRC) $(ADVANCED_GTK_SRC) $(ADVANCED_UNIX_SRC) @@ -2589,6 +2598,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! $(ADVANCED_MSW_HDR) $(ADVANCED_MSW_ONLY_HDR) $(ADVANCED_MSW_HDR) $(ADVANCED_MAC_HDR) + $(ADVANCED_COCOA_HDR) $(ADVANCED_UNIX_HDR) $(ADVANCED_GTK_HDR) $(ADVANCED_UNIX_HDR) $(ADVANCED_UNIX_HDR) diff --git a/configure.in b/configure.in index aac7f2c4a3..aaecc87202 100644 --- a/configure.in +++ b/configure.in @@ -5610,7 +5610,7 @@ fi if test "$wxUSE_SYSTEM_OPTIONS" = "yes"; then AC_DEFINE(wxUSE_SYSTEM_OPTIONS) if test "$TOOLKIT" = "MSW" -o "$TOOLKIT" = "GTK" -o "$TOOLKIT" = "X11" -o \ - "$TOOLKIT" = "MOTIF"; then + "$TOOLKIT" = "MOTIF" -o "$TOOLKIT" = "COCOA"; then SAMPLES_SUBDIRS="$SAMPLES_SUBDIRS taskbar" fi fi diff --git a/include/wx/cocoa/taskbar.h b/include/wx/cocoa/taskbar.h new file mode 100644 index 0000000000..4316e92ebb --- /dev/null +++ b/include/wx/cocoa/taskbar.h @@ -0,0 +1,53 @@ +///////////////////////////////////////////////////////////////////////// +// File: wx/cocoa/taskbar.h +// Purpose: Defines wxTaskBarIcon class +// Author: David Elliott +// Modified by: +// Created: 2004/01/24 +// RCS-ID: $Id$ +// Copyright: (c) 2004 David Elliott +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////// + +#ifndef _WX_COCOA_TASKBAR_H__ +#define _WX_COCOA_TASKBAR_H__ + +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) +#pragma interface "taskbar.h" +#endif + +#include "wx/icon.h" + +class WXDLLEXPORT wxIcon; +class WXDLLEXPORT wxMenu; + +class wxTaskBarIconCocoaImpl; +class wxTaskBarIconDockImpl; + +class WXDLLEXPORT wxTaskBarIcon : public wxTaskBarIconBase +{ + friend class wxTaskBarIconDockImpl; + DECLARE_DYNAMIC_CLASS_NO_COPY(wxTaskBarIcon) +public: + //type of taskbar item to create (currently only DOCK is implemented) + enum wxTaskBarIconType + { DOCK + , CUSTOM_STATUSITEM +// , STATUSITEM // TODO: Implement using NSStatusItem w/o custom NSView +// , MENUEXTRA // Menu extras require undocumented hacks + , DEFAULT_TYPE = CUSTOM_STATUSITEM + }; + + // Only one wxTaskBarIcon can be of the Dock type so by default + // create NSStatusItem for maximum source compatibility. + wxTaskBarIcon(wxTaskBarIconType iconType = DEFAULT_TYPE); + virtual ~wxTaskBarIcon(); + + bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString); + bool RemoveIcon(); + bool PopupMenu(wxMenu *menu); //, int x, int y); +protected: + wxTaskBarIconCocoaImpl *m_impl; +}; + +#endif // _WX_COCOA_TASKBAR_H__ diff --git a/include/wx/features.h b/include/wx/features.h index 6345fec778..d372e97f0d 100644 --- a/include/wx/features.h +++ b/include/wx/features.h @@ -30,8 +30,9 @@ #endif /* taskbar is implemented in the major ports */ -#if defined(__WXMSW__) || \ - defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXX11__) || defined(__WXMAC_OSX__) +#if defined(__WXMSW__) || defined(__WXCOCOA__) || \ + defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXX11__) || \ + (defined(__WXMAC__) && __WXMAC_OSX__) || defined(__WXCOCOA__) #define wxHAS_TASK_BAR_ICON #else #undef wxHAS_TASK_BAR_ICON diff --git a/include/wx/taskbar.h b/include/wx/taskbar.h index 99dc5b2d10..bc8371c18d 100644 --- a/include/wx/taskbar.h +++ b/include/wx/taskbar.h @@ -45,8 +45,10 @@ private: #include "wx/msw/taskbar.h" #elif defined(__WXGTK__) || defined(__WXX11__) || defined(__WXMOTIF__) #include "wx/unix/taskbarx11.h" -#elif defined(__DARWIN__) +#elif defined (__WXMAC__) && __WXMAC_OSX__ #include "wx/mac/taskbarosx.h" +#elif defined (__WXCOCOA__) + #include "wx/cocoa/taskbar.h" #endif // ---------------------------------------------------------------------------- diff --git a/src/cocoa/taskbar.mm b/src/cocoa/taskbar.mm new file mode 100644 index 0000000000..5975e31c3d --- /dev/null +++ b/src/cocoa/taskbar.mm @@ -0,0 +1,402 @@ +///////////////////////////////////////////////////////////////////////// +// File: src/cocoa/taskbar.mm +// Purpose: Implements wxTaskBarIcon class +// Author: David Elliott +// Modified by: +// Created: 2004/01/24 +// RCS-ID: $Id$ +// Copyright: (c) 2004 David Elliott +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////// + +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) +#pragma implementation "taskbar.h" +#endif + +#include "wx/wxprec.h" +#ifdef wxHAS_TASK_BAR_ICON + +#ifndef WX_PRECOMP + #include "wx/menu.h" + #include "wx/icon.h" + #include "wx/log.h" + #include "wx/dcclient.h" +#endif + +#include "wx/taskbar.h" + +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import +#import + +#include "wx/cocoa/NSApplication.h" +#include "wx/cocoa/autorelease.h" + +class wxTaskBarIconWindow; + +// ============================================================================ +// wxTaskBarIconCocoaImpl +// Base class for the various Cocoa implementations. +// ============================================================================ +class wxTaskBarIconCocoaImpl +{ +public: + wxTaskBarIconCocoaImpl(wxTaskBarIcon *taskBarIcon) + : m_taskBarIcon(taskBarIcon) + , m_iconWindow(NULL) + {} + virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString) = 0; + virtual bool RemoveIcon() = 0; + virtual bool PopupMenu(wxMenu *menu) = 0; + virtual ~wxTaskBarIconCocoaImpl(); + inline wxTaskBarIcon* GetTaskBarIcon() { return m_taskBarIcon; } +protected: + wxTaskBarIcon *m_taskBarIcon; + wxTaskBarIconWindow *m_iconWindow; +private: + wxTaskBarIconCocoaImpl(); +}; + +// ============================================================================ +// wxTaskBarIconDockImpl +// An implementation using the Dock icon. +// ============================================================================ +class wxTaskBarIconDockImpl: public wxTaskBarIconCocoaImpl +{ +public: + wxTaskBarIconDockImpl(wxTaskBarIcon *taskBarIcon); + virtual ~wxTaskBarIconDockImpl(); + virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString); + virtual bool RemoveIcon(); + virtual bool PopupMenu(wxMenu *menu); + + static WX_NSMenu CocoaGetDockNSMenu(); +protected: + WX_NSMenu CocoaDoGetDockNSMenu(); + WX_NSImage m_originalDockIcon; + // There can be only one Dock icon, so make sure we keep it that way + static wxTaskBarIconDockImpl *sm_dockIcon; +private: + wxTaskBarIconDockImpl(); +}; + +// ============================================================================ +// wxTaskBarIconCustomStatusItemImpl +// An implementation using an NSStatusItem with a custom NSView +// ============================================================================ +class wxTaskBarIconCustomStatusItemImpl: public wxTaskBarIconCocoaImpl +{ +public: + wxTaskBarIconCustomStatusItemImpl(wxTaskBarIcon *taskBarIcon); + virtual ~wxTaskBarIconCustomStatusItemImpl(); + virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString); + virtual bool RemoveIcon(); + virtual bool PopupMenu(wxMenu *menu); +protected: + NSStatusItem *m_cocoaNSStatusItem; +private: + wxTaskBarIconCustomStatusItemImpl(); +}; + +// ============================================================================ +// wxTaskBarIconWindow +// Used by all implementations to forward events from the wxMenu +// ============================================================================ +class wxTaskBarIconWindow: public wxWindow +{ + DECLARE_EVENT_TABLE() +public: + wxTaskBarIconWindow(wxTaskBarIconCocoaImpl *taskBarIconImpl) + : wxWindow(NULL,-1) + , m_taskBarIconImpl(taskBarIconImpl) + { wxASSERT(m_taskBarIconImpl); } + + void OnMenuEvent(wxCommandEvent& event); +protected: + wxTaskBarIconCocoaImpl *m_taskBarIconImpl; +}; + +// ============================================================================ +// wxTaskBarIconWindowCustom +// Used by the CustomStatusIcon implementation for the custom NSView. +// ============================================================================ +class wxTaskBarIconWindowCustom: public wxTaskBarIconWindow +{ + DECLARE_EVENT_TABLE() +public: + wxTaskBarIconWindowCustom(wxTaskBarIconCocoaImpl *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. +// ============================================================================ +IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler) + +wxTaskBarIcon::wxTaskBarIcon(wxTaskBarIconType iconType) +{ + if(iconType == DOCK) + m_impl = new wxTaskBarIconDockImpl(this); + else if(iconType == CUSTOM_STATUSITEM) + m_impl = new wxTaskBarIconCustomStatusItemImpl(this); + else + { m_impl = NULL; + wxFAIL_MSG(wxT("Invalid wxTaskBarIcon type")); + } +} + +wxTaskBarIcon::~wxTaskBarIcon() +{ + delete m_impl; +} + +// Operations +bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip) +{ + return m_impl->SetIcon(icon,tooltip); +} + +bool wxTaskBarIcon::RemoveIcon() +{ + return m_impl->RemoveIcon(); +} + +bool wxTaskBarIcon::PopupMenu(wxMenu *menu) +{ + return m_impl->PopupMenu(menu); +} + +// ============================================================================ +// wxTaskBarIconCocoaImpl +// ============================================================================ + +#if 0 +wxTaskBarIconCocoaImpl::wxTaskBarIconCocoaImpl(wxTaskBarIcon *taskBarIcon) +: m_taskBarIcon(taskBarIcon) +, m_iconWindow(NULL) +{ +} +#endif + +wxTaskBarIconCocoaImpl::~wxTaskBarIconCocoaImpl() +{ +// wxAutoNSAutoreleasePool pool; + delete m_iconWindow; +} + +// ============================================================================ +// wxTaskBarIconDockImpl +// ============================================================================ +wxTaskBarIconDockImpl *wxTaskBarIconDockImpl::sm_dockIcon = NULL; + +wxTaskBarIconDockImpl::wxTaskBarIconDockImpl(wxTaskBarIcon *taskBarIcon) +: wxTaskBarIconCocoaImpl(taskBarIcon) +{ + m_originalDockIcon = nil; + wxASSERT_MSG(!sm_dockIcon,"You should never have more than one dock icon!"); + sm_dockIcon = this; +} + +wxTaskBarIconDockImpl::~wxTaskBarIconDockImpl() +{ +// wxAutoNSAutoreleasePool pool; + if(sm_dockIcon == this) + sm_dockIcon = NULL; +} + +WX_NSMenu wxTaskBarIconDockImpl::CocoaGetDockNSMenu() +{ + if(sm_dockIcon) + return sm_dockIcon->CocoaDoGetDockNSMenu(); + return nil; +} + +WX_NSMenu wxTaskBarIconDockImpl::CocoaDoGetDockNSMenu() +{ + wxMenu *dockMenu = m_taskBarIcon->CreatePopupMenu(); + if(!dockMenu) + return nil; + if(!m_iconWindow) + m_iconWindow = new wxTaskBarIconWindow(this); + dockMenu->SetInvokingWindow(m_iconWindow); + dockMenu->UpdateUI(); + dockMenu->SetCocoaDeletes(true); + return dockMenu->GetNSMenu(); +} + +bool wxTaskBarIconDockImpl::SetIcon(const wxIcon& icon, const wxString& tooltip) +{ + wxAutoNSAutoreleasePool pool; + m_originalDockIcon = [[[NSApplication sharedApplication] applicationIconImage] retain]; + [[NSApplication sharedApplication] setApplicationIconImage:icon.GetNSImage()]; + return true; +} + +bool wxTaskBarIconDockImpl::RemoveIcon() +{ + [[NSApplication sharedApplication] setApplicationIconImage:m_originalDockIcon]; + [m_originalDockIcon release]; + return true; +} + +bool wxTaskBarIconDockImpl::PopupMenu(wxMenu *menu) +{ + wxFAIL_MSG(wxT("You cannot force the Dock icon menu to popup")); + return false; +} + + +// ============================================================================ +// wxTaskBarIconCustomStatusItemImpl +// ============================================================================ +wxTaskBarIconCustomStatusItemImpl::wxTaskBarIconCustomStatusItemImpl(wxTaskBarIcon *taskBarIcon) +: wxTaskBarIconCocoaImpl(taskBarIcon) +{ + m_cocoaNSStatusItem = nil; +} + +wxTaskBarIconCustomStatusItemImpl::~wxTaskBarIconCustomStatusItemImpl() +{ +} + +bool wxTaskBarIconCustomStatusItemImpl::SetIcon(const wxIcon& icon, const wxString& tooltip) +{ + wxAutoNSAutoreleasePool pool; + if(!m_cocoaNSStatusItem) + { + m_cocoaNSStatusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; + [m_cocoaNSStatusItem retain]; + } + 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 + [m_iconWindow->GetNSView() setFrame:NSMakeRect(0.0,0.0,wxMax(10,icon.GetWidth()),[[NSStatusBar systemStatusBar] thickness])]; + [m_cocoaNSStatusItem setView:m_iconWindow->GetNSView()]; + return true; +} + +bool wxTaskBarIconCustomStatusItemImpl::RemoveIcon() +{ + [m_cocoaNSStatusItem release]; + m_cocoaNSStatusItem = nil; + delete m_iconWindow; + m_iconWindow = NULL; + return true; +} + +bool wxTaskBarIconCustomStatusItemImpl::PopupMenu(wxMenu *menu) +{ + wxASSERT(menu); + menu->SetInvokingWindow(m_iconWindow); + menu->UpdateUI(); + + if([m_cocoaNSStatusItem respondsToSelector:@selector(popUpStatusItemMenu:)]) + { // OS X >= 10.3 + [m_cocoaNSStatusItem popUpStatusItemMenu:menu->GetNSMenu()]; + } + 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:[[m_iconWindow->GetNSView() window] windowNumber] + context:[NSGraphicsContext currentContext] + eventNumber:0 clickCount:1 pressure:0.0]; + [NSMenu popUpContextMenu:menu->GetNSMenu() withEvent:nsevent forView:m_iconWindow->GetNSView()]; + } + menu->SetInvokingWindow(NULL); + return true; +} + +// ============================================================================ +// wxTaskBarIconWindow +// ============================================================================ +BEGIN_EVENT_TABLE(wxTaskBarIconWindow, wxWindow) + EVT_MENU(-1, wxTaskBarIconWindow::OnMenuEvent) +END_EVENT_TABLE() + +void wxTaskBarIconWindow::OnMenuEvent(wxCommandEvent &event) +{ + 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 wxTaskBarIconWindowCustom::OnPaint(wxPaintEvent &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); +} + +// ============================================================================ +// wxTaskBarIconNSApplicationDelegateCategory +// ============================================================================ + +// This neatly solves the problem of DLL separation. If the wxAdvanced +// library (which this file is part of) is loaded then this category is +// defined and we get dock menu behavior without app.mm ever having to +// know we exist. C++ did sucketh so. :-) + +@interface wxNSApplicationDelegate(wxTaskBarIconNSApplicationDelegateCategory) +- (NSMenu*)applicationDockMenu:(NSApplication *)sender; +@end + +@implementation wxNSApplicationDelegate(wxTaskBarIconNSApplicationDelegateCategory) +- (NSMenu*)applicationDockMenu:(NSApplication *)sender +{ + return wxTaskBarIconDockImpl::CocoaGetDockNSMenu(); +} +@end + +#endif //def wxHAS_TASK_BAR_ICON -- 2.45.2