Menu Only 算是 Cocoa App 中最常见的一项,它使得 App 不占用你的 Dock 栏,在多 workspace 的时候也不影响正常使用,随时都可以在屏幕的菜单栏中执行快捷操作。尤其是针对一些需要便捷性要求比较高的应用来讲,Menu bar 的功能必不可少。本文就简单介绍一下关于 Menu App 中关键的几个开发步骤。
/*
* TransformProcessType()
*
* Summary:
* Changes the 'type' of the process specified in the psn parameter.
* The type is specified in the transformState parameter.
*
* Discussion:
* Given a psn for an application, this call transforms that
* application into the given type. Foreground applications have a
* menu bar and appear in the Dock. Background applications do not
* appear in the Dock, do not have a menu bar ( and should not have
* windows or other user interface ). UIElement applications do not
* have a menu bar, do not appear in the dock, but may in limited
* circumstances present windows and user interface. If a foreground
* application is frontmost when transformed into a background
* application, it is first hidden and another application is made
* frontmost. A UIElement or background-only application which is
* transformed into a foreground application is not brought to the
* front (use SetFrontProcess() after the transform if this is
* required) nor will it be shown if it is hidden ( even if hidden
* automatically by being transformed into a background-only
* application ), so the caller should use ShowHideProcess() to show
* the application after it is transformed into a foreground
* application. Applications can only transform themselves; this
* call cannot change the type of another application.
extern OSStatus
TransformProcessType(
const ProcessSerialNumber * psn,
ProcessApplicationTransformState transformState) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER;
上方的注释写的非常清楚,我们日常的 Cocoa Application 主要包含三种类型:
Foreground applications, 拥有一个 menu bar,并且会在 Dock 上出现;
Background applications,Dock 上不存在并且没有 menu bar,并且不应该存在任何 UI 交互界面(建议)
functoggleDock(show: Bool) -> Bool {
// ProcessApplicationTransformStatelet transformState = show ?
// show to foreground application // or not show to background application ProcessApplicationTransformState(kProcessTransformToForegroundApplication)
: ProcessApplicationTransformState(kProcessTransformToUIElementApplication)
// transform current application type.var psn = ProcessSerialNumber(highLongOfPSN: 0, lowLongOfPSN: UInt32(kCurrentProcess))
return TransformProcessType(&psn, transformState) == 0}
这里实际上还有一种方案也是很多开发者选用的方案,通过指定 App 的ActivationPolicy来实现的,核心的 API 是 setActivationPolicy:
1
2
3
4
/* Attempts to modify the application's activation policy. In OS X 10.9, any policy may be set; prior to 10.9, the activation policy may be changed to NSApplicationActivationPolicyProhibited or NSApplicationActivationPolicyRegular, but may not be changed to NSApplicationActivationPolicyAccessory. This returns YES if setting the activation policy is successful, and NO if not.
*/ @available(OSX 10.6, *)
open funcsetActivationPolicy(_ activationPolicy: NSApplication.ActivationPolicy) -> Bool
/* The following activation policies control whether and how an application may be activated. They are determined by the Info.plist. */publicenumActivationPolicy : Int {
/* The application is an ordinary app that appears in the Dock and may have a user interface. This is the default for bundled apps, unless overridden in the Info.plist. */case regular
/* The application does not appear in the Dock and does not have a menu bar, but it may be activated programmatically or by clicking on one of its windows. This corresponds to LSUIElement=1 in the Info.plist. */case accessory
/* The application does not appear in the Dock and may not create windows or be activated. This corresponds to LSBackgroundOnly=1 in the Info.plist. This is also the default for unbundled executables that do not have Info.plists. */case prohibited
}
实际上不同的 activation policy 和 Info.plist 文件中写入不同元素的效果是对等的。regular policy 的应用就是常规引用的形式,会出现在 Dock 上,accessory policy 的应用就是指定当前应用为 agent,不再 Dock 出现。
显示或者隐藏 Dock 的功能就可以通过切换当前的激活策略(activation policy来实现,如下代码所示: