1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/cocoa/evtloop.mm
3 // Purpose: implements wxEventLoop for Cocoa
4 // Author: David Elliott
7 // Copyright: (c) 2003 David Elliott <dfe@cox.net>
8 // (c) 2013 Rob Bresalier
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::DoRun()
35 [[NSApplication sharedApplication] run];
42 void wxGUIEventLoop::ScheduleExit(int rc)
44 wxCHECK_RET( IsInsideRun(), wxT("can't call ScheduleExit() if not started") );
48 NSApplication *cocoaApp = [NSApplication sharedApplication];
49 wxLogTrace(wxTRACE_COCOA,wxT("wxEventLoop::Exit isRunning=%d"), (int)[cocoaApp isRunning]);
50 wxTheApp->WakeUpIdle();
52 If we're being called from idle time (which occurs while checking the
53 queue for new events) there may or may not be any events in the queue.
54 In order to successfully stop the event loop, at least one event must
55 be processed. To ensure this always happens, WakeUpIdle is called.
57 If the application was active when closed then this is unnecessary
58 because it would receive a deactivate event anyway. However, if the
59 application was not active when closed, then no events would be
60 added to the queue by Cocoa and thus the application would wait
61 indefinitely for the next event.
63 [cocoaApp stop: cocoaApp];
66 // ----------------------------------------------------------------------------
67 // wxEventLoop message processing dispatching
68 // ----------------------------------------------------------------------------
70 bool wxGUIEventLoop::Pending() const
72 // a pointer to the event is returned if there is one, or nil if not
73 return [[NSApplication sharedApplication]
74 nextEventMatchingMask: NSAnyEventMask
75 untilDate: nil /* Equivalent to [NSDate distantPast] */
76 inMode: NSDefaultRunLoopMode
80 bool wxGUIEventLoop::Dispatch()
82 // This check is required by wxGTK but probably not really for wxCocoa
83 // Keep it here to encourage developers to write cross-platform code
84 wxCHECK_MSG( IsRunning(), false, wxT("can't call Dispatch() if not running") );
85 NSApplication *cocoaApp = [NSApplication sharedApplication];
86 // Block to retrieve an event then send it
87 if(NSEvent *event = [cocoaApp
88 nextEventMatchingMask:NSAnyEventMask
89 untilDate:[NSDate distantFuture]
90 inMode:NSDefaultRunLoopMode
93 [cocoaApp sendEvent: event];
99 int wxGUIEventLoop::DispatchTimeout(unsigned long timeout)
101 NSApplication *cocoaApp = [NSApplication sharedApplication];
102 NSEvent *event = [cocoaApp
103 nextEventMatchingMask:NSAnyEventMask
104 untilDate:[[NSDate alloc] initWithTimeIntervalSinceNow:timeout/1000]
105 inMode:NSDefaultRunLoopMode
110 [cocoaApp sendEvent: event];
115 bool wxGUIEventLoop::YieldFor(long eventsToProcess)
118 // disable log flushing from here because a call to wxYield() shouldn't
119 // normally result in message boxes popping up &c
123 m_isInsideYield = true;
124 m_eventsToProcessInsideYield = eventsToProcess;
126 // Run the event loop until it is out of events
129 // TODO: implement event filtering using the eventsToProcess mask
131 wxAutoNSAutoreleasePool pool;
132 /* NOTE: It may be better to use something like
133 NSEventTrackingRunLoopMode since we don't necessarily want all
134 timers/sources/observers to run, only those which would
135 run while tracking events. However, it should be noted that
136 NSEventTrackingRunLoopMode is in the common set of modes
137 so it may not effectively make much of a difference.
139 NSEvent *event = [GetNSApplication()
140 nextEventMatchingMask:NSAnyEventMask
141 untilDate:[NSDate distantPast]
142 inMode:NSDefaultRunLoopMode
146 [GetNSApplication() sendEvent: event];
150 Because we just told NSApplication to avoid blocking it will in turn
151 run the CFRunLoop with a timeout of 0 seconds. In that case, our
152 run loop observer on kCFRunLoopBeforeWaiting never fires because
153 no waiting occurs. Therefore, no idle events are sent.
155 Believe it or not, this is actually desirable because we do not want
156 to process idle from here. However, we do want to process pending
157 events because some user code expects to do work in a thread while
158 the main thread waits and then notify the main thread by posting
162 wxTheApp->ProcessPendingEvents();
165 // let the logs be flashed again
169 m_isInsideYield = false;