message_pump_mac.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  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. // The basis for all native run loops on the Mac is the CFRunLoop. It can be
  5. // used directly, it can be used as the driving force behind the similar
  6. // Foundation NSRunLoop, and it can be used to implement higher-level event
  7. // loops such as the NSApplication event loop.
  8. //
  9. // This file introduces a basic CFRunLoop-based implementation of the
  10. // MessagePump interface called CFRunLoopBase. CFRunLoopBase contains all
  11. // of the machinery necessary to dispatch events to a delegate, but does not
  12. // implement the specific run loop. Concrete subclasses must provide their
  13. // own DoRun and DoQuit implementations.
  14. //
  15. // A concrete subclass that just runs a CFRunLoop loop is provided in
  16. // MessagePumpCFRunLoop. For an NSRunLoop, the similar MessagePumpNSRunLoop
  17. // is provided.
  18. //
  19. // For the application's event loop, an implementation based on AppKit's
  20. // NSApplication event system is provided in MessagePumpNSApplication.
  21. //
  22. // Typically, MessagePumpNSApplication only makes sense on a Cocoa
  23. // application's main thread. If a CFRunLoop-based message pump is needed on
  24. // any other thread, one of the other concrete subclasses is preferable.
  25. // MessagePumpMac::Create is defined, which returns a new NSApplication-based
  26. // or NSRunLoop-based MessagePump subclass depending on which thread it is
  27. // called on.
  28. #ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_
  29. #define BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_
  30. #include "base/message_loop/message_pump.h"
  31. #include <CoreFoundation/CoreFoundation.h>
  32. #include "base/macros.h"
  33. #include "base/message_loop/timer_slack.h"
  34. #include "build/build_config.h"
  35. #if defined(__OBJC__)
  36. #if defined(OS_IOS)
  37. #import <Foundation/Foundation.h>
  38. #else
  39. #import <AppKit/AppKit.h>
  40. // Clients must subclass NSApplication and implement this protocol if they use
  41. // MessagePumpMac.
  42. @protocol CrAppProtocol
  43. // Must return true if -[NSApplication sendEvent:] is currently on the stack.
  44. // See the comment for |CreateAutoreleasePool()| in the cc file for why this is
  45. // necessary.
  46. - (BOOL)isHandlingSendEvent;
  47. @end
  48. #endif // !defined(OS_IOS)
  49. #endif // defined(__OBJC__)
  50. namespace base {
  51. class RunLoop;
  52. class TimeTicks;
  53. // AutoreleasePoolType is a proxy type for autorelease pools. Its definition
  54. // depends on the translation unit (TU) in which this header appears. In pure
  55. // C++ TUs, it is defined as a forward C++ class declaration (that is never
  56. // defined), because autorelease pools are an Objective-C concept. In Automatic
  57. // Reference Counting (ARC) Objective-C TUs, it is similarly defined as a
  58. // forward C++ class declaration, because clang will not allow the type
  59. // "NSAutoreleasePool" in such TUs. Finally, in Manual Retain Release (MRR)
  60. // Objective-C TUs, it is a type alias for NSAutoreleasePool. In all cases, a
  61. // method that takes or returns an NSAutoreleasePool* can use
  62. // AutoreleasePoolType* instead.
  63. #if !defined(__OBJC__) || __has_feature(objc_arc)
  64. class AutoreleasePoolType;
  65. #else // !defined(__OBJC__) || __has_feature(objc_arc)
  66. typedef NSAutoreleasePool AutoreleasePoolType;
  67. #endif // !defined(__OBJC__) || __has_feature(objc_arc)
  68. class BASE_EXPORT MessagePumpCFRunLoopBase : public MessagePump {
  69. public:
  70. // MessagePump:
  71. void Run(Delegate* delegate) override;
  72. void Quit() override;
  73. void ScheduleWork() override;
  74. void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
  75. void SetTimerSlack(TimerSlack timer_slack) override;
  76. #if defined(OS_IOS)
  77. // Some iOS message pumps do not support calling |Run()| to spin the main
  78. // message loop directly. Instead, call |Attach()| to set up a delegate, then
  79. // |Detach()| before destroying the message pump. These methods do nothing if
  80. // the message pump supports calling |Run()| and |Quit()|.
  81. virtual void Attach(Delegate* delegate);
  82. virtual void Detach();
  83. #endif // OS_IOS
  84. protected:
  85. // Needs access to CreateAutoreleasePool.
  86. friend class MessagePumpScopedAutoreleasePool;
  87. friend class TestMessagePumpCFRunLoopBase;
  88. // Tasks will be pumped in the run loop modes described by
  89. // |initial_mode_mask|, which maps bits to the index of an internal array of
  90. // run loop mode identifiers.
  91. explicit MessagePumpCFRunLoopBase(int initial_mode_mask);
  92. ~MessagePumpCFRunLoopBase() override;
  93. // Subclasses should implement the work they need to do in MessagePump::Run
  94. // in the DoRun method. MessagePumpCFRunLoopBase::Run calls DoRun directly.
  95. // This arrangement is used because MessagePumpCFRunLoopBase needs to set
  96. // up and tear down things before and after the "meat" of DoRun.
  97. virtual void DoRun(Delegate* delegate) = 0;
  98. // Similar to DoRun, this allows subclasses to perform custom handling when
  99. // quitting a run loop. Return true if the quit took effect immediately;
  100. // otherwise call OnDidQuit() when the quit is actually applied (e.g., a
  101. // nested native runloop exited).
  102. virtual bool DoQuit() = 0;
  103. // Should be called by subclasses to signal when a deferred quit takes place.
  104. void OnDidQuit();
  105. // Accessors for private data members to be used by subclasses.
  106. CFRunLoopRef run_loop() const { return run_loop_; }
  107. int nesting_level() const { return nesting_level_; }
  108. int run_nesting_level() const { return run_nesting_level_; }
  109. bool keep_running() const { return keep_running_; }
  110. // Sets this pump's delegate. Signals the appropriate sources if
  111. // |delegateless_work_| is true. |delegate| can be NULL.
  112. void SetDelegate(Delegate* delegate);
  113. // Return an autorelease pool to wrap around any work being performed.
  114. // In some cases, CreateAutoreleasePool may return nil intentionally to
  115. // preventing an autorelease pool from being created, allowing any
  116. // objects autoreleased by work to fall into the current autorelease pool.
  117. virtual AutoreleasePoolType* CreateAutoreleasePool();
  118. // Enable and disable entries in |enabled_modes_| to match |mode_mask|.
  119. void SetModeMask(int mode_mask);
  120. // Get the current mode mask from |enabled_modes_|.
  121. int GetModeMask() const;
  122. private:
  123. class ScopedModeEnabler;
  124. // The maximum number of run loop modes that can be monitored.
  125. static constexpr int kNumModes = 4;
  126. // All sources of delayed work scheduling converge to this, using TimeDelta
  127. // avoids querying Now() for key callers.
  128. void ScheduleDelayedWorkImpl(TimeDelta delta);
  129. // Timer callback scheduled by ScheduleDelayedWork. This does not do any
  130. // work, but it signals |work_source_| so that delayed work can be performed
  131. // within the appropriate priority constraints.
  132. static void RunDelayedWorkTimer(CFRunLoopTimerRef timer, void* info);
  133. // Perform highest-priority work. This is associated with |work_source_|
  134. // signalled by ScheduleWork or RunDelayedWorkTimer. The static method calls
  135. // the instance method; the instance method returns true if it resignalled
  136. // |work_source_| to be called again from the loop.
  137. static void RunWorkSource(void* info);
  138. bool RunWork();
  139. // Perform idle-priority work. This is normally called by PreWaitObserver,
  140. // but is also associated with |idle_work_source_|. When this function
  141. // actually does perform idle work, it will resignal that source. The
  142. // static method calls the instance method.
  143. static void RunIdleWorkSource(void* info);
  144. void RunIdleWork();
  145. // Perform work that may have been deferred because it was not runnable
  146. // within a nested run loop. This is associated with
  147. // |nesting_deferred_work_source_| and is signalled by
  148. // MaybeScheduleNestingDeferredWork when returning from a nested loop,
  149. // so that an outer loop will be able to perform the necessary tasks if it
  150. // permits nestable tasks.
  151. static void RunNestingDeferredWorkSource(void* info);
  152. void RunNestingDeferredWork();
  153. // Schedules possible nesting-deferred work to be processed before the run
  154. // loop goes to sleep, exits, or begins processing sources at the top of its
  155. // loop. If this function detects that a nested loop had run since the
  156. // previous attempt to schedule nesting-deferred work, it will schedule a
  157. // call to RunNestingDeferredWorkSource.
  158. void MaybeScheduleNestingDeferredWork();
  159. // Observer callback responsible for performing idle-priority work, before
  160. // the run loop goes to sleep. Associated with |pre_wait_observer_|.
  161. static void PreWaitObserver(CFRunLoopObserverRef observer,
  162. CFRunLoopActivity activity, void* info);
  163. // Observer callback called before the run loop processes any sources.
  164. // Associated with |pre_source_observer_|.
  165. static void PreSourceObserver(CFRunLoopObserverRef observer,
  166. CFRunLoopActivity activity, void* info);
  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. // Called by EnterExitObserver after performing maintenance on
  173. // |nesting_level_|. This allows subclasses an opportunity to perform
  174. // additional processing on the basis of run loops starting and stopping.
  175. virtual void EnterExitRunLoop(CFRunLoopActivity activity);
  176. // The thread's run loop.
  177. CFRunLoopRef run_loop_;
  178. // The enabled modes. Posted tasks may run in any non-null entry.
  179. std::unique_ptr<ScopedModeEnabler> enabled_modes_[kNumModes];
  180. // The timer, sources, and observers are described above alongside their
  181. // callbacks.
  182. CFRunLoopTimerRef delayed_work_timer_;
  183. CFRunLoopSourceRef work_source_;
  184. CFRunLoopSourceRef idle_work_source_;
  185. CFRunLoopSourceRef nesting_deferred_work_source_;
  186. CFRunLoopObserverRef pre_wait_observer_;
  187. CFRunLoopObserverRef pre_source_observer_;
  188. CFRunLoopObserverRef enter_exit_observer_;
  189. // (weak) Delegate passed as an argument to the innermost Run call.
  190. Delegate* delegate_;
  191. base::TimerSlack timer_slack_;
  192. // The recursion depth of the currently-executing CFRunLoopRun loop on the
  193. // run loop's thread. 0 if no run loops are running inside of whatever scope
  194. // the object was created in.
  195. int nesting_level_;
  196. // The recursion depth (calculated in the same way as |nesting_level_|) of the
  197. // innermost executing CFRunLoopRun loop started by a call to Run.
  198. int run_nesting_level_;
  199. // The deepest (numerically highest) recursion depth encountered since the
  200. // most recent attempt to run nesting-deferred work.
  201. int deepest_nesting_level_;
  202. // Whether we should continue running application tasks. Set to false when
  203. // Quit() is called for the innermost run loop.
  204. bool keep_running_;
  205. // "Delegateless" work flags are set when work is ready to be performed but
  206. // must wait until a delegate is available to process it. This can happen
  207. // when a MessagePumpCFRunLoopBase is instantiated and work arrives without
  208. // any call to Run on the stack. The Run method will check for delegateless
  209. // work on entry and redispatch it as needed once a delegate is available.
  210. bool delegateless_work_;
  211. bool delegateless_idle_work_;
  212. DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoopBase);
  213. };
  214. class BASE_EXPORT MessagePumpCFRunLoop : public MessagePumpCFRunLoopBase {
  215. public:
  216. MessagePumpCFRunLoop();
  217. ~MessagePumpCFRunLoop() override;
  218. void DoRun(Delegate* delegate) override;
  219. bool DoQuit() override;
  220. private:
  221. void EnterExitRunLoop(CFRunLoopActivity activity) override;
  222. // True if Quit is called to stop the innermost MessagePump
  223. // (|innermost_quittable_|) but some other CFRunLoopRun loop
  224. // (|nesting_level_|) is running inside the MessagePump's innermost Run call.
  225. bool quit_pending_;
  226. DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoop);
  227. };
  228. class BASE_EXPORT MessagePumpNSRunLoop : public MessagePumpCFRunLoopBase {
  229. public:
  230. MessagePumpNSRunLoop();
  231. ~MessagePumpNSRunLoop() override;
  232. void DoRun(Delegate* delegate) override;
  233. bool DoQuit() override;
  234. private:
  235. // A source that doesn't do anything but provide something signalable
  236. // attached to the run loop. This source will be signalled when Quit
  237. // is called, to cause the loop to wake up so that it can stop.
  238. CFRunLoopSourceRef quit_source_;
  239. DISALLOW_COPY_AND_ASSIGN(MessagePumpNSRunLoop);
  240. };
  241. #if defined(OS_IOS)
  242. // This is a fake message pump. It attaches sources to the main thread's
  243. // CFRunLoop, so PostTask() will work, but it is unable to drive the loop
  244. // directly, so calling Run() or Quit() are errors.
  245. class MessagePumpUIApplication : public MessagePumpCFRunLoopBase {
  246. public:
  247. MessagePumpUIApplication();
  248. ~MessagePumpUIApplication() override;
  249. void DoRun(Delegate* delegate) override;
  250. bool DoQuit() override;
  251. // MessagePumpCFRunLoopBase.
  252. // MessagePumpUIApplication can not spin the main message loop directly.
  253. // Instead, call |Attach()| to set up a delegate. It is an error to call
  254. // |Run()|.
  255. void Attach(Delegate* delegate) override;
  256. void Detach() override;
  257. private:
  258. RunLoop* run_loop_;
  259. DISALLOW_COPY_AND_ASSIGN(MessagePumpUIApplication);
  260. };
  261. #else
  262. // While in scope, permits posted tasks to be run in private AppKit run loop
  263. // modes that would otherwise make the UI unresponsive. E.g., menu fade out.
  264. class BASE_EXPORT ScopedPumpMessagesInPrivateModes {
  265. public:
  266. ScopedPumpMessagesInPrivateModes();
  267. ~ScopedPumpMessagesInPrivateModes();
  268. int GetModeMaskForTest();
  269. private:
  270. DISALLOW_COPY_AND_ASSIGN(ScopedPumpMessagesInPrivateModes);
  271. };
  272. class MessagePumpNSApplication : public MessagePumpCFRunLoopBase {
  273. public:
  274. MessagePumpNSApplication();
  275. ~MessagePumpNSApplication() override;
  276. void DoRun(Delegate* delegate) override;
  277. bool DoQuit() override;
  278. private:
  279. friend class ScopedPumpMessagesInPrivateModes;
  280. void EnterExitRunLoop(CFRunLoopActivity activity) override;
  281. // True if DoRun is managing its own run loop as opposed to letting
  282. // -[NSApplication run] handle it. The outermost run loop in the application
  283. // is managed by -[NSApplication run], inner run loops are handled by a loop
  284. // in DoRun.
  285. bool running_own_loop_;
  286. // True if Quit() was called while a modal window was shown and needed to be
  287. // deferred.
  288. bool quit_pending_;
  289. DISALLOW_COPY_AND_ASSIGN(MessagePumpNSApplication);
  290. };
  291. class MessagePumpCrApplication : public MessagePumpNSApplication {
  292. public:
  293. MessagePumpCrApplication();
  294. ~MessagePumpCrApplication() override;
  295. protected:
  296. // Returns nil if NSApp is currently in the middle of calling
  297. // -sendEvent. Requires NSApp implementing CrAppProtocol.
  298. AutoreleasePoolType* CreateAutoreleasePool() override;
  299. private:
  300. DISALLOW_COPY_AND_ASSIGN(MessagePumpCrApplication);
  301. };
  302. #endif // !defined(OS_IOS)
  303. class BASE_EXPORT MessagePumpMac {
  304. public:
  305. // If not on the main thread, returns a new instance of
  306. // MessagePumpNSRunLoop.
  307. //
  308. // On the main thread, if NSApp exists and conforms to
  309. // CrAppProtocol, creates an instances of MessagePumpCrApplication.
  310. //
  311. // Otherwise creates an instance of MessagePumpNSApplication using a
  312. // default NSApplication.
  313. static std::unique_ptr<MessagePump> Create();
  314. #if !defined(OS_IOS)
  315. // If a pump is created before the required CrAppProtocol is
  316. // created, the wrong MessagePump subclass could be used.
  317. // UsingCrApp() returns false if the message pump was created before
  318. // NSApp was initialized, or if NSApp does not implement
  319. // CrAppProtocol. NSApp must be initialized before calling.
  320. static bool UsingCrApp();
  321. // Wrapper to query -[NSApp isHandlingSendEvent] from C++ code.
  322. // Requires NSApp to implement CrAppProtocol.
  323. static bool IsHandlingSendEvent();
  324. #endif // !defined(OS_IOS)
  325. private:
  326. DISALLOW_IMPLICIT_CONSTRUCTORS(MessagePumpMac);
  327. };
  328. // Tasks posted to the message loop are posted under this mode, as well
  329. // as kCFRunLoopCommonModes.
  330. extern const CFStringRef BASE_EXPORT kMessageLoopExclusiveRunLoopMode;
  331. } // namespace base
  332. #endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_