Snow Leopard & LSUIElement -> приложение не активируется должным образом, окно не "активно", хотя и является "ключом" - PullRequest
12 голосов
/ 28 мая 2010

Я столкнулся с несколькими проблемами с фоновым приложением, которое использует LSUIElement = 1, чтобы скрыть свой элемент закрепления, строку меню и предотвратить его появление в переключателе приложений Command-Tab.

Кажется, это проблема только снежного барса.

Приложение помещает NSStatusItem в строку меню и при нажатии открывает меню. Выбор «Preferences ...» должен вызвать NSWindow с настройками.

Первое, что, похоже, не работает, это то, что окно не упорядочено спереди, а появляется за всеми остальными окнами приложения.

Я пытался это исправить, позвонив

[[NSApplication sharedApplication] activateIgnoringOtherApps: YES]

но это не сработало.

Через некоторое время я понял, что меню блокирует отправку сообщения в цикл выполнения, поэтому я написал другой метод на MainController и отправил сообщение с задержкой:

[self executeSelector: @selector (setFront :) withObject: [окно предпочтений контроллера] afterDelay: 1.0];

-(void)setFront: (id) theWindow {

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

Обратите внимание на подход «отправляй каждое возможное сообщение, чтобы сделать то, что должен делать».

Это работает, в некотором роде, окно выводится на передний план поверх всех других окон из всех приложений, НО в большинстве случаев оно не активно, то есть строка заголовка неактивна. Нажатие на строку заголовка также не сделает окно активным. Нажатие внутри окна сделает его активным!?

Все это, похоже, не было проблемой в Leopard; просто вызывал activIgnoringOtherApps и заставлял ключ окна работать нормально.

В Snow Leopard есть новый API, разработанный для замены LSUIElement, который должен эмулировать его поведение:

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

Я играл с этим, но он только для SL, и я не смог установить LSUIElement.

Ответы [ 2 ]

8 голосов
/ 02 ноября 2010

Это странно - я пишу приложение LSUIElement под Snow Leopard, и у меня не было таких проблем, как вы описали ... У меня была проблема, что недавно созданное окно не появилось спереди , но я исправил это, вызвав activIgnoringOtherApps. Это было все, что мне нужно было сделать, чтобы все заработало как надо:

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

Я даже не трогал ничего, что имело «полис» в названии.

4 голосов
/ 28 мая 2010

После публикации вопроса в отчаянии я продолжал искать и в конце концов нашел решение. Так как это поставило меня в тупик на несколько дней, и, похоже, нет другого ответа, который может найти Google, я объясню решение для "будущих поколений".

В Snow Leopard добавлен новый API-интерфейс презентации NSApplication:

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

Предполагается, что это имитирует работу LSUIElement, но обеспечивает больший контроль разработчика. К сожалению, симуляция не идеальна, поэтому происходит изменение поведения между 10,5 и 10,6.

В частности, если ваше приложение имеет строку LSUIElement = 1 в своем info.plist, Snow Leopard инициализирует «презентацию приложения .. вместо эквивалентной комбинации флагов NSApplicationPresentationOptions».

Только на самом деле это не так. Он устанавливает новый NSApplication setActivationPolicy равным NSApplicationActivationPolicyAccessory:

"Приложение не отображается в Dock и не имеет строки меню, но оно может быть активировано программно или нажатием одного из его окон. Это соответствует значению ключа LSUIElement в Info.plist приложения 1. "

Несмотря на упоминание о программной активации, activIgnoringOtherApps: просто полностью игнорируется.

Решение состоит в том, чтобы установить политику активации на «обычную»:

[[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];

}

Надеюсь, кто-нибудь найдет это полезным.

...