* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "window_layout_policy_cascade.h"
#include <hitrace_meter.h>
#include "minimize_app.h"
#include "window_helper.h"
#include "window_inner_manager.h"
#include "window_manager_hilog.h"
#include "window_manager_service_utils.h"
#include "window_system_effect.h"
#include "wm_math.h"
namespace OHOS {
namespace Rosen {
namespace {
constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "Cascade"};
}
WindowLayoutPolicyCascade::WindowLayoutPolicyCascade(DisplayGroupWindowTree& displayGroupWindowTree)
: WindowLayoutPolicy(displayGroupWindowTree)
{
CascadeRects cascadeRects {
.primaryRect_ = {0, 0, 0, 0},
.secondaryRect_ = {0, 0, 0, 0},
.dividerRect_ = {0, 0, 0, 0},
.defaultCascadeRect_ = {0, 0, 0, 0},
};
for (auto& iter : DisplayGroupInfo::GetInstance().GetAllDisplayRects()) {
cascadeRectsMap_.insert(std::make_pair(iter.first, cascadeRects));
}
}
void WindowLayoutPolicyCascade::Launch()
{
InitAllRects();
WLOGI("WindowLayoutPolicyCascade::Launch");
}
void WindowLayoutPolicyCascade::Reorder()
{
WLOGFD("Cascade reorder start");
for (auto& iter : DisplayGroupInfo::GetInstance().GetAllDisplayRects()) {
DisplayId displayId = iter.first;
Rect rect = cascadeRectsMap_[displayId].defaultCascadeRect_;
bool isFirstReorderedWindow = true;
const auto& appWindowNodeVec = *(displayGroupWindowTree_[displayId][WindowRootNodeType::APP_WINDOW_NODE]);
for (auto nodeIter = appWindowNodeVec.begin(); nodeIter != appWindowNodeVec.end(); nodeIter++) {
auto node = *nodeIter;
if (node == nullptr || node->GetWindowType() != WindowType::WINDOW_TYPE_APP_MAIN_WINDOW) {
WLOGFW("get node failed or not app window.");
continue;
}
if (!WindowHelper::IsWindowModeSupported(node->GetWindowModeSupportType(),
WindowMode::WINDOW_MODE_FLOATING) ||
!WindowHelper::IsRectSatisfiedWithSizeLimits(rect, node->GetWindowUpdatedSizeLimits())) {
MinimizeApp::AddNeedMinimizeApp(node, MinimizeReason::LAYOUT_CASCADE);
continue;
}
if (isFirstReorderedWindow) {
isFirstReorderedWindow = false;
} else {
rect = StepCascadeRect(rect, displayId);
}
node->SetRequestRect(rect);
node->SetDecoStatus(true);
if (node->GetWindowMode() != WindowMode::WINDOW_MODE_FLOATING) {
node->SetWindowMode(WindowMode::WINDOW_MODE_FLOATING);
WindowSystemEffect::SetWindowEffect(node);
if (node->GetWindowToken()) {
node->GetWindowToken()->UpdateWindowMode(WindowModeInfo{ WindowMode::WINDOW_MODE_FLOATING });
}
}
WLOGFD("Cascade reorder Id: %{public}d, rect:[%{public}d, %{public}d, %{public}d, %{public}d]",
node->GetWindowId(), rect.posX_, rect.posY_, rect.width_, rect.height_);
}
LayoutWindowTree(displayId);
}
WLOGI("Cascade Reorder end");
}
void WindowLayoutPolicyCascade::InitAllRects()
{
UpdateDisplayGroupRect();
for (auto& iter : DisplayGroupInfo::GetInstance().GetAllDisplayRects()) {
auto displayId = iter.first;
InitSplitRects(displayId);
LayoutWindowTree(displayId);
InitCascadeRect(displayId);
}
}
void WindowLayoutPolicyCascade::LayoutSplitNodes(DisplayId displayId, WindowUpdateType type, bool layoutByDivider)
{
std::vector<WindowRootNodeType> rootNodeType = {
WindowRootNodeType::ABOVE_WINDOW_NODE,
WindowRootNodeType::APP_WINDOW_NODE,
WindowRootNodeType::BELOW_WINDOW_NODE
};
for (const auto& rootType : rootNodeType) {
if (displayGroupWindowTree_[displayId].find(rootType) == displayGroupWindowTree_[displayId].end()) {
continue;
}
auto appWindowNodeVec = *(displayGroupWindowTree_[displayId][rootType]);
for (const auto& childNode : appWindowNodeVec) {
if (type == WindowUpdateType::WINDOW_UPDATE_REMOVED) {
* If updateType is remove we need to layout all appNodes, cause remove split node or
* divider means exit split mode, split node may change to other mode
*/
LayoutWindowNode(childNode);
} else if (childNode->IsSplitMode()) {
if (layoutByDivider && type == WindowUpdateType::WINDOW_UPDATE_ACTIVE) {
childNode->SetWindowSizeChangeReason(WindowSizeChangeReason::DRAG);
}
LayoutWindowNode(childNode);
}
}
}
}
void WindowLayoutPolicyCascade::LayoutDivider(const sptr<WindowNode>& node, WindowUpdateType type)
{
auto displayId = node->GetDisplayId();
switch (type) {
case WindowUpdateType::WINDOW_UPDATE_ADDED:
SetInitialDividerRect(node, displayId);
[[fallthrough]];
case WindowUpdateType::WINDOW_UPDATE_ACTIVE:
UpdateDividerPosition(node);
LayoutWindowNode(node);
SetSplitRectByDivider(node->GetWindowRect(), displayId);
break;
case WindowUpdateType::WINDOW_UPDATE_REMOVED:
InitSplitRects(displayId);
break;
default:
WLOGFW("Unknown update type, type: %{public}u", type);
}
LayoutSplitNodes(displayId, type, true);
}
void WindowLayoutPolicyCascade::LayoutPreProcess(const sptr<WindowNode>& node, WindowUpdateType updateType)
{
if (updateType == WindowUpdateType::WINDOW_UPDATE_ADDED) {
GetStoragedAspectRatio(node);
}
SetDefaultCascadeRect(node);
FixWindowRectWithinDisplay(node);
}
void WindowLayoutPolicyCascade::PerformWindowLayout(const sptr<WindowNode>& node, WindowUpdateType updateType)
{
HITRACE_METER(HITRACE_TAG_WINDOW_MANAGER);
const auto& windowType = node->GetWindowType();
const auto& requestRect = node->GetRequestRect();
WLOGFD("windowId: %{public}u, windowType: %{public}u, updateType: %{public}u, requestRect: "
"requestRect: [%{public}d, %{public}d, %{public}u, %{public}u]", node->GetWindowId(), windowType, updateType,
requestRect.posX_, requestRect.posY_, requestRect.width_, requestRect.height_);
LayoutPreProcess(node, updateType);
switch (windowType) {
case WindowType::WINDOW_TYPE_DOCK_SLICE:
LayoutDivider(node, updateType);
break;
case WindowType::WINDOW_TYPE_STATUS_BAR:
case WindowType::WINDOW_TYPE_NAVIGATION_BAR:
case WindowType::WINDOW_TYPE_LAUNCHER_DOCK:
LayoutWindowTree(node->GetDisplayId());
InitCascadeRect(node->GetDisplayId());
break;
default:
if (node->IsSplitMode()) {
LayoutSplitNodes(node->GetDisplayId(), updateType);
} else {
LayoutWindowNode(node);
}
}
if (updateType == WindowUpdateType::WINDOW_UPDATE_REMOVED) {
NotifyClientAndAnimation(node, node->GetRequestRect(), WindowSizeChangeReason::HIDE);
}
}
void WindowLayoutPolicyCascade::SetInitialDividerRect(const sptr<WindowNode>& node, DisplayId displayId)
{
const auto& restoredRect = restoringDividerWindowRects_[displayId];
const auto& presetRect = cascadeRectsMap_[node->GetDisplayId()].dividerRect_;
auto divRect = WindowHelper::IsEmptyRect(restoredRect) ? presetRect : restoredRect;
node->SetRequestRect(divRect);
restoringDividerWindowRects_.erase(displayId);
}
void WindowLayoutPolicyCascade::SetSplitDividerWindowRects(std::map<DisplayId, Rect> dividerWindowRects)
{
restoringDividerWindowRects_ = dividerWindowRects;
}
void WindowLayoutPolicyCascade::LimitDividerInDisplayRegion(Rect& rect, DisplayId displayId) const
{
const Rect& limitRect = limitRectMap_[displayId];
if (rect.width_ < rect.height_) {
if (rect.posX_ < limitRect.posX_) {
rect.posX_ = limitRect.posX_;
} else if (rect.posX_ + static_cast<int32_t>(rect.width_) >
limitRect.posX_ + static_cast<int32_t>(limitRect.width_)) {
rect.posX_ = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - rect.width_);
}
} else {
if (rect.posY_ < limitRect.posY_) {
rect.posY_ = limitRect.posY_;
} else if (rect.posY_ + static_cast<int32_t>(rect.height_) >
limitRect.posY_ + static_cast<int32_t>(limitRect.height_)) {
rect.posY_ = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - rect.height_);
}
}
WLOGFD("limit divider move bounds: [%{public}d, %{public}d, %{public}u, %{public}u]",
rect.posX_, rect.posY_, rect.width_, rect.height_);
}
void WindowLayoutPolicyCascade::UpdateDividerPosition(const sptr<WindowNode>& node) const
{
auto rect = node->GetRequestRect();
auto displayId = node->GetDisplayId();
LimitDividerInDisplayRegion(rect, displayId);
if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG_END) {
LimitDividerPositionBySplitRatio(displayId, rect);
}
node->SetRequestRect(rect);
}
void WindowLayoutPolicyCascade::InitCascadeRect(DisplayId displayId)
{
constexpr uint32_t half = 2;
constexpr float ratio = DEFAULT_ASPECT_RATIO;
* Calculate default width and height, if width or height is
* smaller than minWidth or minHeight, use the minimum limits
*/
const auto& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
auto vpr = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(displayId);
uint32_t defaultW = std::max(static_cast<uint32_t>(displayRect.width_ * ratio),
static_cast<uint32_t>(MIN_FLOATING_WIDTH * vpr));
uint32_t defaultH = std::max(static_cast<uint32_t>(displayRect.height_ * ratio),
static_cast<uint32_t>(MIN_FLOATING_HEIGHT * vpr));
Rect resRect = {0, 0, defaultW, defaultH};
const Rect& limitRect = limitRectMap_[displayId];
if (defaultW <= limitRect.width_ && defaultH <= limitRect.height_) {
resRect.posX_ = limitRect.posX_ + static_cast<int32_t>((limitRect.width_ - defaultW) / half);
resRect.posY_ = limitRect.posY_ + static_cast<int32_t>((limitRect.height_ - defaultH) / half);
}
WLOGI("Init CascadeRect :[%{public}d, %{public}d, %{public}d, %{public}d]",
resRect.posX_, resRect.posY_, resRect.width_, resRect.height_);
cascadeRectsMap_[displayId].defaultCascadeRect_ = resRect;
}
bool WindowLayoutPolicyCascade::CheckAspectRatioBySizeLimits(const sptr<WindowNode>& node,
WindowLimits& newLimits) const
{
const auto& sizeLimits = node->GetWindowUpdatedSizeLimits();
if (node->GetWindowProperty() != nullptr && !node->GetWindowProperty()->GetDecorEnable()) {
newLimits = sizeLimits;
} else {
float vpr = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
uint32_t winFrameW = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * vpr) * 2;
uint32_t winFrameH = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * vpr) +
static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * vpr);
newLimits.maxWidth_ = sizeLimits.maxWidth_ - winFrameW;
newLimits.minWidth_ = sizeLimits.minWidth_ - winFrameW;
newLimits.maxHeight_ = sizeLimits.maxHeight_ - winFrameH;
newLimits.minHeight_ = sizeLimits.minHeight_ - winFrameH;
}
float maxRatio = static_cast<float>(newLimits.maxWidth_) / static_cast<float>(newLimits.minHeight_);
float minRatio = static_cast<float>(newLimits.minWidth_) / static_cast<float>(newLimits.maxHeight_);
float aspectRatio = node->GetAspectRatio();
if (MathHelper::GreatNotEqual(aspectRatio, maxRatio) ||
MathHelper::LessNotEqual(aspectRatio, minRatio)) {
return false;
}
uint32_t newMaxWidth = static_cast<uint32_t>(static_cast<float>(newLimits.maxHeight_) * aspectRatio);
newLimits.maxWidth_ = std::min(newMaxWidth, newLimits.maxWidth_);
uint32_t newMinWidth = static_cast<uint32_t>(static_cast<float>(newLimits.minHeight_) * aspectRatio);
newLimits.minWidth_ = std::max(newMinWidth, newLimits.minWidth_);
uint32_t newMaxHeight = static_cast<uint32_t>(static_cast<float>(newLimits.maxWidth_) / aspectRatio);
newLimits.maxHeight_ = std::min(newMaxHeight, newLimits.maxHeight_);
uint32_t newMinHeight = static_cast<uint32_t>(static_cast<float>(newLimits.minWidth_) / aspectRatio);
newLimits.minHeight_ = std::max(newMinHeight, newLimits.minHeight_);
return true;
}
void WindowLayoutPolicyCascade::ComputeRectByAspectRatio(const sptr<WindowNode>& node) const
{
float aspectRatio = node->GetAspectRatio();
if (!WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode()) ||
IsMoveToOrDragMove(node->GetWindowSizeChangeReason()) || MathHelper::NearZero(aspectRatio)) {
return;
}
WindowLimits newLimits;
if (!CheckAspectRatioBySizeLimits(node, newLimits)) {
return;
}
float vpr = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
uint32_t winFrameW = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * vpr) * 2;
uint32_t winFrameH = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * vpr) +
static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * vpr);
auto newRect = node->GetRequestRect();
if (node->GetWindowProperty() != nullptr && node->GetWindowProperty()->GetDecorEnable()) {
newRect.width_ = (newRect.width_ > winFrameW) ? (newRect.width_ - winFrameW) : 0;
newRect.height_ = (newRect.height_ > winFrameH) ? (newRect.height_ - winFrameH) : 0;
}
auto oriRect = newRect;
newRect.width_ = std::max(newLimits.minWidth_, newRect.width_);
newRect.height_ = std::max(newLimits.minHeight_, newRect.height_);
newRect.width_ = std::min(newLimits.maxWidth_, newRect.width_);
newRect.height_ = std::min(newLimits.maxHeight_, newRect.height_);
float curRatio = static_cast<float>(newRect.width_) / static_cast<float>(newRect.height_);
if (std::abs(curRatio - aspectRatio) > 0.0001f) {
if (node->GetDragType() == DragType::DRAG_BOTTOM_OR_TOP) {
newRect.width_ = static_cast<uint32_t>(static_cast<float>(newRect.height_) * aspectRatio);
} else {
newRect.height_ = static_cast<uint32_t>(static_cast<float>(newRect.width_) / aspectRatio);
}
}
FixWindowRectWhenDrag(node, oriRect, newRect);
if (newRect.posY_ < limitRectMap_[node->GetDisplayId()].posY_ &&
node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG) {
auto lastRect = node->GetWindowRect();
lastRect.width_ -= winFrameW;
lastRect.height_ -= winFrameH;
newRect = lastRect;
}
node->SetRequestRect(newRect);
node->SetDecoStatus(false);
WLOGFD("WinId: %{public}u, newRect: %{public}d %{public}d %{public}u %{public}u",
node->GetWindowId(), newRect.posX_, newRect.posY_, newRect.width_, newRect.height_);
}
void WindowLayoutPolicyCascade::ComputeDecoratedRequestRect(const sptr<WindowNode>& node) const
{
auto property = node->GetWindowProperty();
if (property == nullptr) {
WLOGE("window property is nullptr");
return;
}
if (!property->GetDecorEnable() || property->GetDecoStatus() ||
IsMoveToOrDragMove(node->GetWindowSizeChangeReason())) {
return;
}
float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
uint32_t winFrameW = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * virtualPixelRatio);
uint32_t winTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
auto oriRect = property->GetRequestRect();
Rect dstRect;
dstRect.posX_ = oriRect.posX_;
dstRect.posY_ = oriRect.posY_;
dstRect.width_ = oriRect.width_ + winFrameW + winFrameW;
dstRect.height_ = oriRect.height_ + winTitleBarH + winFrameW;
property->SetRequestRect(dstRect);
property->SetDecoStatus(true);
}
void WindowLayoutPolicyCascade::ApplyWindowRectConstraints(const sptr<WindowNode>& node, Rect& winRect) const
{
WLOGFD("[Before constraints] windowId: %{public}u, winRect:[%{public}d, %{public}d, %{public}u, %{public}u]",
node->GetWindowId(), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
ComputeRectByAspectRatio(node);
ComputeDecoratedRequestRect(node);
winRect = node->GetRequestRect();
LimitFloatingWindowSize(node, winRect);
LimitMainFloatingWindowPosition(node, winRect);
* Use the orientation of the window and display to determine
* whether the screen is rotating, then rotate the divider
*/
if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE &&
((!WindowHelper::IsLandscapeRect(winRect) && IsVerticalDisplay(node->GetDisplayId())) ||
(WindowHelper::IsLandscapeRect(winRect) && !IsVerticalDisplay(node->GetDisplayId())))) {
winRect = cascadeRectsMap_[node->GetDisplayId()].dividerRect_;
node->SetRequestRect(winRect);
WLOGFD("Reset divider when display rotation, divRect: [%{public}d, %{public}d, %{public}u, %{public}u]",
winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
}
WLOGFD("[After constraints] windowId: %{public}u, winRect:[%{public}d, %{public}d, %{public}u, %{public}u]",
node->GetWindowId(), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
}
void WindowLayoutPolicyCascade::UpdateLayoutRect(const sptr<WindowNode>& node)
{
auto property = node->GetWindowProperty();
if (property == nullptr) {
WLOGFE("window property is nullptr.");
return;
}
auto mode = node->GetWindowMode();
Rect winRect = property->GetRequestRect();
auto displayId = node->GetDisplayId();
WLOGFD("[Before CascadeLayout] windowId: %{public}u, mode: %{public}u, type: %{public}u requestRect: [%{public}d, "
"%{public}d, %{public}u, %{public}u]", node->GetWindowId(), mode, node->GetWindowType(), winRect.posX_,
winRect.posY_, winRect.width_, winRect.height_);
switch (mode) {
case WindowMode::WINDOW_MODE_SPLIT_PRIMARY:
winRect = cascadeRectsMap_[displayId].primaryRect_;
break;
case WindowMode::WINDOW_MODE_SPLIT_SECONDARY:
winRect = cascadeRectsMap_[displayId].secondaryRect_;
break;
case WindowMode::WINDOW_MODE_FULLSCREEN: {
UpdateWindowSizeLimits(node);
bool needAvoid = (node->GetWindowFlags() & static_cast<uint32_t>(WindowFlag::WINDOW_FLAG_NEED_AVOID));
winRect = needAvoid ? limitRectMap_[displayId] : DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
auto displayInfo = DisplayGroupInfo::GetInstance().GetDisplayInfo(displayId);
if (displayInfo && WmsUtils::IsExpectedRotatableWindow(node->GetRequestedOrientation(),
displayInfo->GetDisplayOrientation(), node->GetWindowFlags())) {
WLOGFD("[FixOrientation] the window is expected rotatable, pre-calculated");
winRect = {winRect.posX_, winRect.posY_, winRect.height_, winRect.width_};
}
if (property->GetMaximizeMode() == MaximizeMode::MODE_AVOID_SYSTEM_BAR) {
node->SetRequestRect(node->GetOriginRect());
property->SetMaximizeMode(MaximizeMode::MODE_FULL_FILL);
}
break;
}
case WindowMode::WINDOW_MODE_FLOATING: {
if (node->GetWindowType() == WindowType::WINDOW_TYPE_APP_COMPONENT) {
break;
}
UpdateWindowSizeLimits(node);
winRect = property->GetRequestRect();
ApplyWindowRectConstraints(node, winRect);
if (property->GetMaximizeMode() == MaximizeMode::MODE_AVOID_SYSTEM_BAR) {
GetMaximizeRect(node, winRect);
WLOGFI("[In CascadeLayout] winId: %{public}u, maxRect: %{public}d, %{public}d, %{public}u, %{public}u",
node->GetWindowId(), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
}
break;
}
default:
WLOGFW("Layout invalid mode, winId: %{public}u, mode: %{public}u", node->GetWindowId(), mode);
}
WLOGFD("[After CascadeLayout] windowId: %{public}u, isDecor: %{public}u, winRect: [%{public}d, %{public}d, "
"%{public}u, %{public}u], reason: %{public}u", node->GetWindowId(), node->GetDecoStatus(), winRect.posX_,
winRect.posY_, winRect.width_, winRect.height_, node->GetWindowSizeChangeReason());
const Rect& lastWinRect = node->GetWindowRect();
node->SetWindowRect(winRect);
CalcAndSetNodeHotZone(winRect, node);
UpdateSurfaceBounds(node, winRect, lastWinRect);
NotifyClientAndAnimation(node, winRect, node->GetWindowSizeChangeReason());
}
void WindowLayoutPolicyCascade::LimitDividerPositionBySplitRatio(DisplayId displayId, Rect& winRect) const
{
int32_t oriPos = IsVerticalDisplay(displayId) ? winRect.posY_ : winRect.posX_;
int32_t& dstPos = IsVerticalDisplay(displayId) ? winRect.posY_ : winRect.posX_;
if (splitRatioPointsMap_[displayId].size() == 0) {
return;
}
uint32_t minDiff = std::max(limitRectMap_[displayId].width_, limitRectMap_[displayId].height_);
int32_t closestPoint = oriPos;
for (const auto& elem : splitRatioPointsMap_[displayId]) {
uint32_t diff = (oriPos > elem) ? static_cast<uint32_t>(oriPos - elem) : static_cast<uint32_t>(elem - oriPos);
if (diff < minDiff) {
closestPoint = elem;
minDiff = diff;
}
}
dstPos = closestPoint;
}
void WindowLayoutPolicyCascade::InitSplitRects(DisplayId displayId)
{
float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(displayId);
uint32_t dividerWidth = static_cast<uint32_t>(DIVIDER_WIDTH * virtualPixelRatio);
auto& dividerRect = cascadeRectsMap_[displayId].dividerRect_;
const auto& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
if (!IsVerticalDisplay(displayId)) {
dividerRect = { static_cast<uint32_t>((displayRect.width_ - dividerWidth) * DEFAULT_SPLIT_RATIO), 0,
dividerWidth, displayRect.height_ };
} else {
dividerRect = { 0, static_cast<uint32_t>((displayRect.height_ - dividerWidth) * DEFAULT_SPLIT_RATIO),
displayRect.width_, dividerWidth };
}
SetSplitRectByDivider(dividerRect, displayId);
}
void WindowLayoutPolicyCascade::SetSplitRectByDivider(const Rect& divRect, DisplayId displayId)
{
auto& dividerRect = cascadeRectsMap_[displayId].dividerRect_;
auto& primaryRect = cascadeRectsMap_[displayId].primaryRect_;
auto& secondaryRect = cascadeRectsMap_[displayId].secondaryRect_;
const auto& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
dividerRect.width_ = divRect.width_;
dividerRect.height_ = divRect.height_;
if (!IsVerticalDisplay(displayId)) {
primaryRect.posX_ = displayRect.posX_;
primaryRect.posY_ = displayRect.posY_;
primaryRect.width_ = divRect.posX_;
primaryRect.height_ = displayRect.height_;
secondaryRect.posX_ = divRect.posX_ + static_cast<int32_t>(dividerRect.width_);
secondaryRect.posY_ = displayRect.posY_;
secondaryRect.width_ = static_cast<uint32_t>(static_cast<int32_t>(displayRect.width_) - secondaryRect.posX_);
secondaryRect.height_ = displayRect.height_;
} else {
primaryRect.posX_ = displayRect.posX_;
primaryRect.posY_ = displayRect.posY_;
primaryRect.height_ = divRect.posY_;
primaryRect.width_ = displayRect.width_;
secondaryRect.posX_ = displayRect.posX_;
secondaryRect.posY_ = divRect.posY_ + static_cast<int32_t>(dividerRect.height_);
secondaryRect.height_ = static_cast<uint32_t>(static_cast<int32_t>(displayRect.height_) - secondaryRect.posY_);
secondaryRect.width_ = displayRect.width_;
}
WLOGFD("DividerRect: [%{public}d %{public}d %{public}u %{public}u] "
"PrimaryRect: [%{public}d %{public}d %{public}u %{public}u] "
"SecondaryRect: [%{public}d %{public}d %{public}u %{public}u]",
dividerRect.posX_, dividerRect.posY_, dividerRect.width_, dividerRect.height_,
primaryRect.posX_, primaryRect.posY_, primaryRect.width_, primaryRect.height_,
secondaryRect.posX_, secondaryRect.posY_, secondaryRect.width_, secondaryRect.height_);
}
Rect WindowLayoutPolicyCascade::GetCurCascadeRect(const sptr<WindowNode>& node) const
{
Rect cascadeRect = {0, 0, 0, 0};
const DisplayId& displayId = node->GetDisplayId();
const auto& appWindowNodeVec = *(const_cast<WindowLayoutPolicyCascade*>(this)->
displayGroupWindowTree_[displayId][WindowRootNodeType::APP_WINDOW_NODE]);
const auto& aboveAppWindowNodeVec = *(const_cast<WindowLayoutPolicyCascade*>(this)->
displayGroupWindowTree_[displayId][WindowRootNodeType::ABOVE_WINDOW_NODE]);
std::vector<std::vector<sptr<WindowNode>>> roots = { aboveAppWindowNodeVec, appWindowNodeVec };
for (auto& root : roots) {
for (auto iter = root.rbegin(); iter != root.rend(); iter++) {
if ((*iter)->GetWindowType() == WindowType::WINDOW_TYPE_APP_MAIN_WINDOW &&
(*iter)->GetWindowId() != node->GetWindowId()) {
auto property = (*iter)->GetWindowProperty();
if (property != nullptr && property->GetMaximizeMode() != MaximizeMode::MODE_AVOID_SYSTEM_BAR) {
cascadeRect = ((*iter)->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING ?
property->GetWindowRect() : property->GetRequestRect());
}
WLOGFD("Get current cascadeRect: %{public}u [%{public}d, %{public}d, %{public}u, %{public}u]",
(*iter)->GetWindowId(), cascadeRect.posX_, cascadeRect.posY_,
cascadeRect.width_, cascadeRect.height_);
break;
}
}
}
if (WindowHelper::IsEmptyRect(cascadeRect)) {
WLOGFD("cascade rect is empty use first cascade rect");
return cascadeRectsMap_[displayId].defaultCascadeRect_;
}
return StepCascadeRect(cascadeRect, displayId);
}
Rect WindowLayoutPolicyCascade::StepCascadeRect(Rect rect, DisplayId displayId) const
{
float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(displayId);
uint32_t cascadeWidth = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
uint32_t cascadeHeight = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
const Rect& limitRect = limitRectMap_[displayId];
Rect cascadeRect = {0, 0, 0, 0};
cascadeRect.width_ = rect.width_;
cascadeRect.height_ = rect.height_;
cascadeRect.posX_ = (rect.posX_ + static_cast<int32_t>(cascadeWidth) >= limitRect.posX_) &&
(rect.posX_ + static_cast<int32_t>(rect.width_ + cascadeWidth) <=
(limitRect.posX_ + static_cast<int32_t>(limitRect.width_))) ?
(rect.posX_ + static_cast<int32_t>(cascadeWidth)) : limitRect.posX_;
cascadeRect.posY_ = (rect.posY_ + static_cast<int32_t>(cascadeHeight) >= limitRect.posY_) &&
(rect.posY_ + static_cast<int32_t>(rect.height_ + cascadeHeight) <=
(limitRect.posY_ + static_cast<int32_t>(limitRect.height_))) ?
(rect.posY_ + static_cast<int32_t>(cascadeHeight)) : limitRect.posY_;
WLOGFD("Step cascadeRect :[%{public}d, %{public}d, %{public}u, %{public}u]",
cascadeRect.posX_, cascadeRect.posY_, cascadeRect.width_, cascadeRect.height_);
return cascadeRect;
}
void WindowLayoutPolicyCascade::SetDefaultCascadeRect(const sptr<WindowNode>& node)
{
auto property = node->GetWindowProperty();
if (property == nullptr) {
WLOGFE("window property is nullptr.");
return;
}
if (!WindowHelper::IsEmptyRect(property->GetRequestRect())) {
return;
}
static bool isFirstAppWindow = true;
Rect rect;
if (WindowHelper::IsAppWindow(property->GetWindowType()) && isFirstAppWindow) {
WLOGFD("Set first app window cascade rect");
rect = cascadeRectsMap_[node->GetDisplayId()].defaultCascadeRect_;
isFirstAppWindow = false;
} else if (WindowHelper::IsAppWindow(property->GetWindowType()) && !isFirstAppWindow) {
WLOGFD("Set other app window cascade rect");
rect = GetCurCascadeRect(node);
} else {
WLOGFD("Set system window cascade rect");
rect = cascadeRectsMap_[node->GetDisplayId()].defaultCascadeRect_;
}
WLOGFD("Set cascadeRect :[%{public}d, %{public}d, %{public}u, %{public}u]",
rect.posX_, rect.posY_, rect.width_, rect.height_);
node->SetRequestRect(rect);
node->SetDecoStatus(true);
}
Rect WindowLayoutPolicyCascade::GetDividerRect(DisplayId displayId) const
{
Rect dividerRect = {0, 0, 0, 0};
if (cascadeRectsMap_.find(displayId) != std::end(cascadeRectsMap_)) {
dividerRect = cascadeRectsMap_[displayId].dividerRect_;
}
return dividerRect;
}
DockWindowShowState WindowLayoutPolicyCascade::GetDockWindowShowState(DisplayId displayId, Rect& dockWinRect) const
{
auto& displayWindowTree = displayGroupWindowTree_[displayId];
auto& nodeVec = *(displayWindowTree[WindowRootNodeType::ABOVE_WINDOW_NODE]);
for (auto& node : nodeVec) {
if (node->GetWindowType() != WindowType::WINDOW_TYPE_LAUNCHER_DOCK) {
continue;
}
dockWinRect = node->GetWindowRect();
auto displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
WLOGI("begin dockWinRect :[%{public}d, %{public}d, %{public}u, %{public}u]",
dockWinRect.posX_, dockWinRect.posY_, dockWinRect.width_, dockWinRect.height_);
if (dockWinRect.height_ < dockWinRect.width_) {
if (static_cast<uint32_t>(dockWinRect.posY_) + dockWinRect.height_ == displayRect.height_) {
return DockWindowShowState::SHOWN_IN_BOTTOM;
} else {
return DockWindowShowState::NOT_SHOWN;
}
} else {
if (dockWinRect.posX_ == 0) {
return DockWindowShowState::SHOWN_IN_LEFT;
} else if (static_cast<uint32_t>(dockWinRect.posX_) + dockWinRect.width_ == displayRect.width_) {
return DockWindowShowState::SHOWN_IN_RIGHT;
} else {
return DockWindowShowState::NOT_SHOWN;
}
}
}
return DockWindowShowState::NOT_SHOWN;
}
void WindowLayoutPolicyCascade::LimitFloatingWindowSize(const sptr<WindowNode>& node, Rect& winRect) const
{
if (node->GetWindowMode() != WindowMode::WINDOW_MODE_FLOATING) {
return;
}
Rect oriWinRect = winRect;
const Rect& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(node->GetDisplayId());
UpdateFloatingWindowSizeBySizeLimits(node, displayRect, winRect);
UpdateFloatingWindowSizeForStretchableWindow(node, displayRect, winRect);
FixWindowRectWhenDrag(node, oriWinRect, winRect);
}
void WindowLayoutPolicyCascade::LimitMainFloatingWindowPosition(const sptr<WindowNode>& node, Rect& winRect) const
{
if (!WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
return;
}
auto reason = node->GetWindowSizeChangeReason();
if (reason == WindowSizeChangeReason::DRAG) {
LimitWindowPositionWhenDrag(node, winRect);
FixWindowSizeByRatioIfDragBeyondLimitRegion(node, winRect);
} else {
LimitWindowPositionWhenInitRectOrMove(node, winRect);
}
}
void WindowLayoutPolicyCascade::UpdateFloatingWindowSizeForStretchableWindow(const sptr<WindowNode>& node,
const Rect& displayRect, Rect& winRect) const
{
if (!node->GetStretchable() || !WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
return;
}
if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG) {
const Rect &originRect = node->GetOriginRect();
if (originRect.height_ == 0 || originRect.width_ == 0) {
WLOGE("invalid originRect. window id: %{public}u", node->GetWindowId());
return;
}
auto dragType = node->GetDragType();
if (dragType == DragType::DRAG_BOTTOM_OR_TOP) {
winRect.width_ = winRect.height_ * originRect.width_ / originRect.height_;
} else if (dragType == DragType::DRAG_LEFT_TOP_CORNER || dragType == DragType::DRAG_RIGHT_TOP_CORNER ||
dragType == DragType::DRAG_LEFT_OR_RIGHT) {
winRect.height_ = winRect.width_ * originRect.height_ / originRect.width_;
}
}
const auto& sizeLimits = node->GetWindowUpdatedSizeLimits();
float scale = std::min(static_cast<float>(winRect.width_) / sizeLimits.minWidth_,
static_cast<float>(winRect.height_) / sizeLimits.minHeight_);
if (MathHelper::NearZero(scale)) {
WLOGE("invalid sizeLimits");
return;
}
if (scale < 1.0f) {
winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / scale);
winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) / scale);
}
}
void WindowLayoutPolicyCascade::FixWindowSizeByRatioIfDragBeyondLimitRegion(const sptr<WindowNode>& node,
Rect& winRect) const
{
if (!MathHelper::NearZero(node->GetAspectRatio())) {
return;
}
const auto& sizeLimits = node->GetWindowUpdatedSizeLimits();
if (sizeLimits.maxWidth_ == sizeLimits.minWidth_ && sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
WLOGFD("window rect can not be changed");
return;
}
if (winRect.height_ == 0) {
return;
}
float curRatio = static_cast<float>(winRect.width_) / static_cast<float>(winRect.height_);
if (sizeLimits.minRatio_ <= curRatio && curRatio <= sizeLimits.maxRatio_) {
WLOGFD("window ratio is satisfied with limit ratio, curRatio: %{public}f", curRatio);
return;
}
float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
Rect limitRect = (node->isShowingOnMultiDisplays_) ? displayGroupLimitRect_ : limitRectMap_[node->GetDisplayId()];
int32_t limitMinPosX = limitRect.posX_ + static_cast<int32_t>(windowTitleBarH);
int32_t limitMaxPosX = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - windowTitleBarH);
int32_t limitMinPosY = limitRect.posY_;
int32_t limitMaxPosY = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - windowTitleBarH);
Rect dockWinRect;
DockWindowShowState dockShownState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect);
WLOGFD("dock window show type: %{public}u", dockShownState);
if (dockShownState == DockWindowShowState::SHOWN_IN_BOTTOM) {
limitMaxPosY = dockWinRect.posY_ - static_cast<int32_t>(windowTitleBarH);
} else if (dockShownState == DockWindowShowState::SHOWN_IN_LEFT) {
limitMinPosX = dockWinRect.posX_ + static_cast<int32_t>(dockWinRect.width_ + windowTitleBarH);
} else if (dockShownState == DockWindowShowState::SHOWN_IN_RIGHT) {
limitMaxPosX = dockWinRect.posX_ - static_cast<int32_t>(windowTitleBarH);
}
float newRatio = curRatio < sizeLimits.minRatio_ ? sizeLimits.minRatio_ : sizeLimits.maxRatio_;
if ((winRect.posX_ + static_cast<int32_t>(winRect.width_) == limitMinPosX) || (winRect.posX_ == limitMaxPosX)) {
if (sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
return;
}
winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / newRatio);
}
if ((winRect.posY_ == limitMinPosY) || (winRect.posX_ == limitMaxPosY)) {
if (sizeLimits.maxWidth_ == sizeLimits.minWidth_) {
return;
}
winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) * newRatio);
}
WLOGFD("After limit by ratio if beyond limit region, winRect: %{public}d %{public}d %{public}u %{public}u",
winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
}
void WindowLayoutPolicyCascade::UpdateFloatingWindowSizeBySizeLimits(const sptr<WindowNode>& node,
const Rect& displayRect, Rect& winRect) const
{
const auto& sizeLimits = node->GetWindowUpdatedSizeLimits();
if ((!WindowHelper::IsSystemWindow(node->GetWindowType()) &&
(!WindowHelper::IsSubWindow(node->GetWindowType()))) ||
node->GetWindowType() == WindowType::WINDOW_TYPE_FLOAT_CAMERA ||
node->GetWindowType() == WindowType::WINDOW_TYPE_DIALOG) {
winRect.width_ = std::max(sizeLimits.minWidth_, winRect.width_);
winRect.height_ = std::max(sizeLimits.minHeight_, winRect.height_);
}
winRect.width_ = std::min(sizeLimits.maxWidth_, winRect.width_);
winRect.height_ = std::min(sizeLimits.maxHeight_, winRect.height_);
WLOGFD("After limit by size, winRect: %{public}d %{public}d %{public}u %{public}u",
winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
if (sizeLimits.maxWidth_ == sizeLimits.minWidth_ &&
sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
winRect.width_ = sizeLimits.maxWidth_;
winRect.height_ = sizeLimits.maxHeight_;
WLOGFD("window rect can not be changed");
return;
}
if (!MathHelper::NearZero(node->GetAspectRatio())) {
return;
}
float curRatio = static_cast<float>(winRect.width_) / static_cast<float>(winRect.height_);
if (!WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode()) ||
(sizeLimits.minRatio_ <= curRatio && curRatio <= sizeLimits.maxRatio_)) {
WLOGFD("window is system window or ratio is satisfied with limits, curSize: [%{public}d, %{public}d], "
"curRatio: %{public}f", winRect.width_, winRect.height_, curRatio);
return;
}
float newRatio = curRatio < sizeLimits.minRatio_ ? sizeLimits.minRatio_ : sizeLimits.maxRatio_;
if (sizeLimits.maxWidth_ == sizeLimits.minWidth_) {
winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / newRatio);
return;
}
if (sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) * newRatio);
return;
}
auto dragType = node->GetDragType();
if (dragType == DragType::DRAG_BOTTOM_OR_TOP) {
winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) * newRatio);
} else {
winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / newRatio);
}
WLOGI("After limit by customize config, winRect: %{public}d %{public}d %{public}u %{public}u",
winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
}
void WindowLayoutPolicyCascade::FixWindowRectWhenDrag(const sptr<WindowNode>& node,
const Rect& oriWinRect, Rect& winRect) const
{
const auto& lastWinRect = node->GetWindowRect();
if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG) {
if (oriWinRect.posX_ != lastWinRect.posX_) {
winRect.posX_ = oriWinRect.posX_ + static_cast<int32_t>(oriWinRect.width_) -
static_cast<int32_t>(winRect.width_);
}
if (oriWinRect.posY_ != lastWinRect.posY_) {
winRect.posY_ = oriWinRect.posY_ + static_cast<int32_t>(oriWinRect.height_) -
static_cast<int32_t>(winRect.height_);
}
}
}
void WindowLayoutPolicyCascade::LimitWindowPositionWhenDrag(const sptr<WindowNode>& node, Rect& winRect) const
{
float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
const Rect& lastRect = node->GetWindowRect();
Rect oriWinRect = winRect;
Rect limitRect = (node->isShowingOnMultiDisplays_) ? displayGroupLimitRect_ : limitRectMap_[node->GetDisplayId()];
int32_t limitMinPosX = limitRect.posX_ + static_cast<int32_t>(windowTitleBarH);
int32_t limitMaxPosX = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - windowTitleBarH);
int32_t limitMinPosY = limitRect.posY_;
int32_t limitMaxPosY = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - windowTitleBarH);
Rect dockWinRect;
DockWindowShowState dockShownState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect);
if (dockShownState == DockWindowShowState::SHOWN_IN_BOTTOM) {
limitMaxPosY = dockWinRect.posY_ - static_cast<int32_t>(windowTitleBarH);
} else if (dockShownState == DockWindowShowState::SHOWN_IN_LEFT) {
limitMinPosX = dockWinRect.posX_ + static_cast<int32_t>(dockWinRect.width_ + windowTitleBarH);
} else if (dockShownState == DockWindowShowState::SHOWN_IN_RIGHT) {
limitMaxPosX = dockWinRect.posX_ - static_cast<int32_t>(windowTitleBarH);
}
if (oriWinRect.posX_ + static_cast<int32_t>(oriWinRect.width_) < limitMinPosX) {
if (oriWinRect.width_ != lastRect.width_) {
winRect.width_ = static_cast<uint32_t>(limitMinPosX - oriWinRect.posX_);
}
}
if (oriWinRect.posX_ > limitMaxPosX) {
winRect.posX_ = limitMaxPosX;
if (oriWinRect.width_ != lastRect.width_) {
winRect.width_ = static_cast<uint32_t>(
oriWinRect.posX_ + static_cast<int32_t>(oriWinRect.width_) - winRect.posX_);
}
}
if (oriWinRect.posY_ < limitMinPosY) {
winRect.posY_ = limitMinPosY;
if (oriWinRect.height_ != lastRect.height_) {
winRect.height_ = static_cast<uint32_t>(
oriWinRect.posY_ + static_cast<int32_t>(oriWinRect.height_) - winRect.posY_);
}
}
if (winRect.posY_ > limitMaxPosY) {
winRect.posY_ = limitMaxPosY;
if (oriWinRect.height_ != lastRect.height_) {
winRect.height_ = static_cast<uint32_t>(
oriWinRect.posY_ + static_cast<int32_t>(oriWinRect.height_) - winRect.posY_);
}
}
WLOGI("After limit by position, winRect: %{public}d %{public}d %{public}u %{public}u",
winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
}
void WindowLayoutPolicyCascade::LimitWindowPositionWhenInitRectOrMove(const sptr<WindowNode>& node, Rect& winRect) const
{
float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
Rect limitRect = (node->isShowingOnMultiDisplays_) ? displayGroupLimitRect_ : limitRectMap_[node->GetDisplayId()];
if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
Rect dockWinRect;
DockWindowShowState dockShownState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect);
winRect.posY_ = std::max(limitRect.posY_, winRect.posY_);
winRect.posY_ = std::min(limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - windowTitleBarH),
winRect.posY_);
if (dockShownState == DockWindowShowState::SHOWN_IN_BOTTOM) {
WLOGFD("dock window show in bottom");
winRect.posY_ = std::min(dockWinRect.posY_ - static_cast<int32_t>(windowTitleBarH),
winRect.posY_);
}
winRect.posX_ = std::max(limitRect.posX_ + static_cast<int32_t>(windowTitleBarH - winRect.width_),
winRect.posX_);
if (dockShownState == DockWindowShowState::SHOWN_IN_LEFT) {
WLOGFD("dock window show in left");
winRect.posX_ = std::max(static_cast<int32_t>(dockWinRect.width_ + windowTitleBarH - winRect.width_),
winRect.posX_);
}
winRect.posX_ = std::min(limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - windowTitleBarH),
winRect.posX_);
if (dockShownState == DockWindowShowState::SHOWN_IN_RIGHT) {
WLOGFD("dock window show in right");
winRect.posX_ = std::min(dockWinRect.posX_ - static_cast<int32_t>(windowTitleBarH),
winRect.posX_);
}
auto reason = node->GetWindowSizeChangeReason();
if (floatingBottomPosY_ != 0 && reason == WindowSizeChangeReason::UNDEFINED) {
int32_t bottomPosY = static_cast<int32_t>(floatingBottomPosY_ * virtualPixelRatio);
if (winRect.posY_ + static_cast<int32_t>(winRect.height_) >= bottomPosY) {
winRect.posY_ = limitRect.posY_;
}
}
}
WLOGI("After limit by position if init or move, winRect: %{public}d %{public}d %{public}u %{public}u",
winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
}
void WindowLayoutPolicyCascade::GetMaximizeRect(const sptr<WindowNode>& node, Rect& maxRect)
{
auto property = node->GetWindowProperty();
if (property == nullptr) {
WLOGFE("window property is nullptr.");
return;
}
const auto& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(node->GetDisplayId());
const Rect& limitRect = limitRectMap_[node->GetDisplayId()];
Rect dockWinRect = { 0, 0, 0, 0 };
DockWindowShowState dockState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect);
uint32_t dockHeight = dockState == DockWindowShowState::SHOWN_IN_BOTTOM ? dockWinRect.height_ : 0;
maxRect.posX_ = limitRect.posX_;
maxRect.posY_ = limitRect.posY_;
maxRect.width_ = limitRect.width_;
maxRect.height_ = displayRect.height_ - limitRect.posY_ - dockHeight;
WLOGFI("GetMaximizeRect maxRect = %{public}d, %{public}d, %{public}u, %{public}u ",
maxRect.posX_, maxRect.posY_, maxRect.width_, maxRect.height_);
}
}
}