Cocoa - 以编程方式转到前台/后台

pAK*_*-76 4 macos xcode cocoa

我有一个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 {
                //..
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

问题是:

  • 还有一个Dock图标(不是什么大问题);
  • 还有菜单,这也不是什么大问题,但它们似乎并不总是如此.

有没有办法完全禁用菜单或使其始终显示在前台?提前致谢.

Hof*_*ofi 16

这是我们的做法.(Works 10.7+)

  1. 不要在app plist中使用LSBackgroundOnly NOR LSUIElement
  2. 添加并初始化菜单和NSStatusBar菜单
  3. 应用程序初始化但尚未显示任何窗口后,您可能需要显示第一个窗口(如果有).我们使用applicationDidFinishLaunching.

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

      [NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];

      在10.9你最后可以使用其他正确的

      [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];

    • 如果你应该在app init完成后打开任何窗口而不是简单地显示主窗口

  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)将解决此问题,但会导致另一个小问题,即使您希望在没有显示任何窗口的情况下启动,您的应用程序图标也可能在启动时在停靠栏中显示片刻.(但我们可以解决这个问题,不拥有菜单栏对我们来说是一个更大的问题,所以我们选择了这个)

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

    解决方法:我们无法为此找到可行的解决方法,并向Apple报告为错误.

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

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

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

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

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