OSX Lion bug:以编程方式启动屏幕保护程序时,桌面可能无法使用(OSX Lion bug: Desktop may become unusable when launching screensaver programmatically)

要在OS X Lion上启动屏幕保护程序,我使用系统范围的键盘快捷键,使用简单的AppleScript立即启动屏幕保护程序:

tell application "ScreenSaverEngine" to launch

虽然这在大多数情况下都能很好地工作,但是在调用脚本时正好移动鼠标时我会遇到一个奇怪的问题。 然后,加载ScreenSaverEngine.app并锁定桌面,但ScreenSaverEngine UI不会显示。 相反,桌面仍然可见,但无法将焦点设置在其他应用程序或UI控件上; 桌面会话基本上是锁定的。

“解锁”桌面的唯一方法是强制将焦点设置在Activity Monitor应用程序上(通过按住Ctrl键单击其停靠图标并选择“显示所有Windows”),然后终止ScreenSaverEngine进程。

通过从终端启动ScreenSaverEngine,可以轻松地重现相同的行为:

/System/Library/Frameworks/ScreenSaver.framework/Resources/ScreenSaverEngine.app/Contents/MacOS/ScreenSaverEngine

并在按下Enter键的同时主动移动鼠标光标。

有没有人知道一种可用于以编程方式启动屏幕保护程序的方法,并且不会遇到此问题?

注意:我知道还有其他锁定屏幕的选项(快速用户切换,Keychain锁定和Hot Corners),但我对这些解决方案不感兴趣,我需要一种以编程方式启动屏幕保护程序的方法。

To start the screensaver on OS X Lion, I use a system-wide keyboard shortcut that immediately starts the screensaver, using a simple applescript:

tell application "ScreenSaverEngine" to launch

Although this works perfectly in most cases, I have a strange issue when the mouse is moved exactly at the time the script is invoked. Then, the ScreenSaverEngine.app is loaded and the desktop is locked, but the ScreenSaverEngine UI does not show up. Instead, the desktop is still visible, but it is not possible to set focus on other applications or UI controls; the desktop session is basically locked.

The only way to 'unlock' the desktop is to force setting focus on the Activity Monitor app (by Ctrl-clicking its dock icon and selecting Show All Windows) and then killing the ScreenSaverEngine process.

The same behaviour can be easily reproduced by launching ScreenSaverEngine from the Terminal:

/System/Library/Frameworks/ScreenSaver.framework/Resources/ScreenSaverEngine.app/Contents/MacOS/ScreenSaverEngine

and actively moving the mouse cursor while pressing the Enter key.

Does anyone know a method that can be used to launch the screensaver programmatically, and does not suffer from this issue?

Note: I know that there are other options to lock the screen (Fast user switching, the Keychain lock and Hot Corners), but I'm not interested in those solutions, I need a way to programmatically start the screensaver.

最满意答案

我在谷歌深处找到了答案。 使用私有ScreenSaver.framework中未记录的ScreenSaverController类启动屏幕保护程序按预期工作。

我使用以下标题:

#import <Foundation/Foundation.h> @interface ScreenSaverController : NSObject + controller; @end @protocol ScreenSaverControl - (BOOL) screenSaverIsRunning; - (BOOL) screenSaverCanRun; - (void) setScreenSaverCanRun:(BOOL)fp8; - (void) screenSaverStartNow; - (void) screenSaverStopNow; - (void) restartForUser:(id)fp8; - (double) screenSaverTimeRemaining; - (void) screenSaverDidFade; - (BOOL) screenSaverIsRunningInBackground; - (void) screenSaverDidFadeInBackground:(BOOL)fp8 psnHi:(unsigned int)fp12 psnLow:(unsigned int)fp16; @end

并将ScreenSaver.framework链接到我的项目。 启动屏幕保护程序就像这样简单:

[[ScreenSaverController controller] screenSaverStartNow];

当屏幕保护程序以这种方式启动时,我在我的问题中描述的行为无法再现。 如果在调用此方法时主动移动鼠标,屏幕保护程序立即返回时屏幕会快速闪烁(不锁定桌面)。

适用于10.6.8和10.7.4。

免责声明:谨慎使用Apple框架中的未记录类,因为它们不受支持,并且在未来版本的OS X中功能可能会中断(考虑弱链接)。 此外,它将取消您的应用程序从App Store的资格。

I found the answer myself in the deep depths of Google. Using the undocumented ScreenSaverController class from the private ScreenSaver.framework to start the screensaver works as expected.

I use the following header:

#import <Foundation/Foundation.h> @interface ScreenSaverController : NSObject + controller; @end @protocol ScreenSaverControl - (BOOL) screenSaverIsRunning; - (BOOL) screenSaverCanRun; - (void) setScreenSaverCanRun:(BOOL)fp8; - (void) screenSaverStartNow; - (void) screenSaverStopNow; - (void) restartForUser:(id)fp8; - (double) screenSaverTimeRemaining; - (void) screenSaverDidFade; - (BOOL) screenSaverIsRunningInBackground; - (void) screenSaverDidFadeInBackground:(BOOL)fp8 psnHi:(unsigned int)fp12 psnLow:(unsigned int)fp16; @end

and link the ScreenSaver.framework to my project. Starting the screensaver is then as simple as:

[[ScreenSaverController controller] screenSaverStartNow];

The behaviour I described in my question cannot be reproduced when the screensaver is started this way. If the mouse is moved actively when invoking this method, the screen quickly flashes as the screensaver returns immediately (without locking the desktop).

Works on 10.6.8 and 10.7.4.

Disclaimer: use undocumented classes from Apple frameworks with care, as they are unsupported and functionality may break in future versions of OS X (consider weak linking). Also, it will disqualify your app from the App Store.

更多推荐