Я сталкиваюсь с некоторыми проблема с фоновым приложением, которое использует LSUIElement=1, чтобы скрыть его объект прикрепления, строку меню и препятствовать тому, чтобы она появилась в переключателе приложения Вкладки Команды.
Это, кажется, Snow Leopard только проблема.
Приложение размещает NSStatusItem в строку меню и открывается меню при нажатии. Выбор "Предпочтений..." должен поднять NSWindow с предпочтениями.
Первая вещь, которая, кажется, не работает, состоит в том, что Окно не становится заказанным в в передней стороне, но появляется позади всех других окон приложения.
Я пытался зафиксировать это путем вызова
[[NSApplication sharedApplication] activateIgnoringOtherApps: YES]
но это не работало.
Через некоторое время я выяснил, что меню блокирует сообщение к циклу выполнения от того, чтобы быть отправленным, таким образом, я записал другой метод на MainController и отправил сообщение с задержкой:
[сам performSelector:@selector (setFront:) withObject: [окно preferencesController] 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-what-it-should-be-doing-approach.
Это работает, отчасти, окно выявлено сверху всех других окон из всех приложений, НО большую часть времени это не активно, означая, что это - строка заголовка, отображается серым. Нажатие на строку заголовка не сделает окно активным также. Нажатие на INSIDE окна сделает это активным!?
Это все, казалось, не было проблемой в Leopard; просто вызов activateIgnoringOtherApps и создание ключа окна, казалось, работали просто великолепно.
В Snow Leopard существует новый API, разработанный для замены LSUIElement, который, как предполагается, эмулирует его поведение:
http://developer.apple.com/mac/library/releasenotes/cocoa/appkit.html
Я играл вокруг с этим, но это только для SL, и я не смог получить LSUIElement быть установленным.
После размещения вопроса в отчаянии я продолжил поиски и в конце концов нашел решение. Поскольку это поставило меня в тупик на несколько дней и, похоже, нет другого ответа, который мог бы найти Google, я объясню решение для "будущих поколений".
Snow Leopard добавляет новый API NSApplication presentationOptions:
http://developer.apple.com/mac/library/releasenotes/cocoa/appkit.html
Это должно имитировать работу LSUIElement, но предоставить больше контроля разработчику. К сожалению, имитация не идеальна, поэтому между 10.5 и 10.6 есть изменения в поведении.
В частности, если ваше приложение имеет строку LSUIElement = 1 в info.plist, Snow Leopard инициализирует "presentationOptions приложения ... эквивалентной комбинацией флагов NSApplicationPresentationOptions".
Только на самом деле это не так. Он устанавливает новую NSApplication setActivationPolicy в NSApplicationActivationPolicyAccessory:
"Приложение не появляется в Dock и не имеет строки меню, но оно может быть активировано программно или щелчком на одном из его окон. Это соответствует значению ключа LSUIElement в Info.plist приложения, равному 1."
Несмотря на упоминание о программной активации, activateIgnoringOtherApps: просто полностью игнорируется.
Решением является установка политики активации на "обычную":
[[NSApplication sharedApplication] setActivationPolicy: NSApplicationActivationPolicyRegular];
Конечно, вы можете сделать это, только если используете 10.6 SDK в качестве базового 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];
}
Надеюсь, кому-нибудь это пригодится.