From 39413100cdc8cd7d3ef55ff3c79d94b7cf89cc5e Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Tue, 2 Jun 2015 15:32:02 +0200 Subject: Fix drag and drop for Xcb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the xcb plugin work in native coordinates, using platform windows as much as possible. As part of this, replace QMouseEvent in QBasicDrag with just a QPoint. This is private API, so we can change this without warning. In addition to xcb, QBasicDrag is used in QSimpleDrag and for Wayland. QSimpleDrag does not yet have a fix for highDpi, but it should continue working in the non-scaled case. Wayland (and any other module which uses QBasicDrag) will need a compile fix. Also fix bug in QWindowSystemInterface: handleDrag()/handleDrop() take positions in window local coordinates, not global. Change-Id: I86543e4f52a7b3ba1efeac815cf89bbd97c0a0a2 Reviewed-by: Morten Johan Sørvig --- src/gui/kernel/qhighdpiscaling_p.h | 12 ++++++++ src/gui/kernel/qsimpledrag.cpp | 40 +++++++++++++++++---------- src/gui/kernel/qsimpledrag_p.h | 8 +++--- src/gui/kernel/qwindowsysteminterface.cpp | 4 +-- src/plugins/platforms/xcb/qxcbdrag.cpp | 46 ++++++++++++++++--------------- src/plugins/platforms/xcb/qxcbdrag.h | 18 ++++++------ src/plugins/platforms/xcb/qxcbwindow.cpp | 8 +++--- 7 files changed, 81 insertions(+), 55 deletions(-) diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h index 827c21ad5c..6c96fa2e07 100644 --- a/src/gui/kernel/qhighdpiscaling_p.h +++ b/src/gui/kernel/qhighdpiscaling_p.h @@ -171,6 +171,18 @@ inline QRect fromNativeScreenGeometry(const QRect &nativeScreenGeometry, const Q return QRect(nativeScreenGeometry.topLeft(), fromNative(nativeScreenGeometry.size(), QHighDpiScaling::factor(screen))); } +inline QPoint fromNativeLocalPosition(const QPoint &pos, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return pos / scaleFactor; +} + +inline QPoint toNativeLocalPosition(const QPoint &pos, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return pos * scaleFactor; +} + inline QPointF fromNativeLocalPosition(const QPointF &pos, const QWindow *window) { const qreal scaleFactor = QHighDpiScaling::factor(window); diff --git a/src/gui/kernel/qsimpledrag.cpp b/src/gui/kernel/qsimpledrag.cpp index 090e88c118..517f3024aa 100644 --- a/src/gui/kernel/qsimpledrag.cpp +++ b/src/gui/kernel/qsimpledrag.cpp @@ -55,6 +55,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -106,6 +107,12 @@ void QBasicDrag::disableEventFilter() qApp->removeEventFilter(this); } + +static inline QPoint getNativeMousePos(QEvent *e, QObject *o) +{ + return QHighDpi::toNativePixels(static_cast(e)->globalPos(), qobject_cast(o)); +} + bool QBasicDrag::eventFilter(QObject *o, QEvent *e) { Q_UNUSED(o); @@ -139,19 +146,21 @@ bool QBasicDrag::eventFilter(QObject *o, QEvent *e) } case QEvent::MouseMove: - move(static_cast(e)); + { + QPoint nativePosition = getNativeMousePos(e, o); + move(nativePosition); return true; // Eat all mouse events - + } case QEvent::MouseButtonRelease: disableEventFilter(); if (canDrop()) { - drop(static_cast(e)); + QPoint nativePosition = getNativeMousePos(e, o); + drop(nativePosition); } else { cancel(); } exitDndEventLoop(); return true; // Eat all mouse events - case QEvent::MouseButtonPress: case QEvent::MouseButtonDblClick: case QEvent::Wheel: @@ -218,13 +227,13 @@ void QBasicDrag::cancel() m_drag_icon_window->setVisible(false); } -void QBasicDrag::move(const QMouseEvent *) +void QBasicDrag::move(const QPoint &) { if (m_drag) m_drag_icon_window->updateGeometry(); } -void QBasicDrag::drop(const QMouseEvent *) +void QBasicDrag::drop(const QPoint &) { disableEventFilter(); restoreCursor(); @@ -321,14 +330,15 @@ void QSimpleDrag::cancel() } } -void QSimpleDrag::move(const QMouseEvent *me) +void QSimpleDrag::move(const QPoint &globalPos) { - QBasicDrag::move(me); - QWindow *window = topLevelAt(me->globalPos()); + //### not high-DPI aware + QBasicDrag::move(globalPos); + QWindow *window = topLevelAt(globalPos); if (!window) return; - const QPoint pos = me->globalPos() - window->geometry().topLeft(); + const QPoint pos = globalPos - window->geometry().topLeft(); const QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(window, drag()->mimeData(), pos, drag()->supportedActions()); @@ -336,14 +346,16 @@ void QSimpleDrag::move(const QMouseEvent *me) setCanDrop(qt_response.isAccepted()); } -void QSimpleDrag::drop(const QMouseEvent *me) +void QSimpleDrag::drop(const QPoint &globalPos) { - QBasicDrag::drop(me); - QWindow *window = topLevelAt(me->globalPos()); + //### not high-DPI aware + + QBasicDrag::drop(globalPos); + QWindow *window = topLevelAt(globalPos); if (!window) return; - const QPoint pos = me->globalPos() - window->geometry().topLeft(); + const QPoint pos = globalPos - window->geometry().topLeft(); const QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(window, drag()->mimeData(),pos, drag()->supportedActions()); if (response.isAccepted()) { diff --git a/src/gui/kernel/qsimpledrag_p.h b/src/gui/kernel/qsimpledrag_p.h index 7812f8b863..728ae7bd15 100644 --- a/src/gui/kernel/qsimpledrag_p.h +++ b/src/gui/kernel/qsimpledrag_p.h @@ -73,8 +73,8 @@ protected: virtual void startDrag(); virtual void cancel(); - virtual void move(const QMouseEvent *me); - virtual void drop(const QMouseEvent *me); + virtual void move(const QPoint &globalPos) = 0; + virtual void drop(const QPoint &globalPos) = 0; virtual void endDrag(); QShapedPixmapWindow *shapedPixmapWindow() const { return m_drag_icon_window; } @@ -111,8 +111,8 @@ public: protected: virtual void startDrag() Q_DECL_OVERRIDE; virtual void cancel() Q_DECL_OVERRIDE; - virtual void move(const QMouseEvent *me) Q_DECL_OVERRIDE; - virtual void drop(const QMouseEvent *me) Q_DECL_OVERRIDE; + virtual void move(const QPoint &globalPos) Q_DECL_OVERRIDE; + virtual void drop(const QPoint &globalPos) Q_DECL_OVERRIDE; private: QWindow *m_current_window; diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 13cbf5b8b6..13461e981e 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -651,12 +651,12 @@ int QWindowSystemInterface::windowSystemEventsQueued() #ifndef QT_NO_DRAGANDDROP QPlatformDragQtResponse QWindowSystemInterface::handleDrag(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions) { - return QGuiApplicationPrivate::processDrag(w, dropData, QHighDpi::fromNativePixels(p, w),supportedActions); + return QGuiApplicationPrivate::processDrag(w, dropData, QHighDpi::fromNativeLocalPosition(p, w) ,supportedActions); } QPlatformDropQtResponse QWindowSystemInterface::handleDrop(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions) { - return QGuiApplicationPrivate::processDrop(w, dropData, QHighDpi::fromNativePixels(p, w),supportedActions); + return QGuiApplicationPrivate::processDrop(w, dropData, QHighDpi::fromNativeLocalPosition(p, w),supportedActions); } #endif // QT_NO_DRAGANDDROP diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index 38375e748b..8d4878e12e 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -71,12 +71,16 @@ QT_BEGIN_NAMESPACE const int xdnd_version = 5; +static inline xcb_window_t xcb_window(QPlatformWindow *w) +{ + return static_cast(w)->xcb_window(); +} + static inline xcb_window_t xcb_window(QWindow *w) { return static_cast(w->handle())->xcb_window(); } - static xcb_window_t xdndProxy(QXcbConnection *c, xcb_window_t w) { xcb_window_t proxy = XCB_NONE; @@ -297,11 +301,9 @@ xcb_window_t QXcbDrag::findRealWindow(const QPoint & pos, xcb_window_t w, int md return 0; } -void QXcbDrag::move(const QMouseEvent *me) +void QXcbDrag::move(const QPoint &globalPos) { - // ### does this need to be high DPI aware???? - QBasicDrag::move(me); - QPoint globalPos = me->globalPos(); + QBasicDrag::move(globalPos); if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid()) return; @@ -439,7 +441,7 @@ void QXcbDrag::move(const QMouseEvent *me) DEBUG() << "sending Xdnd enter source=" << enter.data.data32[0]; if (w) - handleEnter(w->window(), &enter); + handleEnter(w, &enter); else if (target) xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&enter); waiting_for_status = false; @@ -467,15 +469,15 @@ void QXcbDrag::move(const QMouseEvent *me) source_time = connection()->time(); if (w) - handle_xdnd_position(w->window(), &move); + handle_xdnd_position(w, &move); else xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&move); } } -void QXcbDrag::drop(const QMouseEvent *event) +void QXcbDrag::drop(const QPoint &globalPos) { - QBasicDrag::drop(event); + QBasicDrag::drop(globalPos); if (!current_target) return; @@ -501,7 +503,7 @@ void QXcbDrag::drop(const QMouseEvent *event) connection()->time(), current_target, current_proxy_target, - (w ? w->window() : 0), + w, // current_embeddig_widget, currentDrag(), QTime::currentTime() @@ -514,7 +516,7 @@ void QXcbDrag::drop(const QMouseEvent *event) } if (w) { - handleDrop(w->window(), &drop); + handleDrop(w, &drop); } else { xcb_send_event(xcb_connection(), false, current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&drop); } @@ -660,7 +662,7 @@ static bool checkEmbedded(QWidget* w, const XEvent* xe) #endif -void QXcbDrag::handleEnter(QWindow *window, const xcb_client_message_event_t *event) +void QXcbDrag::handleEnter(QPlatformWindow *window, const xcb_client_message_event_t *event) { Q_UNUSED(window); DEBUG() << "handleEnter" << window; @@ -700,14 +702,14 @@ void QXcbDrag::handleEnter(QWindow *window, const xcb_client_message_event_t *ev DEBUG() << " " << connection()->atomName(xdnd_types.at(i)); } -void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *e) +void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *e) { QPoint p((e->data.data32[2] & 0xffff0000) >> 16, e->data.data32[2] & 0x0000ffff); Q_ASSERT(w); QRect geometry = w->geometry(); p -= geometry.topLeft(); - if (!w || (w->type() == Qt::Desktop)) + if (!w || !w->window() || (w->window()->type() == Qt::Desktop)) return; if (e->data.data32[0] != xdnd_dragsource) { @@ -716,7 +718,7 @@ void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t } currentPosition = p; - currentWindow = w; + currentWindow = w->window(); // timestamp from the source if (e->data.data32[3] != XCB_NONE) { @@ -733,7 +735,7 @@ void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t supported_actions = Qt::DropActions(toDropAction(e->data.data32[4])); } - QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(w,dropData,p,supported_actions); + QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(w->window(),dropData,p,supported_actions); QRect answerRect(p + geometry.topLeft(), QSize(1,1)); answerRect = qt_response.answerRect().translated(geometry.topLeft()).intersected(geometry); @@ -789,7 +791,7 @@ namespace }; } -void QXcbDrag::handlePosition(QWindow * w, const xcb_client_message_event_t *event) +void QXcbDrag::handlePosition(QPlatformWindow * w, const xcb_client_message_event_t *event) { xcb_client_message_event_t *lastEvent = const_cast(event); xcb_generic_event_t *nextEvent; @@ -852,10 +854,10 @@ void QXcbDrag::handleStatus(const xcb_client_message_event_t *event) DEBUG("xdndHandleStatus end"); } -void QXcbDrag::handleLeave(QWindow *w, const xcb_client_message_event_t *event) +void QXcbDrag::handleLeave(QPlatformWindow *w, const xcb_client_message_event_t *event) { DEBUG("xdnd leave"); - if (!currentWindow || w != currentWindow.data()) + if (!currentWindow || w != currentWindow.data()->handle()) return; // sanity // ### @@ -870,7 +872,7 @@ void QXcbDrag::handleLeave(QWindow *w, const xcb_client_message_event_t *event) DEBUG("xdnd drag leave from unexpected source (%x not %x", event->data.data32[0], xdnd_dragsource); } - QWindowSystemInterface::handleDrag(w,0,QPoint(),Qt::IgnoreAction); + QWindowSystemInterface::handleDrag(w->window(),0,QPoint(),Qt::IgnoreAction); xdnd_dragsource = 0; xdnd_types.clear(); @@ -900,7 +902,7 @@ void QXcbDrag::send_leave() w = 0; if (w) - handleLeave(w->window(), (const xcb_client_message_event_t *)&leave); + handleLeave(w, (const xcb_client_message_event_t *)&leave); else xcb_send_event(xcb_connection(), false,current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&leave); @@ -911,7 +913,7 @@ void QXcbDrag::send_leave() waiting_for_status = false; } -void QXcbDrag::handleDrop(QWindow *, const xcb_client_message_event_t *event) +void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *event) { DEBUG("xdndHandleDrop"); if (!currentWindow) { diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h index 95da76b732..699d402ea6 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.h +++ b/src/plugins/platforms/xcb/qxcbdrag.h @@ -53,8 +53,8 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_DRAGANDDROP -class QMouseEvent; class QWindow; +class QPlatformWindow; class QXcbConnection; class QXcbWindow; class QXcbDropData; @@ -72,14 +72,14 @@ public: void startDrag() Q_DECL_OVERRIDE; void cancel() Q_DECL_OVERRIDE; - void move(const QMouseEvent *me) Q_DECL_OVERRIDE; - void drop(const QMouseEvent *me) Q_DECL_OVERRIDE; + void move(const QPoint &globalPos) Q_DECL_OVERRIDE; + void drop(const QPoint &globalPos) Q_DECL_OVERRIDE; void endDrag() Q_DECL_OVERRIDE; - void handleEnter(QWindow *window, const xcb_client_message_event_t *event); - void handlePosition(QWindow *w, const xcb_client_message_event_t *event); - void handleLeave(QWindow *w, const xcb_client_message_event_t *event); - void handleDrop(QWindow *, const xcb_client_message_event_t *event); + void handleEnter(QPlatformWindow *window, const xcb_client_message_event_t *event); + void handlePosition(QPlatformWindow *w, const xcb_client_message_event_t *event); + void handleLeave(QPlatformWindow *w, const xcb_client_message_event_t *event); + void handleDrop(QPlatformWindow *, const xcb_client_message_event_t *event); void handleStatus(const xcb_client_message_event_t *event); void handleSelectionRequest(const xcb_selection_request_event_t *event); @@ -99,7 +99,7 @@ private: void init(); - void handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *event); + void handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *event); void handle_xdnd_status(const xcb_client_message_event_t *event); void send_leave(); @@ -146,7 +146,7 @@ private: xcb_timestamp_t timestamp; xcb_window_t target; xcb_window_t proxy_target; - QWindow *targetWindow; + QPlatformWindow *targetWindow; // QWidget *embedding_widget; QPointer drag; QTime time; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 0c0353d035..ad7e5a0320 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -1927,13 +1927,13 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even } #ifndef QT_NO_DRAGANDDROP } else if (event->type == atom(QXcbAtom::XdndEnter)) { - connection()->drag()->handleEnter(window(), event); + connection()->drag()->handleEnter(this, event); } else if (event->type == atom(QXcbAtom::XdndPosition)) { - connection()->drag()->handlePosition(window(), event); + connection()->drag()->handlePosition(this, event); } else if (event->type == atom(QXcbAtom::XdndLeave)) { - connection()->drag()->handleLeave(window(), event); + connection()->drag()->handleLeave(this, event); } else if (event->type == atom(QXcbAtom::XdndDrop)) { - connection()->drag()->handleDrop(window(), event); + connection()->drag()->handleDrop(this, event); #endif } else if (event->type == atom(QXcbAtom::_XEMBED)) { handleXEmbedMessage(event); -- cgit v1.2.3