applied patch 1372197, with some minor mods and cleanup

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@36336 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
David Surovell
2005-12-03 17:55:33 +00:00
parent f2be55804a
commit d806d30a0f
4 changed files with 507 additions and 206 deletions

View File

@@ -17,44 +17,31 @@ class WXDLLEXPORT wxMenu;
class WXDLLEXPORT wxTaskBarIcon : public wxTaskBarIconBase class WXDLLEXPORT wxTaskBarIcon : public wxTaskBarIconBase
{ {
DECLARE_DYNAMIC_CLASS_NO_COPY(wxTaskBarIcon)
public: public:
//type of taskbar item to create // type of taskbar item to create (currently only DOCK is implemented)
//TODO: currently only DOCK is implemented
enum wxTaskBarIconType enum wxTaskBarIconType
{ {
DOCK, DOCK
STATUSITEM, // , CUSTOM_STATUSITEM
MENUEXTRA // , STATUSITEM
// , MENUEXTRA
, DEFAULT_TYPE = DOCK
}; };
wxTaskBarIcon(const wxTaskBarIconType& nType = DOCK); wxTaskBarIcon(wxTaskBarIconType iconType = DEFAULT_TYPE);
virtual ~wxTaskBarIcon(); virtual ~wxTaskBarIcon();
inline bool IsOk() const { return true; } bool IsOk() const { return true; }
inline bool IsIconInstalled() const { return m_iconAdded; }
bool IsIconInstalled() const;
//TODO: not tested extensively
bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString); bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString);
bool RemoveIcon(); bool RemoveIcon();
//TODO: end not tested extensively
//pops up the menu
bool PopupMenu(wxMenu *menu); bool PopupMenu(wxMenu *menu);
//internal functions - don't call
wxMenu* GetCurrentMenu();
wxMenu* DoCreatePopupMenu();
protected: protected:
wxTaskBarIconType m_nType; class wxTaskBarIconImpl* m_impl;
void* m_pEventHandlerRef; friend class wxTaskBarIconImpl;
wxMenu* m_pMenu;
WXHMENU m_theLastMenu;
bool m_iconAdded;
void OnRightDown(wxTaskBarIconEvent& evt);
DECLARE_DYNAMIC_CLASS(wxTaskBarIcon)
}; };
#endif #endif
// _TASKBAR_H_ // _TASKBAR_H_

View File

@@ -53,7 +53,6 @@ BEGIN_EVENT_TABLE(MyDialog, wxDialog)
END_EVENT_TABLE() END_EVENT_TABLE()
MyDialog::MyDialog(wxWindow* parent, const wxWindowID id, const wxString& title, MyDialog::MyDialog(wxWindow* parent, const wxWindowID id, const wxString& title,
const wxPoint& pos, const wxSize& size, const long windowStyle): const wxPoint& pos, const wxSize& size, const long windowStyle):
wxDialog(parent, id, title, pos, size, windowStyle) wxDialog(parent, id, title, pos, size, windowStyle)
@@ -108,8 +107,12 @@ void MyDialog::Init(void)
enum { enum {
PU_RESTORE = 10001, PU_RESTORE = 10001,
PU_NEW_ICON, PU_NEW_ICON,
PU_OLD_ICON,
PU_EXIT, PU_EXIT,
PU_CHECKMARK PU_CHECKMARK,
PU_SUB1,
PU_SUB2,
PU_SUBMAIN
}; };
@@ -117,9 +120,12 @@ BEGIN_EVENT_TABLE(MyTaskBarIcon, wxTaskBarIcon)
EVT_MENU(PU_RESTORE, MyTaskBarIcon::OnMenuRestore) EVT_MENU(PU_RESTORE, MyTaskBarIcon::OnMenuRestore)
EVT_MENU(PU_EXIT, MyTaskBarIcon::OnMenuExit) EVT_MENU(PU_EXIT, MyTaskBarIcon::OnMenuExit)
EVT_MENU(PU_NEW_ICON,MyTaskBarIcon::OnMenuSetNewIcon) EVT_MENU(PU_NEW_ICON,MyTaskBarIcon::OnMenuSetNewIcon)
EVT_MENU(PU_OLD_ICON,MyTaskBarIcon::OnMenuSetOldIcon)
EVT_MENU(PU_CHECKMARK,MyTaskBarIcon::OnMenuCheckmark) EVT_MENU(PU_CHECKMARK,MyTaskBarIcon::OnMenuCheckmark)
EVT_UPDATE_UI(PU_CHECKMARK,MyTaskBarIcon::OnMenuUICheckmark) EVT_UPDATE_UI(PU_CHECKMARK,MyTaskBarIcon::OnMenuUICheckmark)
EVT_TASKBAR_LEFT_DCLICK (MyTaskBarIcon::OnLeftButtonDClick) EVT_TASKBAR_LEFT_DCLICK (MyTaskBarIcon::OnLeftButtonDClick)
EVT_MENU(PU_SUB1, MyTaskBarIcon::OnMenuSub)
EVT_MENU(PU_SUB2, MyTaskBarIcon::OnMenuSub)
END_EVENT_TABLE() END_EVENT_TABLE()
void MyTaskBarIcon::OnMenuRestore(wxCommandEvent& ) void MyTaskBarIcon::OnMenuRestore(wxCommandEvent& )
@@ -138,6 +144,7 @@ void MyTaskBarIcon::OnMenuCheckmark(wxCommandEvent& )
{ {
check =!check; check =!check;
} }
void MyTaskBarIcon::OnMenuUICheckmark(wxUpdateUIEvent &event) void MyTaskBarIcon::OnMenuUICheckmark(wxUpdateUIEvent &event)
{ {
event.Check( check ); event.Check( check );
@@ -151,16 +158,45 @@ void MyTaskBarIcon::OnMenuSetNewIcon(wxCommandEvent&)
wxMessageBox(wxT("Could not set new icon.")); wxMessageBox(wxT("Could not set new icon."));
} }
void MyTaskBarIcon::OnMenuSetOldIcon(wxCommandEvent&)
{
if (IsIconInstalled())
{
RemoveIcon();
}
else
{
wxMessageBox(wxT("wxTaskBarIcon Sample - icon already is the old version"));
}
}
void MyTaskBarIcon::OnMenuSub(wxCommandEvent&)
{
wxMessageBox(wxT("You clicked on a submenu!"));
}
// Overridables // Overridables
wxMenu *MyTaskBarIcon::CreatePopupMenu() wxMenu *MyTaskBarIcon::CreatePopupMenu()
{ {
// Try creating menus different ways
// TODO: Probably try calling SetBitmap with some XPMs here
wxMenu *menu = new wxMenu; wxMenu *menu = new wxMenu;
menu->Append(PU_RESTORE, _T("&Restore TBTest")); menu->Append(PU_RESTORE, _T("&Restore TBTest"));
menu->Append(PU_NEW_ICON,_T("&Set New Icon")); menu->AppendSeparator();
menu->Append(PU_CHECKMARK, _T("Checkmark"),wxT( "" ), wxITEM_CHECK ); menu->Append(PU_OLD_ICON, _T("&Restore Old Icon"));
menu->Append(PU_NEW_ICON, _T("&Set New Icon"));
menu->AppendSeparator();
menu->Append(PU_CHECKMARK, _T("Checkmark"),wxT(""), wxITEM_CHECK);
menu->AppendSeparator();
wxMenu *submenu = new wxMenu;
submenu->Append(PU_SUB1, _T("One submenu"));
submenu->AppendSeparator();
submenu->Append(PU_SUB2, _T("Another submenu"));
menu->Append(PU_SUBMAIN, _T("Submenu"), submenu);
#ifndef __WXMAC_OSX__ /*Mac has built-in quit menu*/
menu->AppendSeparator();
menu->Append(PU_EXIT, _T("E&xit")); menu->Append(PU_EXIT, _T("E&xit"));
#endif
return menu; return menu;
} }

View File

@@ -24,8 +24,10 @@ public:
void OnMenuRestore(wxCommandEvent&); void OnMenuRestore(wxCommandEvent&);
void OnMenuExit(wxCommandEvent&); void OnMenuExit(wxCommandEvent&);
void OnMenuSetNewIcon(wxCommandEvent&); void OnMenuSetNewIcon(wxCommandEvent&);
void OnMenuSetOldIcon(wxCommandEvent&);
void OnMenuCheckmark(wxCommandEvent&); void OnMenuCheckmark(wxCommandEvent&);
void OnMenuUICheckmark(wxUpdateUIEvent&); void OnMenuUICheckmark(wxUpdateUIEvent&);
void OnMenuSub(wxCommandEvent&);
virtual wxMenu *CreatePopupMenu(); virtual wxMenu *CreatePopupMenu();
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()

View File

@@ -1,4 +1,4 @@
///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Name: taskbar.cpp // Name: taskbar.cpp
// Purpose: wxTaskBarIcon OSX Implementation // Purpose: wxTaskBarIcon OSX Implementation
// Author: Ryan Norton // Author: Ryan Norton
@@ -7,7 +7,15 @@
// RCS-ID: $Id$ // RCS-ID: $Id$
// Copyright: (c) 2004 Ryan Norton // Copyright: (c) 2004 Ryan Norton
// Licence: wxWindows licence // Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
//=============================================================================
// Declarations
//=============================================================================
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include "wx/wxprec.h" #include "wx/wxprec.h"
@@ -20,103 +28,256 @@
#include "wx/icon.h" #include "wx/icon.h"
#include "wx/dcmemory.h" #include "wx/dcmemory.h"
IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler) //-----------------------------------------------------------------------------
//
// wxTaskBarIconImpl
//
// Superclass of wxTaskBarIcon implementations
//-----------------------------------------------------------------------------
class wxTaskBarIconImpl
{
public:
wxTaskBarIconImpl(wxTaskBarIcon* parent);
virtual ~wxTaskBarIconImpl();
virtual bool IsIconInstalled() const = 0;
virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip) = 0;
virtual bool RemoveIcon() = 0;
virtual bool PopupMenu(wxMenu *menu) = 0;
wxMenu* CreatePopupMenu()
{ return m_parent->CreatePopupMenu(); }
wxTaskBarIcon* m_parent;
class wxTaskBarIconWindow* m_menuEventWindow;
};
//-----------------------------------------------------------------------------
//
// 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)
: wxTopLevelWindow(NULL, -1, wxT("")), m_impl(impl)
{
Connect(-1, wxEVT_COMMAND_MENU_SELECTED,
wxCommandEventHandler(wxTaskBarIconWindow::OnMenuEvent)
);
}
void OnMenuEvent(wxCommandEvent& event)
{
m_impl->m_parent->ProcessEvent(event);
}
private:
wxTaskBarIconImpl* m_impl;
};
//-----------------------------------------------------------------------------
//
// wxDockBarIconImpl
//
//-----------------------------------------------------------------------------
class wxDockTaskBarIcon : public wxTaskBarIconImpl
{
public:
wxDockTaskBarIcon(wxTaskBarIcon* parent);
virtual ~wxDockTaskBarIcon();
virtual bool IsIconInstalled() const;
virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip);
virtual bool RemoveIcon();
virtual bool PopupMenu(wxMenu *menu);
wxMenu* DoCreatePopupMenu();
EventHandlerRef m_eventHandlerRef;
EventHandlerUPP m_eventupp;
wxMenu* m_pMenu;
MenuRef m_theLastMenu;
bool m_iconAdded;
wxWindow* m_eventWindow;
};
// Forward declarations for utility functions for dock implementation
pascal OSStatus wxDockEventHandler( EventHandlerCallRef inHandlerCallRef,
EventRef inEvent, void* pData);
wxMenu* wxDeepCopyMenu(wxMenu* menu);
//=============================================================================
//
// Implementation
//
//=============================================================================
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// wxTaskBarIconImpl
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//-----------------------------------------------------------------------------
// wxTaskBarIconImpl Constructor
//
// Initializes members and creates the event window
//-----------------------------------------------------------------------------
wxTaskBarIconImpl::wxTaskBarIconImpl(wxTaskBarIcon* parent)
: m_parent(parent), m_menuEventWindow(new wxTaskBarIconWindow(this))
{
}
//-----------------------------------------------------------------------------
// wxTaskBarIconImpl Destructor
//
// Cleans up the event window
//-----------------------------------------------------------------------------
wxTaskBarIconImpl::~wxTaskBarIconImpl()
{
delete m_menuEventWindow;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// wxDockTaskBarIcon
//
// OS X DOCK implementation of wxTaskBarIcon using carbon
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// wxDockEventHandler
//
// This is the global mac/carbon event handler for the dock.
// We need this for two reasons:
// 1) To handle wxTaskBarIcon menu events (see below for why)
// 2) To handle events from the dock when it requests a menu
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pascal OSStatus wxDockEventHandler( EventHandlerCallRef inHandlerCallRef, pascal OSStatus wxDockEventHandler( EventHandlerCallRef inHandlerCallRef,
EventRef inEvent, void* pData) EventRef inEvent, void* pData)
{ {
wxTaskBarIcon*& pTB = (wxTaskBarIcon*&) pData; // Get the parameters we want from the event
wxDockTaskBarIcon* pTB = (wxDockTaskBarIcon*) pData;
const UInt32 eventClass = GetEventClass(inEvent); const UInt32 eventClass = GetEventClass(inEvent);
const UInt32 eventKind = GetEventKind(inEvent); const UInt32 eventKind = GetEventKind(inEvent);
//
// Handle wxTaskBar menu events (note that this is a global event handler
// so it will actually get called by all commands/menus)
//
if (eventClass == kEventClassCommand && eventKind == kEventCommandProcess) if (eventClass == kEventClassCommand && eventKind == kEventCommandProcess)
{ {
//TODO: This is a complete copy of // if we have no taskbar menu quickly pass it back to wxApp
//static pascal OSStatus wxMacAppCommandEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) if (! pTB->m_pMenu )
if (! pTB->GetCurrentMenu() )
{ {
return eventNotHandledErr; return eventNotHandledErr;
} }
MenuRef hMenu = MAC_WXHMENU(pTB->GetCurrentMenu()->GetHMenu()); //
OSStatus result = eventNotHandledErr ; // This is the real reason why we need this. Normally menus
// get handled in wxMacAppEventHandler
HICommand command ; //
// pascal OSStatus wxMacAppEventHandler(EventHandlerCallRef handler,
// EventRef event, void *data)
//
// However, in the case of a taskbar menu call
// command.menu.menuRef IS NULL!
// Which causes the wxApp handler just to skip it.
//
MenuRef taskbarMenuRef = MAC_WXHMENU(pTB->m_pMenu->GetHMenu());
OSStatus result = eventNotHandledErr;
OSErr err; OSErr err;
err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, // get the HICommand from the event
NULL, sizeof(HICommand), NULL, &command); HICommand command;
wxASSERT(err == noErr); err = GetEventParameter(inEvent, kEventParamDirectObject,
typeHICommand, NULL,
MenuItemIndex menuItemIndex; sizeof(HICommand), NULL, &command);
err = GetIndMenuItemWithCommandID(hMenu, command.commandID, 1, NULL, &menuItemIndex); if (err == noErr)
wxASSERT(err == noErr); {
//
// Obtain the REAL menuRef and the menuItemIndex in the real menuRef
MenuCommand id = command.commandID ; //
wxMenuItem* item = NULL; // NOTE: menuRef is generally used here for submenus, as
// GetMenuItemRefCon could give an incorrect wxMenuItem if we pass
// just the top level wxTaskBar menu
//
MenuItemIndex menuItemIndex;
MenuRef menuRef;
err = GetIndMenuItemWithCommandID(taskbarMenuRef,
command.commandID,
1, &menuRef, &menuItemIndex);
if (err == noErr)
{
MenuCommand id = command.commandID;
wxMenuItem* item = NULL;
// for items we don't really control if (id != 0) // get the wxMenuItem reference from the MenuRef
if ( id == kHICommandPreferences ) GetMenuItemRefCon(menuRef, menuItemIndex, (UInt32*) &item);
{
id = wxApp::s_macPreferencesMenuItemId ;
wxMenuBar* mbar = wxMenuBar::MacGetInstalledMenuBar() ;
if ( mbar ) if (item)
{ {
wxMenu* menu = NULL ; // Handle items that are checkable
item = mbar->FindItem( id , &menu ) ; // FIXME: Doesn't work (at least on 10.2)!
} if (item->IsCheckable())
} item->Check( !item->IsChecked() ) ;
else if (id != 0)
GetMenuItemRefCon( hMenu , menuItemIndex , (UInt32*) &item ) ;
if ( item ) // send the wxEvent to the wxMenu
{ item->GetMenu()->SendEvent(id,
if (item->IsCheckable()) item->IsCheckable() ?
{ item->IsChecked() : -1
item->Check( !item->IsChecked() ) ; );
err = noErr; // successfully handled the event
}
} }
} //end if noErr on getting HICommand from event
item->GetMenu()->SendEvent( id , item->IsCheckable() ? item->IsChecked() : -1 ) ; return err; // return whether we handled the event or not
result = noErr ;
}
return result ;
} }
wxASSERT(eventClass == kEventClassApplication && eventKind == kEventAppGetDockTileMenu); // We better have a kEventClassApplication/kEventAppGetDockTileMenu combo here,
// otherwise something is truly funky
//process the right click events wxASSERT(eventClass == kEventClassApplication &&
wxTaskBarIconEvent downevt(wxEVT_TASKBAR_RIGHT_DOWN,NULL); eventKind == kEventAppGetDockTileMenu);
pTB->ProcessEvent(downevt);
// process the right click events
wxTaskBarIconEvent upevt(wxEVT_TASKBAR_RIGHT_UP,NULL); // NB: This may result in double or even triple-creation of the menus
pTB->ProcessEvent(upevt); // We need to do this for 2.4 compat, however
wxTaskBarIconEvent downevt(wxEVT_TASKBAR_RIGHT_DOWN,NULL);
pTB->m_parent->ProcessEvent(downevt);
wxTaskBarIconEvent upevt(wxEVT_TASKBAR_RIGHT_UP,NULL);
pTB->m_parent->ProcessEvent(upevt);
//create popup menu //create popup menu
wxMenu* menu = pTB->DoCreatePopupMenu(); wxMenu* menu = pTB->DoCreatePopupMenu();
OSStatus err = noErr; OSStatus err = noErr;
if(menu) if (menu)
{ {
//note to self - a MenuRef IS A MenuHandle //note to self - a MenuRef IS A MenuHandle
MenuRef hMenu = MAC_WXHMENU(menu->GetHMenu()); MenuRef hMenu = MAC_WXHMENU(menu->GetHMenu());
//When we call SetEventParameter it will decrement // When we call SetEventParameter it will decrement
//the reference count of the menu - we need to make // the reference count of the menu - we need to make
//sure it stays around in the wxMenu class here // sure it stays around in the wxMenu class here
RetainMenu(hMenu); RetainMenu(hMenu);
//set the actual dock menu // set the actual dock menu
err = SetEventParameter((EventRef) inEvent, kEventParamMenuRef, err = SetEventParameter(inEvent, kEventParamMenuRef,
typeMenuRef, sizeof(MenuRef), typeMenuRef, sizeof(MenuRef), &hMenu);
&hMenu); wxASSERT(err == noErr);
wxASSERT(err == 0);
return err; return err;
} }
@@ -124,59 +285,148 @@ pascal OSStatus wxDockEventHandler( EventHandlerCallRef inHandlerCallRef,
return eventNotHandledErr; return eventNotHandledErr;
} }
DEFINE_ONE_SHOT_HANDLER_GETTER( wxDockEventHandler ); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// wxDeepCopyMenu
wxTaskBarIcon::wxTaskBarIcon(const wxTaskBarIconType& nType) //
: m_nType(nType), m_pEventHandlerRef(NULL), m_pMenu(NULL), // Performs a top-to-bottom copy of the input menu and all of its
m_theLastMenu((WXHMENU)GetApplicationDockTileMenu()), m_iconAdded(false) // submenus.
//
// This is mostly needed for 2.4 compatability. However wxPython and others
// still use this way of setting the taskbarmenu.
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
wxMenu* wxDeepCopyMenu(wxMenu* menu)
{ {
//Register the events that will return the dock menu if (!menu)
EventTypeSpec tbEventList[] = { { kEventClassCommand, kEventProcessCommand }, return NULL;
{ kEventClassApplication, kEventAppGetDockTileMenu } };
//
// NB: Here we have to perform a deep copy of the menu,
// copying each and every menu item from menu to m_pMenu.
// Other implementations use wxWindow::PopupMenu here,
// which idle execution until the user selects something,
// but since the mac handles this internally, we can't -
// and have no way at all to idle it while the dock menu
// is being shown before menu goes out of scope (it may
// not be on the heap, and may expire right after this function
// is done - we need it to last until the carbon event is triggered -
// that's when the user right clicks).
//
// Also, since there is no equal (assignment) operator
// on either wxMenu or wxMenuItem, we have to do all the
// dirty work ourselves.
//
// perform a deep copy of the menu
wxMenuItemList& theList = menu->GetMenuItems();
wxMenuItemList::compatibility_iterator theNode = theList.GetFirst();
#ifdef __WXDEBUG__ // create the main menu
OSStatus err = wxMenu* m_pMenu = new wxMenu(menu->GetTitle());
#endif
InstallApplicationEventHandler(
GetwxDockEventHandlerUPP(),
GetEventTypeCount(tbEventList), tbEventList,
this, (&(EventHandlerRef&)m_pEventHandlerRef));
wxASSERT(err == noErr);
Connect(wxEVT_TASKBAR_RIGHT_DOWN, wxTaskBarIconEventHandler(wxTaskBarIcon::OnRightDown));
}
wxTaskBarIcon::~wxTaskBarIcon() while (theNode != NULL)
{
//clean up event handler
RemoveEventHandler((EventHandlerRef&)m_pEventHandlerRef);
//restore old icon and menu to the dock
RemoveIcon();
}
wxMenu* wxTaskBarIcon::GetCurrentMenu()
{
return m_pMenu;
}
wxMenu* wxTaskBarIcon::DoCreatePopupMenu()
{
wxMenu* theNewMenu = CreatePopupMenu();
if (theNewMenu)
{ {
delete m_pMenu; wxMenuItem* theItem = theNode->GetData();
m_pMenu = theNewMenu; m_pMenu->Append(new wxMenuItem(m_pMenu, // parent menu
m_pMenu->SetEventHandler(this); theItem->GetId(), // id
theItem->GetText(), // text label
theItem->GetHelp(), // status bar help string
theItem->GetKind(), // menu flags - checkable, separator, etc.
wxDeepCopyMenu(theItem->GetSubMenu()) // submenu
));
theNode = theNode->GetNext();
} }
return m_pMenu; return m_pMenu;
} }
// Operations: //-----------------------------------------------------------------------------
bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip) // wxDockTaskBarIcon Constructor
//
// Initializes the dock implementation of wxTaskBarIcon.
//
// Here we create some mac-specific event handlers and UPPs.
//-----------------------------------------------------------------------------
wxDockTaskBarIcon::wxDockTaskBarIcon(wxTaskBarIcon* parent)
: wxTaskBarIconImpl(parent),
m_eventHandlerRef(NULL), m_pMenu(NULL),
m_theLastMenu(GetApplicationDockTileMenu()), m_iconAdded(false)
{
// register the events that will return the dock menu
EventTypeSpec tbEventList[] = { { kEventClassCommand, kEventProcessCommand },
{ kEventClassApplication, kEventAppGetDockTileMenu } };
m_eventupp = NewEventHandlerUPP(wxDockEventHandler);
wxASSERT(m_eventupp != NULL);
#ifdef __WXDEBUG__
OSStatus err =
#endif
InstallApplicationEventHandler(
m_eventupp,
GetEventTypeCount(tbEventList), tbEventList,
this, &m_eventHandlerRef);
wxASSERT(err == noErr);
}
//-----------------------------------------------------------------------------
// wxDockTaskBarIcon Destructor
//
// Cleans up mac events and restores the old icon to the dock
//-----------------------------------------------------------------------------
wxDockTaskBarIcon::~wxDockTaskBarIcon()
{
// clean up event handler and event UPP
RemoveEventHandler(m_eventHandlerRef);
DisposeEventHandlerUPP(m_eventupp);
// restore old icon and menu to the dock
RemoveIcon();
}
//-----------------------------------------------------------------------------
// wxDockTaskBarIcon::DoCreatePopupMenu
//
// Helper function that handles a request from the dock event handler
// to get the menu for the dock
//-----------------------------------------------------------------------------
wxMenu* wxDockTaskBarIcon::DoCreatePopupMenu()
{
// get the menu from the parent
wxMenu* theNewMenu = CreatePopupMenu();
if (theNewMenu)
{
if (m_pMenu)
delete m_pMenu;
m_pMenu = theNewMenu;
m_pMenu->SetInvokingWindow(m_menuEventWindow);
}
// the return here can be one of three things
// (in order of priority):
// 1) User passed a menu from CreatePopupMenu override
// 2) menu sent to and copied from PopupMenu
// 3) If neither (1) or (2), then NULL
//
return m_pMenu;
}
//-----------------------------------------------------------------------------
// wxDockTaskBarIcon::IsIconInstalled
//
// Returns whether or not the dock is not using the default image
//-----------------------------------------------------------------------------
bool wxDockTaskBarIcon::IsIconInstalled() const
{
return m_iconAdded;
}
//-----------------------------------------------------------------------------
// wxDockTaskBarIcon::SetIcon
//
// Sets the icon for the dock CGImage functions and SetApplicationDockTileImage
//-----------------------------------------------------------------------------
bool wxDockTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
{ {
wxBitmap bmp( icon ) ; wxBitmap bmp( icon ) ;
OSStatus err = noErr ; OSStatus err = noErr ;
@@ -211,7 +461,8 @@ bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
); );
wxASSERT(err == 0); wxASSERT(err == 0);
#endif #endif
wxASSERT(pImage != NULL );
wxASSERT(pImage != NULL);
err = SetApplicationDockTileImage(pImage); err = SetApplicationDockTileImage(pImage);
wxASSERT(err == 0); wxASSERT(err == 0);
@@ -222,79 +473,104 @@ bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
return m_iconAdded = err == noErr; return m_iconAdded = err == noErr;
} }
bool wxTaskBarIcon::RemoveIcon() //-----------------------------------------------------------------------------
// wxDockTaskBarIcon::RemoveIcon
//
// Restores the old image for the dock via RestoreApplicationDockTileImage
//-----------------------------------------------------------------------------
bool wxDockTaskBarIcon::RemoveIcon()
{ {
if(m_pMenu)
{
delete m_pMenu;
m_pMenu = NULL;
}
//restore old icon to the dock
OSStatus err = RestoreApplicationDockTileImage();
wxASSERT(err == 0);
//restore the old menu to the dock
SetApplicationDockTileMenu(MAC_WXHMENU(m_theLastMenu));
return !(m_iconAdded = !(err == noErr));
}
bool wxTaskBarIcon::PopupMenu(wxMenu *menu)
{
wxASSERT(menu != NULL);
if (m_pMenu) if (m_pMenu)
{ {
delete m_pMenu; delete m_pMenu;
m_pMenu = NULL; m_pMenu = NULL;
} }
// // restore old icon to the dock
// NB: Here we have to perform a deep copy of the menu, OSStatus err = RestoreApplicationDockTileImage();
// copying each and every menu item from menu to m_pMenu. wxASSERT(err == noErr);
// Other implementations use wxWindow::PopupMenu here,
// which idle execution until the user selects something, // restore the old menu to the dock
// but since the mac handles this internally, we can't - SetApplicationDockTileMenu(m_theLastMenu);
// and have no way at all to idle it while the dock menu
// is being shown before menu goes out of scope (it may return !(m_iconAdded = !(err == noErr));
// not be on the heap, and may expire right after this function }
// is done - we need it to last until the carbon event is triggered -
// that's when the user right clicks). //-----------------------------------------------------------------------------
// // wxDockTaskBarIcon::PopupMenu
// Also, since there is no equal (assignment) operator //
// on either wxMenu or wxMenuItem, we have to do all the // 2.4 and wxPython method that "pops of the menu in the taskbar".
// dirty work ourselves. //
// // In reality because of the way the dock menu works in carbon
// we just save the menu, and if the user didn't override CreatePopupMenu
// return the menu passed here, thus sort of getting the same effect.
//-----------------------------------------------------------------------------
bool wxDockTaskBarIcon::PopupMenu(wxMenu *menu)
{
wxASSERT(menu != NULL);
if (m_pMenu)
delete m_pMenu;
//start copy of menu
m_pMenu = wxDeepCopyMenu(menu);
//Perform a deep copy of the menu //finish up
wxMenuItemList& theList = menu->GetMenuItems(); m_pMenu->SetInvokingWindow(m_menuEventWindow);
wxMenuItemList::compatibility_iterator theNode = theList.GetFirst();
//create the main menu
m_pMenu = new wxMenu(menu->GetTitle());
while(theNode != NULL)
{
wxMenuItem* theItem = theNode->GetData();
m_pMenu->Append(new wxMenuItem( m_pMenu, //parent menu
theItem->GetId(), //id
theItem->GetText(), //text label
theItem->GetHelp(), //status bar help string
theItem->GetKind(), //menu flags - checkable, separator, etc.
theItem->GetSubMenu() //submenu
));
theNode = theNode->GetNext();
}
m_pMenu->SetEventHandler(this);
return true; return true;
} }
//Skip the event so that popupmenu isn't called in parent, avoiding double-creation of the menus //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void wxTaskBarIcon::OnRightDown(wxTaskBarIconEvent& evt) //
// wxTaskBarIcon
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler)
//-----------------------------------------------------------------------------
// wxTaskBarIcon Constructor
//
// Creates the backend
//
// Note that we only support DOCK currently as others require cocoa and
// also some require hacks and other such things. (MenuExtras are
// actually seperate programs that also require a special undocumented id
// hack and other such fun stuff).
//-----------------------------------------------------------------------------
wxTaskBarIcon::wxTaskBarIcon(wxTaskBarIconType nType)
{ {
evt.Skip(); wxASSERT_MSG(nType == DOCK,
wxT("Only the DOCK implementation of wxTaskBarIcon")
wxT("on mac carbon is currently supported!"));
m_impl = new wxDockTaskBarIcon(this);
} }
//-----------------------------------------------------------------------------
// wxTaskBarIcon Destructor
//
// Destroys the backend
//-----------------------------------------------------------------------------
wxTaskBarIcon::~wxTaskBarIcon()
{
delete m_impl;
}
//-----------------------------------------------------------------------------
// wxTaskBarIcon::SetIcon
// wxTaskBarIcon::RemoveIcon
// wxTaskBarIcon::PopupMenu
//
// Just calls the backend version of the said function.
//-----------------------------------------------------------------------------
bool wxTaskBarIcon::IsIconInstalled() const
{ return m_impl->IsIconInstalled(); }
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); }
#endif //wxHAS_TASK_BAR_ICON #endif //wxHAS_TASK_BAR_ICON