3
votes

I have a Cocoa-based command line application that programmatically creates an NSWindow + NSView. It uses a nextEventMatchingMask loop to manually pump the event loop and dispatch events. This loop is called by some upper level code periodically to poll for input.

If I run everything on the main thread then this works fine in that the view receives input events correctly.

If instead I move the window creation and message loop to a separate thread then nextEventMatchingMask no longer returns any events and the view doesn't receive input.

I'm aware that only the "main" thread in a Cocoa app is supposed to handle events. This secondary thread however is the only thread that needs to talk to Cocoa, so I would like to use it as the "main" thread as far as Cocoa is concerned. Is this possible? I call NSApplicationLoad from this thread, and as far as I know this is the first Cocoa function called in the process.

If I can't specify which is the main Cocoa thread then, is there any other way to be able to create an NSWindow on a background thread and receive events for it? I can't do something like call NSApplication Run because I am not in control of the application's main loop. I just need to pull input events from the Window when the upper level code requests that I do so.

2
This: stackoverflow.com/questions/6178618/… sounds exactly like my situation.eodabash

2 Answers

3
votes

Maybe you need to start the runloop on the secondary thread. In your main thread, when you spawn off your secondary thread, call something like this:

[NSThread detachNewThreadSelector:@selector(launchThread) 
                         toTarget:[ThreadHandler class] 
                       withObject:nil];

In the ThreadHandler class, have something like:

+ (void)launchThread
{
    NSRunLoop *threadRunLoop = [NSRunLoop currentRunLoop];
    while (someThreadExitCondition && [threadRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1]]);
}

This should start your thread runloop processing events. I'm not sure without testing whether this would allow you to process events for a window created in a secondary thread, but it might get you started on how to run the thread's runloop. You could even set up something like a Distributed Objects situation where you pump events from the main event loop through a NSConnection to the secondary thread (example). Hopefully this might at least give you another avenue to pursue.

1
votes

That's not behavior I would rely on.

If you need to run your backend on a thread which is not restricted by a run loop, then run it on a secondary thread in order to run the UI from the main thread.

Alternatively, you could create another process...