From 93160b96670ab08b983ce666c62885b6bca7723b Mon Sep 17 00:00:00 2001 From: Dan Gudmundsson Date: Fri, 5 Feb 2021 10:54:43 +0100 Subject: [PATCH] Make non-bundled apps work on recent macOS versions Currently non-bundled apps don't work on Catalina and Big Sur and what's worse is that old the code makes it impossible to make it work in user code. Remove the old workaround, and replace it with an alternative one, which seems to work under all supported macOS versions and is also used by Tcl/Tk. Closes https://github.com/wxWidgets/wxWidgets/pull/2216 --- src/osx/cocoa/utils.mm | 87 +++++++++--------------------------------- 1 file changed, 19 insertions(+), 68 deletions(-) diff --git a/src/osx/cocoa/utils.mm b/src/osx/cocoa/utils.mm index ed2dfaff89..792971c816 100644 --- a/src/osx/cocoa/utils.mm +++ b/src/osx/cocoa/utils.mm @@ -72,6 +72,25 @@ void wxBell() wxUnusedVar(notification); [NSApp stop:nil]; wxTheApp->OSXOnDidFinishLaunching(); + + // We need to activate the application manually if it's not part of a + // bundle, otherwise not only it won't come to the foreground, but under + // recent macOS versions (10.15+), its menus simply won't work at all. + // + // Note that we have not one but two methods to opt out from this behaviour + // for compatibility. + if ( !wxApp::sm_isEmbedded && wxTheApp && wxTheApp->OSXIsGUIApplication() ) + { + CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle() ) ; + CFStringRef path = CFURLCopyFileSystemPath ( url , kCFURLPOSIXPathStyle ) ; + CFRelease( url ) ; + wxString app = wxCFStringRef(path).AsString(wxLocale::GetSystemEncoding()); + if ( !app.EndsWith(".app") ) + { + [NSApp setActivationPolicy: NSApplicationActivationPolicyRegular]; + [NSApp activateIgnoringOtherApps: YES]; + } + } } - (void)application:(NSApplication *)sender openFiles:(NSArray *)fileNames @@ -287,50 +306,6 @@ void wxBell() } @end - -// more on bringing non-bundled apps to the foreground -// https://devforums.apple.com/thread/203753 - -#if 0 - -// one possible solution is also quoted here -// from https://stackoverflow.com/questions/7596643/when-calling-transformprocesstype-the-app-menu-doesnt-show-up - -@interface wxNSNonBundledAppHelper : NSObject { - -} - -+ (void)transformToForegroundApplication; - -@end - -@implementation wxNSNonBundledAppHelper - -+ (void)transformToForegroundApplication { - for (NSRunningApplication * app in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.finder"]) { - [app activateWithOptions:NSApplicationActivateIgnoringOtherApps]; - break; - } - [self performSelector:@selector(transformStep2) withObject:nil afterDelay:0.1]; -} - -+ (void)transformStep2 -{ - ProcessSerialNumber psn = { 0, kCurrentProcess }; - (void) TransformProcessType(&psn, kProcessTransformToForegroundApplication); - - [self performSelector:@selector(transformStep3) withObject:nil afterDelay:0.1]; -} - -+ (void)transformStep3 -{ - [[NSRunningApplication currentApplication] activateWithOptions:NSApplicationActivateIgnoringOtherApps]; -} - -@end - -#endif - // here we subclass NSApplication, for the purpose of being able to override sendEvent. @interface wxNSApplication : NSApplication { @@ -353,16 +328,6 @@ void wxBell() return self; } -- (void) transformToForegroundApplication { - ProcessSerialNumber psn = { 0, kCurrentProcess }; - TransformProcessType(&psn, kProcessTransformToForegroundApplication); - - [[NSRunningApplication currentApplication] activateWithOptions: - (NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)]; -} - - - /* This is needed because otherwise we don't receive any key-up events for command-key combinations (an AppKit bug, apparently) */ - (void)sendEvent:(NSEvent *)anEvent @@ -391,20 +356,6 @@ bool wxApp::DoInitGui() if (!sm_isEmbedded) { [wxNSApplication sharedApplication]; - - if ( OSXIsGUIApplication() ) - { - CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle() ) ; - CFStringRef path = CFURLCopyFileSystemPath ( url , kCFURLPOSIXPathStyle ) ; - CFRelease( url ) ; - wxString app = wxCFStringRef(path).AsString(wxLocale::GetSystemEncoding()); - - // workaround is only needed for non-bundled apps - if ( !app.EndsWith(".app") ) - { - [(wxNSApplication*) [wxNSApplication sharedApplication] transformToForegroundApplication]; - } - } appcontroller = OSXCreateAppController(); [[NSApplication sharedApplication] setDelegate:(id )appcontroller];