always_on_top_controller.cc 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  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. #include "ash/wm/always_on_top_controller.h"
  5. #include "ash/public/cpp/shell_window_ids.h"
  6. #include "ash/public/cpp/window_properties.h"
  7. #include "ash/wm/desks/desks_controller.h"
  8. #include "ash/wm/desks/desks_util.h"
  9. #include "ash/wm/window_state.h"
  10. #include "ash/wm/workspace/workspace_layout_manager.h"
  11. #include "ui/aura/client/aura_constants.h"
  12. #include "ui/aura/window.h"
  13. namespace ash {
  14. DEFINE_UI_CLASS_PROPERTY_KEY(bool, kDisallowReparentKey, false)
  15. AlwaysOnTopController::AlwaysOnTopController(
  16. aura::Window* always_on_top_container,
  17. aura::Window* pip_container)
  18. : always_on_top_container_(always_on_top_container),
  19. pip_container_(pip_container) {
  20. DCHECK(!desks_util::IsDeskContainer(always_on_top_container_));
  21. DCHECK(!desks_util::IsDeskContainer(pip_container_));
  22. always_on_top_container_->SetLayoutManager(
  23. new WorkspaceLayoutManager(always_on_top_container_));
  24. pip_container_->SetLayoutManager(new WorkspaceLayoutManager(pip_container_));
  25. // Container should be empty.
  26. DCHECK(always_on_top_container_->children().empty());
  27. DCHECK(pip_container_->children().empty());
  28. always_on_top_container_->AddObserver(this);
  29. pip_container->AddObserver(this);
  30. }
  31. AlwaysOnTopController::~AlwaysOnTopController() {
  32. // At this point, all windows should be removed and AlwaysOnTopController
  33. // will have removed itself as an observer in OnWindowDestroying.
  34. DCHECK(!always_on_top_container_);
  35. DCHECK(!pip_container_);
  36. }
  37. // static
  38. void AlwaysOnTopController::SetDisallowReparent(aura::Window* window) {
  39. window->SetProperty(kDisallowReparentKey, true);
  40. }
  41. aura::Window* AlwaysOnTopController::GetContainer(aura::Window* window) const {
  42. DCHECK(always_on_top_container_);
  43. DCHECK(pip_container_);
  44. // On other platforms, there are different window levels. For now, treat any
  45. // window with non-normal level as "always on top". Perhaps the nuance of
  46. // multiple levels will be needed later.
  47. if (window->GetProperty(aura::client::kZOrderingKey) ==
  48. ui::ZOrderLevel::kNormal) {
  49. aura::Window* root = always_on_top_container_->GetRootWindow();
  50. // TODO(afakhry): Do we need to worry about the context of |window| here? Or
  51. // is it safe to assume that |window| should always be parented to the
  52. // active desks' container.
  53. const int window_workspace =
  54. window->GetProperty(aura::client::kWindowWorkspaceKey);
  55. if (window_workspace != aura::client::kWindowWorkspaceUnassignedWorkspace) {
  56. auto* desk_container =
  57. DesksController::Get()->GetDeskContainer(root, window_workspace);
  58. if (desk_container)
  59. return desk_container;
  60. }
  61. return desks_util::GetActiveDeskContainerForRoot(root);
  62. }
  63. if (window->parent() && WindowState::Get(window)->IsPip())
  64. return pip_container_;
  65. return always_on_top_container_;
  66. }
  67. void AlwaysOnTopController::ClearLayoutManagers() {
  68. always_on_top_container_->SetLayoutManager(nullptr);
  69. pip_container_->SetLayoutManager(nullptr);
  70. }
  71. void AlwaysOnTopController::SetLayoutManagerForTest(
  72. std::unique_ptr<WorkspaceLayoutManager> layout_manager) {
  73. always_on_top_container_->SetLayoutManager(layout_manager.release());
  74. }
  75. void AlwaysOnTopController::AddWindow(aura::Window* window) {
  76. window->AddObserver(this);
  77. WindowState::Get(window)->AddObserver(this);
  78. }
  79. void AlwaysOnTopController::RemoveWindow(aura::Window* window) {
  80. window->RemoveObserver(this);
  81. WindowState::Get(window)->RemoveObserver(this);
  82. }
  83. void AlwaysOnTopController::ReparentWindow(aura::Window* window) {
  84. DCHECK(window->GetType() == aura::client::WINDOW_TYPE_NORMAL ||
  85. window->GetType() == aura::client::WINDOW_TYPE_POPUP);
  86. aura::Window* container = GetContainer(window);
  87. if (window->parent() != container &&
  88. !window->GetProperty(kDisallowReparentKey))
  89. container->AddChild(window);
  90. }
  91. void AlwaysOnTopController::OnWindowHierarchyChanged(
  92. const HierarchyChangeParams& params) {
  93. if (params.old_parent == always_on_top_container_ ||
  94. params.old_parent == pip_container_) {
  95. RemoveWindow(params.target);
  96. }
  97. if (params.new_parent == always_on_top_container_ ||
  98. params.new_parent == pip_container_) {
  99. AddWindow(params.target);
  100. }
  101. }
  102. void AlwaysOnTopController::OnWindowPropertyChanged(aura::Window* window,
  103. const void* key,
  104. intptr_t old) {
  105. if (window != always_on_top_container_ && window != pip_container_ &&
  106. key == aura::client::kZOrderingKey) {
  107. ReparentWindow(window);
  108. }
  109. }
  110. void AlwaysOnTopController::OnWindowDestroying(aura::Window* window) {
  111. if (window == always_on_top_container_) {
  112. always_on_top_container_->RemoveObserver(this);
  113. always_on_top_container_ = nullptr;
  114. } else if (window == pip_container_) {
  115. pip_container_->RemoveObserver(this);
  116. pip_container_ = nullptr;
  117. } else {
  118. RemoveWindow(window);
  119. }
  120. }
  121. void AlwaysOnTopController::OnPreWindowStateTypeChange(
  122. WindowState* window_state,
  123. chromeos::WindowStateType old_type) {
  124. ReparentWindow(window_state->window());
  125. }
  126. } // namespace ash