1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/cocoa/evtloop.mm
3 // Purpose: implements wxEventLoop for Cocoa
4 // Author: David Elliott
6 // Copyright: (c) 2003 David Elliott <dfe@cox.net>
7 // (c) 2013 Rob Bresalier
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 #include "wx/wxprec.h"
13 #include "wx/evtloop.h"
20 #import <AppKit/NSApplication.h>
21 #import <AppKit/NSEvent.h>
22 #import <Foundation/NSRunLoop.h>
24 // ========================================================================
26 // ========================================================================
28 // ----------------------------------------------------------------------------
29 // wxGUIEventLoop running and exiting
30 // ----------------------------------------------------------------------------
32 int wxGUIEventLoop::DoRun()
34 [[NSApplication sharedApplication] run];
41 void wxGUIEventLoop::ScheduleExit(int rc)
43 wxCHECK_RET( IsInsideRun(), wxT("can't call ScheduleExit() if not started") );
47 NSApplication *cocoaApp = [NSApplication sharedApplication];
48 wxLogTrace(wxTRACE_COCOA,wxT("wxEventLoop::Exit isRunning=%d"), (int)[cocoaApp isRunning]);
49 wxTheApp->WakeUpIdle();
51 If we're being called from idle time (which occurs while checking the
52 queue for new events) there may or may not be any events in the queue.
53 In order to successfully stop the event loop, at least one event must
54 be processed. To ensure this always happens, WakeUpIdle is called.
56 If the application was active when closed then this is unnecessary
57 because it would receive a deactivate event anyway. However, if the
58 application was not active when closed, then no events would be
59 added to the queue by Cocoa and thus the application would wait
60 indefinitely for the next event.
62 [cocoaApp stop: cocoaApp];
65 // ----------------------------------------------------------------------------
66 // wxEventLoop message processing dispatching
67 // ----------------------------------------------------------------------------
69 bool wxGUIEventLoop::Pending() const
71 // a pointer to the event is returned if there is one, or nil if not
72 return [[NSApplication sharedApplication]
73 nextEventMatchingMask: NSAnyEventMask
74 untilDate: nil /* Equivalent to [NSDate distantPast] */
75 inMode: NSDefaultRunLoopMode
79 bool wxGUIEventLoop::Dispatch()
81 // This check is required by wxGTK but probably not really for wxCocoa
82 // Keep it here to encourage developers to write cross-platform code
83 wxCHECK_MSG( IsRunning(), false, wxT("can't call Dispatch() if not running") );
84 NSApplication *cocoaApp = [NSApplication sharedApplication];
85 // Block to retrieve an event then send it
86 if(NSEvent *event = [cocoaApp
87 nextEventMatchingMask:NSAnyEventMask
88 untilDate:[NSDate distantFuture]
89 inMode:NSDefaultRunLoopMode
92 [cocoaApp sendEvent: event];
98 int wxGUIEventLoop::DispatchTimeout(unsigned long timeout)
100 NSApplication *cocoaApp = [NSApplication sharedApplication];
101 NSEvent *event = [cocoaApp
102 nextEventMatchingMask:NSAnyEventMask
103 untilDate:[[NSDate alloc] initWithTimeIntervalSinceNow:timeout/1000]
104 inMode:NSDefaultRunLoopMode
109 [cocoaApp sendEvent: event];
114 bool wxGUIEventLoop::YieldFor(long eventsToProcess)
117 // disable log flushing from here because a call to wxYield() shouldn't
118 // normally result in message boxes popping up &c
122 m_isInsideYield = true;
123 m_eventsToProcessInsideYield = eventsToProcess;
125 // Run the event loop until it is out of events
128 // TODO: implement event filtering using the eventsToProcess mask
130 wxAutoNSAutoreleasePool pool;
131 /* NOTE: It may be better to use something like
132 NSEventTrackingRunLoopMode since we don't necessarily want all
133 timers/sources/observers to run, only those which would
134 run while tracking events. However, it should be noted that
135 NSEventTrackingRunLoopMode is in the common set of modes
136 so it may not effectively make much of a difference.
138 NSEvent *event = [GetNSApplication()
139 nextEventMatchingMask:NSAnyEventMask
140 untilDate:[NSDate distantPast]
141 inMode:NSDefaultRunLoopMode
145 [GetNSApplication() sendEvent: event];
149 Because we just told NSApplication to avoid blocking it will in turn
150 run the CFRunLoop with a timeout of 0 seconds. In that case, our
151 run loop observer on kCFRunLoopBeforeWaiting never fires because
152 no waiting occurs. Therefore, no idle events are sent.
154 Believe it or not, this is actually desirable because we do not want
155 to process idle from here. However, we do want to process pending
156 events because some user code expects to do work in a thread while
157 the main thread waits and then notify the main thread by posting
161 wxTheApp->ProcessPendingEvents();
164 // let the logs be flashed again
168 m_isInsideYield = false;