1 // Copyright (c) 2012 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_LOOP_MESSAGE_PUMP_MAC_H_ 31 #define BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_ 32 33 #include "base/message_loop/message_pump.h" 34 35 #include "base/basictypes.h" 36 37 #include <CoreFoundation/CoreFoundation.h> 38 39 #include "base/memory/weak_ptr.h" 40 #include "base/message_loop/timer_slack.h" 41 42 #if defined(__OBJC__) 43 #if defined(OS_IOS) 44 #import <Foundation/Foundation.h> 45 #else 46 #import <AppKit/AppKit.h> 47 48 // Clients must subclass NSApplication and implement this protocol if they use 49 // MessagePumpMac. 50 @protocol CrAppProtocol 51 // Must return true if -[NSApplication sendEvent:] is currently on the stack. 52 // See the comment for |CreateAutoreleasePool()| in the cc file for why this is 53 // necessary. 54 - (BOOL)isHandlingSendEvent; 55 @end 56 #endif // !defined(OS_IOS) 57 #endif // defined(__OBJC__) 58 59 namespace base { 60 61 class MessagePumpInstrumentation; 62 class RunLoop; 63 class TimeTicks; 64 65 // AutoreleasePoolType is a proxy type for autorelease pools. Its definition 66 // depends on the translation unit (TU) in which this header appears. In pure 67 // C++ TUs, it is defined as a forward C++ class declaration (that is never 68 // defined), because autorelease pools are an Objective-C concept. In Automatic 69 // Reference Counting (ARC) Objective-C TUs, it is similarly defined as a 70 // forward C++ class declaration, because clang will not allow the type 71 // "NSAutoreleasePool" in such TUs. Finally, in Manual Retain Release (MRR) 72 // Objective-C TUs, it is a type alias for NSAutoreleasePool. In all cases, a 73 // method that takes or returns an NSAutoreleasePool* can use 74 // AutoreleasePoolType* instead. 75 #if !defined(__OBJC__) || __has_feature(objc_arc) 76 class AutoreleasePoolType; 77 #else // !defined(__OBJC__) || __has_feature(objc_arc) 78 typedef NSAutoreleasePool AutoreleasePoolType; 79 #endif // !defined(__OBJC__) || __has_feature(objc_arc) 80 81 class MessagePumpCFRunLoopBase : public MessagePump { 82 // Needs access to CreateAutoreleasePool. 83 friend class MessagePumpScopedAutoreleasePool; 84 public: 85 MessagePumpCFRunLoopBase(); 86 virtual ~MessagePumpCFRunLoopBase(); 87 88 // Subclasses should implement the work they need to do in MessagePump::Run 89 // in the DoRun method. MessagePumpCFRunLoopBase::Run calls DoRun directly. 90 // This arrangement is used because MessagePumpCFRunLoopBase needs to set 91 // up and tear down things before and after the "meat" of DoRun. 92 virtual void Run(Delegate* delegate) OVERRIDE; 93 virtual void DoRun(Delegate* delegate) = 0; 94 95 virtual void ScheduleWork() OVERRIDE; 96 virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE; 97 virtual void SetTimerSlack(TimerSlack timer_slack) OVERRIDE; 98 99 protected: 100 // Accessors for private data members to be used by subclasses. run_loop()101 CFRunLoopRef run_loop() const { return run_loop_; } nesting_level()102 int nesting_level() const { return nesting_level_; } run_nesting_level()103 int run_nesting_level() const { return run_nesting_level_; } 104 105 // Sets this pump's delegate. Signals the appropriate sources if 106 // |delegateless_work_| is true. |delegate| can be NULL. 107 void SetDelegate(Delegate* delegate); 108 109 // Return an autorelease pool to wrap around any work being performed. 110 // In some cases, CreateAutoreleasePool may return nil intentionally to 111 // preventing an autorelease pool from being created, allowing any 112 // objects autoreleased by work to fall into the current autorelease pool. 113 virtual AutoreleasePoolType* CreateAutoreleasePool(); 114 115 // Enables instrumentation of the MessagePump. See MessagePumpInstrumentation 116 // in the implementation for details. 117 void EnableInstrumentation(); 118 WeakPtr<MessagePumpInstrumentation> instrumentation_; 119 120 private: 121 // Timer callback scheduled by ScheduleDelayedWork. This does not do any 122 // work, but it signals work_source_ so that delayed work can be performed 123 // within the appropriate priority constraints. 124 static void RunDelayedWorkTimer(CFRunLoopTimerRef timer, void* info); 125 126 // Perform highest-priority work. This is associated with work_source_ 127 // signalled by ScheduleWork or RunDelayedWorkTimer. The static method calls 128 // the instance method; the instance method returns true if it resignalled 129 // work_source_ to be called again from the loop. 130 static void RunWorkSource(void* info); 131 bool RunWork(); 132 133 // Perform idle-priority work. This is normally called by 134 // StartOrEndWaitObserver, but is also associated with idle_work_source_. When 135 // this function actually does perform idle work, it will resignal that 136 // source. The static method calls the instance method; the instance method 137 // returns true if idle work was done. 138 static void RunIdleWorkSource(void* info); 139 bool RunIdleWork(); 140 141 // Perform work that may have been deferred because it was not runnable 142 // within a nested run loop. This is associated with 143 // nesting_deferred_work_source_ and is signalled by 144 // MaybeScheduleNestingDeferredWork when returning from a nested loop, 145 // so that an outer loop will be able to perform the necessary tasks if it 146 // permits nestable tasks. 147 static void RunNestingDeferredWorkSource(void* info); 148 bool RunNestingDeferredWork(); 149 150 // Schedules possible nesting-deferred work to be processed before the run 151 // loop goes to sleep, exits, or begins processing sources at the top of its 152 // loop. If this function detects that a nested loop had run since the 153 // previous attempt to schedule nesting-deferred work, it will schedule a 154 // call to RunNestingDeferredWorkSource. 155 void MaybeScheduleNestingDeferredWork(); 156 157 // Observer callback responsible for performing idle-priority work, before 158 // the run loop goes to sleep. Associated with idle_work_observer_. 159 static void StartOrEndWaitObserver(CFRunLoopObserverRef observer, 160 CFRunLoopActivity activity, void* info); 161 162 // Observer callback called before the run loop processes any sources. 163 // Associated with pre_source_observer_. 164 static void PreSourceObserver(CFRunLoopObserverRef observer, 165 CFRunLoopActivity activity, void* info); 166 167 // Observer callback called when the run loop starts and stops, at the 168 // beginning and end of calls to CFRunLoopRun. This is used to maintain 169 // nesting_level_. Associated with enter_exit_observer_. 170 static void EnterExitObserver(CFRunLoopObserverRef observer, 171 CFRunLoopActivity activity, void* info); 172 173 // Called by EnterExitObserver after performing maintenance on nesting_level_. 174 // This allows subclasses an opportunity to perform additional processing on 175 // the basis of run loops starting and stopping. 176 virtual void EnterExitRunLoop(CFRunLoopActivity activity); 177 178 // The thread's run loop. 179 CFRunLoopRef run_loop_; 180 181 // The timer, sources, and observers are described above alongside their 182 // callbacks. 183 CFRunLoopTimerRef delayed_work_timer_; 184 CFRunLoopSourceRef work_source_; 185 CFRunLoopSourceRef idle_work_source_; 186 CFRunLoopSourceRef nesting_deferred_work_source_; 187 CFRunLoopObserverRef pre_wait_observer_; 188 CFRunLoopObserverRef pre_source_observer_; 189 CFRunLoopObserverRef enter_exit_observer_; 190 191 // (weak) Delegate passed as an argument to the innermost Run call. 192 Delegate* delegate_; 193 194 // The time that delayed_work_timer_ is scheduled to fire. This is tracked 195 // independently of CFRunLoopTimerGetNextFireDate(delayed_work_timer_) 196 // to be able to reset the timer properly after waking from system sleep. 197 // See PowerStateNotification. 198 CFAbsoluteTime delayed_work_fire_time_; 199 200 base::TimerSlack timer_slack_; 201 202 // The recursion depth of the currently-executing CFRunLoopRun loop on the 203 // run loop's thread. 0 if no run loops are running inside of whatever scope 204 // the object was created in. 205 int nesting_level_; 206 207 // The recursion depth (calculated in the same way as nesting_level_) of the 208 // innermost executing CFRunLoopRun loop started by a call to Run. 209 int run_nesting_level_; 210 211 // The deepest (numerically highest) recursion depth encountered since the 212 // most recent attempt to run nesting-deferred work. 213 int deepest_nesting_level_; 214 215 // "Delegateless" work flags are set when work is ready to be performed but 216 // must wait until a delegate is available to process it. This can happen 217 // when a MessagePumpCFRunLoopBase is instantiated and work arrives without 218 // any call to Run on the stack. The Run method will check for delegateless 219 // work on entry and redispatch it as needed once a delegate is available. 220 bool delegateless_work_; 221 bool delegateless_idle_work_; 222 223 DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoopBase); 224 }; 225 226 class BASE_EXPORT MessagePumpCFRunLoop : public MessagePumpCFRunLoopBase { 227 public: 228 MessagePumpCFRunLoop(); 229 virtual ~MessagePumpCFRunLoop(); 230 231 virtual void DoRun(Delegate* delegate) OVERRIDE; 232 virtual void Quit() OVERRIDE; 233 234 private: 235 virtual void EnterExitRunLoop(CFRunLoopActivity activity) OVERRIDE; 236 237 // True if Quit is called to stop the innermost MessagePump 238 // (innermost_quittable_) but some other CFRunLoopRun loop (nesting_level_) 239 // is running inside the MessagePump's innermost Run call. 240 bool quit_pending_; 241 242 DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoop); 243 }; 244 245 class BASE_EXPORT MessagePumpNSRunLoop : public MessagePumpCFRunLoopBase { 246 public: 247 MessagePumpNSRunLoop(); 248 virtual ~MessagePumpNSRunLoop(); 249 250 virtual void DoRun(Delegate* delegate) OVERRIDE; 251 virtual void Quit() OVERRIDE; 252 253 private: 254 // A source that doesn't do anything but provide something signalable 255 // attached to the run loop. This source will be signalled when Quit 256 // is called, to cause the loop to wake up so that it can stop. 257 CFRunLoopSourceRef quit_source_; 258 259 // False after Quit is called. 260 bool keep_running_; 261 262 DISALLOW_COPY_AND_ASSIGN(MessagePumpNSRunLoop); 263 }; 264 265 #if defined(OS_IOS) 266 // This is a fake message pump. It attaches sources to the main thread's 267 // CFRunLoop, so PostTask() will work, but it is unable to drive the loop 268 // directly, so calling Run() or Quit() are errors. 269 class MessagePumpUIApplication : public MessagePumpCFRunLoopBase { 270 public: 271 MessagePumpUIApplication(); 272 virtual ~MessagePumpUIApplication(); 273 virtual void DoRun(Delegate* delegate) OVERRIDE; 274 virtual void Quit() OVERRIDE; 275 276 // This message pump can not spin the main message loop directly. Instead, 277 // call |Attach()| to set up a delegate. It is an error to call |Run()|. 278 virtual void Attach(Delegate* delegate); 279 280 private: 281 RunLoop* run_loop_; 282 283 DISALLOW_COPY_AND_ASSIGN(MessagePumpUIApplication); 284 }; 285 286 #else 287 288 class MessagePumpNSApplication : public MessagePumpCFRunLoopBase { 289 public: 290 MessagePumpNSApplication(); 291 virtual ~MessagePumpNSApplication(); 292 293 virtual void DoRun(Delegate* delegate) OVERRIDE; 294 virtual void Quit() OVERRIDE; 295 296 private: 297 // False after Quit is called. 298 bool keep_running_; 299 300 // True if DoRun is managing its own run loop as opposed to letting 301 // -[NSApplication run] handle it. The outermost run loop in the application 302 // is managed by -[NSApplication run], inner run loops are handled by a loop 303 // in DoRun. 304 bool running_own_loop_; 305 306 DISALLOW_COPY_AND_ASSIGN(MessagePumpNSApplication); 307 }; 308 309 class MessagePumpCrApplication : public MessagePumpNSApplication { 310 public: 311 MessagePumpCrApplication(); 312 virtual ~MessagePumpCrApplication(); 313 314 protected: 315 // Returns nil if NSApp is currently in the middle of calling 316 // -sendEvent. Requires NSApp implementing CrAppProtocol. 317 virtual AutoreleasePoolType* CreateAutoreleasePool() OVERRIDE; 318 319 private: 320 DISALLOW_COPY_AND_ASSIGN(MessagePumpCrApplication); 321 }; 322 #endif // !defined(OS_IOS) 323 324 class BASE_EXPORT MessagePumpMac { 325 public: 326 // If not on the main thread, returns a new instance of 327 // MessagePumpNSRunLoop. 328 // 329 // On the main thread, if NSApp exists and conforms to 330 // CrAppProtocol, creates an instances of MessagePumpCrApplication. 331 // 332 // Otherwise creates an instance of MessagePumpNSApplication using a 333 // default NSApplication. 334 static MessagePump* Create(); 335 336 #if !defined(OS_IOS) 337 // If a pump is created before the required CrAppProtocol is 338 // created, the wrong MessagePump subclass could be used. 339 // UsingCrApp() returns false if the message pump was created before 340 // NSApp was initialized, or if NSApp does not implement 341 // CrAppProtocol. NSApp must be initialized before calling. 342 static bool UsingCrApp(); 343 344 // Wrapper to query -[NSApp isHandlingSendEvent] from C++ code. 345 // Requires NSApp to implement CrAppProtocol. 346 static bool IsHandlingSendEvent(); 347 #endif // !defined(OS_IOS) 348 349 private: 350 DISALLOW_IMPLICIT_CONSTRUCTORS(MessagePumpMac); 351 }; 352 353 // Tasks posted to the message loop are posted under this mode, as well 354 // as kCFRunLoopCommonModes. 355 extern const CFStringRef BASE_EXPORT kMessageLoopExclusiveRunLoopMode; 356 357 } // namespace base 358 359 #endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_ 360