dde-dock/frame/window/mainwindow.cpp
范朋程 883c74f479 fix: 修复一处任务栏显示异常的问题
windowSizeFashion和windowSizeEfficient给出的值始终对应前端认为的界面高度或宽度.举例:当前缩放为2时,任务栏为高效模式,windowSizeEfficient对应值为50,那么任务栏显示的高度应该为50*2个像素

Log: 修复一处任务栏显示异常的问题
Task: https://pms.uniontech.com/zentao/task-view-36233.html
Change-Id: I1986ca9d1b0d6fad67186c9bad210a54f153095b
Reviewed-on: http://gerrit.uniontech.com/c/dde-dock/+/3301
Reviewed-by: <mailman@uniontech.com>
Reviewed-by: wangwei <wangwei@uniontech.com>
Reviewed-by: niecheng <niecheng@uniontech.com>
Tested-by: <mailman@uniontech.com>
2020-09-03 13:37:10 +08:00

483 lines
17 KiB
C++
Executable File
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.

/*
* Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
*
* Author: sbw <sbw@sbw.so>
*
* Maintainer: sbw <sbw@sbw.so>
* zhaolong <zhaolong@uniontech.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mainwindow.h"
#include "panel/mainpanelcontrol.h"
#include "controller/dockitemmanager.h"
#include "util/utils.h"
#include "util/menuworker.h"
#include <DStyle>
#include <DPlatformWindowHandle>
#include <QDebug>
#include <QEvent>
#include <QResizeEvent>
#include <QScreen>
#include <QGuiApplication>
#include <QX11Info>
#include <qpa/qplatformwindow.h>
#include <QGSettings>
#include <X11/X.h>
#include <X11/Xutil.h>
#include <com_deepin_dde_daemon_dock.h>
#define SNI_WATCHER_SERVICE "org.kde.StatusNotifierWatcher"
#define SNI_WATCHER_PATH "/StatusNotifierWatcher"
#define MAINWINDOW_MAX_SIZE DOCK_MAX_SIZE
#define MAINWINDOW_MIN_SIZE (40)
#define DRAG_AREA_SIZE (5)
using org::kde::StatusNotifierWatcher;
using DBusDock = com::deepin::dde::daemon::Dock;
const QPoint rawXPosition(const QPoint &scaledPos)
{
QScreen const *screen = Utils::screenAtByScaled(scaledPos);
return screen ? screen->geometry().topLeft() +
(scaledPos - screen->geometry().topLeft()) *
screen->devicePixelRatio()
: scaledPos;
}
const QPoint scaledPos(const QPoint &rawXPos)
{
QScreen const *screen = Utils::screenAt(rawXPos);
return screen
? screen->geometry().topLeft() +
(rawXPos - screen->geometry().topLeft()) / screen->devicePixelRatio()
: rawXPos;
}
MainWindow::MainWindow(QWidget *parent)
: DBlurEffectWidget(parent)
, m_mainPanel(new MainPanelControl(this))
, m_platformWindowHandle(this)
, m_wmHelper(DWindowManagerHelper::instance())
, m_multiScreenWorker(new MultiScreenWorker(this, m_wmHelper))
, m_menuWorker(new MenuWorker(m_multiScreenWorker->dockInter(), this))
, m_shadowMaskOptimizeTimer(new QTimer(this))
, m_dbusDaemonInterface(QDBusConnection::sessionBus().interface())
, m_sniWatcher(new StatusNotifierWatcher(SNI_WATCHER_SERVICE, SNI_WATCHER_PATH, QDBusConnection::sessionBus(), this))
, m_dragWidget(new DragWidget(this))
, m_launched(false)
{
setAccessibleName("mainwindow");
m_mainPanel->setAccessibleName("mainpanel");
setAttribute(Qt::WA_TranslucentBackground);
setMouseTracking(true);
setAcceptDrops(true);
DPlatformWindowHandle::enableDXcbForWindow(this, true);
m_platformWindowHandle.setEnableBlurWindow(true);
m_platformWindowHandle.setTranslucentBackground(true);
m_platformWindowHandle.setWindowRadius(0);
m_platformWindowHandle.setShadowOffset(QPoint(0, 5));
m_platformWindowHandle.setShadowColor(QColor(0, 0, 0, 0.3 * 255));
m_mainPanel->setDisplayMode(m_multiScreenWorker->displayMode());
initSNIHost();
initComponents();
initConnections();
resetDragWindow();
m_mainPanel->setDelegate(this);
for (auto item : DockItemManager::instance()->itemList())
m_mainPanel->insertItem(-1, item);
m_dragWidget->setMouseTracking(true);
m_dragWidget->setFocusPolicy(Qt::NoFocus);
if ((Top == m_multiScreenWorker->position()) || (Bottom == m_multiScreenWorker->position())) {
m_dragWidget->setCursor(Qt::SizeVerCursor);
} else {
m_dragWidget->setCursor(Qt::SizeHorCursor);
}
}
MainWindow::~MainWindow()
{
}
void MainWindow::launch()
{
m_launched = true;
qApp->processEvents();
setVisible(true);
m_multiScreenWorker->initShow();
m_shadowMaskOptimizeTimer->start();
}
void MainWindow::showEvent(QShowEvent *e)
{
QWidget::showEvent(e);
// connect(qGuiApp, &QGuiApplication::primaryScreenChanged,
// windowHandle(), [this](QScreen * new_screen) {
// QScreen *old_screen = windowHandle()->screen();
// windowHandle()->setScreen(new_screen);
// // 屏幕变化后可能导致控件缩放比变化,此时应该重设控件位置大小
// // 比如:窗口大小为 100 x 100, 显示在缩放比为 1.0 的屏幕上,此时窗口的真实大小 = 100x100
// // 随后窗口被移动到了缩放比为 2.0 的屏幕上,应该将真实大小改为 200x200。另外只能使用
// // QPlatformWindow直接设置大小来绕过QWidget和QWindow对新旧geometry的比较。
// const qreal scale = devicePixelRatioF();
// const QPoint screenPos = new_screen->geometry().topLeft();
// const QPoint posInScreen = this->pos() - old_screen->geometry().topLeft();
// const QPoint pos = screenPos + posInScreen * scale;
// const QSize size = this->size() * scale;
// windowHandle()->handle()->setGeometry(QRect(pos, size));
// }, Qt::UniqueConnection);
// windowHandle()->setScreen(qGuiApp->primaryScreen());
}
void MainWindow::mousePressEvent(QMouseEvent *e)
{
e->ignore();
if (e->button() == Qt::RightButton && m_menuWorker->menuEnable()) {
m_menuWorker->showDockSettingsMenu();
return;
}
}
void MainWindow::keyPressEvent(QKeyEvent *e)
{
switch (e->key()) {
#ifdef QT_DEBUG
case Qt::Key_Escape: qApp->quit(); break;
#endif
default:;
}
}
void MainWindow::enterEvent(QEvent *e)
{
QWidget::enterEvent(e);
if (QApplication::overrideCursor() && QApplication::overrideCursor()->shape() != Qt::ArrowCursor)
QApplication::restoreOverrideCursor();
}
void MainWindow::mouseMoveEvent(QMouseEvent *e)
{
Q_UNUSED(e);
//重写mouseMoveEvent 解决bug12866 leaveEvent事件失效
}
void MainWindow::moveEvent(QMoveEvent *event)
{
Q_UNUSED(event);
}
void MainWindow::resizeEvent(QResizeEvent *event)
{
adjustShadowMask();
return DBlurEffectWidget::resizeEvent(event);
}
void MainWindow::dragEnterEvent(QDragEnterEvent *e)
{
QWidget::dragEnterEvent(e);
}
void MainWindow::initSNIHost()
{
// registor dock as SNI Host on dbus
QDBusConnection dbusConn = QDBusConnection::sessionBus();
m_sniHostService = QString("org.kde.StatusNotifierHost-") + QString::number(qApp->applicationPid());
dbusConn.registerService(m_sniHostService);
dbusConn.registerObject("/StatusNotifierHost", this);
if (m_sniWatcher->isValid()) {
m_sniWatcher->RegisterStatusNotifierHost(m_sniHostService);
} else {
qDebug() << SNI_WATCHER_SERVICE << "SNI watcher daemon is not exist for now!";
}
}
void MainWindow::initComponents()
{
m_shadowMaskOptimizeTimer->setSingleShot(true);
m_shadowMaskOptimizeTimer->setInterval(100);
QTimer::singleShot(1, this, &MainWindow::compositeChanged);
themeTypeChanged(DGuiApplicationHelper::instance()->themeType());
}
void MainWindow::compositeChanged()
{
const bool composite = m_wmHelper->hasComposite();
setComposite(composite);
m_shadowMaskOptimizeTimer->start();
}
void MainWindow::initConnections()
{
connect(m_shadowMaskOptimizeTimer, &QTimer::timeout, this, &MainWindow::adjustShadowMask, Qt::QueuedConnection);
connect(m_wmHelper, &DWindowManagerHelper::hasCompositeChanged, this, &MainWindow::compositeChanged, Qt::QueuedConnection);
connect(&m_platformWindowHandle, &DPlatformWindowHandle::frameMarginsChanged, m_shadowMaskOptimizeTimer, static_cast<void (QTimer::*)()>(&QTimer::start));
connect(m_dbusDaemonInterface, &QDBusConnectionInterface::serviceOwnerChanged, this, &MainWindow::onDbusNameOwnerChanged);
connect(DockItemManager::instance(), &DockItemManager::itemInserted, m_mainPanel, &MainPanelControl::insertItem, Qt::DirectConnection);
connect(DockItemManager::instance(), &DockItemManager::itemRemoved, m_mainPanel, &MainPanelControl::removeItem, Qt::DirectConnection);
connect(DockItemManager::instance(), &DockItemManager::itemUpdated, m_mainPanel, &MainPanelControl::itemUpdated, Qt::DirectConnection);
connect(DockItemManager::instance(), &DockItemManager::requestWindowAutoHide, m_menuWorker, &MenuWorker::setAutoHide);
connect(m_mainPanel, &MainPanelControl::itemMoved, DockItemManager::instance(), &DockItemManager::itemMoved, Qt::DirectConnection);
connect(m_mainPanel, &MainPanelControl::itemAdded, DockItemManager::instance(), &DockItemManager::itemAdded, Qt::DirectConnection);
connect(m_dragWidget, &DragWidget::dragPointOffset, m_multiScreenWorker, [ = ] {m_multiScreenWorker->onDragStateChanged(true);});
connect(m_dragWidget, &DragWidget::dragFinished, m_multiScreenWorker, [ = ] {m_multiScreenWorker->onDragStateChanged(false);});
connect(m_dragWidget, &DragWidget::dragPointOffset, this, &MainWindow::onMainWindowSizeChanged);
connect(m_dragWidget, &DragWidget::dragFinished, this, &MainWindow::onDragFinished);
connect(m_dragWidget, &DragWidget::dragFinished, m_multiScreenWorker, [this]{
const QRect &dockRect = m_multiScreenWorker->dockRect(m_multiScreenWorker->deskScreen()
, m_multiScreenWorker->position()
, HideMode::KeepShowing
, m_multiScreenWorker->displayMode());
m_multiScreenWorker->updateTouchRegisterRegion(dockRect);
});
connect(DGuiApplicationHelper::instance(), &DGuiApplicationHelper::themeTypeChanged, this, &MainWindow::themeTypeChanged);
connect(m_menuWorker, &MenuWorker::trayCountChanged, this, &MainWindow::getTrayVisableItemCount, Qt::DirectConnection);
connect(m_menuWorker, &MenuWorker::autoHideChanged, m_multiScreenWorker, &MultiScreenWorker::onAutoHideChanged);
connect(m_multiScreenWorker, &MultiScreenWorker::opacityChanged, this, &MainWindow::setMaskAlpha, Qt::QueuedConnection);
connect(m_multiScreenWorker, &MultiScreenWorker::displayModeChanegd, this, &MainWindow::adjustShadowMask, Qt::QueuedConnection);
// 更新拖拽区域
connect(m_multiScreenWorker, &MultiScreenWorker::requestUpdateDragArea, this, &MainWindow::resetDragWindow);
// 响应后端触控屏拖拽任务栏高度长按信号
connect(TouchSignalManager::instance(), &TouchSignalManager::middleTouchPress, this, &MainWindow::touchRequestResizeDock);
}
void MainWindow::getTrayVisableItemCount()
{
m_mainPanel->getTrayVisableItemCount();
}
void MainWindow::adjustShadowMask()
{
if (!m_launched)
return;
if (m_shadowMaskOptimizeTimer->isActive())
return;
const bool composite = m_wmHelper->hasComposite();
const bool isFasion = m_multiScreenWorker->displayMode() == Fashion;
DStyleHelper dstyle(style());
const int radius = dstyle.pixelMetric(DStyle::PM_TopLevelWindowRadius);
int newRadius = composite && isFasion ? radius : 0;
m_platformWindowHandle.setWindowRadius(newRadius);
QPainterPath clipPath;
clipPath.addRect(QRect(QPoint(0, 0), this->geometry().size()));
m_platformWindowHandle.setClipPath(newRadius != 0 ? QPainterPath() : clipPath);
}
void MainWindow::onDbusNameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner)
{
Q_UNUSED(oldOwner);
if (name == SNI_WATCHER_SERVICE && !newOwner.isEmpty()) {
qDebug() << SNI_WATCHER_SERVICE << "SNI watcher daemon started, register dock to watcher as SNI Host";
m_sniWatcher->RegisterStatusNotifierHost(m_sniHostService);
}
}
void MainWindow::setEffectEnabled(const bool enabled)
{
setMaskColor(AutoColor);
setMaskAlpha(m_multiScreenWorker->opacity());
m_platformWindowHandle.setBorderWidth(enabled ? 1 : 0);
}
void MainWindow::setComposite(const bool hasComposite)
{
setEffectEnabled(hasComposite);
}
bool MainWindow::appIsOnDock(const QString &appDesktop)
{
return DockItemManager::instance()->appIsOnDock(appDesktop);
}
void MainWindow::resetDragWindow()
{
int dockSize = 0;
switch (m_multiScreenWorker->position()) {
case Dock::Top:
m_dragWidget->setGeometry(0, height() - DRAG_AREA_SIZE, width(), DRAG_AREA_SIZE);
break;
case Dock::Bottom:
m_dragWidget->setGeometry(0, 0, width(), DRAG_AREA_SIZE);
break;
case Dock::Left:
m_dragWidget->setGeometry(width() - DRAG_AREA_SIZE, 0, DRAG_AREA_SIZE, height());
break;
case Dock::Right:
m_dragWidget->setGeometry(0, 0, DRAG_AREA_SIZE, height());
break;
}
if (m_multiScreenWorker->position() == Position::Left
|| m_multiScreenWorker->position() == Position::Right) {
dockSize = this->width();
} else {
dockSize = this->height();
}
// 通知窗管和后端更新数据
m_multiScreenWorker->updateDaemonDockSize(dockSize); // 1.先更新任务栏高度
m_multiScreenWorker->requestUpdateFrontendGeometry(); // 2.再更新任务栏位置,保证先1再2
m_multiScreenWorker->requestNotifyWindowManager();
if ((Top == m_multiScreenWorker->position()) || (Bottom == m_multiScreenWorker->position())) {
m_dragWidget->setCursor(Qt::SizeVerCursor);
} else {
m_dragWidget->setCursor(Qt::SizeHorCursor);
}
}
void MainWindow::onMainWindowSizeChanged(QPoint offset)
{
const QRect &rect = m_multiScreenWorker->dockRect(m_multiScreenWorker->deskScreen()
, m_multiScreenWorker->position()
, HideMode::KeepShowing,
m_multiScreenWorker->displayMode());
QRect newRect;
switch (m_multiScreenWorker->position()) {
case Top: {
newRect.setX(rect.x());
newRect.setY(rect.y());
newRect.setWidth(rect.width());
newRect.setHeight(qBound(MAINWINDOW_MIN_SIZE, rect.height() + offset.y(), MAINWINDOW_MAX_SIZE));
}
break;
case Bottom: {
newRect.setX(rect.x());
newRect.setY(rect.y() + rect.height() - qBound(MAINWINDOW_MIN_SIZE, rect.height() - offset.y(), MAINWINDOW_MAX_SIZE));
newRect.setWidth(rect.width());
newRect.setHeight(qBound(MAINWINDOW_MIN_SIZE, rect.height() - offset.y(), MAINWINDOW_MAX_SIZE ));
}
break;
case Left: {
newRect.setX(rect.x());
newRect.setY(rect.y());
newRect.setWidth(qBound(MAINWINDOW_MIN_SIZE, rect.width() + offset.x(), MAINWINDOW_MAX_SIZE));
newRect.setHeight(rect.height());
}
break;
case Right: {
newRect.setX(rect.x() + rect.width() - qBound(MAINWINDOW_MIN_SIZE, rect.width() - offset.x(), MAINWINDOW_MAX_SIZE));
newRect.setY(rect.y());
newRect.setWidth(qBound(MAINWINDOW_MIN_SIZE, rect.width() - offset.x(), MAINWINDOW_MAX_SIZE));
newRect.setHeight(rect.height());
}
break;
}
// 更新界面大小
m_mainPanel->setFixedSize(newRect.size());
setFixedSize(newRect.size());
move(newRect.topLeft());
}
void MainWindow::onDragFinished()
{
resetDragWindow();
}
void MainWindow::themeTypeChanged(DGuiApplicationHelper::ColorType themeType)
{
if (m_wmHelper->hasComposite()) {
if (themeType == DGuiApplicationHelper::DarkType)
m_platformWindowHandle.setBorderColor(QColor(0, 0, 0, 255 * 0.3));
else
m_platformWindowHandle.setBorderColor(QColor(QColor::Invalid));
}
}
void MainWindow::touchRequestResizeDock()
{
const QPoint touchPos(QCursor::pos());
QRect dockRect = m_multiScreenWorker->dockRect(m_multiScreenWorker->deskScreen()
, m_multiScreenWorker->position()
, HideMode::KeepShowing
, m_multiScreenWorker->displayMode());
// 隐藏状态返回
if (width() == 0 || height() == 0) {
return;
}
QGSettings settings("com.deepin.dde.dock.touch", QByteArray(), this);
int resizeHeight = settings.get("resizeHeight").toInt();
QRect touchRect;
// 任务栏屏幕 内侧边线 内外resizeHeight距离矩形区域内长按可拖动任务栏高度
switch (m_multiScreenWorker->position()) {
case Position::Top:
touchRect = QRect(dockRect.x(), dockRect.y() + dockRect.height() - resizeHeight, dockRect.width(), resizeHeight * 2);
break;
case Position::Bottom:
touchRect = QRect(dockRect.x(), dockRect.y() - resizeHeight, dockRect.width(), resizeHeight * 2);
break;
case Position::Left:
touchRect = QRect(dockRect.x() + dockRect.width() - resizeHeight, dockRect.y(), resizeHeight * 2, dockRect.height());
break;
case Position::Right:
touchRect = QRect(dockRect.x() - resizeHeight, dockRect.y(), resizeHeight * 2, dockRect.height());
break;
}
if (!touchRect.contains(touchPos)) {
return;
}
qApp->postEvent(m_dragWidget, new QMouseEvent(QEvent::MouseButtonPress, QPoint(), touchPos, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
}
#include "mainwindow.moc"