]> git.saurik.com Git - wxWidgets.git/blame - src/cocoa/evtloop.mm
Fix horizontal mouse wheel scrolling in wxGTK.
[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 5// Created: 2003/10/02
f5e10026 6// Copyright: (c) 2003 David Elliott <dfe@cox.net>
821d856a 7// (c) 2013 Rob Bresalier
526954c5 8// Licence: wxWindows licence
f5e10026
DE
9///////////////////////////////////////////////////////////////////////////////
10
11#include "wx/wxprec.h"
1df4b194 12
1e04d2bf
PC
13#include "wx/evtloop.h"
14
f5e10026
DE
15#ifndef WX_PRECOMP
16 #include "wx/log.h"
eb537cfb 17 #include "wx/app.h"
f5e10026
DE
18#endif //WX_PRECOMP
19
f5e10026 20#import <AppKit/NSApplication.h>
72ae85dd
DE
21#import <AppKit/NSEvent.h>
22#import <Foundation/NSRunLoop.h>
f5e10026 23
f5e10026 24// ========================================================================
b46b1d59 25// wxGUIEventLoop
f5e10026
DE
26// ========================================================================
27
28// ----------------------------------------------------------------------------
b46b1d59 29// wxGUIEventLoop running and exiting
f5e10026
DE
30// ----------------------------------------------------------------------------
31
c738d187 32int wxGUIEventLoop::DoRun()
f5e10026 33{
f5e10026
DE
34 [[NSApplication sharedApplication] run];
35
16d17da6
VZ
36 OnExit();
37
1df4b194 38 return m_exitcode;
f5e10026
DE
39}
40
d3ad22bd 41void wxGUIEventLoop::ScheduleExit(int rc)
f5e10026 42{
d3ad22bd 43 wxCHECK_RET( IsInsideRun(), wxT("can't call ScheduleExit() if not started") );
f5e10026 44
1df4b194 45 m_exitcode = rc;
f5e10026
DE
46
47 NSApplication *cocoaApp = [NSApplication sharedApplication];
48580976 48 wxLogTrace(wxTRACE_COCOA,wxT("wxEventLoop::Exit isRunning=%d"), (int)[cocoaApp isRunning]);
eb537cfb 49 wxTheApp->WakeUpIdle();
9670dfc4 50 /* Notes:
eb537cfb
DE
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.
9670dfc4
DE
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 */
f5e10026
DE
62 [cocoaApp stop: cocoaApp];
63}
64
65// ----------------------------------------------------------------------------
66// wxEventLoop message processing dispatching
67// ----------------------------------------------------------------------------
68
b46b1d59 69bool wxGUIEventLoop::Pending() const
f5e10026 70{
72ae85dd
DE
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];
f5e10026
DE
77}
78
b46b1d59 79bool wxGUIEventLoop::Dispatch()
f5e10026 80{
72ae85dd
DE
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
9a83f860 83 wxCHECK_MSG( IsRunning(), false, wxT("can't call Dispatch() if not running") );
72ae85dd
DE
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];
72ae85dd 93 }
1df4b194
VZ
94
95 return true;
96}
97
98int 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;
f5e10026
DE
112}
113
8d60daa8
FM
114bool 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 */
834fcdd9
FM
160 if (wxTheApp)
161 wxTheApp->ProcessPendingEvents();
8d60daa8
FM
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}