File highdpi-0005-fix-highdpi-drag-n-drop-for-X11.patch of Package libqt5-qtbase.2170
From 3c12482df08f3bb4b4bc2f2184985790f78d3351 Mon Sep 17 00:00:00 2001
From: Paul Olav Tvete <paul.tvete@theqtcompany.com>
Date: Mon, 22 Jun 2015 12:26:18 +0200
Subject: [PATCH] Fix highdpi drag-n-drop for X11
Task-number: QTBUG-46615
Change-Id: Iad548e62a580d6fbd15b7a826116a53ce23b4b8b
Reviewed-by: Lars Knoll <lars.knoll@theqtcompany.com>
---
src/gui/kernel/qsimpledrag.cpp | 47 ++++++++++++++++++++++----------
src/gui/kernel/qsimpledrag_p.h | 10 ++++---
src/plugins/platforms/xcb/qxcbdrag.cpp | 50 ++++++++++++++++++----------------
src/plugins/platforms/xcb/qxcbdrag.h | 17 ++++++------
4 files changed, 72 insertions(+), 52 deletions(-)
diff --git a/src/gui/kernel/qsimpledrag.cpp b/src/gui/kernel/qsimpledrag.cpp
index b850f53..6e574d8 100644
--- a/src/gui/kernel/qsimpledrag.cpp
+++ b/src/gui/kernel/qsimpledrag.cpp
@@ -55,6 +55,7 @@
#include <private/qdnd_p.h>
#include <private/qshapedpixmapdndwindow_p.h>
+#include <private/qhighdpiscaling_p.h>
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<QMouseEvent *>(e)->globalPos(), qobject_cast<QWindow*>(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<QMouseEvent *>(e));
+ {
+ QPoint nativePosition = getNativeMousePos(e, o);
+ move(nativePosition);
return true; // Eat all mouse events
-
+ }
case QEvent::MouseButtonRelease:
disableEventFilter();
if (canDrop()) {
- drop(static_cast<QMouseEvent *>(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:
@@ -227,13 +236,18 @@ void QBasicDrag::cancel()
m_drag_icon_window->setVisible(false);
}
-void QBasicDrag::move(const QMouseEvent *e)
+/*!
+ Move the drag label to \a globalPos, which is
+ interpreted in device independent coordinates. Typically called from reimplementations of move().
+ */
+
+void QBasicDrag::moveShapedPixmapWindow(const QPoint &globalPos)
{
if (m_drag)
- m_drag_icon_window->updateGeometry(e->globalPos());
+ m_drag_icon_window->updateGeometry(globalPos);
}
-void QBasicDrag::drop(const QMouseEvent *)
+void QBasicDrag::drop(const QPoint &)
{
disableEventFilter();
restoreCursor();
@@ -330,14 +344,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
+ moveShapedPixmapWindow(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());
@@ -345,14 +360,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 7812f8b..a011475 100644
--- a/src/gui/kernel/qsimpledrag_p.h
+++ b/src/gui/kernel/qsimpledrag_p.h
@@ -73,10 +73,12 @@ 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();
+
+ void moveShapedPixmapWindow(const QPoint &deviceIndependentPosition);
QShapedPixmapWindow *shapedPixmapWindow() const { return m_drag_icon_window; }
void updateCursor(Qt::DropAction action);
@@ -111,8 +113,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/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp
index ebbd879..a3e646e 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.cpp
+++ b/src/plugins/platforms/xcb/qxcbdrag.cpp
@@ -51,6 +51,7 @@
#include <private/qshapedpixmapdndwindow_p.h>
#include <private/qsimpledrag_p.h>
+#include <private/qhighdpiscaling_p.h>
QT_BEGIN_NAMESPACE
@@ -71,6 +72,11 @@ QT_BEGIN_NAMESPACE
const int xdnd_version = 5;
+static inline xcb_window_t xcb_window(QPlatformWindow *w)
+{
+ return static_cast<QXcbWindow *>(w)->xcb_window();
+}
+
static inline xcb_window_t xcb_window(QWindow *w)
{
return static_cast<QXcbWindow *>(w->handle())->xcb_window();
@@ -296,14 +302,8 @@ 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)
{
- // The mouse event is in the coordinate system of the window that started the drag.
- // We do not know which window that was at this point, so we just use the device pixel ratio
- // of the QGuiApplication. This will break once we support screens with different DPR. Fixing
- // this properly requires some redesign of the drag and drop architecture.
- QBasicDrag::move(me);
- QPoint globalPos = me->globalPos();
if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid())
return;
@@ -317,6 +317,8 @@ void QXcbDrag::move(const QMouseEvent *me)
}
}
+ QBasicDrag::moveShapedPixmapWindow(QHighDpiScaling::mapPositionFromNative(globalPos, screen));
+
if (screen != current_screen) {
// ### need to recreate the shaped pixmap window?
// int screen = QCursor::x11Screen();
@@ -442,7 +444,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;
@@ -470,15 +472,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;
@@ -504,7 +506,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()
@@ -517,7 +519,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);
}
@@ -663,7 +665,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;
@@ -704,14 +706,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) {
@@ -720,7 +722,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) {
@@ -737,7 +739,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);
@@ -793,7 +795,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<xcb_client_message_event_t *>(event);
xcb_generic_event_t *nextEvent;
@@ -856,10 +858,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
// ###
@@ -874,7 +876,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();
@@ -904,7 +906,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);
@@ -915,7 +917,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 b307634..699d402 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.h
+++ b/src/plugins/platforms/xcb/qxcbdrag.h
@@ -53,7 +53,6 @@ QT_BEGIN_NAMESPACE
#ifndef QT_NO_DRAGANDDROP
-class QMouseEvent;
class QWindow;
class QPlatformWindow;
class QXcbConnection;
@@ -73,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);
@@ -100,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();
@@ -147,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<QDrag> drag;
QTime time;
--
2.6.2