| // Copyright 2014 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/screen_util.h" |
| |
| #include "ash/display/display_configuration_controller.h" |
| #include "ash/display/mirror_window_controller.h" |
| #include "ash/display/window_tree_host_manager.h" |
| #include "ash/public/cpp/shell_window_ids.h" |
| #include "ash/shelf/shelf.h" |
| #include "ash/shell.h" |
| #include "ash/wm/desks/desks_util.h" |
| #include "ash/wm/window_state.h" |
| #include "ash/wm/work_area_insets.h" |
| #include "base/check_op.h" |
| #include "ui/aura/client/screen_position_client.h" |
| #include "ui/aura/window_event_dispatcher.h" |
| #include "ui/aura/window_tree_host.h" |
| #include "ui/display/display.h" |
| #include "ui/display/manager/display_manager.h" |
| #include "ui/display/screen.h" |
| #include "ui/gfx/geometry/size_conversions.h" |
| #include "ui/wm/core/coordinate_conversion.h" |
| |
| namespace ash { |
| |
| namespace screen_util { |
| |
| gfx::Rect GetMaximizedWindowBoundsInParent(aura::Window* window) { |
| if (Shelf::ForWindow(window)->shelf_widget()) |
| return GetDisplayWorkAreaBoundsInParent(window); |
| return GetDisplayBoundsInParent(window); |
| } |
| |
| gfx::Rect GetDisplayBoundsInParent(aura::Window* window) { |
| gfx::Rect result = |
| display::Screen::GetScreen()->GetDisplayNearestWindow(window).bounds(); |
| ::wm::ConvertRectFromScreen(window->parent(), &result); |
| return result; |
| } |
| |
| gfx::Rect GetFullscreenWindowBoundsInParent(aura::Window* window) { |
| gfx::Rect result = GetDisplayBoundsInParent(window); |
| const WorkAreaInsets* const work_area_insets = |
| WorkAreaInsets::ForWindow(window->GetRootWindow()); |
| result.Inset( |
| gfx::Insets().set_top(work_area_insets->accessibility_panel_height() + |
| work_area_insets->docked_magnifier_height())); |
| return result; |
| } |
| |
| gfx::Rect GetDisplayWorkAreaBoundsInParent(aura::Window* window) { |
| // If it is application window under `non_lock_screen_containers`, use |
| // `in_session_user_work_area_insets`, otherwise, use `user_work_area_insets`. |
| const aura::Window* non_lock_screen_containers = Shell::GetContainer( |
| window->GetRootWindow(), kShellWindowId_NonLockScreenContainersContainer); |
| gfx::Insets insets = |
| non_lock_screen_containers->Contains(window) |
| ? WorkAreaInsets::ForWindow(window) |
| ->in_session_user_work_area_insets() |
| : WorkAreaInsets::ForWindow(window)->user_work_area_insets(); |
| gfx::Rect bounds = |
| display::Screen::GetScreen()->GetDisplayNearestWindow(window).bounds(); |
| bounds.Inset(insets); |
| ::wm::ConvertRectFromScreen(window->parent(), &bounds); |
| return bounds; |
| } |
| |
| // TODO(yongshun): Remove or consolidate this function with |
| // `GetDisplayWorkAreaBoundsInParent`. |
| gfx::Rect GetDisplayWorkAreaBoundsInParentForLockScreen(aura::Window* window) { |
| gfx::Rect bounds = WorkAreaInsets::ForWindow(window)->user_work_area_bounds(); |
| ::wm::ConvertRectFromScreen(window->parent(), &bounds); |
| return bounds; |
| } |
| |
| // TODO(yongshun): Remove or consolidate this function with |
| // `GetDisplayWorkAreaBoundsInParent`. |
| gfx::Rect GetDisplayWorkAreaBoundsInParentForActiveDeskContainer( |
| aura::Window* window) { |
| aura::Window* root_window = window->GetRootWindow(); |
| return GetDisplayWorkAreaBoundsInParent( |
| desks_util::GetActiveDeskContainerForRoot(root_window)); |
| } |
| |
| // TODO(yongshun): Remove or consolidate this function with |
| // `GetDisplayWorkAreaBoundsInParent`. |
| gfx::Rect GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer( |
| aura::Window* window) { |
| gfx::Rect bounds = |
| GetDisplayWorkAreaBoundsInParentForActiveDeskContainer(window); |
| ::wm::ConvertRectToScreen(window->GetRootWindow(), &bounds); |
| return bounds; |
| } |
| |
| gfx::Rect GetDisplayBoundsWithShelf(aura::Window* window) { |
| if (!Shell::Get()->display_manager()->IsInUnifiedMode()) { |
| return display::Screen::GetScreen() |
| ->GetDisplayNearestWindow(window) |
| .bounds(); |
| } |
| |
| // In Unified Mode, the display that should contain the shelf depends on the |
| // current shelf alignment. |
| const display::Display shelf_display = |
| Shell::Get() |
| ->display_configuration_controller() |
| ->GetPrimaryMirroringDisplayForUnifiedDesktop(); |
| DCHECK_NE(shelf_display.id(), display::kInvalidDisplayId); |
| |
| // Transform the bounds back to the unified host's coordinates. |
| auto inverse_unified_transform = |
| window->GetRootWindow()->GetHost()->GetInverseRootTransform(); |
| return inverse_unified_transform.MapRect(shelf_display.bounds()); |
| } |
| |
| gfx::Rect SnapBoundsToDisplayEdge(const gfx::Rect& bounds, |
| const aura::Window* window) { |
| display::Display display = |
| display::Screen::GetScreen()->GetDisplayNearestWindow( |
| const_cast<aura::Window*>(window)); |
| |
| const float dsf = display.device_scale_factor(); |
| const gfx::Size display_size_in_pixel = display.GetSizeInPixel(); |
| const gfx::Size scaled_size_in_pixel = |
| gfx::ScaleToFlooredSize(display.size(), dsf); |
| |
| // Adjusts |bounds| such that the scaled enclosed bounds are atleast as big as |
| // the scaled enclosing unadjusted bounds. |
| gfx::Rect snapped_bounds = bounds; |
| if (scaled_size_in_pixel.width() < display_size_in_pixel.width() && |
| display.bounds().right() == bounds.right()) { |
| snapped_bounds.Inset(gfx::Insets::TLBR(0, 0, 0, -1)); |
| DCHECK_GE(gfx::ScaleToEnclosedRect(snapped_bounds, dsf).right(), |
| gfx::ScaleToEnclosingRect(bounds, dsf).right()); |
| } |
| if (scaled_size_in_pixel.height() < display_size_in_pixel.height() && |
| display.bounds().bottom() == bounds.bottom()) { |
| snapped_bounds.Inset(gfx::Insets::TLBR(0, 0, -1, 0)); |
| DCHECK_GE(gfx::ScaleToEnclosedRect(snapped_bounds, dsf).bottom(), |
| gfx::ScaleToEnclosingRect(bounds, dsf).bottom()); |
| } |
| |
| return snapped_bounds; |
| } |
| |
| gfx::Rect GetIdealBoundsForMaximizedOrFullscreenOrPinnedState( |
| aura::Window* window) { |
| auto* window_state = WindowState::Get(window); |
| if (window_state->IsMaximized()) { |
| auto* shelf = ash::Shelf::ForWindow(window); |
| if (shelf->auto_hide_behavior() == ash::ShelfAutoHideBehavior::kAlways) { |
| gfx::Rect bounds = |
| ash::screen_util::GetFullscreenWindowBoundsInParent(window); |
| ::wm::ConvertRectToScreen(window->parent(), &bounds); |
| return bounds; |
| } |
| if (shelf->auto_hide_behavior() == |
| ash::ShelfAutoHideBehavior::kAlwaysHidden) { |
| return display::Screen::GetScreen() |
| ->GetDisplayNearestWindow(const_cast<aura::Window*>(window)) |
| .work_area(); |
| } |
| auto work_area = |
| ash::WorkAreaInsets::ForWindow(window)->ComputeStableWorkArea(); |
| return work_area; |
| } |
| if (window_state->IsFullscreen() || window_state->IsPinned()) { |
| gfx::Rect bounds = |
| ash::screen_util::GetFullscreenWindowBoundsInParent(window); |
| ::wm::ConvertRectToScreen(window->parent(), &bounds); |
| return bounds; |
| } |
| NOTREACHED() << "The window is not maximzied or fullscreen or pinned. state=" |
| << window_state->GetStateType(); |
| return window->GetBoundsInScreen(); |
| } |
| |
| } // namespace screen_util |
| |
| } // namespace ash |