|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | // The basis for all native run loops on the Mac is the CFRunLoop.  It can be | 
|  | // used directly, it can be used as the driving force behind the similar | 
|  | // Foundation NSRunLoop, and it can be used to implement higher-level event | 
|  | // loops such as the NSApplication event loop. | 
|  | // | 
|  | // This file introduces a basic CFRunLoop-based implementation of the | 
|  | // MessagePump interface called CFRunLoopBase.  CFRunLoopBase contains all | 
|  | // of the machinery necessary to dispatch events to a delegate, but does not | 
|  | // implement the specific run loop.  Concrete subclasses must provide their | 
|  | // own DoRun and Quit implementations. | 
|  | // | 
|  | // A concrete subclass that just runs a CFRunLoop loop is provided in | 
|  | // MessagePumpCFRunLoop.  For an NSRunLoop, the similar MessagePumpNSRunLoop | 
|  | // is provided. | 
|  | // | 
|  | // For the application's event loop, an implementation based on AppKit's | 
|  | // NSApplication event system is provided in MessagePumpNSApplication. | 
|  | // | 
|  | // Typically, MessagePumpNSApplication only makes sense on a Cocoa | 
|  | // application's main thread.  If a CFRunLoop-based message pump is needed on | 
|  | // any other thread, one of the other concrete subclasses is preferable. | 
|  | // MessagePumpMac::Create is defined, which returns a new NSApplication-based | 
|  | // or NSRunLoop-based MessagePump subclass depending on which thread it is | 
|  | // called on. | 
|  |  | 
|  | #ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_ | 
|  | #define BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_ | 
|  |  | 
|  | #include "base/message_loop/message_pump.h" | 
|  |  | 
|  |  | 
|  | #include <CoreFoundation/CoreFoundation.h> | 
|  |  | 
|  | #include "base/macros.h" | 
|  | #include "base/memory/weak_ptr.h" | 
|  | #include "base/message_loop/timer_slack.h" | 
|  | #include "build/build_config.h" | 
|  |  | 
|  | #if defined(__OBJC__) | 
|  | #if defined(OS_IOS) | 
|  | #import <Foundation/Foundation.h> | 
|  | #else | 
|  | #import <AppKit/AppKit.h> | 
|  |  | 
|  | // Clients must subclass NSApplication and implement this protocol if they use | 
|  | // MessagePumpMac. | 
|  | @protocol CrAppProtocol | 
|  | // Must return true if -[NSApplication sendEvent:] is currently on the stack. | 
|  | // See the comment for |CreateAutoreleasePool()| in the cc file for why this is | 
|  | // necessary. | 
|  | - (BOOL)isHandlingSendEvent; | 
|  | @end | 
|  | #endif  // !defined(OS_IOS) | 
|  | #endif  // defined(__OBJC__) | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | class RunLoop; | 
|  | class TimeTicks; | 
|  |  | 
|  | // AutoreleasePoolType is a proxy type for autorelease pools. Its definition | 
|  | // depends on the translation unit (TU) in which this header appears. In pure | 
|  | // C++ TUs, it is defined as a forward C++ class declaration (that is never | 
|  | // defined), because autorelease pools are an Objective-C concept. In Automatic | 
|  | // Reference Counting (ARC) Objective-C TUs, it is similarly defined as a | 
|  | // forward C++ class declaration, because clang will not allow the type | 
|  | // "NSAutoreleasePool" in such TUs. Finally, in Manual Retain Release (MRR) | 
|  | // Objective-C TUs, it is a type alias for NSAutoreleasePool. In all cases, a | 
|  | // method that takes or returns an NSAutoreleasePool* can use | 
|  | // AutoreleasePoolType* instead. | 
|  | #if !defined(__OBJC__) || __has_feature(objc_arc) | 
|  | class AutoreleasePoolType; | 
|  | #else   // !defined(__OBJC__) || __has_feature(objc_arc) | 
|  | typedef NSAutoreleasePool AutoreleasePoolType; | 
|  | #endif  // !defined(__OBJC__) || __has_feature(objc_arc) | 
|  |  | 
|  | class BASE_EXPORT MessagePumpCFRunLoopBase : public MessagePump { | 
|  | public: | 
|  | // MessagePump: | 
|  | void Run(Delegate* delegate) override; | 
|  | void ScheduleWork() override; | 
|  | void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override; | 
|  | void SetTimerSlack(TimerSlack timer_slack) override; | 
|  |  | 
|  | protected: | 
|  | // Needs access to CreateAutoreleasePool. | 
|  | friend class MessagePumpScopedAutoreleasePool; | 
|  | friend class TestMessagePumpCFRunLoopBase; | 
|  |  | 
|  | // Tasks will be pumped in the run loop modes described by | 
|  | // |initial_mode_mask|, which maps bits to the index of an internal array of | 
|  | // run loop mode identifiers. | 
|  | explicit MessagePumpCFRunLoopBase(int initial_mode_mask); | 
|  | ~MessagePumpCFRunLoopBase() override; | 
|  |  | 
|  | // Subclasses should implement the work they need to do in MessagePump::Run | 
|  | // in the DoRun method.  MessagePumpCFRunLoopBase::Run calls DoRun directly. | 
|  | // This arrangement is used because MessagePumpCFRunLoopBase needs to set | 
|  | // up and tear down things before and after the "meat" of DoRun. | 
|  | virtual void DoRun(Delegate* delegate) = 0; | 
|  |  | 
|  | // Accessors for private data members to be used by subclasses. | 
|  | CFRunLoopRef run_loop() const { return run_loop_; } | 
|  | int nesting_level() const { return nesting_level_; } | 
|  | int run_nesting_level() const { return run_nesting_level_; } | 
|  |  | 
|  | // Sets this pump's delegate.  Signals the appropriate sources if | 
|  | // |delegateless_work_| is true.  |delegate| can be NULL. | 
|  | void SetDelegate(Delegate* delegate); | 
|  |  | 
|  | // Return an autorelease pool to wrap around any work being performed. | 
|  | // In some cases, CreateAutoreleasePool may return nil intentionally to | 
|  | // preventing an autorelease pool from being created, allowing any | 
|  | // objects autoreleased by work to fall into the current autorelease pool. | 
|  | virtual AutoreleasePoolType* CreateAutoreleasePool(); | 
|  |  | 
|  | // Enable and disable entries in |enabled_modes_| to match |mode_mask|. | 
|  | void SetModeMask(int mode_mask); | 
|  |  | 
|  | // Get the current mode mask from |enabled_modes_|. | 
|  | int GetModeMask() const; | 
|  |  | 
|  | private: | 
|  | class ScopedModeEnabler; | 
|  |  | 
|  | // The maximum number of run loop modes that can be monitored. | 
|  | static constexpr int kNumModes = 4; | 
|  |  | 
|  | // Marking timers as invalid at the right time helps significantly reduce | 
|  | // power use (see the comment in RunDelayedWorkTimer()), however there is no | 
|  | // public API for doing so. CFRuntime.h states that CFRuntimeBase, upon which | 
|  | // the above timer invalidation functions are based, can change from release | 
|  | // to release and should not be accessed directly (this struct last changed at | 
|  | // least in 2008 in CF-476). | 
|  | // | 
|  | // This function uses private API to modify a test timer's valid state and | 
|  | // uses public API to confirm that the private API changed the right bit. | 
|  | static bool CanInvalidateCFRunLoopTimers(); | 
|  |  | 
|  | // Sets a Core Foundation object's "invalid" bit to |valid|. Based on code | 
|  | // from CFRunLoop.c. | 
|  | static void ChromeCFRunLoopTimerSetValid(CFRunLoopTimerRef timer, bool valid); | 
|  |  | 
|  | // Timer callback scheduled by ScheduleDelayedWork.  This does not do any | 
|  | // work, but it signals work_source_ so that delayed work can be performed | 
|  | // within the appropriate priority constraints. | 
|  | static void RunDelayedWorkTimer(CFRunLoopTimerRef timer, void* info); | 
|  |  | 
|  | // Perform highest-priority work.  This is associated with work_source_ | 
|  | // signalled by ScheduleWork or RunDelayedWorkTimer.  The static method calls | 
|  | // the instance method; the instance method returns true if it resignalled | 
|  | // work_source_ to be called again from the loop. | 
|  | static void RunWorkSource(void* info); | 
|  | bool RunWork(); | 
|  |  | 
|  | // Perform idle-priority work.  This is normally called by PreWaitObserver, | 
|  | // but is also associated with idle_work_source_.  When this function | 
|  | // actually does perform idle work, it will resignal that source.  The | 
|  | // static method calls the instance method; the instance method returns | 
|  | // true if idle work was done. | 
|  | static void RunIdleWorkSource(void* info); | 
|  | bool RunIdleWork(); | 
|  |  | 
|  | // Perform work that may have been deferred because it was not runnable | 
|  | // within a nested run loop.  This is associated with | 
|  | // nesting_deferred_work_source_ and is signalled by | 
|  | // MaybeScheduleNestingDeferredWork when returning from a nested loop, | 
|  | // so that an outer loop will be able to perform the necessary tasks if it | 
|  | // permits nestable tasks. | 
|  | static void RunNestingDeferredWorkSource(void* info); | 
|  | bool RunNestingDeferredWork(); | 
|  |  | 
|  | // Schedules possible nesting-deferred work to be processed before the run | 
|  | // loop goes to sleep, exits, or begins processing sources at the top of its | 
|  | // loop.  If this function detects that a nested loop had run since the | 
|  | // previous attempt to schedule nesting-deferred work, it will schedule a | 
|  | // call to RunNestingDeferredWorkSource. | 
|  | void MaybeScheduleNestingDeferredWork(); | 
|  |  | 
|  | // Observer callback responsible for performing idle-priority work, before | 
|  | // the run loop goes to sleep.  Associated with idle_work_observer_. | 
|  | static void PreWaitObserver(CFRunLoopObserverRef observer, | 
|  | CFRunLoopActivity activity, void* info); | 
|  |  | 
|  | // Observer callback called before the run loop processes any sources. | 
|  | // Associated with pre_source_observer_. | 
|  | static void PreSourceObserver(CFRunLoopObserverRef observer, | 
|  | CFRunLoopActivity activity, void* info); | 
|  |  | 
|  | // Observer callback called when the run loop starts and stops, at the | 
|  | // beginning and end of calls to CFRunLoopRun.  This is used to maintain | 
|  | // nesting_level_.  Associated with enter_exit_observer_. | 
|  | static void EnterExitObserver(CFRunLoopObserverRef observer, | 
|  | CFRunLoopActivity activity, void* info); | 
|  |  | 
|  | // Called by EnterExitObserver after performing maintenance on nesting_level_. | 
|  | // This allows subclasses an opportunity to perform additional processing on | 
|  | // the basis of run loops starting and stopping. | 
|  | virtual void EnterExitRunLoop(CFRunLoopActivity activity); | 
|  |  | 
|  | // The thread's run loop. | 
|  | CFRunLoopRef run_loop_; | 
|  |  | 
|  | // The enabled modes. Posted tasks may run in any non-null entry. | 
|  | std::unique_ptr<ScopedModeEnabler> enabled_modes_[kNumModes]; | 
|  |  | 
|  | // The timer, sources, and observers are described above alongside their | 
|  | // callbacks. | 
|  | CFRunLoopTimerRef delayed_work_timer_; | 
|  | CFRunLoopSourceRef work_source_; | 
|  | CFRunLoopSourceRef idle_work_source_; | 
|  | CFRunLoopSourceRef nesting_deferred_work_source_; | 
|  | CFRunLoopObserverRef pre_wait_observer_; | 
|  | CFRunLoopObserverRef pre_source_observer_; | 
|  | CFRunLoopObserverRef enter_exit_observer_; | 
|  |  | 
|  | // (weak) Delegate passed as an argument to the innermost Run call. | 
|  | Delegate* delegate_; | 
|  |  | 
|  | // The time that delayed_work_timer_ is scheduled to fire.  This is tracked | 
|  | // independently of CFRunLoopTimerGetNextFireDate(delayed_work_timer_) | 
|  | // to be able to reset the timer properly after waking from system sleep. | 
|  | // See PowerStateNotification. | 
|  | CFAbsoluteTime delayed_work_fire_time_; | 
|  |  | 
|  | base::TimerSlack timer_slack_; | 
|  |  | 
|  | // The recursion depth of the currently-executing CFRunLoopRun loop on the | 
|  | // run loop's thread.  0 if no run loops are running inside of whatever scope | 
|  | // the object was created in. | 
|  | int nesting_level_; | 
|  |  | 
|  | // The recursion depth (calculated in the same way as nesting_level_) of the | 
|  | // innermost executing CFRunLoopRun loop started by a call to Run. | 
|  | int run_nesting_level_; | 
|  |  | 
|  | // The deepest (numerically highest) recursion depth encountered since the | 
|  | // most recent attempt to run nesting-deferred work. | 
|  | int deepest_nesting_level_; | 
|  |  | 
|  | // "Delegateless" work flags are set when work is ready to be performed but | 
|  | // must wait until a delegate is available to process it.  This can happen | 
|  | // when a MessagePumpCFRunLoopBase is instantiated and work arrives without | 
|  | // any call to Run on the stack.  The Run method will check for delegateless | 
|  | // work on entry and redispatch it as needed once a delegate is available. | 
|  | bool delegateless_work_; | 
|  | bool delegateless_idle_work_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoopBase); | 
|  | }; | 
|  |  | 
|  | class BASE_EXPORT MessagePumpCFRunLoop : public MessagePumpCFRunLoopBase { | 
|  | public: | 
|  | MessagePumpCFRunLoop(); | 
|  | ~MessagePumpCFRunLoop() override; | 
|  |  | 
|  | void DoRun(Delegate* delegate) override; | 
|  | void Quit() override; | 
|  |  | 
|  | private: | 
|  | void EnterExitRunLoop(CFRunLoopActivity activity) override; | 
|  |  | 
|  | // True if Quit is called to stop the innermost MessagePump | 
|  | // (innermost_quittable_) but some other CFRunLoopRun loop (nesting_level_) | 
|  | // is running inside the MessagePump's innermost Run call. | 
|  | bool quit_pending_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoop); | 
|  | }; | 
|  |  | 
|  | class BASE_EXPORT MessagePumpNSRunLoop : public MessagePumpCFRunLoopBase { | 
|  | public: | 
|  | MessagePumpNSRunLoop(); | 
|  | ~MessagePumpNSRunLoop() override; | 
|  |  | 
|  | void DoRun(Delegate* delegate) override; | 
|  | void Quit() override; | 
|  |  | 
|  | private: | 
|  | // A source that doesn't do anything but provide something signalable | 
|  | // attached to the run loop.  This source will be signalled when Quit | 
|  | // is called, to cause the loop to wake up so that it can stop. | 
|  | CFRunLoopSourceRef quit_source_; | 
|  |  | 
|  | // False after Quit is called. | 
|  | bool keep_running_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(MessagePumpNSRunLoop); | 
|  | }; | 
|  |  | 
|  | #if defined(OS_IOS) | 
|  | // This is a fake message pump.  It attaches sources to the main thread's | 
|  | // CFRunLoop, so PostTask() will work, but it is unable to drive the loop | 
|  | // directly, so calling Run() or Quit() are errors. | 
|  | class MessagePumpUIApplication : public MessagePumpCFRunLoopBase { | 
|  | public: | 
|  | MessagePumpUIApplication(); | 
|  | ~MessagePumpUIApplication() override; | 
|  | void DoRun(Delegate* delegate) override; | 
|  | void Quit() override; | 
|  |  | 
|  | // This message pump can not spin the main message loop directly.  Instead, | 
|  | // call |Attach()| to set up a delegate.  It is an error to call |Run()|. | 
|  | virtual void Attach(Delegate* delegate); | 
|  |  | 
|  | private: | 
|  | RunLoop* run_loop_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(MessagePumpUIApplication); | 
|  | }; | 
|  |  | 
|  | #else | 
|  |  | 
|  | // While in scope, permits posted tasks to be run in private AppKit run loop | 
|  | // modes that would otherwise make the UI unresponsive. E.g., menu fade out. | 
|  | class BASE_EXPORT ScopedPumpMessagesInPrivateModes { | 
|  | public: | 
|  | ScopedPumpMessagesInPrivateModes(); | 
|  | ~ScopedPumpMessagesInPrivateModes(); | 
|  |  | 
|  | int GetModeMaskForTest(); | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(ScopedPumpMessagesInPrivateModes); | 
|  | }; | 
|  |  | 
|  | class MessagePumpNSApplication : public MessagePumpCFRunLoopBase { | 
|  | public: | 
|  | MessagePumpNSApplication(); | 
|  | ~MessagePumpNSApplication() override; | 
|  |  | 
|  | void DoRun(Delegate* delegate) override; | 
|  | void Quit() override; | 
|  |  | 
|  | private: | 
|  | friend class ScopedPumpMessagesInPrivateModes; | 
|  |  | 
|  | // False after Quit is called. | 
|  | bool keep_running_; | 
|  |  | 
|  | // True if DoRun is managing its own run loop as opposed to letting | 
|  | // -[NSApplication run] handle it.  The outermost run loop in the application | 
|  | // is managed by -[NSApplication run], inner run loops are handled by a loop | 
|  | // in DoRun. | 
|  | bool running_own_loop_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(MessagePumpNSApplication); | 
|  | }; | 
|  |  | 
|  | class MessagePumpCrApplication : public MessagePumpNSApplication { | 
|  | public: | 
|  | MessagePumpCrApplication(); | 
|  | ~MessagePumpCrApplication() override; | 
|  |  | 
|  | protected: | 
|  | // Returns nil if NSApp is currently in the middle of calling | 
|  | // -sendEvent.  Requires NSApp implementing CrAppProtocol. | 
|  | AutoreleasePoolType* CreateAutoreleasePool() override; | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(MessagePumpCrApplication); | 
|  | }; | 
|  | #endif  // !defined(OS_IOS) | 
|  |  | 
|  | class BASE_EXPORT MessagePumpMac { | 
|  | public: | 
|  | // If not on the main thread, returns a new instance of | 
|  | // MessagePumpNSRunLoop. | 
|  | // | 
|  | // On the main thread, if NSApp exists and conforms to | 
|  | // CrAppProtocol, creates an instances of MessagePumpCrApplication. | 
|  | // | 
|  | // Otherwise creates an instance of MessagePumpNSApplication using a | 
|  | // default NSApplication. | 
|  | static std::unique_ptr<MessagePump> Create(); | 
|  |  | 
|  | #if !defined(OS_IOS) | 
|  | // If a pump is created before the required CrAppProtocol is | 
|  | // created, the wrong MessagePump subclass could be used. | 
|  | // UsingCrApp() returns false if the message pump was created before | 
|  | // NSApp was initialized, or if NSApp does not implement | 
|  | // CrAppProtocol.  NSApp must be initialized before calling. | 
|  | static bool UsingCrApp(); | 
|  |  | 
|  | // Wrapper to query -[NSApp isHandlingSendEvent] from C++ code. | 
|  | // Requires NSApp to implement CrAppProtocol. | 
|  | static bool IsHandlingSendEvent(); | 
|  | #endif  // !defined(OS_IOS) | 
|  |  | 
|  | private: | 
|  | DISALLOW_IMPLICIT_CONSTRUCTORS(MessagePumpMac); | 
|  | }; | 
|  |  | 
|  | // Tasks posted to the message loop are posted under this mode, as well | 
|  | // as kCFRunLoopCommonModes. | 
|  | extern const CFStringRef BASE_EXPORT kMessageLoopExclusiveRunLoopMode; | 
|  |  | 
|  | }  // namespace base | 
|  |  | 
|  | #endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_ |