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