8

我有一个 LSUIElement 设置为 1 的应用程序。它有一个内置的编辑器,所以我希望应用程序在编辑器打开时出现在 Cmd+Tab 循环中。

    -(void)stepIntoForeground
    {
        if (NSAppKitVersionNumber < NSAppKitVersionNumber10_7) return;
        if (counter == 0) {
            ProcessSerialNumber psn = {0, kCurrentProcess};
            OSStatus osstatus = TransformProcessType(&psn, kProcessTransformToForegroundApplication);
            if (osstatus == 0) {
                ++counter;
            } else {
                //...
            }
        }
    }
    -(void)stepIntoBackground
    {
        if (NSAppKitVersionNumber < NSAppKitVersionNumber10_7) return;
        if (counter == 0) return;

        if (counter == 1) {
            ProcessSerialNumber psn = {0, kCurrentProcess};
            OSStatus osstatus = TransformProcessType(&psn, kProcessTransformToUIElementApplication);
            if (osstatus == 0) {
                --counter;
            } else {
                //..
            }
        }
    }

问题是:

  • 还有一个 Dock 图标(没什么大不了的);
  • 还有菜单,这也没什么大不了的,但它们并不总是出现。

有没有办法完全禁用菜单或让它总是出现在前台?提前致谢。

4

3 回答 3

21

这是我们的做法。(作品 10.7+)

  1. 不要在应用程序列表中使用 LSBackgroundOnly 或 LSUIElement
  2. 添加并初始化你的菜单和 NSStatusBar 菜单
  3. 在应用程序初始化但尚未显示任何窗口后,您可能希望在其中显示第一个窗口(如果有)。我们使用 applicationDidFinishLaunching。

    • 如果您不想在应用程序初始化使用后显示任何窗口

      [NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];

      在 10.9 上,您终于可以使用其他非常正确的

      [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];

    • 如果您应该在应用程序初始化完成后打开任何窗口,而不是简单地显示主窗口

  4. 维护您的窗口列表

  5. 如果最后一个窗口关闭,请致电

    [NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];

    在 10.9 上,您终于可以使用其他非常正确的

    [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];

  6. 下次显示您的第一个窗口时,请致电

    [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
    [NSApp activateIgnoringOtherApps:YES];
    [[self window] makeKeyAndOrderFront:nil];

这应该可以解决问题,如果至少一个应用程序窗口可见,您将拥有菜单、带有状态信号的停靠图标以及 cmd+tab 元素与您的应用程序,如果最后一个应用程序窗口关闭,则只有您的 NSStatusBar 元素保留。

已知的问题:

  • 第一步很重要,因为如果没有它,如果系统模式对话框暂停您的启动(您的应用程序是从网上下载并被隔离,则在首次启动时可能会出现一个确认对话框,具体取决于您的安全设置)您的菜单栏可能不属于您的显示第一个应用程序窗口后的应用程序。

    解决方法:作为普通应用程序启动(步骤 1.)可以解决此问题,但会导致另一个小问题,即使您想在不显示任何窗口的情况下启动,您的应用程序图标也可能会在启动时出现在 Dock 中片刻。(但我们可以解决这个问题,不拥有菜单栏对我们来说是一个更大的问题,所以我们选择了这个)

  • 在 NSApplicationActivationPolicyRegular 和 NSApplicationActivationPolicyAccessory (或 NSApplicationActivationPolicyProhibited 在 10.9 以下的操作系统上)之间进行更改将杀死您的状态栏菜单元素的工具提示,该工具提示将最初显示,但不会在第二次调用 NSApplicationActivationPolicyAccessory -> NSApplicationActivationPolicyProhibited 之后显示

    解决方法:我们找不到解决此问题的解决方法,并将其作为错误报告给 Apple。

  • 从 NSApplicationActivationPolicyRegular 更改为 NSApplicationActivationPolicyAccessory 在某些操作系统版本上还有其他问题,例如有时可见的应用程序窗口中可能不再有鼠标事件

    解决方法:首先切换到 NSApplicationActivationPolicyProhibited(注意这会导致不需要的应用程序消息,例如 NSApplicationWillResignActiveNotification、NSWindowDidResignMainNotification 等!)

  • 从 NSApplicationActivationPolicyAccessory 更改为 NSApplicationActivationPolicyRegular 与某些操作系统版本一样是虚假的

    • 应用程序主菜单被冻结,直到第一个应用程序前端状态更改
    • 在此政策之后激活的应用程序并不总是排在应用程序顺序的前面

    解决方法:首先切换到 NSApplicationActivationPolicyProhibited,注意最终切换到所需的 NSApplicationActivationPolicyRegular 应该延迟,使用 fe dispatch_async 或类似的

于 2012-10-19T19:23:34.820 回答
2

使用 swift 4,在 applicationDidfinishLaunching(_:Notification)

NSApplication.shared.setActivationPolicy(.regular)

为我做了诀窍,但我只是想让键盘焦点到我以编程方式创建的窗口。谢谢。

于 2017-12-06T22:00:05.260 回答
1

您可以在您的 plist 文件中将 App“Application is agent (UIElement)”设置为 YES。

编辑:

我认为有一些技巧可以做到这一点。但这真的不是它的本意。Cmd+tab 用于将应用程序置于前台,但如果您没有菜单栏,则对用户来说它看起来不像前台。

我宁愿制作一个菜单栏来访问该应用程序。

于 2012-10-18T07:12:31.930 回答