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