Как я могу заставить мое приложение вести себя так, как будто я меняю приложение - агент (UIElement) во время выполнения с помощью Swift?

Я кодирую приложение для Mac, которое представляет собой NSPopover в правой части строки меню (для Application is agent(UIElement) установлено значение YES). Я разрешаю пользователю отсоединять всплывающее окно, щелкнув и перетащив его вниз, что помещает приложение в окно. Это нормально работает; однако, когда приложение перетаскивается из строки меню и превращается в окно, я хотел бы, чтобы значок моего приложения появлялся в доке, а также отображал меню для конкретных приложений в левой части строки меню, как если бы Application is agent(UIElement) установлен в NO. И наоборот, когда окно закрывается и приложение возвращается во всплывающее окно в строке меню, я бы хотел, чтобы значок моего приложения исчез из док-станции и больше не отображал меню для конкретных приложений в левой части строки меню (Application is agent(UIElement) установить обратно на YES).

Из этого вопроса я понимаю, что изменение Application is agent(UIElement) во время выполнения невозможно. Однако ответ дан в Objective-C, и последняя функция, похоже, обесценилась с OS X 10.9. Как сделать так, чтобы поведение моего приложения было таким же, как при изменении Application is agent(UIElement) во время выполнения с помощью Swift?

Я знаю, что отображение значка приложения / меню строки меню произойдет в windowDidBecomeMain, а скрытие меню значка приложения / строки меню произойдет в windowWillClose.

Спасибо.


person TonyStark4ever    schedule 26.06.2018    source источник


Ответы (2)


Потребовалось много проб и ошибок, но я наконец понял это. Вместо использования Application is agent(UIElement) вы используете NSApp.setActivationPolicy. Теперь это мой код. В делегате приложения:

var isWindow = false

class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {

    let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
    let popover = NSPopover()

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // Insert code here to initialize your application

        NSApp.setActivationPolicy(.accessory)

        if let button = statusItem.button {
            button.image = NSImage(named: "StatusBarImage")
            button.action = #selector(togglePopover(_:))
        }
        popover.contentViewController = MainViewController.loadController()
        popover.delegate = self
        popover.animates = false
        popover.behavior = .transient
    }

    @objc func togglePopover(_ sender: Any?) {
        if popover.isShown == true {
            popover.performClose(sender)
        } else if detachedWindowController.window!.isVisible {
            detachedWindowController.window?.setIsVisible(false)
            isWindow = true
        } else if isWindow == true {
            detachedWindowController.window?.setIsVisible(true)
        } else {
            if let button = statusItem.button {
                popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
            }
        }
    }

    lazy var detachedWindowController: DetachedWindowController = {
        let detachedWindowController = DetachedWindowController(windowNibName: "DetachedWindowController")
        detachedWindowController.contentViewController = MainViewController.loadController()
        return detachedWindowController
    }()

    func popoverShouldDetach(_ popover: NSPopover) -> Bool {
        return true
    }

    func detachableWindow(for popover: NSPopover) -> NSWindow? {
        return detachedWindowController.window
    }
}

В DetachedWindowController:

class DetachedWindowController: NSWindowController, NSWindowDelegate {

    @IBOutlet var detachedWindow: NSWindow!

    override func windowDidLoad() {
        super.windowDidLoad()

        detachedWindow.delegate = self
    }

    func windowWillClose(_ notification: Notification) {
        isWindow = false
        NSApp.setActivationPolicy(.accessory)
    }

    func windowDidBecomeMain(_ notification: Notification) {
        if NSApp.activationPolicy() == .accessory {
            NSApp.setActivationPolicy(.regular)
        }
    }
}
person TonyStark4ever    schedule 27.06.2018

Кроме того, вам может потребоваться сделать что-то вроде ниже, если у вас возникнут проблемы с отображением меню и значка док-станции после переключения на обычный режим. В более старых версиях Mac OS это определенно требовалось.

        // needed to activate menu
    NSArray *dockAppA = [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.loginwindow"];
    NSRunningApplication *dock = [dockAppA firstObject];
    [dock activateWithOptions:NSApplicationActivateIgnoringOtherApps];

    NSArray *dockAppB = [NSRunningApplication runningApplicationsWithBundleIdentifier:@"myAppBundleIdentifier"];
    NSRunningApplication *myApp = [dockAppB firstObject];
    [myApp activateWithOptions:NSApplicationActivateIgnoringOtherApps];
person Marc T.    schedule 28.06.2018