2

On Windows and GTK+ it is possible to have a fully nested run loop that can still pump events to windows that are not waiting for modal input. However, with Cocoa, all I see for NSAlert are -[NSAlert runModal], which affects all windows, and -[NSAlert beginSheetForModal:...:], which are modal to the given window and are not code-modal. Code-modal in this case means the function does not return until the NSAlert is dismissed. (I'll also need to do this for the other various dialogs, such as NSOpenPanel.)

Basically what I would like to know is if it is possible to model a call to -[NSAlert beginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo:] that safely allows other window events to continue running, but that does not itself return until the dialog is dismissed. For instance, something like

[alert beginSheetModalForWindow:w modalDelegate:delegate didEndSelector:... contextInfo:NULL];
while (!delegate->done)
    [NSApp doMainLoopIteration]; // not real

but not racy like that. Or perhaps even something like

[alert ...];
[delegate waitForAlertDidEnd];

This is being called from a C function for interop with a non-Objective-C environment.

Is this possible, or am I out of luck?

This needs to target Mac OS X 10.7+, so I can't use the new block-based NSAlert method which was introduced in 10.9.

Thanks!

Update

Now I have some actual code to show for this:

NSInteger ret;

[box beginSheetModalForWindow:parent
    modalDelegate:[NSApp delegate]
    didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
    contextInfo:&ret];
// TODO
return (intptr_t) ret;

I'd like the TODO to be a wait for the didEndSelector to run, while still pumping other events. The didEndSelector is

- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)data
{
    NSInteger *ret = (NSInteger *) data;

    *ret = returnCode;
}

If there's a statement that I need to put in there to make what I want work, that can be done too.

Thanks!

andlabs
  • 11,290
  • 1
  • 31
  • 52
  • Spinning the run loop is easy, but why can't you do whatever you need to do in the delegate method instead of here? – jscs Jun 28 '14 at 18:48
  • Because this is being passed to code that is not written in Objective-C and works in an environment that expects functions like message box requests to be code-modal. There's no way to do this kind of delegate thing in the Windows API without rolling your own message box, for instance. – andlabs Jun 28 '14 at 19:11
  • Is your `beginSheetModalForWindow:...` call off the main thread? – jscs Jul 01 '14 at 21:41
  • No. (I could have had it on the main thread, but other complications have arisen on other platforms that prevent this from happening, so main thread only for now.) – andlabs Jul 01 '14 at 22:35
  • I can't see how you have a race condition, then, with cranking the main thread's run loop around from two different points _on the main thread_. – jscs Jul 05 '14 at 05:12
  • Perhaps; I may have used the wrong word when writing that. IIRC it was actually having two dialogs closeable in any order... That being said, I'm considering just leaving the question abandoned, as this particular project has stalled, and my plans for a replacement API circumvent the issue at hand. Thanks in the meantime. – andlabs Jul 05 '14 at 22:12
  • Oh, I can see how you might get weird ordering problems, sure. Glad I was maybe slightly helpful. – jscs Jul 06 '14 at 07:16

0 Answers0