1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: cocoa/evtloop.mm
3 // Purpose: implements wxEventLoop for Cocoa
4 // Author: David Elliott
8 // Copyright: (c) 2003 David Elliott <dfe@cox.net>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
14 #include "wx/evtloop.h"
21 #import <AppKit/NSApplication.h>
22 #import <AppKit/NSEvent.h>
23 #import <Foundation/NSRunLoop.h>
25 // ========================================================================
27 // ========================================================================
29 // ----------------------------------------------------------------------------
30 // wxGUIEventLoop running and exiting
31 // ----------------------------------------------------------------------------
33 int wxGUIEventLoop::Run()
35 // event loops are not recursive, you need to create another loop!
36 wxCHECK_MSG( !IsRunning(), -1, wxT("can't reenter a message loop") );
38 wxEventLoopActivator activate(this);
40 [[NSApplication sharedApplication] run];
47 void wxGUIEventLoop::Exit(int rc)
49 wxCHECK_RET( IsRunning(), wxT("can't call Exit() if not running") );
53 NSApplication *cocoaApp = [NSApplication sharedApplication];
54 wxLogTrace(wxTRACE_COCOA,wxT("wxEventLoop::Exit isRunning=%d"), (int)[cocoaApp isRunning]);
55 wxTheApp->WakeUpIdle();
57 If we're being called from idle time (which occurs while checking the
58 queue for new events) there may or may not be any events in the queue.
59 In order to successfully stop the event loop, at least one event must
60 be processed. To ensure this always happens, WakeUpIdle is called.
62 If the application was active when closed then this is unnecessary
63 because it would receive a deactivate event anyway. However, if the
64 application was not active when closed, then no events would be
65 added to the queue by Cocoa and thus the application would wait
66 indefinitely for the next event.
68 [cocoaApp stop: cocoaApp];
71 // ----------------------------------------------------------------------------
72 // wxEventLoop message processing dispatching
73 // ----------------------------------------------------------------------------
75 bool wxGUIEventLoop::Pending() const
77 // a pointer to the event is returned if there is one, or nil if not
78 return [[NSApplication sharedApplication]
79 nextEventMatchingMask: NSAnyEventMask
80 untilDate: nil /* Equivalent to [NSDate distantPast] */
81 inMode: NSDefaultRunLoopMode
85 bool wxGUIEventLoop::Dispatch()
87 // This check is required by wxGTK but probably not really for wxCocoa
88 // Keep it here to encourage developers to write cross-platform code
89 wxCHECK_MSG( IsRunning(), false, wxT("can't call Dispatch() if not running") );
90 NSApplication *cocoaApp = [NSApplication sharedApplication];
91 // Block to retrieve an event then send it
92 if(NSEvent *event = [cocoaApp
93 nextEventMatchingMask:NSAnyEventMask
94 untilDate:[NSDate distantFuture]
95 inMode:NSDefaultRunLoopMode
98 [cocoaApp sendEvent: event];
104 int wxGUIEventLoop::DispatchTimeout(unsigned long timeout)
106 NSApplication *cocoaApp = [NSApplication sharedApplication];
107 NSEvent *event = [cocoaApp
108 nextEventMatchingMask:NSAnyEventMask
109 untilDate:[[NSDate alloc] initWithTimeIntervalSinceNow:timeout/1000]
110 inMode:NSDefaultRunLoopMode
115 [cocoaApp sendEvent: event];
120 bool wxGUIEventLoop::YieldFor(long eventsToProcess)
123 // disable log flushing from here because a call to wxYield() shouldn't
124 // normally result in message boxes popping up &c
128 m_isInsideYield = true;
129 m_eventsToProcessInsideYield = eventsToProcess;
131 // Run the event loop until it is out of events
134 // TODO: implement event filtering using the eventsToProcess mask
136 wxAutoNSAutoreleasePool pool;
137 /* NOTE: It may be better to use something like
138 NSEventTrackingRunLoopMode since we don't necessarily want all
139 timers/sources/observers to run, only those which would
140 run while tracking events. However, it should be noted that
141 NSEventTrackingRunLoopMode is in the common set of modes
142 so it may not effectively make much of a difference.
144 NSEvent *event = [GetNSApplication()
145 nextEventMatchingMask:NSAnyEventMask
146 untilDate:[NSDate distantPast]
147 inMode:NSDefaultRunLoopMode
151 [GetNSApplication() sendEvent: event];
155 Because we just told NSApplication to avoid blocking it will in turn
156 run the CFRunLoop with a timeout of 0 seconds. In that case, our
157 run loop observer on kCFRunLoopBeforeWaiting never fires because
158 no waiting occurs. Therefore, no idle events are sent.
160 Believe it or not, this is actually desirable because we do not want
161 to process idle from here. However, we do want to process pending
162 events because some user code expects to do work in a thread while
163 the main thread waits and then notify the main thread by posting
167 wxTheApp->ProcessPendingEvents();
170 // let the logs be flashed again
174 m_isInsideYield = false;