1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxTaskBarIcon OSX Implementation 
   8 // Copyright:   (c) 2004 Ryan Norton 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 #include "wx/wxprec.h" 
  14 #ifdef wxHAS_TASK_BAR_ICON 
  16 #include "wx/mac/private.h" 
  18 #include "wx/taskbar.h" 
  21 #include "wx/dcmemory.h" 
  23 IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon
, wxEvtHandler
) 
  25 pascal OSStatus 
wxDockEventHandler( EventHandlerCallRef inHandlerCallRef
, 
  26                                     EventRef inEvent
, void* pData
) 
  28     wxTaskBarIcon
*& pTB 
= (wxTaskBarIcon
*&) pData
; 
  30     const UInt32 eventClass 
= GetEventClass(inEvent
); 
  31     const UInt32 eventKind 
= GetEventKind(inEvent
); 
  33     if (eventClass 
== kEventClassCommand 
&& eventKind 
== kEventCommandProcess
)  
  35         //TODO: This is a complete copy of  
  36         //static pascal OSStatus wxMacAppCommandEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) 
  38         if (! pTB
->GetCurrentMenu() ) 
  40             return eventNotHandledErr
; 
  43         MenuRef hMenu 
= MAC_WXHMENU(pTB
->GetCurrentMenu()->GetHMenu()); 
  44         OSStatus result 
= eventNotHandledErr 
; 
  49         err 
=    GetEventParameter(inEvent
, kEventParamDirectObject
, typeHICommand
,      
  50                             NULL
, sizeof(HICommand
), NULL
, &command
); 
  51         wxASSERT(err 
== noErr
); 
  53         MenuItemIndex menuItemIndex
; 
  54         err 
= GetIndMenuItemWithCommandID(hMenu
, command
.commandID
, 1, NULL
, &menuItemIndex
); 
  55         wxASSERT(err 
== noErr
); 
  58         MenuCommand id 
= command
.commandID 
; 
  59         wxMenuItem
* item 
= NULL
; 
  61         // for items we don't really control 
  62         if ( id 
== kHICommandPreferences 
) 
  64             id 
= wxApp::s_macPreferencesMenuItemId 
; 
  66             wxMenuBar
* mbar 
= wxMenuBar::MacGetInstalledMenuBar() ; 
  71                 item 
= mbar
->FindItem( id 
, &menu 
) ; 
  75             GetMenuItemRefCon( hMenu 
, menuItemIndex 
, (UInt32
*) &item 
) ; 
  79             if (item
->IsCheckable()) 
  81                 item
->Check( !item
->IsChecked() ) ; 
  84             item
->GetMenu()->SendEvent( id 
, item
->IsCheckable() ? item
->IsChecked() : -1 ) ; 
  91     wxASSERT(eventClass 
== kEventClassApplication 
&& eventKind 
== kEventAppGetDockTileMenu
); 
  93         //process the right click events 
  94         wxTaskBarIconEvent 
downevt(wxEVT_TASKBAR_RIGHT_DOWN
,NULL
); 
  95         pTB
->ProcessEvent(downevt
); 
  97         wxTaskBarIconEvent 
upevt(wxEVT_TASKBAR_RIGHT_UP
,NULL
); 
  98         pTB
->ProcessEvent(upevt
); 
 101     wxMenu
* menu 
= pTB
->DoCreatePopupMenu(); 
 103     OSStatus err 
= noErr
; 
 107         //note to self - a MenuRef IS A MenuHandle 
 108         MenuRef hMenu 
= MAC_WXHMENU(menu
->GetHMenu()); 
 110         //When we call SetEventParameter it will decrement 
 111         //the reference count of the menu - we need to make 
 112         //sure it stays around in the wxMenu class here 
 115         //set the actual dock menu 
 116         err 
= SetEventParameter((EventRef
) inEvent
, kEventParamMenuRef
,  
 117                     typeMenuRef
, sizeof(MenuRef
),  
 124         return eventNotHandledErr
; 
 127 DEFINE_ONE_SHOT_HANDLER_GETTER( wxDockEventHandler 
); 
 129 wxTaskBarIcon::wxTaskBarIcon(const wxTaskBarIconType
& nType
) 
 130     : m_nType(nType
), m_pEventHandlerRef(NULL
), m_pMenu(NULL
),  
 131         m_theLastMenu((WXHMENU
)GetApplicationDockTileMenu()), m_iconAdded(false)  
 133     //Register the events that will return the dock menu 
 134     EventTypeSpec tbEventList
[] = { { kEventClassCommand
, kEventProcessCommand 
}, 
 135                                     { kEventClassApplication
, kEventAppGetDockTileMenu 
} }; 
 140     InstallApplicationEventHandler( 
 141             GetwxDockEventHandlerUPP(), 
 142             GetEventTypeCount(tbEventList
), tbEventList
,  
 143             this, (&(EventHandlerRef
&)m_pEventHandlerRef
)); 
 145     wxASSERT(err 
== noErr
); 
 148 wxTaskBarIcon::~wxTaskBarIcon() 
 150     //clean up event handler 
 151     RemoveEventHandler((EventHandlerRef
&)m_pEventHandlerRef
); 
 153     //restore old icon and menu to the dock 
 157 wxMenu
* wxTaskBarIcon::GetCurrentMenu() 
 162 wxMenu
* wxTaskBarIcon::DoCreatePopupMenu() 
 164     wxMenu
* theNewMenu 
= CreatePopupMenu(); 
 169         m_pMenu 
= theNewMenu
; 
 170         m_pMenu
->SetEventHandler(this); 
 177 bool wxTaskBarIcon::SetIcon(const wxIcon
& icon
, const wxString
& tooltip
) 
 179     wxBitmap 
bmp( icon 
) ; 
 180     OSStatus err 
= noErr 
; 
 184 #if 1 // is always available under OSX now        
 185     pImage 
= (CGImageRef
) bmp
.CGImageCreate() ; 
 189     iconport 
= bmp
.GetHBITMAP( &maskport 
) ; 
 193         // Make a mask with no transparent pixels 
 194         wxBitmap   
mbmp(icon
.GetWidth(), icon
.GetHeight()); 
 196         dc
.SelectObject(mbmp
); 
 197         dc
.SetBackground(*wxBLACK_BRUSH
); 
 199         dc
.SelectObject(wxNullBitmap
); 
 200         bmp
.SetMask( new wxMask(mbmp
, *wxWHITE
) ) ; 
 201         iconport 
= bmp
.GetHBITMAP( &maskport 
) ; 
 204     //create the icon from the bitmap and mask bitmap contained within 
 205     err 
= CreateCGImageFromPixMaps( 
 206                                             GetGWorldPixMap(MAC_WXHBITMAP(iconport
)), 
 207                                             GetGWorldPixMap(MAC_WXHBITMAP(maskport
)), 
 212     wxASSERT(pImage 
!= NULL 
); 
 213     err 
= SetApplicationDockTileImage(pImage
); 
 218         CGImageRelease(pImage
); 
 220     return m_iconAdded 
= err 
== noErr
; 
 223 bool wxTaskBarIcon::RemoveIcon() 
 231     //restore old icon to the dock 
 232         OSStatus err 
= RestoreApplicationDockTileImage(); 
 235     //restore the old menu to the dock 
 236     SetApplicationDockTileMenu(MAC_WXHMENU(m_theLastMenu
)); 
 238     return !(m_iconAdded 
= !(err 
== noErr
)); 
 241 bool wxTaskBarIcon::PopupMenu(wxMenu 
*menu
) 
 243     wxASSERT(menu 
!= NULL
); 
 252     // NB:  Here we have to perform a deep copy of the menu, 
 253     // copying each and every menu item from menu to m_pMenu. 
 254     // Other implementations use wxWindow::PopupMenu here,  
 255     // which idle execution until the user selects something, 
 256     // but since the mac handles this internally, we can't -  
 257     // and have no way at all to idle it while the dock menu 
 258     // is being shown before menu goes out of scope (it may 
 259     // not be on the heap, and may expire right after this function 
 260     // is done - we need it to last until the carbon event is triggered -  
 261     // that's when the user right clicks). 
 263     // Also, since there is no equal (assignment) operator  
 264     // on either wxMenu or wxMenuItem, we have to do all the 
 265     // dirty work ourselves. 
 268     //Perform a deep copy of the menu 
 269     wxMenuItemList
& theList 
= menu
->GetMenuItems(); 
 270     wxMenuItemList::compatibility_iterator theNode 
= theList
.GetFirst(); 
 272     //create the main menu 
 273     m_pMenu 
= new wxMenu(menu
->GetTitle()); 
 275     while(theNode 
!= NULL
) 
 277         wxMenuItem
* theItem 
= theNode
->GetData(); 
 278         m_pMenu
->Append(new wxMenuItem( m_pMenu
, //parent menu 
 279                                         theItem
->GetId(), //id 
 280                                         theItem
->GetText(), //text label 
 281                                         theItem
->GetHelp(), //status bar help string 
 282                                         theItem
->GetKind(), //menu flags - checkable, seperator, etc. 
 283                                         theItem
->GetSubMenu() //submenu 
 285         theNode 
= theNode
->GetNext(); 
 288     m_pMenu
->SetEventHandler(this); 
 292 #endif //wxHAS_TASK_BAR_ICON