【问题标题】:Hiding the dock icon without hiding the menu bar隐藏停靠图标而不隐藏菜单栏
【发布时间】:2014-06-12 09:00:20
【问题描述】:

我使用this thread 中的想法来隐藏我的应用程序的停靠图标可选。如果停靠图标毕竟显示,菜单栏也应该显示。只有Jiulong's answer 我无法完成这项工作。菜单栏仍处于隐藏状态。

所以基本上'应用程序是代理'在 InfoPList 中设置为'1',并使用此代码:

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];
}

那么为什么菜单栏不显示,直到我隐藏并重新调整应用程序的焦点?有什么解决办法吗?我看到'Quick Search Box' for mac app 在启动时也不显示菜单栏...


编辑:我联系了 Apple,他们给了我碳和非碳解决方案。给定一个在 Plist 文件中将“Application is Agent”设置为“YES”的新项目,则此代码可以在 AppDelegate 类中使用:

#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

请注意,我也提交了错误报告。

这是非碳解决方案的 Swift 版本:

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)
}

【问题讨论】:

标签: cocoa osx-mavericks nsmenu


【解决方案1】:

首先,您应该在现代代码中使用-[NSApplication setActivationPolicy:] 而不是TransformProcessType()-[NSApplication setPresentationOptions:] 而不是SetSystemUIMode()。如果切换到这些还不足以解决菜单栏不更新的问题,我建议您尝试使用-setPresentationOptions:+[NSMenu setMenuBarVisible:]隐藏菜单栏,然后​​立即撤消该操作。

另外,通过尝试激活 Dock 来放弃该业务。

所以,类似:

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];
}

【讨论】:

  • 当我使用 2 个 +[NSMenu setMenuBarVisible:] 行时,这很有效 - 非常感谢 Ken!
  • 哦,我还有一个问题 - 菜单栏现在显示,但它只在应用程序被隐藏和重新聚焦时响应点击。右侧的按钮(状态栏按钮,例如聚光灯按钮)一直响应。你知道这里可能会发生什么吗?
  • 不是临时的,不。听起来像可可虫。当然,隐藏和显示菜单栏也是如此。
  • 好的,我会从 Apple 获得一些技术支持并报告,谢谢!
  • @BrunoVandekerkhove 你用不负责任的菜单项解决了这个问题吗?我有同样的问题
猜你喜欢
  • 2013-01-04
  • 2012-01-12
  • 1970-01-01
  • 1970-01-01
  • 2018-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多