Document domain parameter of wxTranslations::GetTranslatedString().
[wxWidgets.git] / src / cocoa / evtloop.mm
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/cocoa/evtloop.mm
3 // Purpose:     implements wxEventLoop for Cocoa
4 // Author:      David Elliott
5 // Created:     2003/10/02
6 // Copyright:   (c) 2003 David Elliott <dfe@cox.net>
7 //              (c) 2013 Rob Bresalier
8 // Licence:     wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 #include "wx/wxprec.h"
12
13 #include "wx/evtloop.h"
14
15 #ifndef WX_PRECOMP
16     #include "wx/log.h"
17     #include "wx/app.h"
18 #endif //WX_PRECOMP
19
20 #import <AppKit/NSApplication.h>
21 #import <AppKit/NSEvent.h>
22 #import <Foundation/NSRunLoop.h>
23
24 // ========================================================================
25 // wxGUIEventLoop
26 // ========================================================================
27
28 // ----------------------------------------------------------------------------
29 // wxGUIEventLoop running and exiting
30 // ----------------------------------------------------------------------------
31
32 int wxGUIEventLoop::DoRun()
33 {
34     [[NSApplication sharedApplication] run];
35
36     OnExit();
37
38     return m_exitcode;
39 }
40
41 void wxGUIEventLoop::ScheduleExit(int rc)
42 {
43     wxCHECK_RET( IsInsideRun(), wxT("can't call ScheduleExit() if not started") );
44
45     m_exitcode = rc;
46
47     NSApplication *cocoaApp = [NSApplication sharedApplication];
48     wxLogTrace(wxTRACE_COCOA,wxT("wxEventLoop::Exit isRunning=%d"), (int)[cocoaApp isRunning]);
49     wxTheApp->WakeUpIdle();
50     /* Notes:
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.
55
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.
61     */
62     [cocoaApp stop: cocoaApp];
63 }
64
65 // ----------------------------------------------------------------------------
66 // wxEventLoop message processing dispatching
67 // ----------------------------------------------------------------------------
68
69 bool wxGUIEventLoop::Pending() const
70 {
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
76             dequeue: NO];
77 }
78
79 bool wxGUIEventLoop::Dispatch()
80 {
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
90                 dequeue: YES])
91     {
92         [cocoaApp sendEvent: event];
93     }
94
95     return true;
96 }
97
98 int wxGUIEventLoop::DispatchTimeout(unsigned long timeout)
99 {
100     NSApplication *cocoaApp = [NSApplication sharedApplication];
101     NSEvent *event = [cocoaApp
102                 nextEventMatchingMask:NSAnyEventMask
103                 untilDate:[[NSDate alloc] initWithTimeIntervalSinceNow:timeout/1000]
104                 inMode:NSDefaultRunLoopMode
105                 dequeue: YES];
106     if ( !event )
107         return -1;
108
109     [cocoaApp sendEvent: event];
110
111     return true;
112 }
113
114 bool wxGUIEventLoop::YieldFor(long eventsToProcess)
115 {
116 #if wxUSE_LOG
117     // disable log flushing from here because a call to wxYield() shouldn't
118     // normally result in message boxes popping up &c
119     wxLog::Suspend();
120 #endif // wxUSE_LOG
121
122     m_isInsideYield = true;
123     m_eventsToProcessInsideYield = eventsToProcess;
124
125     // Run the event loop until it is out of events
126     while (1)
127     {
128         // TODO: implement event filtering using the eventsToProcess mask
129
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.
137          */
138         NSEvent *event = [GetNSApplication()
139                 nextEventMatchingMask:NSAnyEventMask
140                 untilDate:[NSDate distantPast]
141                 inMode:NSDefaultRunLoopMode
142                 dequeue: YES];
143         if(!event)
144             break;
145         [GetNSApplication() sendEvent: event];
146     }
147
148     /*
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.
153
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
158         an event.
159      */
160     if (wxTheApp)
161         wxTheApp->ProcessPendingEvents();
162
163 #if wxUSE_LOG
164     // let the logs be flashed again
165     wxLog::Resume();
166 #endif // wxUSE_LOG
167
168     m_isInsideYield = false;
169
170     return true;
171 }