shell_desktop_controller_aura.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. // Copyright 2014 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/shell_desktop_controller_aura.h"
  5. #include <algorithm>
  6. #include <memory>
  7. #include <string>
  8. #include "base/check_op.h"
  9. #include "base/memory/raw_ptr.h"
  10. #include "base/run_loop.h"
  11. #include "build/chromeos_buildflags.h"
  12. #include "components/keep_alive_registry/keep_alive_registry.h"
  13. #include "extensions/browser/app_window/app_window.h"
  14. #include "extensions/browser/app_window/native_app_window.h"
  15. #include "extensions/shell/browser/shell_app_window_client.h"
  16. #include "ui/aura/client/cursor_client.h"
  17. #include "ui/aura/window.h"
  18. #include "ui/aura/window_tree_host.h"
  19. #include "ui/base/cursor/cursor.h"
  20. #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
  21. #include "ui/base/ime/init/input_method_factory.h"
  22. #include "ui/base/ime/input_method.h"
  23. #include "ui/display/screen.h"
  24. #include "ui/gfx/geometry/rect.h"
  25. #include "ui/gfx/geometry/size.h"
  26. #include "ui/gfx/native_widget_types.h"
  27. #include "ui/wm/core/base_focus_rules.h"
  28. #include "ui/wm/core/compound_event_filter.h"
  29. #include "ui/wm/core/cursor_loader.h"
  30. #include "ui/wm/core/cursor_manager.h"
  31. #include "ui/wm/core/focus_controller.h"
  32. #include "ui/wm/core/native_cursor_manager.h"
  33. #include "ui/wm/core/native_cursor_manager_delegate.h"
  34. #if BUILDFLAG(IS_CHROMEOS_ASH)
  35. #include "base/command_line.h"
  36. #include "chromeos/dbus/power/power_manager_client.h"
  37. #include "extensions/shell/browser/shell_screen.h"
  38. #include "extensions/shell/common/switches.h"
  39. #include "third_party/cros_system_api/dbus/service_constants.h"
  40. #include "ui/base/user_activity/user_activity_detector.h"
  41. #include "ui/chromeos/user_activity_power_manager_notifier.h"
  42. #include "ui/display/types/display_mode.h"
  43. #include "ui/display/types/display_snapshot.h"
  44. #include "ui/display/types/native_display_delegate.h"
  45. #include "ui/ozone/public/ozone_platform.h" // nogncheck
  46. #else
  47. #include "ui/views/widget/desktop_aura/desktop_screen.h"
  48. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  49. namespace extensions {
  50. namespace {
  51. // A class that bridges the gap between CursorManager and Aura. It borrows
  52. // heavily from NativeCursorManagerAsh.
  53. class ShellNativeCursorManager : public wm::NativeCursorManager {
  54. public:
  55. explicit ShellNativeCursorManager(
  56. ShellDesktopControllerAura* desktop_controller)
  57. : desktop_controller_(desktop_controller) {}
  58. ShellNativeCursorManager(const ShellNativeCursorManager&) = delete;
  59. ShellNativeCursorManager& operator=(const ShellNativeCursorManager&) = delete;
  60. ~ShellNativeCursorManager() override {}
  61. // wm::NativeCursorManager overrides.
  62. void SetDisplay(const display::Display& display,
  63. wm::NativeCursorManagerDelegate* delegate) override {
  64. if (cursor_loader_.SetDisplayData(display.panel_rotation(),
  65. display.device_scale_factor()))
  66. SetCursor(delegate->GetCursor(), delegate);
  67. }
  68. void SetCursor(gfx::NativeCursor cursor,
  69. wm::NativeCursorManagerDelegate* delegate) override {
  70. cursor_loader_.SetPlatformCursor(&cursor);
  71. delegate->CommitCursor(cursor);
  72. if (delegate->IsCursorVisible())
  73. SetCursorOnAllRootWindows(cursor);
  74. }
  75. void SetVisibility(bool visible,
  76. wm::NativeCursorManagerDelegate* delegate) override {
  77. delegate->CommitVisibility(visible);
  78. if (visible) {
  79. SetCursor(delegate->GetCursor(), delegate);
  80. } else {
  81. gfx::NativeCursor invisible_cursor(ui::mojom::CursorType::kNone);
  82. cursor_loader_.SetPlatformCursor(&invisible_cursor);
  83. SetCursorOnAllRootWindows(invisible_cursor);
  84. }
  85. }
  86. void SetCursorSize(ui::CursorSize cursor_size,
  87. wm::NativeCursorManagerDelegate* delegate) override {
  88. cursor_loader_.SetSize(cursor_size);
  89. delegate->CommitCursorSize(cursor_size);
  90. if (delegate->IsCursorVisible())
  91. SetCursor(delegate->GetCursor(), delegate);
  92. }
  93. void SetMouseEventsEnabled(
  94. bool enabled,
  95. wm::NativeCursorManagerDelegate* delegate) override {
  96. delegate->CommitMouseEventsEnabled(enabled);
  97. SetVisibility(delegate->IsCursorVisible(), delegate);
  98. }
  99. private:
  100. // Sets |cursor| as the active cursor within Aura.
  101. void SetCursorOnAllRootWindows(gfx::NativeCursor cursor) {
  102. for (auto* window : desktop_controller_->GetAllRootWindows())
  103. window->GetHost()->SetCursor(cursor);
  104. }
  105. raw_ptr<ShellDesktopControllerAura> desktop_controller_; // Not owned.
  106. wm::CursorLoader cursor_loader_{/*use_platform_cursors=*/false};
  107. };
  108. class AppsFocusRules : public wm::BaseFocusRules {
  109. public:
  110. AppsFocusRules() {}
  111. AppsFocusRules(const AppsFocusRules&) = delete;
  112. AppsFocusRules& operator=(const AppsFocusRules&) = delete;
  113. ~AppsFocusRules() override {}
  114. bool SupportsChildActivation(const aura::Window* window) const override {
  115. return true;
  116. }
  117. };
  118. } // namespace
  119. ShellDesktopControllerAura::ShellDesktopControllerAura(
  120. content::BrowserContext* browser_context)
  121. : browser_context_(browser_context),
  122. app_window_client_(new ShellAppWindowClient) {
  123. extensions::AppWindowClient::Set(app_window_client_.get());
  124. #if BUILDFLAG(IS_CHROMEOS_ASH)
  125. chromeos::PowerManagerClient::Get()->AddObserver(this);
  126. display_configurator_ = std::make_unique<display::DisplayConfigurator>();
  127. display_configurator_->Init(
  128. ui::OzonePlatform::GetInstance()->CreateNativeDisplayDelegate(), false);
  129. display_configurator_->ForceInitialConfigure();
  130. display_configurator_->AddObserver(this);
  131. #endif
  132. InitWindowManager();
  133. }
  134. ShellDesktopControllerAura::~ShellDesktopControllerAura() {
  135. TearDownWindowManager();
  136. #if BUILDFLAG(IS_CHROMEOS_ASH)
  137. chromeos::PowerManagerClient::Get()->RemoveObserver(this);
  138. #endif
  139. extensions::AppWindowClient::Set(NULL);
  140. }
  141. void ShellDesktopControllerAura::PreMainMessageLoopRun() {
  142. KeepAliveRegistry::GetInstance()->AddObserver(this);
  143. }
  144. void ShellDesktopControllerAura::WillRunMainMessageLoop(
  145. std::unique_ptr<base::RunLoop>& run_loop) {
  146. quit_when_idle_closure_ = run_loop->QuitWhenIdleClosure();
  147. }
  148. void ShellDesktopControllerAura::PostMainMessageLoopRun() {
  149. KeepAliveRegistry::GetInstance()->SetIsShuttingDown(true);
  150. KeepAliveRegistry::GetInstance()->RemoveObserver(this);
  151. }
  152. void ShellDesktopControllerAura::AddAppWindow(AppWindow* app_window,
  153. gfx::NativeWindow window) {
  154. // Find the closest display to the specified bounds.
  155. const display::Display& display =
  156. display::Screen::GetScreen()->GetDisplayMatching(
  157. window->GetBoundsInScreen());
  158. // Create a RootWindowController for the display if necessary.
  159. if (root_window_controllers_.count(display.id()) == 0) {
  160. root_window_controllers_[display.id()] =
  161. CreateRootWindowControllerForDisplay(display);
  162. }
  163. root_window_controllers_[display.id()]->AddAppWindow(app_window, window);
  164. }
  165. void ShellDesktopControllerAura::CloseAppWindows() {
  166. for (auto& pair : root_window_controllers_)
  167. pair.second->CloseAppWindows();
  168. }
  169. void ShellDesktopControllerAura::CloseRootWindowController(
  170. RootWindowController* root_window_controller) {
  171. const auto it = std::find_if(
  172. root_window_controllers_.cbegin(), root_window_controllers_.cend(),
  173. [root_window_controller](const auto& candidate_pair) {
  174. return candidate_pair.second.get() == root_window_controller;
  175. });
  176. DCHECK(it != root_window_controllers_.end());
  177. TearDownRootWindowController(it->second.get());
  178. root_window_controllers_.erase(it);
  179. MaybeQuit();
  180. }
  181. #if BUILDFLAG(IS_CHROMEOS_ASH)
  182. void ShellDesktopControllerAura::PowerButtonEventReceived(
  183. bool down,
  184. base::TimeTicks timestamp) {
  185. if (down) {
  186. chromeos::PowerManagerClient::Get()->RequestShutdown(
  187. power_manager::REQUEST_SHUTDOWN_FOR_USER, "AppShell power button");
  188. }
  189. }
  190. void ShellDesktopControllerAura::OnDisplayModeChanged(
  191. const display::DisplayConfigurator::DisplayStateList& displays) {
  192. for (const display::DisplaySnapshot* display_mode : displays) {
  193. if (!display_mode->current_mode())
  194. continue;
  195. auto it = root_window_controllers_.find(display_mode->display_id());
  196. if (it != root_window_controllers_.end())
  197. it->second->UpdateSize(display_mode->current_mode()->size());
  198. }
  199. }
  200. #endif
  201. ui::EventDispatchDetails ShellDesktopControllerAura::DispatchKeyEventPostIME(
  202. ui::KeyEvent* key_event) {
  203. if (key_event->target()) {
  204. aura::WindowTreeHost* host = static_cast<aura::Window*>(key_event->target())
  205. ->GetRootWindow()
  206. ->GetHost();
  207. return host->DispatchKeyEventPostIME(key_event);
  208. }
  209. // Send the key event to the focused window.
  210. aura::Window* active_window =
  211. const_cast<aura::Window*>(focus_controller_->GetActiveWindow());
  212. if (active_window) {
  213. return active_window->GetRootWindow()->GetHost()->DispatchKeyEventPostIME(
  214. key_event);
  215. }
  216. return GetPrimaryHost()->DispatchKeyEventPostIME(key_event);
  217. }
  218. void ShellDesktopControllerAura::OnKeepAliveStateChanged(
  219. bool is_keeping_alive) {
  220. if (!is_keeping_alive)
  221. MaybeQuit();
  222. }
  223. void ShellDesktopControllerAura::OnKeepAliveRestartStateChanged(
  224. bool can_restart) {}
  225. aura::WindowTreeHost* ShellDesktopControllerAura::GetPrimaryHost() {
  226. if (root_window_controllers_.empty())
  227. return nullptr;
  228. const display::Display& display =
  229. display::Screen::GetScreen()->GetPrimaryDisplay();
  230. if (root_window_controllers_.count(display.id()) == 1)
  231. return root_window_controllers_[display.id()]->host();
  232. // Fall back to an existing host.
  233. return root_window_controllers_.begin()->second->host();
  234. }
  235. aura::Window::Windows ShellDesktopControllerAura::GetAllRootWindows() {
  236. aura::Window::Windows windows;
  237. for (auto& pair : root_window_controllers_)
  238. windows.push_back(pair.second->host()->window());
  239. return windows;
  240. }
  241. void ShellDesktopControllerAura::SetWindowBoundsInScreen(
  242. AppWindow* app_window,
  243. const gfx::Rect& bounds) {
  244. display::Display display =
  245. display::Screen::GetScreen()->GetDisplayMatching(bounds);
  246. // Create a RootWindowController for the display if necessary.
  247. if (root_window_controllers_.count(display.id()) == 0) {
  248. root_window_controllers_[display.id()] =
  249. CreateRootWindowControllerForDisplay(display);
  250. }
  251. // Check if the window is parented to a different RootWindowController.
  252. if (app_window->GetNativeWindow()->GetRootWindow() !=
  253. root_window_controllers_[display.id()]->host()->window()) {
  254. // Move the window to the appropriate RootWindowController for the display.
  255. for (const auto& it : root_window_controllers_) {
  256. if (it.second->host()->window() ==
  257. app_window->GetNativeWindow()->GetRootWindow()) {
  258. it.second->RemoveAppWindow(app_window);
  259. break;
  260. }
  261. }
  262. root_window_controllers_[display.id()]->AddAppWindow(
  263. app_window, app_window->GetNativeWindow());
  264. }
  265. app_window->GetNativeWindow()->SetBoundsInScreen(bounds, display);
  266. }
  267. void ShellDesktopControllerAura::InitWindowManager() {
  268. root_window_event_filter_ = std::make_unique<wm::CompoundEventFilter>();
  269. // Screen may be initialized in tests.
  270. if (!display::Screen::GetScreen()) {
  271. #if BUILDFLAG(IS_CHROMEOS_ASH)
  272. screen_ = std::make_unique<ShellScreen>(this, GetStartingWindowSize());
  273. // TODO(pkasting): Make ShellScreen() call SetScreenInstance() as the
  274. // classes in CreateDesktopScreen() do, and remove this.
  275. display::Screen::SetScreenInstance(screen_.get());
  276. #else
  277. // TODO(crbug.com/756680): Refactor DesktopScreen out of views.
  278. screen_ = views::CreateDesktopScreen();
  279. #endif
  280. }
  281. focus_controller_ =
  282. std::make_unique<wm::FocusController>(new AppsFocusRules());
  283. cursor_manager_ = std::make_unique<wm::CursorManager>(
  284. std::make_unique<ShellNativeCursorManager>(this));
  285. cursor_manager_->SetDisplay(
  286. display::Screen::GetScreen()->GetPrimaryDisplay());
  287. cursor_manager_->SetCursor(ui::mojom::CursorType::kPointer);
  288. #if BUILDFLAG(IS_CHROMEOS_ASH)
  289. user_activity_detector_ = std::make_unique<ui::UserActivityDetector>();
  290. user_activity_notifier_ =
  291. std::make_unique<ui::UserActivityPowerManagerNotifier>(
  292. user_activity_detector_.get(), /*fingerprint=*/mojo::NullRemote());
  293. #endif
  294. }
  295. void ShellDesktopControllerAura::TearDownWindowManager() {
  296. for (auto& pair : root_window_controllers_)
  297. TearDownRootWindowController(pair.second.get());
  298. root_window_controllers_.clear();
  299. #if BUILDFLAG(IS_CHROMEOS_ASH)
  300. user_activity_notifier_.reset();
  301. user_activity_detector_.reset();
  302. #endif
  303. cursor_manager_.reset();
  304. focus_controller_.reset();
  305. if (screen_) {
  306. #if BUILDFLAG(IS_CHROMEOS_ASH)
  307. display::Screen::SetScreenInstance(nullptr);
  308. #endif
  309. screen_.reset();
  310. }
  311. root_window_event_filter_.reset();
  312. }
  313. std::unique_ptr<RootWindowController>
  314. ShellDesktopControllerAura::CreateRootWindowControllerForDisplay(
  315. const display::Display& display) {
  316. // Convert display's bounds from DIP to physical pixels for WindowTreeHost.
  317. gfx::Rect bounds(gfx::ScaleToFlooredPoint(display.bounds().origin(),
  318. display.device_scale_factor()),
  319. display.GetSizeInPixel());
  320. auto root_window_controller =
  321. std::make_unique<RootWindowController>(this, bounds, browser_context_);
  322. // Initialize the root window with our clients.
  323. aura::Window* root_window = root_window_controller->host()->window();
  324. root_window->AddPreTargetHandler(root_window_event_filter_.get());
  325. aura::client::SetFocusClient(root_window, focus_controller_.get());
  326. root_window->AddPreTargetHandler(focus_controller_.get());
  327. wm::SetActivationClient(root_window, focus_controller_.get());
  328. aura::client::SetCursorClient(root_window, cursor_manager_.get());
  329. if (!input_method_) {
  330. // Create an input method and become its key event dispatcher.
  331. input_method_ = ui::CreateInputMethod(
  332. this, root_window_controller->host()->GetAcceleratedWidget());
  333. root_window_controller->host()->SetSharedInputMethod(input_method_.get());
  334. }
  335. return root_window_controller;
  336. }
  337. void ShellDesktopControllerAura::TearDownRootWindowController(
  338. RootWindowController* root) {
  339. root->host()->window()->RemovePreTargetHandler(
  340. root_window_event_filter_.get());
  341. root->host()->window()->RemovePreTargetHandler(focus_controller_.get());
  342. }
  343. void ShellDesktopControllerAura::MaybeQuit() {
  344. // Quit if there are no app windows open and no keep-alives waiting for apps
  345. // to relaunch. |run_loop_| may be null in tests.
  346. if (quit_when_idle_closure_ && root_window_controllers_.empty() &&
  347. !KeepAliveRegistry::GetInstance()->IsKeepingAlive()) {
  348. std::move(quit_when_idle_closure_).Run();
  349. }
  350. }
  351. #if BUILDFLAG(IS_CHROMEOS_ASH)
  352. gfx::Size ShellDesktopControllerAura::GetStartingWindowSize() {
  353. gfx::Size size = GetPrimaryDisplaySize();
  354. base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  355. if (command_line->HasSwitch(switches::kAppShellHostWindowSize)) {
  356. const std::string size_str =
  357. command_line->GetSwitchValueASCII(switches::kAppShellHostWindowSize);
  358. int width, height;
  359. CHECK_EQ(2, sscanf(size_str.c_str(), "%dx%d", &width, &height));
  360. size = gfx::Size(width, height);
  361. }
  362. return size.IsEmpty() ? gfx::Size(1920, 1080) : size;
  363. }
  364. gfx::Size ShellDesktopControllerAura::GetPrimaryDisplaySize() {
  365. const display::DisplayConfigurator::DisplayStateList& displays =
  366. display_configurator_->cached_displays();
  367. const display::DisplayMode* mode =
  368. displays.empty() ? nullptr : displays[0]->current_mode();
  369. return mode ? mode->size() : gfx::Size();
  370. }
  371. #endif
  372. } // namespace extensions