Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 165 additions & 2 deletions xcb/dnotitlebarwindowhelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
#include "dnativesettings.h"
#include "dplatformintegration.h"

#include <QMouseEvent>

Check warning on line 15 in xcb/dnotitlebarwindowhelper.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QMouseEvent> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QTouchEvent>

Check warning on line 16 in xcb/dnotitlebarwindowhelper.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QTouchEvent> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QTimer>

Check warning on line 17 in xcb/dnotitlebarwindowhelper.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QTimer> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QMetaProperty>

Check warning on line 18 in xcb/dnotitlebarwindowhelper.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QMetaProperty> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QScreen>

Check warning on line 19 in xcb/dnotitlebarwindowhelper.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QScreen> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <qpa/qplatformwindow.h>
#include <QGuiApplication>
#include <QStyleHints>
Expand All @@ -40,6 +41,9 @@
if (window->flags().testFlag(Qt::FramelessWindowHint))
window->setFlags(window->flags() & ~Qt::FramelessWindowHint);

// 初始化窗口类型判断结果
m_isQuickWindow = window->inherits("QQuickWindow");

mapped[window] = this;
m_nativeSettingsValid = DPlatformIntegration::buildNativeSettings(this, windowID);
Q_ASSERT(m_nativeSettingsValid);
Expand Down Expand Up @@ -524,15 +528,35 @@
VtableHook::resetVtable(w);
return w->event(event);
}
DNoTitlebarWindowHelper *self = mapped.value(w);

// get touch begin position
static bool isTouchDown = false;
static QPointF touchBeginPosition;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
static QHash<int, QObject*> touchPointGrabbers; // 新增:记录触摸点的grabber状态
const auto isQuickWindow = self->m_isQuickWindow;
#endif

if (event->type() == QEvent::TouchBegin) {
isTouchDown = true;
// ========== 新增:记录处理前的grabber状态 ==========
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (isQuickWindow && event->isPointerEvent()) {
QPointerEvent *pe = static_cast<QPointerEvent*>(event);
touchPointGrabbers.clear();
for (const auto &point : pe->points()) {
QObject *grabber = pe->exclusiveGrabber(point);
touchPointGrabbers[point.id()] = grabber;
}
}
#endif
}
if (event->type() == QEvent::TouchEnd || event->type() == QEvent::MouseButtonRelease) {
isTouchDown = false;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
touchPointGrabbers.clear(); // 清理grabber记录
#endif
}
if (isTouchDown && event->type() == QEvent::MouseButtonPress) {
touchBeginPosition = static_cast<QMouseEvent*>(event)->globalPos();
Expand All @@ -546,7 +570,6 @@
}
}

DNoTitlebarWindowHelper *self = mapped.value(w);
quint32 winId = self->m_windowID;
bool is_mouse_move = event->type() == QEvent::MouseMove && static_cast<QMouseEvent*>(event)->buttons() == Qt::LeftButton;

Expand All @@ -570,10 +593,15 @@
g_pressPoint[this] = dynamic_cast<QMouseEvent*>(event)->globalPos();
}

// ========== 修改:鼠标事件处理保持原有逻辑 ==========
if (is_mouse_move && !event->isAccepted() && g_pressPoint.contains(this)) {
QMouseEvent *me = static_cast<QMouseEvent*>(event);
QRect windowRect = QRect(QPoint(0, 0), w->size());
if (!windowRect.contains(me->windowPos().toPoint())) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (!windowRect.contains(me->scenePosition().toPoint())) {
#else
if (!windowRect.contains(me->localPos().toPoint())) {
#endif
return ret;
}

Expand All @@ -583,6 +611,7 @@
}

if (!self->m_windowMoving && self->isEnableSystemMove(winId)) {
qDebug() << "Starting mouse drag for window ID:" << winId;
self->m_windowMoving = true;

event->accept();
Expand All @@ -594,6 +623,39 @@
}
}

// ========== 新增:QML窗口触摸事件的特殊处理 ==========
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (isQuickWindow && event->isPointerEvent()) {
QPointerEvent *pe = static_cast<QPointerEvent*>(event);

// 检查是否是触摸事件
bool isTouchEvent = (event->type() == QEvent::TouchBegin ||
event->type() == QEvent::TouchUpdate ||
event->type() == QEvent::TouchEnd);

if (isTouchEvent) {
// 检查是否有新的grabber产生(说明QML Item处理了触摸事件)
bool wasHandledByQML = false;
for (const auto &point : pe->points()) {
QObject *grabberBefore = touchPointGrabbers.value(point.id());
QObject *grabberAfter = pe->exclusiveGrabber(point);

if (grabberBefore != grabberAfter && grabberAfter != nullptr) {
wasHandledByQML = true;
break;
}
}

// 如果没有QML Item处理触摸事件,尝试窗口拖拽
if (!wasHandledByQML && self->isEnableSystemMove(winId)) {
if (self->handleTouchDragForQML(pe)) {
return ret;
}
}
}
}
#endif

return ret;
}

Expand Down Expand Up @@ -733,4 +795,105 @@
Utility::updateMousePointForWindowMove(winId);
}

#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
bool DNoTitlebarWindowHelper::handleTouchDragForQML(QPointerEvent *touchEvent)
{
QWindow *w = this->m_window;
static QHash<int, QPointF> touchStartPositions;
static QHash<int, bool> touchIsMoving;
static QHash<int, QPointF> lastTouchPositions; // 新增:记录最后的触摸位置用于更新

const auto points = touchEvent->points();
if (points.isEmpty()) {
return false;
}

// 只处理第一个触摸点
const auto &point = points.first();
int touchId = point.id();

// ========== 新增:多屏幕坐标处理 ==========
QScreen *windowScreen = w->screen();
QPointF globalPos = point.globalPosition();
QPointF localPos = point.position();

switch (touchEvent->type()) {
case QEvent::TouchBegin: {
touchStartPositions[touchId] = globalPos;
lastTouchPositions[touchId] = globalPos;
touchIsMoving[touchId] = false;
return false; // 不消费事件,让QML先处理
}

case QEvent::TouchUpdate: {
if (!touchStartPositions.contains(touchId)) {
return false;
}

QPointF startPos = touchStartPositions[touchId];
QPointF currentPos = globalPos;
QPointF delta = currentPos - startPos;
qreal distance = delta.manhattanLength();
qreal threshold = QGuiApplication::styleHints()->startDragDistance();

// 更新最后触摸位置
lastTouchPositions[touchId] = currentPos;

// 检查移动距离是否达到拖拽阈值
if (!touchIsMoving[touchId] && distance >= threshold) {

// ========== 修改:多屏幕环境下的窗口边界检查 ==========
QRect windowRect = QRect(QPoint(0, 0), w->size());
QPoint localTouchPos = localPos.toPoint();
bool inBounds = windowRect.contains(localTouchPos);

// 使用本地坐标检查(更可靠)
if (!inBounds) {
return false;
}

// 开始窗口移动
if (isEnableSystemMove(m_windowID)) {
qDebug() << "Starting touch drag for QML window ID:" << m_windowID
<< "on screen:" << (windowScreen ? windowScreen->name() : "unknown");
m_windowMoving = true;
touchIsMoving[touchId] = true;

startMoveWindow(m_windowID);
touchEvent->accept();
return true;
}
} else if (touchIsMoving[touchId] && m_windowMoving) {
// ========== 修改:使用带坐标参数的updateMousePointForWindowMove ==========
Utility::updateMousePointForWindowMove(m_windowID, currentPos.toPoint());
touchEvent->accept();
return true;
}
break;
}

case QEvent::TouchEnd: {
if (touchIsMoving.value(touchId, false)) {
m_windowMoving = false;
// ========== 修改:使用最后的触摸位置结束窗口移动 ==========
QPointF lastPos = lastTouchPositions.value(touchId, globalPos);
Utility::updateMousePointForWindowMove(m_windowID, lastPos.toPoint(), true);
qDebug() << "Finished touch drag for QML window ID:" << m_windowID;
}

// 清理状态
touchStartPositions.remove(touchId);
touchIsMoving.remove(touchId);
lastTouchPositions.remove(touchId);
break;
}

default:
break;
}

return false;
}
#endif

DPP_END_NAMESPACE
12 changes: 12 additions & 0 deletions xcb/dnotitlebarwindowhelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@

QT_BEGIN_NAMESPACE
class QWindow;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
class QPointerEvent;
#endif
QT_END_NAMESPACE

DPP_BEGIN_NAMESPACE
Expand Down Expand Up @@ -104,6 +107,14 @@ private slots:
bool isEnableSystemMove(quint32 winId);
bool updateWindowBlurAreasForWM();
void updateWindowShape();

#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
// 新增:QML窗口触摸拖拽处理函数 (仅Qt6)
bool handleTouchDragForQML(QPointerEvent *touchEvent);
#else
// Qt5版本的触摸拖拽处理函数
bool handleTouchDragForQML(QTouchEvent *touchEvent);
#endif

void onWindowSizeChanged();

Expand All @@ -114,6 +125,7 @@ private slots:
quint32 m_windowID;
bool m_windowMoving = false;
bool m_nativeSettingsValid = false;
bool m_isQuickWindow = false; // 新增:缓存窗口类型判断结果

QVector<Utility::BlurArea> m_blurAreaList;
QList<QPainterPath> m_blurPathList;
Expand Down
2 changes: 2 additions & 0 deletions xcb/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ class Utility
// 导致窗口无法移动。此处跟deepin-wm配合,使用其它方式通知窗管鼠标位置更新了
// TODO: kwin适配udpate之后没有结束move状态,新增一个finished参数,当传入true时通知kwin结束
static void updateMousePointForWindowMove(quint32 WId, bool finished = false);
// 新增:支持多屏幕的版本,接受自定义全局坐标
static void updateMousePointForWindowMove(quint32 WId, const QPoint &globalPos, bool finished = false);

static void showWindowSystemMenu(quint32 WId, QPoint globalPos = QPoint());
static void setFrameExtents(WId wid, const QMargins &margins);
Expand Down
9 changes: 8 additions & 1 deletion xcb/utility_x11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,15 @@ void Utility::cancelWindowMoveResize(quint32 WId)

void Utility::updateMousePointForWindowMove(quint32 WId, bool finished/* = false*/)
{
xcb_client_message_event_t xev;
// 获取主屏幕的光标位置并调用重载版本
const QPoint &globalPos = qApp->primaryScreen()->handle()->cursor()->pos();
updateMousePointForWindowMove(WId, globalPos, finished);
}

// 新增:支持多屏幕的版本,接受自定义全局坐标
void Utility::updateMousePointForWindowMove(quint32 WId, const QPoint &globalPos, bool finished/* = false*/)
{
xcb_client_message_event_t xev;

xev.response_type = XCB_CLIENT_MESSAGE;
xev.type = internAtom("_DEEPIN_MOVE_UPDATE");
Expand Down