Hiding the dock icon without hiding the menu bar
Asked Answered
J

1

3

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)
}
Judd answered 26/4, 2014 at 16:22 Comment(1)
See my solution in similar SO question: https://mcmap.net/q/235042/-how-to-hide-the-dock-icon. Tested and works on macOS 11.Departed
M
1

First, you should use -[NSApplication setActivationPolicy:] rather than TransformProcessType() and -[NSApplication setPresentationOptions:] rather than SetSystemUIMode() in modern code. If switching to those is not enough to fix the problem with the menu bar not updating, I recommend that you try using -setPresentationOptions: or +[NSMenu setMenuBarVisible:] to hide the menu bar and then immediately reverse that operation.

Also, drop that business with trying to activate the Dock.

So, something like:

if (![[NSUserDefaults standardUserDefaults] boolForKey:@"LaunchAsAgentApp"]) {
    [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
    [NSApp setPresentationOptions:NSApplicationPresentationDefault]; // probably not necessary since it's the default
    [NSMenu setMenuBarVisible:NO]; // these two lines may not be necessary, either; using -setActivationPolicy: instead of TransformProcessType() may be enough
    [NSMenu setMenuBarVisible:YES];
}
Mantel answered 26/4, 2014 at 17:32 Comment(5)
That works when I use the 2 +[NSMenu setMenuBarVisible:] lines - thanks a whole lot Ken!Judd
Oh, and I still have one issue with this - the menu bar now shows, but it only responds to clicks when the app is hidden and refocused. The button on the right (the status bar buttons, such as the spotlight button) do respond all the time. Do you know what might be happening here?Judd
Not off-hand, no. Sounds like a Cocoa bug. Of course, so does the need to hide and show the menu bar.Mantel
Okay I'll get some technical support from Apple and report back, thanks!Judd
@BrunoVandekerkhove Have you resolved that issue with non-responsible menu items? I stocked with the same issueNematode

© 2022 - 2024 — McMap. All rights reserved.