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
);
239 fName
= wxMacFSRefToPath( &theRef
) ;
247 // AEOApp calls MacNewFile
249 short wxApp
::MacHandleAEOApp(const WXEVENTREF
WXUNUSED(event
) , WXEVENTREF
WXUNUSED(reply
))
255 // AEQuit attempts to quit the application
257 short wxApp
::MacHandleAEQuit(const WXEVENTREF
WXUNUSED(event
) , WXEVENTREF
WXUNUSED(reply
))
260 wxTheApp
->OnQueryEndSession(event
);
261 if ( !event
.GetVeto() )
264 wxTheApp
->OnEndSession(event
);
269 // AEROApp calls MacReopenApp
271 short wxApp
::MacHandleAERApp(const WXEVENTREF
WXUNUSED(event
) , WXEVENTREF
WXUNUSED(reply
))
280 //----------------------------------------------------------------------
281 // Support Routines linking the Mac...File Calls to the Document Manager
282 //----------------------------------------------------------------------
284 void wxApp
::MacOpenFiles(const wxArrayString
& fileNames
)
287 const size_t fileCount
= fileNames
.GetCount();
288 for (i
= 0; i
< fileCount
; i
++)
290 MacOpenFile(fileNames
[i
]);
294 void wxApp
::MacOpenFile(const wxString
& fileName
)
296 #if wxUSE_DOC_VIEW_ARCHITECTURE
297 wxDocManager
* dm
= wxDocManager
::GetDocumentManager() ;
299 dm
->CreateDocument(fileName
, wxDOC_SILENT
) ;
303 void wxApp
::MacOpenURL(const wxString
& WXUNUSED(url
) )
307 void wxApp
::MacPrintFile(const wxString
& fileName
)
309 #if wxUSE_DOC_VIEW_ARCHITECTURE
311 #if wxUSE_PRINTING_ARCHITECTURE
312 wxDocManager
* dm
= wxDocManager
::GetDocumentManager() ;
315 wxDocument
*doc
= dm
->CreateDocument(fileName
, wxDOC_SILENT
) ;
318 wxView
* view
= doc
->GetFirstView() ;
321 wxPrintout
*printout
= view
->OnCreatePrintout();
325 printer
.Print(view
->GetFrame(), printout
, true);
332 doc
->DeleteAllViews();
333 dm
->RemoveDocument(doc
) ;
344 void wxApp
::MacNewFile()
348 void wxApp
::MacReopenApp()
351 // if there is no open window -> create a new one
352 // if all windows are hidden -> show the first
353 // if some windows are not hidden -> do nothing
355 wxWindowList
::compatibility_iterator node
= wxTopLevelWindows
.GetFirst();
362 wxTopLevelWindow
* firstIconized
= NULL
;
363 wxTopLevelWindow
* firstHidden
= NULL
;
366 wxTopLevelWindow
* win
= (wxTopLevelWindow
*) node
->GetData();
367 if ( !win
->IsShown() )
369 // make sure we don't show 'virtual toplevel windows' like wxTaskBarIconWindow
370 if ( firstHidden
== NULL
&& ( wxDynamicCast( win
, wxFrame
) || wxDynamicCast( win
, wxDialog
) ) )
373 else if ( win
->IsIconized() )
375 if ( firstIconized
== NULL
)
376 firstIconized
= win
;
380 // we do have a visible, non-iconized toplevelwindow -> do nothing
384 node
= node
->GetNext();
388 firstIconized
->Iconize( false ) ;
389 else if ( firstHidden
)
390 firstHidden
->Show( true );
394 //----------------------------------------------------------------------
395 // Macintosh CommandID support - converting between native and wx IDs
396 //----------------------------------------------------------------------
398 // if no native match they just return the passed-in id
408 IdPair gCommandIds
[] =
410 { kHICommandCut
, wxID_CUT
} ,
411 { kHICommandCopy
, wxID_COPY
} ,
412 { kHICommandPaste
, wxID_PASTE
} ,
413 { kHICommandSelectAll
, wxID_SELECTALL
} ,
414 { kHICommandClear
, wxID_CLEAR
} ,
415 { kHICommandUndo
, wxID_UNDO
} ,
416 { kHICommandRedo
, wxID_REDO
} ,
419 int wxMacCommandToId( UInt32 macCommandId
)
423 switch ( macCommandId
)
425 case kHICommandPreferences
:
426 wxid
= wxApp
::s_macPreferencesMenuItemId
;
429 case kHICommandQuit
:
430 wxid
= wxApp
::s_macExitMenuItemId
;
433 case kHICommandAbout
:
434 wxid
= wxApp
::s_macAboutMenuItemId
;
439 for ( size_t i
= 0 ; i
< WXSIZEOF(gCommandIds
) ; ++i
)
441 if ( gCommandIds
[i
].macId
== macCommandId
)
443 wxid
= gCommandIds
[i
].wxId
;
452 wxid
= (int) macCommandId
;
457 UInt32
wxIdToMacCommand( int wxId
)
461 if ( wxId
== wxApp
::s_macPreferencesMenuItemId
)
462 macId
= kHICommandPreferences
;
463 else if (wxId
== wxApp
::s_macExitMenuItemId
)
464 macId
= kHICommandQuit
;
465 else if (wxId
== wxApp
::s_macAboutMenuItemId
)
466 macId
= kHICommandAbout
;
469 for ( size_t i
= 0 ; i
< WXSIZEOF(gCommandIds
) ; ++i
)
471 if ( gCommandIds
[i
].wxId
== wxId
)
473 macId
= gCommandIds
[i
].macId
;
485 wxMenu
* wxFindMenuFromMacCommand( const HICommand
&command
, wxMenuItem
* &item
)
487 wxMenu
* itemMenu
= NULL
;
488 #ifndef __WXUNIVERSAL__
491 // for 'standard' commands which don't have a wx-menu
492 if ( command
.commandID
== kHICommandPreferences
|| command
.commandID
== kHICommandQuit
|| command
.commandID
== kHICommandAbout
)
494 id
= wxMacCommandToId( command
.commandID
) ;
496 wxMenuBar
* mbar
= wxMenuBar
::MacGetInstalledMenuBar() ;
498 item
= mbar
->FindItem( id
, &itemMenu
) ;
500 else if ( command
.commandID
!= 0 && command
.menu
.menuRef
!= 0 && command
.menu
.menuItemIndex
!= 0 )
502 id
= wxMacCommandToId( command
.commandID
) ;
503 // make sure it is one of our own menus, or of the 'synthetic' apple and help menus , otherwise don't touch
504 MenuItemIndex firstUserHelpMenuItem
;
505 static MenuHandle helpMenuHandle
= NULL
;
506 if ( helpMenuHandle
== NULL
)
508 if ( UMAGetHelpMenuDontCreate( &helpMenuHandle
, &firstUserHelpMenuItem
) != noErr
)
509 helpMenuHandle
= NULL
;
512 // is it part of the application or the Help menu, then look for the id directly
513 if ( ( GetMenuHandle( kwxMacAppleMenuId
) != NULL
&& command
.menu
.menuRef
== GetMenuHandle( kwxMacAppleMenuId
) ) ||
514 ( helpMenuHandle
!= NULL
&& command
.menu
.menuRef
== helpMenuHandle
) ||
515 wxMenuBar
::MacGetWindowMenuHMenu() != NULL
&& command
.menu
.menuRef
== wxMenuBar
::MacGetWindowMenuHMenu() )
517 wxMenuBar
* mbar
= wxMenuBar
::MacGetInstalledMenuBar() ;
519 item
= mbar
->FindItem( id
, &itemMenu
) ;
525 GetMenuItemRefCon( command
.menu
.menuRef
, command
.menu
.menuItemIndex
, &refCon
) ;
526 itemMenu
= wxFindMenuFromMacMenu( command
.menu
.menuRef
) ;
527 if ( itemMenu
!= NULL
&& refCon
!= 0)
528 item
= (wxMenuItem
*) refCon
;
537 //----------------------------------------------------------------------
538 // Carbon Event Handler
539 //----------------------------------------------------------------------
543 static const EventTypeSpec eventList
[] =
545 { kEventClassCommand
, kEventProcessCommand
} ,
546 { kEventClassCommand
, kEventCommandUpdateStatus
} ,
548 { kEventClassMenu
, kEventMenuOpening
},
549 { kEventClassMenu
, kEventMenuClosed
},
550 { kEventClassMenu
, kEventMenuTargetItem
},
552 { kEventClassApplication
, kEventAppActivated
} ,
553 { kEventClassApplication
, kEventAppDeactivated
} ,
554 // handling the quit event is not recommended by apple
555 // rather using the quit apple event - which we do
557 { kEventClassAppleEvent
, kEventAppleEvent
} ,
559 { kEventClassMouse
, kEventMouseDown
} ,
560 { kEventClassMouse
, kEventMouseMoved
} ,
561 { kEventClassMouse
, kEventMouseUp
} ,
562 { kEventClassMouse
, kEventMouseDragged
} ,
566 static pascal OSStatus
567 wxMacAppMenuEventHandler( EventHandlerCallRef
WXUNUSED(handler
),
569 void *WXUNUSED(data
) )
571 wxMacCarbonEvent
cEvent( event
) ;
572 MenuRef menuRef
= cEvent
.GetParameter
<MenuRef
>(kEventParamDirectObject
) ;
573 #ifndef __WXUNIVERSAL__
574 wxMenu
* menu
= wxFindMenuFromMacMenu( menuRef
) ;
578 switch (GetEventKind(event
))
580 case kEventMenuOpening
:
581 menu
->HandleMenuOpened();
584 case kEventMenuClosed
:
585 menu
->HandleMenuClosed();
588 case kEventMenuTargetItem
:
592 command
.menu
.menuRef
= menuRef
;
593 command
.menu
.menuItemIndex
= cEvent
.GetParameter
<MenuItemIndex
>(kEventParamMenuItemIndex
,typeMenuItemIndex
) ;
594 command
.commandID
= cEvent
.GetParameter
<MenuCommand
>(kEventParamMenuCommand
,typeMenuCommand
) ;
595 if (command
.commandID
!= 0)
597 wxMenuItem
* item
= NULL
;
598 wxMenu
* itemMenu
= wxFindMenuFromMacCommand( command
, item
) ;
599 if ( itemMenu
&& item
)
600 itemMenu
->HandleMenuItemHighlighted( item
);
606 wxFAIL_MSG(wxT("Unexpected menu event kind"));
612 return eventNotHandledErr
;
615 static pascal OSStatus
616 wxMacAppCommandEventHandler( EventHandlerCallRef
WXUNUSED(handler
) ,
618 void *WXUNUSED(data
) )
620 OSStatus result
= eventNotHandledErr
;
624 wxMacCarbonEvent
cEvent( event
) ;
625 cEvent
.GetParameter
<HICommand
>(kEventParamDirectObject
,typeHICommand
,&command
) ;
627 wxMenuItem
* item
= NULL
;
628 wxMenu
* itemMenu
= wxFindMenuFromMacCommand( command
, item
) ;
632 wxASSERT( itemMenu
!= NULL
) ;
634 switch ( cEvent
.GetKind() )
636 case kEventProcessCommand
:
637 if ( itemMenu
->HandleCommandProcess( item
) )
641 case kEventCommandUpdateStatus
:
642 if ( itemMenu
->HandleCommandUpdateStatus( item
) )
653 static pascal OSStatus
654 wxMacAppApplicationEventHandler( EventHandlerCallRef
WXUNUSED(handler
) ,
656 void *WXUNUSED(data
) )
658 OSStatus result
= eventNotHandledErr
;
659 switch ( GetEventKind( event
) )
661 case kEventAppActivated
:
663 wxTheApp
->SetActive( true , NULL
) ;
667 case kEventAppDeactivated
:
669 wxTheApp
->SetActive( false , NULL
) ;
680 pascal OSStatus
wxMacAppEventHandler( EventHandlerCallRef handler
, EventRef event
, void *data
)
682 EventRef formerEvent
= (EventRef
) wxTheApp
->MacGetCurrentEvent() ;
683 EventHandlerCallRef formerEventHandlerCallRef
= (EventHandlerCallRef
) wxTheApp
->MacGetCurrentEventHandlerCallRef() ;
684 wxTheApp
->MacSetCurrentEvent( event
, handler
) ;
686 OSStatus result
= eventNotHandledErr
;
687 switch ( GetEventClass( event
) )
690 case kEventClassCommand
:
691 result
= wxMacAppCommandEventHandler( handler
, event
, data
) ;
694 case kEventClassApplication
:
695 result
= wxMacAppApplicationEventHandler( handler
, event
, data
) ;
698 case kEventClassMenu
:
699 result
= wxMacAppMenuEventHandler( handler
, event
, data
) ;
702 case kEventClassMouse
:
704 wxMacCarbonEvent
cEvent( event
) ;
707 Point screenMouseLocation
= cEvent
.GetParameter
<Point
>(kEventParamMouseLocation
) ;
708 ::FindWindow(screenMouseLocation
, &window
);
709 // only send this event in case it had not already been sent to a tlw, as we get
710 // double events otherwise (in case event.skip) was called
711 if ( window
== NULL
)
712 result
= wxMacTopLevelMouseEventHandler( handler
, event
, NULL
) ;
716 case kEventClassAppleEvent
:
717 result
= AEProcessEvent(event
);
724 wxTheApp
->MacSetCurrentEvent( formerEvent
, formerEventHandlerCallRef
) ;
729 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacAppEventHandler
)
732 #if wxDEBUG_LEVEL && wxOSX_USE_COCOA_OR_CARBON
735 wxMacAssertOutputHandler(OSType
WXUNUSED(componentSignature
),
736 UInt32
WXUNUSED(options
),
737 const char *assertionString
,
738 const char *exceptionLabelString
,
739 const char *errorString
,
740 const char *fileName
,
743 ConstStr255Param
WXUNUSED(outputMsg
))
745 // flow into assert handling
746 wxString fileNameStr
;
747 wxString assertionStr
;
748 wxString exceptionStr
;
752 fileNameStr
= wxString(fileName
, wxConvLocal
);
753 assertionStr
= wxString(assertionString
, wxConvLocal
);
754 exceptionStr
= wxString((exceptionLabelString
!=0) ? exceptionLabelString
: "", wxConvLocal
) ;
755 errorStr
= wxString((errorString
!=0) ? errorString
: "", wxConvLocal
) ;
757 fileNameStr
= fileName
;
758 assertionStr
= assertionString
;
759 exceptionStr
= (exceptionLabelString
!=0) ? exceptionLabelString
: "" ;
760 errorStr
= (errorString
!=0) ? errorString
: "" ;
765 wxLogDebug( wxT("AssertMacros: %s %s %s file: %s, line: %ld (value %p)\n"),
766 assertionStr
.c_str() ,
767 exceptionStr
.c_str() ,
769 fileNameStr
.c_str(), lineNumber
,
773 wxOnAssert(fileNameStr
, lineNumber
, assertionStr
,
774 wxString
::Format( wxT("%s %s value (%p)") , exceptionStr
, errorStr
, value
) ) ;
778 #endif // wxDEBUG_LEVEL
780 bool wxApp
::Initialize(int& argc
, wxChar
**argv
)
784 #if wxDEBUG_LEVEL && wxOSX_USE_COCOA_OR_CARBON
785 InstallDebugAssertOutputHandler( NewDebugAssertOutputHandlerUPP( wxMacAssertOutputHandler
) );
788 // Mac OS X passes a process serial number command line argument when
789 // the application is launched from the Finder. This argument must be
790 // removed from the command line arguments before being handled by the
791 // application (otherwise applications would need to handle it)
794 static const wxChar
*ARG_PSN
= wxT("-psn_");
795 if ( wxStrncmp(argv
[1], ARG_PSN
, wxStrlen(ARG_PSN
)) == 0 )
797 // remove this argument
799 memmove(argv
+ 1, argv
+ 2, argc
* sizeof(wxChar
*));
804 Cocoa supports -Key value options which set the user defaults key "Key"
805 to the value "value" Some of them are very handy for debugging like
806 -NSShowAllViews YES. Cocoa picks these up from the real argv so
807 our removal of them from the wx copy of it does not affect Cocoa's
810 We basically just assume that any "-NS" option and its following
811 argument needs to be removed from argv. We hope that user code does
812 not expect to see -NS options and indeed it's probably a safe bet
813 since most user code accepting options is probably using the
814 double-dash GNU-style syntax.
816 for(int i
=1; i
< argc
; ++i
)
818 static const wxChar
*ARG_NS
= wxT("-NS");
819 if( wxStrncmp(argv
[i
], ARG_NS
, wxStrlen(ARG_NS
)) == 0 )
821 // Only eat this option if it has an argument
824 memmove(argv
+ i
, argv
+ i
+ 2, (argc
-i
-1)*sizeof(wxChar
*));
826 // drop back one position so the next run through the loop
827 // reprocesses the argument at our current index.
833 if ( !wxAppBase
::Initialize(argc
, argv
) )
837 wxFont
::SetDefaultEncoding(wxLocale
::GetSystemEncoding());
840 // these might be the startup dirs, set them to the 'usual' dir containing the app bundle
841 wxString startupCwd
= wxGetCwd() ;
842 if ( startupCwd
== wxT("/") || startupCwd
.Right(15) == wxT("/Contents/MacOS") )
844 CFURLRef url
= CFBundleCopyBundleURL(CFBundleGetMainBundle() ) ;
845 CFURLRef urlParent
= CFURLCreateCopyDeletingLastPathComponent( kCFAllocatorDefault
, url
) ;
847 CFStringRef path
= CFURLCopyFileSystemPath ( urlParent
, kCFURLPOSIXPathStyle
) ;
848 CFRelease( urlParent
) ;
849 wxString cwd
= wxCFStringRef(path
).AsString(wxLocale
::GetSystemEncoding());
850 wxSetWorkingDirectory( cwd
) ;
856 #if wxOSX_USE_COCOA_OR_CARBON
857 bool wxApp
::CallOnInit()
859 wxMacAutoreleasePool autoreleasepool
;
864 bool wxApp
::OnInitGui()
866 if ( !wxAppBase
::OnInitGui() )
875 bool wxApp
::ProcessIdle()
877 wxMacAutoreleasePool autoreleasepool
;
878 return wxAppBase
::ProcessIdle();
883 wxMacAutoreleasePool pool
;
884 return wxAppBase
::OnRun();
888 bool wxApp
::DoInitGui()
890 InstallStandardEventHandler( GetApplicationEventTarget() ) ;
893 InstallApplicationEventHandler(
894 GetwxMacAppEventHandlerUPP(),
895 GetEventTypeCount(eventList
), eventList
, wxTheApp
, (EventHandlerRef
*)&(wxTheApp
->m_macEventHandler
));
900 sODocHandler
= NewAEEventHandlerUPP(AEHandleODoc
) ;
901 sGURLHandler
= NewAEEventHandlerUPP(AEHandleGURL
) ;
902 sOAppHandler
= NewAEEventHandlerUPP(AEHandleOApp
) ;
903 sPDocHandler
= NewAEEventHandlerUPP(AEHandlePDoc
) ;
904 sRAppHandler
= NewAEEventHandlerUPP(AEHandleRApp
) ;
905 sQuitHandler
= NewAEEventHandlerUPP(AEHandleQuit
) ;
907 AEInstallEventHandler( kCoreEventClass
, kAEOpenDocuments
,
908 sODocHandler
, 0 , FALSE
) ;
909 AEInstallEventHandler( kInternetEventClass
, kAEGetURL
,
910 sGURLHandler
, 0 , FALSE
) ;
911 AEInstallEventHandler( kCoreEventClass
, kAEOpenApplication
,
912 sOAppHandler
, 0 , FALSE
) ;
913 AEInstallEventHandler( kCoreEventClass
, kAEPrintDocuments
,
914 sPDocHandler
, 0 , FALSE
) ;
915 AEInstallEventHandler( kCoreEventClass
, kAEReopenApplication
,
916 sRAppHandler
, 0 , FALSE
) ;
917 AEInstallEventHandler( kCoreEventClass
, kAEQuitApplication
,
918 sQuitHandler
, 0 , FALSE
) ;
921 if ( !wxMacInitCocoa() )
927 void wxApp
::DoCleanUp()
930 RemoveEventHandler( (EventHandlerRef
)(wxTheApp
->m_macEventHandler
) );
934 AERemoveEventHandler( kCoreEventClass
, kAEOpenDocuments
,
935 sODocHandler
, FALSE
) ;
936 AERemoveEventHandler( kInternetEventClass
, kAEGetURL
,
937 sGURLHandler
, FALSE
) ;
938 AERemoveEventHandler( kCoreEventClass
, kAEOpenApplication
,
939 sOAppHandler
, FALSE
) ;
940 AERemoveEventHandler( kCoreEventClass
, kAEPrintDocuments
,
941 sPDocHandler
, FALSE
) ;
942 AERemoveEventHandler( kCoreEventClass
, kAEReopenApplication
,
943 sRAppHandler
, FALSE
) ;
944 AERemoveEventHandler( kCoreEventClass
, kAEQuitApplication
,
945 sQuitHandler
, FALSE
) ;
947 DisposeAEEventHandlerUPP( sODocHandler
) ;
948 DisposeAEEventHandlerUPP( sGURLHandler
) ;
949 DisposeAEEventHandlerUPP( sOAppHandler
) ;
950 DisposeAEEventHandlerUPP( sPDocHandler
) ;
951 DisposeAEEventHandlerUPP( sRAppHandler
) ;
952 DisposeAEEventHandlerUPP( sQuitHandler
) ;
958 void wxApp
::CleanUp()
960 wxMacAutoreleasePool autoreleasepool
;
962 wxToolTip
::RemoveToolTips() ;
967 wxAppBase
::CleanUp();
970 //----------------------------------------------------------------------
971 // misc initialization stuff
972 //----------------------------------------------------------------------
976 m_printMode
= wxPRINT_WINDOWS
;
978 m_macCurrentEvent
= NULL
;
979 m_macCurrentEventHandlerCallRef
= NULL
;
980 m_macPool
= new wxMacAutoreleasePool();
989 CFMutableArrayRef
GetAutoReleaseArray()
991 static CFMutableArrayRef array
= 0;
993 array
= CFArrayCreateMutable(kCFAllocatorDefault
,0,&kCFTypeArrayCallBacks
);
997 void wxApp
::MacAddToAutorelease( void* cfrefobj
)
999 CFArrayAppendValue( GetAutoReleaseArray(), cfrefobj
);
1002 void wxApp
::MacReleaseAutoreleasePool()
1006 m_macPool
= new wxMacAutoreleasePool();
1009 void wxApp
::OnIdle(wxIdleEvent
& WXUNUSED(event
))
1011 // If they are pending events, we must process them: pending events are
1012 // either events to the threads other than main or events posted with
1013 // wxPostEvent() functions
1014 #ifndef __WXUNIVERSAL__
1016 if (!wxMenuBar
::MacGetInstalledMenuBar() && wxMenuBar
::MacGetCommonMenuBar())
1017 wxMenuBar
::MacGetCommonMenuBar()->MacInstallMenuBar();
1020 CFArrayRemoveAllValues( GetAutoReleaseArray() );
1023 void wxApp
::WakeUpIdle()
1025 wxEventLoopBase
* const loop
= wxEventLoopBase
::GetActive();
1031 void wxApp
::OnEndSession(wxCloseEvent
& WXUNUSED(event
))
1034 GetTopWindow()->Close(true);
1037 // Default behaviour: close the application with prompts. The
1038 // user can veto the close, and therefore the end session.
1039 void wxApp
::OnQueryEndSession(wxCloseEvent
& event
)
1041 if ( !wxDialog
::OSXHasModalDialogsOpen() )
1045 if (!GetTopWindow()->Close(!event
.CanVeto()))
1055 extern "C" void wxCYield() ;
1062 void wxApp
::MacHandleUnhandledEvent( WXEVENTREF
WXUNUSED(evr
) )
1064 // Override to process unhandled events as you please
1067 #if wxOSX_USE_COCOA_OR_CARBON
1069 CGKeyCode
wxCharCodeWXToOSX(wxKeyCode code
)
1075 // Clang warns about switch values not of the same type as (enumerated)
1076 // switch controlling expression. This is generally useful but here we
1077 // really want to be able to use letters and digits without making them
1078 // part of wxKeyCode enum.
1080 #pragma clang diagnostic push
1081 #pragma clang diagnostic ignored "-Wswitch"
1084 case 'a': case 'A': keycode
= kVK_ANSI_A
; break;
1085 case 'b': case 'B': keycode
= kVK_ANSI_B
; break;
1086 case 'c': case 'C': keycode
= kVK_ANSI_C
; break;
1087 case 'd': case 'D': keycode
= kVK_ANSI_D
; break;
1088 case 'e': case 'E': keycode
= kVK_ANSI_E
; break;
1089 case 'f': case 'F': keycode
= kVK_ANSI_F
; break;
1090 case 'g': case 'G': keycode
= kVK_ANSI_G
; break;
1091 case 'h': case 'H': keycode
= kVK_ANSI_H
; break;
1092 case 'i': case 'I': keycode
= kVK_ANSI_I
; break;
1093 case 'j': case 'J': keycode
= kVK_ANSI_J
; break;
1094 case 'k': case 'K': keycode
= kVK_ANSI_K
; break;
1095 case 'l': case 'L': keycode
= kVK_ANSI_L
; break;
1096 case 'm': case 'M': keycode
= kVK_ANSI_M
; break;
1097 case 'n': case 'N': keycode
= kVK_ANSI_N
; break;
1098 case 'o': case 'O': keycode
= kVK_ANSI_O
; break;
1099 case 'p': case 'P': keycode
= kVK_ANSI_P
; break;
1100 case 'q': case 'Q': keycode
= kVK_ANSI_Q
; break;
1101 case 'r': case 'R': keycode
= kVK_ANSI_R
; break;
1102 case 's': case 'S': keycode
= kVK_ANSI_S
; break;
1103 case 't': case 'T': keycode
= kVK_ANSI_T
; break;
1104 case 'u': case 'U': keycode
= kVK_ANSI_U
; break;
1105 case 'v': case 'V': keycode
= kVK_ANSI_V
; break;
1106 case 'w': case 'W': keycode
= kVK_ANSI_W
; break;
1107 case 'x': case 'X': keycode
= kVK_ANSI_X
; break;
1108 case 'y': case 'Y': keycode
= kVK_ANSI_Y
; break;
1109 case 'z': case 'Z': keycode
= kVK_ANSI_Z
; break;
1111 case '0': keycode
= kVK_ANSI_0
; break;
1112 case '1': keycode
= kVK_ANSI_1
; break;
1113 case '2': keycode
= kVK_ANSI_2
; break;
1114 case '3': keycode
= kVK_ANSI_3
; break;
1115 case '4': keycode
= kVK_ANSI_4
; break;
1116 case '5': keycode
= kVK_ANSI_5
; break;
1117 case '6': keycode
= kVK_ANSI_6
; break;
1118 case '7': keycode
= kVK_ANSI_7
; break;
1119 case '8': keycode
= kVK_ANSI_8
; break;
1120 case '9': keycode
= kVK_ANSI_9
; break;
1123 #pragma clang diagnostic pop
1126 case WXK_BACK
: keycode
= kVK_Delete
; break;
1127 case WXK_TAB
: keycode
= kVK_Tab
; break;
1128 case WXK_RETURN
: keycode
= kVK_Return
; break;
1129 case WXK_ESCAPE
: keycode
= kVK_Escape
; break;
1130 case WXK_SPACE
: keycode
= kVK_Space
; break;
1131 case WXK_DELETE
: keycode
= kVK_Delete
; break;
1133 case WXK_SHIFT
: keycode
= kVK_Shift
; break;
1134 case WXK_ALT
: keycode
= kVK_Option
; break;
1135 case WXK_RAW_CONTROL
: keycode
= kVK_Control
; break;
1136 case WXK_CONTROL
: keycode
= kVK_Command
; break;
1138 case WXK_CAPITAL
: keycode
= kVK_CapsLock
; break;
1139 case WXK_END
: keycode
= kVK_End
; break;
1140 case WXK_HOME
: keycode
= kVK_Home
; break;
1141 case WXK_LEFT
: keycode
= kVK_LeftArrow
; break;
1142 case WXK_UP
: keycode
= kVK_UpArrow
; break;
1143 case WXK_RIGHT
: keycode
= kVK_RightArrow
; break;
1144 case WXK_DOWN
: keycode
= kVK_DownArrow
; break;
1146 case WXK_HELP
: keycode
= kVK_Help
; break;
1149 case WXK_NUMPAD0
: keycode
= kVK_ANSI_Keypad0
; break;
1150 case WXK_NUMPAD1
: keycode
= kVK_ANSI_Keypad1
; break;
1151 case WXK_NUMPAD2
: keycode
= kVK_ANSI_Keypad2
; break;
1152 case WXK_NUMPAD3
: keycode
= kVK_ANSI_Keypad3
; break;
1153 case WXK_NUMPAD4
: keycode
= kVK_ANSI_Keypad4
; break;
1154 case WXK_NUMPAD5
: keycode
= kVK_ANSI_Keypad5
; break;
1155 case WXK_NUMPAD6
: keycode
= kVK_ANSI_Keypad6
; break;
1156 case WXK_NUMPAD7
: keycode
= kVK_ANSI_Keypad7
; break;
1157 case WXK_NUMPAD8
: keycode
= kVK_ANSI_Keypad8
; break;
1158 case WXK_NUMPAD9
: keycode
= kVK_ANSI_Keypad9
; break;
1159 case WXK_F1
: keycode
= kVK_F1
; break;
1160 case WXK_F2
: keycode
= kVK_F2
; break;
1161 case WXK_F3
: keycode
= kVK_F3
; break;
1162 case WXK_F4
: keycode
= kVK_F4
; break;
1163 case WXK_F5
: keycode
= kVK_F5
; break;
1164 case WXK_F6
: keycode
= kVK_F6
; break;
1165 case WXK_F7
: keycode
= kVK_F7
; break;
1166 case WXK_F8
: keycode
= kVK_F8
; break;
1167 case WXK_F9
: keycode
= kVK_F9
; break;
1168 case WXK_F10
: keycode
= kVK_F10
; break;
1169 case WXK_F11
: keycode
= kVK_F11
; break;
1170 case WXK_F12
: keycode
= kVK_F12
; break;
1171 case WXK_F13
: keycode
= kVK_F13
; break;
1172 case WXK_F14
: keycode
= kVK_F14
; break;
1173 case WXK_F15
: keycode
= kVK_F15
; break;
1174 case WXK_F16
: keycode
= kVK_F16
; break;
1175 case WXK_F17
: keycode
= kVK_F17
; break;
1176 case WXK_F18
: keycode
= kVK_F18
; break;
1177 case WXK_F19
: keycode
= kVK_F19
; break;
1178 case WXK_F20
: keycode
= kVK_F20
; break;
1180 case WXK_PAGEUP
: keycode
= kVK_PageUp
; break;
1181 case WXK_PAGEDOWN
: keycode
= kVK_PageDown
; break;
1183 case WXK_NUMPAD_DELETE
: keycode
= kVK_ANSI_KeypadClear
; break;
1184 case WXK_NUMPAD_EQUAL
: keycode
= kVK_ANSI_KeypadEquals
; break;
1185 case WXK_NUMPAD_MULTIPLY
: keycode
= kVK_ANSI_KeypadMultiply
; break;
1186 case WXK_NUMPAD_ADD
: keycode
= kVK_ANSI_KeypadPlus
; break;
1187 case WXK_NUMPAD_SUBTRACT
: keycode
= kVK_ANSI_KeypadMinus
; break;
1188 case WXK_NUMPAD_DECIMAL
: keycode
= kVK_ANSI_KeypadDecimal
; break;
1189 case WXK_NUMPAD_DIVIDE
: keycode
= kVK_ANSI_KeypadDivide
; break;
1192 wxLogDebug( "Unrecognised keycode %d", code
);
1193 keycode
= static_cast<CGKeyCode
>(-1);
1199 long wxMacTranslateKey(unsigned char key
, unsigned char code
)
1204 case kHomeCharCode
:
1208 case kEnterCharCode
:
1209 retval
= WXK_RETURN
;
1215 case kHelpCharCode
:
1219 case kBackspaceCharCode
:
1227 case kPageUpCharCode
:
1228 retval
= WXK_PAGEUP
;
1231 case kPageDownCharCode
:
1232 retval
= WXK_PAGEDOWN
;
1235 case kReturnCharCode
:
1236 retval
= WXK_RETURN
;
1239 case kFunctionKeyCharCode
:
1309 case kEscapeCharCode
:
1310 retval
= WXK_ESCAPE
;
1313 case kLeftArrowCharCode
:
1317 case kRightArrowCharCode
:
1318 retval
= WXK_RIGHT
;
1321 case kUpArrowCharCode
:
1325 case kDownArrowCharCode
:
1329 case kDeleteCharCode
:
1330 retval
= WXK_DELETE
;
1340 int wxMacKeyCodeToModifier(wxKeyCode key
)
1358 case WXK_RAW_CONTROL
:
1367 #if wxOSX_USE_COCOA && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
1369 // defined in utils.mm
1371 #elif wxOSX_USE_COCOA_OR_CARBON
1373 wxMouseState
wxGetMouseState()
1377 wxPoint pt
= wxGetMousePosition();
1381 UInt32 buttons
= GetCurrentButtonState();
1382 ms
.SetLeftDown( (buttons
& 0x01) != 0 );
1383 ms
.SetMiddleDown( (buttons
& 0x04) != 0 );
1384 ms
.SetRightDown( (buttons
& 0x02) != 0 );
1386 UInt32 modifiers
= GetCurrentKeyModifiers();
1387 ms
.SetRawControlDown(modifiers
& controlKey
);
1388 ms
.SetShiftDown(modifiers
& shiftKey
);
1389 ms
.SetAltDown(modifiers
& optionKey
);
1390 ms
.SetControlDown(modifiers
& cmdKey
);
1397 // TODO : once the new key/char handling is tested, move all the code to wxWindow
1399 bool wxApp
::MacSendKeyDownEvent( wxWindow
* focus
, long keymessage
, long modifiers
, long when
, short wherex
, short wherey
, wxChar uniChar
)
1404 wxKeyEvent
event(wxEVT_KEY_DOWN
) ;
1405 MacCreateKeyEvent( event
, focus
, keymessage
, modifiers
, when
, wherex
, wherey
, uniChar
) ;
1407 return focus
->OSXHandleKeyEvent(event
);
1410 bool wxApp
::MacSendKeyUpEvent( wxWindow
* focus
, long keymessage
, long modifiers
, long when
, short wherex
, short wherey
, wxChar uniChar
)
1415 wxKeyEvent
event( wxEVT_KEY_UP
) ;
1416 MacCreateKeyEvent( event
, focus
, keymessage
, modifiers
, when
, wherex
, wherey
, uniChar
) ;
1418 return focus
->OSXHandleKeyEvent(event
) ;
1421 bool wxApp
::MacSendCharEvent( wxWindow
* focus
, long keymessage
, long modifiers
, long when
, short wherex
, short wherey
, wxChar uniChar
)
1425 wxKeyEvent
event(wxEVT_CHAR
) ;
1426 MacCreateKeyEvent( event
, focus
, keymessage
, modifiers
, when
, wherex
, wherey
, uniChar
) ;
1428 bool handled
= false ;
1430 #if wxOSX_USE_CARBON
1431 long keyval
= event
.m_keyCode
;
1434 wxKeyEvent
eventCharHook(wxEVT_CHAR_HOOK
, event
);
1435 handled
= focus
->HandleWindowEvent( eventCharHook
);
1436 if ( handled
&& eventCharHook
.IsNextEventAllowed() )
1442 handled
= focus
->HandleWindowEvent( event
) ;
1445 if ( !handled
&& (keyval
== WXK_TAB
) )
1447 wxWindow
* iter
= focus
->GetParent() ;
1448 while ( iter
&& !handled
)
1450 if ( iter
->HasFlag( wxTAB_TRAVERSAL
) )
1452 wxNavigationKeyEvent new_event
;
1453 new_event
.SetEventObject( focus
);
1454 new_event
.SetDirection( !event
.ShiftDown() );
1455 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1456 new_event
.SetWindowChange( event
.ControlDown() );
1457 new_event
.SetCurrentFocus( focus
);
1458 handled
= focus
->GetParent()->HandleWindowEvent( new_event
);
1459 if ( handled
&& new_event
.GetSkipped() )
1463 iter
= iter
->GetParent() ;
1467 // backdoor handler for default return and command escape
1468 if ( !handled
&& (!focus
->IsKindOf(CLASSINFO(wxControl
) ) || !focus
->AcceptsFocus() ) )
1470 // if window is not having a focus still testing for default enter or cancel
1471 // TODO: add the UMA version for ActiveNonFloatingWindow
1473 wxWindow
* focus
= wxNonOwnedWindow
::GetFromWXWindow( (WXWindow
) FrontWindow() ) ;
1476 if ( keyval
== WXK_RETURN
|| keyval
== WXK_NUMPAD_ENTER
)
1478 wxTopLevelWindow
*tlw
= wxDynamicCast(wxGetTopLevelParent(focus
), wxTopLevelWindow
);
1479 if ( tlw
&& tlw
->GetDefaultItem() )
1481 wxButton
*def
= wxDynamicCast(tlw
->GetDefaultItem(), wxButton
);
1482 if ( def
&& def
->IsEnabled() )
1484 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, def
->GetId() );
1485 event
.SetEventObject(def
);
1486 def
->Command(event
);
1492 else if (keyval
== WXK_ESCAPE
|| (keyval
== '.' && modifiers
& cmdKey
) )
1494 // generate wxID_CANCEL if command-. or <esc> has been pressed (typically in dialogs)
1495 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1496 new_event
.SetEventObject( focus
);
1497 handled
= focus
->HandleWindowEvent( new_event
);
1506 // This method handles common code for SendKeyDown, SendKeyUp, and SendChar events.
1507 void wxApp
::MacCreateKeyEvent( wxKeyEvent
& event
, wxWindow
* focus
, long keymessage
, long modifiers
, long when
, short wherex
, short wherey
, wxChar uniChar
)
1509 #if wxOSX_USE_COCOA_OR_CARBON
1511 short keycode
, keychar
;
1513 keychar
= short(keymessage
& charCodeMask
);
1514 keycode
= short(keymessage
& keyCodeMask
) >> 8 ;
1515 if ( !(event
.GetEventType() == wxEVT_CHAR
) && (modifiers
& (controlKey
| shiftKey
| optionKey
) ) )
1517 // control interferes with some built-in keys like pgdown, return etc. therefore we remove the controlKey modifier
1518 // and look at the character after
1520 // TODO new implementation using TextInputSources
1523 UInt32 keyInfo
= KeyTranslate((Ptr
)GetScriptManagerVariable(smKCHRCache
), ( modifiers
& (~(controlKey
| shiftKey
| optionKey
))) | keycode
, &state
);
1524 keychar
= short(keyInfo
& charCodeMask
);
1528 long keyval
= wxMacTranslateKey(keychar
, keycode
) ;
1529 if ( keyval
== keychar
&& ( event
.GetEventType() == wxEVT_KEY_UP
|| event
.GetEventType() == wxEVT_KEY_DOWN
) )
1530 keyval
= wxToupper( keyval
) ;
1532 // Check for NUMPAD keys. For KEY_UP/DOWN events we need to use the
1533 // WXK_NUMPAD constants, but for the CHAR event we want to use the
1534 // standard ascii values
1535 if ( event
.GetEventType() != wxEVT_CHAR
)
1537 if (keyval
>= '0' && keyval
<= '9' && keycode
>= 82 && keycode
<= 92)
1539 keyval
= (keyval
- '0') + WXK_NUMPAD0
;
1541 else if (keycode
>= 65 && keycode
<= 81)
1546 keyval
= WXK_NUMPAD_ENTER
;
1550 keyval
= WXK_NUMPAD_EQUAL
;
1554 keyval
= WXK_NUMPAD_MULTIPLY
;
1558 keyval
= WXK_NUMPAD_DIVIDE
;
1562 keyval
= WXK_NUMPAD_SUBTRACT
;
1566 keyval
= WXK_NUMPAD_ADD
;
1570 keyval
= WXK_NUMPAD_DECIMAL
;
1578 event
.m_shiftDown
= modifiers
& shiftKey
;
1579 event
.m_rawControlDown
= modifiers
& controlKey
;
1580 event
.m_altDown
= modifiers
& optionKey
;
1581 event
.m_controlDown
= modifiers
& cmdKey
;
1582 event
.m_keyCode
= keyval
;
1584 event
.m_uniChar
= uniChar
;
1587 event
.m_rawCode
= keymessage
;
1588 event
.m_rawFlags
= modifiers
;
1591 event
.SetTimestamp(when
);
1592 event
.SetEventObject(focus
);
1596 wxUnusedVar(keymessage
);
1597 wxUnusedVar(modifiers
);
1599 wxUnusedVar(wherex
);
1600 wxUnusedVar(wherey
);
1601 wxUnusedVar(uniChar
);
1606 void wxApp
::MacHideApp()
1608 #if wxOSX_USE_CARBON
1609 wxMacCarbonEvent
event( kEventClassCommand
, kEventCommandProcess
);
1611 memset( &command
, 0 , sizeof(command
) );
1612 command
.commandID
= kHICommandHide
;
1613 event
.SetParameter
<HICommand
>(kEventParamDirectObject
, command
);
1614 SendEventToApplication( event
);