123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465 |
- // Copyright (c) 2012 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 "ash/wm/window_util.h"
- #include <memory>
- #include <tuple>
- #include "ash/constants/app_types.h"
- #include "ash/multi_user/multi_user_window_manager_impl.h"
- #include "ash/public/cpp/app_types_util.h"
- #include "ash/public/cpp/shell_window_ids.h"
- #include "ash/public/cpp/tablet_mode_observer.h"
- #include "ash/public/cpp/window_properties.h"
- #include "ash/root_window_controller.h"
- #include "ash/scoped_animation_disabler.h"
- #include "ash/screen_util.h"
- #include "ash/session/session_controller_impl.h"
- #include "ash/shelf/shelf.h"
- #include "ash/shell.h"
- #include "ash/shell_delegate.h"
- #include "ash/wm/mru_window_tracker.h"
- #include "ash/wm/overview/overview_controller.h"
- #include "ash/wm/overview/overview_session.h"
- #include "ash/wm/splitview/split_view_controller.h"
- #include "ash/wm/tablet_mode/tablet_mode_controller.h"
- #include "ash/wm/window_positioning_utils.h"
- #include "ash/wm/window_state.h"
- #include "ash/wm/wm_event.h"
- #include "base/bind.h"
- #include "base/containers/contains.h"
- #include "chromeos/ui/base/chromeos_ui_constants.h"
- #include "chromeos/ui/frame/interior_resize_handler_targeter.h"
- #include "ui/aura/client/aura_constants.h"
- #include "ui/aura/client/capture_client.h"
- #include "ui/aura/client/focus_client.h"
- #include "ui/aura/window.h"
- #include "ui/aura/window_delegate.h"
- #include "ui/aura/window_event_dispatcher.h"
- #include "ui/aura/window_targeter.h"
- #include "ui/base/hit_test.h"
- #include "ui/compositor/compositor.h"
- #include "ui/compositor/layer.h"
- #include "ui/compositor/layer_tree_owner.h"
- #include "ui/display/display.h"
- #include "ui/display/screen.h"
- #include "ui/events/event.h"
- #include "ui/gfx/geometry/rect.h"
- #include "ui/gfx/geometry/size.h"
- #include "ui/gfx/geometry/transform_util.h"
- #include "ui/views/view.h"
- #include "ui/views/widget/widget.h"
- #include "ui/wm/core/coordinate_conversion.h"
- #include "ui/wm/core/easy_resize_window_targeter.h"
- #include "ui/wm/core/window_animations.h"
- #include "ui/wm/public/activation_client.h"
- namespace ash {
- namespace window_util {
- namespace {
- // This window targeter reserves space for the portion of the resize handles
- // that extend within a top level window.
- class InteriorResizeHandleTargeterAsh
- : public chromeos::InteriorResizeHandleTargeter {
- public:
- InteriorResizeHandleTargeterAsh() = default;
- InteriorResizeHandleTargeterAsh(const InteriorResizeHandleTargeterAsh&) =
- delete;
- InteriorResizeHandleTargeterAsh& operator=(
- const InteriorResizeHandleTargeterAsh&) = delete;
- ~InteriorResizeHandleTargeterAsh() override = default;
- bool ShouldUseExtendedBounds(const aura::Window* target) const override {
- // Fullscreen/maximized windows can't be drag-resized.
- const WindowState* window_state = WindowState::Get(window());
- if (window_state && window_state->IsMaximizedOrFullscreenOrPinned())
- return false;
- // The shrunken hit region only applies to children of |window()|.
- return InteriorResizeHandleTargeter::ShouldUseExtendedBounds(target);
- }
- };
- } // namespace
- aura::Window* GetActiveWindow() {
- if (auto* activation_client =
- wm::GetActivationClient(Shell::GetPrimaryRootWindow())) {
- return activation_client->GetActiveWindow();
- }
- return nullptr;
- }
- aura::Window* GetFocusedWindow() {
- return aura::client::GetFocusClient(Shell::GetPrimaryRootWindow())
- ->GetFocusedWindow();
- }
- aura::Window* GetCaptureWindow() {
- return aura::client::GetCaptureWindow(Shell::GetPrimaryRootWindow());
- }
- void GetBlockingContainersForRoot(aura::Window* root_window,
- aura::Window** min_container,
- aura::Window** system_modal_container) {
- if (Shell::Get()->session_controller()->IsUserSessionBlocked()) {
- *min_container =
- root_window->GetChildById(kShellWindowId_LockScreenContainersContainer);
- *system_modal_container =
- root_window->GetChildById(kShellWindowId_LockSystemModalContainer);
- } else {
- *min_container = nullptr;
- *system_modal_container =
- root_window->GetChildById(kShellWindowId_SystemModalContainer);
- }
- }
- bool IsWindowUserPositionable(aura::Window* window) {
- return window->GetType() == aura::client::WINDOW_TYPE_NORMAL;
- }
- void PinWindow(aura::Window* window, bool trusted) {
- WMEvent event(trusted ? WM_EVENT_TRUSTED_PIN : WM_EVENT_PIN);
- WindowState::Get(window)->OnWMEvent(&event);
- }
- void SetAutoHideShelf(aura::Window* window, bool autohide) {
- WindowState::Get(window)->set_autohide_shelf_when_maximized_or_fullscreen(
- autohide);
- for (aura::Window* root_window : Shell::GetAllRootWindows())
- Shelf::ForWindow(root_window)->UpdateVisibilityState();
- }
- bool MoveWindowToDisplay(aura::Window* window, int64_t display_id) {
- DCHECK(window);
- aura::Window* root = Shell::GetRootWindowForDisplayId(display_id);
- if (!root || root == window->GetRootWindow()) {
- NOTREACHED();
- return false;
- }
- WindowState* window_state = WindowState::Get(window);
- if (window_state->allow_set_bounds_direct()) {
- display::Display display;
- if (!display::Screen::GetScreen()->GetDisplayWithDisplayId(display_id,
- &display))
- return false;
- gfx::Rect bounds = window->bounds();
- gfx::Rect work_area_in_display(display.size());
- work_area_in_display.Inset(display.GetWorkAreaInsets());
- AdjustBoundsToEnsureMinimumWindowVisibility(work_area_in_display, &bounds);
- SetBoundsWMEvent event(bounds, display_id);
- window_state->OnWMEvent(&event);
- return true;
- }
- // Moves |window| to the given |root| window's corresponding container.
- aura::Window* container = RootWindowController::ForWindow(root)->GetContainer(
- window->parent()->GetId());
- if (!container)
- return false;
- // Update restore bounds to target root window.
- if (window_state->HasRestoreBounds()) {
- gfx::Rect restore_bounds = window_state->GetRestoreBoundsInParent();
- ::wm::ConvertRectToScreen(root, &restore_bounds);
- window_state->SetRestoreBoundsInScreen(restore_bounds);
- }
- container->AddChild(window);
- return true;
- }
- int GetNonClientComponent(aura::Window* window, const gfx::Point& location) {
- return window->delegate()
- ? window->delegate()->GetNonClientComponent(location)
- : HTNOWHERE;
- }
- void SetChildrenUseExtendedHitRegionForWindow(aura::Window* window) {
- gfx::Insets mouse_extend(-chromeos::kResizeOutsideBoundsSize);
- gfx::Insets touch_extend = gfx::ScaleToFlooredInsets(
- mouse_extend, chromeos::kResizeOutsideBoundsScaleForTouch);
- window->SetEventTargeter(std::make_unique<::wm::EasyResizeWindowTargeter>(
- mouse_extend, touch_extend));
- }
- void CloseWidgetForWindow(aura::Window* window) {
- views::Widget* widget = views::Widget::GetWidgetForNativeView(window);
- DCHECK(widget);
- widget->Close();
- }
- void InstallResizeHandleWindowTargeterForWindow(aura::Window* window) {
- window->SetEventTargeter(std::make_unique<InteriorResizeHandleTargeterAsh>());
- }
- bool IsDraggingTabs(const aura::Window* window) {
- return window->GetProperty(ash::kIsDraggingTabsKey);
- }
- bool ShouldExcludeForCycleList(const aura::Window* window) {
- // Exclude windows:
- // - non user positionable windows, such as extension popups.
- // - windows being dragged
- // - pip windows
- const WindowState* state = WindowState::Get(window);
- if (!state->IsUserPositionable() || state->is_dragged() || state->IsPip())
- return true;
- // Exclude the AppList window, which will hide as soon as cycling starts
- // anyway. It doesn't make sense to count it as a "switchable" window, yet
- // a lot of code relies on the MRU list returning the app window. If we
- // don't manually remove it, the window cycling UI won't crash or misbehave,
- // but there will be a flicker as the target window changes. Also exclude
- // unselectable windows such as extension popups.
- for (auto* parent = window->parent(); parent; parent = parent->parent()) {
- if (parent->GetId() == kShellWindowId_AppListContainer)
- return true;
- }
- return window->GetProperty(kHideInOverviewKey);
- }
- bool ShouldExcludeForOverview(const aura::Window* window) {
- // If we're currently in tablet splitview, remove the default snapped window
- // from the window list. The default snapped window occupies one side of the
- // screen, while the other windows occupy the other side of the screen in
- // overview mode. The default snap position is the position where the window
- // was first snapped. See |default_snap_position_| in SplitViewController for
- // more detail.
- auto* split_view_controller =
- SplitViewController::Get(Shell::GetPrimaryRootWindow());
- if (split_view_controller->InTabletSplitViewMode() &&
- window == split_view_controller->GetDefaultSnappedWindow()) {
- return true;
- }
- // Remove everything cycle list should not have.
- return ShouldExcludeForCycleList(window);
- }
- void EnsureTransientRoots(std::vector<aura::Window*>* out_window_list) {
- for (auto it = out_window_list->begin(); it != out_window_list->end();) {
- aura::Window* transient_root = ::wm::GetTransientRoot(*it);
- if (*it != transient_root) {
- if (base::Contains(*out_window_list, transient_root)) {
- it = out_window_list->erase(it);
- } else {
- *it = transient_root;
- ++it;
- }
- } else {
- ++it;
- }
- }
- }
- void MinimizeAndHideWithoutAnimation(
- const std::vector<aura::Window*>& windows) {
- for (auto* window : windows) {
- ScopedAnimationDisabler disable(window);
- // ARC windows are minimized asynchronously, so we hide them after
- // minimization. We minimize ARC windows first so they receive occlusion
- // updates before losing focus from being hidden. See crbug.com/910304.
- // TODO(oshima): Investigate better way to handle ARC apps immediately.
- WindowState::Get(window)->Minimize();
- window->Hide();
- }
- if (windows.size()) {
- // Disable the animations using |disable|. However, doing so will skip
- // detaching the resources associated with the layer. So we have to trick
- // the compositor into releasing the resources.
- // crbug.com/924802.
- auto* compositor = windows[0]->layer()->GetCompositor();
- bool was_visible = compositor->IsVisible();
- compositor->SetVisible(false);
- compositor->SetVisible(was_visible);
- }
- }
- aura::Window* GetRootWindowAt(const gfx::Point& point_in_screen) {
- const display::Display& display =
- display::Screen::GetScreen()->GetDisplayNearestPoint(point_in_screen);
- DCHECK(display.is_valid());
- RootWindowController* root_window_controller =
- Shell::GetRootWindowControllerWithDisplayId(display.id());
- return root_window_controller ? root_window_controller->GetRootWindow()
- : nullptr;
- }
- aura::Window* GetRootWindowMatching(const gfx::Rect& rect_in_screen) {
- const display::Display& display =
- display::Screen::GetScreen()->GetDisplayMatching(rect_in_screen);
- RootWindowController* root_window_controller =
- Shell::GetRootWindowControllerWithDisplayId(display.id());
- return root_window_controller ? root_window_controller->GetRootWindow()
- : nullptr;
- }
- bool IsArcPipWindow(const aura::Window* window) {
- return IsArcWindow(window) && WindowState::Get(window)->IsPip();
- }
- void ExpandArcPipWindow() {
- auto* pip_container = Shell::GetContainer(Shell::GetPrimaryRootWindow(),
- kShellWindowId_PipContainer);
- if (!pip_container)
- return;
- auto pip_window_iter =
- std::find_if(pip_container->children().begin(),
- pip_container->children().end(), IsArcPipWindow);
- if (pip_window_iter == pip_container->children().end())
- return;
- auto* window_state = WindowState::Get(*pip_window_iter);
- window_state->Restore();
- }
- bool IsAnyWindowDragged() {
- OverviewController* overview_controller = Shell::Get()->overview_controller();
- if (overview_controller->InOverviewSession() &&
- overview_controller->overview_session()
- ->GetCurrentDraggedOverviewItem()) {
- return true;
- }
- for (aura::Window* window :
- Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk)) {
- if (WindowState::Get(window)->is_dragged())
- return true;
- }
- return false;
- }
- aura::Window* GetTopWindow() {
- MruWindowTracker::WindowList windows =
- Shell::Get()->mru_window_tracker()->BuildWindowForCycleList(kActiveDesk);
- return windows.empty() ? nullptr : windows[0];
- }
- bool ShouldMinimizeTopWindowOnBack() {
- Shell* shell = Shell::Get();
- // We never want to minimize the main app window in the Kiosk session.
- if (shell->session_controller()->IsRunningInAppMode())
- return false;
- if (!shell->tablet_mode_controller()->InTabletMode())
- return false;
- aura::Window* window = GetTopWindow();
- if (!window)
- return false;
- // Do not minimize the window if it is in overview. This can avoid unnecessary
- // window minimize animation.
- OverviewController* overview_controller = Shell::Get()->overview_controller();
- if (overview_controller->InOverviewSession() &&
- overview_controller->overview_session()->IsWindowInOverview(window)) {
- return false;
- }
- // ARC and crostini apps will handle the back event that follows on the client
- // side and will minimize/close the window there.
- const int app_type = window->GetProperty(aura::client::kAppType);
- if (app_type == static_cast<int>(AppType::ARC_APP) ||
- app_type == static_cast<int>(AppType::CROSTINI_APP)) {
- return false;
- }
- // Use the value of |kMinimizeOnBackKey| if it is provided. It can be provided
- // by windows with custom web contents.
- bool* can_minimize_on_back_key = window->GetProperty(kMinimizeOnBackKey);
- if (can_minimize_on_back_key)
- return *can_minimize_on_back_key;
- // Minimize the window if it is at the bottom page.
- return !shell->shell_delegate()->CanGoBack(window);
- }
- void SendBackKeyEvent(aura::Window* root_window) {
- // Send up event as well as down event as ARC++ clients expect this
- // sequence.
- // TODO: Investigate if we should be using the current modifiers.
- ui::KeyEvent press_key_event(ui::ET_KEY_PRESSED, ui::VKEY_BROWSER_BACK,
- ui::EF_NONE);
- std::ignore = root_window->GetHost()->SendEventToSink(&press_key_event);
- ui::KeyEvent release_key_event(ui::ET_KEY_RELEASED, ui::VKEY_BROWSER_BACK,
- ui::EF_NONE);
- std::ignore = root_window->GetHost()->SendEventToSink(&release_key_event);
- }
- WindowTransientDescendantIteratorRange GetVisibleTransientTreeIterator(
- aura::Window* window) {
- auto hide_predicate = [](aura::Window* window) {
- return window->GetProperty(kHideInOverviewKey);
- };
- return GetTransientTreeIterator(window, base::BindRepeating(hide_predicate));
- }
- gfx::RectF GetTransformedBounds(aura::Window* transformed_window,
- int top_inset) {
- gfx::RectF bounds;
- for (auto* window : GetVisibleTransientTreeIterator(transformed_window)) {
- // Ignore other window types when computing bounding box of overview target
- // item.
- if (window != transformed_window &&
- window->GetType() != aura::client::WINDOW_TYPE_NORMAL) {
- continue;
- }
- gfx::RectF window_bounds(window->GetTargetBounds());
- gfx::Transform new_transform =
- TransformAboutPivot(gfx::ToRoundedPoint(window_bounds.origin()),
- window->layer()->GetTargetTransform());
- new_transform.TransformRect(&window_bounds);
- // The preview title is shown above the preview window. Hide the window
- // header for apps or browser windows with no tabs (web apps) to avoid
- // showing both the window header and the preview title.
- if (top_inset > 0) {
- gfx::RectF header_bounds(window_bounds);
- header_bounds.set_height(top_inset);
- new_transform.TransformRect(&header_bounds);
- window_bounds.Inset(gfx::InsetsF::TLBR(header_bounds.height(), 0, 0, 0));
- }
- ::wm::TranslateRectToScreen(window->parent(), &window_bounds);
- bounds.Union(window_bounds);
- }
- return bounds;
- }
- bool ShouldShowForCurrentUser(aura::Window* window) {
- MultiUserWindowManager* multi_user_window_manager =
- MultiUserWindowManagerImpl::Get();
- if (!multi_user_window_manager)
- return true;
- const AccountId account_id =
- multi_user_window_manager->GetUserPresentingWindow(window);
- // An empty account ID is returned if the window is presented for all users.
- if (!account_id.is_valid())
- return true;
- return account_id == multi_user_window_manager->CurrentAccountId();
- }
- aura::Window* GetEventHandlerForEvent(const ui::LocatedEvent& event) {
- gfx::Point location_in_screen = event.location();
- ::wm::ConvertPointToScreen(static_cast<aura::Window*>(event.target()),
- &location_in_screen);
- aura::Window* root_window_at_point = GetRootWindowAt(location_in_screen);
- gfx::Point location_in_root = location_in_screen;
- ::wm::ConvertPointFromScreen(root_window_at_point, &location_in_root);
- return root_window_at_point->GetEventHandlerForPoint(location_in_root);
- }
- } // namespace window_util
- } // namespace ash
|