| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 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 | 
|  | 5 #include "ash/wm/screen_pinning_controller.h" | 
|  | 6 | 
|  | 7 #include <algorithm> | 
|  | 8 #include <vector> | 
|  | 9 | 
|  | 10 #include "ash/aura/wm_window_aura.h" | 
|  | 11 #include "ash/common/shell_window_ids.h" | 
|  | 12 #include "ash/common/wm/window_state.h" | 
|  | 13 #include "ash/common/wm_shell_common.h" | 
|  | 14 #include "ash/common/wm_window.h" | 
|  | 15 #include "ash/common/wm_window_observer.h" | 
|  | 16 #include "ash/display/window_tree_host_manager.h" | 
|  | 17 #include "ash/shell.h" | 
|  | 18 #include "ash/wm/dim_window.h" | 
|  | 19 #include "base/auto_reset.h" | 
|  | 20 #include "base/logging.h" | 
|  | 21 #include "base/stl_util.h" | 
|  | 22 #include "ui/aura/window_observer.h" | 
|  | 23 | 
|  | 24 namespace ash { | 
|  | 25 namespace { | 
|  | 26 | 
|  | 27 WmWindow* CreateDimWindow(WmWindow* container) { | 
|  | 28   DimWindow* dim_window = new DimWindow(WmWindowAura::GetAuraWindow(container)); | 
|  | 29   dim_window->SetDimOpacity(1);  // Set whole black. | 
|  | 30   WmWindow* result = WmWindowAura::Get(dim_window); | 
|  | 31   result->SetFullscreen(); | 
|  | 32   result->Show(); | 
|  | 33   return result; | 
|  | 34 } | 
|  | 35 | 
|  | 36 // Returns a list of WmWindows corresponding to SystemModalContainers, | 
|  | 37 // except ones whose root is shared with |pinned_window|. | 
|  | 38 std::vector<WmWindow*> GetSystemModalWindowsExceptPinned( | 
|  | 39     WmWindow* pinned_window) { | 
|  | 40   WmWindow* pinned_root = pinned_window->GetRootWindow(); | 
|  | 41 | 
|  | 42   std::vector<WmWindow*> result; | 
|  | 43   for (WmWindow* system_modal : WmWindowAura::FromAuraWindows( | 
|  | 44            ash::Shell::GetContainersFromAllRootWindows( | 
|  | 45                kShellWindowId_SystemModalContainer, nullptr))) { | 
|  | 46     if (system_modal->GetRootWindow() == pinned_root) | 
|  | 47       continue; | 
|  | 48     result.push_back(system_modal); | 
|  | 49   } | 
|  | 50   return result; | 
|  | 51 } | 
|  | 52 | 
|  | 53 void AddObserverToChildren(WmWindow* container, | 
|  | 54                            aura::WindowObserver* observer) { | 
|  | 55   for (WmWindow* child : container->GetChildren()) { | 
|  | 56     WmWindowAura::GetAuraWindow(child)->AddObserver(observer); | 
|  | 57   } | 
|  | 58 } | 
|  | 59 | 
|  | 60 void RemoveObserverFromChildren(WmWindow* container, | 
|  | 61                                 aura::WindowObserver* observer) { | 
|  | 62   for (WmWindow* child : container->GetChildren()) { | 
|  | 63     WmWindowAura::GetAuraWindow(child)->RemoveObserver(observer); | 
|  | 64   } | 
|  | 65 } | 
|  | 66 | 
|  | 67 }  // namespace | 
|  | 68 | 
|  | 69 // Adapter to fire OnPinnedContainerWindowStackingChanged(). | 
|  | 70 class ScreenPinningController::PinnedContainerChildWindowObserver | 
|  | 71     : public aura::WindowObserver { | 
|  | 72  public: | 
|  | 73   explicit PinnedContainerChildWindowObserver( | 
|  | 74       ScreenPinningController* controller) | 
|  | 75       : controller_(controller) {} | 
|  | 76 | 
|  | 77   void OnWindowStackingChanged(aura::Window* window) override { | 
|  | 78     controller_->OnPinnedContainerWindowStackingChanged( | 
|  | 79         WmWindowAura::Get(window)); | 
|  | 80   } | 
|  | 81 | 
|  | 82  private: | 
|  | 83   ScreenPinningController* controller_; | 
|  | 84   DISALLOW_COPY_AND_ASSIGN(PinnedContainerChildWindowObserver); | 
|  | 85 }; | 
|  | 86 | 
|  | 87 // Adapter to translate OnWindowAdded/OnWillRemoveWindow for the container | 
|  | 88 // containing the pinned window, to the corresponding controller's methods. | 
|  | 89 class ScreenPinningController::PinnedContainerWindowObserver | 
|  | 90     : public aura::WindowObserver { | 
|  | 91  public: | 
|  | 92   explicit PinnedContainerWindowObserver(ScreenPinningController* controller) | 
|  | 93       : controller_(controller) {} | 
|  | 94 | 
|  | 95   void OnWindowAdded(aura::Window* new_window) override { | 
|  | 96     controller_->OnWindowAddedToPinnedContainer(WmWindowAura::Get(new_window)); | 
|  | 97   } | 
|  | 98   void OnWillRemoveWindow(aura::Window* window) override { | 
|  | 99     controller_->OnWillRemoveWindowFromPinnedContainer( | 
|  | 100         WmWindowAura::Get(window)); | 
|  | 101   } | 
|  | 102   void OnWindowDestroying(aura::Window* window) override { | 
|  | 103     // Just in case. There is nothing we can do here. | 
|  | 104     window->RemoveObserver(this); | 
|  | 105   } | 
|  | 106 | 
|  | 107  private: | 
|  | 108   ScreenPinningController* controller_; | 
|  | 109   DISALLOW_COPY_AND_ASSIGN(PinnedContainerWindowObserver); | 
|  | 110 }; | 
|  | 111 | 
|  | 112 // Adapter to fire OnSystemModalContainerWindowStackingChanged(). | 
|  | 113 class ScreenPinningController::SystemModalContainerChildWindowObserver | 
|  | 114     : public aura::WindowObserver { | 
|  | 115  public: | 
|  | 116   explicit SystemModalContainerChildWindowObserver( | 
|  | 117       ScreenPinningController* controller) | 
|  | 118       : controller_(controller) {} | 
|  | 119 | 
|  | 120   void OnWindowStackingChanged(aura::Window* window) override { | 
|  | 121     controller_->OnSystemModalContainerWindowStackingChanged( | 
|  | 122         WmWindowAura::Get(window)); | 
|  | 123   } | 
|  | 124 | 
|  | 125  private: | 
|  | 126   ScreenPinningController* controller_; | 
|  | 127   DISALLOW_COPY_AND_ASSIGN(SystemModalContainerChildWindowObserver); | 
|  | 128 }; | 
|  | 129 | 
|  | 130 // Adapter to translate OnWindowAdded/OnWillRemoveWindow for the | 
|  | 131 // SystemModalContainer to the corresponding controller's methods. | 
|  | 132 class ScreenPinningController::SystemModalContainerWindowObserver | 
|  | 133     : public aura::WindowObserver { | 
|  | 134  public: | 
|  | 135   explicit SystemModalContainerWindowObserver( | 
|  | 136       ScreenPinningController* controller) | 
|  | 137       : controller_(controller) {} | 
|  | 138 | 
|  | 139   void OnWindowAdded(aura::Window* new_window) override { | 
|  | 140     controller_->OnWindowAddedToSystemModalContainer( | 
|  | 141         WmWindowAura::Get(new_window)); | 
|  | 142   } | 
|  | 143   void OnWillRemoveWindow(aura::Window* window) override { | 
|  | 144     controller_->OnWillRemoveWindowFromSystemModalContainer( | 
|  | 145         WmWindowAura::Get(window)); | 
|  | 146   } | 
|  | 147   void OnWindowDestroying(aura::Window* window) override { | 
|  | 148     // Just in case. There is nothing we can do here. | 
|  | 149     window->RemoveObserver(this); | 
|  | 150   } | 
|  | 151 | 
|  | 152  private: | 
|  | 153   ScreenPinningController* controller_; | 
|  | 154   DISALLOW_COPY_AND_ASSIGN(SystemModalContainerWindowObserver); | 
|  | 155 }; | 
|  | 156 | 
|  | 157 // Tracks DimWindow's life. | 
|  | 158 class ScreenPinningController::DimWindowObserver : public aura::WindowObserver { | 
|  | 159  public: | 
|  | 160   explicit DimWindowObserver(ScreenPinningController* controller) | 
|  | 161       : controller_(controller) {} | 
|  | 162 | 
|  | 163   void OnWindowParentChanged(aura::Window* window, | 
|  | 164                              aura::Window* parent) override { | 
|  | 165     // In case of parent change, there is nothing we can do for that change. | 
|  | 166     // Also, it is unsafe to delete the moving window here, because it could | 
|  | 167     // cause SEGV. Instead, we just hide it. | 
|  | 168     // Note that, the window is still tracked by the ScreenPinningController, | 
|  | 169     // so that it should be deleted on "unpin", at least. | 
|  | 170     window->Hide(); | 
|  | 171   } | 
|  | 172 | 
|  | 173   void OnWindowDestroying(aura::Window* window) override { | 
|  | 174     controller_->OnDimWindowDestroying(WmWindowAura::Get(window)); | 
|  | 175   } | 
|  | 176 | 
|  | 177  private: | 
|  | 178   ScreenPinningController* controller_; | 
|  | 179   DISALLOW_COPY_AND_ASSIGN(DimWindowObserver); | 
|  | 180 }; | 
|  | 181 | 
|  | 182 ScreenPinningController::ScreenPinningController( | 
|  | 183     WmShellCommon* wm_shell_common, | 
|  | 184     WindowTreeHostManager* window_tree_host_manager) | 
|  | 185     : wm_shell_common_(wm_shell_common), | 
|  | 186       window_tree_host_manager_(window_tree_host_manager), | 
|  | 187       pinned_container_window_observer_( | 
|  | 188           new PinnedContainerWindowObserver(this)), | 
|  | 189       pinned_container_child_window_observer_( | 
|  | 190           new PinnedContainerChildWindowObserver(this)), | 
|  | 191       system_modal_container_window_observer_( | 
|  | 192           new SystemModalContainerWindowObserver(this)), | 
|  | 193       system_modal_container_child_window_observer_( | 
|  | 194           new SystemModalContainerChildWindowObserver(this)), | 
|  | 195       dim_window_observer_(new DimWindowObserver(this)) { | 
|  | 196   wm_shell_common_->AddShellObserver(this); | 
|  | 197   window_tree_host_manager_->AddObserver(this); | 
|  | 198 } | 
|  | 199 | 
|  | 200 ScreenPinningController::~ScreenPinningController() { | 
|  | 201   window_tree_host_manager_->RemoveObserver(this); | 
|  | 202   wm_shell_common_->RemoveShellObserver(this); | 
|  | 203 } | 
|  | 204 | 
|  | 205 bool ScreenPinningController::IsPinned() const { | 
|  | 206   return pinned_window_ != nullptr; | 
|  | 207 } | 
|  | 208 | 
|  | 209 void ScreenPinningController::OnPinnedStateChanged(WmWindow* pinned_window) { | 
|  | 210   if (pinned_window->GetWindowState()->IsPinned()) { | 
|  | 211     if (pinned_window_) { | 
|  | 212       LOG(DFATAL) << "Pinned mode is enabled, while it is already in " | 
|  | 213                   << "the pinned mode"; | 
|  | 214       return; | 
|  | 215     } | 
|  | 216 | 
|  | 217     WmWindow* container = pinned_window->GetParent(); | 
|  | 218     std::vector<WmWindow*> system_modal_containers = | 
|  | 219         GetSystemModalWindowsExceptPinned(pinned_window); | 
|  | 220 | 
|  | 221     // Set up the container which has the pinned window. | 
|  | 222     pinned_window_ = pinned_window; | 
|  | 223     background_window_ = CreateDimWindow(container); | 
|  | 224     container->StackChildAtTop(pinned_window); | 
|  | 225     container->StackChildBelow(background_window_, pinned_window); | 
|  | 226 | 
|  | 227     // Set the dim windows to the system containers, other than the one which | 
|  | 228     // the root window of the pinned window holds. | 
|  | 229     for (WmWindow* system_modal : system_modal_containers) { | 
|  | 230       WmWindow* dim_window = CreateDimWindow(system_modal); | 
|  | 231       system_modal->StackChildAtBottom(dim_window); | 
|  | 232       dim_windows_.push_back(dim_window); | 
|  | 233       WmWindowAura::GetAuraWindow(dim_window) | 
|  | 234           ->AddObserver(dim_window_observer_.get()); | 
|  | 235     } | 
|  | 236 | 
|  | 237     // Set observers. | 
|  | 238     WmWindowAura::GetAuraWindow(container)->AddObserver( | 
|  | 239         pinned_container_window_observer_.get()); | 
|  | 240     AddObserverToChildren(container, | 
|  | 241                           pinned_container_child_window_observer_.get()); | 
|  | 242     for (WmWindow* system_modal : system_modal_containers) { | 
|  | 243       WmWindowAura::GetAuraWindow(system_modal) | 
|  | 244           ->AddObserver(system_modal_container_window_observer_.get()); | 
|  | 245       AddObserverToChildren( | 
|  | 246           system_modal, system_modal_container_child_window_observer_.get()); | 
|  | 247     } | 
|  | 248   } else { | 
|  | 249     if (pinned_window != pinned_window_) { | 
|  | 250       LOG(DFATAL) << "Pinned mode is being disabled, but for the different " | 
|  | 251                   << "target window."; | 
|  | 252       return; | 
|  | 253     } | 
|  | 254 | 
|  | 255     WmWindow* container = pinned_window->GetParent(); | 
|  | 256     std::vector<WmWindow*> system_modal_containers = | 
|  | 257         GetSystemModalWindowsExceptPinned(pinned_window_); | 
|  | 258 | 
|  | 259     // Unset observers. | 
|  | 260     for (WmWindow* system_modal : | 
|  | 261          GetSystemModalWindowsExceptPinned(pinned_window_)) { | 
|  | 262       RemoveObserverFromChildren( | 
|  | 263           system_modal, system_modal_container_child_window_observer_.get()); | 
|  | 264       WmWindowAura::GetAuraWindow(system_modal) | 
|  | 265           ->RemoveObserver(system_modal_container_window_observer_.get()); | 
|  | 266     } | 
|  | 267     RemoveObserverFromChildren(container, | 
|  | 268                                pinned_container_child_window_observer_.get()); | 
|  | 269     WmWindowAura::GetAuraWindow(container)->RemoveObserver( | 
|  | 270         pinned_container_window_observer_.get()); | 
|  | 271 | 
|  | 272     // Delete the dim windows. This works, but do not use RAII, because | 
|  | 273     // the window is owned by the parent. | 
|  | 274     // Note: dim_windows_ will be updated during the deletion. So, copy is | 
|  | 275     // needed. | 
|  | 276     for (WmWindow* dim_window : std::vector<WmWindow*>(dim_windows_)) { | 
|  | 277       delete WmWindowAura::GetAuraWindow(dim_window); | 
|  | 278     } | 
|  | 279     DCHECK(dim_windows_.empty()); | 
|  | 280     delete WmWindowAura::GetAuraWindow(background_window_); | 
|  | 281     background_window_ = nullptr; | 
|  | 282 | 
|  | 283     pinned_window_ = nullptr; | 
|  | 284   } | 
|  | 285 } | 
|  | 286 | 
|  | 287 void ScreenPinningController::OnWindowAddedToPinnedContainer( | 
|  | 288     WmWindow* new_window) { | 
|  | 289   KeepPinnedWindowOnTop(); | 
|  | 290   WmWindowAura::GetAuraWindow(new_window) | 
|  | 291       ->AddObserver(pinned_container_child_window_observer_.get()); | 
|  | 292 } | 
|  | 293 | 
|  | 294 void ScreenPinningController::OnWillRemoveWindowFromPinnedContainer( | 
|  | 295     WmWindow* window) { | 
|  | 296   WmWindowAura::GetAuraWindow(window)->RemoveObserver( | 
|  | 297       pinned_container_child_window_observer_.get()); | 
|  | 298   if (window == pinned_window_) { | 
|  | 299     pinned_window_->GetWindowState()->Restore(); | 
|  | 300     return; | 
|  | 301   } | 
|  | 302   if (window == background_window_) { | 
|  | 303     background_window_ = nullptr; | 
|  | 304     return; | 
|  | 305   } | 
|  | 306 } | 
|  | 307 | 
|  | 308 void ScreenPinningController::OnPinnedContainerWindowStackingChanged( | 
|  | 309     WmWindow* window) { | 
|  | 310   KeepPinnedWindowOnTop(); | 
|  | 311 } | 
|  | 312 | 
|  | 313 void ScreenPinningController::OnWindowAddedToSystemModalContainer( | 
|  | 314     WmWindow* new_window) { | 
|  | 315   KeepDimWindowAtBottom(new_window->GetParent()); | 
|  | 316   WmWindowAura::GetAuraWindow(new_window) | 
|  | 317       ->AddObserver(system_modal_container_child_window_observer_.get()); | 
|  | 318 } | 
|  | 319 | 
|  | 320 void ScreenPinningController::OnWillRemoveWindowFromSystemModalContainer( | 
|  | 321     WmWindow* window) { | 
|  | 322   WmWindowAura::GetAuraWindow(window)->RemoveObserver( | 
|  | 323       system_modal_container_child_window_observer_.get()); | 
|  | 324 } | 
|  | 325 | 
|  | 326 void ScreenPinningController::OnSystemModalContainerWindowStackingChanged( | 
|  | 327     WmWindow* window) { | 
|  | 328   KeepDimWindowAtBottom(window->GetParent()); | 
|  | 329 } | 
|  | 330 | 
|  | 331 void ScreenPinningController::OnDimWindowDestroying(WmWindow* window) { | 
|  | 332   dim_windows_.erase( | 
|  | 333       std::find(dim_windows_.begin(), dim_windows_.end(), window)); | 
|  | 334 } | 
|  | 335 | 
|  | 336 void ScreenPinningController::OnDisplayConfigurationChanged() { | 
|  | 337   // Note: this is called on display attached or detached. | 
|  | 338   if (!IsPinned()) | 
|  | 339     return; | 
|  | 340 | 
|  | 341   // On display detaching, all necessary windows are transfered to the | 
|  | 342   // primary display's tree, and called this. | 
|  | 343   // So, delete the dim windows which are not a part of target system modal | 
|  | 344   // container. | 
|  | 345   // On display attaching, the new system modal container does not have the | 
|  | 346   // dim window. So create it. | 
|  | 347 | 
|  | 348   // First, delete unnecessary dim windows. | 
|  | 349   // The delete will update dim_windows_, so create the copy is needed. | 
|  | 350   for (WmWindow* dim_window : std::vector<WmWindow*>(dim_windows_)) { | 
|  | 351     if (!dim_window->GetTargetVisibility()) | 
|  | 352       delete WmWindowAura::GetAuraWindow(dim_window); | 
|  | 353   } | 
|  | 354 | 
|  | 355   // Then, create missing dim_windows. | 
|  | 356   std::vector<WmWindow*> system_modal_containers = | 
|  | 357       GetSystemModalWindowsExceptPinned(pinned_window_); | 
|  | 358   for (WmWindow* system_modal : system_modal_containers) { | 
|  | 359     const std::vector<WmWindow*> children = system_modal->GetChildren(); | 
|  | 360     if (!children.empty() && ContainsValue(dim_windows_, children[0])) { | 
|  | 361       // The system modal dialog has the dim window. | 
|  | 362       continue; | 
|  | 363     } | 
|  | 364 | 
|  | 365     // This is the new system modal dialog. | 
|  | 366     WmWindow* dim_window = CreateDimWindow(system_modal); | 
|  | 367     system_modal->StackChildAtBottom(dim_window); | 
|  | 368     dim_windows_.push_back(dim_window); | 
|  | 369     WmWindowAura::GetAuraWindow(dim_window) | 
|  | 370         ->AddObserver(dim_window_observer_.get()); | 
|  | 371 | 
|  | 372     // Set observers to the tree. | 
|  | 373     WmWindowAura::GetAuraWindow(system_modal) | 
|  | 374         ->AddObserver(system_modal_container_window_observer_.get()); | 
|  | 375     AddObserverToChildren(system_modal, | 
|  | 376                           system_modal_container_child_window_observer_.get()); | 
|  | 377   } | 
|  | 378 } | 
|  | 379 | 
|  | 380 void ScreenPinningController::KeepPinnedWindowOnTop() { | 
|  | 381   if (in_restacking_) | 
|  | 382     return; | 
|  | 383 | 
|  | 384   base::AutoReset<bool> auto_reset(&in_restacking_, true); | 
|  | 385   WmWindow* container = pinned_window_->GetParent(); | 
|  | 386   container->StackChildAtTop(pinned_window_); | 
|  | 387   container->StackChildBelow(background_window_, pinned_window_); | 
|  | 388 } | 
|  | 389 | 
|  | 390 void ScreenPinningController::KeepDimWindowAtBottom(WmWindow* container) { | 
|  | 391   if (in_restacking_) | 
|  | 392     return; | 
|  | 393 | 
|  | 394   base::AutoReset<bool> auto_reset(&in_restacking_, true); | 
|  | 395   for (WmWindow* dim_window : dim_windows_) { | 
|  | 396     if (dim_window->GetParent() == container) { | 
|  | 397       container->StackChildAtBottom(dim_window); | 
|  | 398       break; | 
|  | 399     } | 
|  | 400   } | 
|  | 401 } | 
|  | 402 | 
|  | 403 }  // namespace ash | 
| OLD | NEW | 
|---|