1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/ui/wm/window_util.h"
#include "chromeos/ui/base/app_types.h"
#include "chromeos/ui/base/display_util.h"
#include "chromeos/ui/base/window_properties.h"
#include "chromeos/ui/base/window_state_type.h"
#include "chromeos/ui/wm/constants.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
namespace chromeos::wm {
namespace {
gfx::Size GetPreferredFloatedWindowTabletSize(const gfx::Rect& work_area,
bool landscape) {
// We use the landscape bounds to determine the preferred width and height,
// even in portrait mode.
const int landscape_width =
landscape ? work_area.width() : work_area.height();
const int landscape_height =
landscape ? work_area.height() : work_area.width();
const int preferred_width =
static_cast<int>(landscape_width * kFloatedWindowTabletWidthRatio);
const int preferred_height =
landscape_height * kFloatedWindowTabletHeightRatio;
return gfx::Size(preferred_width, preferred_height);
}
bool CanFloatWindowInClamshell(aura::Window* window) {
CHECK(window);
const gfx::Rect work_area =
display::Screen::GetScreen()->GetDisplayNearestWindow(window).work_area();
const gfx::Size minimum_size = window->delegate()->GetMinimumSize();
if (minimum_size.width() > work_area.width() - 2 * kFloatedWindowPaddingDp ||
minimum_size.height() >
work_area.height() - 2 * kFloatedWindowPaddingDp) {
return false;
}
return true;
}
bool CanFloatWindowInTablet(aura::Window* window) {
return !GetFloatedWindowTabletSize(window).IsEmpty();
}
} // namespace
bool IsLandscapeOrientationForWindow(aura::Window* window) {
display::Display display =
display::Screen::GetScreen()->GetDisplayNearestWindow(window);
const OrientationType orientation = RotationToOrientation(
GetDisplayNaturalOrientation(display), display.rotation());
return IsLandscapeOrientation(orientation);
}
gfx::Size GetFloatedWindowTabletSize(aura::Window* window) {
CHECK(window);
if ((window->GetProperty(aura::client::kResizeBehaviorKey) &
aura::client::kResizeBehaviorCanResize) == 0) {
return gfx::Size();
}
const gfx::Rect work_area =
display::Screen::GetScreen()->GetDisplayNearestWindow(window).work_area();
const bool landscape = IsLandscapeOrientationForWindow(window);
const gfx::Size preferred_size =
GetPreferredFloatedWindowTabletSize(work_area, landscape);
const gfx::Size minimum_size = window->delegate()->GetMinimumSize();
if (minimum_size.height() > preferred_size.height()) {
return gfx::Size();
}
const int landscape_width =
landscape ? work_area.width() : work_area.height();
// The maximum size for a floated window is half the landscape width minus
// some space for the split view divider and padding.
const int maximum_float_width =
(landscape_width - kSplitviewDividerShortSideLength) / 2 -
kFloatedWindowPaddingDp * 2;
if (minimum_size.width() > maximum_float_width) {
return gfx::Size();
}
// For browsers, we need to add some padding to the minimum size since the
// browser returns a minimum size that makes the omnibox untappable for many
// websites. However, we don't add this padding if it causes an otherwise
// floatable window to not be floatable anymore.
// TODO(b/278769645): Remove this workaround once browser returns a viable
// minimum size.
const int minimum_width_padding =
window->GetProperty(chromeos::kAppTypeKey) == chromeos::AppType::BROWSER
? kBrowserExtraPaddingDp
: 0;
// If the preferred width is less than the minimum width, use the minimum
// width. Add padding to the preferred width if the window is a browser, but
// don't exceed the maximum float width.
int width = std::max(preferred_size.width(),
minimum_size.width() + minimum_width_padding);
width = std::min(width, maximum_float_width);
return gfx::Size(width, preferred_size.height());
}
bool CanFloatWindow(aura::Window* window) {
if (window->GetProperty(chromeos::kAppTypeKey) ==
chromeos::AppType::NON_APP) {
return false;
}
if (!window->GetProperty(kSupportsFloatedStateKey)) {
return false;
}
const auto state_type = window->GetProperty(chromeos::kWindowStateTypeKey);
const bool unresizable =
(window->GetProperty(aura::client::kResizeBehaviorKey) &
aura::client::kResizeBehaviorCanResize) == 0;
// Windows which occupy the entire display should not be the target of
// unresizable floating.
if (unresizable && (state_type == chromeos::WindowStateType::kFullscreen ||
state_type == chromeos::WindowStateType::kMaximized)) {
return false;
}
if (window->GetProperty(aura::client::kZOrderingKey) !=
ui::ZOrderLevel::kNormal) {
return false;
}
return display::Screen::GetScreen()->InTabletMode()
? CanFloatWindowInTablet(window)
: CanFloatWindowInClamshell(window);
}
} // namespace chromeos::wm
|