+++ /dev/null
-///////////////////////////////////////////////////////////////////////////////
-// Name: src/mac/carbon/taskbar.cpp
-// Purpose: wxTaskBarIcon
-// Author: Ryan Norton
-// Modified by:
-// Created: 09/25/2004
-// RCS-ID: $Id$
-// Copyright: (c) 2004 Ryan Norton
-// Licence: wxWindows licence
-///////////////////////////////////////////////////////////////////////////////
-
-#include "wx/wxprec.h"
-
-#if wxUSE_TASKBARICON
-
-#include "wx/taskbar.h"
-
-#ifndef WX_PRECOMP
- #include "wx/dcmemory.h"
- #include "wx/menu.h"
- #include "wx/toplevel.h"
- #include "wx/icon.h"
-#endif
-
-#include "wx/mac/private.h"
-
-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;
-
- DECLARE_NO_COPY_CLASS(wxTaskBarIconImpl)
-};
-
-//-----------------------------------------------------------------------------
-//
-// 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, wxID_ANY, wxEmptyString), 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;
-};
-
-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;
- wxWindow *m_eventWindow;
- wxMenu *m_pMenu;
- MenuRef m_theLastMenu;
- bool m_iconAdded;
-};
-
-// Forward declarations for utility functions for dock implementation
-pascal OSStatus wxDockEventHandler(
- EventHandlerCallRef inHandlerCallRef,
- EventRef inEvent, void* pData );
-wxMenu * wxDeepCopyMenu( wxMenu *menu );
-
-
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-//
-// wxTaskBarIconImpl
-//
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-wxTaskBarIconImpl::wxTaskBarIconImpl(wxTaskBarIcon* parent)
- : m_parent(parent), m_menuEventWindow(new wxTaskBarIconWindow(this))
-{
-}
-
-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 WXUNUSED(inHandlerCallRef),
- EventRef inEvent,
- void *pData)
-{
- // Get the parameters we want from the event
- wxDockTaskBarIcon* pTB = (wxDockTaskBarIcon*) pData;
- const UInt32 eventClass = GetEventClass(inEvent);
- const UInt32 eventKind = GetEventKind(inEvent);
-
- OSStatus err = eventNotHandledErr;
-
- // 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 || eventKind == kEventCommandUpdateStatus ))
- {
- // if we have no taskbar menu quickly pass it back to wxApp
- if (pTB->m_pMenu != NULL)
- {
- // This is the real reason why we need this. Normally menus
- // get handled in wxMacAppEventHandler
- // However, in the case of a taskbar menu call
- // command.menu.menuRef IS NULL!
- // Which causes the wxApp handler just to skip it.
-
- // get the HICommand from the event
- HICommand command;
- if (GetEventParameter(inEvent, kEventParamDirectObject,
- typeHICommand, NULL,sizeof(HICommand), NULL, &command ) == noErr)
- {
- // Obtain the REAL menuRef and the menuItemIndex in the real menuRef
- //
- // 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;
- MenuRef taskbarMenuRef = MAC_WXHMENU(pTB->m_pMenu->GetHMenu());
-
- // the next command is only successful if it was a command from the taskbar menu
- // otherwise we pass it on
- if (GetIndMenuItemWithCommandID(taskbarMenuRef,command.commandID,
- 1, &menuRef, &menuItemIndex ) == noErr)
- {
- wxMenu* itemMenu = wxFindMenuFromMacMenu( menuRef ) ;
- int id = wxMacCommandToId( command.commandID ) ;
- wxMenuItem *item = NULL;
-
- if (id != 0) // get the wxMenuItem reference from the MenuRef
- GetMenuItemRefCon( menuRef, menuItemIndex, (URefCon*) &item );
-
- if (item && itemMenu )
- {
- if ( eventKind == kEventCommandProcess )
- err = itemMenu->MacHandleCommandProcess( item, id );
- else if ( eventKind == kEventCommandUpdateStatus )
- err = itemMenu->MacHandleCommandUpdateStatus( item, id );
- }
- }
- }
- } //end if noErr on getting HICommand from event
- }
- else if ((eventClass == kEventClassApplication) && (eventKind == kEventAppGetDockTileMenu ))
- {
- // process the right click events
- // NB: This may result in double or even triple-creation of the menus
- // 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
- wxMenu* menu = pTB->DoCreatePopupMenu();
-
- if (menu != NULL)
- {
- // note to self - a MenuRef *is* a MenuHandle
- MenuRef hMenu = MAC_WXHMENU(menu->GetHMenu());
-
- // When SetEventParameter is called it will decrement
- // the reference count of the menu - we need to make
- // sure it stays around in the wxMenu class here
- CFRetain(hMenu);
-
- // set the actual dock menu
- err = SetEventParameter(
- inEvent, kEventParamMenuRef,
- typeMenuRef, sizeof(MenuRef), &hMenu );
- verify_noerr( err );
- }
- }
-
- return err;
-}
-
-//-----------------------------------------------------------------------------
-// wxDeepCopyMenu
-//
-// Performs a top-to-bottom copy of the input menu and all of its
-// 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 )
-{
- if (menu == NULL)
- return NULL;
-
- // 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();
-
- // create the main menu
- wxMenu *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->GetItemLabel(), // 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;
-}
-
-//-----------------------------------------------------------------------------
-// wxDockTaskBarIcon ctor
-//
-// 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 },
- { kEventClassCommand, kEventCommandUpdateStatus },
- { kEventClassApplication, kEventAppGetDockTileMenu }
- };
-
- m_eventupp = NewEventHandlerUPP(wxDockEventHandler);
- wxASSERT(m_eventupp != NULL);
-
- OSStatus err = InstallApplicationEventHandler(
- m_eventupp,
- GetEventTypeCount(tbEventList), tbEventList,
- this, &m_eventHandlerRef);
- verify_noerr( err );
-}
-
-//-----------------------------------------------------------------------------
-// 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& WXUNUSED(tooltip))
-{
- // convert the wxIcon into a wxBitmap so we can perform some
- // wxBitmap operations with it
- wxBitmap bmp( icon );
- wxASSERT( bmp.Ok() );
-
- // get the CGImageRef for the wxBitmap:
- // OSX builds only, but then the dock only exists in OSX
- CGImageRef pImage = (CGImageRef) bmp.CreateCGImage();
- wxASSERT( pImage != NULL );
-
- // actually set the dock image
- OSStatus err = SetApplicationDockTileImage( pImage );
- verify_noerr( err );
-
- // free the CGImage, now that it's referenced by the dock
- if (pImage != NULL)
- CGImageRelease( pImage );
-
- bool success = (err == noErr);
- m_iconAdded = success;
-
- return success;
-}
-
-//-----------------------------------------------------------------------------
-// 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();
- verify_noerr( err );
-
- // restore the old menu to the dock
- SetApplicationDockTileMenu( m_theLastMenu );
-
- bool success = (err == noErr);
- m_iconAdded = !success;
-
- return success;
-}
-
-//-----------------------------------------------------------------------------
-// wxDockTaskBarIcon::PopupMenu
-//
-// 2.4 and wxPython method that "pops of the menu in the taskbar".
-//
-// 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);
-
- // finish up
- m_pMenu->SetInvokingWindow(m_menuEventWindow);
-
- return true;
-}
-
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-//
-// 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)
-{
- wxASSERT_MSG(
- nType == DOCK,
- wxT("Only the DOCK implementation of wxTaskBarIcon 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 // wxUSE_TASKBARICON