I’m building an application with a main window and a sub-window that I’d like to present as a modal session. So I’m using this code within the window controller:
self.session = [[NSApplication sharedApplication] beginModalSessionForWindow: self.window];
[[NSApplication sharedApplication] runModalSession: self.session];
However, regardless of where I put this code – in windowDidLoad, in a post-windowDidLoad call from the main window, or even in the window controller’s init function – what I get is a modeless sub-window. The sub-window appears over the main window, but the main window continues to respond to input events.
What am I doing wrong?
nvm – found my answer by reading some examples. (Once again, hours of research before posting on Stack failed to yield answers, and I stumble across insight right after posting.)
For posterity, here’s the answer: beginModalSessionForWindow doesn’t work like runModalForWindow.
With runModal, you can execute that code anywhere, and Cocoa will immediately halt all processing except for the modal window. (Unfortunately, that includes timers tied to non-UI events for background processing.) The code that executes runModal is blocked, and resumes only after the modal window is closed. The system enforces the modality of the window.
beginModalSessionForWindow works very differently. Wherever you execute it, the code starts up the modal window and then keeps executing. In the general use case (as demonstrated in Apple’s examples), if you call beginModal before a loop and then condition the loop on polling the status of the session, the loop can perform whatever other processing you want; and during the loop, it’s also blocking normal UI events – just like any IBAction would when executing a long-running loop.
The point is that beginModalSession actually doesn’t enforce any modality of the window. Rather, your code enforces the modality of the window by executing a long-running loop. If you don’t use a loop, but instead just let the “modal” session run and resume the ordinary event loop… then your other windows get all event processing, including UI events. The “modal” window becomes modeless.
I will argue that “beginModalSessionForWindow” should really be called beginModelessSessionForWindow, because that’s what it does: it creates a modeless window and returns.