Snow Leopard & LSUIElement-> приложение, не активируясь правильно, окно, не “активное” несмотря на то, чтобы быть “ключевым”

Я сталкиваюсь с некоторыми проблема с фоновым приложением, которое использует 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 быть установленным.

12
задан ThinkingStiff 23 February 2013 в 21:42
поделиться

1 ответ

После размещения вопроса в отчаянии я продолжил поиски и в конце концов нашел решение. Поскольку это поставило меня в тупик на несколько дней и, похоже, нет другого ответа, который мог бы найти 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];

}

Надеюсь, кому-нибудь это пригодится.

4
ответ дан 2 December 2019 в 21:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: