I have a Cocoa application that displays an application-modal alert using the NSAlert
class. I'd like the alert window to float above all other applications' windows. Can this be done with NSAlert
, or do I need to implement my own window?
I don't know if any of this matters, but the application is an agent application (LSUIElement
is true) implemented as an NSStatusItem
. (For more info about the app, including source code, look <here>.)
Here is the code that displays the alert:
- (void)showTimerExpiredAlert {
[NSApp activateIgnoringOtherApps:YES];
NSAlert *alert = [[NSAlert alloc] init];
[alert setAlertStyle:NSInformationalAlertStyle];
[alert setMessageText:NSLocalizedString(@"Menubar Countdown Complete", @"Expiration message")];
[alert setInformativeText:NSLocalizedString(@"The countdown timer has reached 00:00:00.",
@"Expiration information")];
[alert addButtonWithTitle:NSLocalizedString(@"OK", @"OK button title")];
[alert addButtonWithTitle:NSLocalizedString(@"Restart Countdown...", @"Restart button title")];
NSInteger clickedButton = [alert runModal];
[alert release];
if (clickedButton == NSAlertSecondButtonReturn) {
// ...
}
}
I've tried putting this before the runModal
call:
[[alert window] setFloatingPanel:YES];
I've also tried this:
[[alert window] setLevel:NSFloatingWindowLevel];
But neither of those makes the window stay above others if I click another application's window. I suspect runModal
just doesn't honor either of those settings.
I wrecked my brain about this exact thing a while ago.
The only way that I could get this to work (sort of), was to subclass NSApplication, and override -sendEvent. In -sendEvent, you'd first call super's implementation, then do something like this:
id *modalWindow = [self modalWindow];
if (modalWindow && [modalWindow level] != MY_DESIRED_MODAL_WINDOW_LEVEL)
[modalWindow setLevel: MY_DESIRED_MODAL_WINDOW_LEVEL];
Apart from that even this didn't work quite spotlessly – when switching apps – you'd never want to do this anyway because it's a blatant, crude hack.
So yes, sadly you're better off writing your own version of NSAlert. If you really care about this possibility, I'd file a bug on it. It is pretty weird that [[alert window] setLevel: someLevel] isn't honored by NSApplication and it's a waste to have to re-build NSAlert with all its neat little auto-layout features just to be able to do this.