mirror of
https://github.com/openharmony/windowmanager.git
synced 2026-07-19 17:08:11 -04:00
8dfe22908a
Signed-off-by: l00574490 <liuqi149@huawei.com> Change-Id: I210656846119aaa4d9179f0d9cb9c70597f9909b
324 lines
13 KiB
C++
324 lines
13 KiB
C++
/*
|
|
* Copyright (c) 2022 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_tile.h"
|
|
#include <ability_manager_client.h>
|
|
#include "minimize_app.h"
|
|
#include "window_helper.h"
|
|
#include "window_inner_manager.h"
|
|
#include "window_manager_hilog.h"
|
|
#include "wm_trace.h"
|
|
|
|
namespace OHOS {
|
|
namespace Rosen {
|
|
namespace {
|
|
constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "WindowLayoutPolicyTile"};
|
|
constexpr uint32_t EDGE_INTERVAL = 48;
|
|
constexpr uint32_t MID_INTERVAL = 24;
|
|
}
|
|
|
|
WindowLayoutPolicyTile::WindowLayoutPolicyTile(const sptr<DisplayGroupInfo>& displayGroupInfo,
|
|
DisplayGroupWindowTree& displayGroupWindowTree)
|
|
: WindowLayoutPolicy(displayGroupInfo, displayGroupWindowTree)
|
|
{
|
|
for (auto& iter : displayGroupInfo_->GetAllDisplayRects()) {
|
|
maxTileWinNumMap_.insert(std::make_pair(iter.first, static_cast<uint32_t>(1)));
|
|
}
|
|
}
|
|
|
|
void WindowLayoutPolicyTile::Launch()
|
|
{
|
|
// compute limit rect
|
|
InitAllRects();
|
|
// select app min win in queue, and minimize others
|
|
InitForegroundNodeQueue();
|
|
for (auto& iter : displayGroupInfo_->GetAllDisplayRects()) {
|
|
DisplayId displayId = iter.first;
|
|
AssignNodePropertyForTileWindows(displayId);
|
|
LayoutForegroundNodeQueue(displayId);
|
|
auto& displayWindowTree = displayGroupWindowTree_[displayId];
|
|
LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::BELOW_WINDOW_NODE]));
|
|
}
|
|
WLOGFI("WindowLayoutPolicyTile::Launch");
|
|
}
|
|
|
|
void WindowLayoutPolicyTile::InitAllRects()
|
|
{
|
|
displayGroupLimitRect_ = displayGroupRect_;
|
|
for (auto& iter : displayGroupInfo_->GetAllDisplayRects()) {
|
|
DisplayId displayId = iter.first;
|
|
limitRectMap_[displayId] = iter.second;
|
|
auto& displayWindowTree = displayGroupWindowTree_[displayId];
|
|
LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::ABOVE_WINDOW_NODE]));
|
|
InitTileWindowRects(displayId);
|
|
}
|
|
}
|
|
|
|
uint32_t WindowLayoutPolicyTile::GetMaxTileWinNum(DisplayId displayId) const
|
|
{
|
|
float virtualPixelRatio = GetVirtualPixelRatio(displayId);
|
|
constexpr uint32_t half = 2;
|
|
uint32_t edgeIntervalVp = static_cast<uint32_t>(EDGE_INTERVAL * half * virtualPixelRatio);
|
|
uint32_t midIntervalVp = static_cast<uint32_t>(MID_INTERVAL * virtualPixelRatio);
|
|
uint32_t minFloatingW = IsVerticalDisplay(displayId) ? MIN_VERTICAL_FLOATING_WIDTH : MIN_VERTICAL_FLOATING_HEIGHT;
|
|
minFloatingW = static_cast<uint32_t>(minFloatingW * virtualPixelRatio);
|
|
uint32_t drawableW = limitRectMap_[displayId].width_ - edgeIntervalVp + midIntervalVp;
|
|
return static_cast<uint32_t>(drawableW / (minFloatingW + midIntervalVp));
|
|
}
|
|
|
|
void WindowLayoutPolicyTile::InitTileWindowRects(DisplayId displayId)
|
|
{
|
|
float virtualPixelRatio = GetVirtualPixelRatio(displayId);
|
|
uint32_t edgeIntervalVp = static_cast<uint32_t>(EDGE_INTERVAL * virtualPixelRatio);
|
|
uint32_t midIntervalVp = static_cast<uint32_t>(MID_INTERVAL * virtualPixelRatio);
|
|
|
|
constexpr float ratio = DEFAULT_ASPECT_RATIO;
|
|
const Rect& limitRect = limitRectMap_[displayId];
|
|
const Rect& displayRect = displayGroupInfo_->GetDisplayRect(displayId);
|
|
constexpr int half = 2;
|
|
maxTileWinNumMap_[displayId] = GetMaxTileWinNum(displayId);
|
|
WLOGFI("set max tile window num %{public}u", maxTileWinNumMap_[displayId]);
|
|
auto& presetRects = presetRectsMap_[displayId];
|
|
presetRects.clear();
|
|
uint32_t w = displayRect.width_ * ratio;
|
|
uint32_t h = displayRect.height_ * ratio;
|
|
w = w > limitRect.width_ ? limitRect.width_ : w;
|
|
h = h > limitRect.height_ ? limitRect.height_ : h;
|
|
int x = limitRect.posX_ + ((limitRect.width_ - w) / half);
|
|
int y = limitRect.posY_ + ((limitRect.height_ - h) / half);
|
|
|
|
std::vector<Rect> single = {{ x, y, w, h }};
|
|
presetRects.emplace_back(single);
|
|
for (uint32_t num = 2; num <= maxTileWinNumMap_[displayId]; num++) { // start calc preset with 2 windows
|
|
w = (limitRect.width_ - edgeIntervalVp * half - midIntervalVp * (num - 1)) / num;
|
|
std::vector<Rect> curLevel;
|
|
for (uint32_t i = 0; i < num; i++) {
|
|
int curX = limitRect.posX_ + edgeIntervalVp + i * (w + midIntervalVp);
|
|
Rect curRect = { curX, y, w, h };
|
|
WLOGFI("presetRects: level %{public}u, id %{public}u, [%{public}d %{public}d %{public}u %{public}u]",
|
|
num, i, curX, y, w, h);
|
|
curLevel.emplace_back(curRect);
|
|
}
|
|
presetRects.emplace_back(curLevel);
|
|
}
|
|
}
|
|
|
|
void WindowLayoutPolicyTile::AddWindowNode(const sptr<WindowNode>& node)
|
|
{
|
|
WM_FUNCTION_TRACE();
|
|
|
|
// update window size limits when add window
|
|
UpdateWindowSizeLimits(node);
|
|
|
|
if (WindowHelper::IsMainWindow(node->GetWindowType())) {
|
|
DisplayId displayId = node->GetDisplayId();
|
|
ForegroundNodeQueuePushBack(node, displayId);
|
|
AssignNodePropertyForTileWindows(displayId);
|
|
LayoutForegroundNodeQueue(displayId);
|
|
} else {
|
|
UpdateWindowNode(node); // currently, update and add do the same process
|
|
}
|
|
}
|
|
|
|
void WindowLayoutPolicyTile::UpdateWindowNode(const sptr<WindowNode>& node, bool isAddWindow)
|
|
{
|
|
WM_FUNCTION_TRACE();
|
|
WindowLayoutPolicy::UpdateWindowNode(node);
|
|
if (avoidTypes_.find(node->GetWindowType()) != avoidTypes_.end()) {
|
|
DisplayId displayId = node->GetDisplayId();
|
|
InitTileWindowRects(displayId);
|
|
AssignNodePropertyForTileWindows(displayId);
|
|
LayoutForegroundNodeQueue(displayId);
|
|
}
|
|
}
|
|
|
|
void WindowLayoutPolicyTile::RemoveWindowNode(const sptr<WindowNode>& node)
|
|
{
|
|
WM_FUNCTION_TRACE();
|
|
WLOGFI("RemoveWindowNode %{public}u in tile", node->GetWindowId());
|
|
auto type = node->GetWindowType();
|
|
auto displayId = node->GetDisplayId();
|
|
// affect other windows, trigger off global layout
|
|
if (avoidTypes_.find(type) != avoidTypes_.end()) {
|
|
LayoutWindowTree(displayId);
|
|
} else {
|
|
ForegroundNodeQueueRemove(node);
|
|
AssignNodePropertyForTileWindows(displayId);
|
|
LayoutForegroundNodeQueue(displayId);
|
|
}
|
|
Rect reqRect = node->GetRequestRect();
|
|
if (node->GetWindowToken()) {
|
|
node->GetWindowToken()->UpdateWindowRect(reqRect, node->GetDecoStatus(), WindowSizeChangeReason::HIDE);
|
|
}
|
|
}
|
|
|
|
void WindowLayoutPolicyTile::LayoutForegroundNodeQueue(DisplayId displayId)
|
|
{
|
|
for (auto& node : foregroundNodesMap_[displayId]) {
|
|
Rect winRect = node->GetRequestRect();
|
|
Rect lastRect = node->GetWindowRect();
|
|
node->SetWindowRect(winRect);
|
|
CalcAndSetNodeHotZone(winRect, node);
|
|
if (node->GetWindowToken()) {
|
|
node->GetWindowToken()->UpdateWindowRect(
|
|
winRect, node->GetDecoStatus(), node->GetWindowSizeChangeReason());
|
|
}
|
|
|
|
UpdateSurfaceBounds(node, winRect, lastRect);
|
|
for (auto& childNode : node->children_) {
|
|
LayoutWindowNode(childNode);
|
|
}
|
|
}
|
|
}
|
|
|
|
void WindowLayoutPolicyTile::InitForegroundNodeQueue()
|
|
{
|
|
for (auto& iter : displayGroupInfo_->GetAllDisplayRects()) {
|
|
DisplayId displayId = iter.first;
|
|
foregroundNodesMap_[displayId].clear();
|
|
const auto& appWindowNodes = *(displayGroupWindowTree_[displayId][WindowRootNodeType::APP_WINDOW_NODE]);
|
|
for (auto& node : appWindowNodes) {
|
|
if (WindowHelper::IsMainWindow(node->GetWindowType())) {
|
|
ForegroundNodeQueuePushBack(node, displayId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void WindowLayoutPolicyTile::ForegroundNodeQueuePushBack(const sptr<WindowNode>& node, DisplayId displayId)
|
|
{
|
|
if (node == nullptr) {
|
|
return;
|
|
}
|
|
auto& foregroundNodes = foregroundNodesMap_[displayId];
|
|
auto iter = std::find_if(foregroundNodes.begin(), foregroundNodes.end(),
|
|
[node](sptr<WindowNode> foregroundNode) {
|
|
return foregroundNode->GetWindowId() == node->GetWindowId();
|
|
});
|
|
if (iter != foregroundNodes.end()) {
|
|
return;
|
|
}
|
|
|
|
if (!WindowHelper::IsWindowModeSupported(node->GetModeSupportInfo(), WindowMode::WINDOW_MODE_FLOATING)) {
|
|
WLOGFD("window don't support tile mode, winId: %{public}d", node->GetWindowId());
|
|
MinimizeApp::AddNeedMinimizeApp(node, MinimizeReason::LAYOUT_TILE);
|
|
return;
|
|
}
|
|
WLOGFI("add win in tile, displayId: %{public}" PRIu64", winId: %{public}d", displayId, node->GetWindowId());
|
|
while (foregroundNodes.size() >= maxTileWinNumMap_[displayId]) {
|
|
auto removeNode = foregroundNodes.front();
|
|
foregroundNodes.pop_front();
|
|
WLOGFI("pop win in queue head for add new win, windowId: %{public}d", removeNode->GetWindowId());
|
|
MinimizeApp::AddNeedMinimizeApp(removeNode, MinimizeReason::LAYOUT_TILE);
|
|
}
|
|
foregroundNodes.push_back(node);
|
|
}
|
|
|
|
void WindowLayoutPolicyTile::ForegroundNodeQueueRemove(const sptr<WindowNode>& node)
|
|
{
|
|
if (node == nullptr) {
|
|
return;
|
|
}
|
|
DisplayId displayId = node->GetDisplayId();
|
|
auto& foregroundNodes = foregroundNodesMap_[displayId];
|
|
auto iter = std::find(foregroundNodes.begin(), foregroundNodes.end(), node);
|
|
if (iter != foregroundNodes.end()) {
|
|
WLOGFI("remove win in tile for win id: %{public}d", node->GetWindowId());
|
|
foregroundNodes.erase(iter);
|
|
}
|
|
}
|
|
|
|
void WindowLayoutPolicyTile::AssignNodePropertyForTileWindows(DisplayId displayId)
|
|
{
|
|
// set rect for foreground windows
|
|
uint32_t num = foregroundNodesMap_[displayId].size();
|
|
auto& presetRects = presetRectsMap_[displayId];
|
|
if (num > maxTileWinNumMap_[displayId] || num > presetRects.size() || num == 0) {
|
|
WLOGE("invalid tile queue");
|
|
return;
|
|
}
|
|
std::vector<Rect>& presetRect = presetRects[num - 1];
|
|
if (presetRect.size() != num) {
|
|
WLOGE("invalid preset rects");
|
|
return;
|
|
}
|
|
auto rectIt = presetRect.begin();
|
|
for (auto node : foregroundNodesMap_[displayId]) {
|
|
auto& rect = (*rectIt);
|
|
if (WindowHelper::IsWindowModeSupported(node->GetModeSupportInfo(), WindowMode::WINDOW_MODE_FLOATING) &&
|
|
WindowHelper::IsRectSatisfiedWithSizeLimits(rect, node->GetWindowSizeLimits())) {
|
|
node->SetWindowMode(WindowMode::WINDOW_MODE_FLOATING);
|
|
if (node->GetWindowToken()) {
|
|
node->GetWindowToken()->UpdateWindowMode(WindowMode::WINDOW_MODE_FLOATING);
|
|
}
|
|
node->SetRequestRect(rect);
|
|
node->SetDecoStatus(true);
|
|
WLOGFI("set rect for qwin id: %{public}d [%{public}d %{public}d %{public}d %{public}d]",
|
|
node->GetWindowId(), rect.posX_, rect.posY_, rect.width_, rect.height_);
|
|
rectIt++;
|
|
} else {
|
|
MinimizeApp::AddNeedMinimizeApp(node, MinimizeReason::LAYOUT_TILE);
|
|
}
|
|
}
|
|
}
|
|
|
|
void WindowLayoutPolicyTile::UpdateLayoutRect(const sptr<WindowNode>& node)
|
|
{
|
|
auto type = node->GetWindowType();
|
|
auto mode = node->GetWindowMode();
|
|
auto flags = node->GetWindowFlags();
|
|
auto property = node->GetWindowProperty();
|
|
if (property == nullptr) {
|
|
WLOGFE("window property is nullptr.");
|
|
return;
|
|
}
|
|
auto decorEnable = property->GetDecorEnable();
|
|
bool needAvoid = (flags & static_cast<uint32_t>(WindowFlag::WINDOW_FLAG_NEED_AVOID));
|
|
bool parentLimit = (flags & static_cast<uint32_t>(WindowFlag::WINDOW_FLAG_PARENT_LIMIT));
|
|
bool subWindow = WindowHelper::IsSubWindow(type);
|
|
bool floatingWindow = (mode == WindowMode::WINDOW_MODE_FLOATING);
|
|
const Rect lastRect = node->GetWindowRect();
|
|
Rect limitRect = displayGroupInfo_->GetDisplayRect(node->GetDisplayId());
|
|
ComputeDecoratedRequestRect(node);
|
|
Rect winRect = node->GetRequestRect();
|
|
|
|
WLOGFI("Id:%{public}u, avoid:%{public}d parLimit:%{public}d floating:%{public}d, sub:%{public}d, " \
|
|
"deco:%{public}d, type:%{public}u, requestRect:[%{public}d, %{public}d, %{public}u, %{public}u]",
|
|
node->GetWindowId(), needAvoid, parentLimit, floatingWindow, subWindow, decorEnable,
|
|
static_cast<uint32_t>(type), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
|
|
if (needAvoid) {
|
|
limitRect = limitRectMap_[node->GetDisplayId()];
|
|
}
|
|
|
|
if (!floatingWindow) { // fullscreen window
|
|
winRect = limitRect;
|
|
} else { // floating window
|
|
if (subWindow && parentLimit) { // subwindow and limited by parent
|
|
limitRect = node->parent_->GetWindowRect();
|
|
UpdateFloatingLayoutRect(limitRect, winRect);
|
|
}
|
|
}
|
|
|
|
LimitFloatingWindowSize(node, displayGroupInfo_->GetDisplayRect(node->GetDisplayId()), winRect);
|
|
LimitMainFloatingWindowPosition(node, winRect);
|
|
|
|
node->SetWindowRect(winRect);
|
|
CalcAndSetNodeHotZone(winRect, node);
|
|
UpdateClientRectAndResetReason(node, lastRect, winRect);
|
|
UpdateSurfaceBounds(node, winRect, lastRect);
|
|
}
|
|
} // Rosen
|
|
} // OHOS
|