Macos 将LSUIElement转换为前台应用程序
我有一个必须一直运行的应用程序(如果用户同意) 当用户退出应用程序时,我将前台应用程序转换为LSUIElement(应用程序只有一个菜单栏图标、停靠图标和菜单消失) 我在菜单项中有一个选项,可以正常工作并将LSUIElement转换为前台应用程序(我使用函数Macos 将LSUIElement转换为前台应用程序,macos,cocoa,lsuielement,Macos,Cocoa,Lsuielement,我有一个必须一直运行的应用程序(如果用户同意) 当用户退出应用程序时,我将前台应用程序转换为LSUIElement(应用程序只有一个菜单栏图标、停靠图标和菜单消失) 我在菜单项中有一个选项,可以正常工作并将LSUIElement转换为前台应用程序(我使用函数[NSApp setActivationPolicy:NSApp ActivationPolicyRegular]和[NSApp activateIgnoringOtherApps:YES]) 我的问题出现在用户双击应用程序时。我在委托方法应
[NSApp setActivationPolicy:NSApp ActivationPolicyRegular]
和[NSApp activateIgnoringOtherApps:YES]
)
我的问题出现在用户双击应用程序时。我在委托方法应用程序willunhide:(NSNotification*)通知中再次使用[NSApp setActivationPolicy:nsapplication activationpolicy regular]
,除未显示的菜单外,所有功能都很好。如果我转到另一个应用程序,然后我回来,菜单就会出现。我尝试了不同的方法,但没有找到好的
我想知道的是当用户双击应用程序时调用的委托方法,或者是在那一刻调用的NSApplication
中的函数是什么,因为我认为在应用程序中使用设置激活策略:
将隐藏函数太晚了。要将普通应用程序转换为我使用的LSUIElement
ProcessSerialNumber psn = { 0, kCurrentProcess };
TransformProcessType(&psn, kProcessTransformToUIElementApplication);
并将其更改回前台:
ProcessSerialNumber psn = { 0, kCurrentProcess };
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
要将普通应用程序转换为LSUIElement,我使用
ProcessSerialNumber psn = { 0, kCurrentProcess };
TransformProcessType(&psn, kProcessTransformToUIElementApplication);
并将其更改回前台:
ProcessSerialNumber psn = { 0, kCurrentProcess };
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
答案是这样的。在我找到这个问题之前,我已经做了隐藏/显示。这个问题启发了我最终的答案
下面是以下代码的作用:
当应用程序启动时,应用程序将显示在dock中,并显示菜单栏项
当用户单击菜单栏项时,应用程序将隐藏并从dock中删除
当用户再次单击时,应用程序将显示回dock
如果应用程序被隐藏,并且用户通过双击或启动板再次打开应用程序,则应用程序将在dock中再次显示
如果应用程序未被隐藏,但被其他应用程序遮挡,单击菜单栏项目或重新启动它将使应用程序位于最前面
当用户单击窗口上的关闭按钮时,应用程序将从dock中删除
当用户通过cmd+q或从文件菜单退出应用程序时,应用程序退出,菜单栏项也退出
我已经删除了其他不直接相关的代码
您可能会注意到的其他事项:
没有为my Info.plist设置LSUIElement或将其设置为NO。如果要设置为“是”。您需要在序列图像板中设置“不启动视图控制器”,并自己从窗口控制器构造
您还需要通过鼠标左键单击菜单栏项来处理逻辑,因为您从一开始就没有窗口
代码:
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)
}
}
答案是这样的。在我找到这个问题之前,我已经做了隐藏/显示。这个问题启发了我最终的答案
下面是以下代码的作用:
当应用程序启动时,应用程序将显示在dock中,并显示菜单栏项
当用户单击菜单栏项时,应用程序将隐藏并从dock中删除
当用户再次单击时,应用程序将显示回dock
如果应用程序被隐藏,并且用户通过双击或启动板再次打开应用程序,则应用程序将在dock中再次显示
如果应用程序未被隐藏,但被其他应用程序遮挡,单击菜单栏项目或重新启动它将使应用程序位于最前面
当用户单击窗口上的关闭按钮时,应用程序将从dock中删除
当用户通过cmd+q或从文件菜单退出应用程序时,应用程序退出,菜单栏项也退出
我已经删除了其他不直接相关的代码
您可能会注意到的其他事项:
没有为my Info.plist设置LSUIElement或将其设置为NO。如果要设置为“是”。您需要在序列图像板中设置“不启动视图控制器”,并自己从窗口控制器构造
您还需要通过鼠标左键单击菜单栏项来处理逻辑,因为您从一开始就没有窗口
代码:
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)
}
}
从我所知的TransformProcessType
和NSApp setActivationPolicy:
具有相同的效果。从我所知的TransformProcessType
和NSApp setActivationPolicy:
具有相同的效果。您是否尝试过从应用程序Houldhandlereopen:
调用它?是的,我尝试过,但是没有成功。在应用程序隐藏中?我也有同样的问题。您找到解决方案了吗?您是否尝试过从应用程序Houldhandlereopen:
调用它?是的,我尝试过,但没有成功。在applicationDidUnhide中,我也遇到了同样的问题。你找到解决办法了吗?