native_widget_ns_window_fullscreen_controller.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // Copyright 2022 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. #ifndef COMPONENTS_REMOTE_COCOA_APP_SHIM_NATIVE_WIDGET_NS_WINDOW_FULLSCREEN_CONTROLLER_H_
  5. #define COMPONENTS_REMOTE_COCOA_APP_SHIM_NATIVE_WIDGET_NS_WINDOW_FULLSCREEN_CONTROLLER_H_
  6. #include "base/callback_forward.h"
  7. #include "base/memory/raw_ptr.h"
  8. #include "base/memory/weak_ptr.h"
  9. #include "base/time/time.h"
  10. #include "components/remote_cocoa/app_shim/remote_cocoa_app_shim_export.h"
  11. #include "third_party/abseil-cpp/absl/types/optional.h"
  12. #include "ui/display/types/display_constants.h"
  13. #include "ui/gfx/geometry/rect.h"
  14. namespace remote_cocoa {
  15. class NativeWidgetNSWindowBridge;
  16. class REMOTE_COCOA_APP_SHIM_EXPORT NativeWidgetNSWindowFullscreenController {
  17. public:
  18. class Client {
  19. public:
  20. // Called when a transition between fullscreen and windowed (or vice-versa).
  21. // If `is_target_fullscreen` is true, then the target of the transition is
  22. // fullscreen.
  23. virtual void FullscreenControllerTransitionStart(
  24. bool is_target_fullscreen) = 0;
  25. // Called when a transition between fullscreen and windowed is complete.
  26. // If `is_fullscreen` is true, then the window is now fullscreen.
  27. virtual void FullscreenControllerTransitionComplete(bool is_fullscreen) = 0;
  28. // Set the window's frame to the specified rectangle. If `animate` is true,
  29. // then animate the transition. Runs the `completion_callback` callback once
  30. // the animation is complete, or immediately when `animate` is false.
  31. virtual void FullscreenControllerSetFrame(
  32. const gfx::Rect& frame,
  33. bool animate,
  34. base::OnceCallback<void()> completion_callback) = 0;
  35. // Call -[NSWindow toggleFullscreen:].
  36. virtual void FullscreenControllerToggleFullscreen() = 0;
  37. // Call -[NSWindow close]. Note that this call may result in the caller
  38. // being destroyed.
  39. virtual void FullscreenControllerCloseWindow() = 0;
  40. // Return the display id for the display that the window is currently on.
  41. virtual int64_t FullscreenControllerGetDisplayId() const = 0;
  42. // Return the frame that should be set prior to transitioning to fullscreen
  43. // on the display specified by `display_id`. If `display_id` is invalid,
  44. // then return an empty rectangle.
  45. virtual gfx::Rect FullscreenControllerGetFrameForDisplay(
  46. int64_t display_id) const = 0;
  47. // Get the window's current frame.
  48. virtual gfx::Rect FullscreenControllerGetFrame() const = 0;
  49. };
  50. explicit NativeWidgetNSWindowFullscreenController(Client* client);
  51. NativeWidgetNSWindowFullscreenController(
  52. const NativeWidgetNSWindowFullscreenController&) = delete;
  53. NativeWidgetNSWindowFullscreenController& operator=(
  54. const NativeWidgetNSWindowFullscreenController&) = delete;
  55. ~NativeWidgetNSWindowFullscreenController();
  56. // Called by NativeWidget::SetFullscreen.
  57. void EnterFullscreen(int64_t target_display_id);
  58. void ExitFullscreen();
  59. // Called from NativeWidgetNSWindowBridge:CloseWindow, indicating that the
  60. // window has been requested to be closed. If a transition is in progress,
  61. // then the close will be deferred until after the transition completes.
  62. void OnWindowWantsToClose();
  63. // Return true if an active transition has caused closing of the window to be
  64. // deferred.
  65. bool HasDeferredWindowClose() const { return has_deferred_window_close_; }
  66. // Called by NativeWidgetNSWindowBridge::OnWindowWillClose.
  67. void OnWindowWillClose();
  68. // Called by -[NSWindowDelegate windowWill/DidEnter/ExitFullScreen:].
  69. void OnWindowWillEnterFullscreen();
  70. void OnWindowDidEnterFullscreen();
  71. void OnWindowWillExitFullscreen();
  72. void OnWindowDidExitFullscreen();
  73. // Return false unless the state is kWindowed or kFullscreen.
  74. bool IsInFullscreenTransition() const;
  75. // Return true if the window can be resized. The window cannot be resized
  76. // while fullscreen or during a transition.
  77. bool CanResize() const;
  78. // Return the fullscreen state that will be arrived at when all transition
  79. // is done.
  80. bool GetTargetFullscreenState() const;
  81. private:
  82. enum class State {
  83. // In windowed mode.
  84. kWindowed,
  85. // Moving the window to the target display on which it will go fullscreen.
  86. kWindowedMovingToFullscreenTarget,
  87. // In transition to enter fullscreen mode. This encompases the following
  88. // states:
  89. // - From the kWindowed state, a task for ToggleFullscreen has been
  90. // posted.
  91. // - OnWindowWillEnterFullscreen has been called (either as a result of
  92. // ToggleFullscreen, or as a result of user interaction), but neither
  93. // OnWindowDidEnterFullscreen nor OnWindowDidExitFullscreen have been
  94. // called yet.
  95. kEnterFullscreenTransition,
  96. // In fullscreen mode.
  97. kFullscreen,
  98. // In transition to exit fullscreen mode. This encompases the following
  99. // states:
  100. // - From the kFullscreen state, a task for ToggleFullscreen has been
  101. // posted.
  102. // - OnWindowWillExitFullscreen has been called (either as a result of
  103. // ToggleFullscreen, or as a result of user interaction), but neither
  104. // OnWindowDidExitFullscreen nor OnWindowDidEnterFullscreen have been
  105. // called yet.
  106. kExitFullscreenTransition,
  107. // Moving the window back to its original position from before it entered
  108. // fullscreen.
  109. kWindowedRestoringOriginalFrame,
  110. // The window has been closed.
  111. kClosed,
  112. };
  113. struct PendingState {
  114. bool is_fullscreen = false;
  115. int64_t display_id = display::kInvalidDisplayId;
  116. };
  117. // Move the window to `target_display_id`, and then post a task to go
  118. // fullscreen.
  119. void MoveToTargetDisplayThenToggleFullscreen(int64_t target_display_id);
  120. // Set the window's frame back to `windowed_frame_`, and then return to
  121. // the kWindowed state.
  122. void RestoreWindowedFrame();
  123. // Helper function wrapping -[NSWindow toggleFullscreen:].
  124. void ToggleFullscreen();
  125. // If not currently in transition, consume `pending_state_` and start a
  126. // transition to the state it specifies.
  127. void HandlePendingState();
  128. // If there exists a deferred close, then close the window, set the
  129. // current state to kClosed, and return true.
  130. bool HandleDeferredClose();
  131. // Set `state` to `new_state`, and invalidate any posted tasks. Posted tasks
  132. // exist to transition from the current state to a new state, and so if the
  133. // current state changes, then those tasks are no longer applicable.
  134. void SetStateAndCancelPostedTasks(State new_state);
  135. State state_ = State::kWindowed;
  136. // If a call to EnterFullscreen or ExitFullscreen happens during a
  137. // transition, then that final requested state is stored in `pending_state_`.
  138. absl::optional<PendingState> pending_state_;
  139. // If we call setFrame while in fullscreen transitions, then we will need to
  140. // restore the original window frame when we return to windowed mode. We save
  141. // that original frame in `windowed_frame_`, and set set
  142. // `restore_windowed_frame_` to true if we call setFrame.
  143. bool restore_windowed_frame_ = false;
  144. absl::optional<gfx::Rect> windowed_frame_;
  145. // Trying to close an NSWindow during a fullscreen transition will cause the
  146. // window to lock up. Use this to track if CloseWindow was called during a
  147. // fullscreen transition, to defer the -[NSWindow close] call until the
  148. // transition is complete.
  149. // https://crbug.com/945237
  150. bool has_deferred_window_close_ = false;
  151. // Weak, owns `this`.
  152. const raw_ptr<Client> client_;
  153. base::WeakPtrFactory<NativeWidgetNSWindowFullscreenController> weak_factory_{
  154. this};
  155. };
  156. } // namespace remote_cocoa
  157. #endif // COMPONENTS_REMOTE_COCOA_APP_SHIM_NATIVE_WIDGET_NS_WINDOW_FULLSCREEN_CONTROLLER_H_