summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Olav Tvete <paul.tvete@theqtcompany.com>2015-06-02 15:32:02 +0200
committerPaul Olav Tvete <paul.tvete@theqtcompany.com>2015-06-03 07:51:47 +0000
commit39413100cdc8cd7d3ef55ff3c79d94b7cf89cc5e (patch)
treef95d0ebd3a7bb69bab3b3bdef675667a9b978b07
parentd0a017e9b03dd3cf19b640fad4dd56ef0494ce5f (diff)
Fix drag and drop for Xcb
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 <morten.sorvig@theqtcompany.com>
-rw-r--r--src/gui/kernel/qhighdpiscaling_p.h12
-rw-r--r--src/gui/kernel/qsimpledrag.cpp40
-rw-r--r--src/gui/kernel/qsimpledrag_p.h8
-rw-r--r--src/gui/kernel/qwindowsysteminterface.cpp4
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.cpp46
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.h18
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp8
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 <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:
@@ -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<QXcbWindow *>(w)->xcb_window();
+}
+
static inline xcb_window_t xcb_window(QWindow *w)
{
return static_cast<QXcbWindow *>(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<xcb_client_message_event_t *>(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<QDrag> 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);