dde-dock/frame/window/mainwindow.cpp
liuxing 7d2d83c2d8 fix: 任务栏在上时拖动改变任务栏的高度时不跟随手指移动
当触屏拖拽触屏按下坐标在任务栏拖拽窗口之外时,拖拽窗口不会收到触屏的mousemove事件,导致拖拽中途不刷新任务栏大小。通过转发后端触屏移动信号解决。

Log: 解决任务栏拖动改变任务栏的高度时不跟随手指移动问题
Bug: https://pms.uniontech.com/zentao/bug-view-46281.html
Change-Id: I4b74614c3a830b2ed164c1b80f34a97ef8800e4a
Reviewed-on: http://gerrit.uniontech.com/c/dde-dock/+/3870
Reviewed-by: <mailman@uniontech.com>
Reviewed-by: niecheng <niecheng@uniontech.com>
Reviewed-by: fanpengcheng <fanpengcheng@uniontech.com>
Tested-by: <mailman@uniontech.com>
2020-09-07 20:21:36 +08:00

486 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(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);
connect(TouchSignalManager::instance(), &TouchSignalManager::touchMove, m_dragWidget, [ this ](){
static QPoint lastPos;
QPoint curPos = QCursor::pos();
if (lastPos == curPos) {
return;
}
lastPos = curPos;
qApp->postEvent(m_dragWidget, new QMouseEvent(QEvent::MouseMove, m_dragWidget->mapFromGlobal(curPos)
, curPos, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
});
}
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, m_dragWidget->mapFromGlobal(touchPos)
, touchPos, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
}
#include "mainwindow.moc"