window_util.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. // Copyright (c) 2012 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 "ash/wm/window_util.h"
  5. #include <memory>
  6. #include <tuple>
  7. #include "ash/constants/app_types.h"
  8. #include "ash/multi_user/multi_user_window_manager_impl.h"
  9. #include "ash/public/cpp/app_types_util.h"
  10. #include "ash/public/cpp/shell_window_ids.h"
  11. #include "ash/public/cpp/tablet_mode_observer.h"
  12. #include "ash/public/cpp/window_properties.h"
  13. #include "ash/root_window_controller.h"
  14. #include "ash/scoped_animation_disabler.h"
  15. #include "ash/screen_util.h"
  16. #include "ash/session/session_controller_impl.h"
  17. #include "ash/shelf/shelf.h"
  18. #include "ash/shell.h"
  19. #include "ash/shell_delegate.h"
  20. #include "ash/wm/mru_window_tracker.h"
  21. #include "ash/wm/overview/overview_controller.h"
  22. #include "ash/wm/overview/overview_session.h"
  23. #include "ash/wm/splitview/split_view_controller.h"
  24. #include "ash/wm/tablet_mode/tablet_mode_controller.h"
  25. #include "ash/wm/window_positioning_utils.h"
  26. #include "ash/wm/window_state.h"
  27. #include "ash/wm/wm_event.h"
  28. #include "base/bind.h"
  29. #include "base/containers/contains.h"
  30. #include "chromeos/ui/base/chromeos_ui_constants.h"
  31. #include "chromeos/ui/frame/interior_resize_handler_targeter.h"
  32. #include "ui/aura/client/aura_constants.h"
  33. #include "ui/aura/client/capture_client.h"
  34. #include "ui/aura/client/focus_client.h"
  35. #include "ui/aura/window.h"
  36. #include "ui/aura/window_delegate.h"
  37. #include "ui/aura/window_event_dispatcher.h"
  38. #include "ui/aura/window_targeter.h"
  39. #include "ui/base/hit_test.h"
  40. #include "ui/compositor/compositor.h"
  41. #include "ui/compositor/layer.h"
  42. #include "ui/compositor/layer_tree_owner.h"
  43. #include "ui/display/display.h"
  44. #include "ui/display/screen.h"
  45. #include "ui/events/event.h"
  46. #include "ui/gfx/geometry/rect.h"
  47. #include "ui/gfx/geometry/size.h"
  48. #include "ui/gfx/geometry/transform_util.h"
  49. #include "ui/views/view.h"
  50. #include "ui/views/widget/widget.h"
  51. #include "ui/wm/core/coordinate_conversion.h"
  52. #include "ui/wm/core/easy_resize_window_targeter.h"
  53. #include "ui/wm/core/window_animations.h"
  54. #include "ui/wm/public/activation_client.h"
  55. namespace ash {
  56. namespace window_util {
  57. namespace {
  58. // This window targeter reserves space for the portion of the resize handles
  59. // that extend within a top level window.
  60. class InteriorResizeHandleTargeterAsh
  61. : public chromeos::InteriorResizeHandleTargeter {
  62. public:
  63. InteriorResizeHandleTargeterAsh() = default;
  64. InteriorResizeHandleTargeterAsh(const InteriorResizeHandleTargeterAsh&) =
  65. delete;
  66. InteriorResizeHandleTargeterAsh& operator=(
  67. const InteriorResizeHandleTargeterAsh&) = delete;
  68. ~InteriorResizeHandleTargeterAsh() override = default;
  69. bool ShouldUseExtendedBounds(const aura::Window* target) const override {
  70. // Fullscreen/maximized windows can't be drag-resized.
  71. const WindowState* window_state = WindowState::Get(window());
  72. if (window_state && window_state->IsMaximizedOrFullscreenOrPinned())
  73. return false;
  74. // The shrunken hit region only applies to children of |window()|.
  75. return InteriorResizeHandleTargeter::ShouldUseExtendedBounds(target);
  76. }
  77. };
  78. } // namespace
  79. aura::Window* GetActiveWindow() {
  80. if (auto* activation_client =
  81. wm::GetActivationClient(Shell::GetPrimaryRootWindow())) {
  82. return activation_client->GetActiveWindow();
  83. }
  84. return nullptr;
  85. }
  86. aura::Window* GetFocusedWindow() {
  87. return aura::client::GetFocusClient(Shell::GetPrimaryRootWindow())
  88. ->GetFocusedWindow();
  89. }
  90. aura::Window* GetCaptureWindow() {
  91. return aura::client::GetCaptureWindow(Shell::GetPrimaryRootWindow());
  92. }
  93. void GetBlockingContainersForRoot(aura::Window* root_window,
  94. aura::Window** min_container,
  95. aura::Window** system_modal_container) {
  96. if (Shell::Get()->session_controller()->IsUserSessionBlocked()) {
  97. *min_container =
  98. root_window->GetChildById(kShellWindowId_LockScreenContainersContainer);
  99. *system_modal_container =
  100. root_window->GetChildById(kShellWindowId_LockSystemModalContainer);
  101. } else {
  102. *min_container = nullptr;
  103. *system_modal_container =
  104. root_window->GetChildById(kShellWindowId_SystemModalContainer);
  105. }
  106. }
  107. bool IsWindowUserPositionable(aura::Window* window) {
  108. return window->GetType() == aura::client::WINDOW_TYPE_NORMAL;
  109. }
  110. void PinWindow(aura::Window* window, bool trusted) {
  111. WMEvent event(trusted ? WM_EVENT_TRUSTED_PIN : WM_EVENT_PIN);
  112. WindowState::Get(window)->OnWMEvent(&event);
  113. }
  114. void SetAutoHideShelf(aura::Window* window, bool autohide) {
  115. WindowState::Get(window)->set_autohide_shelf_when_maximized_or_fullscreen(
  116. autohide);
  117. for (aura::Window* root_window : Shell::GetAllRootWindows())
  118. Shelf::ForWindow(root_window)->UpdateVisibilityState();
  119. }
  120. bool MoveWindowToDisplay(aura::Window* window, int64_t display_id) {
  121. DCHECK(window);
  122. aura::Window* root = Shell::GetRootWindowForDisplayId(display_id);
  123. if (!root || root == window->GetRootWindow()) {
  124. NOTREACHED();
  125. return false;
  126. }
  127. WindowState* window_state = WindowState::Get(window);
  128. if (window_state->allow_set_bounds_direct()) {
  129. display::Display display;
  130. if (!display::Screen::GetScreen()->GetDisplayWithDisplayId(display_id,
  131. &display))
  132. return false;
  133. gfx::Rect bounds = window->bounds();
  134. gfx::Rect work_area_in_display(display.size());
  135. work_area_in_display.Inset(display.GetWorkAreaInsets());
  136. AdjustBoundsToEnsureMinimumWindowVisibility(work_area_in_display, &bounds);
  137. SetBoundsWMEvent event(bounds, display_id);
  138. window_state->OnWMEvent(&event);
  139. return true;
  140. }
  141. // Moves |window| to the given |root| window's corresponding container.
  142. aura::Window* container = RootWindowController::ForWindow(root)->GetContainer(
  143. window->parent()->GetId());
  144. if (!container)
  145. return false;
  146. // Update restore bounds to target root window.
  147. if (window_state->HasRestoreBounds()) {
  148. gfx::Rect restore_bounds = window_state->GetRestoreBoundsInParent();
  149. ::wm::ConvertRectToScreen(root, &restore_bounds);
  150. window_state->SetRestoreBoundsInScreen(restore_bounds);
  151. }
  152. container->AddChild(window);
  153. return true;
  154. }
  155. int GetNonClientComponent(aura::Window* window, const gfx::Point& location) {
  156. return window->delegate()
  157. ? window->delegate()->GetNonClientComponent(location)
  158. : HTNOWHERE;
  159. }
  160. void SetChildrenUseExtendedHitRegionForWindow(aura::Window* window) {
  161. gfx::Insets mouse_extend(-chromeos::kResizeOutsideBoundsSize);
  162. gfx::Insets touch_extend = gfx::ScaleToFlooredInsets(
  163. mouse_extend, chromeos::kResizeOutsideBoundsScaleForTouch);
  164. window->SetEventTargeter(std::make_unique<::wm::EasyResizeWindowTargeter>(
  165. mouse_extend, touch_extend));
  166. }
  167. void CloseWidgetForWindow(aura::Window* window) {
  168. views::Widget* widget = views::Widget::GetWidgetForNativeView(window);
  169. DCHECK(widget);
  170. widget->Close();
  171. }
  172. void InstallResizeHandleWindowTargeterForWindow(aura::Window* window) {
  173. window->SetEventTargeter(std::make_unique<InteriorResizeHandleTargeterAsh>());
  174. }
  175. bool IsDraggingTabs(const aura::Window* window) {
  176. return window->GetProperty(ash::kIsDraggingTabsKey);
  177. }
  178. bool ShouldExcludeForCycleList(const aura::Window* window) {
  179. // Exclude windows:
  180. // - non user positionable windows, such as extension popups.
  181. // - windows being dragged
  182. // - pip windows
  183. const WindowState* state = WindowState::Get(window);
  184. if (!state->IsUserPositionable() || state->is_dragged() || state->IsPip())
  185. return true;
  186. // Exclude the AppList window, which will hide as soon as cycling starts
  187. // anyway. It doesn't make sense to count it as a "switchable" window, yet
  188. // a lot of code relies on the MRU list returning the app window. If we
  189. // don't manually remove it, the window cycling UI won't crash or misbehave,
  190. // but there will be a flicker as the target window changes. Also exclude
  191. // unselectable windows such as extension popups.
  192. for (auto* parent = window->parent(); parent; parent = parent->parent()) {
  193. if (parent->GetId() == kShellWindowId_AppListContainer)
  194. return true;
  195. }
  196. return window->GetProperty(kHideInOverviewKey);
  197. }
  198. bool ShouldExcludeForOverview(const aura::Window* window) {
  199. // If we're currently in tablet splitview, remove the default snapped window
  200. // from the window list. The default snapped window occupies one side of the
  201. // screen, while the other windows occupy the other side of the screen in
  202. // overview mode. The default snap position is the position where the window
  203. // was first snapped. See |default_snap_position_| in SplitViewController for
  204. // more detail.
  205. auto* split_view_controller =
  206. SplitViewController::Get(Shell::GetPrimaryRootWindow());
  207. if (split_view_controller->InTabletSplitViewMode() &&
  208. window == split_view_controller->GetDefaultSnappedWindow()) {
  209. return true;
  210. }
  211. // Remove everything cycle list should not have.
  212. return ShouldExcludeForCycleList(window);
  213. }
  214. void EnsureTransientRoots(std::vector<aura::Window*>* out_window_list) {
  215. for (auto it = out_window_list->begin(); it != out_window_list->end();) {
  216. aura::Window* transient_root = ::wm::GetTransientRoot(*it);
  217. if (*it != transient_root) {
  218. if (base::Contains(*out_window_list, transient_root)) {
  219. it = out_window_list->erase(it);
  220. } else {
  221. *it = transient_root;
  222. ++it;
  223. }
  224. } else {
  225. ++it;
  226. }
  227. }
  228. }
  229. void MinimizeAndHideWithoutAnimation(
  230. const std::vector<aura::Window*>& windows) {
  231. for (auto* window : windows) {
  232. ScopedAnimationDisabler disable(window);
  233. // ARC windows are minimized asynchronously, so we hide them after
  234. // minimization. We minimize ARC windows first so they receive occlusion
  235. // updates before losing focus from being hidden. See crbug.com/910304.
  236. // TODO(oshima): Investigate better way to handle ARC apps immediately.
  237. WindowState::Get(window)->Minimize();
  238. window->Hide();
  239. }
  240. if (windows.size()) {
  241. // Disable the animations using |disable|. However, doing so will skip
  242. // detaching the resources associated with the layer. So we have to trick
  243. // the compositor into releasing the resources.
  244. // crbug.com/924802.
  245. auto* compositor = windows[0]->layer()->GetCompositor();
  246. bool was_visible = compositor->IsVisible();
  247. compositor->SetVisible(false);
  248. compositor->SetVisible(was_visible);
  249. }
  250. }
  251. aura::Window* GetRootWindowAt(const gfx::Point& point_in_screen) {
  252. const display::Display& display =
  253. display::Screen::GetScreen()->GetDisplayNearestPoint(point_in_screen);
  254. DCHECK(display.is_valid());
  255. RootWindowController* root_window_controller =
  256. Shell::GetRootWindowControllerWithDisplayId(display.id());
  257. return root_window_controller ? root_window_controller->GetRootWindow()
  258. : nullptr;
  259. }
  260. aura::Window* GetRootWindowMatching(const gfx::Rect& rect_in_screen) {
  261. const display::Display& display =
  262. display::Screen::GetScreen()->GetDisplayMatching(rect_in_screen);
  263. RootWindowController* root_window_controller =
  264. Shell::GetRootWindowControllerWithDisplayId(display.id());
  265. return root_window_controller ? root_window_controller->GetRootWindow()
  266. : nullptr;
  267. }
  268. bool IsArcPipWindow(const aura::Window* window) {
  269. return IsArcWindow(window) && WindowState::Get(window)->IsPip();
  270. }
  271. void ExpandArcPipWindow() {
  272. auto* pip_container = Shell::GetContainer(Shell::GetPrimaryRootWindow(),
  273. kShellWindowId_PipContainer);
  274. if (!pip_container)
  275. return;
  276. auto pip_window_iter =
  277. std::find_if(pip_container->children().begin(),
  278. pip_container->children().end(), IsArcPipWindow);
  279. if (pip_window_iter == pip_container->children().end())
  280. return;
  281. auto* window_state = WindowState::Get(*pip_window_iter);
  282. window_state->Restore();
  283. }
  284. bool IsAnyWindowDragged() {
  285. OverviewController* overview_controller = Shell::Get()->overview_controller();
  286. if (overview_controller->InOverviewSession() &&
  287. overview_controller->overview_session()
  288. ->GetCurrentDraggedOverviewItem()) {
  289. return true;
  290. }
  291. for (aura::Window* window :
  292. Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk)) {
  293. if (WindowState::Get(window)->is_dragged())
  294. return true;
  295. }
  296. return false;
  297. }
  298. aura::Window* GetTopWindow() {
  299. MruWindowTracker::WindowList windows =
  300. Shell::Get()->mru_window_tracker()->BuildWindowForCycleList(kActiveDesk);
  301. return windows.empty() ? nullptr : windows[0];
  302. }
  303. bool ShouldMinimizeTopWindowOnBack() {
  304. Shell* shell = Shell::Get();
  305. // We never want to minimize the main app window in the Kiosk session.
  306. if (shell->session_controller()->IsRunningInAppMode())
  307. return false;
  308. if (!shell->tablet_mode_controller()->InTabletMode())
  309. return false;
  310. aura::Window* window = GetTopWindow();
  311. if (!window)
  312. return false;
  313. // Do not minimize the window if it is in overview. This can avoid unnecessary
  314. // window minimize animation.
  315. OverviewController* overview_controller = Shell::Get()->overview_controller();
  316. if (overview_controller->InOverviewSession() &&
  317. overview_controller->overview_session()->IsWindowInOverview(window)) {
  318. return false;
  319. }
  320. // ARC and crostini apps will handle the back event that follows on the client
  321. // side and will minimize/close the window there.
  322. const int app_type = window->GetProperty(aura::client::kAppType);
  323. if (app_type == static_cast<int>(AppType::ARC_APP) ||
  324. app_type == static_cast<int>(AppType::CROSTINI_APP)) {
  325. return false;
  326. }
  327. // Use the value of |kMinimizeOnBackKey| if it is provided. It can be provided
  328. // by windows with custom web contents.
  329. bool* can_minimize_on_back_key = window->GetProperty(kMinimizeOnBackKey);
  330. if (can_minimize_on_back_key)
  331. return *can_minimize_on_back_key;
  332. // Minimize the window if it is at the bottom page.
  333. return !shell->shell_delegate()->CanGoBack(window);
  334. }
  335. void SendBackKeyEvent(aura::Window* root_window) {
  336. // Send up event as well as down event as ARC++ clients expect this
  337. // sequence.
  338. // TODO: Investigate if we should be using the current modifiers.
  339. ui::KeyEvent press_key_event(ui::ET_KEY_PRESSED, ui::VKEY_BROWSER_BACK,
  340. ui::EF_NONE);
  341. std::ignore = root_window->GetHost()->SendEventToSink(&press_key_event);
  342. ui::KeyEvent release_key_event(ui::ET_KEY_RELEASED, ui::VKEY_BROWSER_BACK,
  343. ui::EF_NONE);
  344. std::ignore = root_window->GetHost()->SendEventToSink(&release_key_event);
  345. }
  346. WindowTransientDescendantIteratorRange GetVisibleTransientTreeIterator(
  347. aura::Window* window) {
  348. auto hide_predicate = [](aura::Window* window) {
  349. return window->GetProperty(kHideInOverviewKey);
  350. };
  351. return GetTransientTreeIterator(window, base::BindRepeating(hide_predicate));
  352. }
  353. gfx::RectF GetTransformedBounds(aura::Window* transformed_window,
  354. int top_inset) {
  355. gfx::RectF bounds;
  356. for (auto* window : GetVisibleTransientTreeIterator(transformed_window)) {
  357. // Ignore other window types when computing bounding box of overview target
  358. // item.
  359. if (window != transformed_window &&
  360. window->GetType() != aura::client::WINDOW_TYPE_NORMAL) {
  361. continue;
  362. }
  363. gfx::RectF window_bounds(window->GetTargetBounds());
  364. gfx::Transform new_transform =
  365. TransformAboutPivot(gfx::ToRoundedPoint(window_bounds.origin()),
  366. window->layer()->GetTargetTransform());
  367. new_transform.TransformRect(&window_bounds);
  368. // The preview title is shown above the preview window. Hide the window
  369. // header for apps or browser windows with no tabs (web apps) to avoid
  370. // showing both the window header and the preview title.
  371. if (top_inset > 0) {
  372. gfx::RectF header_bounds(window_bounds);
  373. header_bounds.set_height(top_inset);
  374. new_transform.TransformRect(&header_bounds);
  375. window_bounds.Inset(gfx::InsetsF::TLBR(header_bounds.height(), 0, 0, 0));
  376. }
  377. ::wm::TranslateRectToScreen(window->parent(), &window_bounds);
  378. bounds.Union(window_bounds);
  379. }
  380. return bounds;
  381. }
  382. bool ShouldShowForCurrentUser(aura::Window* window) {
  383. MultiUserWindowManager* multi_user_window_manager =
  384. MultiUserWindowManagerImpl::Get();
  385. if (!multi_user_window_manager)
  386. return true;
  387. const AccountId account_id =
  388. multi_user_window_manager->GetUserPresentingWindow(window);
  389. // An empty account ID is returned if the window is presented for all users.
  390. if (!account_id.is_valid())
  391. return true;
  392. return account_id == multi_user_window_manager->CurrentAccountId();
  393. }
  394. aura::Window* GetEventHandlerForEvent(const ui::LocatedEvent& event) {
  395. gfx::Point location_in_screen = event.location();
  396. ::wm::ConvertPointToScreen(static_cast<aura::Window*>(event.target()),
  397. &location_in_screen);
  398. aura::Window* root_window_at_point = GetRootWindowAt(location_in_screen);
  399. gfx::Point location_in_root = location_in_screen;
  400. ::wm::ConvertPointFromScreen(root_window_at_point, &location_in_root);
  401. return root_window_at_point->GetEventHandlerForPoint(location_in_root);
  402. }
  403. } // namespace window_util
  404. } // namespace ash