简体   繁体   中英

Why doesn't activate(ignoringOtherApps:) enable the menu bar?

There are a number of tutorials/questions/answers on StackOverflow about being able to launch a GUI application with a simple program, without creating an app bundle and Info.plist. The majority of these use the Objective-C method [NSApp activateIgnoringOtherApps:true] to bring the application to the foreground, along with [NSWindow makeKeyAndOrderFront:] to bring the windows to the foreground.

The problem seems to be that on version 10.15 of macOS, the menu bar is not enabled until the first time you switch away from the app and back again. I've managed to reduce the problem to the following few lines of Swift:

// Run this, click on the Apple logo in the top left
// You cannot get the Apple system menu until you tab
// to another application and back again
import AppKit

var app = NSApplication.shared
app.setActivationPolicy(.regular)
app.activate(ignoringOtherApps: true)
app.run()

When this is run as a command line application, the Apple menu at the top left cannot be selected. If you switch from that app and then back again, it works.

Adding windows and doing the makeKeyAndOrderFront has no effect; you can add them in, and the window does get the focus - but the menu bar isn't enabled until you switch away/back.

What's also confusing is that if you make a directory Example.app/Contents/MacOS and then copy the above binary in, and use open to launch the app, then the menu does work right from first launch. The difference appears to be the way in which the app is launched from the Terminal vs LaunchServices.

Is there any way to fix this minimal example so that the menu works right away?

For ease of reproduction, I have pushed the code to https://github.com/alblue/Bugger and there's a makefile that will do the build and run it from the command line ( make run ) and via an app bundle ( make app ).

I managed to discover a simple fix for this; move the activate into the applicationDidFinishLaunching delegate:

import AppKit

@objc
class Delegate: NSObject, NSApplicationDelegate {
        func applicationDidFinishLaunching(_ notification: Notification) {
                app.setActivationPolicy(.regular)
                app.activate(ignoringOtherApps: true)
        }
}

var app = NSApplication.shared
let delegate = Delegate()
app.delegate = delegate
app.run()

After this change, the menu is clickable.

For 10.15, the call to setActivationPolicy also needs to be in the applicationDidFinishLaunching callback.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM