1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/app.cpp
4 // Author: Stefan Csomor
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
20 #include "wx/window.h"
23 #include "wx/button.h"
27 #include "wx/palette.h"
29 #include "wx/cursor.h"
30 #include "wx/dialog.h"
31 #include "wx/msgdlg.h"
32 #include "wx/textctrl.h"
33 #include "wx/memory.h"
34 #include "wx/gdicmn.h"
35 #include "wx/module.h"
38 #include "wx/tooltip.h"
39 #include "wx/docview.h"
40 #include "wx/filename.h"
42 #include "wx/thread.h"
43 #include "wx/evtloop.h"
49 #include "wx/osx/uma.h"
51 #include "wx/osx/private.h"
54 #if defined(WXMAKINGDLL_CORE)
55 # include <mach-o/dyld.h>
58 // Keep linker from discarding wxStockGDIMac
59 wxFORCE_LINK_MODULE(gdiobj
)
61 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
62 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
63 EVT_IDLE(wxApp::OnIdle
)
64 EVT_END_SESSION(wxApp::OnEndSession
)
65 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
)
69 // platform specific static variables
70 static const short kwxMacAppleMenuId
= 1 ;
72 wxWindow
* wxApp::s_captureWindow
= NULL
;
73 long wxApp::s_lastModifiers
= 0 ;
75 long wxApp::s_macAboutMenuItemId
= wxID_ABOUT
;
76 long wxApp::s_macPreferencesMenuItemId
= wxID_PREFERENCES
;
77 long wxApp::s_macExitMenuItemId
= wxID_EXIT
;
78 wxString
wxApp::s_macHelpMenuTitleName
= wxT("&Help") ;
80 bool wxApp::sm_isEmbedded
= false; // Normally we're not a plugin
84 //----------------------------------------------------------------------
85 // Core Apple Event Support
86 //----------------------------------------------------------------------
88 AEEventHandlerUPP sODocHandler
= NULL
;
89 AEEventHandlerUPP sGURLHandler
= NULL
;
90 AEEventHandlerUPP sOAppHandler
= NULL
;
91 AEEventHandlerUPP sPDocHandler
= NULL
;
92 AEEventHandlerUPP sRAppHandler
= NULL
;
93 AEEventHandlerUPP sQuitHandler
= NULL
;
95 pascal OSErr
AEHandleODoc( const AppleEvent
*event
, AppleEvent
*reply
, SRefCon refcon
) ;
96 pascal OSErr
AEHandleOApp( const AppleEvent
*event
, AppleEvent
*reply
, SRefCon refcon
) ;
97 pascal OSErr
AEHandlePDoc( const AppleEvent
*event
, AppleEvent
*reply
, SRefCon refcon
) ;
98 pascal OSErr
AEHandleQuit( const AppleEvent
*event
, AppleEvent
*reply
, SRefCon refcon
) ;
99 pascal OSErr
AEHandleRApp( const AppleEvent
*event
, AppleEvent
*reply
, SRefCon refcon
) ;
100 pascal OSErr
AEHandleGURL( const AppleEvent
*event
, AppleEvent
*reply
, SRefCon refcon
) ;
102 pascal OSErr
AEHandleODoc( const AppleEvent
*event
, AppleEvent
*reply
, SRefCon
WXUNUSED(refcon
) )
104 return wxTheApp
->MacHandleAEODoc( (AppleEvent
*) event
, reply
) ;
107 pascal OSErr
AEHandleOApp( const AppleEvent
*event
, AppleEvent
*reply
, SRefCon
WXUNUSED(refcon
) )
109 return wxTheApp
->MacHandleAEOApp( (AppleEvent
*) event
, reply
) ;
112 pascal OSErr
AEHandlePDoc( const AppleEvent
*event
, AppleEvent
*reply
, SRefCon
WXUNUSED(refcon
) )
114 return wxTheApp
->MacHandleAEPDoc( (AppleEvent
*) event
, reply
) ;
117 pascal OSErr
AEHandleQuit( const AppleEvent
*event
, AppleEvent
*reply
, SRefCon
WXUNUSED(refcon
) )
119 return wxTheApp
->MacHandleAEQuit( (AppleEvent
*) event
, reply
) ;
122 pascal OSErr
AEHandleRApp( const AppleEvent
*event
, AppleEvent
*reply
, SRefCon
WXUNUSED(refcon
) )
124 return wxTheApp
->MacHandleAERApp( (AppleEvent
*) event
, reply
) ;
127 pascal OSErr
AEHandleGURL( const AppleEvent
*event
, AppleEvent
*reply
, SRefCon
WXUNUSED(refcon
) )
129 return wxTheApp
->MacHandleAEGURL((WXEVENTREF
*)event
, reply
) ;
133 // AEODoc Calls MacOpenFiles with all of the files passed
135 short wxApp::MacHandleAEODoc(const WXEVENTREF event
, WXEVENTREF
WXUNUSED(reply
))
139 DescType returnedType
;
145 err
= AEGetParamDesc((AppleEvent
*)event
, keyDirectObject
, typeAEList
,&docList
);
149 err
= AECountItems(&docList
, &itemsInList
);
153 ProcessSerialNumber PSN
;
154 PSN
.highLongOfPSN
= 0 ;
155 PSN
.lowLongOfPSN
= kCurrentProcess
;
156 SetFrontProcess( &PSN
) ;
161 wxArrayString fileNames
;
162 for (i
= 1; i
<= itemsInList
; i
++)
165 &docList
, i
, typeFSRef
, &keywd
, &returnedType
,
166 (Ptr
)&theRef
, sizeof(theRef
), &actualSize
);
171 fName
= wxMacFSRefToPath( &theRef
) ;
173 fileNames
.Add(fName
);
176 MacOpenFiles(fileNames
);
181 // AEODoc Calls MacOpenURL on the url passed
183 short wxApp::MacHandleAEGURL(const WXEVENTREF event
, WXEVENTREF
WXUNUSED(reply
))
185 DescType returnedType
;
188 OSErr err
= AEGetParamPtr((AppleEvent
*)event
, keyDirectObject
, typeChar
,
189 &returnedType
, url
, sizeof(url
)-1,
194 url
[actualSize
] = '\0'; // Terminate the C string
196 ProcessSerialNumber PSN
;
197 PSN
.highLongOfPSN
= 0 ;
198 PSN
.lowLongOfPSN
= kCurrentProcess
;
199 SetFrontProcess( &PSN
) ;
201 MacOpenURL(wxString(url
, wxConvUTF8
));
206 // AEPDoc Calls MacPrintFile on each of the files passed
208 short wxApp::MacHandleAEPDoc(const WXEVENTREF event
, WXEVENTREF
WXUNUSED(reply
))
212 DescType returnedType
;
218 err
= AEGetParamDesc((AppleEvent
*)event
, keyDirectObject
, typeAEList
,&docList
);
222 err
= AECountItems(&docList
, &itemsInList
);
226 ProcessSerialNumber PSN
;
227 PSN
.highLongOfPSN
= 0 ;
228 PSN
.lowLongOfPSN
= kCurrentProcess
;
229 SetFrontProcess( &PSN
) ;
234 for (i
= 1; i
<= itemsInList
; i
++)
237 &docList
, i
, typeFSRef
, &keywd
, &returnedType
,
238 (Ptr
)&theRef
, sizeof(theRef
), &actualSize
);
243 fName
= wxMacFSRefToPath( &theRef
) ;
251 // AEOApp calls MacNewFile
253 short wxApp::MacHandleAEOApp(const WXEVENTREF
WXUNUSED(event
) , WXEVENTREF
WXUNUSED(reply
))
259 // AEQuit attempts to quit the application
261 short wxApp::MacHandleAEQuit(const WXEVENTREF
WXUNUSED(event
) , WXEVENTREF
WXUNUSED(reply
))
264 wxTheApp
->OnQueryEndSession(event
);
265 if ( !event
.GetVeto() )
268 wxTheApp
->OnEndSession(event
);
273 // AEROApp calls MacReopenApp
275 short wxApp::MacHandleAERApp(const WXEVENTREF
WXUNUSED(event
) , WXEVENTREF
WXUNUSED(reply
))
284 //----------------------------------------------------------------------
285 // Support Routines linking the Mac...File Calls to the Document Manager
286 //----------------------------------------------------------------------
288 void wxApp::MacOpenFiles(const wxArrayString
& fileNames
)
291 const size_t fileCount
= fileNames
.GetCount();
292 for (i
= 0; i
< fileCount
; i
++)
294 MacOpenFile(fileNames
[i
]);
298 void wxApp::MacOpenFile(const wxString
& fileName
)
300 #if wxUSE_DOC_VIEW_ARCHITECTURE
301 wxDocManager
* dm
= wxDocManager::GetDocumentManager() ;
303 dm
->CreateDocument(fileName
, wxDOC_SILENT
) ;
307 void wxApp::MacOpenURL(const wxString
& WXUNUSED(url
) )
311 void wxApp::MacPrintFile(const wxString
& fileName
)
313 #if wxUSE_DOC_VIEW_ARCHITECTURE
315 #if wxUSE_PRINTING_ARCHITECTURE
316 wxDocManager
* dm
= wxDocManager::GetDocumentManager() ;
319 wxDocument
*doc
= dm
->CreateDocument(fileName
, wxDOC_SILENT
) ;
322 wxView
* view
= doc
->GetFirstView() ;
325 wxPrintout
*printout
= view
->OnCreatePrintout();
329 printer
.Print(view
->GetFrame(), printout
, true);
336 doc
->DeleteAllViews();
337 dm
->RemoveDocument(doc
) ;
348 void wxApp::MacNewFile()
352 void wxApp::MacReopenApp()
355 // if there is no open window -> create a new one
356 // if all windows are hidden -> show the first
357 // if some windows are not hidden -> do nothing
359 wxWindowList::compatibility_iterator node
= wxTopLevelWindows
.GetFirst();
366 wxTopLevelWindow
* firstIconized
= NULL
;
367 wxTopLevelWindow
* firstHidden
= NULL
;
370 wxTopLevelWindow
* win
= (wxTopLevelWindow
*) node
->GetData();
371 if ( !win
->IsShown() )
373 // make sure we don't show 'virtual toplevel windows' like wxTaskBarIconWindow
374 if ( firstHidden
== NULL
&& ( wxDynamicCast( win
, wxFrame
) || wxDynamicCast( win
, wxDialog
) ) )
377 else if ( win
->IsIconized() )
379 if ( firstIconized
== NULL
)
380 firstIconized
= win
;
384 // we do have a visible, non-iconized toplevelwindow -> do nothing
388 node
= node
->GetNext();
392 firstIconized
->Iconize( false ) ;
394 // showing hidden windows is not really always a good solution, also non-modal dialogs when closed end up
395 // as hidden tlws, we don't want to reshow those, so let's just reopen the minimized a.k.a. iconized tlws
396 // unless we find a regression ...
398 else if ( firstHidden
)
399 firstHidden
->Show( true );
404 //----------------------------------------------------------------------
405 // Macintosh CommandID support - converting between native and wx IDs
406 //----------------------------------------------------------------------
408 // if no native match they just return the passed-in id
418 IdPair gCommandIds
[] =
420 { kHICommandCut
, wxID_CUT
} ,
421 { kHICommandCopy
, wxID_COPY
} ,
422 { kHICommandPaste
, wxID_PASTE
} ,
423 { kHICommandSelectAll
, wxID_SELECTALL
} ,
424 { kHICommandClear
, wxID_CLEAR
} ,
425 { kHICommandUndo
, wxID_UNDO
} ,
426 { kHICommandRedo
, wxID_REDO
} ,
429 int wxMacCommandToId( UInt32 macCommandId
)
433 switch ( macCommandId
)
435 case kHICommandPreferences
:
436 wxid
= wxApp::s_macPreferencesMenuItemId
;
439 case kHICommandQuit
:
440 wxid
= wxApp::s_macExitMenuItemId
;
443 case kHICommandAbout
:
444 wxid
= wxApp::s_macAboutMenuItemId
;
449 for ( size_t i
= 0 ; i
< WXSIZEOF(gCommandIds
) ; ++i
)
451 if ( gCommandIds
[i
].macId
== macCommandId
)
453 wxid
= gCommandIds
[i
].wxId
;
462 wxid
= (int) macCommandId
;
467 UInt32
wxIdToMacCommand( int wxId
)
471 if ( wxId
== wxApp::s_macPreferencesMenuItemId
)
472 macId
= kHICommandPreferences
;
473 else if (wxId
== wxApp::s_macExitMenuItemId
)
474 macId
= kHICommandQuit
;
475 else if (wxId
== wxApp::s_macAboutMenuItemId
)
476 macId
= kHICommandAbout
;
479 for ( size_t i
= 0 ; i
< WXSIZEOF(gCommandIds
) ; ++i
)
481 if ( gCommandIds
[i
].wxId
== wxId
)
483 macId
= gCommandIds
[i
].macId
;
495 wxMenu
* wxFindMenuFromMacCommand( const HICommand
&command
, wxMenuItem
* &item
)
497 wxMenu
* itemMenu
= NULL
;
498 #ifndef __WXUNIVERSAL__
501 // for 'standard' commands which don't have a wx-menu
502 if ( command
.commandID
== kHICommandPreferences
|| command
.commandID
== kHICommandQuit
|| command
.commandID
== kHICommandAbout
)
504 id
= wxMacCommandToId( command
.commandID
) ;
506 wxMenuBar
* mbar
= wxMenuBar::MacGetInstalledMenuBar() ;
508 item
= mbar
->FindItem( id
, &itemMenu
) ;
510 else if ( command
.commandID
!= 0 && command
.menu
.menuRef
!= 0 && command
.menu
.menuItemIndex
!= 0 )
512 id
= wxMacCommandToId( command
.commandID
) ;
513 // make sure it is one of our own menus, or of the 'synthetic' apple and help menus , otherwise don't touch
514 MenuItemIndex firstUserHelpMenuItem
;
515 static MenuHandle helpMenuHandle
= NULL
;
516 if ( helpMenuHandle
== NULL
)
518 if ( UMAGetHelpMenuDontCreate( &helpMenuHandle
, &firstUserHelpMenuItem
) != noErr
)
519 helpMenuHandle
= NULL
;
522 // is it part of the application or the Help menu, then look for the id directly
523 if ( ( GetMenuHandle( kwxMacAppleMenuId
) != NULL
&& command
.menu
.menuRef
== GetMenuHandle( kwxMacAppleMenuId
) ) ||
524 ( helpMenuHandle
!= NULL
&& command
.menu
.menuRef
== helpMenuHandle
) ||
525 wxMenuBar::MacGetWindowMenuHMenu() != NULL
&& command
.menu
.menuRef
== wxMenuBar::MacGetWindowMenuHMenu() )
527 wxMenuBar
* mbar
= wxMenuBar::MacGetInstalledMenuBar() ;
529 item
= mbar
->FindItem( id
, &itemMenu
) ;
535 GetMenuItemRefCon( command
.menu
.menuRef
, command
.menu
.menuItemIndex
, &refCon
) ;
536 itemMenu
= wxFindMenuFromMacMenu( command
.menu
.menuRef
) ;
537 if ( itemMenu
!= NULL
&& refCon
!= 0)
538 item
= (wxMenuItem
*) refCon
;
547 //----------------------------------------------------------------------
548 // Carbon Event Handler
549 //----------------------------------------------------------------------
553 static const EventTypeSpec eventList
[] =
555 { kEventClassCommand
, kEventProcessCommand
} ,
556 { kEventClassCommand
, kEventCommandUpdateStatus
} ,
558 { kEventClassMenu
, kEventMenuOpening
},
559 { kEventClassMenu
, kEventMenuClosed
},
560 { kEventClassMenu
, kEventMenuTargetItem
},
562 { kEventClassApplication
, kEventAppActivated
} ,
563 { kEventClassApplication
, kEventAppDeactivated
} ,
564 // handling the quit event is not recommended by apple
565 // rather using the quit apple event - which we do
567 { kEventClassAppleEvent
, kEventAppleEvent
} ,
569 { kEventClassMouse
, kEventMouseDown
} ,
570 { kEventClassMouse
, kEventMouseMoved
} ,
571 { kEventClassMouse
, kEventMouseUp
} ,
572 { kEventClassMouse
, kEventMouseDragged
} ,
576 static pascal OSStatus
577 wxMacAppMenuEventHandler( EventHandlerCallRef
WXUNUSED(handler
),
579 void *WXUNUSED(data
) )
581 wxMacCarbonEvent
cEvent( event
) ;
582 MenuRef menuRef
= cEvent
.GetParameter
<MenuRef
>(kEventParamDirectObject
) ;
583 #ifndef __WXUNIVERSAL__
584 wxMenu
* menu
= wxFindMenuFromMacMenu( menuRef
) ;
588 switch (GetEventKind(event
))
590 case kEventMenuOpening
:
591 menu
->HandleMenuOpened();
594 case kEventMenuClosed
:
595 menu
->HandleMenuClosed();
598 case kEventMenuTargetItem
:
602 command
.menu
.menuRef
= menuRef
;
603 command
.menu
.menuItemIndex
= cEvent
.GetParameter
<MenuItemIndex
>(kEventParamMenuItemIndex
,typeMenuItemIndex
) ;
604 command
.commandID
= cEvent
.GetParameter
<MenuCommand
>(kEventParamMenuCommand
,typeMenuCommand
) ;
605 if (command
.commandID
!= 0)
607 wxMenuItem
* item
= NULL
;
608 wxMenu
* itemMenu
= wxFindMenuFromMacCommand( command
, item
) ;
609 if ( itemMenu
&& item
)
610 itemMenu
->HandleMenuItemHighlighted( item
);
616 wxFAIL_MSG(wxT("Unexpected menu event kind"));
622 return eventNotHandledErr
;
625 static pascal OSStatus
626 wxMacAppCommandEventHandler( EventHandlerCallRef
WXUNUSED(handler
) ,
628 void *WXUNUSED(data
) )
630 OSStatus result
= eventNotHandledErr
;
634 wxMacCarbonEvent
cEvent( event
) ;
635 cEvent
.GetParameter
<HICommand
>(kEventParamDirectObject
,typeHICommand
,&command
) ;
637 wxMenuItem
* item
= NULL
;
638 wxMenu
* itemMenu
= wxFindMenuFromMacCommand( command
, item
) ;
642 wxASSERT( itemMenu
!= NULL
) ;
644 switch ( cEvent
.GetKind() )
646 case kEventProcessCommand
:
647 if ( itemMenu
->HandleCommandProcess( item
) )
651 case kEventCommandUpdateStatus
:
652 if ( itemMenu
->HandleCommandUpdateStatus( item
) )
663 static pascal OSStatus
664 wxMacAppApplicationEventHandler( EventHandlerCallRef
WXUNUSED(handler
) ,
666 void *WXUNUSED(data
) )
668 OSStatus result
= eventNotHandledErr
;
669 switch ( GetEventKind( event
) )
671 case kEventAppActivated
:
673 wxTheApp
->SetActive( true , NULL
) ;
677 case kEventAppDeactivated
:
679 wxTheApp
->SetActive( false , NULL
) ;
690 pascal OSStatus
wxMacAppEventHandler( EventHandlerCallRef handler
, EventRef event
, void *data
)
692 EventRef formerEvent
= (EventRef
) wxTheApp
->MacGetCurrentEvent() ;
693 EventHandlerCallRef formerEventHandlerCallRef
= (EventHandlerCallRef
) wxTheApp
->MacGetCurrentEventHandlerCallRef() ;
694 wxTheApp
->MacSetCurrentEvent( event
, handler
) ;
696 OSStatus result
= eventNotHandledErr
;
697 switch ( GetEventClass( event
) )
700 case kEventClassCommand
:
701 result
= wxMacAppCommandEventHandler( handler
, event
, data
) ;
704 case kEventClassApplication
:
705 result
= wxMacAppApplicationEventHandler( handler
, event
, data
) ;
708 case kEventClassMenu
:
709 result
= wxMacAppMenuEventHandler( handler
, event
, data
) ;
712 case kEventClassMouse
:
714 wxMacCarbonEvent
cEvent( event
) ;
717 Point screenMouseLocation
= cEvent
.GetParameter
<Point
>(kEventParamMouseLocation
) ;
718 ::FindWindow(screenMouseLocation
, &window
);
719 // only send this event in case it had not already been sent to a tlw, as we get
720 // double events otherwise (in case event.skip) was called
721 if ( window
== NULL
)
722 result
= wxMacTopLevelMouseEventHandler( handler
, event
, NULL
) ;
726 case kEventClassAppleEvent
:
727 result
= AEProcessEvent(event
);
734 wxTheApp
->MacSetCurrentEvent( formerEvent
, formerEventHandlerCallRef
) ;
739 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacAppEventHandler
)
742 #if wxDEBUG_LEVEL && wxOSX_USE_COCOA_OR_CARBON
745 wxMacAssertOutputHandler(OSType
WXUNUSED(componentSignature
),
746 UInt32
WXUNUSED(options
),
747 const char *assertionString
,
748 const char *exceptionLabelString
,
749 const char *errorString
,
750 const char *fileName
,
753 ConstStr255Param
WXUNUSED(outputMsg
))
755 // flow into assert handling
756 wxString fileNameStr
;
757 wxString assertionStr
;
758 wxString exceptionStr
;
762 fileNameStr
= wxString(fileName
, wxConvLocal
);
763 assertionStr
= wxString(assertionString
, wxConvLocal
);
764 exceptionStr
= wxString((exceptionLabelString
!=0) ? exceptionLabelString
: "", wxConvLocal
) ;
765 errorStr
= wxString((errorString
!=0) ? errorString
: "", wxConvLocal
) ;
767 fileNameStr
= fileName
;
768 assertionStr
= assertionString
;
769 exceptionStr
= (exceptionLabelString
!=0) ? exceptionLabelString
: "" ;
770 errorStr
= (errorString
!=0) ? errorString
: "" ;
775 wxLogDebug( wxT("AssertMacros: %s %s %s file: %s, line: %ld (value %p)\n"),
776 assertionStr
.c_str() ,
777 exceptionStr
.c_str() ,
779 fileNameStr
.c_str(), lineNumber
,
783 wxOnAssert(fileNameStr
, lineNumber
, assertionStr
,
784 wxString::Format( wxT("%s %s value (%p)") , exceptionStr
, errorStr
, value
) ) ;
788 #endif // wxDEBUG_LEVEL
790 bool wxApp::Initialize(int& argc
, wxChar
**argv
)
794 #if wxDEBUG_LEVEL && wxOSX_USE_COCOA_OR_CARBON
795 InstallDebugAssertOutputHandler( NewDebugAssertOutputHandlerUPP( wxMacAssertOutputHandler
) );
798 // Mac OS X passes a process serial number command line argument when
799 // the application is launched from the Finder. This argument must be
800 // removed from the command line arguments before being handled by the
801 // application (otherwise applications would need to handle it)
804 static const wxChar
*ARG_PSN
= wxT("-psn_");
805 if ( wxStrncmp(argv
[1], ARG_PSN
, wxStrlen(ARG_PSN
)) == 0 )
807 // remove this argument
809 memmove(argv
+ 1, argv
+ 2, argc
* sizeof(wxChar
*));
814 Cocoa supports -Key value options which set the user defaults key "Key"
815 to the value "value" Some of them are very handy for debugging like
816 -NSShowAllViews YES. Cocoa picks these up from the real argv so
817 our removal of them from the wx copy of it does not affect Cocoa's
820 We basically just assume that any "-NS" option and its following
821 argument needs to be removed from argv. We hope that user code does
822 not expect to see -NS options and indeed it's probably a safe bet
823 since most user code accepting options is probably using the
824 double-dash GNU-style syntax.
826 for(int i
=1; i
< argc
; ++i
)
828 static const wxChar
*ARG_NS
= wxT("-NS");
829 if( wxStrncmp(argv
[i
], ARG_NS
, wxStrlen(ARG_NS
)) == 0 )
831 // Only eat this option if it has an argument
834 memmove(argv
+ i
, argv
+ i
+ 2, (argc
-i
-1)*sizeof(wxChar
*));
836 // drop back one position so the next run through the loop
837 // reprocesses the argument at our current index.
843 if ( !wxAppBase::Initialize(argc
, argv
) )
847 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
850 // these might be the startup dirs, set them to the 'usual' dir containing the app bundle
851 wxString startupCwd
= wxGetCwd() ;
852 if ( startupCwd
== wxT("/") || startupCwd
.Right(15) == wxT("/Contents/MacOS") )
854 CFURLRef url
= CFBundleCopyBundleURL(CFBundleGetMainBundle() ) ;
855 CFURLRef urlParent
= CFURLCreateCopyDeletingLastPathComponent( kCFAllocatorDefault
, url
) ;
857 CFStringRef path
= CFURLCopyFileSystemPath ( urlParent
, kCFURLPOSIXPathStyle
) ;
858 CFRelease( urlParent
) ;
859 wxString cwd
= wxCFStringRef(path
).AsString(wxLocale::GetSystemEncoding());
860 wxSetWorkingDirectory( cwd
) ;
866 #if wxOSX_USE_COCOA_OR_CARBON
867 bool wxApp::CallOnInit()
869 wxMacAutoreleasePool autoreleasepool
;
874 bool wxApp::OnInitGui()
876 if ( !wxAppBase::OnInitGui() )
885 bool wxApp::ProcessIdle()
887 wxMacAutoreleasePool autoreleasepool
;
888 return wxAppBase::ProcessIdle();
893 wxMacAutoreleasePool pool
;
894 return wxAppBase::OnRun();
898 bool wxApp::DoInitGui()
900 InstallStandardEventHandler( GetApplicationEventTarget() ) ;
903 InstallApplicationEventHandler(
904 GetwxMacAppEventHandlerUPP(),
905 GetEventTypeCount(eventList
), eventList
, wxTheApp
, (EventHandlerRef
*)&(wxTheApp
->m_macEventHandler
));
910 sODocHandler
= NewAEEventHandlerUPP(AEHandleODoc
) ;
911 sGURLHandler
= NewAEEventHandlerUPP(AEHandleGURL
) ;
912 sOAppHandler
= NewAEEventHandlerUPP(AEHandleOApp
) ;
913 sPDocHandler
= NewAEEventHandlerUPP(AEHandlePDoc
) ;
914 sRAppHandler
= NewAEEventHandlerUPP(AEHandleRApp
) ;
915 sQuitHandler
= NewAEEventHandlerUPP(AEHandleQuit
) ;
917 AEInstallEventHandler( kCoreEventClass
, kAEOpenDocuments
,
918 sODocHandler
, 0 , FALSE
) ;
919 AEInstallEventHandler( kInternetEventClass
, kAEGetURL
,
920 sGURLHandler
, 0 , FALSE
) ;
921 AEInstallEventHandler( kCoreEventClass
, kAEOpenApplication
,
922 sOAppHandler
, 0 , FALSE
) ;
923 AEInstallEventHandler( kCoreEventClass
, kAEPrintDocuments
,
924 sPDocHandler
, 0 , FALSE
) ;
925 AEInstallEventHandler( kCoreEventClass
, kAEReopenApplication
,
926 sRAppHandler
, 0 , FALSE
) ;
927 AEInstallEventHandler( kCoreEventClass
, kAEQuitApplication
,
928 sQuitHandler
, 0 , FALSE
) ;
931 if ( !wxMacInitCocoa() )
937 void wxApp::DoCleanUp()
940 RemoveEventHandler( (EventHandlerRef
)(wxTheApp
->m_macEventHandler
) );
944 AERemoveEventHandler( kCoreEventClass
, kAEOpenDocuments
,
945 sODocHandler
, FALSE
) ;
946 AERemoveEventHandler( kInternetEventClass
, kAEGetURL
,
947 sGURLHandler
, FALSE
) ;
948 AERemoveEventHandler( kCoreEventClass
, kAEOpenApplication
,
949 sOAppHandler
, FALSE
) ;
950 AERemoveEventHandler( kCoreEventClass
, kAEPrintDocuments
,
951 sPDocHandler
, FALSE
) ;
952 AERemoveEventHandler( kCoreEventClass
, kAEReopenApplication
,
953 sRAppHandler
, FALSE
) ;
954 AERemoveEventHandler( kCoreEventClass
, kAEQuitApplication
,
955 sQuitHandler
, FALSE
) ;
957 DisposeAEEventHandlerUPP( sODocHandler
) ;
958 DisposeAEEventHandlerUPP( sGURLHandler
) ;
959 DisposeAEEventHandlerUPP( sOAppHandler
) ;
960 DisposeAEEventHandlerUPP( sPDocHandler
) ;
961 DisposeAEEventHandlerUPP( sRAppHandler
) ;
962 DisposeAEEventHandlerUPP( sQuitHandler
) ;
968 void wxApp::CleanUp()
970 wxMacAutoreleasePool autoreleasepool
;
972 wxToolTip::RemoveToolTips() ;
977 wxAppBase::CleanUp();
980 //----------------------------------------------------------------------
981 // misc initialization stuff
982 //----------------------------------------------------------------------
986 m_printMode
= wxPRINT_WINDOWS
;
988 m_macCurrentEvent
= NULL
;
989 m_macCurrentEventHandlerCallRef
= NULL
;
990 m_macPool
= new wxMacAutoreleasePool();
999 CFMutableArrayRef
GetAutoReleaseArray()
1001 static CFMutableArrayRef array
= 0;
1003 array
= CFArrayCreateMutable(kCFAllocatorDefault
,0,&kCFTypeArrayCallBacks
);
1007 void wxApp::MacAddToAutorelease( void* cfrefobj
)
1009 CFArrayAppendValue( GetAutoReleaseArray(), cfrefobj
);
1012 void wxApp::MacReleaseAutoreleasePool()
1016 m_macPool
= new wxMacAutoreleasePool();
1019 void wxApp::OnIdle(wxIdleEvent
& WXUNUSED(event
))
1021 // If they are pending events, we must process them: pending events are
1022 // either events to the threads other than main or events posted with
1023 // wxPostEvent() functions
1024 #ifndef __WXUNIVERSAL__
1026 if (!wxMenuBar::MacGetInstalledMenuBar() && wxMenuBar::MacGetCommonMenuBar())
1027 wxMenuBar::MacGetCommonMenuBar()->MacInstallMenuBar();
1030 CFArrayRemoveAllValues( GetAutoReleaseArray() );
1033 void wxApp::WakeUpIdle()
1035 wxEventLoopBase
* const loop
= wxEventLoopBase::GetActive();
1041 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
))
1044 GetTopWindow()->Close(true);
1047 // Default behaviour: close the application with prompts. The
1048 // user can veto the close, and therefore the end session.
1049 void wxApp::OnQueryEndSession(wxCloseEvent
& event
)
1051 if ( !wxDialog::OSXHasModalDialogsOpen() )
1055 if (!GetTopWindow()->Close(!event
.CanVeto()))
1065 extern "C" void wxCYield() ;
1072 void wxApp::MacHandleUnhandledEvent( WXEVENTREF
WXUNUSED(evr
) )
1074 // Override to process unhandled events as you please
1077 #if wxOSX_USE_COCOA_OR_CARBON
1079 CGKeyCode
wxCharCodeWXToOSX(wxKeyCode code
)
1085 // Clang warns about switch values not of the same type as (enumerated)
1086 // switch controlling expression. This is generally useful but here we
1087 // really want to be able to use letters and digits without making them
1088 // part of wxKeyCode enum.
1090 #pragma clang diagnostic push
1091 #pragma clang diagnostic ignored "-Wswitch"
1094 case 'a': case 'A': keycode
= kVK_ANSI_A
; break;
1095 case 'b': case 'B': keycode
= kVK_ANSI_B
; break;
1096 case 'c': case 'C': keycode
= kVK_ANSI_C
; break;
1097 case 'd': case 'D': keycode
= kVK_ANSI_D
; break;
1098 case 'e': case 'E': keycode
= kVK_ANSI_E
; break;
1099 case 'f': case 'F': keycode
= kVK_ANSI_F
; break;
1100 case 'g': case 'G': keycode
= kVK_ANSI_G
; break;
1101 case 'h': case 'H': keycode
= kVK_ANSI_H
; break;
1102 case 'i': case 'I': keycode
= kVK_ANSI_I
; break;
1103 case 'j': case 'J': keycode
= kVK_ANSI_J
; break;
1104 case 'k': case 'K': keycode
= kVK_ANSI_K
; break;
1105 case 'l': case 'L': keycode
= kVK_ANSI_L
; break;
1106 case 'm': case 'M': keycode
= kVK_ANSI_M
; break;
1107 case 'n': case 'N': keycode
= kVK_ANSI_N
; break;
1108 case 'o': case 'O': keycode
= kVK_ANSI_O
; break;
1109 case 'p': case 'P': keycode
= kVK_ANSI_P
; break;
1110 case 'q': case 'Q': keycode
= kVK_ANSI_Q
; break;
1111 case 'r': case 'R': keycode
= kVK_ANSI_R
; break;
1112 case 's': case 'S': keycode
= kVK_ANSI_S
; break;
1113 case 't': case 'T': keycode
= kVK_ANSI_T
; break;
1114 case 'u': case 'U': keycode
= kVK_ANSI_U
; break;
1115 case 'v': case 'V': keycode
= kVK_ANSI_V
; break;
1116 case 'w': case 'W': keycode
= kVK_ANSI_W
; break;
1117 case 'x': case 'X': keycode
= kVK_ANSI_X
; break;
1118 case 'y': case 'Y': keycode
= kVK_ANSI_Y
; break;
1119 case 'z': case 'Z': keycode
= kVK_ANSI_Z
; break;
1121 case '0': keycode
= kVK_ANSI_0
; break;
1122 case '1': keycode
= kVK_ANSI_1
; break;
1123 case '2': keycode
= kVK_ANSI_2
; break;
1124 case '3': keycode
= kVK_ANSI_3
; break;
1125 case '4': keycode
= kVK_ANSI_4
; break;
1126 case '5': keycode
= kVK_ANSI_5
; break;
1127 case '6': keycode
= kVK_ANSI_6
; break;
1128 case '7': keycode
= kVK_ANSI_7
; break;
1129 case '8': keycode
= kVK_ANSI_8
; break;
1130 case '9': keycode
= kVK_ANSI_9
; break;
1133 #pragma clang diagnostic pop
1136 case WXK_BACK
: keycode
= kVK_Delete
; break;
1137 case WXK_TAB
: keycode
= kVK_Tab
; break;
1138 case WXK_RETURN
: keycode
= kVK_Return
; break;
1139 case WXK_ESCAPE
: keycode
= kVK_Escape
; break;
1140 case WXK_SPACE
: keycode
= kVK_Space
; break;
1141 case WXK_DELETE
: keycode
= kVK_ForwardDelete
; break;
1143 case WXK_SHIFT
: keycode
= kVK_Shift
; break;
1144 case WXK_ALT
: keycode
= kVK_Option
; break;
1145 case WXK_RAW_CONTROL
: keycode
= kVK_Control
; break;
1146 case WXK_CONTROL
: keycode
= kVK_Command
; break;
1148 case WXK_CAPITAL
: keycode
= kVK_CapsLock
; break;
1149 case WXK_END
: keycode
= kVK_End
; break;
1150 case WXK_HOME
: keycode
= kVK_Home
; break;
1151 case WXK_LEFT
: keycode
= kVK_LeftArrow
; break;
1152 case WXK_UP
: keycode
= kVK_UpArrow
; break;
1153 case WXK_RIGHT
: keycode
= kVK_RightArrow
; break;
1154 case WXK_DOWN
: keycode
= kVK_DownArrow
; break;
1156 case WXK_HELP
: keycode
= kVK_Help
; break;
1159 case WXK_NUMPAD0
: keycode
= kVK_ANSI_Keypad0
; break;
1160 case WXK_NUMPAD1
: keycode
= kVK_ANSI_Keypad1
; break;
1161 case WXK_NUMPAD2
: keycode
= kVK_ANSI_Keypad2
; break;
1162 case WXK_NUMPAD3
: keycode
= kVK_ANSI_Keypad3
; break;
1163 case WXK_NUMPAD4
: keycode
= kVK_ANSI_Keypad4
; break;
1164 case WXK_NUMPAD5
: keycode
= kVK_ANSI_Keypad5
; break;
1165 case WXK_NUMPAD6
: keycode
= kVK_ANSI_Keypad6
; break;
1166 case WXK_NUMPAD7
: keycode
= kVK_ANSI_Keypad7
; break;
1167 case WXK_NUMPAD8
: keycode
= kVK_ANSI_Keypad8
; break;
1168 case WXK_NUMPAD9
: keycode
= kVK_ANSI_Keypad9
; break;
1169 case WXK_F1
: keycode
= kVK_F1
; break;
1170 case WXK_F2
: keycode
= kVK_F2
; break;
1171 case WXK_F3
: keycode
= kVK_F3
; break;
1172 case WXK_F4
: keycode
= kVK_F4
; break;
1173 case WXK_F5
: keycode
= kVK_F5
; break;
1174 case WXK_F6
: keycode
= kVK_F6
; break;
1175 case WXK_F7
: keycode
= kVK_F7
; break;
1176 case WXK_F8
: keycode
= kVK_F8
; break;
1177 case WXK_F9
: keycode
= kVK_F9
; break;
1178 case WXK_F10
: keycode
= kVK_F10
; break;
1179 case WXK_F11
: keycode
= kVK_F11
; break;
1180 case WXK_F12
: keycode
= kVK_F12
; break;
1181 case WXK_F13
: keycode
= kVK_F13
; break;
1182 case WXK_F14
: keycode
= kVK_F14
; break;
1183 case WXK_F15
: keycode
= kVK_F15
; break;
1184 case WXK_F16
: keycode
= kVK_F16
; break;
1185 case WXK_F17
: keycode
= kVK_F17
; break;
1186 case WXK_F18
: keycode
= kVK_F18
; break;
1187 case WXK_F19
: keycode
= kVK_F19
; break;
1188 case WXK_F20
: keycode
= kVK_F20
; break;
1190 case WXK_PAGEUP
: keycode
= kVK_PageUp
; break;
1191 case WXK_PAGEDOWN
: keycode
= kVK_PageDown
; break;
1193 case WXK_NUMPAD_DELETE
: keycode
= kVK_ANSI_KeypadClear
; break;
1194 case WXK_NUMPAD_EQUAL
: keycode
= kVK_ANSI_KeypadEquals
; break;
1195 case WXK_NUMPAD_MULTIPLY
: keycode
= kVK_ANSI_KeypadMultiply
; break;
1196 case WXK_NUMPAD_ADD
: keycode
= kVK_ANSI_KeypadPlus
; break;
1197 case WXK_NUMPAD_SUBTRACT
: keycode
= kVK_ANSI_KeypadMinus
; break;
1198 case WXK_NUMPAD_DECIMAL
: keycode
= kVK_ANSI_KeypadDecimal
; break;
1199 case WXK_NUMPAD_DIVIDE
: keycode
= kVK_ANSI_KeypadDivide
; break;
1202 wxLogDebug( "Unrecognised keycode %d", code
);
1203 keycode
= static_cast<CGKeyCode
>(-1);
1209 long wxMacTranslateKey(unsigned char key
, unsigned char code
)
1214 case kHomeCharCode
:
1218 case kEnterCharCode
:
1219 retval
= WXK_RETURN
;
1225 case kHelpCharCode
:
1229 case kBackspaceCharCode
:
1237 case kPageUpCharCode
:
1238 retval
= WXK_PAGEUP
;
1241 case kPageDownCharCode
:
1242 retval
= WXK_PAGEDOWN
;
1245 case kReturnCharCode
:
1246 retval
= WXK_RETURN
;
1249 case kFunctionKeyCharCode
:
1319 case kEscapeCharCode
:
1320 retval
= WXK_ESCAPE
;
1323 case kLeftArrowCharCode
:
1327 case kRightArrowCharCode
:
1328 retval
= WXK_RIGHT
;
1331 case kUpArrowCharCode
:
1335 case kDownArrowCharCode
:
1339 case kDeleteCharCode
:
1340 retval
= WXK_DELETE
;
1350 int wxMacKeyCodeToModifier(wxKeyCode key
)
1368 case WXK_RAW_CONTROL
:
1377 #if wxOSX_USE_COCOA && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
1379 // defined in utils.mm
1381 #elif wxOSX_USE_COCOA_OR_CARBON
1383 wxMouseState
wxGetMouseState()
1387 wxPoint pt
= wxGetMousePosition();
1391 UInt32 buttons
= GetCurrentButtonState();
1392 ms
.SetLeftDown( (buttons
& 0x01) != 0 );
1393 ms
.SetMiddleDown( (buttons
& 0x04) != 0 );
1394 ms
.SetRightDown( (buttons
& 0x02) != 0 );
1396 UInt32 modifiers
= GetCurrentKeyModifiers();
1397 ms
.SetRawControlDown(modifiers
& controlKey
);
1398 ms
.SetShiftDown(modifiers
& shiftKey
);
1399 ms
.SetAltDown(modifiers
& optionKey
);
1400 ms
.SetControlDown(modifiers
& cmdKey
);
1407 // TODO : once the new key/char handling is tested, move all the code to wxWindow
1409 bool wxApp::MacSendKeyDownEvent( wxWindow
* focus
, long keymessage
, long modifiers
, long when
, wxChar uniChar
)
1414 wxKeyEvent
event(wxEVT_KEY_DOWN
) ;
1415 MacCreateKeyEvent( event
, focus
, keymessage
, modifiers
, when
, uniChar
) ;
1417 return focus
->OSXHandleKeyEvent(event
);
1420 bool wxApp::MacSendKeyUpEvent( wxWindow
* focus
, long keymessage
, long modifiers
, long when
, wxChar uniChar
)
1425 wxKeyEvent
event( wxEVT_KEY_UP
) ;
1426 MacCreateKeyEvent( event
, focus
, keymessage
, modifiers
, when
, uniChar
) ;
1428 return focus
->OSXHandleKeyEvent(event
) ;
1431 bool wxApp::MacSendCharEvent( wxWindow
* focus
, long keymessage
, long modifiers
, long when
, wxChar uniChar
)
1435 wxKeyEvent
event(wxEVT_CHAR
) ;
1436 MacCreateKeyEvent( event
, focus
, keymessage
, modifiers
, when
, uniChar
) ;
1438 bool handled
= false ;
1440 #if wxOSX_USE_CARBON
1441 long keyval
= event
.m_keyCode
;
1444 wxKeyEvent
eventCharHook(wxEVT_CHAR_HOOK
, event
);
1445 handled
= focus
->HandleWindowEvent( eventCharHook
);
1446 if ( handled
&& eventCharHook
.IsNextEventAllowed() )
1452 handled
= focus
->HandleWindowEvent( event
) ;
1455 if ( !handled
&& (keyval
== WXK_TAB
) )
1457 wxWindow
* iter
= focus
->GetParent() ;
1458 while ( iter
&& !handled
)
1460 if ( iter
->HasFlag( wxTAB_TRAVERSAL
) )
1462 wxNavigationKeyEvent new_event
;
1463 new_event
.SetEventObject( focus
);
1464 new_event
.SetDirection( !event
.ShiftDown() );
1465 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1466 new_event
.SetWindowChange( event
.ControlDown() );
1467 new_event
.SetCurrentFocus( focus
);
1468 handled
= focus
->GetParent()->HandleWindowEvent( new_event
);
1469 if ( handled
&& new_event
.GetSkipped() )
1473 iter
= iter
->GetParent() ;
1477 // backdoor handler for default return and command escape
1478 if ( !handled
&& (!focus
->IsKindOf(CLASSINFO(wxControl
) ) || !focus
->AcceptsFocus() ) )
1480 // if window is not having a focus still testing for default enter or cancel
1481 // TODO: add the UMA version for ActiveNonFloatingWindow
1483 wxWindow
* focus
= wxNonOwnedWindow::GetFromWXWindow( (WXWindow
) FrontWindow() ) ;
1486 if ( keyval
== WXK_RETURN
|| keyval
== WXK_NUMPAD_ENTER
)
1488 wxTopLevelWindow
*tlw
= wxDynamicCast(wxGetTopLevelParent(focus
), wxTopLevelWindow
);
1489 if ( tlw
&& tlw
->GetDefaultItem() )
1491 wxButton
*def
= wxDynamicCast(tlw
->GetDefaultItem(), wxButton
);
1492 if ( def
&& def
->IsEnabled() )
1494 wxCommandEvent
event(wxEVT_BUTTON
, def
->GetId() );
1495 event
.SetEventObject(def
);
1496 def
->Command(event
);
1502 else if (keyval
== WXK_ESCAPE
|| (keyval
== '.' && modifiers
& cmdKey
) )
1504 // generate wxID_CANCEL if command-. or <esc> has been pressed (typically in dialogs)
1505 wxCommandEvent
new_event(wxEVT_BUTTON
,wxID_CANCEL
);
1506 new_event
.SetEventObject( focus
);
1507 handled
= focus
->HandleWindowEvent( new_event
);
1516 // This method handles common code for SendKeyDown, SendKeyUp, and SendChar events.
1517 void wxApp::MacCreateKeyEvent( wxKeyEvent
& event
, wxWindow
* focus
, long keymessage
, long modifiers
, long when
, wxChar uniChar
)
1519 #if wxOSX_USE_COCOA_OR_CARBON
1521 short keycode
, keychar
;
1523 keychar
= short(keymessage
& charCodeMask
);
1524 keycode
= short(keymessage
& keyCodeMask
) >> 8 ;
1525 if ( !(event
.GetEventType() == wxEVT_CHAR
) && (modifiers
& (controlKey
| shiftKey
| optionKey
) ) )
1527 // control interferes with some built-in keys like pgdown, return etc. therefore we remove the controlKey modifier
1528 // and look at the character after
1530 // TODO new implementation using TextInputSources
1533 UInt32 keyInfo
= KeyTranslate((Ptr
)GetScriptManagerVariable(smKCHRCache
), ( modifiers
& (~(controlKey
| shiftKey
| optionKey
))) | keycode
, &state
);
1534 keychar
= short(keyInfo
& charCodeMask
);
1538 long keyval
= wxMacTranslateKey(keychar
, keycode
) ;
1539 if ( keyval
== keychar
&& ( event
.GetEventType() == wxEVT_KEY_UP
|| event
.GetEventType() == wxEVT_KEY_DOWN
) )
1540 keyval
= wxToupper( keyval
) ;
1542 // Check for NUMPAD keys. For KEY_UP/DOWN events we need to use the
1543 // WXK_NUMPAD constants, but for the CHAR event we want to use the
1544 // standard ascii values
1545 if ( event
.GetEventType() != wxEVT_CHAR
)
1547 if (keyval
>= '0' && keyval
<= '9' && keycode
>= 82 && keycode
<= 92)
1549 keyval
= (keyval
- '0') + WXK_NUMPAD0
;
1551 else if (keycode
>= 65 && keycode
<= 81)
1556 keyval
= WXK_NUMPAD_ENTER
;
1560 keyval
= WXK_NUMPAD_EQUAL
;
1564 keyval
= WXK_NUMPAD_MULTIPLY
;
1568 keyval
= WXK_NUMPAD_DIVIDE
;
1572 keyval
= WXK_NUMPAD_SUBTRACT
;
1576 keyval
= WXK_NUMPAD_ADD
;
1580 keyval
= WXK_NUMPAD_DECIMAL
;
1588 event
.m_shiftDown
= modifiers
& shiftKey
;
1589 event
.m_rawControlDown
= modifiers
& controlKey
;
1590 event
.m_altDown
= modifiers
& optionKey
;
1591 event
.m_controlDown
= modifiers
& cmdKey
;
1592 event
.m_keyCode
= keyval
;
1594 event
.m_uniChar
= uniChar
;
1597 event
.m_rawCode
= keymessage
;
1598 event
.m_rawFlags
= modifiers
;
1599 event
.SetTimestamp(when
);
1600 event
.SetEventObject(focus
);
1604 wxUnusedVar(keymessage
);
1605 wxUnusedVar(modifiers
);
1607 wxUnusedVar(uniChar
);
1612 void wxApp::MacHideApp()
1614 #if wxOSX_USE_CARBON
1615 wxMacCarbonEvent
event( kEventClassCommand
, kEventCommandProcess
);
1617 memset( &command
, 0 , sizeof(command
) );
1618 command
.commandID
= kHICommandHide
;
1619 event
.SetParameter
<HICommand
>(kEventParamDirectObject
, command
);
1620 SendEventToApplication( event
);