1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/osx/carbon/app.cpp
3 // Purpose:     wxApp
4 // Author:      Stefan Csomor
5 // Modified by:
6 // Created:     1998-01-01
7 // Copyright:   (c) Stefan Csomor
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 #include "wx/wxprec.h"
12 
13 #include "wx/app.h"
14 
15 #ifndef WX_PRECOMP
16     #include "wx/intl.h"
17     #include "wx/log.h"
18     #include "wx/utils.h"
19     #include "wx/window.h"
20     #include "wx/frame.h"
21     #include "wx/dc.h"
22     #include "wx/button.h"
23     #include "wx/menu.h"
24     #include "wx/pen.h"
25     #include "wx/brush.h"
26     #include "wx/palette.h"
27     #include "wx/icon.h"
28     #include "wx/cursor.h"
29     #include "wx/dialog.h"
30     #include "wx/msgdlg.h"
31     #include "wx/textctrl.h"
32     #include "wx/memory.h"
33     #include "wx/gdicmn.h"
34     #include "wx/module.h"
35 #endif
36 
37 #include "wx/tooltip.h"
38 #include "wx/docview.h"
39 #include "wx/filename.h"
40 #include "wx/link.h"
41 #include "wx/thread.h"
42 #include "wx/evtloop.h"
43 
44 #include <string.h>
45 
46 // mac
47 #if wxOSX_USE_CARBON
48 #include "wx/osx/uma.h"
49 #else
50 #include "wx/osx/private.h"
51 #endif
52 
53 #if defined(WXMAKINGDLL_CORE)
54 #   include <mach-o/dyld.h>
55 #endif
56 
57 // Keep linker from discarding wxStockGDIMac
58 wxFORCE_LINK_MODULE(gdiobj)
59 
60 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
61 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
62     EVT_IDLE(wxApp::OnIdle)
63     EVT_END_SESSION(wxApp::OnEndSession)
64     EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
65 END_EVENT_TABLE()
66 
67 
68 wxWindow* wxApp::s_captureWindow = NULL ;
69 long      wxApp::s_lastModifiers = 0 ;
70 
71 long      wxApp::s_macAboutMenuItemId = wxID_ABOUT ;
72 long      wxApp::s_macPreferencesMenuItemId = wxID_PREFERENCES ;
73 long      wxApp::s_macExitMenuItemId = wxID_EXIT ;
74 wxString  wxApp::s_macHelpMenuTitleName = wxT("&Help") ;
75 
76 bool      wxApp::sm_isEmbedded = false; // Normally we're not a plugin
77 
78 #if wxOSX_USE_CARBON
79 
80 //----------------------------------------------------------------------
81 // Core Apple Event Support
82 //----------------------------------------------------------------------
83 
84 AEEventHandlerUPP sODocHandler = NULL ;
85 AEEventHandlerUPP sGURLHandler = NULL ;
86 AEEventHandlerUPP sOAppHandler = NULL ;
87 AEEventHandlerUPP sPDocHandler = NULL ;
88 AEEventHandlerUPP sRAppHandler = NULL ;
89 AEEventHandlerUPP sQuitHandler = NULL ;
90 
91 pascal OSErr AEHandleODoc( const AppleEvent *event , AppleEvent *reply , SRefCon refcon ) ;
92 pascal OSErr AEHandleOApp( const AppleEvent *event , AppleEvent *reply , SRefCon refcon ) ;
93 pascal OSErr AEHandlePDoc( const AppleEvent *event , AppleEvent *reply , SRefCon refcon ) ;
94 pascal OSErr AEHandleQuit( const AppleEvent *event , AppleEvent *reply , SRefCon refcon ) ;
95 pascal OSErr AEHandleRApp( const AppleEvent *event , AppleEvent *reply , SRefCon refcon ) ;
96 pascal OSErr AEHandleGURL( const AppleEvent *event , AppleEvent *reply , SRefCon refcon ) ;
97 
AEHandleODoc(const AppleEvent * event,AppleEvent * reply,SRefCon WXUNUSED (refcon))98 pascal OSErr AEHandleODoc( const AppleEvent *event , AppleEvent *reply , SRefCon WXUNUSED(refcon) )
99 {
100     return wxTheApp->MacHandleAEODoc( (AppleEvent*) event , reply) ;
101 }
102 
AEHandleOApp(const AppleEvent * event,AppleEvent * reply,SRefCon WXUNUSED (refcon))103 pascal OSErr AEHandleOApp( const AppleEvent *event , AppleEvent *reply , SRefCon WXUNUSED(refcon) )
104 {
105     return wxTheApp->MacHandleAEOApp( (AppleEvent*) event , reply ) ;
106 }
107 
AEHandlePDoc(const AppleEvent * event,AppleEvent * reply,SRefCon WXUNUSED (refcon))108 pascal OSErr AEHandlePDoc( const AppleEvent *event , AppleEvent *reply , SRefCon WXUNUSED(refcon) )
109 {
110     return wxTheApp->MacHandleAEPDoc( (AppleEvent*) event , reply ) ;
111 }
112 
AEHandleQuit(const AppleEvent * event,AppleEvent * reply,SRefCon WXUNUSED (refcon))113 pascal OSErr AEHandleQuit( const AppleEvent *event , AppleEvent *reply , SRefCon WXUNUSED(refcon) )
114 {
115     return wxTheApp->MacHandleAEQuit( (AppleEvent*) event , reply) ;
116 }
117 
AEHandleRApp(const AppleEvent * event,AppleEvent * reply,SRefCon WXUNUSED (refcon))118 pascal OSErr AEHandleRApp( const AppleEvent *event , AppleEvent *reply , SRefCon WXUNUSED(refcon) )
119 {
120     return wxTheApp->MacHandleAERApp( (AppleEvent*) event , reply) ;
121 }
122 
AEHandleGURL(const AppleEvent * event,AppleEvent * reply,SRefCon WXUNUSED (refcon))123 pascal OSErr AEHandleGURL( const AppleEvent *event , AppleEvent *reply , SRefCon WXUNUSED(refcon) )
124 {
125     return wxTheApp->MacHandleAEGURL((WXEVENTREF *)event , reply) ;
126 }
127 
128 
129 // AEODoc Calls MacOpenFiles with all of the files passed
130 
MacHandleAEODoc(const WXEVENTREF event,WXEVENTREF WXUNUSED (reply))131 short wxApp::MacHandleAEODoc(const WXEVENTREF event, WXEVENTREF WXUNUSED(reply))
132 {
133     AEDescList docList;
134     AEKeyword keywd;
135     DescType returnedType;
136     Size actualSize;
137     long itemsInList;
138     OSErr err;
139     short i;
140 
141     err = AEGetParamDesc((AppleEvent *)event, keyDirectObject, typeAEList,&docList);
142     if (err != noErr)
143         return err;
144 
145     err = AECountItems(&docList, &itemsInList);
146     if (err != noErr)
147         return err;
148 
149     ProcessSerialNumber PSN ;
150     PSN.highLongOfPSN = 0 ;
151     PSN.lowLongOfPSN = kCurrentProcess ;
152     SetFrontProcess( &PSN ) ;
153 
154     wxString fName ;
155     FSRef theRef ;
156 
157     wxArrayString fileNames;
158     for (i = 1; i <= itemsInList; i++)
159     {
160         err = AEGetNthPtr(
161             &docList, i, typeFSRef, &keywd, &returnedType,
162             (Ptr)&theRef, sizeof(theRef), &actualSize);
163 
164         if ( err != noErr)
165             return err;
166 
167         fName = wxMacFSRefToPath( &theRef ) ;
168 
169         fileNames.Add(fName);
170     }
171 
172     MacOpenFiles(fileNames);
173 
174     return noErr;
175 }
176 
177 // AEODoc Calls MacOpenURL on the url passed
178 
MacHandleAEGURL(const WXEVENTREF event,WXEVENTREF WXUNUSED (reply))179 short wxApp::MacHandleAEGURL(const WXEVENTREF event, WXEVENTREF WXUNUSED(reply))
180 {
181     DescType returnedType;
182     Size actualSize;
183     char url[255];
184     OSErr err = AEGetParamPtr((AppleEvent *)event, keyDirectObject, typeChar,
185                               &returnedType, url, sizeof(url)-1,
186                               &actualSize);
187     if (err != noErr)
188         return err;
189 
190     url[actualSize] = '\0';    // Terminate the C string
191 
192     ProcessSerialNumber PSN ;
193     PSN.highLongOfPSN = 0 ;
194     PSN.lowLongOfPSN = kCurrentProcess ;
195     SetFrontProcess( &PSN ) ;
196 
197     MacOpenURL(wxString(url, wxConvUTF8));
198 
199     return noErr;
200 }
201 
202 // AEPDoc Calls MacPrintFile on each of the files passed
203 
MacHandleAEPDoc(const WXEVENTREF event,WXEVENTREF WXUNUSED (reply))204 short wxApp::MacHandleAEPDoc(const WXEVENTREF event , WXEVENTREF WXUNUSED(reply))
205 {
206     AEDescList docList;
207     AEKeyword keywd;
208     DescType returnedType;
209     Size actualSize;
210     long itemsInList;
211     OSErr err;
212     short i;
213 
214     err = AEGetParamDesc((AppleEvent *)event, keyDirectObject, typeAEList,&docList);
215     if (err != noErr)
216         return err;
217 
218     err = AECountItems(&docList, &itemsInList);
219     if (err != noErr)
220         return err;
221 
222     ProcessSerialNumber PSN ;
223     PSN.highLongOfPSN = 0 ;
224     PSN.lowLongOfPSN = kCurrentProcess ;
225     SetFrontProcess( &PSN ) ;
226 
227     wxString fName ;
228     FSRef theRef ;
229 
230     wxArrayString fileNames;
231 
232     for (i = 1; i <= itemsInList; i++)
233     {
234         err = AEGetNthPtr(
235             &docList, i, typeFSRef, &keywd, &returnedType,
236             (Ptr)&theRef, sizeof(theRef), &actualSize);
237 
238         if ( err != noErr)
239             return err;
240 
241         fName = wxMacFSRefToPath( &theRef ) ;
242         fileNames.Add( fName );
243     }
244 
245     MacPrintFiles(fileNames);
246 
247     return noErr;
248 }
249 
250 // AEOApp calls MacNewFile
251 
MacHandleAEOApp(const WXEVENTREF WXUNUSED (event),WXEVENTREF WXUNUSED (reply))252 short wxApp::MacHandleAEOApp(const WXEVENTREF WXUNUSED(event) , WXEVENTREF WXUNUSED(reply))
253 {
254     MacNewFile() ;
255     return noErr ;
256 }
257 
258 // AEQuit attempts to quit the application
259 
MacHandleAEQuit(const WXEVENTREF WXUNUSED (event),WXEVENTREF WXUNUSED (reply))260 short wxApp::MacHandleAEQuit(const WXEVENTREF WXUNUSED(event) , WXEVENTREF WXUNUSED(reply))
261 {
262     wxCloseEvent event(wxEVT_QUERY_END_SESSION, wxID_ANY);
263     event.SetEventObject(this);
264     event.SetCanVeto(true);
265     ProcessEvent(event);
266     if ( !event.GetVeto() )
267     {
268         wxCloseEvent event(wxEVT_END_SESSION, wxID_ANY);
269         event.SetEventObject(this);
270         event.SetCanVeto(false);
271         ProcessEvent(event);
272     }
273     return noErr ;
274 }
275 
276 // AEROApp calls MacReopenApp
277 
MacHandleAERApp(const WXEVENTREF WXUNUSED (event),WXEVENTREF WXUNUSED (reply))278 short wxApp::MacHandleAERApp(const WXEVENTREF WXUNUSED(event) , WXEVENTREF WXUNUSED(reply))
279 {
280     MacReopenApp() ;
281 
282     return noErr ;
283 }
284 
285 #endif
286 
287 //----------------------------------------------------------------------
288 // Support Routines linking the Mac...File Calls to the Document Manager
289 //----------------------------------------------------------------------
290 
MacOpenFiles(const wxArrayString & fileNames)291 void wxApp::MacOpenFiles(const wxArrayString & fileNames )
292 {
293     size_t i;
294     const size_t fileCount = fileNames.GetCount();
295     for (i = 0; i < fileCount; i++)
296     {
297         MacOpenFile(fileNames[i]);
298     }
299 }
300 
MacOpenFile(const wxString & fileName)301 void wxApp::MacOpenFile(const wxString & fileName )
302 {
303 #if wxUSE_DOC_VIEW_ARCHITECTURE
304     wxDocManager* dm = wxDocManager::GetDocumentManager() ;
305     if ( dm )
306         dm->CreateDocument(fileName , wxDOC_SILENT ) ;
307 #endif
308 }
309 
MacOpenURL(const wxString & WXUNUSED (url))310 void wxApp::MacOpenURL(const wxString & WXUNUSED(url) )
311 {
312 }
313 
MacPrintFiles(const wxArrayString & fileNames)314 void wxApp::MacPrintFiles(const wxArrayString & fileNames )
315 {
316     size_t i;
317     const size_t fileCount = fileNames.GetCount();
318     for (i = 0; i < fileCount; i++)
319     {
320         MacPrintFile(fileNames[i]);
321     }
322 }
323 
MacPrintFile(const wxString & fileName)324 void wxApp::MacPrintFile(const wxString & fileName )
325 {
326 #if wxUSE_DOC_VIEW_ARCHITECTURE
327 
328 #if wxUSE_PRINTING_ARCHITECTURE
329     wxDocManager* dm = wxDocManager::GetDocumentManager() ;
330     if ( dm )
331     {
332         wxDocument *doc = dm->CreateDocument(fileName , wxDOC_SILENT ) ;
333         if ( doc )
334         {
335             wxView* view = doc->GetFirstView() ;
336             if ( view )
337             {
338                 wxPrintout *printout = view->OnCreatePrintout();
339                 if (printout)
340                 {
341                     wxPrinter printer;
342                     printer.Print(view->GetFrame(), printout, true);
343                     delete printout;
344                 }
345             }
346 
347             if (doc->Close())
348             {
349                 doc->DeleteAllViews();
350                 dm->RemoveDocument(doc) ;
351             }
352         }
353     }
354 #endif //print
355 
356 #endif //docview
357 }
358 
359 
360 
MacNewFile()361 void wxApp::MacNewFile()
362 {
363 }
364 
MacReopenApp()365 void wxApp::MacReopenApp()
366 {
367     // HIG says :
368     // if there is no open window -> create a new one
369     // if all windows are hidden -> show the first
370     // if some windows are not hidden -> do nothing
371 
372     wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst();
373     if ( !node )
374     {
375         MacNewFile() ;
376     }
377     else
378     {
379         wxTopLevelWindow* firstIconized = NULL ;
380         wxTopLevelWindow* firstHidden = NULL ;
381         while (node)
382         {
383             wxTopLevelWindow* win = (wxTopLevelWindow*) node->GetData();
384             if ( !win->IsShown() )
385             {
386                 // make sure we don't show 'virtual toplevel windows' like wxTaskBarIconWindow
387                 if ( firstHidden == NULL && ( wxDynamicCast( win, wxFrame ) || wxDynamicCast( win, wxDialog ) ) )
388                    firstHidden = win ;
389             }
390             else if ( win->IsIconized() )
391             {
392                 if ( firstIconized == NULL )
393                     firstIconized = win ;
394             }
395             else
396             {
397                 // we do have a visible, non-iconized toplevelwindow -> do nothing
398                 return;
399             }
400 
401             node = node->GetNext();
402         }
403 
404         if ( firstIconized )
405             firstIconized->Iconize( false ) ;
406 
407         // showing hidden windows is not really always a good solution, also non-modal dialogs when closed end up
408         // as hidden tlws, we don't want to reshow those, so let's just reopen the minimized a.k.a. iconized tlws
409         // unless we find a regression ...
410 #if 0
411         else if ( firstHidden )
412             firstHidden->Show( true );
413 #endif
414     }
415 }
416 
417 #if wxOSX_USE_COCOA_OR_IPHONE
OSXOnWillFinishLaunching()418 void wxApp::OSXOnWillFinishLaunching()
419 {
420 }
421 
OSXOnDidFinishLaunching()422 void wxApp::OSXOnDidFinishLaunching()
423 {
424 }
425 
OSXOnWillTerminate()426 void wxApp::OSXOnWillTerminate()
427 {
428     wxCloseEvent event(wxEVT_END_SESSION, wxID_ANY);
429     event.SetEventObject(this);
430     event.SetCanVeto(false);
431     ProcessEvent(event);
432 }
433 
OSXOnShouldTerminate()434 bool wxApp::OSXOnShouldTerminate()
435 {
436     wxCloseEvent event(wxEVT_QUERY_END_SESSION, wxID_ANY);
437     event.SetEventObject(this);
438     event.SetCanVeto(true);
439     ProcessEvent(event);
440     return !event.GetVeto();
441 }
442 #endif
443 
444 //----------------------------------------------------------------------
445 // Macintosh CommandID support - converting between native and wx IDs
446 //----------------------------------------------------------------------
447 
448 // if no native match they just return the passed-in id
449 
450 #if wxOSX_USE_CARBON
451 
452 // platform specific static variables
453 static const short kwxMacAppleMenuId = 1 ;
454 
455 struct IdPair
456 {
457     UInt32 macId ;
458     int wxId ;
459 } ;
460 
461 IdPair gCommandIds [] =
462 {
463     { kHICommandCut ,           wxID_CUT } ,
464     { kHICommandCopy ,          wxID_COPY } ,
465     { kHICommandPaste ,         wxID_PASTE } ,
466     { kHICommandSelectAll ,     wxID_SELECTALL } ,
467     { kHICommandClear ,         wxID_CLEAR } ,
468     { kHICommandUndo ,          wxID_UNDO } ,
469     { kHICommandRedo ,          wxID_REDO } ,
470 } ;
471 
wxMacCommandToId(UInt32 macCommandId)472 int wxMacCommandToId( UInt32 macCommandId )
473 {
474     int wxid = 0 ;
475 
476     switch ( macCommandId )
477     {
478         case kHICommandPreferences :
479             wxid = wxApp::s_macPreferencesMenuItemId ;
480             break ;
481 
482         case kHICommandQuit :
483             wxid = wxApp::s_macExitMenuItemId ;
484             break ;
485 
486         case kHICommandAbout :
487             wxid = wxApp::s_macAboutMenuItemId ;
488             break ;
489 
490         default :
491             {
492                 for ( size_t i = 0 ; i < WXSIZEOF(gCommandIds) ; ++i )
493                 {
494                     if ( gCommandIds[i].macId == macCommandId )
495                     {
496                         wxid = gCommandIds[i].wxId ;
497                         break ;
498                     }
499                 }
500             }
501             break ;
502     }
503 
504     if ( wxid == 0 )
505         wxid = (int) macCommandId ;
506 
507     return wxid ;
508 }
509 
wxIdToMacCommand(int wxId)510 UInt32 wxIdToMacCommand( int wxId )
511 {
512     UInt32 macId = 0 ;
513 
514     if ( wxId == wxApp::s_macPreferencesMenuItemId )
515         macId = kHICommandPreferences ;
516     else if (wxId == wxApp::s_macExitMenuItemId)
517         macId = kHICommandQuit ;
518     else if (wxId == wxApp::s_macAboutMenuItemId)
519         macId = kHICommandAbout ;
520     else
521     {
522         for ( size_t i = 0 ; i < WXSIZEOF(gCommandIds) ; ++i )
523         {
524             if ( gCommandIds[i].wxId == wxId )
525             {
526                 macId = gCommandIds[i].macId ;
527                 break ;
528             }
529         }
530     }
531 
532     if ( macId == 0 )
533         macId = (int) wxId ;
534 
535     return macId ;
536 }
537 
wxFindMenuFromMacCommand(const HICommand & command,wxMenuItem * & item)538 wxMenu* wxFindMenuFromMacCommand( const HICommand &command , wxMenuItem* &item )
539 {
540     wxMenu* itemMenu = NULL ;
541 #ifndef __WXUNIVERSAL__
542     int id = 0 ;
543 
544     // for 'standard' commands which don't have a wx-menu
545     if ( command.commandID == kHICommandPreferences || command.commandID == kHICommandQuit || command.commandID == kHICommandAbout )
546     {
547         id = wxMacCommandToId( command.commandID ) ;
548 
549         wxMenuBar* mbar = wxMenuBar::MacGetInstalledMenuBar() ;
550         if ( mbar )
551             item = mbar->FindItem( id , &itemMenu ) ;
552     }
553     else if ( command.commandID != 0 && command.menu.menuRef != 0 && command.menu.menuItemIndex != 0 )
554     {
555         id = wxMacCommandToId( command.commandID ) ;
556         // make sure it is one of our own menus, or of the 'synthetic' apple and help menus , otherwise don't touch
557         MenuItemIndex firstUserHelpMenuItem ;
558         static MenuHandle helpMenuHandle = NULL ;
559         if ( helpMenuHandle == NULL )
560         {
561             if ( UMAGetHelpMenuDontCreate( &helpMenuHandle , &firstUserHelpMenuItem) != noErr )
562                 helpMenuHandle = NULL ;
563         }
564 
565         // is it part of the application or the Help menu, then look for the id directly
566         if ( ( GetMenuHandle( kwxMacAppleMenuId ) != NULL && command.menu.menuRef == GetMenuHandle( kwxMacAppleMenuId ) ) ||
567              ( helpMenuHandle != NULL && command.menu.menuRef == helpMenuHandle ) ||
568              wxMenuBar::MacGetWindowMenuHMenu() != NULL && command.menu.menuRef == wxMenuBar::MacGetWindowMenuHMenu() )
569         {
570             wxMenuBar* mbar = wxMenuBar::MacGetInstalledMenuBar() ;
571             if ( mbar )
572                 item = mbar->FindItem( id , &itemMenu ) ;
573         }
574         else
575         {
576             URefCon refCon = 0 ;
577 
578             GetMenuItemRefCon( command.menu.menuRef , command.menu.menuItemIndex , &refCon ) ;
579             itemMenu = wxFindMenuFromMacMenu( command.menu.menuRef ) ;
580             if ( itemMenu != NULL && refCon != 0)
581                 item = (wxMenuItem*) refCon;
582         }
583     }
584 #endif
585     return itemMenu ;
586 }
587 
588 #endif
589 
590 //----------------------------------------------------------------------
591 // Carbon Event Handler
592 //----------------------------------------------------------------------
593 
594 #if wxOSX_USE_CARBON
595 
596 static const EventTypeSpec eventList[] =
597 {
598     { kEventClassCommand, kEventProcessCommand } ,
599     { kEventClassCommand, kEventCommandUpdateStatus } ,
600 
601     { kEventClassMenu, kEventMenuOpening },
602     { kEventClassMenu, kEventMenuClosed },
603     { kEventClassMenu, kEventMenuTargetItem },
604 
605     { kEventClassApplication , kEventAppActivated } ,
606     { kEventClassApplication , kEventAppDeactivated } ,
607     // handling the quit event is not recommended by apple
608     // rather using the quit apple event - which we do
609 
610     { kEventClassAppleEvent , kEventAppleEvent } ,
611 
612     { kEventClassMouse , kEventMouseDown } ,
613     { kEventClassMouse , kEventMouseMoved } ,
614     { kEventClassMouse , kEventMouseUp } ,
615     { kEventClassMouse , kEventMouseDragged } ,
616     { 'WXMC' , 'WXMC' }
617 } ;
618 
619 static pascal OSStatus
wxMacAppMenuEventHandler(EventHandlerCallRef WXUNUSED (handler),EventRef event,void * WXUNUSED (data))620 wxMacAppMenuEventHandler( EventHandlerCallRef WXUNUSED(handler),
621                           EventRef event,
622                           void *WXUNUSED(data) )
623 {
624     wxMacCarbonEvent cEvent( event ) ;
625     MenuRef menuRef = cEvent.GetParameter<MenuRef>(kEventParamDirectObject) ;
626 #ifndef __WXUNIVERSAL__
627     wxMenu* menu = wxFindMenuFromMacMenu( menuRef ) ;
628 
629     if ( menu )
630     {
631         switch (GetEventKind(event))
632         {
633             case kEventMenuOpening:
634                 menu->HandleMenuOpened();
635                 break;
636 
637             case kEventMenuClosed:
638                 menu->HandleMenuClosed();
639                 break;
640 
641             case kEventMenuTargetItem:
642                 {
643                     HICommand command ;
644 
645                     command.menu.menuRef = menuRef;
646                     command.menu.menuItemIndex = cEvent.GetParameter<MenuItemIndex>(kEventParamMenuItemIndex,typeMenuItemIndex) ;
647                     command.commandID = cEvent.GetParameter<MenuCommand>(kEventParamMenuCommand,typeMenuCommand) ;
648                     if (command.commandID != 0)
649                     {
650                         wxMenuItem* item = NULL ;
651                         wxMenu* itemMenu = wxFindMenuFromMacCommand( command , item ) ;
652                         if ( itemMenu && item )
653                             itemMenu->HandleMenuItemHighlighted( item );
654                     }
655                 }
656                 break;
657 
658             default:
659                 wxFAIL_MSG(wxT("Unexpected menu event kind"));
660                 break;
661         }
662 
663     }
664 #endif
665     return eventNotHandledErr;
666 }
667 
668 static pascal OSStatus
wxMacAppCommandEventHandler(EventHandlerCallRef WXUNUSED (handler),EventRef event,void * WXUNUSED (data))669 wxMacAppCommandEventHandler( EventHandlerCallRef WXUNUSED(handler) ,
670                              EventRef event ,
671                              void *WXUNUSED(data) )
672 {
673     OSStatus result = eventNotHandledErr ;
674 
675     HICommand command ;
676 
677     wxMacCarbonEvent cEvent( event ) ;
678     cEvent.GetParameter<HICommand>(kEventParamDirectObject,typeHICommand,&command) ;
679 
680     wxMenuItem* item = NULL ;
681     wxMenu* itemMenu = wxFindMenuFromMacCommand( command , item ) ;
682 
683     if ( item )
684     {
685         wxASSERT( itemMenu != NULL ) ;
686 
687         switch ( cEvent.GetKind() )
688         {
689             case kEventProcessCommand :
690                 if ( itemMenu->HandleCommandProcess( item ) )
691                     result = noErr;
692             break ;
693 
694         case kEventCommandUpdateStatus:
695             if ( itemMenu->HandleCommandUpdateStatus( item ) )
696                     result = noErr;
697             break ;
698 
699         default :
700             break ;
701         }
702     }
703     return result ;
704 }
705 
706 static pascal OSStatus
wxMacAppApplicationEventHandler(EventHandlerCallRef WXUNUSED (handler),EventRef event,void * WXUNUSED (data))707 wxMacAppApplicationEventHandler( EventHandlerCallRef WXUNUSED(handler) ,
708                                  EventRef event ,
709                                  void *WXUNUSED(data) )
710 {
711     OSStatus result = eventNotHandledErr ;
712     switch ( GetEventKind( event ) )
713     {
714         case kEventAppActivated :
715             if ( wxTheApp )
716                 wxTheApp->SetActive( true , NULL ) ;
717             result = noErr ;
718             break ;
719 
720         case kEventAppDeactivated :
721             if ( wxTheApp )
722                 wxTheApp->SetActive( false , NULL ) ;
723             result = noErr ;
724             break ;
725 
726         default :
727             break ;
728     }
729 
730     return result ;
731 }
732 
wxMacAppEventHandler(EventHandlerCallRef handler,EventRef event,void * data)733 pascal OSStatus wxMacAppEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
734 {
735     EventRef formerEvent = (EventRef) wxTheApp->MacGetCurrentEvent() ;
736     EventHandlerCallRef formerEventHandlerCallRef = (EventHandlerCallRef) wxTheApp->MacGetCurrentEventHandlerCallRef() ;
737     wxTheApp->MacSetCurrentEvent( event , handler ) ;
738 
739     OSStatus result = eventNotHandledErr ;
740     switch ( GetEventClass( event ) )
741     {
742 #ifndef __LP64__
743         case kEventClassCommand :
744             result = wxMacAppCommandEventHandler( handler , event , data ) ;
745             break ;
746 #endif
747         case kEventClassApplication :
748             result = wxMacAppApplicationEventHandler( handler , event , data ) ;
749             break ;
750 #ifndef __LP64__
751         case kEventClassMenu :
752             result = wxMacAppMenuEventHandler( handler , event , data ) ;
753             break ;
754 
755         case kEventClassMouse :
756             {
757                 wxMacCarbonEvent cEvent( event ) ;
758 
759                 WindowRef window ;
760                 Point screenMouseLocation = cEvent.GetParameter<Point>(kEventParamMouseLocation) ;
761                 ::FindWindow(screenMouseLocation, &window);
762                 // only send this event in case it had not already been sent to a tlw, as we get
763                 // double events otherwise (in case event.skip) was called
764                 if ( window == NULL )
765                     result = wxMacTopLevelMouseEventHandler( handler , event , NULL ) ;
766             }
767             break ;
768 #endif
769         case kEventClassAppleEvent :
770             result = AEProcessEvent(event);
771             break ;
772 
773         default :
774             break ;
775     }
776 
777     wxTheApp->MacSetCurrentEvent( formerEvent, formerEventHandlerCallRef ) ;
778 
779     return result ;
780 }
781 
DEFINE_ONE_SHOT_HANDLER_GETTER(wxMacAppEventHandler)782 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacAppEventHandler )
783 #endif
784 
785 #if wxDEBUG_LEVEL && wxOSX_USE_COCOA_OR_CARBON
786 
787 pascal static void
788 wxMacAssertOutputHandler(OSType WXUNUSED(componentSignature),
789                          UInt32 WXUNUSED(options),
790                          const char *assertionString,
791                          const char *exceptionLabelString,
792                          const char *errorString,
793                          const char *fileName,
794                          long lineNumber,
795                          void *value,
796                          ConstStr255Param WXUNUSED(outputMsg))
797 {
798     // flow into assert handling
799     wxString fileNameStr ;
800     wxString assertionStr ;
801     wxString exceptionStr ;
802     wxString errorStr ;
803 
804 #if wxUSE_UNICODE
805     fileNameStr = wxString(fileName, wxConvLocal);
806     assertionStr = wxString(assertionString, wxConvLocal);
807     exceptionStr = wxString((exceptionLabelString!=0) ? exceptionLabelString : "", wxConvLocal) ;
808     errorStr = wxString((errorString!=0) ? errorString : "", wxConvLocal) ;
809 #else
810     fileNameStr = fileName;
811     assertionStr = assertionString;
812     exceptionStr = (exceptionLabelString!=0) ? exceptionLabelString : "" ;
813     errorStr = (errorString!=0) ? errorString : "" ;
814 #endif
815 
816 #if 1
817     // flow into log
818     wxLogDebug( wxT("AssertMacros: %s %s %s file: %s, line: %ld (value %p)\n"),
819         assertionStr.c_str() ,
820         exceptionStr.c_str() ,
821         errorStr.c_str(),
822         fileNameStr.c_str(), lineNumber ,
823         value ) ;
824 #else
825 
826     wxOnAssert(fileNameStr, lineNumber , assertionStr ,
827         wxString::Format( wxT("%s %s value (%p)") , exceptionStr, errorStr , value ) ) ;
828 #endif
829 }
830 
831 #endif // wxDEBUG_LEVEL
832 
Initialize(int & argc,wxChar ** argv)833 bool wxApp::Initialize(int& argc, wxChar **argv)
834 {
835     // Mac-specific
836 
837 #if wxDEBUG_LEVEL && wxOSX_USE_COCOA_OR_CARBON
838     InstallDebugAssertOutputHandler( NewDebugAssertOutputHandlerUPP( wxMacAssertOutputHandler ) );
839 #endif
840 
841     /*
842      Cocoa supports -Key value options which set the user defaults key "Key"
843      to the value "value"  Some of them are very handy for debugging like
844      -NSShowAllViews YES.  Cocoa picks these up from the real argv so
845      our removal of them from the wx copy of it does not affect Cocoa's
846      ability to see them.
847 
848      We basically just assume that any "-NS" option and its following
849      argument needs to be removed from argv.  We hope that user code does
850      not expect to see -NS options and indeed it's probably a safe bet
851      since most user code accepting options is probably using the
852      double-dash GNU-style syntax.
853      */
854     for(int i=1; i < argc; ++i)
855     {
856         static const wxChar *ARG_NS = wxT("-NS");
857         if( wxStrncmp(argv[i], ARG_NS, wxStrlen(ARG_NS)) == 0 )
858         {
859             // Only eat this option if it has an argument
860             if( (i + 1) < argc )
861             {
862                 memmove(argv + i, argv + i + 2, (argc-i-1)*sizeof(wxChar*));
863                 argc -= 2;
864                 // drop back one position so the next run through the loop
865                 // reprocesses the argument at our current index.
866                 --i;
867             }
868         }
869     }
870 
871     if ( !wxAppBase::Initialize(argc, argv) )
872         return false;
873 
874 #if wxUSE_INTL
875     wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
876 #endif
877 
878     // these might be the startup dirs, set them to the 'usual' dir containing the app bundle
879     wxString startupCwd = wxGetCwd() ;
880     if ( startupCwd == wxT("/") || startupCwd.Right(15) == wxT("/Contents/MacOS") )
881     {
882         CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle() ) ;
883         CFURLRef urlParent = CFURLCreateCopyDeletingLastPathComponent( kCFAllocatorDefault , url ) ;
884         CFRelease( url ) ;
885         CFStringRef path = CFURLCopyFileSystemPath ( urlParent , kCFURLPOSIXPathStyle ) ;
886         CFRelease( urlParent ) ;
887         wxString cwd = wxCFStringRef(path).AsString(wxLocale::GetSystemEncoding());
888         wxSetWorkingDirectory( cwd ) ;
889     }
890 
891     return true;
892 }
893 
894 #if wxOSX_USE_CARBON
CallOnInit()895 bool wxApp::CallOnInit()
896 {
897     wxMacAutoreleasePool autoreleasepool;
898     return OnInit();
899 }
900 #endif
901 
OnInitGui()902 bool wxApp::OnInitGui()
903 {
904     if ( !wxAppBase::OnInitGui() )
905         return false ;
906 
907     if ( !DoInitGui() )
908         return false;
909 
910     return true ;
911 }
912 
ProcessIdle()913 bool wxApp::ProcessIdle()
914 {
915     wxMacAutoreleasePool autoreleasepool;
916     return wxAppBase::ProcessIdle();
917 }
918 
OnRun()919 int wxApp::OnRun()
920 {
921     wxMacAutoreleasePool pool;
922     return wxAppBase::OnRun();
923 }
924 
925 #if wxOSX_USE_CARBON
DoInitGui()926 bool wxApp::DoInitGui()
927 {
928     InstallStandardEventHandler( GetApplicationEventTarget() ) ;
929     if (!sm_isEmbedded)
930     {
931         InstallApplicationEventHandler(
932             GetwxMacAppEventHandlerUPP(),
933             GetEventTypeCount(eventList), eventList, wxTheApp, (EventHandlerRef *)&(wxTheApp->m_macEventHandler));
934     }
935 
936     if (!sm_isEmbedded)
937     {
938         sODocHandler = NewAEEventHandlerUPP(AEHandleODoc) ;
939         sGURLHandler = NewAEEventHandlerUPP(AEHandleGURL) ;
940         sOAppHandler = NewAEEventHandlerUPP(AEHandleOApp) ;
941         sPDocHandler = NewAEEventHandlerUPP(AEHandlePDoc) ;
942         sRAppHandler = NewAEEventHandlerUPP(AEHandleRApp) ;
943         sQuitHandler = NewAEEventHandlerUPP(AEHandleQuit) ;
944 
945         AEInstallEventHandler( kCoreEventClass , kAEOpenDocuments ,
946                                sODocHandler , 0 , FALSE ) ;
947         AEInstallEventHandler( kInternetEventClass, kAEGetURL,
948                                sGURLHandler , 0 , FALSE ) ;
949         AEInstallEventHandler( kCoreEventClass , kAEOpenApplication ,
950                                sOAppHandler , 0 , FALSE ) ;
951         AEInstallEventHandler( kCoreEventClass , kAEPrintDocuments ,
952                                sPDocHandler , 0 , FALSE ) ;
953         AEInstallEventHandler( kCoreEventClass , kAEReopenApplication ,
954                                sRAppHandler , 0 , FALSE ) ;
955         AEInstallEventHandler( kCoreEventClass , kAEQuitApplication ,
956                                sQuitHandler , 0 , FALSE ) ;
957     }
958 
959     if ( !wxMacInitCocoa() )
960         return false;
961 
962     return true;
963 }
964 
DoCleanUp()965 void wxApp::DoCleanUp()
966 {
967     if (!sm_isEmbedded)
968         RemoveEventHandler( (EventHandlerRef)(wxTheApp->m_macEventHandler) );
969 
970     if (!sm_isEmbedded)
971     {
972         AERemoveEventHandler( kCoreEventClass , kAEOpenDocuments ,
973                                sODocHandler , FALSE ) ;
974         AERemoveEventHandler( kInternetEventClass, kAEGetURL,
975                                sGURLHandler , FALSE ) ;
976         AERemoveEventHandler( kCoreEventClass , kAEOpenApplication ,
977                                sOAppHandler , FALSE ) ;
978         AERemoveEventHandler( kCoreEventClass , kAEPrintDocuments ,
979                                sPDocHandler , FALSE ) ;
980         AERemoveEventHandler( kCoreEventClass , kAEReopenApplication ,
981                                sRAppHandler , FALSE ) ;
982         AERemoveEventHandler( kCoreEventClass , kAEQuitApplication ,
983                                sQuitHandler , FALSE ) ;
984 
985         DisposeAEEventHandlerUPP( sODocHandler ) ;
986         DisposeAEEventHandlerUPP( sGURLHandler ) ;
987         DisposeAEEventHandlerUPP( sOAppHandler ) ;
988         DisposeAEEventHandlerUPP( sPDocHandler ) ;
989         DisposeAEEventHandlerUPP( sRAppHandler ) ;
990         DisposeAEEventHandlerUPP( sQuitHandler ) ;
991     }
992 }
993 
994 #endif
995 
CleanUp()996 void wxApp::CleanUp()
997 {
998     wxMacAutoreleasePool autoreleasepool;
999 #if wxUSE_TOOLTIPS
1000     wxToolTip::RemoveToolTips() ;
1001 #endif
1002 
1003     DoCleanUp();
1004 
1005     wxAppBase::CleanUp();
1006 }
1007 
1008 //----------------------------------------------------------------------
1009 // misc initialization stuff
1010 //----------------------------------------------------------------------
1011 
wxApp()1012 wxApp::wxApp()
1013 {
1014     m_printMode = wxPRINT_WINDOWS;
1015 
1016     m_macCurrentEvent = NULL ;
1017     m_macCurrentEventHandlerCallRef = NULL ;
1018     m_macPool = new wxMacAutoreleasePool();
1019 }
1020 
~wxApp()1021 wxApp::~wxApp()
1022 {
1023     if (m_macPool)
1024         delete m_macPool;
1025 }
1026 
GetAutoReleaseArray()1027 CFMutableArrayRef GetAutoReleaseArray()
1028 {
1029     static CFMutableArrayRef array = 0;
1030     if ( array == 0)
1031         array= CFArrayCreateMutable(kCFAllocatorDefault,0,&kCFTypeArrayCallBacks);
1032     return array;
1033 }
1034 
MacAddToAutorelease(void * cfrefobj)1035 void wxApp::MacAddToAutorelease( void* cfrefobj )
1036 {
1037     CFArrayAppendValue( GetAutoReleaseArray(), cfrefobj );
1038 }
1039 
MacReleaseAutoreleasePool()1040 void wxApp::MacReleaseAutoreleasePool()
1041 {
1042     if (m_macPool)
1043         delete m_macPool;
1044     m_macPool = new wxMacAutoreleasePool();
1045 }
1046 
OnIdle(wxIdleEvent & WXUNUSED (event))1047 void wxApp::OnIdle(wxIdleEvent& WXUNUSED(event))
1048 {
1049     // If they are pending events, we must process them: pending events are
1050     // either events to the threads other than main or events posted with
1051     // wxPostEvent() functions
1052 #ifndef __WXUNIVERSAL__
1053 #if wxUSE_MENUS
1054   if (!wxMenuBar::MacGetInstalledMenuBar() && wxMenuBar::MacGetCommonMenuBar())
1055     wxMenuBar::MacGetCommonMenuBar()->MacInstallMenuBar();
1056 #endif
1057 #endif
1058     CFArrayRemoveAllValues( GetAutoReleaseArray() );
1059 }
1060 
WakeUpIdle()1061 void wxApp::WakeUpIdle()
1062 {
1063     wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
1064 
1065     if ( loop )
1066         loop->WakeUp();
1067 }
1068 
OnEndSession(wxCloseEvent & WXUNUSED (event))1069 void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
1070 {
1071     if (GetTopWindow())
1072         GetTopWindow()->Close(true);
1073 }
1074 
1075 // Default behaviour: close the application with prompts. The
1076 // user can veto the close, and therefore the end session.
OnQueryEndSession(wxCloseEvent & event)1077 void wxApp::OnQueryEndSession(wxCloseEvent& event)
1078 {
1079     if ( !wxDialog::OSXHasModalDialogsOpen() )
1080     {
1081         if (GetTopWindow())
1082         {
1083             if (!GetTopWindow()->Close(!event.CanVeto()))
1084                 event.Veto(true);
1085         }
1086     }
1087     else
1088     {
1089         event.Veto(true);
1090     }
1091 }
1092 
1093 extern "C" void wxCYield() ;
wxCYield()1094 void wxCYield()
1095 {
1096     wxYield() ;
1097 }
1098 
1099 // virtual
MacHandleUnhandledEvent(WXEVENTREF WXUNUSED (evr))1100 void wxApp::MacHandleUnhandledEvent( WXEVENTREF WXUNUSED(evr) )
1101 {
1102     // Override to process unhandled events as you please
1103 }
1104 
1105 #if wxOSX_USE_COCOA_OR_CARBON
1106 
wxCharCodeWXToOSX(wxKeyCode code)1107 CGKeyCode wxCharCodeWXToOSX(wxKeyCode code)
1108 {
1109     CGKeyCode keycode;
1110 
1111     switch (code)
1112     {
1113         // Clang warns about switch values not of the same type as (enumerated)
1114         // switch controlling expression. This is generally useful but here we
1115         // really want to be able to use letters and digits without making them
1116         // part of wxKeyCode enum.
1117 #ifdef __clang__
1118     #pragma clang diagnostic push
1119     #pragma clang diagnostic ignored "-Wswitch"
1120 #endif // __clang__
1121 
1122         case 'a': case 'A':   keycode = kVK_ANSI_A; break;
1123         case 'b': case 'B':   keycode = kVK_ANSI_B; break;
1124         case 'c': case 'C':   keycode = kVK_ANSI_C; break;
1125         case 'd': case 'D':   keycode = kVK_ANSI_D; break;
1126         case 'e': case 'E':   keycode = kVK_ANSI_E; break;
1127         case 'f': case 'F':   keycode = kVK_ANSI_F; break;
1128         case 'g': case 'G':   keycode = kVK_ANSI_G; break;
1129         case 'h': case 'H':   keycode = kVK_ANSI_H; break;
1130         case 'i': case 'I':   keycode = kVK_ANSI_I; break;
1131         case 'j': case 'J':   keycode = kVK_ANSI_J; break;
1132         case 'k': case 'K':   keycode = kVK_ANSI_K; break;
1133         case 'l': case 'L':   keycode = kVK_ANSI_L; break;
1134         case 'm': case 'M':   keycode = kVK_ANSI_M; break;
1135         case 'n': case 'N':   keycode = kVK_ANSI_N; break;
1136         case 'o': case 'O':   keycode = kVK_ANSI_O; break;
1137         case 'p': case 'P':   keycode = kVK_ANSI_P; break;
1138         case 'q': case 'Q':   keycode = kVK_ANSI_Q; break;
1139         case 'r': case 'R':   keycode = kVK_ANSI_R; break;
1140         case 's': case 'S':   keycode = kVK_ANSI_S; break;
1141         case 't': case 'T':   keycode = kVK_ANSI_T; break;
1142         case 'u': case 'U':   keycode = kVK_ANSI_U; break;
1143         case 'v': case 'V':   keycode = kVK_ANSI_V; break;
1144         case 'w': case 'W':   keycode = kVK_ANSI_W; break;
1145         case 'x': case 'X':   keycode = kVK_ANSI_X; break;
1146         case 'y': case 'Y':   keycode = kVK_ANSI_Y; break;
1147         case 'z': case 'Z':   keycode = kVK_ANSI_Z; break;
1148 
1149         case '0':             keycode = kVK_ANSI_0; break;
1150         case '1':             keycode = kVK_ANSI_1; break;
1151         case '2':             keycode = kVK_ANSI_2; break;
1152         case '3':             keycode = kVK_ANSI_3; break;
1153         case '4':             keycode = kVK_ANSI_4; break;
1154         case '5':             keycode = kVK_ANSI_5; break;
1155         case '6':             keycode = kVK_ANSI_6; break;
1156         case '7':             keycode = kVK_ANSI_7; break;
1157         case '8':             keycode = kVK_ANSI_8; break;
1158         case '9':             keycode = kVK_ANSI_9; break;
1159 
1160 #ifdef __clang__
1161     #pragma clang diagnostic pop
1162 #endif // __clang__
1163 
1164         case WXK_BACK:        keycode = kVK_Delete; break;
1165         case WXK_TAB:         keycode = kVK_Tab; break;
1166         case WXK_RETURN:      keycode = kVK_Return; break;
1167         case WXK_ESCAPE:      keycode = kVK_Escape; break;
1168         case WXK_SPACE:       keycode = kVK_Space; break;
1169         case WXK_DELETE:      keycode = kVK_ForwardDelete; break;
1170 
1171         case WXK_SHIFT:       keycode = kVK_Shift; break;
1172         case WXK_ALT:         keycode = kVK_Option; break;
1173         case WXK_RAW_CONTROL: keycode = kVK_Control; break;
1174         case WXK_CONTROL:     keycode = kVK_Command; break;
1175 
1176         case WXK_CAPITAL:     keycode = kVK_CapsLock; break;
1177         case WXK_END:         keycode = kVK_End; break;
1178         case WXK_HOME:        keycode = kVK_Home; break;
1179         case WXK_LEFT:        keycode = kVK_LeftArrow; break;
1180         case WXK_UP:          keycode = kVK_UpArrow; break;
1181         case WXK_RIGHT:       keycode = kVK_RightArrow; break;
1182         case WXK_DOWN:        keycode = kVK_DownArrow; break;
1183 
1184         case WXK_HELP:        keycode = kVK_Help; break;
1185 
1186 
1187         case WXK_NUMPAD0:     keycode = kVK_ANSI_Keypad0; break;
1188         case WXK_NUMPAD1:     keycode = kVK_ANSI_Keypad1; break;
1189         case WXK_NUMPAD2:     keycode = kVK_ANSI_Keypad2; break;
1190         case WXK_NUMPAD3:     keycode = kVK_ANSI_Keypad3; break;
1191         case WXK_NUMPAD4:     keycode = kVK_ANSI_Keypad4; break;
1192         case WXK_NUMPAD5:     keycode = kVK_ANSI_Keypad5; break;
1193         case WXK_NUMPAD6:     keycode = kVK_ANSI_Keypad6; break;
1194         case WXK_NUMPAD7:     keycode = kVK_ANSI_Keypad7; break;
1195         case WXK_NUMPAD8:     keycode = kVK_ANSI_Keypad8; break;
1196         case WXK_NUMPAD9:     keycode = kVK_ANSI_Keypad9; break;
1197         case WXK_F1:          keycode = kVK_F1; break;
1198         case WXK_F2:          keycode = kVK_F2; break;
1199         case WXK_F3:          keycode = kVK_F3; break;
1200         case WXK_F4:          keycode = kVK_F4; break;
1201         case WXK_F5:          keycode = kVK_F5; break;
1202         case WXK_F6:          keycode = kVK_F6; break;
1203         case WXK_F7:          keycode = kVK_F7; break;
1204         case WXK_F8:          keycode = kVK_F8; break;
1205         case WXK_F9:          keycode = kVK_F9; break;
1206         case WXK_F10:         keycode = kVK_F10; break;
1207         case WXK_F11:         keycode = kVK_F11; break;
1208         case WXK_F12:         keycode = kVK_F12; break;
1209         case WXK_F13:         keycode = kVK_F13; break;
1210         case WXK_F14:         keycode = kVK_F14; break;
1211         case WXK_F15:         keycode = kVK_F15; break;
1212         case WXK_F16:         keycode = kVK_F16; break;
1213         case WXK_F17:         keycode = kVK_F17; break;
1214         case WXK_F18:         keycode = kVK_F18; break;
1215         case WXK_F19:         keycode = kVK_F19; break;
1216         case WXK_F20:         keycode = kVK_F20; break;
1217 
1218         case WXK_PAGEUP:      keycode = kVK_PageUp; break;
1219         case WXK_PAGEDOWN:    keycode = kVK_PageDown; break;
1220 
1221         case WXK_NUMPAD_DELETE:    keycode = kVK_ANSI_KeypadClear; break;
1222         case WXK_NUMPAD_EQUAL:     keycode = kVK_ANSI_KeypadEquals; break;
1223         case WXK_NUMPAD_MULTIPLY:  keycode = kVK_ANSI_KeypadMultiply; break;
1224         case WXK_NUMPAD_ADD:       keycode = kVK_ANSI_KeypadPlus; break;
1225         case WXK_NUMPAD_SUBTRACT:  keycode = kVK_ANSI_KeypadMinus; break;
1226         case WXK_NUMPAD_DECIMAL:   keycode = kVK_ANSI_KeypadDecimal; break;
1227         case WXK_NUMPAD_DIVIDE:    keycode = kVK_ANSI_KeypadDivide; break;
1228 
1229         default:
1230             wxLogDebug( "Unrecognised keycode %d", code );
1231             keycode = static_cast<CGKeyCode>(-1);
1232     }
1233 
1234     return keycode;
1235 }
1236 
wxMacTranslateKey(unsigned char key,unsigned char code)1237 long wxMacTranslateKey(unsigned char key, unsigned char code)
1238 {
1239     long retval = key ;
1240     switch (key)
1241     {
1242         case kHomeCharCode :
1243             retval = WXK_HOME;
1244             break;
1245 
1246         case kEnterCharCode :
1247             retval = WXK_RETURN;
1248             break;
1249         case kEndCharCode :
1250             retval = WXK_END;
1251             break;
1252 
1253         case kHelpCharCode :
1254             retval = WXK_HELP;
1255             break;
1256 
1257         case kBackspaceCharCode :
1258             retval = WXK_BACK;
1259             break;
1260 
1261         case kTabCharCode :
1262             retval = WXK_TAB;
1263             break;
1264 
1265         case kPageUpCharCode :
1266             retval = WXK_PAGEUP;
1267             break;
1268 
1269         case kPageDownCharCode :
1270             retval = WXK_PAGEDOWN;
1271             break;
1272 
1273         case kReturnCharCode :
1274             retval = WXK_RETURN;
1275             break;
1276 
1277         case kFunctionKeyCharCode :
1278         {
1279             switch ( code )
1280             {
1281                 case 0x7a :
1282                     retval = WXK_F1 ;
1283                     break;
1284 
1285                 case 0x78 :
1286                     retval = WXK_F2 ;
1287                     break;
1288 
1289                 case 0x63 :
1290                     retval = WXK_F3 ;
1291                     break;
1292 
1293                 case 0x76 :
1294                     retval = WXK_F4 ;
1295                     break;
1296 
1297                 case 0x60 :
1298                     retval = WXK_F5 ;
1299                     break;
1300 
1301                 case 0x61 :
1302                     retval = WXK_F6 ;
1303                     break;
1304 
1305                 case 0x62:
1306                     retval = WXK_F7 ;
1307                     break;
1308 
1309                 case 0x64 :
1310                     retval = WXK_F8 ;
1311                     break;
1312 
1313                 case 0x65 :
1314                     retval = WXK_F9 ;
1315                     break;
1316 
1317                 case 0x6D :
1318                     retval = WXK_F10 ;
1319                     break;
1320 
1321                 case 0x67 :
1322                     retval = WXK_F11 ;
1323                     break;
1324 
1325                 case 0x6F :
1326                     retval = WXK_F12 ;
1327                     break;
1328 
1329                 case 0x69 :
1330                     retval = WXK_F13 ;
1331                     break;
1332 
1333                 case 0x6B :
1334                     retval = WXK_F14 ;
1335                     break;
1336 
1337                 case 0x71 :
1338                     retval = WXK_F15 ;
1339                     break;
1340 
1341                 default:
1342                     break;
1343             }
1344         }
1345         break ;
1346 
1347         case kEscapeCharCode :
1348             retval = WXK_ESCAPE ;
1349             break ;
1350 
1351         case kLeftArrowCharCode :
1352             retval = WXK_LEFT ;
1353             break ;
1354 
1355         case kRightArrowCharCode :
1356             retval = WXK_RIGHT ;
1357             break ;
1358 
1359         case kUpArrowCharCode :
1360             retval = WXK_UP ;
1361             break ;
1362 
1363         case kDownArrowCharCode :
1364             retval = WXK_DOWN ;
1365             break ;
1366 
1367         case kDeleteCharCode :
1368             retval = WXK_DELETE ;
1369             break ;
1370 
1371         default:
1372             break ;
1373      } // end switch
1374 
1375     return retval;
1376 }
1377 
wxMacKeyCodeToModifier(wxKeyCode key)1378 int wxMacKeyCodeToModifier(wxKeyCode key)
1379 {
1380     switch (key)
1381     {
1382     case WXK_START:
1383     case WXK_MENU:
1384     case WXK_COMMAND:
1385         return cmdKey;
1386 
1387     case WXK_SHIFT:
1388         return shiftKey;
1389 
1390     case WXK_CAPITAL:
1391         return alphaLock;
1392 
1393     case WXK_ALT:
1394         return optionKey;
1395 
1396     case WXK_RAW_CONTROL:
1397         return controlKey;
1398 
1399     default:
1400         return 0;
1401     }
1402 }
1403 #endif
1404 
1405 #if wxOSX_USE_COCOA && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
1406 
1407 // defined in utils.mm
1408 
1409 #elif wxOSX_USE_COCOA_OR_CARBON
1410 
wxGetMouseState()1411 wxMouseState wxGetMouseState()
1412 {
1413     wxMouseState ms;
1414 
1415     wxPoint pt = wxGetMousePosition();
1416     ms.SetX(pt.x);
1417     ms.SetY(pt.y);
1418 
1419     UInt32 buttons = GetCurrentButtonState();
1420     ms.SetLeftDown( (buttons & 0x01) != 0 );
1421     ms.SetMiddleDown( (buttons & 0x04) != 0 );
1422     ms.SetRightDown( (buttons & 0x02) != 0 );
1423 
1424     UInt32 modifiers = GetCurrentKeyModifiers();
1425     ms.SetRawControlDown(modifiers & controlKey);
1426     ms.SetShiftDown(modifiers & shiftKey);
1427     ms.SetAltDown(modifiers & optionKey);
1428     ms.SetControlDown(modifiers & cmdKey);
1429 
1430     return ms;
1431 }
1432 
1433 #endif
1434 
1435 // TODO : once the new key/char handling is tested, move all the code to wxWindow
1436 
MacSendKeyDownEvent(wxWindow * focus,long keymessage,long modifiers,long when,wxChar uniChar)1437 bool wxApp::MacSendKeyDownEvent( wxWindow* focus , long keymessage , long modifiers , long when , wxChar uniChar )
1438 {
1439     if ( !focus )
1440         return false ;
1441 
1442     wxKeyEvent event(wxEVT_KEY_DOWN) ;
1443     MacCreateKeyEvent( event, focus , keymessage , modifiers , when , uniChar ) ;
1444 
1445     return focus->OSXHandleKeyEvent(event);
1446 }
1447 
MacSendKeyUpEvent(wxWindow * focus,long keymessage,long modifiers,long when,wxChar uniChar)1448 bool wxApp::MacSendKeyUpEvent( wxWindow* focus , long keymessage , long modifiers , long when , wxChar uniChar )
1449 {
1450     if ( !focus )
1451         return false ;
1452 
1453     wxKeyEvent event( wxEVT_KEY_UP ) ;
1454     MacCreateKeyEvent( event, focus , keymessage , modifiers , when , uniChar ) ;
1455 
1456     return focus->OSXHandleKeyEvent(event) ;
1457 }
1458 
MacSendCharEvent(wxWindow * focus,long keymessage,long modifiers,long when,wxChar uniChar)1459 bool wxApp::MacSendCharEvent( wxWindow* focus , long keymessage , long modifiers , long when , wxChar uniChar )
1460 {
1461     if ( !focus )
1462         return false ;
1463     wxKeyEvent event(wxEVT_CHAR) ;
1464     MacCreateKeyEvent( event, focus , keymessage , modifiers , when , uniChar ) ;
1465 
1466     bool handled = false ;
1467 
1468 #if wxOSX_USE_CARBON
1469     long keyval = event.m_keyCode ;
1470 
1471     {
1472         wxKeyEvent eventCharHook(wxEVT_CHAR_HOOK, event);
1473         handled = focus->HandleWindowEvent( eventCharHook );
1474         if ( handled && eventCharHook.IsNextEventAllowed() )
1475             handled = false ;
1476     }
1477 
1478     if ( !handled )
1479     {
1480         handled = focus->HandleWindowEvent( event ) ;
1481     }
1482 
1483     if ( !handled && (keyval == WXK_TAB) )
1484     {
1485         wxWindow* iter = focus->GetParent() ;
1486         while ( iter && !handled )
1487         {
1488             if ( iter->HasFlag( wxTAB_TRAVERSAL ) )
1489             {
1490                 wxNavigationKeyEvent new_event;
1491                 new_event.SetEventObject( focus );
1492                 new_event.SetDirection( !event.ShiftDown() );
1493                 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1494                 new_event.SetWindowChange( event.ControlDown() );
1495                 new_event.SetCurrentFocus( focus );
1496                 handled = focus->GetParent()->HandleWindowEvent( new_event );
1497                 if ( handled && new_event.GetSkipped() )
1498                     handled = false ;
1499             }
1500 
1501             iter = iter->GetParent() ;
1502         }
1503     }
1504 
1505     // backdoor handler for default return and command escape
1506     if ( !handled && (!focus->IsKindOf(CLASSINFO(wxControl) ) || !focus->AcceptsFocus() ) )
1507     {
1508         // if window is not having a focus still testing for default enter or cancel
1509         // TODO: add the UMA version for ActiveNonFloatingWindow
1510 #ifndef __LP64__
1511         wxWindow* focus = wxNonOwnedWindow::GetFromWXWindow( (WXWindow) FrontWindow() ) ;
1512         if ( focus )
1513         {
1514             if ( keyval == WXK_RETURN || keyval == WXK_NUMPAD_ENTER )
1515             {
1516                 wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(focus), wxTopLevelWindow);
1517                 if ( tlw && tlw->GetDefaultItem() )
1518                 {
1519                     wxButton *def = wxDynamicCast(tlw->GetDefaultItem(), wxButton);
1520                     if ( def && def->IsEnabled() )
1521                     {
1522                         wxCommandEvent event(wxEVT_BUTTON, def->GetId() );
1523                         event.SetEventObject(def);
1524                         def->Command(event);
1525 
1526                         return true ;
1527                     }
1528                 }
1529             }
1530             else if (keyval == WXK_ESCAPE || (keyval == '.' && modifiers & cmdKey ) )
1531             {
1532                 // generate wxID_CANCEL if command-. or <esc> has been pressed (typically in dialogs)
1533                 wxCommandEvent new_event(wxEVT_BUTTON,wxID_CANCEL);
1534                 new_event.SetEventObject( focus );
1535                 handled = focus->HandleWindowEvent( new_event );
1536             }
1537         }
1538 #endif
1539     }
1540 #endif
1541     return handled ;
1542 }
1543 
1544 // This method handles common code for SendKeyDown, SendKeyUp, and SendChar events.
MacCreateKeyEvent(wxKeyEvent & event,wxWindow * focus,long keymessage,long modifiers,long when,wxChar uniChar)1545 void wxApp::MacCreateKeyEvent( wxKeyEvent& event, wxWindow* focus , long keymessage , long modifiers , long when , wxChar uniChar )
1546 {
1547 #if wxOSX_USE_COCOA_OR_CARBON
1548 
1549     short keycode, keychar ;
1550 
1551     keychar = short(keymessage & charCodeMask);
1552     keycode = short(keymessage & keyCodeMask) >> 8 ;
1553     if ( !(event.GetEventType() == wxEVT_CHAR) && (modifiers & (controlKey | shiftKey | optionKey) ) )
1554     {
1555         // control interferes with some built-in keys like pgdown, return etc. therefore we remove the controlKey modifier
1556         // and look at the character after
1557 #ifdef __LP64__
1558         // TODO new implementation using TextInputSources
1559 #else
1560         UInt32 state = 0;
1561         UInt32 keyInfo = KeyTranslate((Ptr)GetScriptManagerVariable(smKCHRCache), ( modifiers & (~(controlKey | shiftKey | optionKey))) | keycode, &state);
1562         keychar = short(keyInfo & charCodeMask);
1563 #endif
1564     }
1565 
1566     long keyval = wxMacTranslateKey(keychar, keycode) ;
1567     if ( keyval == keychar && ( event.GetEventType() == wxEVT_KEY_UP || event.GetEventType() == wxEVT_KEY_DOWN ) )
1568         keyval = wxToupper( keyval ) ;
1569 
1570     // Check for NUMPAD keys.  For KEY_UP/DOWN events we need to use the
1571     // WXK_NUMPAD constants, but for the CHAR event we want to use the
1572     // standard ascii values
1573     if ( event.GetEventType() != wxEVT_CHAR )
1574     {
1575         if (keyval >= '0' && keyval <= '9' && keycode >= 82 && keycode <= 92)
1576         {
1577             keyval = (keyval - '0') + WXK_NUMPAD0;
1578         }
1579         else if (keycode >= 65 && keycode <= 81)
1580         {
1581             switch (keycode)
1582             {
1583                 case 76 :
1584                     keyval = WXK_NUMPAD_ENTER;
1585                     break;
1586 
1587                 case 81:
1588                     keyval = WXK_NUMPAD_EQUAL;
1589                     break;
1590 
1591                 case 67:
1592                     keyval = WXK_NUMPAD_MULTIPLY;
1593                     break;
1594 
1595                 case 75:
1596                     keyval = WXK_NUMPAD_DIVIDE;
1597                     break;
1598 
1599                 case 78:
1600                     keyval = WXK_NUMPAD_SUBTRACT;
1601                     break;
1602 
1603                 case 69:
1604                     keyval = WXK_NUMPAD_ADD;
1605                     break;
1606 
1607                 case 65:
1608                     keyval = WXK_NUMPAD_DECIMAL;
1609                     break;
1610                 default:
1611                     break;
1612             }
1613         }
1614     }
1615 
1616     event.m_shiftDown = modifiers & shiftKey;
1617     event.m_rawControlDown = modifiers & controlKey;
1618     event.m_altDown = modifiers & optionKey;
1619     event.m_controlDown = modifiers & cmdKey;
1620     event.m_keyCode = keyval ;
1621 #if wxUSE_UNICODE
1622     event.m_uniChar = uniChar ;
1623 #endif
1624 
1625     event.m_rawCode = keymessage;
1626     event.m_rawFlags = modifiers;
1627     event.SetTimestamp(when);
1628     event.SetEventObject(focus);
1629 #else
1630     wxUnusedVar(event);
1631     wxUnusedVar(focus);
1632     wxUnusedVar(keymessage);
1633     wxUnusedVar(modifiers);
1634     wxUnusedVar(when);
1635     wxUnusedVar(uniChar);
1636 #endif
1637 }
1638 
1639 
MacHideApp()1640 void wxApp::MacHideApp()
1641 {
1642 #if wxOSX_USE_CARBON
1643     wxMacCarbonEvent event( kEventClassCommand , kEventCommandProcess );
1644     HICommand command;
1645     memset( &command, 0 , sizeof(command) );
1646     command.commandID = kHICommandHide ;
1647     event.SetParameter<HICommand>(kEventParamDirectObject, command );
1648     SendEventToApplication( event );
1649 #endif
1650 }
1651