雪豹& LSUIElement - >应用程序没有正确激活,窗口不是“活动”,尽管是“关键”

时间:2010-05-28 11:52:42

标签: cocoa nswindow appkit

我遇到一个问题,后台应用程序使用LSUIElement = 1隐藏其停靠项,菜单栏并阻止它出现在Command-Tab应用程序切换器中。

这似乎只是Snow Leopard的问题。

应用程序在菜单栏中放置一个NSStatusItem,并在单击时弹出一个菜单。选择“首选项...”应该会显示带有首选项的NSWindow。

首先看起来不起作用的是Window没有在前面排序,但是出现在所有其他应用程序窗口后面。

我试图通过调用

来解决这个问题
[[NSApplication sharedApplication] activateIgnoringOtherApps: YES]

但这没效果。

过了一会儿,我发现菜单阻止了发送到运行循环的消息,所以我在MainController上写了另一个方法并发送了延迟信息:

[self performSelector:@selector(setFront :)               withObject:[preferencesController window] afterDelay:1.0];

-(void)setFront: (id) theWindow {

 [[NSApplication sharedApplication]activateIgnoringOtherApps:YES];
 [theWindow orderFrontRegardless];
 [theWindow makeKeyWindow]; 
        [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
}

请注意send-every-possible-message-to-make-it-do-it-it-it-doing-doing-approach。

这很有效,窗口在所有应用程序的所有其他窗口的顶部显示,但大多数时候它不活动,这意味着它的标题栏显示为灰色。单击标题栏也不会使窗口处于活动状态。单击窗口的INSIDE将使其激活!?

这一切似乎都不是豹子的问题;只是调用activateIgnoringOtherApps并使窗口键似乎工作正常。

在Snow Leopard中有一个新的API,旨在取代应该模仿其行为的LSUIElement:

http://developer.apple.com/mac/library/releasenotes/cocoa/appkit.html

我已经玩过了,但它只是SL而且我无法设置LSUIElement。

2 个答案:

答案 0 :(得分:8)

这很奇怪 - 我正在Snow Leopard下写一个LSUIElement应用程序,我没有你所描述的问题......我确实遇到了新创建的窗口没有出现在前面的问题,但我通过调用activateIgnoringOtherApps修复了它。这就是我必须做的就是让它按原样运作:

[NSApp activateIgnoringOtherApps: YES];
[preferencesWindow makeKeyAndOrderFront: self];

我甚至没有触及名字中有'政策'的任何东西。

答案 1 :(得分:4)

在绝望中发布问题之后,我确实继续寻找并最终找到了解决方案。由于这让我困扰了几天,谷歌似乎找不到其他答案,我将为“后代”解释解决方案。

Snow Leopard添加了一个新的NSApplication presentationOptions API:

http://developer.apple.com/mac/library/releasenotes/cocoa/appkit.html

这应该模拟LSUIElement的工作方式,但提供更多开发人员控制。不幸的是,模拟并不完美,因此10.5和10.6之间的行为发生了变化。

特别是,如果您的应用程序在其info.plist中具有LSUIElement = 1行,则Snow Leopard会将“应用程序的presentationOptions ..”初始化为NSApplicationPresentationOptions标志的等效组合。

只有它不是真的。它将新的NSApplication setActivationPolicy设置为NSApplicationActivationPolicyAccessory:

“应用程序没有出现在Dock中,也没有菜单栏,但可以通过编程方式或通过单击其中一个窗口来激活它。这对应于应用程序的Info.plist中的LSUIElement键的值1。“

尽管提到以编程方式激活,但activateIgnoringOtherApps:完全被忽略了。

解决方案是将激活策略设置为“常规”:

[[NSApplication sharedApplication] setActivationPolicy: NSApplicationActivationPolicyRegular];

当然,如果你使用10.6 SDK作为Base SDK,你只能这样做,这是目前很少有人想做的事情,所以下面是10.5安全的方法:

NSApplication* app = [NSApplication sharedApplication];

if( [app respondsToSelector: @selector(setActivationPolicy:)] ) {

    NSMethodSignature* method = [[app class] instanceMethodSignatureForSelector: @selector(setActivationPolicy:)];
    NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: method];
    [invocation setTarget: app];
    [invocation setSelector: @selector(setActivationPolicy:)];
    NSInteger myNSApplicationActivationPolicyAccessory = 0;
    [invocation setArgument: &myNSApplicationActivationPolicyAccessory atIndex: 2];
    [invocation invoke];

}

我希望有人会觉得这很有用。