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 void wxApp::OSXOnWillFinishLaunching()
408 void wxApp::OSXOnDidFinishLaunching()
412 //----------------------------------------------------------------------
413 // Macintosh CommandID support - converting between native and wx IDs
414 //----------------------------------------------------------------------
416 // if no native match they just return the passed-in id
426 IdPair gCommandIds
[] =
428 { kHICommandCut
, wxID_CUT
} ,
429 { kHICommandCopy
, wxID_COPY
} ,
430 { kHICommandPaste
, wxID_PASTE
} ,
431 { kHICommandSelectAll
, wxID_SELECTALL
} ,
432 { kHICommandClear
, wxID_CLEAR
} ,
433 { kHICommandUndo
, wxID_UNDO
} ,
434 { kHICommandRedo
, wxID_REDO
} ,
437 int wxMacCommandToId( UInt32 macCommandId
)
441 switch ( macCommandId
)
443 case kHICommandPreferences
:
444 wxid
= wxApp::s_macPreferencesMenuItemId
;
447 case kHICommandQuit
:
448 wxid
= wxApp::s_macExitMenuItemId
;
451 case kHICommandAbout
:
452 wxid
= wxApp::s_macAboutMenuItemId
;
457 for ( size_t i
= 0 ; i
< WXSIZEOF(gCommandIds
) ; ++i
)
459 if ( gCommandIds
[i
].macId
== macCommandId
)
461 wxid
= gCommandIds
[i
].wxId
;
470 wxid
= (int) macCommandId
;
475 UInt32
wxIdToMacCommand( int wxId
)
479 if ( wxId
== wxApp::s_macPreferencesMenuItemId
)
480 macId
= kHICommandPreferences
;
481 else if (wxId
== wxApp::s_macExitMenuItemId
)
482 macId
= kHICommandQuit
;
483 else if (wxId
== wxApp::s_macAboutMenuItemId
)
484 macId
= kHICommandAbout
;
487 for ( size_t i
= 0 ; i
< WXSIZEOF(gCommandIds
) ; ++i
)
489 if ( gCommandIds
[i
].wxId
== wxId
)
491 macId
= gCommandIds
[i
].macId
;
503 wxMenu
* wxFindMenuFromMacCommand( const HICommand
&command
, wxMenuItem
* &item
)
505 wxMenu
* itemMenu
= NULL
;
506 #ifndef __WXUNIVERSAL__
509 // for 'standard' commands which don't have a wx-menu
510 if ( command
.commandID
== kHICommandPreferences
|| command
.commandID
== kHICommandQuit
|| command
.commandID
== kHICommandAbout
)
512 id
= wxMacCommandToId( command
.commandID
) ;
514 wxMenuBar
* mbar
= wxMenuBar::MacGetInstalledMenuBar() ;
516 item
= mbar
->FindItem( id
, &itemMenu
) ;
518 else if ( command
.commandID
!= 0 && command
.menu
.menuRef
!= 0 && command
.menu
.menuItemIndex
!= 0 )
520 id
= wxMacCommandToId( command
.commandID
) ;
521 // make sure it is one of our own menus, or of the 'synthetic' apple and help menus , otherwise don't touch
522 MenuItemIndex firstUserHelpMenuItem
;
523 static MenuHandle helpMenuHandle
= NULL
;
524 if ( helpMenuHandle
== NULL
)
526 if ( UMAGetHelpMenuDontCreate( &helpMenuHandle
, &firstUserHelpMenuItem
) != noErr
)
527 helpMenuHandle
= NULL
;
530 // is it part of the application or the Help menu, then look for the id directly
531 if ( ( GetMenuHandle( kwxMacAppleMenuId
) != NULL
&& command
.menu
.menuRef
== GetMenuHandle( kwxMacAppleMenuId
) ) ||
532 ( helpMenuHandle
!= NULL
&& command
.menu
.menuRef
== helpMenuHandle
) ||
533 wxMenuBar::MacGetWindowMenuHMenu() != NULL
&& command
.menu
.menuRef
== wxMenuBar::MacGetWindowMenuHMenu() )
535 wxMenuBar
* mbar
= wxMenuBar::MacGetInstalledMenuBar() ;
537 item
= mbar
->FindItem( id
, &itemMenu
) ;
543 GetMenuItemRefCon( command
.menu
.menuRef
, command
.menu
.menuItemIndex
, &refCon
) ;
544 itemMenu
= wxFindMenuFromMacMenu( command
.menu
.menuRef
) ;
545 if ( itemMenu
!= NULL
&& refCon
!= 0)
546 item
= (wxMenuItem
*) refCon
;
555 //----------------------------------------------------------------------
556 // Carbon Event Handler
557 //----------------------------------------------------------------------
561 static const EventTypeSpec eventList
[] =
563 { kEventClassCommand
, kEventProcessCommand
} ,
564 { kEventClassCommand
, kEventCommandUpdateStatus
} ,
566 { kEventClassMenu
, kEventMenuOpening
},
567 { kEventClassMenu
, kEventMenuClosed
},
568 { kEventClassMenu
, kEventMenuTargetItem
},
570 { kEventClassApplication
, kEventAppActivated
} ,
571 { kEventClassApplication
, kEventAppDeactivated
} ,
572 // handling the quit event is not recommended by apple
573 // rather using the quit apple event - which we do
575 { kEventClassAppleEvent
, kEventAppleEvent
} ,
577 { kEventClassMouse
, kEventMouseDown
} ,
578 { kEventClassMouse
, kEventMouseMoved
} ,
579 { kEventClassMouse
, kEventMouseUp
} ,
580 { kEventClassMouse
, kEventMouseDragged
} ,
584 static pascal OSStatus
585 wxMacAppMenuEventHandler( EventHandlerCallRef
WXUNUSED(handler
),
587 void *WXUNUSED(data
) )
589 wxMacCarbonEvent
cEvent( event
) ;
590 MenuRef menuRef
= cEvent
.GetParameter
<MenuRef
>(kEventParamDirectObject
) ;
591 #ifndef __WXUNIVERSAL__
592 wxMenu
* menu
= wxFindMenuFromMacMenu( menuRef
) ;
596 switch (GetEventKind(event
))
598 case kEventMenuOpening
:
599 menu
->HandleMenuOpened();
602 case kEventMenuClosed
:
603 menu
->HandleMenuClosed();
606 case kEventMenuTargetItem
:
610 command
.menu
.menuRef
= menuRef
;
611 command
.menu
.menuItemIndex
= cEvent
.GetParameter
<MenuItemIndex
>(kEventParamMenuItemIndex
,typeMenuItemIndex
) ;
612 command
.commandID
= cEvent
.GetParameter
<MenuCommand
>(kEventParamMenuCommand
,typeMenuCommand
) ;
613 if (command
.commandID
!= 0)
615 wxMenuItem
* item
= NULL
;
616 wxMenu
* itemMenu
= wxFindMenuFromMacCommand( command
, item
) ;
617 if ( itemMenu
&& item
)
618 itemMenu
->HandleMenuItemHighlighted( item
);
624 wxFAIL_MSG(wxT("Unexpected menu event kind"));
630 return eventNotHandledErr
;
633 static pascal OSStatus
634 wxMacAppCommandEventHandler( EventHandlerCallRef
WXUNUSED(handler
) ,
636 void *WXUNUSED(data
) )
638 OSStatus result
= eventNotHandledErr
;
642 wxMacCarbonEvent
cEvent( event
) ;
643 cEvent
.GetParameter
<HICommand
>(kEventParamDirectObject
,typeHICommand
,&command
) ;
645 wxMenuItem
* item
= NULL
;
646 wxMenu
* itemMenu
= wxFindMenuFromMacCommand( command
, item
) ;
650 wxASSERT( itemMenu
!= NULL
) ;
652 switch ( cEvent
.GetKind() )
654 case kEventProcessCommand
:
655 if ( itemMenu
->HandleCommandProcess( item
) )
659 case kEventCommandUpdateStatus
:
660 if ( itemMenu
->HandleCommandUpdateStatus( item
) )
671 static pascal OSStatus
672 wxMacAppApplicationEventHandler( EventHandlerCallRef
WXUNUSED(handler
) ,
674 void *WXUNUSED(data
) )
676 OSStatus result
= eventNotHandledErr
;
677 switch ( GetEventKind( event
) )
679 case kEventAppActivated
:
681 wxTheApp
->SetActive( true , NULL
) ;
685 case kEventAppDeactivated
:
687 wxTheApp
->SetActive( false , NULL
) ;
698 pascal OSStatus
wxMacAppEventHandler( EventHandlerCallRef handler
, EventRef event
, void *data
)
700 EventRef formerEvent
= (EventRef
) wxTheApp
->MacGetCurrentEvent() ;
701 EventHandlerCallRef formerEventHandlerCallRef
= (EventHandlerCallRef
) wxTheApp
->MacGetCurrentEventHandlerCallRef() ;
702 wxTheApp
->MacSetCurrentEvent( event
, handler
) ;
704 OSStatus result
= eventNotHandledErr
;
705 switch ( GetEventClass( event
) )
708 case kEventClassCommand
:
709 result
= wxMacAppCommandEventHandler( handler
, event
, data
) ;
712 case kEventClassApplication
:
713 result
= wxMacAppApplicationEventHandler( handler
, event
, data
) ;
716 case kEventClassMenu
:
717 result
= wxMacAppMenuEventHandler( handler
, event
, data
) ;
720 case kEventClassMouse
:
722 wxMacCarbonEvent
cEvent( event
) ;
725 Point screenMouseLocation
= cEvent
.GetParameter
<Point
>(kEventParamMouseLocation
) ;
726 ::FindWindow(screenMouseLocation
, &window
);
727 // only send this event in case it had not already been sent to a tlw, as we get
728 // double events otherwise (in case event.skip) was called
729 if ( window
== NULL
)
730 result
= wxMacTopLevelMouseEventHandler( handler
, event
, NULL
) ;
734 case kEventClassAppleEvent
:
735 result
= AEProcessEvent(event
);
742 wxTheApp
->MacSetCurrentEvent( formerEvent
, formerEventHandlerCallRef
) ;
747 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacAppEventHandler
)
750 #if wxDEBUG_LEVEL && wxOSX_USE_COCOA_OR_CARBON
753 wxMacAssertOutputHandler(OSType
WXUNUSED(componentSignature
),
754 UInt32
WXUNUSED(options
),
755 const char *assertionString
,
756 const char *exceptionLabelString
,
757 const char *errorString
,
758 const char *fileName
,
761 ConstStr255Param
WXUNUSED(outputMsg
))
763 // flow into assert handling
764 wxString fileNameStr
;
765 wxString assertionStr
;
766 wxString exceptionStr
;
770 fileNameStr
= wxString(fileName
, wxConvLocal
);
771 assertionStr
= wxString(assertionString
, wxConvLocal
);
772 exceptionStr
= wxString((exceptionLabelString
!=0) ? exceptionLabelString
: "", wxConvLocal
) ;
773 errorStr
= wxString((errorString
!=0) ? errorString
: "", wxConvLocal
) ;
775 fileNameStr
= fileName
;
776 assertionStr
= assertionString
;
777 exceptionStr
= (exceptionLabelString
!=0) ? exceptionLabelString
: "" ;
778 errorStr
= (errorString
!=0) ? errorString
: "" ;
783 wxLogDebug( wxT("AssertMacros: %s %s %s file: %s, line: %ld (value %p)\n"),
784 assertionStr
.c_str() ,
785 exceptionStr
.c_str() ,
787 fileNameStr
.c_str(), lineNumber
,
791 wxOnAssert(fileNameStr
, lineNumber
, assertionStr
,
792 wxString::Format( wxT("%s %s value (%p)") , exceptionStr
, errorStr
, value
) ) ;
796 #endif // wxDEBUG_LEVEL
798 bool wxApp::Initialize(int& argc
, wxChar
**argv
)
802 #if wxDEBUG_LEVEL && wxOSX_USE_COCOA_OR_CARBON
803 InstallDebugAssertOutputHandler( NewDebugAssertOutputHandlerUPP( wxMacAssertOutputHandler
) );
806 // Mac OS X passes a process serial number command line argument when
807 // the application is launched from the Finder. This argument must be
808 // removed from the command line arguments before being handled by the
809 // application (otherwise applications would need to handle it)
812 static const wxChar
*ARG_PSN
= wxT("-psn_");
813 if ( wxStrncmp(argv
[1], ARG_PSN
, wxStrlen(ARG_PSN
)) == 0 )
815 // remove this argument
817 memmove(argv
+ 1, argv
+ 2, argc
* sizeof(wxChar
*));
822 Cocoa supports -Key value options which set the user defaults key "Key"
823 to the value "value" Some of them are very handy for debugging like
824 -NSShowAllViews YES. Cocoa picks these up from the real argv so
825 our removal of them from the wx copy of it does not affect Cocoa's
828 We basically just assume that any "-NS" option and its following
829 argument needs to be removed from argv. We hope that user code does
830 not expect to see -NS options and indeed it's probably a safe bet
831 since most user code accepting options is probably using the
832 double-dash GNU-style syntax.
834 for(int i
=1; i
< argc
; ++i
)
836 static const wxChar
*ARG_NS
= wxT("-NS");
837 if( wxStrncmp(argv
[i
], ARG_NS
, wxStrlen(ARG_NS
)) == 0 )
839 // Only eat this option if it has an argument
842 memmove(argv
+ i
, argv
+ i
+ 2, (argc
-i
-1)*sizeof(wxChar
*));
844 // drop back one position so the next run through the loop
845 // reprocesses the argument at our current index.
851 if ( !wxAppBase::Initialize(argc
, argv
) )
855 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
858 // these might be the startup dirs, set them to the 'usual' dir containing the app bundle
859 wxString startupCwd
= wxGetCwd() ;
860 if ( startupCwd
== wxT("/") || startupCwd
.Right(15) == wxT("/Contents/MacOS") )
862 CFURLRef url
= CFBundleCopyBundleURL(CFBundleGetMainBundle() ) ;
863 CFURLRef urlParent
= CFURLCreateCopyDeletingLastPathComponent( kCFAllocatorDefault
, url
) ;
865 CFStringRef path
= CFURLCopyFileSystemPath ( urlParent
, kCFURLPOSIXPathStyle
) ;
866 CFRelease( urlParent
) ;
867 wxString cwd
= wxCFStringRef(path
).AsString(wxLocale::GetSystemEncoding());
868 wxSetWorkingDirectory( cwd
) ;
874 #if wxOSX_USE_COCOA_OR_CARBON
875 bool wxApp::CallOnInit()
877 wxMacAutoreleasePool autoreleasepool
;
882 bool wxApp::OnInitGui()
884 if ( !wxAppBase::OnInitGui() )
893 bool wxApp::ProcessIdle()
895 wxMacAutoreleasePool autoreleasepool
;
896 return wxAppBase::ProcessIdle();
901 wxMacAutoreleasePool pool
;
902 return wxAppBase::OnRun();
906 bool wxApp::DoInitGui()
908 InstallStandardEventHandler( GetApplicationEventTarget() ) ;
911 InstallApplicationEventHandler(
912 GetwxMacAppEventHandlerUPP(),
913 GetEventTypeCount(eventList
), eventList
, wxTheApp
, (EventHandlerRef
*)&(wxTheApp
->m_macEventHandler
));
918 sODocHandler
= NewAEEventHandlerUPP(AEHandleODoc
) ;
919 sGURLHandler
= NewAEEventHandlerUPP(AEHandleGURL
) ;
920 sOAppHandler
= NewAEEventHandlerUPP(AEHandleOApp
) ;
921 sPDocHandler
= NewAEEventHandlerUPP(AEHandlePDoc
) ;
922 sRAppHandler
= NewAEEventHandlerUPP(AEHandleRApp
) ;
923 sQuitHandler
= NewAEEventHandlerUPP(AEHandleQuit
) ;
925 AEInstallEventHandler( kCoreEventClass
, kAEOpenDocuments
,
926 sODocHandler
, 0 , FALSE
) ;
927 AEInstallEventHandler( kInternetEventClass
, kAEGetURL
,
928 sGURLHandler
, 0 , FALSE
) ;
929 AEInstallEventHandler( kCoreEventClass
, kAEOpenApplication
,
930 sOAppHandler
, 0 , FALSE
) ;
931 AEInstallEventHandler( kCoreEventClass
, kAEPrintDocuments
,
932 sPDocHandler
, 0 , FALSE
) ;
933 AEInstallEventHandler( kCoreEventClass
, kAEReopenApplication
,
934 sRAppHandler
, 0 , FALSE
) ;
935 AEInstallEventHandler( kCoreEventClass
, kAEQuitApplication
,
936 sQuitHandler
, 0 , FALSE
) ;
939 if ( !wxMacInitCocoa() )
945 void wxApp::DoCleanUp()
948 RemoveEventHandler( (EventHandlerRef
)(wxTheApp
->m_macEventHandler
) );
952 AERemoveEventHandler( kCoreEventClass
, kAEOpenDocuments
,
953 sODocHandler
, FALSE
) ;
954 AERemoveEventHandler( kInternetEventClass
, kAEGetURL
,
955 sGURLHandler
, FALSE
) ;
956 AERemoveEventHandler( kCoreEventClass
, kAEOpenApplication
,
957 sOAppHandler
, FALSE
) ;
958 AERemoveEventHandler( kCoreEventClass
, kAEPrintDocuments
,
959 sPDocHandler
, FALSE
) ;
960 AERemoveEventHandler( kCoreEventClass
, kAEReopenApplication
,
961 sRAppHandler
, FALSE
) ;
962 AERemoveEventHandler( kCoreEventClass
, kAEQuitApplication
,
963 sQuitHandler
, FALSE
) ;
965 DisposeAEEventHandlerUPP( sODocHandler
) ;
966 DisposeAEEventHandlerUPP( sGURLHandler
) ;
967 DisposeAEEventHandlerUPP( sOAppHandler
) ;
968 DisposeAEEventHandlerUPP( sPDocHandler
) ;
969 DisposeAEEventHandlerUPP( sRAppHandler
) ;
970 DisposeAEEventHandlerUPP( sQuitHandler
) ;
976 void wxApp::CleanUp()
978 wxMacAutoreleasePool autoreleasepool
;
980 wxToolTip::RemoveToolTips() ;
985 wxAppBase::CleanUp();
988 //----------------------------------------------------------------------
989 // misc initialization stuff
990 //----------------------------------------------------------------------
994 m_printMode
= wxPRINT_WINDOWS
;
996 m_macCurrentEvent
= NULL
;
997 m_macCurrentEventHandlerCallRef
= NULL
;
998 m_macPool
= new wxMacAutoreleasePool();
1007 CFMutableArrayRef
GetAutoReleaseArray()
1009 static CFMutableArrayRef array
= 0;
1011 array
= CFArrayCreateMutable(kCFAllocatorDefault
,0,&kCFTypeArrayCallBacks
);
1015 void wxApp::MacAddToAutorelease( void* cfrefobj
)
1017 CFArrayAppendValue( GetAutoReleaseArray(), cfrefobj
);
1020 void wxApp::MacReleaseAutoreleasePool()
1024 m_macPool
= new wxMacAutoreleasePool();
1027 void wxApp::OnIdle(wxIdleEvent
& WXUNUSED(event
))
1029 // If they are pending events, we must process them: pending events are
1030 // either events to the threads other than main or events posted with
1031 // wxPostEvent() functions
1032 #ifndef __WXUNIVERSAL__
1034 if (!wxMenuBar::MacGetInstalledMenuBar() && wxMenuBar::MacGetCommonMenuBar())
1035 wxMenuBar::MacGetCommonMenuBar()->MacInstallMenuBar();
1038 CFArrayRemoveAllValues( GetAutoReleaseArray() );
1041 void wxApp::WakeUpIdle()
1043 wxEventLoopBase
* const loop
= wxEventLoopBase::GetActive();
1049 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
))
1052 GetTopWindow()->Close(true);
1055 // Default behaviour: close the application with prompts. The
1056 // user can veto the close, and therefore the end session.
1057 void wxApp::OnQueryEndSession(wxCloseEvent
& event
)
1059 if ( !wxDialog::OSXHasModalDialogsOpen() )
1063 if (!GetTopWindow()->Close(!event
.CanVeto()))
1073 extern "C" void wxCYield() ;
1080 void wxApp::MacHandleUnhandledEvent( WXEVENTREF
WXUNUSED(evr
) )
1082 // Override to process unhandled events as you please
1085 #if wxOSX_USE_COCOA_OR_CARBON
1087 CGKeyCode
wxCharCodeWXToOSX(wxKeyCode code
)
1093 // Clang warns about switch values not of the same type as (enumerated)
1094 // switch controlling expression. This is generally useful but here we
1095 // really want to be able to use letters and digits without making them
1096 // part of wxKeyCode enum.
1098 #pragma clang diagnostic push
1099 #pragma clang diagnostic ignored "-Wswitch"
1102 case 'a': case 'A': keycode
= kVK_ANSI_A
; break;
1103 case 'b': case 'B': keycode
= kVK_ANSI_B
; break;
1104 case 'c': case 'C': keycode
= kVK_ANSI_C
; break;
1105 case 'd': case 'D': keycode
= kVK_ANSI_D
; break;
1106 case 'e': case 'E': keycode
= kVK_ANSI_E
; break;
1107 case 'f': case 'F': keycode
= kVK_ANSI_F
; break;
1108 case 'g': case 'G': keycode
= kVK_ANSI_G
; break;
1109 case 'h': case 'H': keycode
= kVK_ANSI_H
; break;
1110 case 'i': case 'I': keycode
= kVK_ANSI_I
; break;
1111 case 'j': case 'J': keycode
= kVK_ANSI_J
; break;
1112 case 'k': case 'K': keycode
= kVK_ANSI_K
; break;
1113 case 'l': case 'L': keycode
= kVK_ANSI_L
; break;
1114 case 'm': case 'M': keycode
= kVK_ANSI_M
; break;
1115 case 'n': case 'N': keycode
= kVK_ANSI_N
; break;
1116 case 'o': case 'O': keycode
= kVK_ANSI_O
; break;
1117 case 'p': case 'P': keycode
= kVK_ANSI_P
; break;
1118 case 'q': case 'Q': keycode
= kVK_ANSI_Q
; break;
1119 case 'r': case 'R': keycode
= kVK_ANSI_R
; break;
1120 case 's': case 'S': keycode
= kVK_ANSI_S
; break;
1121 case 't': case 'T': keycode
= kVK_ANSI_T
; break;
1122 case 'u': case 'U': keycode
= kVK_ANSI_U
; break;
1123 case 'v': case 'V': keycode
= kVK_ANSI_V
; break;
1124 case 'w': case 'W': keycode
= kVK_ANSI_W
; break;
1125 case 'x': case 'X': keycode
= kVK_ANSI_X
; break;
1126 case 'y': case 'Y': keycode
= kVK_ANSI_Y
; break;
1127 case 'z': case 'Z': keycode
= kVK_ANSI_Z
; break;
1129 case '0': keycode
= kVK_ANSI_0
; break;
1130 case '1': keycode
= kVK_ANSI_1
; break;
1131 case '2': keycode
= kVK_ANSI_2
; break;
1132 case '3': keycode
= kVK_ANSI_3
; break;
1133 case '4': keycode
= kVK_ANSI_4
; break;
1134 case '5': keycode
= kVK_ANSI_5
; break;
1135 case '6': keycode
= kVK_ANSI_6
; break;
1136 case '7': keycode
= kVK_ANSI_7
; break;
1137 case '8': keycode
= kVK_ANSI_8
; break;
1138 case '9': keycode
= kVK_ANSI_9
; break;
1141 #pragma clang diagnostic pop
1144 case WXK_BACK
: keycode
= kVK_Delete
; break;
1145 case WXK_TAB
: keycode
= kVK_Tab
; break;
1146 case WXK_RETURN
: keycode
= kVK_Return
; break;
1147 case WXK_ESCAPE
: keycode
= kVK_Escape
; break;
1148 case WXK_SPACE
: keycode
= kVK_Space
; break;
1149 case WXK_DELETE
: keycode
= kVK_ForwardDelete
; break;
1151 case WXK_SHIFT
: keycode
= kVK_Shift
; break;
1152 case WXK_ALT
: keycode
= kVK_Option
; break;
1153 case WXK_RAW_CONTROL
: keycode
= kVK_Control
; break;
1154 case WXK_CONTROL
: keycode
= kVK_Command
; break;
1156 case WXK_CAPITAL
: keycode
= kVK_CapsLock
; break;
1157 case WXK_END
: keycode
= kVK_End
; break;
1158 case WXK_HOME
: keycode
= kVK_Home
; break;
1159 case WXK_LEFT
: keycode
= kVK_LeftArrow
; break;
1160 case WXK_UP
: keycode
= kVK_UpArrow
; break;
1161 case WXK_RIGHT
: keycode
= kVK_RightArrow
; break;
1162 case WXK_DOWN
: keycode
= kVK_DownArrow
; break;
1164 case WXK_HELP
: keycode
= kVK_Help
; break;
1167 case WXK_NUMPAD0
: keycode
= kVK_ANSI_Keypad0
; break;
1168 case WXK_NUMPAD1
: keycode
= kVK_ANSI_Keypad1
; break;
1169 case WXK_NUMPAD2
: keycode
= kVK_ANSI_Keypad2
; break;
1170 case WXK_NUMPAD3
: keycode
= kVK_ANSI_Keypad3
; break;
1171 case WXK_NUMPAD4
: keycode
= kVK_ANSI_Keypad4
; break;
1172 case WXK_NUMPAD5
: keycode
= kVK_ANSI_Keypad5
; break;
1173 case WXK_NUMPAD6
: keycode
= kVK_ANSI_Keypad6
; break;
1174 case WXK_NUMPAD7
: keycode
= kVK_ANSI_Keypad7
; break;
1175 case WXK_NUMPAD8
: keycode
= kVK_ANSI_Keypad8
; break;
1176 case WXK_NUMPAD9
: keycode
= kVK_ANSI_Keypad9
; break;
1177 case WXK_F1
: keycode
= kVK_F1
; break;
1178 case WXK_F2
: keycode
= kVK_F2
; break;
1179 case WXK_F3
: keycode
= kVK_F3
; break;
1180 case WXK_F4
: keycode
= kVK_F4
; break;
1181 case WXK_F5
: keycode
= kVK_F5
; break;
1182 case WXK_F6
: keycode
= kVK_F6
; break;
1183 case WXK_F7
: keycode
= kVK_F7
; break;
1184 case WXK_F8
: keycode
= kVK_F8
; break;
1185 case WXK_F9
: keycode
= kVK_F9
; break;
1186 case WXK_F10
: keycode
= kVK_F10
; break;
1187 case WXK_F11
: keycode
= kVK_F11
; break;
1188 case WXK_F12
: keycode
= kVK_F12
; break;
1189 case WXK_F13
: keycode
= kVK_F13
; break;
1190 case WXK_F14
: keycode
= kVK_F14
; break;
1191 case WXK_F15
: keycode
= kVK_F15
; break;
1192 case WXK_F16
: keycode
= kVK_F16
; break;
1193 case WXK_F17
: keycode
= kVK_F17
; break;
1194 case WXK_F18
: keycode
= kVK_F18
; break;
1195 case WXK_F19
: keycode
= kVK_F19
; break;
1196 case WXK_F20
: keycode
= kVK_F20
; break;
1198 case WXK_PAGEUP
: keycode
= kVK_PageUp
; break;
1199 case WXK_PAGEDOWN
: keycode
= kVK_PageDown
; break;
1201 case WXK_NUMPAD_DELETE
: keycode
= kVK_ANSI_KeypadClear
; break;
1202 case WXK_NUMPAD_EQUAL
: keycode
= kVK_ANSI_KeypadEquals
; break;
1203 case WXK_NUMPAD_MULTIPLY
: keycode
= kVK_ANSI_KeypadMultiply
; break;
1204 case WXK_NUMPAD_ADD
: keycode
= kVK_ANSI_KeypadPlus
; break;
1205 case WXK_NUMPAD_SUBTRACT
: keycode
= kVK_ANSI_KeypadMinus
; break;
1206 case WXK_NUMPAD_DECIMAL
: keycode
= kVK_ANSI_KeypadDecimal
; break;
1207 case WXK_NUMPAD_DIVIDE
: keycode
= kVK_ANSI_KeypadDivide
; break;
1210 wxLogDebug( "Unrecognised keycode %d", code
);
1211 keycode
= static_cast<CGKeyCode
>(-1);
1217 long wxMacTranslateKey(unsigned char key
, unsigned char code
)
1222 case kHomeCharCode
:
1226 case kEnterCharCode
:
1227 retval
= WXK_RETURN
;
1233 case kHelpCharCode
:
1237 case kBackspaceCharCode
:
1245 case kPageUpCharCode
:
1246 retval
= WXK_PAGEUP
;
1249 case kPageDownCharCode
:
1250 retval
= WXK_PAGEDOWN
;
1253 case kReturnCharCode
:
1254 retval
= WXK_RETURN
;
1257 case kFunctionKeyCharCode
:
1327 case kEscapeCharCode
:
1328 retval
= WXK_ESCAPE
;
1331 case kLeftArrowCharCode
:
1335 case kRightArrowCharCode
:
1336 retval
= WXK_RIGHT
;
1339 case kUpArrowCharCode
:
1343 case kDownArrowCharCode
:
1347 case kDeleteCharCode
:
1348 retval
= WXK_DELETE
;
1358 int wxMacKeyCodeToModifier(wxKeyCode key
)
1376 case WXK_RAW_CONTROL
:
1385 #if wxOSX_USE_COCOA && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
1387 // defined in utils.mm
1389 #elif wxOSX_USE_COCOA_OR_CARBON
1391 wxMouseState
wxGetMouseState()
1395 wxPoint pt
= wxGetMousePosition();
1399 UInt32 buttons
= GetCurrentButtonState();
1400 ms
.SetLeftDown( (buttons
& 0x01) != 0 );
1401 ms
.SetMiddleDown( (buttons
& 0x04) != 0 );
1402 ms
.SetRightDown( (buttons
& 0x02) != 0 );
1404 UInt32 modifiers
= GetCurrentKeyModifiers();
1405 ms
.SetRawControlDown(modifiers
& controlKey
);
1406 ms
.SetShiftDown(modifiers
& shiftKey
);
1407 ms
.SetAltDown(modifiers
& optionKey
);
1408 ms
.SetControlDown(modifiers
& cmdKey
);
1415 // TODO : once the new key/char handling is tested, move all the code to wxWindow
1417 bool wxApp::MacSendKeyDownEvent( wxWindow
* focus
, long keymessage
, long modifiers
, long when
, wxChar uniChar
)
1422 wxKeyEvent
event(wxEVT_KEY_DOWN
) ;
1423 MacCreateKeyEvent( event
, focus
, keymessage
, modifiers
, when
, uniChar
) ;
1425 return focus
->OSXHandleKeyEvent(event
);
1428 bool wxApp::MacSendKeyUpEvent( wxWindow
* focus
, long keymessage
, long modifiers
, long when
, wxChar uniChar
)
1433 wxKeyEvent
event( wxEVT_KEY_UP
) ;
1434 MacCreateKeyEvent( event
, focus
, keymessage
, modifiers
, when
, uniChar
) ;
1436 return focus
->OSXHandleKeyEvent(event
) ;
1439 bool wxApp::MacSendCharEvent( wxWindow
* focus
, long keymessage
, long modifiers
, long when
, wxChar uniChar
)
1443 wxKeyEvent
event(wxEVT_CHAR
) ;
1444 MacCreateKeyEvent( event
, focus
, keymessage
, modifiers
, when
, uniChar
) ;
1446 bool handled
= false ;
1448 #if wxOSX_USE_CARBON
1449 long keyval
= event
.m_keyCode
;
1452 wxKeyEvent
eventCharHook(wxEVT_CHAR_HOOK
, event
);
1453 handled
= focus
->HandleWindowEvent( eventCharHook
);
1454 if ( handled
&& eventCharHook
.IsNextEventAllowed() )
1460 handled
= focus
->HandleWindowEvent( event
) ;
1463 if ( !handled
&& (keyval
== WXK_TAB
) )
1465 wxWindow
* iter
= focus
->GetParent() ;
1466 while ( iter
&& !handled
)
1468 if ( iter
->HasFlag( wxTAB_TRAVERSAL
) )
1470 wxNavigationKeyEvent new_event
;
1471 new_event
.SetEventObject( focus
);
1472 new_event
.SetDirection( !event
.ShiftDown() );
1473 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1474 new_event
.SetWindowChange( event
.ControlDown() );
1475 new_event
.SetCurrentFocus( focus
);
1476 handled
= focus
->GetParent()->HandleWindowEvent( new_event
);
1477 if ( handled
&& new_event
.GetSkipped() )
1481 iter
= iter
->GetParent() ;
1485 // backdoor handler for default return and command escape
1486 if ( !handled
&& (!focus
->IsKindOf(CLASSINFO(wxControl
) ) || !focus
->AcceptsFocus() ) )
1488 // if window is not having a focus still testing for default enter or cancel
1489 // TODO: add the UMA version for ActiveNonFloatingWindow
1491 wxWindow
* focus
= wxNonOwnedWindow::GetFromWXWindow( (WXWindow
) FrontWindow() ) ;
1494 if ( keyval
== WXK_RETURN
|| keyval
== WXK_NUMPAD_ENTER
)
1496 wxTopLevelWindow
*tlw
= wxDynamicCast(wxGetTopLevelParent(focus
), wxTopLevelWindow
);
1497 if ( tlw
&& tlw
->GetDefaultItem() )
1499 wxButton
*def
= wxDynamicCast(tlw
->GetDefaultItem(), wxButton
);
1500 if ( def
&& def
->IsEnabled() )
1502 wxCommandEvent
event(wxEVT_BUTTON
, def
->GetId() );
1503 event
.SetEventObject(def
);
1504 def
->Command(event
);
1510 else if (keyval
== WXK_ESCAPE
|| (keyval
== '.' && modifiers
& cmdKey
) )
1512 // generate wxID_CANCEL if command-. or <esc> has been pressed (typically in dialogs)
1513 wxCommandEvent
new_event(wxEVT_BUTTON
,wxID_CANCEL
);
1514 new_event
.SetEventObject( focus
);
1515 handled
= focus
->HandleWindowEvent( new_event
);
1524 // This method handles common code for SendKeyDown, SendKeyUp, and SendChar events.
1525 void wxApp::MacCreateKeyEvent( wxKeyEvent
& event
, wxWindow
* focus
, long keymessage
, long modifiers
, long when
, wxChar uniChar
)
1527 #if wxOSX_USE_COCOA_OR_CARBON
1529 short keycode
, keychar
;
1531 keychar
= short(keymessage
& charCodeMask
);
1532 keycode
= short(keymessage
& keyCodeMask
) >> 8 ;
1533 if ( !(event
.GetEventType() == wxEVT_CHAR
) && (modifiers
& (controlKey
| shiftKey
| optionKey
) ) )
1535 // control interferes with some built-in keys like pgdown, return etc. therefore we remove the controlKey modifier
1536 // and look at the character after
1538 // TODO new implementation using TextInputSources
1541 UInt32 keyInfo
= KeyTranslate((Ptr
)GetScriptManagerVariable(smKCHRCache
), ( modifiers
& (~(controlKey
| shiftKey
| optionKey
))) | keycode
, &state
);
1542 keychar
= short(keyInfo
& charCodeMask
);
1546 long keyval
= wxMacTranslateKey(keychar
, keycode
) ;
1547 if ( keyval
== keychar
&& ( event
.GetEventType() == wxEVT_KEY_UP
|| event
.GetEventType() == wxEVT_KEY_DOWN
) )
1548 keyval
= wxToupper( keyval
) ;
1550 // Check for NUMPAD keys. For KEY_UP/DOWN events we need to use the
1551 // WXK_NUMPAD constants, but for the CHAR event we want to use the
1552 // standard ascii values
1553 if ( event
.GetEventType() != wxEVT_CHAR
)
1555 if (keyval
>= '0' && keyval
<= '9' && keycode
>= 82 && keycode
<= 92)
1557 keyval
= (keyval
- '0') + WXK_NUMPAD0
;
1559 else if (keycode
>= 65 && keycode
<= 81)
1564 keyval
= WXK_NUMPAD_ENTER
;
1568 keyval
= WXK_NUMPAD_EQUAL
;
1572 keyval
= WXK_NUMPAD_MULTIPLY
;
1576 keyval
= WXK_NUMPAD_DIVIDE
;
1580 keyval
= WXK_NUMPAD_SUBTRACT
;
1584 keyval
= WXK_NUMPAD_ADD
;
1588 keyval
= WXK_NUMPAD_DECIMAL
;
1596 event
.m_shiftDown
= modifiers
& shiftKey
;
1597 event
.m_rawControlDown
= modifiers
& controlKey
;
1598 event
.m_altDown
= modifiers
& optionKey
;
1599 event
.m_controlDown
= modifiers
& cmdKey
;
1600 event
.m_keyCode
= keyval
;
1602 event
.m_uniChar
= uniChar
;
1605 event
.m_rawCode
= keymessage
;
1606 event
.m_rawFlags
= modifiers
;
1607 event
.SetTimestamp(when
);
1608 event
.SetEventObject(focus
);
1612 wxUnusedVar(keymessage
);
1613 wxUnusedVar(modifiers
);
1615 wxUnusedVar(uniChar
);
1620 void wxApp::MacHideApp()
1622 #if wxOSX_USE_CARBON
1623 wxMacCarbonEvent
event( kEventClassCommand
, kEventCommandProcess
);
1625 memset( &command
, 0 , sizeof(command
) );
1626 command
.commandID
= kHICommandHide
;
1627 event
.SetParameter
<HICommand
>(kEventParamDirectObject
, command
);
1628 SendEventToApplication( event
);