]>
Commit | Line | Data |
---|---|---|
607667fd | 1 | ///////////////////////////////////////////////////////////////////////////// |
e768548a | 2 | // Name: taskbar.cpp |
607667fd RN |
3 | // Purpose: wxTaskBarIcon OSX Implementation |
4 | // Author: Ryan Norton | |
5 | // Modified by: | |
6 | // Created: 09/25/2004 | |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) 2004 Ryan Norton | |
9 | // Licence: wxWindows licence | |
10 | ///////////////////////////////////////////////////////////////////////////// | |
11 | ||
12 | #include "wx/wxprec.h" | |
13 | ||
14 | #include "wx/defs.h" | |
15 | ||
16 | #ifdef wxHAS_TASK_BAR_ICON | |
17 | ||
18 | #include "wx/mac/private.h" | |
19 | ||
20 | #include "wx/taskbar.h" | |
21 | #include "wx/menu.h" | |
22 | #include "wx/icon.h" | |
af7e08a4 | 23 | #include "wx/dcmemory.h" |
607667fd | 24 | |
607667fd RN |
25 | IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler) |
26 | ||
e768548a RD |
27 | pascal OSStatus wxDockEventHandler( EventHandlerCallRef inHandlerCallRef, |
28 | EventRef inEvent, void* pData) | |
607667fd RN |
29 | { |
30 | wxTaskBarIcon*& pTB = (wxTaskBarIcon*&) pData; | |
31 | ||
32 | const UInt32 eventClass = GetEventClass(inEvent); | |
33 | const UInt32 eventKind = GetEventKind(inEvent); | |
34 | ||
35 | if (eventClass == kEventClassCommand && eventKind == kEventCommandProcess) | |
36 | { | |
af7e08a4 RN |
37 | //TODO: This is a complete copy of |
38 | //static pascal OSStatus wxMacAppCommandEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) | |
39 | ||
40 | MenuRef hMenu = MAC_WXHMENU(pTB->GetCurrentMenu()->GetHMenu()); | |
41 | OSStatus result = eventNotHandledErr ; | |
42 | ||
43 | HICommand command ; | |
44 | OSErr err; | |
45 | ||
46 | err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, | |
607667fd | 47 | NULL, sizeof(HICommand), NULL, &command); |
af7e08a4 | 48 | wxASSERT(err == noErr); |
607667fd | 49 | |
af7e08a4 RN |
50 | MenuItemIndex menuItemIndex; |
51 | err = GetIndMenuItemWithCommandID(hMenu, command.commandID, 1, NULL, &menuItemIndex); | |
52 | wxASSERT(err == noErr); | |
607667fd RN |
53 | |
54 | ||
af7e08a4 RN |
55 | MenuCommand id = command.commandID ; |
56 | wxMenuItem* item = NULL; | |
607667fd | 57 | |
af7e08a4 RN |
58 | // for items we don't really control |
59 | if ( id == kHICommandPreferences ) | |
607667fd | 60 | { |
af7e08a4 RN |
61 | id = wxApp::s_macPreferencesMenuItemId ; |
62 | ||
63 | wxMenuBar* mbar = wxMenuBar::MacGetInstalledMenuBar() ; | |
64 | ||
65 | if ( mbar ) | |
66 | { | |
67 | wxMenu* menu = NULL ; | |
68 | item = mbar->FindItem( id , &menu ) ; | |
69 | } | |
607667fd | 70 | } |
af7e08a4 RN |
71 | else if (id != 0) |
72 | GetMenuItemRefCon( hMenu , menuItemIndex , (UInt32*) &item ) ; | |
607667fd | 73 | |
af7e08a4 | 74 | if ( item ) |
e768548a | 75 | { |
af7e08a4 RN |
76 | if (item->IsCheckable()) |
77 | { | |
78 | item->Check( !item->IsChecked() ) ; | |
79 | } | |
80 | ||
81 | item->GetMenu()->SendEvent( id , item->IsCheckable() ? item->IsChecked() : -1 ) ; | |
82 | result = noErr ; | |
e768548a | 83 | } |
af7e08a4 RN |
84 | |
85 | return result ; | |
607667fd RN |
86 | } |
87 | ||
88 | wxASSERT(eventClass == kEventClassApplication && eventKind == kEventAppGetDockTileMenu); | |
af7e08a4 RN |
89 | |
90 | //process the right click events | |
91 | wxTaskBarIconEvent downevt(wxEVT_TASKBAR_RIGHT_DOWN,NULL); | |
92 | pTB->ProcessEvent(downevt); | |
93 | ||
94 | wxTaskBarIconEvent upevt(wxEVT_TASKBAR_RIGHT_UP,NULL); | |
95 | pTB->ProcessEvent(upevt); | |
96 | ||
a45beea1 RN |
97 | //create popup menu |
98 | wxMenu* menu = pTB->DoCreatePopupMenu(); | |
99 | ||
100 | OSStatus err = noErr; | |
101 | ||
102 | if(menu) | |
103 | { | |
104 | //note to self - a MenuRef IS A MenuHandle | |
105 | MenuRef hMenu = MAC_WXHMENU(menu->GetHMenu()); | |
106 | ||
107 | //When we call SetEventParameter it will decrement | |
108 | //the reference count of the menu - we need to make | |
109 | //sure it stays around in the wxMenu class here | |
110 | RetainMenu(hMenu); | |
607667fd | 111 | |
a45beea1 RN |
112 | //set the actual dock menu |
113 | err = SetEventParameter((EventRef) inEvent, kEventParamMenuRef, | |
e768548a RD |
114 | typeMenuRef, sizeof(MenuRef), |
115 | &hMenu); | |
a45beea1 | 116 | wxASSERT(err == 0); |
a45beea1 | 117 | |
af7e08a4 RN |
118 | return err; |
119 | } | |
120 | else | |
121 | return eventNotHandledErr; | |
607667fd RN |
122 | } |
123 | ||
124 | DEFINE_ONE_SHOT_HANDLER_GETTER( wxDockEventHandler ); | |
125 | ||
126 | wxTaskBarIcon::wxTaskBarIcon(const wxTaskBarIconType& nType) | |
af7e08a4 RN |
127 | : m_nType(nType), m_pEventHandlerRef(NULL), m_pMenu(NULL), |
128 | m_theLastMenu((WXHMENU)GetApplicationDockTileMenu()), m_iconAdded(false) | |
607667fd RN |
129 | { |
130 | //Register the events that will return the dock menu | |
e768548a | 131 | EventTypeSpec tbEventList[] = { { kEventClassCommand, kEventProcessCommand }, |
607667fd | 132 | { kEventClassApplication, kEventAppGetDockTileMenu } }; |
e768548a | 133 | |
cc3388ae | 134 | #ifdef __WXDEBUG__ |
e768548a | 135 | OSStatus err = |
cc3388ae | 136 | #endif |
e768548a | 137 | InstallApplicationEventHandler( |
607667fd RN |
138 | GetwxDockEventHandlerUPP(), |
139 | GetEventTypeCount(tbEventList), tbEventList, | |
e768548a RD |
140 | this, (&(EventHandlerRef&)m_pEventHandlerRef)); |
141 | ||
142 | wxASSERT(err == noErr); | |
607667fd | 143 | } |
cc3388ae | 144 | |
607667fd RN |
145 | wxTaskBarIcon::~wxTaskBarIcon() |
146 | { | |
af7e08a4 | 147 | //clean up event handler |
cc3388ae | 148 | RemoveEventHandler((EventHandlerRef&)m_pEventHandlerRef); |
af7e08a4 RN |
149 | |
150 | //restore old icon and menu to the dock | |
151 | RemoveIcon(); | |
607667fd RN |
152 | } |
153 | ||
a45beea1 | 154 | wxMenu* wxTaskBarIcon::GetCurrentMenu() |
607667fd | 155 | { |
a45beea1 | 156 | return m_pMenu; |
607667fd RN |
157 | } |
158 | ||
a45beea1 | 159 | wxMenu* wxTaskBarIcon::DoCreatePopupMenu() |
af7e08a4 RN |
160 | { |
161 | wxMenu* theNewMenu = CreatePopupMenu(); | |
a45beea1 | 162 | |
af7e08a4 RN |
163 | if (theNewMenu) |
164 | { | |
165 | delete m_pMenu; | |
166 | m_pMenu = theNewMenu; | |
a45beea1 | 167 | m_pMenu->SetEventHandler(this); |
af7e08a4 | 168 | } |
a45beea1 | 169 | |
607667fd RN |
170 | return m_pMenu; |
171 | } | |
172 | ||
173 | // Operations: | |
174 | bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip) | |
175 | { | |
e768548a RD |
176 | wxMask* mask = icon.GetMask(); |
177 | if (!mask) | |
178 | { | |
179 | // Make a mask with no transparent pixels | |
180 | wxBitmap bmp(icon.GetWidth(), icon.GetHeight()); | |
181 | wxMemoryDC dc; | |
182 | dc.SelectObject(bmp); | |
183 | dc.SetBackground(*wxBLACK_BRUSH); | |
184 | dc.Clear(); | |
185 | dc.SelectObject(wxNullBitmap); | |
186 | mask = new wxMask(bmp, *wxWHITE); | |
187 | } | |
188 | ||
189 | CGImageRef pImage; | |
607667fd | 190 | |
e768548a RD |
191 | //create the icon from the bitmap and mask bitmap contained within |
192 | OSStatus err = CreateCGImageFromPixMaps( | |
193 | GetGWorldPixMap(MAC_WXHBITMAP(icon.GetHBITMAP())), | |
194 | GetGWorldPixMap(MAC_WXHBITMAP(mask->GetMaskBitmap())), | |
195 | &pImage | |
196 | ); | |
197 | ||
198 | wxASSERT(err == 0); | |
cc3388ae | 199 | |
e768548a RD |
200 | err = SetApplicationDockTileImage(pImage); |
201 | ||
202 | wxASSERT(err == 0); | |
739e35e4 RN |
203 | |
204 | if (pImage != NULL) | |
205 | CGImageRelease(pImage); | |
607667fd | 206 | |
e768548a RD |
207 | if (!icon.GetMask()) |
208 | delete mask; | |
209 | ||
210 | return m_iconAdded = err == noErr; | |
607667fd | 211 | } |
e768548a | 212 | |
607667fd RN |
213 | bool wxTaskBarIcon::RemoveIcon() |
214 | { | |
af7e08a4 RN |
215 | if(m_pMenu) |
216 | { | |
217 | delete m_pMenu; | |
218 | m_pMenu = NULL; | |
219 | } | |
220 | ||
221 | //restore old icon to the dock | |
222 | OSStatus err = RestoreApplicationDockTileImage(); | |
223 | wxASSERT(err == 0); | |
224 | ||
225 | //restore the old menu to the dock | |
226 | SetApplicationDockTileMenu(MAC_WXHMENU(m_theLastMenu)); | |
607667fd | 227 | |
e768548a | 228 | return !(m_iconAdded = !(err == noErr)); |
607667fd | 229 | } |
e768548a | 230 | |
607667fd RN |
231 | bool wxTaskBarIcon::PopupMenu(wxMenu *menu) |
232 | { | |
af7e08a4 RN |
233 | wxASSERT(menu != NULL); |
234 | ||
607667fd | 235 | if (m_pMenu) |
af7e08a4 | 236 | { |
607667fd | 237 | delete m_pMenu; |
af7e08a4 RN |
238 | m_pMenu = NULL; |
239 | } | |
a45beea1 | 240 | |
af7e08a4 RN |
241 | // |
242 | // NB: Here we have to perform a deep copy of the menu, | |
243 | // copying each and every menu item from menu to m_pMenu. | |
244 | // Other implementations use wxWindow::PopupMenu here, | |
245 | // which idle execution until the user selects something, | |
246 | // but since the mac handles this internally, we can't - | |
247 | // and have no way at all to idle it while the dock menu | |
248 | // is being shown before menu goes out of scope (it may | |
249 | // not be on the heap, and may expire right after this function | |
250 | // is done - we need it to last until the carbon event is triggered - | |
251 | // that's when the user right clicks). | |
252 | // | |
253 | // Also, since there is no equal (assignment) operator | |
254 | // on either wxMenu or wxMenuItem, we have to do all the | |
255 | // dirty work ourselves. | |
256 | // | |
257 | ||
258 | //Perform a deep copy of the menu | |
259 | wxMenuItemList& theList = menu->GetMenuItems(); | |
260 | wxMenuItemList::compatibility_iterator theNode = theList.GetFirst(); | |
a45beea1 | 261 | |
af7e08a4 RN |
262 | //create the main menu |
263 | m_pMenu = new wxMenu(menu->GetTitle()); | |
a45beea1 | 264 | |
af7e08a4 RN |
265 | while(theNode != NULL) |
266 | { | |
267 | wxMenuItem* theItem = theNode->GetData(); | |
268 | m_pMenu->Append(new wxMenuItem( m_pMenu, //parent menu | |
269 | theItem->GetId(), //id | |
270 | theItem->GetText(), //text label | |
271 | theItem->GetHelp(), //status bar help string | |
272 | theItem->GetKind(), //menu flags - checkable, seperator, etc. | |
273 | theItem->GetSubMenu() //submenu | |
274 | )); | |
275 | theNode = theNode->GetNext(); | |
276 | } | |
277 | ||
278 | m_pMenu->SetEventHandler(this); | |
279 | return true; | |
607667fd RN |
280 | } |
281 | ||
f2641bc2 | 282 | #endif //wxHAS_TASK_BAR_ICON |