| // 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_ |