dde-dock/frame/item/components/previewcontainer.cpp
songwentao 695a1c32a7 fix: 修复点击预览窗口,屏幕键盘失去焦点问题
修改背景: 任务栏该模块代码很久未做改动,本地发现该问题仅在wayland下出现,问题已与窗管对接沟通过,根据窗管建议,上层进
规避,避免因底层强行修改引入新的问题
修复方式: 在wanland下,预览时点击之前取消预览,然后再激活窗口,进行规避

Log: 修复点击预览窗口,键盘失去焦点的问题
Influence: 任务栏-点击预览窗口,任务栏操作正常
Bug: https://pms.uniontech.com/bug-view-159303.html
2022-09-19 13:16:10 +08:00

315 lines
9.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// SPDX-FileCopyrightText: 2011 - 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "previewcontainer.h"
#include "imageutil.h"
#include "utils.h"
#include <QDesktopWidget>
#include <QScreen>
#include <QApplication>
#include <QDragEnterEvent>
#include <QDesktopWidget>
#include <QCursor>
#include <QGSettings>
#define SPACING 0
#define MARGIN 0
#define SNAP_HEIGHT_WITHOUT_COMPOSITE 30
PreviewContainer::PreviewContainer(QWidget *parent)
: QWidget(parent)
, m_needActivate(false)
, m_floatingPreview(new FloatingPreview(this))
, m_mouseLeaveTimer(new QTimer(this))
, m_wmHelper(DWindowManagerHelper::instance())
, m_titleMode(HoverShow)
{
m_windowListLayout = new QBoxLayout(QBoxLayout::LeftToRight, this);
m_windowListLayout->setSpacing(SPACING);
m_windowListLayout->setContentsMargins(MARGIN, MARGIN, MARGIN, MARGIN);
m_mouseLeaveTimer->setSingleShot(true);
m_mouseLeaveTimer->setInterval(300);
m_floatingPreview->setVisible(false);
m_waitForShowPreviewTimer = new QTimer(this);
m_waitForShowPreviewTimer->setSingleShot(true);
m_waitForShowPreviewTimer->setInterval(200);
setAcceptDrops(true);
setFixedSize(SNAP_WIDTH, SNAP_HEIGHT);
connect(m_mouseLeaveTimer, &QTimer::timeout, this, &PreviewContainer::checkMouseLeave, Qt::QueuedConnection);
connect(m_waitForShowPreviewTimer, &QTimer::timeout, this, &PreviewContainer::previewFloating);
}
void PreviewContainer::setWindowInfos(const WindowInfoMap &infos, const WindowList &allowClose)
{
// check removed window
for (auto it(m_snapshots.begin()); it != m_snapshots.end();) {
//初始化预览界面边距
it.value()->setContentsMargins(0, 0, 0, 0);
if (!infos.contains(it.key())) {
m_windowListLayout->removeWidget(it.value());
it.value()->deleteLater();
it = m_snapshots.erase(it);
} else {
++it;
}
}
for (auto it(infos.cbegin()); it != infos.cend(); ++it) {
const WId key = it.key();
if (!m_snapshots.contains(key))
appendSnapWidget(key);
m_snapshots[key]->setWindowInfo(it.value());
m_snapshots[key]->setCloseAble(allowClose.contains(key));
}
if (m_snapshots.isEmpty()) {
emit requestCancelPreviewWindow();
emit requestHidePopup();
}
adjustSize(m_wmHelper->hasComposite());
}
void PreviewContainer::setTitleDisplayMode(int mode)
{
m_titleMode = static_cast<TitleDisplayMode>(mode);
if (!m_wmHelper->hasComposite())
return;
m_floatingPreview->setFloatingTitleVisible(m_titleMode == HoverShow);
for (AppSnapshot *snap : m_snapshots) {
snap->setTitleVisible(m_titleMode == AlwaysShow);
}
}
void PreviewContainer::updateLayoutDirection(const Dock::Position dockPos)
{
if (m_wmHelper->hasComposite() && (dockPos == Dock::Top || dockPos == Dock::Bottom))
m_windowListLayout->setDirection(QBoxLayout::LeftToRight);
else
m_windowListLayout->setDirection(QBoxLayout::TopToBottom);
adjustSize(m_wmHelper->hasComposite());
}
void PreviewContainer::checkMouseLeave()
{
const bool hover = underMouse();
if (hover)
return;
m_floatingPreview->setVisible(false);
if (m_wmHelper->hasComposite()) {
if (m_needActivate) {
m_needActivate = false;
emit requestActivateWindow(m_floatingPreview->trackedWid());
} else {
Q_EMIT requestHidePopup();
emit requestCancelPreviewWindow();
}
}
emit requestHidePopup();
}
void PreviewContainer::prepareHide()
{
m_mouseLeaveTimer->start();
}
void PreviewContainer::adjustSize(bool composite)
{
int count = m_snapshots.size();
const int screenWidth = QDesktopWidget().screenGeometry(this).width();
const int screenHeight = QDesktopWidget().screenGeometry(this).height();
//先根据屏幕宽高计算出能预览的最大数量,然后根据数量计算界面宽高
if (composite) {
// 3D
const int padding = 20;
const bool horizontal = m_windowListLayout->direction() == QBoxLayout::LeftToRight;
if (horizontal) {
count = qMin(count, screenWidth * 2 / SNAP_WIDTH);
const int h = SNAP_HEIGHT + MARGIN * 2;
const int w = SNAP_WIDTH * count + MARGIN * 2 + SPACING * (count - 1);
setFixedHeight(h);
setFixedWidth(qMin(w, screenWidth - padding));
} else {
count = qMin(count, screenWidth * 2 / SNAP_HEIGHT);
const int w = SNAP_WIDTH + MARGIN * 2;
const int h = SNAP_HEIGHT * count + MARGIN * 2 + SPACING * (count - 1);
setFixedWidth(w);
setFixedHeight(qMin(h, screenHeight - padding));
}
} else if (m_windowListLayout->count()) {
// 2D
count = qMin(count, screenWidth / SNAP_HEIGHT_WITHOUT_COMPOSITE);
const int h = SNAP_HEIGHT_WITHOUT_COMPOSITE * count + MARGIN * 2 + SPACING * (count - 1);
auto appSnapshot = static_cast<AppSnapshot *>(m_windowListLayout->itemAt(0)->widget());
auto font = appSnapshot->layout()->itemAt(0)->widget()->font();
QFontMetrics fontMetrics(font);
// 获取 appitem title 的最大宽度
int titleWidth = fontMetrics.boundingRect(appSnapshot->title()).width();
for (int i = 0; i < m_windowListLayout->count(); i++) {
auto otherWidget = static_cast<AppSnapshot *>(m_windowListLayout->itemAt(i)->widget());
titleWidth = qMax(titleWidth, fontMetrics.boundingRect(otherWidget->title()).width());
}
// 关闭按键的宽度和边缘间距的和,调整标题居中
const int closeBtnMargin = 2 * (SNAP_CLOSE_BTN_WIDTH + SNAP_CLOSE_BTN_MARGIN);
if (titleWidth < SNAP_WIDTH - closeBtnMargin)
setFixedSize(titleWidth + closeBtnMargin, h);
else
setFixedSize(SNAP_WIDTH, h);
}
//根据计算的数量,将相应的预览界面添加到布局并显示,其他的暂时不添加,减少界面刷新次数
int i = 0;
for (AppSnapshot *snap : m_snapshots) {
if (i < count && m_windowListLayout->indexOf(snap) < 0 ) {
m_windowListLayout->addWidget(snap);
}
snap->setVisible(i < count);
i++;
}
}
void PreviewContainer::appendSnapWidget(const WId wid)
{
//创建预览界面,默认不显示,等计算出显示数量后再加入布局并显示
AppSnapshot *snap = new AppSnapshot(wid);
snap->setVisible(false);
connect(snap, &AppSnapshot::clicked, this, &PreviewContainer::onSnapshotClicked, Qt::QueuedConnection);
connect(snap, &AppSnapshot::entered, this, &PreviewContainer::previewEntered, Qt::QueuedConnection);
connect(snap, &AppSnapshot::requestCheckWindow, this, &PreviewContainer::requestCheckWindows, Qt::QueuedConnection);
connect(snap, &AppSnapshot::requestCloseAppSnapshot, this, &PreviewContainer::onRequestCloseAppSnapshot);
m_snapshots.insert(wid, snap);
}
void PreviewContainer::enterEvent(QEvent *e)
{
if (Utils::IS_WAYLAND_DISPLAY) {
Utils::updateCursor(this);
}
QWidget::enterEvent(e);
m_needActivate = false;
m_mouseLeaveTimer->stop();
if (m_wmHelper->hasComposite()) {
m_waitForShowPreviewTimer->start();
}
}
void PreviewContainer::leaveEvent(QEvent *e)
{
QWidget::leaveEvent(e);
m_mouseLeaveTimer->start();
m_waitForShowPreviewTimer->stop();
}
void PreviewContainer::dragEnterEvent(QDragEnterEvent *e)
{
if (!m_wmHelper->hasComposite())
return;
e->accept();
m_needActivate = false;
m_mouseLeaveTimer->stop();
}
void PreviewContainer::dragLeaveEvent(QDragLeaveEvent *e)
{
e->ignore();
m_needActivate = true;
m_mouseLeaveTimer->start();
}
void PreviewContainer::onSnapshotClicked(const WId wid)
{
if (Utils::IS_WAYLAND_DISPLAY) {
/* BUGFIX-159303 本地发现该问题仅在wayland下出现问题已与窗管对接沟通过根据窗管建议上层进
规避,避免因底层强行修改引入新的问题 */
Q_EMIT requestCancelPreviewWindow();
}
Q_EMIT requestActivateWindow(wid);
m_needActivate = true;
m_waitForShowPreviewTimer->stop();
requestHidePopup();
}
void PreviewContainer::previewEntered(const WId wid)
{
if (!m_wmHelper->hasComposite())
return;
AppSnapshot *snap = static_cast<AppSnapshot *>(sender());
if (!snap) {
return;
}
snap->setContentsMargins(100, 0, 100, 0);
AppSnapshot *preSnap = m_floatingPreview->trackedWindow();
if (preSnap && preSnap != snap) {
preSnap->setContentsMargins(0, 0, 0, 0);
preSnap->setWindowState();
}
m_currentWId = wid;
m_floatingPreview->trackWindow(snap);
if (m_waitForShowPreviewTimer->isActive()) {
return;
}
previewFloating();
}
void PreviewContainer::previewFloating()
{
if (!m_waitForShowPreviewTimer->isActive()) {
m_floatingPreview->setVisible(true);
m_floatingPreview->raise();
requestPreviewWindow(m_currentWId);
}
return;
}
void PreviewContainer::onRequestCloseAppSnapshot()
{
if (!m_wmHelper->hasComposite())
return ;
if (m_snapshots.keys().isEmpty()) {
Q_EMIT requestHidePopup();
Q_EMIT requestCancelPreviewWindow();
}
}