screen_pinning_controller.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. // Copyright 2016 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. #include "ash/wm/screen_pinning_controller.h"
  5. #include <algorithm>
  6. #include <memory>
  7. #include <vector>
  8. #include "ash/public/cpp/shell_window_ids.h"
  9. #include "ash/shell.h"
  10. #include "ash/window_user_data.h"
  11. #include "ash/wm/always_on_top_controller.h"
  12. #include "ash/wm/container_finder.h"
  13. #include "ash/wm/window_dimmer.h"
  14. #include "ash/wm/window_state.h"
  15. #include "base/auto_reset.h"
  16. #include "base/logging.h"
  17. #include "ui/aura/window.h"
  18. #include "ui/aura/window_observer.h"
  19. #include "ui/compositor/layer.h"
  20. #include "ui/wm/core/window_util.h"
  21. namespace ash {
  22. namespace {
  23. // Returns a list of Windows corresponding to SystemModalContainers,
  24. // except ones whose root is shared with |pinned_window|.
  25. aura::Window::Windows GetSystemModalWindowsExceptPinned(
  26. aura::Window* pinned_window) {
  27. aura::Window* pinned_root = pinned_window->GetRootWindow();
  28. aura::Window::Windows result;
  29. for (aura::Window* system_modal :
  30. GetContainersForAllRootWindows(kShellWindowId_SystemModalContainer)) {
  31. if (system_modal->GetRootWindow() == pinned_root)
  32. continue;
  33. result.push_back(system_modal);
  34. }
  35. return result;
  36. }
  37. void AddObserverToChildren(aura::Window* container,
  38. aura::WindowObserver* observer) {
  39. for (aura::Window* child : container->children())
  40. child->AddObserver(observer);
  41. }
  42. void RemoveObserverFromChildren(aura::Window* container,
  43. aura::WindowObserver* observer) {
  44. for (aura::Window* child : container->children())
  45. child->RemoveObserver(observer);
  46. }
  47. // Returns true if the aura::Window from a WindowDimmer is visible.
  48. bool IsWindowDimmerWindowVisible(WindowDimmer* window_dimmer) {
  49. return window_dimmer->window()->layer()->GetTargetVisibility();
  50. }
  51. } // namespace
  52. // Adapter to fire OnPinnedContainerWindowStackingChanged().
  53. // TODO(oshima): Consider using aura::clinet::WindowStakingClient instead.
  54. class ScreenPinningController::PinnedContainerChildWindowObserver
  55. : public aura::WindowObserver {
  56. public:
  57. explicit PinnedContainerChildWindowObserver(
  58. ScreenPinningController* controller)
  59. : controller_(controller) {}
  60. PinnedContainerChildWindowObserver(
  61. const PinnedContainerChildWindowObserver&) = delete;
  62. PinnedContainerChildWindowObserver& operator=(
  63. const PinnedContainerChildWindowObserver&) = delete;
  64. void OnWindowStackingChanged(aura::Window* window) override {
  65. controller_->OnPinnedContainerWindowStackingChanged(window);
  66. }
  67. private:
  68. ScreenPinningController* controller_;
  69. };
  70. // Adapter to translate OnWindowAdded/OnWillRemoveWindow for the container
  71. // containing the pinned window, to the corresponding controller's methods.
  72. class ScreenPinningController::PinnedContainerWindowObserver
  73. : public aura::WindowObserver {
  74. public:
  75. explicit PinnedContainerWindowObserver(ScreenPinningController* controller)
  76. : controller_(controller) {}
  77. PinnedContainerWindowObserver(const PinnedContainerWindowObserver&) = delete;
  78. PinnedContainerWindowObserver& operator=(
  79. const PinnedContainerWindowObserver&) = delete;
  80. void OnWindowAdded(aura::Window* new_window) override {
  81. controller_->OnWindowAddedToPinnedContainer(new_window);
  82. }
  83. void OnWillRemoveWindow(aura::Window* window) override {
  84. controller_->OnWillRemoveWindowFromPinnedContainer(window);
  85. }
  86. void OnWindowDestroying(aura::Window* window) override {
  87. // Just in case. There is nothing we can do here.
  88. window->RemoveObserver(this);
  89. }
  90. private:
  91. ScreenPinningController* controller_;
  92. };
  93. // Adapter to fire OnSystemModalContainerWindowStackingChanged().
  94. class ScreenPinningController::SystemModalContainerChildWindowObserver
  95. : public aura::WindowObserver {
  96. public:
  97. explicit SystemModalContainerChildWindowObserver(
  98. ScreenPinningController* controller)
  99. : controller_(controller) {}
  100. SystemModalContainerChildWindowObserver(
  101. const SystemModalContainerChildWindowObserver&) = delete;
  102. SystemModalContainerChildWindowObserver& operator=(
  103. const SystemModalContainerChildWindowObserver&) = delete;
  104. void OnWindowStackingChanged(aura::Window* window) override {
  105. controller_->OnSystemModalContainerWindowStackingChanged(window);
  106. }
  107. private:
  108. ScreenPinningController* controller_;
  109. };
  110. // Adapter to translate OnWindowAdded/OnWillRemoveWindow for the
  111. // SystemModalContainer to the corresponding controller's methods.
  112. class ScreenPinningController::SystemModalContainerWindowObserver
  113. : public aura::WindowObserver {
  114. public:
  115. explicit SystemModalContainerWindowObserver(
  116. ScreenPinningController* controller)
  117. : controller_(controller) {}
  118. SystemModalContainerWindowObserver(
  119. const SystemModalContainerWindowObserver&) = delete;
  120. SystemModalContainerWindowObserver& operator=(
  121. const SystemModalContainerWindowObserver&) = delete;
  122. void OnWindowAdded(aura::Window* new_window) override {
  123. controller_->OnWindowAddedToSystemModalContainer(new_window);
  124. }
  125. void OnWillRemoveWindow(aura::Window* window) override {
  126. controller_->OnWillRemoveWindowFromSystemModalContainer(window);
  127. }
  128. void OnWindowDestroying(aura::Window* window) override {
  129. // Just in case. There is nothing we can do here.
  130. window->RemoveObserver(this);
  131. }
  132. private:
  133. ScreenPinningController* controller_;
  134. };
  135. ScreenPinningController::ScreenPinningController()
  136. : window_dimmers_(std::make_unique<WindowUserData<WindowDimmer>>()),
  137. pinned_container_window_observer_(
  138. std::make_unique<PinnedContainerWindowObserver>(this)),
  139. pinned_container_child_window_observer_(
  140. std::make_unique<PinnedContainerChildWindowObserver>(this)),
  141. system_modal_container_window_observer_(
  142. std::make_unique<SystemModalContainerWindowObserver>(this)),
  143. system_modal_container_child_window_observer_(
  144. std::make_unique<SystemModalContainerChildWindowObserver>(this)) {
  145. Shell::Get()->window_tree_host_manager()->AddObserver(this);
  146. }
  147. ScreenPinningController::~ScreenPinningController() {
  148. Shell::Get()->window_tree_host_manager()->RemoveObserver(this);
  149. if (pinned_window_)
  150. pinned_window_->RemoveObserver(this);
  151. pinned_window_ = nullptr;
  152. }
  153. bool ScreenPinningController::IsPinned() const {
  154. return pinned_window_ != nullptr;
  155. }
  156. void ScreenPinningController::SetPinnedWindow(aura::Window* pinned_window) {
  157. if (WindowState::Get(pinned_window)->IsPinned()) {
  158. if (pinned_window_) {
  159. LOG(DFATAL) << "Pinned mode is enabled, while it is already in "
  160. << "the pinned mode";
  161. return;
  162. }
  163. aura::Window* container = pinned_window->parent();
  164. aura::Window::Windows system_modal_containers =
  165. GetSystemModalWindowsExceptPinned(pinned_window);
  166. // Set up the container which has the pinned window.
  167. pinned_window_ = pinned_window;
  168. // To monitor destruction.
  169. pinned_window_->AddObserver(this);
  170. AlwaysOnTopController::SetDisallowReparent(pinned_window);
  171. container->StackChildAtTop(pinned_window);
  172. container->StackChildBelow(CreateWindowDimmer(container), pinned_window);
  173. // Set the dim windows to the system containers, other than the one which
  174. // the root window of the pinned window holds.
  175. for (aura::Window* system_modal : system_modal_containers)
  176. system_modal->StackChildAtBottom(CreateWindowDimmer(system_modal));
  177. // Set observers.
  178. container->AddObserver(pinned_container_window_observer_.get());
  179. AddObserverToChildren(container,
  180. pinned_container_child_window_observer_.get());
  181. for (aura::Window* system_modal : system_modal_containers) {
  182. system_modal->AddObserver(system_modal_container_window_observer_.get());
  183. AddObserverToChildren(
  184. system_modal, system_modal_container_child_window_observer_.get());
  185. }
  186. } else {
  187. if (pinned_window != pinned_window_) {
  188. LOG(DFATAL) << "Pinned mode is being disabled, but for the different "
  189. << "target window.";
  190. return;
  191. }
  192. ResetWindowPinningState();
  193. }
  194. Shell::Get()->NotifyPinnedStateChanged(pinned_window);
  195. }
  196. void ScreenPinningController::OnWindowAddedToPinnedContainer(
  197. aura::Window* new_window) {
  198. KeepPinnedWindowOnTop();
  199. new_window->AddObserver(pinned_container_child_window_observer_.get());
  200. }
  201. void ScreenPinningController::OnWillRemoveWindowFromPinnedContainer(
  202. aura::Window* window) {
  203. window->RemoveObserver(pinned_container_child_window_observer_.get());
  204. }
  205. void ScreenPinningController::OnPinnedContainerWindowStackingChanged(
  206. aura::Window* window) {
  207. KeepPinnedWindowOnTop();
  208. }
  209. void ScreenPinningController::OnWindowAddedToSystemModalContainer(
  210. aura::Window* new_window) {
  211. KeepDimWindowAtBottom(new_window->parent());
  212. new_window->AddObserver(system_modal_container_child_window_observer_.get());
  213. }
  214. void ScreenPinningController::OnWillRemoveWindowFromSystemModalContainer(
  215. aura::Window* window) {
  216. window->RemoveObserver(system_modal_container_child_window_observer_.get());
  217. }
  218. void ScreenPinningController::OnSystemModalContainerWindowStackingChanged(
  219. aura::Window* window) {
  220. KeepDimWindowAtBottom(window->parent());
  221. }
  222. aura::Window* ScreenPinningController::CreateWindowDimmer(
  223. aura::Window* container) {
  224. std::unique_ptr<WindowDimmer> window_dimmer =
  225. std::make_unique<WindowDimmer>(container);
  226. window_dimmer->SetDimOpacity(1); // Fully opaque.
  227. AlwaysOnTopController::SetDisallowReparent(window_dimmer->window());
  228. ::wm::SetWindowFullscreen(window_dimmer->window(), true);
  229. window_dimmer->window()->Show();
  230. aura::Window* window = window_dimmer->window();
  231. window_dimmers_->Set(container, std::move(window_dimmer));
  232. return window;
  233. }
  234. void ScreenPinningController::ResetWindowPinningState() {
  235. aura::Window* container = pinned_window_->parent();
  236. aura::Window::Windows system_modal_containers =
  237. GetSystemModalWindowsExceptPinned(pinned_window_);
  238. // Unset observers.
  239. for (aura::Window* system_modal :
  240. GetSystemModalWindowsExceptPinned(pinned_window_)) {
  241. RemoveObserverFromChildren(
  242. system_modal, system_modal_container_child_window_observer_.get());
  243. system_modal->RemoveObserver(system_modal_container_window_observer_.get());
  244. }
  245. RemoveObserverFromChildren(container,
  246. pinned_container_child_window_observer_.get());
  247. container->RemoveObserver(pinned_container_window_observer_.get());
  248. window_dimmers_->clear();
  249. pinned_window_->RemoveObserver(this);
  250. pinned_window_ = nullptr;
  251. }
  252. void ScreenPinningController::OnDisplayConfigurationChanged() {
  253. // Note: this is called on display attached or detached.
  254. if (!IsPinned())
  255. return;
  256. // On display detaching, all necessary windows are transferred to the
  257. // primary display's tree, and called this.
  258. // So, delete WindowDimmers which are not a part of target system modal
  259. // container.
  260. // On display attaching, the new system modal container does not have the
  261. // WindowDimmer. So create it.
  262. // First, delete unnecessary WindowDimmers.
  263. for (aura::Window* container : window_dimmers_->GetWindows()) {
  264. if (container != pinned_window_->parent() &&
  265. !IsWindowDimmerWindowVisible(window_dimmers_->Get(container))) {
  266. window_dimmers_->Set(container, nullptr);
  267. }
  268. }
  269. // Then, create missing WindowDimmers.
  270. aura::Window::Windows system_modal_containers =
  271. GetSystemModalWindowsExceptPinned(pinned_window_);
  272. for (aura::Window* system_modal : system_modal_containers) {
  273. if (window_dimmers_->Get(system_modal)) {
  274. // |system_modal| already has a WindowDimmer.
  275. continue;
  276. }
  277. // This is the new system modal dialog.
  278. system_modal->StackChildAtBottom(CreateWindowDimmer(system_modal));
  279. // Set observers to the tree.
  280. system_modal->AddObserver(system_modal_container_window_observer_.get());
  281. AddObserverToChildren(system_modal,
  282. system_modal_container_child_window_observer_.get());
  283. }
  284. }
  285. void ScreenPinningController::OnWindowDestroying(aura::Window* window) {
  286. DCHECK_EQ(pinned_window_, window);
  287. WindowState::Get(window)->Restore();
  288. // |pinned_window_| isn't cleared, which means the call to restore window
  289. // didn't unpin itself. This is possible because the window is being
  290. // destroyed and some requests are ignored, but we still want to restore
  291. // the internal state of |ScreenPinningController| so that other windows
  292. // can be pinned again.
  293. if (pinned_window_)
  294. ResetWindowPinningState();
  295. }
  296. void ScreenPinningController::KeepPinnedWindowOnTop() {
  297. if (in_restacking_)
  298. return;
  299. base::AutoReset<bool> auto_reset(&in_restacking_, true);
  300. aura::Window* container = pinned_window_->parent();
  301. container->StackChildAtTop(pinned_window_);
  302. WindowDimmer* pinned_window_dimmer = window_dimmers_->Get(container);
  303. if (pinned_window_dimmer && pinned_window_dimmer->window())
  304. container->StackChildBelow(pinned_window_dimmer->window(), pinned_window_);
  305. }
  306. void ScreenPinningController::KeepDimWindowAtBottom(aura::Window* container) {
  307. if (in_restacking_)
  308. return;
  309. WindowDimmer* window_dimmer = window_dimmers_->Get(container);
  310. if (window_dimmer) {
  311. base::AutoReset<bool> auto_reset(&in_restacking_, true);
  312. container->StackChildAtBottom(window_dimmer->window());
  313. }
  314. }
  315. } // namespace ash