| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "extensions/shell/browser/root_window_controller.h" |
| |
| #include "extensions/browser/app_window/app_window.h" |
| #include "extensions/browser/app_window/native_app_window.h" |
| #include "extensions/shell/browser/shell_app_delegate.h" |
| #include "ui/aura/layout_manager.h" |
| #include "ui/aura/window.h" |
| #include "ui/aura/window_tracker.h" |
| #include "ui/aura/window_tree_host.h" |
| #include "ui/display/display.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/gfx/geometry/size.h" |
| |
| namespace extensions { |
| |
| namespace { |
| |
| // A simple layout manager that makes each new window fill its parent. |
| class FillLayout : public aura::LayoutManager { |
| public: |
| FillLayout(aura::Window* owner) : owner_(owner) { DCHECK(owner_); } |
| ~FillLayout() override = default; |
| |
| private: |
| // aura::LayoutManager: |
| void OnWindowResized() override { |
| // Size the owner's immediate child windows. |
| aura::WindowTracker children_tracker(owner_->children()); |
| while (!children_tracker.windows().empty()) { |
| aura::Window* child = children_tracker.Pop(); |
| child->SetBounds(gfx::Rect(owner_->bounds().size())); |
| } |
| } |
| |
| void OnWindowAddedToLayout(aura::Window* child) override { |
| DCHECK_EQ(owner_, child->parent()); |
| |
| // Create a rect at 0,0 with the size of the parent. |
| gfx::Size parent_size = child->parent()->bounds().size(); |
| child->SetBounds(gfx::Rect(parent_size)); |
| } |
| |
| void OnWillRemoveWindowFromLayout(aura::Window* child) override {} |
| |
| void OnWindowRemovedFromLayout(aura::Window* child) override {} |
| |
| void OnChildWindowVisibilityChanged(aura::Window* child, |
| bool visible) override {} |
| |
| void SetChildBounds(aura::Window* child, |
| const gfx::Rect& requested_bounds) override { |
| SetChildBoundsDirect(child, requested_bounds); |
| } |
| |
| aura::Window* owner_; // Not owned. |
| |
| DISALLOW_COPY_AND_ASSIGN(FillLayout); |
| }; |
| |
| } // namespace |
| |
| RootWindowController::RootWindowController( |
| DesktopDelegate* desktop_delegate, |
| const gfx::Rect& bounds, |
| content::BrowserContext* browser_context) |
| : desktop_delegate_(desktop_delegate), |
| browser_context_(browser_context) { |
| DCHECK(desktop_delegate_); |
| DCHECK(browser_context_); |
| host_.reset(aura::WindowTreeHost::Create(bounds)); |
| |
| host_->InitHost(); |
| host_->window()->Show(); |
| |
| aura::client::SetWindowParentingClient(host_->window(), this); |
| |
| // Ensure the window fills the display. |
| host_->window()->SetLayoutManager(new FillLayout(host_->window())); |
| |
| host_->AddObserver(this); |
| host_->Show(); |
| } |
| |
| RootWindowController::~RootWindowController() { |
| CloseAppWindows(); |
| DestroyWindowTreeHost(); |
| } |
| |
| void RootWindowController::AddAppWindow(AppWindow* app_window, |
| gfx::NativeWindow window) { |
| if (app_windows_.empty()) { |
| // Start observing for OnAppWindowRemoved. |
| AppWindowRegistry* registry = AppWindowRegistry::Get(browser_context_); |
| registry->AddObserver(this); |
| } |
| |
| app_windows_.push_back(app_window); |
| |
| aura::Window* root_window = host_->window(); |
| root_window->AddChild(window); |
| } |
| |
| void RootWindowController::CloseAppWindows() { |
| if (app_windows_.empty()) |
| return; |
| |
| // Remove the observer before closing windows to avoid triggering |
| // OnAppWindowRemoved, which would mutate |app_windows_|. |
| AppWindowRegistry::Get(browser_context_)->RemoveObserver(this); |
| for (AppWindow* app_window : app_windows_) |
| app_window->GetBaseWindow()->Close(); // Close() deletes |app_window|. |
| app_windows_.clear(); |
| } |
| |
| void RootWindowController::UpdateSize(const gfx::Size& size) { |
| host_->UpdateRootWindowSizeInPixels(size); |
| } |
| |
| aura::Window* RootWindowController::GetDefaultParent(aura::Window* window, |
| const gfx::Rect& bounds) { |
| return host_->window(); |
| } |
| |
| void RootWindowController::OnHostCloseRequested(aura::WindowTreeHost* host) { |
| DCHECK_EQ(host_.get(), host); |
| CloseAppWindows(); |
| |
| // The ShellDesktopControllerAura will delete us. |
| desktop_delegate_->CloseRootWindowController(this); |
| } |
| |
| void RootWindowController::OnAppWindowRemoved(AppWindow* window) { |
| if (app_windows_.empty()) |
| return; |
| |
| // If we created this AppWindow, remove it from our list so we don't try to |
| // close it again later. |
| app_windows_.remove(window); |
| |
| // Close when all AppWindows are closed. |
| if (app_windows_.empty()) { |
| AppWindowRegistry::Get(browser_context_)->RemoveObserver(this); |
| desktop_delegate_->CloseRootWindowController(this); |
| } |
| } |
| |
| void RootWindowController::DestroyWindowTreeHost() { |
| host_->RemoveObserver(this); |
| host_.reset(); |
| } |
| |
| } // namespace extensions |