root_window_controller.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // Copyright 2017 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 "extensions/shell/browser/root_window_controller.h"
  5. #include "base/memory/raw_ptr.h"
  6. #include "extensions/browser/app_window/app_window.h"
  7. #include "extensions/browser/app_window/native_app_window.h"
  8. #include "extensions/shell/browser/shell_app_delegate.h"
  9. #include "ui/aura/layout_manager.h"
  10. #include "ui/aura/window.h"
  11. #include "ui/aura/window_tracker.h"
  12. #include "ui/aura/window_tree_host.h"
  13. #include "ui/display/display.h"
  14. #include "ui/gfx/geometry/rect.h"
  15. #include "ui/gfx/geometry/size.h"
  16. #include "ui/platform_window/platform_window_init_properties.h"
  17. #include "ui/wm/core/default_screen_position_client.h"
  18. namespace extensions {
  19. namespace {
  20. // A simple layout manager that makes each new window fill its parent.
  21. class FillLayout : public aura::LayoutManager {
  22. public:
  23. FillLayout(aura::Window* owner) : owner_(owner) { DCHECK(owner_); }
  24. FillLayout(const FillLayout&) = delete;
  25. FillLayout& operator=(const FillLayout&) = delete;
  26. ~FillLayout() override = default;
  27. private:
  28. // aura::LayoutManager:
  29. void OnWindowResized() override {
  30. // Size the owner's immediate child windows.
  31. aura::WindowTracker children_tracker(owner_->children());
  32. while (!children_tracker.windows().empty()) {
  33. aura::Window* child = children_tracker.Pop();
  34. child->SetBounds(gfx::Rect(owner_->bounds().size()));
  35. }
  36. }
  37. void OnWindowAddedToLayout(aura::Window* child) override {
  38. DCHECK_EQ(owner_, child->parent());
  39. // Create a rect at 0,0 with the size of the parent.
  40. gfx::Size parent_size = child->parent()->bounds().size();
  41. child->SetBounds(gfx::Rect(parent_size));
  42. }
  43. void OnWillRemoveWindowFromLayout(aura::Window* child) override {}
  44. void OnWindowRemovedFromLayout(aura::Window* child) override {}
  45. void OnChildWindowVisibilityChanged(aura::Window* child,
  46. bool visible) override {}
  47. void SetChildBounds(aura::Window* child,
  48. const gfx::Rect& requested_bounds) override {
  49. SetChildBoundsDirect(child, requested_bounds);
  50. }
  51. raw_ptr<aura::Window> owner_; // Not owned.
  52. };
  53. // A simple screen positioning client that translates bounds to screen
  54. // coordinates using the offset of the root window in screen coordinates.
  55. class ScreenPositionClient : public wm::DefaultScreenPositionClient {
  56. public:
  57. using DefaultScreenPositionClient::DefaultScreenPositionClient;
  58. ScreenPositionClient(const ScreenPositionClient&) = delete;
  59. ScreenPositionClient& operator=(const ScreenPositionClient&) = delete;
  60. ~ScreenPositionClient() override = default;
  61. // wm::DefaultScreenPositionClient:
  62. void SetBounds(aura::Window* window,
  63. const gfx::Rect& bounds,
  64. const display::Display& display) override {
  65. aura::Window* root_window = window->GetRootWindow();
  66. DCHECK(window);
  67. // Convert the window's origin to its root window's coordinates.
  68. gfx::Point origin = bounds.origin();
  69. aura::Window::ConvertPointToTarget(window->parent(), root_window, &origin);
  70. // Translate the origin by the root window's offset in screen coordinates.
  71. gfx::Point host_origin = GetRootWindowOriginInScreen(root_window);
  72. origin.Offset(-host_origin.x(), -host_origin.y());
  73. window->SetBounds(gfx::Rect(origin, bounds.size()));
  74. }
  75. };
  76. } // namespace
  77. RootWindowController::RootWindowController(
  78. DesktopDelegate* desktop_delegate,
  79. const gfx::Rect& bounds,
  80. content::BrowserContext* browser_context)
  81. : desktop_delegate_(desktop_delegate), browser_context_(browser_context) {
  82. DCHECK(desktop_delegate_);
  83. DCHECK(browser_context_);
  84. host_ =
  85. aura::WindowTreeHost::Create(ui::PlatformWindowInitProperties{bounds});
  86. host_->InitHost();
  87. host_->window()->Show();
  88. aura::client::SetWindowParentingClient(host_->window(), this);
  89. screen_position_client_ =
  90. std::make_unique<ScreenPositionClient>(host_->window());
  91. // Ensure the window fills the display.
  92. host_->window()->SetLayoutManager(new FillLayout(host_->window()));
  93. host_->AddObserver(this);
  94. host_->Show();
  95. }
  96. RootWindowController::~RootWindowController() {
  97. CloseAppWindows();
  98. // The screen position client holds a pointer to the root window, so free it
  99. // before destroying the window tree host.
  100. screen_position_client_.reset();
  101. DestroyWindowTreeHost();
  102. }
  103. void RootWindowController::AddAppWindow(AppWindow* app_window,
  104. gfx::NativeWindow window) {
  105. if (app_windows_.empty()) {
  106. // Start observing for OnAppWindowRemoved.
  107. AppWindowRegistry* registry = AppWindowRegistry::Get(browser_context_);
  108. registry->AddObserver(this);
  109. }
  110. app_windows_.push_back(app_window);
  111. aura::Window* root_window = host_->window();
  112. root_window->AddChild(window);
  113. }
  114. void RootWindowController::RemoveAppWindow(AppWindow* app_window) {
  115. host_->window()->RemoveChild(app_window->GetNativeWindow());
  116. app_windows_.remove(app_window);
  117. if (app_windows_.empty())
  118. AppWindowRegistry::Get(browser_context_)->RemoveObserver(this);
  119. }
  120. void RootWindowController::CloseAppWindows() {
  121. if (app_windows_.empty())
  122. return;
  123. // Remove the observer before closing windows to avoid triggering
  124. // OnAppWindowRemoved, which would mutate |app_windows_|.
  125. AppWindowRegistry::Get(browser_context_)->RemoveObserver(this);
  126. for (AppWindow* app_window : app_windows_)
  127. app_window->GetBaseWindow()->Close(); // Close() deletes |app_window|.
  128. app_windows_.clear();
  129. }
  130. void RootWindowController::UpdateSize(const gfx::Size& size) {
  131. host_->SetBoundsInPixels(gfx::Rect(size));
  132. }
  133. aura::Window* RootWindowController::GetDefaultParent(aura::Window* window,
  134. const gfx::Rect& bounds) {
  135. return host_->window();
  136. }
  137. void RootWindowController::OnHostCloseRequested(aura::WindowTreeHost* host) {
  138. DCHECK_EQ(host_.get(), host);
  139. CloseAppWindows();
  140. // The ShellDesktopControllerAura will delete us.
  141. desktop_delegate_->CloseRootWindowController(this);
  142. }
  143. void RootWindowController::OnAppWindowRemoved(AppWindow* window) {
  144. if (app_windows_.empty())
  145. return;
  146. // If we created this AppWindow, remove it from our list so we don't try to
  147. // close it again later.
  148. app_windows_.remove(window);
  149. // Close when all AppWindows are closed.
  150. if (app_windows_.empty()) {
  151. AppWindowRegistry::Get(browser_context_)->RemoveObserver(this);
  152. desktop_delegate_->CloseRootWindowController(this);
  153. }
  154. }
  155. void RootWindowController::DestroyWindowTreeHost() {
  156. host_->RemoveObserver(this);
  157. host_.reset();
  158. }
  159. } // namespace extensions