I use the ideas in this thread to hide the dock icon of my app optionally. If the dock icon is shown after all, the menu bar should be shown too. Only with Jiulong's answer I haven't been able to make this work. The menu bar is still hidden.
So basically 'Application is agent' is set to '1' in the InfoPList, and this code is used :
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"LaunchAsAgentApp"]) {
ProcessSerialNumber psn = { 0, kCurrentProcess };
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
SetSystemUIMode(kUIModeNormal, 0);
[[NSWorkspace sharedWorkspace] launchAppWithBundleIdentifier:@"com.apple.dock" options:NSWorkspaceLaunchDefault additionalEventParamDescriptor:nil launchIdentifier:nil];
[[NSApplication sharedApplication] activateIgnoringOtherApps:TRUE];
}
So why doesn't the menu bar show up, until I hide and refocus the app? Is there any fix for this? I saw that the 'Quick Search Box' for mac app doesn't show the menu bar upon launching either...
EDIT : I contacted Apple, and they gave me a carbon and a non-carbon solution. Given a new project with 'Application is Agent' set to 'YES' in the Plist file, then this code could be used in the AppDelegate
class :
#define USE_CARBON 0
//
// Note: NSLogDebug is defined in the projects pre-compiled (.pch) file
//
@implementation AppDelegate
{
BOOL show_icon;
}
// Application will finish launching
- (void)applicationWillFinishLaunching:(NSNotification *)notification {
NSLogDebug();
NSURL *receiptUrl = [[NSBundle mainBundle] appStoreReceiptURL];
if (![[NSFileManager defaultManager] fileExistsAtPath:[receiptUrl path]]) {
// exit(173);
}
#if 1
show_icon = YES;
#else
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *hasDockIconDefaultsKey = @"Has Dock Icon?";
// note: toggles value on each run (normally set from user pref pannel)
show_icon = [userDefaults boolForKey:hasDockIconDefaultsKey];
[userDefaults setBool:!show_icon forKey:hasDockIconDefaultsKey];
#endif // if 1
if (show_icon) {
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
[NSApp setPresentationOptions:NSApplicationPresentationDefault];
[NSMenu setMenuBarVisible:NO];
[NSMenu setMenuBarVisible:YES];
}
[NSApp activateIgnoringOtherApps:YES];
} // applicationWillFinishLaunching
// Application did finish launching
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSLogDebug();
// Insert code here to initialize your application
if (show_icon) {
#if USE_CARBON
ProcessSerialNumber psn = {0, kCurrentProcess};
OSStatus returnCode = TransformProcessType(&psn, kProcessTransformToForegroundApplication);
if (noErr != returnCode) {
NSLog(@"TransformProcessType error: %d (0x%0X)", returnCode, returnCode);
}
ProcessSerialNumber psnx = {0, kNoProcess};
GetNextProcess(&psnx);
SetFrontProcess(&psnx);
#else // if 0
NSWorkspace *sharedWorkspace = [NSWorkspace sharedWorkspace];
NSRunningApplication * menuBarOwningApplication = [sharedWorkspace menuBarOwningApplication];
(void) [menuBarOwningApplication activateWithOptions:NSApplicationActivateIgnoringOtherApps];
#endif
[self performSelector:@selector(setFront) withObject:nil afterDelay:0.];
}
} // applicationDidFinishLaunching
// Close app when main window is closed
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
return (YES);
}
- (void)setFront;
{
#if USE_CARBON
ProcessSerialNumber psn = {0, kCurrentProcess};
SetFrontProcess(&psn);
#else // if USE_CARBON
[[NSRunningApplication currentApplication] activateWithOptions:NSApplicationActivateIgnoringOtherApps];
#endif // USE_CARBON
}
@end
Note that I filed a bug report too.
Here's a Swift version of the non-carbon solution :
func applicationWillFinishLaunching(_ notification: Notification) {
if showIcon {
NSApp.setActivationPolicy(.regular)
NSApp.presentationOptions = []
NSMenu.setMenuBarVisible(false)
NSMenu.setMenuBarVisible(true)
}
NSApp.activate(ignoringOtherApps: true)
}
func applicationDidFinishLaunching(_ aNotification: Notification) {
NSApplication.shared.activate(ignoringOtherApps: true)
if showIcon {
let workspace = NSWorkspace.shared
let application = workspace.menuBarOwningApplication
application?.activate(options: .activateIgnoringOtherApps)
self.perform(#selector(activate), with: nil, afterDelay: 0.0)
}
}
@objc private func activate() {
NSRunningApplication.current.activate(options: .activateIgnoringOtherApps)
}
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…