Cocoa - 以编程方式转到前台/后台 [英] Cocoa - go to foreground/background programmatically

查看:19
本文介绍了Cocoa - 以编程方式转到前台/后台的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

 -(void)stepIntoForeground{if (NSAppKitVersionNumber 

问题是:

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

有什么方法可以完全禁用菜单或使其始终显示在前台?提前致谢.

解决方案

我们就是这样做的.(适用于 10.7+)

  1. 不要在应用程序列表中使用 LSBackgroundOnly NOR 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(或 10.9 以下的操作系统上的 NSApplicationActivationPolicyProhibited)之间进行更改将杀死您的状态栏菜单元素的工具提示,工具提示将最初显示,但不会在第二次调用 NSApplicationActivationPolicyAccessory -> NSApplicationActivedPolicy 后显示>

    变通方法:我们找不到解决此问题的变通方法,因此向 Apple 报告了错误.

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

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

  • 从 NSApplicationActivationPolicyAccessory 更改为 NSApplicationActivationPolicyRegular 在某些操作系统版本上是虚假的

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

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

I have an application with LSUIElement set to 1. It has a built-in editor, so I want the application to appear in Cmd+Tab cycle when the editor is open.

    -(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 {
                //..
            }
        }
    }

The problems are:

  • there's also a Dock icon (not a big deal);
  • there's also Menu, that is not a big deal too, but they appear not always.

Is there any way to disable menu at all or to make it appear always in foreground? Thanks in advance.

解决方案

This is how we do it. (Works 10.7+)

  1. DO NOT USE LSBackgroundOnly NOR LSUIElement in the app plist
  2. Add and init your menu and NSStatusBar menu
  3. After app initialized but not yet shown any window take a place where you might want to show the first window if any. We use applicationDidFinishLaunching.

    • If you do not want to show any window yet after app initialized use

      [NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];

      on 10.9 you can use at last the otherwise much correct

      [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];

    • If you should open any window after app init finished than simply show the main window

  4. Maintain your list of windows

  5. If last window closed, call

    [NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];

    on 10.9 you can use at last the otherwise much correct

    [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];

  6. When your first window shown next time, call

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

This should do the trick, if at least one app window is visible you will have menu, dock icon with state signaled, and cmd+tab element with your app, if last app window closed only your NSStatusBar element stays.

Known issues:

  • The first step is important because without that if a system modal dialog suspends your startup (f.e. your app is downloaded from the net and become quarantined a confirmation dialog might appear at first startup depending on your security settings) your menubar might not be owned by your app after your first app window shown.

    Workaround: Starting as normal app (step 1.) would solve this problem, but will cause another small one, your app icon might appear for a moment in the dock at startup even if you would like to startup without any window shown. (but we can deal with this, not owning the menubar was a bigger problem for us, so we chose this instead)

  • Changing between NSApplicationActivationPolicyRegular and NSApplicationActivationPolicyAccessory (or NSApplicationActivationPolicyProhibited on OSes bellow 10.9) will kill your tooltip of status bar menu element, the tooltip will be shown initially but will not ever after the second call of NSApplicationActivationPolicyAccessory -> NSApplicationActivationPolicyProhibited

    Workaround: We could not find a working workaround for this and reported to Apple as a bug.

  • Changing from NSApplicationActivationPolicyRegular to NSApplicationActivationPolicyAccessory has other problems on some OS versions like there might be no more mouse events in visible app windows sometimes

    Workaround: switch first to NSApplicationActivationPolicyProhibited (take care this leads to unwanted app messages, like NSApplicationWillResignActiveNotification, NSWindowDidResignMainNotification, etc. !)

  • Changing from NSApplicationActivationPolicyAccessory to NSApplicationActivationPolicyRegular is bogus as on some OS versions

    • the app main menu is frozen till the first app front status change
    • the app activated after this policy not always get placed front in the application order

    Workaround: switch first to NSApplicationActivationPolicyProhibited, take care the final switch to the desired NSApplicationActivationPolicyRegular should be made delayed, use f.e. dispatch_async or similar

这篇关于Cocoa - 以编程方式转到前台/后台的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆