blob: 381acbfb6c62eb9d1a6e1d00dd9ab30658624644 [file] [log] [blame]
[email protected]96c9ea12008-09-23 21:08:281// Copyright (c) 2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// The basis for all native run loops on the Mac is the CFRunLoop. It can be
6// used directly, it can be used as the driving force behind the similar
7// Foundation NSRunLoop, and it can be used to implement higher-level event
8// loops such as the NSApplication event loop.
9//
10// This file introduces a basic CFRunLoop-based implementation of the
11// MessagePump interface called CFRunLoopBase. CFRunLoopBase contains all
12// of the machinery necessary to dispatch events to a delegate, but does not
13// implement the specific run loop. Concrete subclasses must provide their
14// own DoRun and Quit implementations.
15//
16// A concrete subclass that just runs a CFRunLoop loop is provided in
17// MessagePumpCFRunLoop. For an NSRunLoop, the similar MessagePumpNSRunLoop
18// is provided.
19//
20// For the application's event loop, an implementation based on AppKit's
21// NSApplication event system is provided in MessagePumpNSApplication.
22//
23// Typically, MessagePumpNSApplication only makes sense on a Cocoa
24// application's main thread. If a CFRunLoop-based message pump is needed on
25// any other thread, one of the other concrete subclasses is preferrable.
26// MessagePumpMac::Create is defined, which returns a new NSApplication-based
27// or NSRunLoop-based MessagePump subclass depending on which thread it is
28// called on.
29
30#ifndef BASE_MESSAGE_PUMP_MAC_H_
31#define BASE_MESSAGE_PUMP_MAC_H_
32
33#include "base/message_pump.h"
34
35#include <CoreFoundation/CoreFoundation.h>
36
[email protected]96c9ea12008-09-23 21:08:2837namespace base {
38
[email protected]7b38a2f2009-03-16 20:02:4239class Time;
40
[email protected]96c9ea12008-09-23 21:08:2841class MessagePumpCFRunLoopBase : public MessagePump {
42 public:
43 MessagePumpCFRunLoopBase();
44 virtual ~MessagePumpCFRunLoopBase();
45
46 // Subclasses should implement the work they need to do in MessagePump::Run
47 // in the DoRun method. MessagePumpCFRunLoopBase::Run calls DoRun directly.
48 // This arrangement is used because MessagePumpCFRunLoopBase needs to set
49 // up and tear down things before and after the "meat" of DoRun.
50 virtual void Run(Delegate* delegate);
51 virtual void DoRun(Delegate* delegate) = 0;
52
53 virtual void ScheduleWork();
54 virtual void ScheduleDelayedWork(const Time& delayed_work_time);
55
56 protected:
[email protected]8670fe5e2009-10-22 01:47:4957 // Accessors for private data members to be used by subclasses.
58 CFRunLoopRef run_loop() const { return run_loop_; }
59 int nesting_level() const { return nesting_level_; }
60 int run_nesting_level() const { return run_nesting_level_; }
[email protected]c83d0102009-10-13 13:51:1961
[email protected]96c9ea12008-09-23 21:08:2862 private:
63 // Timer callback scheduled by ScheduleDelayedWork. This does not do any
64 // work, but it signals delayed_work_source_ so that delayed work can be
65 // performed within the appropriate priority constraints.
66 static void RunDelayedWorkTimer(CFRunLoopTimerRef timer, void* info);
67
68 // Perform highest-priority work. This is associated with work_source_
[email protected]c4280a92009-06-25 19:23:1169 // signalled by ScheduleWork. The static method calls the instance method;
70 // the instance method returns true if work was done.
71 static void RunWorkSource(void* info);
72 bool RunWork();
[email protected]96c9ea12008-09-23 21:08:2873
74 // Perform delayed-priority work. This is associated with
75 // delayed_work_source_ signalled by RunDelayedWorkTimer, and is responsible
[email protected]c4280a92009-06-25 19:23:1176 // for calling ScheduleDelayedWork again if appropriate. The static method
77 // calls the instance method; the instance method returns true if more
78 // delayed work is available.
79 static void RunDelayedWorkSource(void* info);
80 bool RunDelayedWork();
81
82 // Perform idle-priority work. This is normally called by PreWaitObserver,
83 // but is also associated with idle_work_source_. When this function
84 // actually does perform idle work, it will resignal that source. The
85 // static method calls the instance method; the instance method returns
86 // true if idle work was done.
87 static void RunIdleWorkSource(void* info);
88 bool RunIdleWork();
89
90 // Perform work that may have been deferred because it was not runnable
91 // within a nested run loop. This is associated with
[email protected]8670fe5e2009-10-22 01:47:4992 // nesting_deferred_work_source_ and is signalled by
93 // MaybeScheduleNestingDeferredWork when returning from a nested loop,
94 // so that an outer loop will be able to perform the necessary tasks if it
95 // permits nestable tasks.
[email protected]c4280a92009-06-25 19:23:1196 static void RunNestingDeferredWorkSource(void* info);
97 bool RunNestingDeferredWork();
[email protected]96c9ea12008-09-23 21:08:2898
[email protected]8670fe5e2009-10-22 01:47:4999 // Schedules possible nesting-deferred work to be processed before the run
[email protected]af87d5b02009-10-22 16:18:03100 // loop goes to sleep, exits, or begins processing sources at the top of its
101 // loop. If this function detects that a nested loop had run since the
102 // previous attempt to schedule nesting-deferred work, it will schedule a
103 // call to RunNestingDeferredWorkSource.
[email protected]8670fe5e2009-10-22 01:47:49104 void MaybeScheduleNestingDeferredWork();
105
[email protected]96c9ea12008-09-23 21:08:28106 // Observer callback responsible for performing idle-priority work, before
107 // the run loop goes to sleep. Associated with idle_work_observer_.
[email protected]c4280a92009-06-25 19:23:11108 static void PreWaitObserver(CFRunLoopObserverRef observer,
109 CFRunLoopActivity activity, void* info);
[email protected]96c9ea12008-09-23 21:08:28110
[email protected]af87d5b02009-10-22 16:18:03111 // Observer callback called before the run loop processes any sources.
112 // Associated with pre_source_observer_.
113 static void PreSourceObserver(CFRunLoopObserverRef observer,
114 CFRunLoopActivity activity, void* info);
115
[email protected]c4280a92009-06-25 19:23:11116 // Observer callback called when the run loop starts and stops, at the
117 // beginning and end of calls to CFRunLoopRun. This is used to maintain
118 // nesting_level_. Associated with enter_exit_observer_.
119 static void EnterExitObserver(CFRunLoopObserverRef observer,
120 CFRunLoopActivity activity, void* info);
121
122 // Called by EnterExitObserver after performing maintenance on nesting_level_.
123 // This allows subclasses an opportunity to perform additional processing on
124 // the basis of run loops starting and stopping.
125 virtual void EnterExitRunLoop(CFRunLoopActivity activity);
126
[email protected]8670fe5e2009-10-22 01:47:49127 // The thread's run loop.
128 CFRunLoopRef run_loop_;
129
[email protected]c4280a92009-06-25 19:23:11130 // The timer, sources, and observers are described above alongside their
[email protected]96c9ea12008-09-23 21:08:28131 // callbacks.
132 CFRunLoopTimerRef delayed_work_timer_;
133 CFRunLoopSourceRef work_source_;
134 CFRunLoopSourceRef delayed_work_source_;
[email protected]c4280a92009-06-25 19:23:11135 CFRunLoopSourceRef idle_work_source_;
136 CFRunLoopSourceRef nesting_deferred_work_source_;
137 CFRunLoopObserverRef pre_wait_observer_;
[email protected]af87d5b02009-10-22 16:18:03138 CFRunLoopObserverRef pre_source_observer_;
[email protected]c4280a92009-06-25 19:23:11139 CFRunLoopObserverRef enter_exit_observer_;
[email protected]96c9ea12008-09-23 21:08:28140
141 // (weak) Delegate passed as an argument to the innermost Run call.
142 Delegate* delegate_;
143
[email protected]8670fe5e2009-10-22 01:47:49144 // The recursion depth of the currently-executing CFRunLoopRun loop on the
145 // run loop's thread. 0 if no run loops are running inside of whatever scope
146 // the object was created in.
147 int nesting_level_;
148
149 // The recursion depth (calculated in the same way as nesting_level_) of the
150 // innermost executing CFRunLoopRun loop started by a call to Run.
151 int run_nesting_level_;
152
153 // The deepest (numerically highest) recursion depth encountered since the
154 // most recent attempt to run nesting-deferred work.
155 int deepest_nesting_level_;
156
[email protected]c83275b2009-07-15 19:57:38157 // "Delegateless" work flags are set when work is ready to be performed but
158 // must wait until a delegate is available to process it. This can happen
159 // when a MessagePumpCFRunLoopBase is instantiated and work arrives without
160 // any call to Run on the stack. The Run method will check for delegateless
161 // work on entry and redispatch it as needed once a delegate is available.
162 bool delegateless_work_;
163 bool delegateless_delayed_work_;
164 bool delegateless_idle_work_;
165
[email protected]96c9ea12008-09-23 21:08:28166 DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoopBase);
167};
168
169class MessagePumpCFRunLoop : public MessagePumpCFRunLoopBase {
170 public:
171 MessagePumpCFRunLoop();
[email protected]96c9ea12008-09-23 21:08:28172
173 virtual void DoRun(Delegate* delegate);
174 virtual void Quit();
175
176 private:
[email protected]c4280a92009-06-25 19:23:11177 virtual void EnterExitRunLoop(CFRunLoopActivity activity);
[email protected]96c9ea12008-09-23 21:08:28178
[email protected]96c9ea12008-09-23 21:08:28179 // True if Quit is called to stop the innermost MessagePump
180 // (innermost_quittable_) but some other CFRunLoopRun loop (nesting_level_)
181 // is running inside the MessagePump's innermost Run call.
182 bool quit_pending_;
183
184 DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoop);
185};
186
187class MessagePumpNSRunLoop : public MessagePumpCFRunLoopBase {
188 public:
189 MessagePumpNSRunLoop();
190 virtual ~MessagePumpNSRunLoop();
191
192 virtual void DoRun(Delegate* delegate);
193 virtual void Quit();
194
195 private:
196 // A source that doesn't do anything but provide something signalable
197 // attached to the run loop. This source will be signalled when Quit
198 // is called, to cause the loop to wake up so that it can stop.
199 CFRunLoopSourceRef quit_source_;
200
201 // False after Quit is called.
202 bool keep_running_;
203
204 DISALLOW_COPY_AND_ASSIGN(MessagePumpNSRunLoop);
205};
206
207class MessagePumpNSApplication : public MessagePumpCFRunLoopBase {
208 public:
209 MessagePumpNSApplication();
210
211 virtual void DoRun(Delegate* delegate);
212 virtual void Quit();
213
214 private:
215 // False after Quit is called.
216 bool keep_running_;
217
218 // True if DoRun is managing its own run loop as opposed to letting
219 // -[NSApplication run] handle it. The outermost run loop in the application
220 // is managed by -[NSApplication run], inner run loops are handled by a loop
221 // in DoRun.
222 bool running_own_loop_;
223
224 DISALLOW_COPY_AND_ASSIGN(MessagePumpNSApplication);
225};
226
227class MessagePumpMac {
228 public:
229 // Returns a new instance of MessagePumpNSApplication if called on the main
230 // thread. Otherwise, returns a new instance of MessagePumpNSRunLoop.
231 static MessagePump* Create();
232
233 private:
234 DISALLOW_IMPLICIT_CONSTRUCTORS(MessagePumpMac);
235};
236
237} // namespace base
238
239#endif // BASE_MESSAGE_PUMP_MAC_H_