Re: NSApp's currentEvent
Re: NSApp's currentEvent
- Subject: Re: NSApp's currentEvent
- From: Bill Bumgarner <email@hidden>
- Date: Thu, 6 Jun 2002 11:03:08 -0400
This kind of manual event handling can be extremely troublesome to
implement, as it seems you are discovering, because it is an attempt to
second guess the event handling patterns of the AppKit. It is generally a
lot easier to allow the AppKit to do its thing unmolested and for your
code to integrate with the AppKit's design patterns as fluidly as possible.
The key is to know that every thread has a couple of additional resources
associated with it that are intimately tied to the run loop. Release
pools, run loops, and NSConnections all have thread specific features.
If you are working with threads in a Cocoa app, always use NSThread
(or other Cocoa/Foundation API) to create the threads. While NSThread is
a wrapper around pthreads, the instantiation of an NSThread does more than
create a pthread. Each thread has additional, higher level than pthreads,
data associated with it that is created during instantiation.
In particular, each thread can have an NSRunLoop associated with it.
When invoking NSRunLoop's +currentRunLoop method, it returns a run loop
instance that is specific to the current thread of execution. As such,
event handling happens on a per thread basis. The timers, ports, and
modes associated with a run loop are specific to a single thread! A
multithreaded application can have multiple run loops. Within
multithreaded Cocoa apps, multiple run loops is a common idiom in that it
allows the app to communicate between threads using NSConnection based
conversations.
The 'main event loop' within an NSApplication based application is
simply an NSRunLoop that is configured to handle various events that are
dispatched by the system. The system dispatches events into the
application through the use of mach ports-- details are interesting, but
not relevant to this discussion.
Given that run loops are thread specific, it means that the
Application's main event loop (based on an NSRunLoop) is also thread
specific. That is, if you want to get or post events that are processed
by the MEL, the events need to be posted or retrieved in the thread of
execution that 'owns' the main event loop's NSRunLoop.
This does not mean that you cannot do multithreaded event processing,
just that the actual event posting and retrieval must be done in the MEL
thread of execution. I.e. from your secondary thread, you need to ask
the MEL to execute a chunk of code to grab the next event or post an event.
This is easily done with NSConnection. Xoptimize was written
primarily to demonstrate how to do intra-thread communication within the
AppKit. While Xoptimize doesn't query for events, the communication code
is exactly what you need. (Grab the Xoptimize source from
www.versiontracker.com -- the source is included in the disk image).
Specifically, you want to look at the -(void)startOptimization: and
-(void)doOptimizationInThread: methods. The former spawns the thread and
the latter is the entry point into the thread that sets up the
NSConnection channel to communication between the two threads.
---
However, reading your original post raised a question-- it may be
completely misdirected. That you want to send events and then retrieve
events using nextEventMatching indicates that you may be trying to use the
application's event queue to pass processing requests from one thread to
another?
If that is the case, then it is likely that the NSConnection based
code can be used to communicate the requests between the threads more
directly, eliminating the creation and consumption of custom event
types. In any case, you must have a running NSRunLoop in any thread that
will be receiving messages from the NSConnection. The NSConnection
communicates between threads by effectively posting a port event into the
runloop of the receiving thread.
You can use a repeating NSTimer to cause the runloop to loop
automatically. A loop can only receive and process events if it is
running. You can also turn the loop 'inside out' as follows.
while (1) {
// do one step of heavy calculation here
while([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate: [NSDate date]]) {;}
// do more calculation here
}
-runMode:beforeDate: will cause the runloop to run exactly once, blocking
until date waiting for input.
#import <Foundation/Foundation.h>
@interface Foo:NSObject
@end
@implementation Foo
+ (void) doSomething
{
NSLog(@"did something (%@)", [NSDate date]);
}
@end
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
[NSTimer scheduledTimerWithTimeInterval:0.0
target:[Foo class]
selector:@selector(doSomething)
userInfo:nil
repeats:NO];
NSLog(@"Running once (%@) ... ", [NSDate date]);
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate date]];
NSLog(@"...ran (%@).", [NSDate date]);
[pool release];
return 0;
}
2002-06-06 10:59:17.826 rltest[10553] Running once (<CFDate 0x108f80
[0x8016024c]>{time = 45068357.8}) ...
2002-06-06 10:59:17.827 rltest[10553] did something (<CFDate 0x10b2a0
[0x8016024c]>{time = 45068357.8})
2002-06-06 10:59:17.828 rltest[10553] ...ran (<CFDate 0x108c70 [0x8016024c]
>{time = 45068357.8}).
b.bum
On Thursday, June 6, 2002, at 08:52 AM, Gregor Nobis <email@hidden>
wrote:
I'm doing some weird customizing stuff with NSApp and need to do event
handling manually and - as if I were crazy - need to call [NSApp
nextEventMatchingMask...] and [NSApp sendEvent:] from different threads.
As a result of this seperation I experienced some trouble: [NSApp
nextEvent...] always returns an empty NSEvent. Everything works fine as
long as both methods are called from the same thread.
Has anyone else had similar problems before? I just can't figure out
what I'm doing wrong.
Any help is greatly appreciated!
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.