1/* 2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "window_layout_policy_cascade.h" 17 18#include <hitrace_meter.h> 19 20#include "minimize_app.h" 21#include "window_helper.h" 22#include "window_inner_manager.h" 23#include "window_manager_hilog.h" 24#include "window_manager_service_utils.h" 25#include "window_system_effect.h" 26#include "wm_math.h" 27 28namespace OHOS { 29namespace Rosen { 30namespace { 31constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "Cascade"}; 32} 33 34WindowLayoutPolicyCascade::WindowLayoutPolicyCascade(DisplayGroupWindowTree& displayGroupWindowTree) 35 : WindowLayoutPolicy(displayGroupWindowTree) 36{ 37 CascadeRects cascadeRects { 38 .primaryRect_ = {0, 0, 0, 0}, 39 .secondaryRect_ = {0, 0, 0, 0}, 40 .dividerRect_ = {0, 0, 0, 0}, 41 .defaultCascadeRect_ = {0, 0, 0, 0}, 42 }; 43 for (auto& iter : DisplayGroupInfo::GetInstance().GetAllDisplayRects()) { 44 cascadeRectsMap_.insert(std::make_pair(iter.first, cascadeRects)); 45 } 46} 47 48void WindowLayoutPolicyCascade::Launch() 49{ 50 InitAllRects(); 51 WLOGI("WindowLayoutPolicyCascade::Launch"); 52} 53 54void WindowLayoutPolicyCascade::Reorder() 55{ 56 WLOGFD("Cascade reorder start"); 57 for (auto& iter : DisplayGroupInfo::GetInstance().GetAllDisplayRects()) { 58 DisplayId displayId = iter.first; 59 Rect rect = cascadeRectsMap_[displayId].defaultCascadeRect_; 60 bool isFirstReorderedWindow = true; 61 const auto& appWindowNodeVec = *(displayGroupWindowTree_[displayId][WindowRootNodeType::APP_WINDOW_NODE]); 62 for (auto nodeIter = appWindowNodeVec.begin(); nodeIter != appWindowNodeVec.end(); nodeIter++) { 63 auto node = *nodeIter; 64 if (node == nullptr || node->GetWindowType() != WindowType::WINDOW_TYPE_APP_MAIN_WINDOW) { 65 WLOGFW("get node failed or not app window."); 66 continue; 67 } 68 // if window don't support floating mode, or default rect of cascade is not satisfied with limits 69 if (!WindowHelper::IsWindowModeSupported(node->GetModeSupportInfo(), WindowMode::WINDOW_MODE_FLOATING) || 70 !WindowHelper::IsRectSatisfiedWithSizeLimits(rect, node->GetWindowUpdatedSizeLimits())) { 71 MinimizeApp::AddNeedMinimizeApp(node, MinimizeReason::LAYOUT_CASCADE); 72 continue; 73 } 74 if (isFirstReorderedWindow) { 75 isFirstReorderedWindow = false; 76 } else { 77 rect = StepCascadeRect(rect, displayId); 78 } 79 node->SetRequestRect(rect); 80 node->SetDecoStatus(true); 81 if (node->GetWindowMode() != WindowMode::WINDOW_MODE_FLOATING) { 82 node->SetWindowMode(WindowMode::WINDOW_MODE_FLOATING); 83 // when change mode, need to reset shadow and radius 84 WindowSystemEffect::SetWindowEffect(node); 85 if (node->GetWindowToken()) { 86 node->GetWindowToken()->UpdateWindowMode(WindowMode::WINDOW_MODE_FLOATING); 87 } 88 } 89 WLOGFD("Cascade reorder Id: %{public}d, rect:[%{public}d, %{public}d, %{public}d, %{public}d]", 90 node->GetWindowId(), rect.posX_, rect.posY_, rect.width_, rect.height_); 91 } 92 LayoutWindowTree(displayId); 93 } 94 WLOGI("Cascade Reorder end"); 95} 96 97void WindowLayoutPolicyCascade::InitAllRects() 98{ 99 UpdateDisplayGroupRect(); 100 for (auto& iter : DisplayGroupInfo::GetInstance().GetAllDisplayRects()) { 101 auto displayId = iter.first; 102 InitSplitRects(displayId); 103 LayoutWindowTree(displayId); 104 InitCascadeRect(displayId); 105 } 106} 107 108void WindowLayoutPolicyCascade::LayoutSplitNodes(DisplayId displayId, WindowUpdateType type, bool layoutByDivider) 109{ 110 std::vector<WindowRootNodeType> rootNodeType = { 111 WindowRootNodeType::ABOVE_WINDOW_NODE, 112 WindowRootNodeType::APP_WINDOW_NODE, 113 WindowRootNodeType::BELOW_WINDOW_NODE 114 }; 115 for (const auto& rootType : rootNodeType) { 116 if (displayGroupWindowTree_[displayId].find(rootType) == displayGroupWindowTree_[displayId].end()) { 117 continue; 118 } 119 auto appWindowNodeVec = *(displayGroupWindowTree_[displayId][rootType]); 120 for (const auto& childNode : appWindowNodeVec) { 121 if (type == WindowUpdateType::WINDOW_UPDATE_REMOVED) { 122 /* 123 * If updateType is remove we need to layout all appNodes, cause remove split node or 124 * divider means exit split mode, split node may change to other mode 125 */ 126 LayoutWindowNode(childNode); 127 } else if (childNode->IsSplitMode()) { // add or update type, layout split node 128 if (layoutByDivider && type == WindowUpdateType::WINDOW_UPDATE_ACTIVE) { 129 childNode->SetWindowSizeChangeReason(WindowSizeChangeReason::DRAG); 130 } 131 LayoutWindowNode(childNode); 132 } 133 } 134 } 135} 136 137void WindowLayoutPolicyCascade::LayoutDivider(const sptr<WindowNode>& node, WindowUpdateType type) 138{ 139 auto displayId = node->GetDisplayId(); 140 switch (type) { 141 case WindowUpdateType::WINDOW_UPDATE_ADDED: 142 SetInitialDividerRect(node, displayId); 143 [[fallthrough]]; 144 case WindowUpdateType::WINDOW_UPDATE_ACTIVE: 145 UpdateDividerPosition(node); 146 LayoutWindowNode(node); 147 SetSplitRectByDivider(node->GetWindowRect(), displayId); // set splitRect by divider 148 break; 149 case WindowUpdateType::WINDOW_UPDATE_REMOVED: 150 InitSplitRects(displayId); // reinit split rects when remove divider 151 break; 152 default: 153 WLOGFW("Unknown update type, type: %{public}u", type); 154 } 155 LayoutSplitNodes(displayId, type, true); 156} 157 158void WindowLayoutPolicyCascade::LayoutPreProcess(const sptr<WindowNode>& node, WindowUpdateType updateType) 159{ 160 if (updateType == WindowUpdateType::WINDOW_UPDATE_ADDED) { 161 // Get aspect ratio from persistent storage when add window 162 GetStoragedAspectRatio(node); 163 } 164 SetDefaultCascadeRect(node); 165 FixWindowRectWithinDisplay(node); 166} 167 168void WindowLayoutPolicyCascade::PerformWindowLayout(const sptr<WindowNode>& node, WindowUpdateType updateType) 169{ 170 HITRACE_METER(HITRACE_TAG_WINDOW_MANAGER); 171 const auto& windowType = node->GetWindowType(); 172 const auto& requestRect = node->GetRequestRect(); 173 WLOGFD("windowId: %{public}u, windowType: %{public}u, updateType: %{public}u, requestRect: " 174 "requestRect: [%{public}d, %{public}d, %{public}u, %{public}u]", node->GetWindowId(), windowType, updateType, 175 requestRect.posX_, requestRect.posY_, requestRect.width_, requestRect.height_); 176 177 LayoutPreProcess(node, updateType); 178 switch (windowType) { 179 case WindowType::WINDOW_TYPE_DOCK_SLICE: 180 LayoutDivider(node, updateType); 181 break; 182 case WindowType::WINDOW_TYPE_STATUS_BAR: 183 case WindowType::WINDOW_TYPE_NAVIGATION_BAR: 184 case WindowType::WINDOW_TYPE_LAUNCHER_DOCK: 185 LayoutWindowTree(node->GetDisplayId()); 186 // AvoidNodes will change limitRect, need to recalculate default cascade rect 187 InitCascadeRect(node->GetDisplayId()); 188 break; 189 default: 190 if (node->IsSplitMode()) { 191 LayoutSplitNodes(node->GetDisplayId(), updateType); 192 } else { 193 LayoutWindowNode(node); 194 } 195 } 196 if (updateType == WindowUpdateType::WINDOW_UPDATE_REMOVED) { 197 NotifyClientAndAnimation(node, node->GetRequestRect(), WindowSizeChangeReason::HIDE); 198 } 199} 200 201void WindowLayoutPolicyCascade::SetInitialDividerRect(const sptr<WindowNode>& node, DisplayId displayId) 202{ 203 const auto& restoredRect = restoringDividerWindowRects_[displayId]; 204 const auto& presetRect = cascadeRectsMap_[node->GetDisplayId()].dividerRect_; 205 auto divRect = WindowHelper::IsEmptyRect(restoredRect) ? presetRect : restoredRect; 206 node->SetRequestRect(divRect); 207 restoringDividerWindowRects_.erase(displayId); 208} 209 210void WindowLayoutPolicyCascade::SetSplitDividerWindowRects(std::map<DisplayId, Rect> dividerWindowRects) 211{ 212 restoringDividerWindowRects_ = dividerWindowRects; 213} 214 215void WindowLayoutPolicyCascade::LimitDividerInDisplayRegion(Rect& rect, DisplayId displayId) const 216{ 217 const Rect& limitRect = limitRectMap_[displayId]; 218 if (rect.width_ < rect.height_) { 219 if (rect.posX_ < limitRect.posX_) { 220 rect.posX_ = limitRect.posX_; 221 } else if (rect.posX_ + static_cast<int32_t>(rect.width_) > 222 limitRect.posX_ + static_cast<int32_t>(limitRect.width_)) { 223 rect.posX_ = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - rect.width_); 224 } 225 } else { 226 if (rect.posY_ < limitRect.posY_) { 227 rect.posY_ = limitRect.posY_; 228 } else if (rect.posY_ + static_cast<int32_t>(rect.height_) > 229 limitRect.posY_ + static_cast<int32_t>(limitRect.height_)) { 230 rect.posY_ = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - rect.height_); 231 } 232 } 233 WLOGFD("limit divider move bounds: [%{public}d, %{public}d, %{public}u, %{public}u]", 234 rect.posX_, rect.posY_, rect.width_, rect.height_); 235} 236 237void WindowLayoutPolicyCascade::UpdateDividerPosition(const sptr<WindowNode>& node) const 238{ 239 auto rect = node->GetRequestRect(); 240 auto displayId = node->GetDisplayId(); 241 LimitDividerInDisplayRegion(rect, displayId); 242 if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG_END) { 243 LimitDividerPositionBySplitRatio(displayId, rect); 244 } 245 node->SetRequestRect(rect); 246} 247 248void WindowLayoutPolicyCascade::InitCascadeRect(DisplayId displayId) 249{ 250 constexpr uint32_t half = 2; 251 constexpr float ratio = DEFAULT_ASPECT_RATIO; 252 253 /* 254 * Calculate default width and height, if width or height is 255 * smaller than minWidth or minHeight, use the minimum limits 256 */ 257 const auto& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId); 258 auto vpr = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(displayId); 259 uint32_t defaultW = std::max(static_cast<uint32_t>(displayRect.width_ * ratio), 260 static_cast<uint32_t>(MIN_FLOATING_WIDTH * vpr)); 261 uint32_t defaultH = std::max(static_cast<uint32_t>(displayRect.height_ * ratio), 262 static_cast<uint32_t>(MIN_FLOATING_HEIGHT * vpr)); 263 264 // calculate default x and y 265 Rect resRect = {0, 0, defaultW, defaultH}; 266 const Rect& limitRect = limitRectMap_[displayId]; 267 if (defaultW <= limitRect.width_ && defaultH <= limitRect.height_) { 268 resRect.posX_ = limitRect.posX_ + static_cast<int32_t>((limitRect.width_ - defaultW) / half); 269 270 resRect.posY_ = limitRect.posY_ + static_cast<int32_t>((limitRect.height_ - defaultH) / half); 271 } 272 WLOGI("Init CascadeRect :[%{public}d, %{public}d, %{public}d, %{public}d]", 273 resRect.posX_, resRect.posY_, resRect.width_, resRect.height_); 274 cascadeRectsMap_[displayId].defaultCascadeRect_ = resRect; 275} 276 277bool WindowLayoutPolicyCascade::CheckAspectRatioBySizeLimits(const sptr<WindowNode>& node, 278 WindowLimits& newLimits) const 279{ 280 // get new limit config with the settings of system and app 281 const auto& sizeLimits = node->GetWindowUpdatedSizeLimits(); 282 if (node->GetWindowProperty() != nullptr && !node->GetWindowProperty()->GetDecorEnable()) { 283 newLimits = sizeLimits; 284 } else { 285 float vpr = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId()); 286 uint32_t winFrameW = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * vpr) * 2; // 2 mean double decor width 287 uint32_t winFrameH = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * vpr) + 288 static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * vpr); // decor height 289 290 newLimits.maxWidth_ = sizeLimits.maxWidth_ - winFrameW; 291 newLimits.minWidth_ = sizeLimits.minWidth_ - winFrameW; 292 newLimits.maxHeight_ = sizeLimits.maxHeight_ - winFrameH; 293 newLimits.minHeight_ = sizeLimits.minHeight_ - winFrameH; 294 } 295 296 float maxRatio = static_cast<float>(newLimits.maxWidth_) / static_cast<float>(newLimits.minHeight_); 297 float minRatio = static_cast<float>(newLimits.minWidth_) / static_cast<float>(newLimits.maxHeight_); 298 float aspectRatio = node->GetAspectRatio(); 299 if (MathHelper::GreatNotEqual(aspectRatio, maxRatio) || 300 MathHelper::LessNotEqual(aspectRatio, minRatio)) { 301 return false; 302 } 303 uint32_t newMaxWidth = static_cast<uint32_t>(static_cast<float>(newLimits.maxHeight_) * aspectRatio); 304 newLimits.maxWidth_ = std::min(newMaxWidth, newLimits.maxWidth_); 305 uint32_t newMinWidth = static_cast<uint32_t>(static_cast<float>(newLimits.minHeight_) * aspectRatio); 306 newLimits.minWidth_ = std::max(newMinWidth, newLimits.minWidth_); 307 uint32_t newMaxHeight = static_cast<uint32_t>(static_cast<float>(newLimits.maxWidth_) / aspectRatio); 308 newLimits.maxHeight_ = std::min(newMaxHeight, newLimits.maxHeight_); 309 uint32_t newMinHeight = static_cast<uint32_t>(static_cast<float>(newLimits.minWidth_) / aspectRatio); 310 newLimits.minHeight_ = std::max(newMinHeight, newLimits.minHeight_); 311 return true; 312} 313 314void WindowLayoutPolicyCascade::ComputeRectByAspectRatio(const sptr<WindowNode>& node) const 315{ 316 float aspectRatio = node->GetAspectRatio(); 317 if (!WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode()) || 318 node->GetWindowSizeChangeReason() == WindowSizeChangeReason::MOVE || MathHelper::NearZero(aspectRatio)) { 319 return; 320 } 321 322 // 1. check ratio by size limits 323 WindowLimits newLimits; 324 if (!CheckAspectRatioBySizeLimits(node, newLimits)) { 325 return; 326 } 327 328 float vpr = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId()); 329 uint32_t winFrameW = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * vpr) * 2; // 2 mean double decor width 330 uint32_t winFrameH = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * vpr) + 331 static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * vpr); // decor height 332 333 // 2. get rect without decoration if enable decoration 334 auto newRect = node->GetRequestRect(); 335 if (node->GetWindowProperty() != nullptr && node->GetWindowProperty()->GetDecorEnable()) { 336 newRect.width_ -= winFrameW; 337 newRect.height_ -= winFrameH; 338 } 339 auto oriRect = newRect; 340 341 // 3. update window rect by new limits and aspect ratio 342 newRect.width_ = std::max(newLimits.minWidth_, newRect.width_); 343 newRect.height_ = std::max(newLimits.minHeight_, newRect.height_); 344 newRect.width_ = std::min(newLimits.maxWidth_, newRect.width_); 345 newRect.height_ = std::min(newLimits.maxHeight_, newRect.height_); 346 float curRatio = static_cast<float>(newRect.width_) / static_cast<float>(newRect.height_); 347 if (std::abs(curRatio - aspectRatio) > 0.0001f) { 348 if (node->GetDragType() == DragType::DRAG_BOTTOM_OR_TOP) { 349 // if drag height, use height to fix size. 350 newRect.width_ = static_cast<uint32_t>(static_cast<float>(newRect.height_) * aspectRatio); 351 } else { 352 // if drag width or corner, use width to fix size. 353 newRect.height_ = static_cast<uint32_t>(static_cast<float>(newRect.width_) / aspectRatio); 354 } 355 } 356 357 // 4. fix window pos in case of moving window when dragging 358 FixWindowRectWhenDrag(node, oriRect, newRect); 359 360 // 5. if posY is smaller than limit posY when drag, use the last window rect 361 if (newRect.posY_ < limitRectMap_[node->GetDisplayId()].posY_ && 362 node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG) { 363 auto lastRect = node->GetWindowRect(); 364 lastRect.width_ -= winFrameW; 365 lastRect.height_ -= winFrameH; 366 newRect = lastRect; 367 } 368 node->SetRequestRect(newRect); 369 node->SetDecoStatus(false); // newRect is not rect with decor, reset decor status 370 WLOGFD("WinId: %{public}u, newRect: %{public}d %{public}d %{public}u %{public}u", 371 node->GetWindowId(), newRect.posX_, newRect.posY_, newRect.width_, newRect.height_); 372} 373 374void WindowLayoutPolicyCascade::ComputeDecoratedRequestRect(const sptr<WindowNode>& node) const 375{ 376 auto property = node->GetWindowProperty(); 377 if (property == nullptr) { 378 WLOGE("window property is nullptr"); 379 return; 380 } 381 382 if (!property->GetDecorEnable() || property->GetDecoStatus() || 383 node->GetWindowSizeChangeReason() == WindowSizeChangeReason::MOVE) { 384 return; 385 } 386 387 float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId()); 388 uint32_t winFrameW = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * virtualPixelRatio); 389 uint32_t winTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio); 390 391 auto oriRect = property->GetRequestRect(); 392 Rect dstRect; 393 dstRect.posX_ = oriRect.posX_; 394 dstRect.posY_ = oriRect.posY_; 395 dstRect.width_ = oriRect.width_ + winFrameW + winFrameW; 396 dstRect.height_ = oriRect.height_ + winTitleBarH + winFrameW; 397 property->SetRequestRect(dstRect); 398 property->SetDecoStatus(true); 399} 400 401void WindowLayoutPolicyCascade::ApplyWindowRectConstraints(const sptr<WindowNode>& node, Rect& winRect) const 402{ 403 WLOGFD("[Before constraints] windowId: %{public}u, winRect:[%{public}d, %{public}d, %{public}u, %{public}u]", 404 node->GetWindowId(), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_); 405 ComputeRectByAspectRatio(node); 406 ComputeDecoratedRequestRect(node); 407 winRect = node->GetRequestRect(); 408 LimitFloatingWindowSize(node, winRect); 409 LimitMainFloatingWindowPosition(node, winRect); 410 411 /* 412 * Use the orientation of the window and display to determine 413 * whether the screen is rotating, then rotate the divider 414 */ 415 if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE && 416 ((!WindowHelper::IsLandscapeRect(winRect) && IsVerticalDisplay(node->GetDisplayId())) || 417 (WindowHelper::IsLandscapeRect(winRect) && !IsVerticalDisplay(node->GetDisplayId())))) { 418 winRect = cascadeRectsMap_[node->GetDisplayId()].dividerRect_; 419 node->SetRequestRect(winRect); 420 WLOGFD("Reset divider when display rotation, divRect: [%{public}d, %{public}d, %{public}u, %{public}u]", 421 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_); 422 } 423 424 WLOGFD("[After constraints] windowId: %{public}u, winRect:[%{public}d, %{public}d, %{public}u, %{public}u]", 425 node->GetWindowId(), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_); 426} 427 428void WindowLayoutPolicyCascade::UpdateLayoutRect(const sptr<WindowNode>& node) 429{ 430 auto property = node->GetWindowProperty(); 431 if (property == nullptr) { 432 WLOGFE("window property is nullptr."); 433 return; 434 } 435 auto mode = node->GetWindowMode(); 436 Rect winRect = property->GetRequestRect(); 437 auto displayId = node->GetDisplayId(); 438 WLOGFD("[Before CascadeLayout] windowId: %{public}u, mode: %{public}u, type: %{public}u requestRect: [%{public}d, " 439 "%{public}d, %{public}u, %{public}u]", node->GetWindowId(), mode, node->GetWindowType(), winRect.posX_, 440 winRect.posY_, winRect.width_, winRect.height_); 441 switch (mode) { 442 case WindowMode::WINDOW_MODE_SPLIT_PRIMARY: 443 winRect = cascadeRectsMap_[displayId].primaryRect_; 444 break; 445 case WindowMode::WINDOW_MODE_SPLIT_SECONDARY: 446 winRect = cascadeRectsMap_[displayId].secondaryRect_; 447 break; 448 case WindowMode::WINDOW_MODE_FULLSCREEN: { 449 UpdateWindowSizeLimits(node); 450 bool needAvoid = (node->GetWindowFlags() & static_cast<uint32_t>(WindowFlag::WINDOW_FLAG_NEED_AVOID)); 451 winRect = needAvoid ? limitRectMap_[displayId] : DisplayGroupInfo::GetInstance().GetDisplayRect(displayId); 452 auto displayInfo = DisplayGroupInfo::GetInstance().GetDisplayInfo(displayId); 453 if (displayInfo && WmsUtils::IsExpectedRotatableWindow(node->GetRequestedOrientation(), 454 displayInfo->GetDisplayOrientation(), node->GetWindowFlags())) { 455 WLOGFD("[FixOrientation] the window is expected rotatable, pre-calculated"); 456 winRect = {winRect.posX_, winRect.posY_, winRect.height_, winRect.width_}; 457 } 458 if (property->GetMaximizeMode() == MaximizeMode::MODE_AVOID_SYSTEM_BAR) { 459 // restore the origin rect so when recover from fullscreen we can use 460 node->SetRequestRect(node->GetOriginRect()); 461 property->SetMaximizeMode(MaximizeMode::MODE_FULL_FILL); 462 } 463 break; 464 } 465 case WindowMode::WINDOW_MODE_FLOATING: { 466 if (node->GetWindowType() == WindowType::WINDOW_TYPE_APP_COMPONENT) { 467 break; 468 } 469 UpdateWindowSizeLimits(node); 470 winRect = property->GetRequestRect(); 471 ApplyWindowRectConstraints(node, winRect); 472 473 if (property->GetMaximizeMode() == MaximizeMode::MODE_AVOID_SYSTEM_BAR) { 474 GetMaximizeRect(node, winRect); 475 WLOGFI("[In CascadeLayout] winId: %{public}u, maxRect: %{public}d, %{public}d, %{public}u, %{public}u", 476 node->GetWindowId(), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_); 477 } 478 break; 479 } 480 default: 481 WLOGFW("Layout invalid mode, winId: %{public}u, mode: %{public}u", node->GetWindowId(), mode); 482 } 483 WLOGFD("[After CascadeLayout] windowId: %{public}u, isDecor: %{public}u, winRect: [%{public}d, %{public}d, " 484 "%{public}u, %{public}u], reason: %{public}u", node->GetWindowId(), node->GetDecoStatus(), winRect.posX_, 485 winRect.posY_, winRect.width_, winRect.height_, node->GetWindowSizeChangeReason()); 486 487 const Rect& lastWinRect = node->GetWindowRect(); 488 node->SetWindowRect(winRect); 489 490 // postProcess after update winRect 491 CalcAndSetNodeHotZone(winRect, node); 492 UpdateSurfaceBounds(node, winRect, lastWinRect); 493 NotifyClientAndAnimation(node, winRect, node->GetWindowSizeChangeReason()); 494} 495 496void WindowLayoutPolicyCascade::LimitDividerPositionBySplitRatio(DisplayId displayId, Rect& winRect) const 497{ 498 int32_t oriPos = IsVerticalDisplay(displayId) ? winRect.posY_ : winRect.posX_; 499 int32_t& dstPos = IsVerticalDisplay(displayId) ? winRect.posY_ : winRect.posX_; 500 if (splitRatioPointsMap_[displayId].size() == 0) { 501 return; 502 } 503 uint32_t minDiff = std::max(limitRectMap_[displayId].width_, limitRectMap_[displayId].height_); 504 int32_t closestPoint = oriPos; 505 for (const auto& elem : splitRatioPointsMap_[displayId]) { 506 uint32_t diff = (oriPos > elem) ? static_cast<uint32_t>(oriPos - elem) : static_cast<uint32_t>(elem - oriPos); 507 if (diff < minDiff) { 508 closestPoint = elem; 509 minDiff = diff; 510 } 511 } 512 dstPos = closestPoint; 513} 514 515void WindowLayoutPolicyCascade::InitSplitRects(DisplayId displayId) 516{ 517 float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(displayId); 518 uint32_t dividerWidth = static_cast<uint32_t>(DIVIDER_WIDTH * virtualPixelRatio); 519 auto& dividerRect = cascadeRectsMap_[displayId].dividerRect_; 520 const auto& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId); 521 if (!IsVerticalDisplay(displayId)) { 522 dividerRect = { static_cast<uint32_t>((displayRect.width_ - dividerWidth) * DEFAULT_SPLIT_RATIO), 0, 523 dividerWidth, displayRect.height_ }; 524 } else { 525 dividerRect = { 0, static_cast<uint32_t>((displayRect.height_ - dividerWidth) * DEFAULT_SPLIT_RATIO), 526 displayRect.width_, dividerWidth }; 527 } 528 SetSplitRectByDivider(dividerRect, displayId); 529} 530 531void WindowLayoutPolicyCascade::SetSplitRectByDivider(const Rect& divRect, DisplayId displayId) 532{ 533 auto& dividerRect = cascadeRectsMap_[displayId].dividerRect_; 534 auto& primaryRect = cascadeRectsMap_[displayId].primaryRect_; 535 auto& secondaryRect = cascadeRectsMap_[displayId].secondaryRect_; 536 const auto& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId); 537 538 dividerRect.width_ = divRect.width_; 539 dividerRect.height_ = divRect.height_; 540 if (!IsVerticalDisplay(displayId)) { 541 primaryRect.posX_ = displayRect.posX_; 542 primaryRect.posY_ = displayRect.posY_; 543 primaryRect.width_ = divRect.posX_; 544 primaryRect.height_ = displayRect.height_; 545 546 secondaryRect.posX_ = divRect.posX_ + static_cast<int32_t>(dividerRect.width_); 547 secondaryRect.posY_ = displayRect.posY_; 548 secondaryRect.width_ = static_cast<uint32_t>(static_cast<int32_t>(displayRect.width_) - secondaryRect.posX_); 549 secondaryRect.height_ = displayRect.height_; 550 } else { 551 primaryRect.posX_ = displayRect.posX_; 552 primaryRect.posY_ = displayRect.posY_; 553 primaryRect.height_ = divRect.posY_; 554 primaryRect.width_ = displayRect.width_; 555 556 secondaryRect.posX_ = displayRect.posX_; 557 secondaryRect.posY_ = divRect.posY_ + static_cast<int32_t>(dividerRect.height_); 558 secondaryRect.height_ = static_cast<uint32_t>(static_cast<int32_t>(displayRect.height_) - secondaryRect.posY_); 559 secondaryRect.width_ = displayRect.width_; 560 } 561 WLOGFD("DividerRect: [%{public}d %{public}d %{public}u %{public}u] " 562 "PrimaryRect: [%{public}d %{public}d %{public}u %{public}u] " 563 "SecondaryRect: [%{public}d %{public}d %{public}u %{public}u]", 564 dividerRect.posX_, dividerRect.posY_, dividerRect.width_, dividerRect.height_, 565 primaryRect.posX_, primaryRect.posY_, primaryRect.width_, primaryRect.height_, 566 secondaryRect.posX_, secondaryRect.posY_, secondaryRect.width_, secondaryRect.height_); 567} 568 569Rect WindowLayoutPolicyCascade::GetCurCascadeRect(const sptr<WindowNode>& node) const 570{ 571 Rect cascadeRect = {0, 0, 0, 0}; 572 const DisplayId& displayId = node->GetDisplayId(); 573 const auto& appWindowNodeVec = *(const_cast<WindowLayoutPolicyCascade*>(this)-> 574 displayGroupWindowTree_[displayId][WindowRootNodeType::APP_WINDOW_NODE]); 575 const auto& aboveAppWindowNodeVec = *(const_cast<WindowLayoutPolicyCascade*>(this)-> 576 displayGroupWindowTree_[displayId][WindowRootNodeType::ABOVE_WINDOW_NODE]); 577 578 std::vector<std::vector<sptr<WindowNode>>> roots = { aboveAppWindowNodeVec, appWindowNodeVec }; 579 for (auto& root : roots) { 580 for (auto iter = root.rbegin(); iter != root.rend(); iter++) { 581 if ((*iter)->GetWindowType() == WindowType::WINDOW_TYPE_APP_MAIN_WINDOW && 582 (*iter)->GetWindowId() != node->GetWindowId()) { 583 auto property = (*iter)->GetWindowProperty(); 584 if (property != nullptr && property->GetMaximizeMode() != MaximizeMode::MODE_AVOID_SYSTEM_BAR) { 585 cascadeRect = ((*iter)->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING ? 586 property->GetWindowRect() : property->GetRequestRect()); 587 } 588 WLOGFD("Get current cascadeRect: %{public}u [%{public}d, %{public}d, %{public}u, %{public}u]", 589 (*iter)->GetWindowId(), cascadeRect.posX_, cascadeRect.posY_, 590 cascadeRect.width_, cascadeRect.height_); 591 break; 592 } 593 } 594 } 595 596 if (WindowHelper::IsEmptyRect(cascadeRect)) { 597 WLOGFD("cascade rect is empty use first cascade rect"); 598 return cascadeRectsMap_[displayId].defaultCascadeRect_; 599 } 600 return StepCascadeRect(cascadeRect, displayId); 601} 602 603Rect WindowLayoutPolicyCascade::StepCascadeRect(Rect rect, DisplayId displayId) const 604{ 605 float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(displayId); 606 uint32_t cascadeWidth = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio); 607 uint32_t cascadeHeight = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio); 608 609 const Rect& limitRect = limitRectMap_[displayId]; 610 Rect cascadeRect = {0, 0, 0, 0}; 611 cascadeRect.width_ = rect.width_; 612 cascadeRect.height_ = rect.height_; 613 cascadeRect.posX_ = (rect.posX_ + static_cast<int32_t>(cascadeWidth) >= limitRect.posX_) && 614 (rect.posX_ + static_cast<int32_t>(rect.width_ + cascadeWidth) <= 615 (limitRect.posX_ + static_cast<int32_t>(limitRect.width_))) ? 616 (rect.posX_ + static_cast<int32_t>(cascadeWidth)) : limitRect.posX_; 617 cascadeRect.posY_ = (rect.posY_ + static_cast<int32_t>(cascadeHeight) >= limitRect.posY_) && 618 (rect.posY_ + static_cast<int32_t>(rect.height_ + cascadeHeight) <= 619 (limitRect.posY_ + static_cast<int32_t>(limitRect.height_))) ? 620 (rect.posY_ + static_cast<int32_t>(cascadeHeight)) : limitRect.posY_; 621 WLOGFD("Step cascadeRect :[%{public}d, %{public}d, %{public}u, %{public}u]", 622 cascadeRect.posX_, cascadeRect.posY_, cascadeRect.width_, cascadeRect.height_); 623 return cascadeRect; 624} 625 626void WindowLayoutPolicyCascade::SetDefaultCascadeRect(const sptr<WindowNode>& node) 627{ 628 auto property = node->GetWindowProperty(); 629 if (property == nullptr) { 630 WLOGFE("window property is nullptr."); 631 return; 632 } 633 if (!WindowHelper::IsEmptyRect(property->GetRequestRect())) { 634 return; 635 } 636 637 static bool isFirstAppWindow = true; 638 Rect rect; 639 if (WindowHelper::IsAppWindow(property->GetWindowType()) && isFirstAppWindow) { 640 WLOGFD("Set first app window cascade rect"); 641 rect = cascadeRectsMap_[node->GetDisplayId()].defaultCascadeRect_; 642 isFirstAppWindow = false; 643 } else if (WindowHelper::IsAppWindow(property->GetWindowType()) && !isFirstAppWindow) { 644 WLOGFD("Set other app window cascade rect"); 645 rect = GetCurCascadeRect(node); 646 } else { 647 // system window 648 WLOGFD("Set system window cascade rect"); 649 rect = cascadeRectsMap_[node->GetDisplayId()].defaultCascadeRect_; 650 } 651 WLOGFD("Set cascadeRect :[%{public}d, %{public}d, %{public}u, %{public}u]", 652 rect.posX_, rect.posY_, rect.width_, rect.height_); 653 node->SetRequestRect(rect); 654 node->SetDecoStatus(true); 655} 656 657Rect WindowLayoutPolicyCascade::GetDividerRect(DisplayId displayId) const 658{ 659 Rect dividerRect = {0, 0, 0, 0}; 660 if (cascadeRectsMap_.find(displayId) != std::end(cascadeRectsMap_)) { 661 dividerRect = cascadeRectsMap_[displayId].dividerRect_; 662 } 663 return dividerRect; 664} 665 666DockWindowShowState WindowLayoutPolicyCascade::GetDockWindowShowState(DisplayId displayId, Rect& dockWinRect) const 667{ 668 auto& displayWindowTree = displayGroupWindowTree_[displayId]; 669 auto& nodeVec = *(displayWindowTree[WindowRootNodeType::ABOVE_WINDOW_NODE]); 670 for (auto& node : nodeVec) { 671 if (node->GetWindowType() != WindowType::WINDOW_TYPE_LAUNCHER_DOCK) { 672 continue; 673 } 674 675 dockWinRect = node->GetWindowRect(); 676 auto displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId); 677 WLOGI("begin dockWinRect :[%{public}d, %{public}d, %{public}u, %{public}u]", 678 dockWinRect.posX_, dockWinRect.posY_, dockWinRect.width_, dockWinRect.height_); 679 if (dockWinRect.height_ < dockWinRect.width_) { 680 if (static_cast<uint32_t>(dockWinRect.posY_) + dockWinRect.height_ == displayRect.height_) { 681 return DockWindowShowState::SHOWN_IN_BOTTOM; 682 } else { 683 return DockWindowShowState::NOT_SHOWN; 684 } 685 } else { 686 if (dockWinRect.posX_ == 0) { 687 return DockWindowShowState::SHOWN_IN_LEFT; 688 } else if (static_cast<uint32_t>(dockWinRect.posX_) + dockWinRect.width_ == displayRect.width_) { 689 return DockWindowShowState::SHOWN_IN_RIGHT; 690 } else { 691 return DockWindowShowState::NOT_SHOWN; 692 } 693 } 694 } 695 return DockWindowShowState::NOT_SHOWN; 696} 697 698void WindowLayoutPolicyCascade::LimitFloatingWindowSize(const sptr<WindowNode>& node, Rect& winRect) const 699{ 700 if (node->GetWindowMode() != WindowMode::WINDOW_MODE_FLOATING) { 701 return; 702 } 703 Rect oriWinRect = winRect; 704 const Rect& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(node->GetDisplayId()); 705 UpdateFloatingWindowSizeBySizeLimits(node, displayRect, winRect); 706 UpdateFloatingWindowSizeForStretchableWindow(node, displayRect, winRect); 707 708 // fix size in case of moving window when dragging 709 FixWindowRectWhenDrag(node, oriWinRect, winRect); 710} 711 712void WindowLayoutPolicyCascade::LimitMainFloatingWindowPosition(const sptr<WindowNode>& node, Rect& winRect) const 713{ 714 if (!WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) { 715 return; 716 } 717 718 auto reason = node->GetWindowSizeChangeReason(); 719 // if drag or move window, limit size and position 720 if (reason == WindowSizeChangeReason::DRAG) { 721 LimitWindowPositionWhenDrag(node, winRect); 722 FixWindowSizeByRatioIfDragBeyondLimitRegion(node, winRect); 723 } else { 724 // Limit window position, such as init window rect when show 725 LimitWindowPositionWhenInitRectOrMove(node, winRect); 726 } 727} 728 729void WindowLayoutPolicyCascade::UpdateFloatingWindowSizeForStretchableWindow(const sptr<WindowNode>& node, 730 const Rect& displayRect, Rect& winRect) const 731{ 732 if (!node->GetStretchable() || !WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) { 733 return; 734 } 735 if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG) { 736 const Rect &originRect = node->GetOriginRect(); 737 if (originRect.height_ == 0 || originRect.width_ == 0) { 738 WLOGE("invalid originRect. window id: %{public}u", node->GetWindowId()); 739 return; 740 } 741 auto dragType = node->GetDragType(); 742 if (dragType == DragType::DRAG_BOTTOM_OR_TOP) { 743 // if drag height, use height to fix size. 744 winRect.width_ = winRect.height_ * originRect.width_ / originRect.height_; 745 } else if (dragType == DragType::DRAG_LEFT_TOP_CORNER || dragType == DragType::DRAG_RIGHT_TOP_CORNER || 746 dragType == DragType::DRAG_LEFT_OR_RIGHT) { 747 // if drag width or corner, use width to fix size. 748 winRect.height_ = winRect.width_ * originRect.height_ / originRect.width_; 749 } 750 } 751 // limit minimum size of window 752 753 const auto& sizeLimits = node->GetWindowUpdatedSizeLimits(); 754 float scale = std::min(static_cast<float>(winRect.width_) / sizeLimits.minWidth_, 755 static_cast<float>(winRect.height_) / sizeLimits.minHeight_); 756 if (MathHelper::NearZero(scale)) { 757 WLOGE("invalid sizeLimits"); 758 return; 759 } 760 if (scale < 1.0f) { 761 winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / scale); 762 winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) / scale); 763 } 764} 765 766void WindowLayoutPolicyCascade::FixWindowSizeByRatioIfDragBeyondLimitRegion(const sptr<WindowNode>& node, 767 Rect& winRect) const 768{ 769 if (!MathHelper::NearZero(node->GetAspectRatio())) { 770 return; 771 } 772 const auto& sizeLimits = node->GetWindowUpdatedSizeLimits(); 773 if (sizeLimits.maxWidth_ == sizeLimits.minWidth_ && sizeLimits.maxHeight_ == sizeLimits.minHeight_) { 774 WLOGFD("window rect can not be changed"); 775 return; 776 } 777 if (winRect.height_ == 0) { 778 return; 779 } 780 float curRatio = static_cast<float>(winRect.width_) / static_cast<float>(winRect.height_); 781 if (sizeLimits.minRatio_ <= curRatio && curRatio <= sizeLimits.maxRatio_) { 782 WLOGFD("window ratio is satisfied with limit ratio, curRatio: %{public}f", curRatio); 783 return; 784 } 785 786 float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId()); 787 uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio); 788 Rect limitRect = (node->isShowingOnMultiDisplays_) ? displayGroupLimitRect_ : limitRectMap_[node->GetDisplayId()]; 789 int32_t limitMinPosX = limitRect.posX_ + static_cast<int32_t>(windowTitleBarH); 790 int32_t limitMaxPosX = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - windowTitleBarH); 791 int32_t limitMinPosY = limitRect.posY_; 792 int32_t limitMaxPosY = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - windowTitleBarH); 793 794 Rect dockWinRect; 795 DockWindowShowState dockShownState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect); 796 WLOGFD("dock window show type: %{public}u", dockShownState); 797 if (dockShownState == DockWindowShowState::SHOWN_IN_BOTTOM) { 798 limitMaxPosY = dockWinRect.posY_ - static_cast<int32_t>(windowTitleBarH); 799 } else if (dockShownState == DockWindowShowState::SHOWN_IN_LEFT) { 800 limitMinPosX = dockWinRect.posX_ + static_cast<int32_t>(dockWinRect.width_ + windowTitleBarH); 801 } else if (dockShownState == DockWindowShowState::SHOWN_IN_RIGHT) { 802 limitMaxPosX = dockWinRect.posX_ - static_cast<int32_t>(windowTitleBarH); 803 } 804 805 float newRatio = curRatio < sizeLimits.minRatio_ ? sizeLimits.minRatio_ : sizeLimits.maxRatio_; 806 if ((winRect.posX_ + static_cast<int32_t>(winRect.width_) == limitMinPosX) || (winRect.posX_ == limitMaxPosX)) { 807 // height can not be changed 808 if (sizeLimits.maxHeight_ == sizeLimits.minHeight_) { 809 return; 810 } 811 winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / newRatio); 812 } 813 814 if ((winRect.posY_ == limitMinPosY) || (winRect.posX_ == limitMaxPosY)) { 815 // width can not be changed 816 if (sizeLimits.maxWidth_ == sizeLimits.minWidth_) { 817 return; 818 } 819 winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) * newRatio); 820 } 821 WLOGFD("After limit by ratio if beyond limit region, winRect: %{public}d %{public}d %{public}u %{public}u", 822 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_); 823} 824 825void WindowLayoutPolicyCascade::UpdateFloatingWindowSizeBySizeLimits(const sptr<WindowNode>& node, 826 const Rect& displayRect, Rect& winRect) const 827{ 828 // get new limit config with the settings of system and app 829 const auto& sizeLimits = node->GetWindowUpdatedSizeLimits(); 830 831 // limit minimum size of floating or subWindow (not system type) window 832 if ((!WindowHelper::IsSystemWindow(node->GetWindowType()) && 833 (!WindowHelper::IsSubWindow(node->GetWindowType()))) || 834 node->GetWindowType() == WindowType::WINDOW_TYPE_FLOAT_CAMERA || 835 node->GetWindowType() == WindowType::WINDOW_TYPE_DIALOG) { 836 winRect.width_ = std::max(sizeLimits.minWidth_, winRect.width_); 837 winRect.height_ = std::max(sizeLimits.minHeight_, winRect.height_); 838 } 839 winRect.width_ = std::min(sizeLimits.maxWidth_, winRect.width_); 840 winRect.height_ = std::min(sizeLimits.maxHeight_, winRect.height_); 841 WLOGFD("After limit by size, winRect: %{public}d %{public}d %{public}u %{public}u", 842 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_); 843 844 // width and height can not be changed 845 if (sizeLimits.maxWidth_ == sizeLimits.minWidth_ && 846 sizeLimits.maxHeight_ == sizeLimits.minHeight_) { 847 winRect.width_ = sizeLimits.maxWidth_; 848 winRect.height_ = sizeLimits.maxHeight_; 849 WLOGFD("window rect can not be changed"); 850 return; 851 } 852 853 if (!MathHelper::NearZero(node->GetAspectRatio())) { 854 return; 855 } 856 float curRatio = static_cast<float>(winRect.width_) / static_cast<float>(winRect.height_); 857 // there is no need to fix size by ratio if this is not main floating window 858 if (!WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode()) || 859 (sizeLimits.minRatio_ <= curRatio && curRatio <= sizeLimits.maxRatio_)) { 860 WLOGFD("window is system window or ratio is satisfied with limits, curSize: [%{public}d, %{public}d], " 861 "curRatio: %{public}f", winRect.width_, winRect.height_, curRatio); 862 return; 863 } 864 865 float newRatio = curRatio < sizeLimits.minRatio_ ? sizeLimits.minRatio_ : sizeLimits.maxRatio_; 866 if (sizeLimits.maxWidth_ == sizeLimits.minWidth_) { 867 winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / newRatio); 868 return; 869 } 870 if (sizeLimits.maxHeight_ == sizeLimits.minHeight_) { 871 winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) * newRatio); 872 return; 873 } 874 875 auto dragType = node->GetDragType(); 876 if (dragType == DragType::DRAG_BOTTOM_OR_TOP) { 877 // if drag height, use height to fix size. 878 winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) * newRatio); 879 } else { 880 // if drag width or corner, use width to fix size. 881 winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / newRatio); 882 } 883 WLOGI("After limit by customize config, winRect: %{public}d %{public}d %{public}u %{public}u", 884 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_); 885} 886 887void WindowLayoutPolicyCascade::FixWindowRectWhenDrag(const sptr<WindowNode>& node, 888 const Rect& oriWinRect, Rect& winRect) const 889{ 890 // fix size in case of moving window when dragging 891 const auto& lastWinRect = node->GetWindowRect(); 892 if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG) { 893 if (oriWinRect.posX_ != lastWinRect.posX_) { 894 winRect.posX_ = oriWinRect.posX_ + static_cast<int32_t>(oriWinRect.width_) - 895 static_cast<int32_t>(winRect.width_); 896 } 897 if (oriWinRect.posY_ != lastWinRect.posY_) { 898 winRect.posY_ = oriWinRect.posY_ + static_cast<int32_t>(oriWinRect.height_) - 899 static_cast<int32_t>(winRect.height_); 900 } 901 } 902} 903 904void WindowLayoutPolicyCascade::LimitWindowPositionWhenDrag(const sptr<WindowNode>& node, Rect& winRect) const 905{ 906 float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId()); 907 uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio); 908 const Rect& lastRect = node->GetWindowRect(); 909 Rect oriWinRect = winRect; 910 911 Rect limitRect = (node->isShowingOnMultiDisplays_) ? displayGroupLimitRect_ : limitRectMap_[node->GetDisplayId()]; 912 int32_t limitMinPosX = limitRect.posX_ + static_cast<int32_t>(windowTitleBarH); 913 int32_t limitMaxPosX = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - windowTitleBarH); 914 int32_t limitMinPosY = limitRect.posY_; 915 int32_t limitMaxPosY = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - windowTitleBarH); 916 917 Rect dockWinRect; 918 DockWindowShowState dockShownState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect); 919 if (dockShownState == DockWindowShowState::SHOWN_IN_BOTTOM) { 920 limitMaxPosY = dockWinRect.posY_ - static_cast<int32_t>(windowTitleBarH); 921 } else if (dockShownState == DockWindowShowState::SHOWN_IN_LEFT) { 922 limitMinPosX = dockWinRect.posX_ + static_cast<int32_t>(dockWinRect.width_ + windowTitleBarH); 923 } else if (dockShownState == DockWindowShowState::SHOWN_IN_RIGHT) { 924 limitMaxPosX = dockWinRect.posX_ - static_cast<int32_t>(windowTitleBarH); 925 } 926 927 // limitMinPosX is minimum (x + width) 928 if (oriWinRect.posX_ + static_cast<int32_t>(oriWinRect.width_) < limitMinPosX) { 929 if (oriWinRect.width_ != lastRect.width_) { 930 winRect.width_ = static_cast<uint32_t>(limitMinPosX - oriWinRect.posX_); 931 } 932 } 933 // maximum position x 934 if (oriWinRect.posX_ > limitMaxPosX) { 935 winRect.posX_ = limitMaxPosX; 936 if (oriWinRect.width_ != lastRect.width_) { 937 winRect.width_ = static_cast<uint32_t>( 938 oriWinRect.posX_ + static_cast<int32_t>(oriWinRect.width_) - winRect.posX_); 939 } 940 } 941 // minimum position y 942 if (oriWinRect.posY_ < limitMinPosY) { 943 winRect.posY_ = limitMinPosY; 944 if (oriWinRect.height_ != lastRect.height_) { 945 winRect.height_ = static_cast<uint32_t>( 946 oriWinRect.posY_ + static_cast<int32_t>(oriWinRect.height_) - winRect.posY_); 947 } 948 } 949 // maximum position y 950 if (winRect.posY_ > limitMaxPosY) { 951 winRect.posY_ = limitMaxPosY; 952 if (oriWinRect.height_ != lastRect.height_) { 953 winRect.height_ = static_cast<uint32_t>( 954 oriWinRect.posY_ + static_cast<int32_t>(oriWinRect.height_) - winRect.posY_); 955 } 956 } 957 WLOGI("After limit by position, winRect: %{public}d %{public}d %{public}u %{public}u", 958 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_); 959} 960 961void WindowLayoutPolicyCascade::LimitWindowPositionWhenInitRectOrMove(const sptr<WindowNode>& node, Rect& winRect) const 962{ 963 float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId()); 964 uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio); 965 966 // if is cross-display window, the limit rect should be full limitRect 967 Rect limitRect = (node->isShowingOnMultiDisplays_) ? displayGroupLimitRect_ : limitRectMap_[node->GetDisplayId()]; 968 969 // limit position of the main floating window(window which support dragging) 970 if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) { 971 Rect dockWinRect; 972 DockWindowShowState dockShownState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect); 973 winRect.posY_ = std::max(limitRect.posY_, winRect.posY_); 974 winRect.posY_ = std::min(limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - windowTitleBarH), 975 winRect.posY_); 976 if (dockShownState == DockWindowShowState::SHOWN_IN_BOTTOM) { 977 WLOGFD("dock window show in bottom"); 978 winRect.posY_ = std::min(dockWinRect.posY_ - static_cast<int32_t>(windowTitleBarH), 979 winRect.posY_); 980 } 981 winRect.posX_ = std::max(limitRect.posX_ + static_cast<int32_t>(windowTitleBarH - winRect.width_), 982 winRect.posX_); 983 if (dockShownState == DockWindowShowState::SHOWN_IN_LEFT) { 984 WLOGFD("dock window show in left"); 985 winRect.posX_ = std::max(static_cast<int32_t>(dockWinRect.width_ + windowTitleBarH - winRect.width_), 986 winRect.posX_); 987 } 988 winRect.posX_ = std::min(limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - windowTitleBarH), 989 winRect.posX_); 990 if (dockShownState == DockWindowShowState::SHOWN_IN_RIGHT) { 991 WLOGFD("dock window show in right"); 992 winRect.posX_ = std::min(dockWinRect.posX_ - static_cast<int32_t>(windowTitleBarH), 993 winRect.posX_); 994 } 995 auto reason = node->GetWindowSizeChangeReason(); 996 // if init window on pc, limit position 997 if (floatingBottomPosY_ != 0 && reason == WindowSizeChangeReason::UNDEFINED) { 998 int32_t bottomPosY = static_cast<int32_t>(floatingBottomPosY_ * virtualPixelRatio); 999 if (winRect.posY_ + static_cast<int32_t>(winRect.height_) >= bottomPosY) { 1000 winRect.posY_ = limitRect.posY_; 1001 } 1002 } 1003 } 1004 WLOGI("After limit by position if init or move, winRect: %{public}d %{public}d %{public}u %{public}u", 1005 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_); 1006} 1007 1008void WindowLayoutPolicyCascade::GetMaximizeRect(const sptr<WindowNode>& node, Rect& maxRect) 1009{ 1010 auto property = node->GetWindowProperty(); 1011 if (property == nullptr) { 1012 WLOGFE("window property is nullptr."); 1013 return; 1014 } 1015 const auto& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(node->GetDisplayId()); 1016 const Rect& limitRect = limitRectMap_[node->GetDisplayId()]; 1017 Rect dockWinRect = { 0, 0, 0, 0 }; 1018 DockWindowShowState dockState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect); 1019 uint32_t dockHeight = dockState == DockWindowShowState::SHOWN_IN_BOTTOM ? dockWinRect.height_ : 0; 1020 maxRect.posX_ = limitRect.posX_; 1021 maxRect.posY_ = limitRect.posY_; 1022 maxRect.width_ = limitRect.width_; 1023 maxRect.height_ = displayRect.height_ - limitRect.posY_ - dockHeight; 1024 WLOGFI("GetMaximizeRect maxRect = %{public}d, %{public}d, %{public}u, %{public}u ", 1025 maxRect.posX_, maxRect.posY_, maxRect.width_, maxRect.height_); 1026} 1027} // Rosen 1028} // OHOS 1029