簡體   English   中英

將 LSUIElement 轉換為前台應用程序

[英]Transform LSUIElement to foreground application

我有一個必須一直運行的應用程序(如果用戶同意這一點)。

當用戶退出應用程序時,我將前台應用程序轉換為 LSUIElement(應用程序只有一個菜單欄圖標,停靠欄圖標和菜單消失)。

我在菜單項中有一個選項可以正常工作並將 LSUIElement 轉換為前台應用程序(我使用功能[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular][NSApp activateIgnoringOtherApps:YES] )。

當用戶雙擊應用程序時出現我的問題。 我再次使用委托方法applicationWillUnhide:(NSNotification *)notification[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular] ,除了沒有出現的菜單外,一切正常。 如果我去另一個應用程序,然后我回來了菜單出現。 我嘗試了不同的方法,但找不到好的方法。

我想知道是在用戶雙擊應用程序時調用的委托方法,或者在那一刻調用的NSApplication函數是什么,因為我認為在applicationWillUnhide函數中使用setActivationPolicy:已晚。

要將普通應用程序轉換為我使用的 LSUIElement

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

並將其改回前台:

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

這是答案。 在找到這個問題之前,我已經完成了隱藏/顯示。 這個問題激發了我的最終答案。

以下代碼的作用如下:

  1. 當應用程序啟動時,應用程序會顯示在 Dock 中並顯示一個菜單欄項。
  2. 當用戶單擊菜單欄項時,應用程序會隱藏並從 Dock 中移除。
  3. 當用戶再次單擊時,應用程序顯示回停靠。
  4. 如果應用程序被隱藏並且用戶通過雙擊或啟動板再次打開該應用程序,該應用程序將再次顯示在 Dock 中。
  5. 如果應用程序沒有被其他應用程序隱藏而是被其他應用程序遮擋,則單擊菜單欄項或重新啟動它會將應用程序置於最前面。
  6. 當用戶單擊窗口上的關閉按鈕時,應用程序從 Dock 中移除。
  7. 當用戶通過 cmd+q 或從文件菜單退出應用程序時,應用程序退出並且菜單欄項也退出。

我已經刪除了其他不直接相關的代碼。

您可能會注意到的其他事項:

  1. 對於我的 Info.plist,LSUIElement 未設置或設置為 NO。 如果你想設置為yes。 您需要在情節提要中設置不啟動視圖控制器並自己從窗口控制器構造。
  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)
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM