将LSUIElement转换为前台应用程序

时间:2012-10-15 13:58:34

标签: macos cocoa lsuielement

我有一个必须一直运行的应用程序(如果用户同意这个)。

当用户退出应用程序时,我将前台应用程序转换为LSUIElement(应用程序只有一个菜单栏图标,停靠栏图标和菜单消失)。

我在菜单项中有一个选项可以正常运行并将LSUIElement转换为前台应用程序(我使用函数[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular][NSApp activateIgnoringOtherApps:YES])。

用户双击应用时出现我的问题。我再次使用委托方法[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]中的applicationWillUnhide:(NSNotification *)notification,除了没有出现的菜单外,一切正常。如果我去另一个应用程序,然后我回来了菜单出现。我尝试了不同的方法,但我找不到好的方法。

我想知道的是当用户双击应用程序时调用的委托方法,或者当时调用NSApplication的函数是什么,因为我认为使用{{1} } setActivationPolicy:函数是迟到的。

2 个答案:

答案 0 :(得分:1)

要将普通应用程序转换为LSUIElement,请使用

ProcessSerialNumber psn = { 0, kCurrentProcess };
TransformProcessType(&psn, kProcessTransformToUIElementApplication);

并将其更改回前景:

ProcessSerialNumber psn = { 0, kCurrentProcess };
TransformProcessType(&psn, kProcessTransformToForegroundApplication);

答案 1 :(得分:0)

这是答案。在找到这个问题之前,我已经完成了隐藏/显示。这个问题启发了我最终的答案。

这是以下代码的作用:

  1. 应用启动时,应用会显示在停靠栏中,并显示菜单栏项。
  2. 当用户单击菜单栏项时,应用会隐藏并从停靠中移除。
  3. 当用户再次单击时,该应用将显示回停靠状态。
  4. 如果该应用处于隐藏状态,并且用户通过双击或启动板再次打开该应用,则该应用会再次显示在扩展坞中。
  5. 如果该应用未隐藏但被其他应用遮挡,则单击菜单栏项或重新启动它会将其置于最前面。
  6. 当用户单击窗口上的关闭按钮时,该应用将从扩展坞中删除。
  7. 当用户通过cmd + q或从文件菜单中退出应用程序时,该应用程序将退出,并且菜单栏项也将退出。

我删除了其他不直接相关的代码。

您可能会注意到的其他事项:

    没有为我的Info.plist设置
  1. LSUIElement或将其设置为NO。如果要设置为是。您无需在情节提要中设置任何初始化视图控制器,而可以从窗口控制器自己构造。
  2. 您还将通过单击鼠标左键来处理逻辑,因为从一开始就没有窗口。

代码:

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
    private let statusItem = NSStatusBar.system.statusItem(withLength:NSStatusItem.squareLength)
    weak private var window:NSWindow? = nil

    func applicationDidFinishLaunching(_ aNotification: Notification) {        
        setupMenubarTray()

        self.window = NSApp.orderedWindows.first

        NotificationCenter.default.addObserver(self, selector: #selector(windowWillClose(_:)), name: NSWindow.willCloseNotification, object: self.window!)
    }

    func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
        if !window!.isVisible {
            activeApp()
            return false
        }

        return true
    }
}

extension AppDelegate {
    @objc func windowWillClose(_ noti:Notification) {
        removeFromDock()
    }

    private func showInDock() {
        NSApp.setActivationPolicy(.regular)
    }

    private func removeFromDock() {
        NSApp.setActivationPolicy(.accessory)
    }
}

// MARK: - setup menubar button
extension AppDelegate {
    private func setupMenubarTray() {
        guard let button = statusItem.button else {
            fatalError()
        }

        setTrayIcon(for:button)
        button.action = #selector(mouseLeftButtonClicked)
    }

    private func setTrayIcon(for button:NSStatusBarButton) {
        let useMonochromeIcon = UserDefaults.standard.bool(forKey: DefaultsKey.useMonochromeIcon.key)
        button.image = NSImage(imageLiteralResourceName: useMonochromeIcon ? "MonochromeIcon" : "TrayIcon")
    }

    @objc private func mouseLeftButtonClicked() {
        if NSApp.isHidden || !window!.isKeyWindow {
            self.activeApp()
        } else {
            self.hide()
        }
    }

    private func activeApp() {
        showInDock()
        window?.makeKeyAndOrderFront(nil)
        NSApp.activate(ignoringOtherApps: true)

        checker.sendNotification()
    }

    private func hide() {
        removeFromDock()
        NSApp.hide(nil)
    }
}