123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437 |
- // Copyright 2014 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/shell_desktop_controller_aura.h"
- #include <algorithm>
- #include <memory>
- #include <string>
- #include "base/check_op.h"
- #include "base/memory/raw_ptr.h"
- #include "base/run_loop.h"
- #include "build/chromeos_buildflags.h"
- #include "components/keep_alive_registry/keep_alive_registry.h"
- #include "extensions/browser/app_window/app_window.h"
- #include "extensions/browser/app_window/native_app_window.h"
- #include "extensions/shell/browser/shell_app_window_client.h"
- #include "ui/aura/client/cursor_client.h"
- #include "ui/aura/window.h"
- #include "ui/aura/window_tree_host.h"
- #include "ui/base/cursor/cursor.h"
- #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
- #include "ui/base/ime/init/input_method_factory.h"
- #include "ui/base/ime/input_method.h"
- #include "ui/display/screen.h"
- #include "ui/gfx/geometry/rect.h"
- #include "ui/gfx/geometry/size.h"
- #include "ui/gfx/native_widget_types.h"
- #include "ui/wm/core/base_focus_rules.h"
- #include "ui/wm/core/compound_event_filter.h"
- #include "ui/wm/core/cursor_loader.h"
- #include "ui/wm/core/cursor_manager.h"
- #include "ui/wm/core/focus_controller.h"
- #include "ui/wm/core/native_cursor_manager.h"
- #include "ui/wm/core/native_cursor_manager_delegate.h"
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- #include "base/command_line.h"
- #include "chromeos/dbus/power/power_manager_client.h"
- #include "extensions/shell/browser/shell_screen.h"
- #include "extensions/shell/common/switches.h"
- #include "third_party/cros_system_api/dbus/service_constants.h"
- #include "ui/base/user_activity/user_activity_detector.h"
- #include "ui/chromeos/user_activity_power_manager_notifier.h"
- #include "ui/display/types/display_mode.h"
- #include "ui/display/types/display_snapshot.h"
- #include "ui/display/types/native_display_delegate.h"
- #include "ui/ozone/public/ozone_platform.h" // nogncheck
- #else
- #include "ui/views/widget/desktop_aura/desktop_screen.h"
- #endif // BUILDFLAG(IS_CHROMEOS_ASH)
- namespace extensions {
- namespace {
- // A class that bridges the gap between CursorManager and Aura. It borrows
- // heavily from NativeCursorManagerAsh.
- class ShellNativeCursorManager : public wm::NativeCursorManager {
- public:
- explicit ShellNativeCursorManager(
- ShellDesktopControllerAura* desktop_controller)
- : desktop_controller_(desktop_controller) {}
- ShellNativeCursorManager(const ShellNativeCursorManager&) = delete;
- ShellNativeCursorManager& operator=(const ShellNativeCursorManager&) = delete;
- ~ShellNativeCursorManager() override {}
- // wm::NativeCursorManager overrides.
- void SetDisplay(const display::Display& display,
- wm::NativeCursorManagerDelegate* delegate) override {
- if (cursor_loader_.SetDisplayData(display.panel_rotation(),
- display.device_scale_factor()))
- SetCursor(delegate->GetCursor(), delegate);
- }
- void SetCursor(gfx::NativeCursor cursor,
- wm::NativeCursorManagerDelegate* delegate) override {
- cursor_loader_.SetPlatformCursor(&cursor);
- delegate->CommitCursor(cursor);
- if (delegate->IsCursorVisible())
- SetCursorOnAllRootWindows(cursor);
- }
- void SetVisibility(bool visible,
- wm::NativeCursorManagerDelegate* delegate) override {
- delegate->CommitVisibility(visible);
- if (visible) {
- SetCursor(delegate->GetCursor(), delegate);
- } else {
- gfx::NativeCursor invisible_cursor(ui::mojom::CursorType::kNone);
- cursor_loader_.SetPlatformCursor(&invisible_cursor);
- SetCursorOnAllRootWindows(invisible_cursor);
- }
- }
- void SetCursorSize(ui::CursorSize cursor_size,
- wm::NativeCursorManagerDelegate* delegate) override {
- cursor_loader_.SetSize(cursor_size);
- delegate->CommitCursorSize(cursor_size);
- if (delegate->IsCursorVisible())
- SetCursor(delegate->GetCursor(), delegate);
- }
- void SetMouseEventsEnabled(
- bool enabled,
- wm::NativeCursorManagerDelegate* delegate) override {
- delegate->CommitMouseEventsEnabled(enabled);
- SetVisibility(delegate->IsCursorVisible(), delegate);
- }
- private:
- // Sets |cursor| as the active cursor within Aura.
- void SetCursorOnAllRootWindows(gfx::NativeCursor cursor) {
- for (auto* window : desktop_controller_->GetAllRootWindows())
- window->GetHost()->SetCursor(cursor);
- }
- raw_ptr<ShellDesktopControllerAura> desktop_controller_; // Not owned.
- wm::CursorLoader cursor_loader_{/*use_platform_cursors=*/false};
- };
- class AppsFocusRules : public wm::BaseFocusRules {
- public:
- AppsFocusRules() {}
- AppsFocusRules(const AppsFocusRules&) = delete;
- AppsFocusRules& operator=(const AppsFocusRules&) = delete;
- ~AppsFocusRules() override {}
- bool SupportsChildActivation(const aura::Window* window) const override {
- return true;
- }
- };
- } // namespace
- ShellDesktopControllerAura::ShellDesktopControllerAura(
- content::BrowserContext* browser_context)
- : browser_context_(browser_context),
- app_window_client_(new ShellAppWindowClient) {
- extensions::AppWindowClient::Set(app_window_client_.get());
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- chromeos::PowerManagerClient::Get()->AddObserver(this);
- display_configurator_ = std::make_unique<display::DisplayConfigurator>();
- display_configurator_->Init(
- ui::OzonePlatform::GetInstance()->CreateNativeDisplayDelegate(), false);
- display_configurator_->ForceInitialConfigure();
- display_configurator_->AddObserver(this);
- #endif
- InitWindowManager();
- }
- ShellDesktopControllerAura::~ShellDesktopControllerAura() {
- TearDownWindowManager();
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- chromeos::PowerManagerClient::Get()->RemoveObserver(this);
- #endif
- extensions::AppWindowClient::Set(NULL);
- }
- void ShellDesktopControllerAura::PreMainMessageLoopRun() {
- KeepAliveRegistry::GetInstance()->AddObserver(this);
- }
- void ShellDesktopControllerAura::WillRunMainMessageLoop(
- std::unique_ptr<base::RunLoop>& run_loop) {
- quit_when_idle_closure_ = run_loop->QuitWhenIdleClosure();
- }
- void ShellDesktopControllerAura::PostMainMessageLoopRun() {
- KeepAliveRegistry::GetInstance()->SetIsShuttingDown(true);
- KeepAliveRegistry::GetInstance()->RemoveObserver(this);
- }
- void ShellDesktopControllerAura::AddAppWindow(AppWindow* app_window,
- gfx::NativeWindow window) {
- // Find the closest display to the specified bounds.
- const display::Display& display =
- display::Screen::GetScreen()->GetDisplayMatching(
- window->GetBoundsInScreen());
- // Create a RootWindowController for the display if necessary.
- if (root_window_controllers_.count(display.id()) == 0) {
- root_window_controllers_[display.id()] =
- CreateRootWindowControllerForDisplay(display);
- }
- root_window_controllers_[display.id()]->AddAppWindow(app_window, window);
- }
- void ShellDesktopControllerAura::CloseAppWindows() {
- for (auto& pair : root_window_controllers_)
- pair.second->CloseAppWindows();
- }
- void ShellDesktopControllerAura::CloseRootWindowController(
- RootWindowController* root_window_controller) {
- const auto it = std::find_if(
- root_window_controllers_.cbegin(), root_window_controllers_.cend(),
- [root_window_controller](const auto& candidate_pair) {
- return candidate_pair.second.get() == root_window_controller;
- });
- DCHECK(it != root_window_controllers_.end());
- TearDownRootWindowController(it->second.get());
- root_window_controllers_.erase(it);
- MaybeQuit();
- }
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- void ShellDesktopControllerAura::PowerButtonEventReceived(
- bool down,
- base::TimeTicks timestamp) {
- if (down) {
- chromeos::PowerManagerClient::Get()->RequestShutdown(
- power_manager::REQUEST_SHUTDOWN_FOR_USER, "AppShell power button");
- }
- }
- void ShellDesktopControllerAura::OnDisplayModeChanged(
- const display::DisplayConfigurator::DisplayStateList& displays) {
- for (const display::DisplaySnapshot* display_mode : displays) {
- if (!display_mode->current_mode())
- continue;
- auto it = root_window_controllers_.find(display_mode->display_id());
- if (it != root_window_controllers_.end())
- it->second->UpdateSize(display_mode->current_mode()->size());
- }
- }
- #endif
- ui::EventDispatchDetails ShellDesktopControllerAura::DispatchKeyEventPostIME(
- ui::KeyEvent* key_event) {
- if (key_event->target()) {
- aura::WindowTreeHost* host = static_cast<aura::Window*>(key_event->target())
- ->GetRootWindow()
- ->GetHost();
- return host->DispatchKeyEventPostIME(key_event);
- }
- // Send the key event to the focused window.
- aura::Window* active_window =
- const_cast<aura::Window*>(focus_controller_->GetActiveWindow());
- if (active_window) {
- return active_window->GetRootWindow()->GetHost()->DispatchKeyEventPostIME(
- key_event);
- }
- return GetPrimaryHost()->DispatchKeyEventPostIME(key_event);
- }
- void ShellDesktopControllerAura::OnKeepAliveStateChanged(
- bool is_keeping_alive) {
- if (!is_keeping_alive)
- MaybeQuit();
- }
- void ShellDesktopControllerAura::OnKeepAliveRestartStateChanged(
- bool can_restart) {}
- aura::WindowTreeHost* ShellDesktopControllerAura::GetPrimaryHost() {
- if (root_window_controllers_.empty())
- return nullptr;
- const display::Display& display =
- display::Screen::GetScreen()->GetPrimaryDisplay();
- if (root_window_controllers_.count(display.id()) == 1)
- return root_window_controllers_[display.id()]->host();
- // Fall back to an existing host.
- return root_window_controllers_.begin()->second->host();
- }
- aura::Window::Windows ShellDesktopControllerAura::GetAllRootWindows() {
- aura::Window::Windows windows;
- for (auto& pair : root_window_controllers_)
- windows.push_back(pair.second->host()->window());
- return windows;
- }
- void ShellDesktopControllerAura::SetWindowBoundsInScreen(
- AppWindow* app_window,
- const gfx::Rect& bounds) {
- display::Display display =
- display::Screen::GetScreen()->GetDisplayMatching(bounds);
- // Create a RootWindowController for the display if necessary.
- if (root_window_controllers_.count(display.id()) == 0) {
- root_window_controllers_[display.id()] =
- CreateRootWindowControllerForDisplay(display);
- }
- // Check if the window is parented to a different RootWindowController.
- if (app_window->GetNativeWindow()->GetRootWindow() !=
- root_window_controllers_[display.id()]->host()->window()) {
- // Move the window to the appropriate RootWindowController for the display.
- for (const auto& it : root_window_controllers_) {
- if (it.second->host()->window() ==
- app_window->GetNativeWindow()->GetRootWindow()) {
- it.second->RemoveAppWindow(app_window);
- break;
- }
- }
- root_window_controllers_[display.id()]->AddAppWindow(
- app_window, app_window->GetNativeWindow());
- }
- app_window->GetNativeWindow()->SetBoundsInScreen(bounds, display);
- }
- void ShellDesktopControllerAura::InitWindowManager() {
- root_window_event_filter_ = std::make_unique<wm::CompoundEventFilter>();
- // Screen may be initialized in tests.
- if (!display::Screen::GetScreen()) {
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- screen_ = std::make_unique<ShellScreen>(this, GetStartingWindowSize());
- // TODO(pkasting): Make ShellScreen() call SetScreenInstance() as the
- // classes in CreateDesktopScreen() do, and remove this.
- display::Screen::SetScreenInstance(screen_.get());
- #else
- // TODO(crbug.com/756680): Refactor DesktopScreen out of views.
- screen_ = views::CreateDesktopScreen();
- #endif
- }
- focus_controller_ =
- std::make_unique<wm::FocusController>(new AppsFocusRules());
- cursor_manager_ = std::make_unique<wm::CursorManager>(
- std::make_unique<ShellNativeCursorManager>(this));
- cursor_manager_->SetDisplay(
- display::Screen::GetScreen()->GetPrimaryDisplay());
- cursor_manager_->SetCursor(ui::mojom::CursorType::kPointer);
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- user_activity_detector_ = std::make_unique<ui::UserActivityDetector>();
- user_activity_notifier_ =
- std::make_unique<ui::UserActivityPowerManagerNotifier>(
- user_activity_detector_.get(), /*fingerprint=*/mojo::NullRemote());
- #endif
- }
- void ShellDesktopControllerAura::TearDownWindowManager() {
- for (auto& pair : root_window_controllers_)
- TearDownRootWindowController(pair.second.get());
- root_window_controllers_.clear();
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- user_activity_notifier_.reset();
- user_activity_detector_.reset();
- #endif
- cursor_manager_.reset();
- focus_controller_.reset();
- if (screen_) {
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- display::Screen::SetScreenInstance(nullptr);
- #endif
- screen_.reset();
- }
- root_window_event_filter_.reset();
- }
- std::unique_ptr<RootWindowController>
- ShellDesktopControllerAura::CreateRootWindowControllerForDisplay(
- const display::Display& display) {
- // Convert display's bounds from DIP to physical pixels for WindowTreeHost.
- gfx::Rect bounds(gfx::ScaleToFlooredPoint(display.bounds().origin(),
- display.device_scale_factor()),
- display.GetSizeInPixel());
- auto root_window_controller =
- std::make_unique<RootWindowController>(this, bounds, browser_context_);
- // Initialize the root window with our clients.
- aura::Window* root_window = root_window_controller->host()->window();
- root_window->AddPreTargetHandler(root_window_event_filter_.get());
- aura::client::SetFocusClient(root_window, focus_controller_.get());
- root_window->AddPreTargetHandler(focus_controller_.get());
- wm::SetActivationClient(root_window, focus_controller_.get());
- aura::client::SetCursorClient(root_window, cursor_manager_.get());
- if (!input_method_) {
- // Create an input method and become its key event dispatcher.
- input_method_ = ui::CreateInputMethod(
- this, root_window_controller->host()->GetAcceleratedWidget());
- root_window_controller->host()->SetSharedInputMethod(input_method_.get());
- }
- return root_window_controller;
- }
- void ShellDesktopControllerAura::TearDownRootWindowController(
- RootWindowController* root) {
- root->host()->window()->RemovePreTargetHandler(
- root_window_event_filter_.get());
- root->host()->window()->RemovePreTargetHandler(focus_controller_.get());
- }
- void ShellDesktopControllerAura::MaybeQuit() {
- // Quit if there are no app windows open and no keep-alives waiting for apps
- // to relaunch. |run_loop_| may be null in tests.
- if (quit_when_idle_closure_ && root_window_controllers_.empty() &&
- !KeepAliveRegistry::GetInstance()->IsKeepingAlive()) {
- std::move(quit_when_idle_closure_).Run();
- }
- }
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- gfx::Size ShellDesktopControllerAura::GetStartingWindowSize() {
- gfx::Size size = GetPrimaryDisplaySize();
- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kAppShellHostWindowSize)) {
- const std::string size_str =
- command_line->GetSwitchValueASCII(switches::kAppShellHostWindowSize);
- int width, height;
- CHECK_EQ(2, sscanf(size_str.c_str(), "%dx%d", &width, &height));
- size = gfx::Size(width, height);
- }
- return size.IsEmpty() ? gfx::Size(1920, 1080) : size;
- }
- gfx::Size ShellDesktopControllerAura::GetPrimaryDisplaySize() {
- const display::DisplayConfigurator::DisplayStateList& displays =
- display_configurator_->cached_displays();
- const display::DisplayMode* mode =
- displays.empty() ? nullptr : displays[0]->current_mode();
- return mode ? mode->size() : gfx::Size();
- }
- #endif
- } // namespace extensions
|