diff --git a/xcb/dnotitlebarwindowhelper.cpp b/xcb/dnotitlebarwindowhelper.cpp index c9715602..8252c76b 100644 --- a/xcb/dnotitlebarwindowhelper.cpp +++ b/xcb/dnotitlebarwindowhelper.cpp @@ -13,6 +13,7 @@ #include "dplatformintegration.h" #include +#include #include #include #include @@ -40,6 +41,9 @@ DNoTitlebarWindowHelper::DNoTitlebarWindowHelper(QWindow *window, quint32 window 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); @@ -524,15 +528,35 @@ bool DNoTitlebarWindowHelper::windowEvent(QEvent *event) 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 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(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(event)->globalPos(); @@ -546,7 +570,6 @@ bool DNoTitlebarWindowHelper::windowEvent(QEvent *event) } } - DNoTitlebarWindowHelper *self = mapped.value(w); quint32 winId = self->m_windowID; bool is_mouse_move = event->type() == QEvent::MouseMove && static_cast(event)->buttons() == Qt::LeftButton; @@ -570,10 +593,15 @@ bool DNoTitlebarWindowHelper::windowEvent(QEvent *event) g_pressPoint[this] = dynamic_cast(event)->globalPos(); } + // ========== 修改:鼠标事件处理保持原有逻辑 ========== if (is_mouse_move && !event->isAccepted() && g_pressPoint.contains(this)) { QMouseEvent *me = static_cast(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; } @@ -583,6 +611,7 @@ bool DNoTitlebarWindowHelper::windowEvent(QEvent *event) } if (!self->m_windowMoving && self->isEnableSystemMove(winId)) { + qDebug() << "Starting mouse drag for window ID:" << winId; self->m_windowMoving = true; event->accept(); @@ -594,6 +623,39 @@ bool DNoTitlebarWindowHelper::windowEvent(QEvent *event) } } + // ========== 新增:QML窗口触摸事件的特殊处理 ========== +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + if (isQuickWindow && event->isPointerEvent()) { + QPointerEvent *pe = static_cast(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; } @@ -733,4 +795,105 @@ void DNoTitlebarWindowHelper::updateMoveWindow(quint32 winId) Utility::updateMousePointForWindowMove(winId); } +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +bool DNoTitlebarWindowHelper::handleTouchDragForQML(QPointerEvent *touchEvent) +{ + QWindow *w = this->m_window; + static QHash touchStartPositions; + static QHash touchIsMoving; + static QHash 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 diff --git a/xcb/dnotitlebarwindowhelper.h b/xcb/dnotitlebarwindowhelper.h index 9c943067..6b4bfa30 100644 --- a/xcb/dnotitlebarwindowhelper.h +++ b/xcb/dnotitlebarwindowhelper.h @@ -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 @@ -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(); @@ -114,6 +125,7 @@ private slots: quint32 m_windowID; bool m_windowMoving = false; bool m_nativeSettingsValid = false; + bool m_isQuickWindow = false; // 新增:缓存窗口类型判断结果 QVector m_blurAreaList; QList m_blurPathList; diff --git a/xcb/utility.h b/xcb/utility.h index cd44baf0..6c93d717 100644 --- a/xcb/utility.h +++ b/xcb/utility.h @@ -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); diff --git a/xcb/utility_x11.cpp b/xcb/utility_x11.cpp index f29ed705..06386bf0 100644 --- a/xcb/utility_x11.cpp +++ b/xcb/utility_x11.cpp @@ -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");