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