summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb/qxcbdrag.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbdrag.cpp')
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.cpp120
1 files changed, 55 insertions, 65 deletions
diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp
index 1d13adf851..d19ea241f1 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.cpp
+++ b/src/plugins/platforms/xcb/qxcbdrag.cpp
@@ -39,6 +39,7 @@
#include "qxcbwindow.h"
#include "qxcbscreen.h"
#include "qwindow.h"
+#include "qxcbcursor.h"
#include <private/qdnd_p.h>
#include <qdebug.h>
#include <qevent.h>
@@ -51,6 +52,7 @@
#include <private/qshapedpixmapdndwindow_p.h>
#include <private/qsimpledrag_p.h>
+#include <private/qhighdpiscaling_p.h>
QT_BEGIN_NAMESPACE
@@ -71,12 +73,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;
@@ -155,7 +161,7 @@ void QXcbDrag::init()
source_time = XCB_CURRENT_TIME;
target_time = XCB_CURRENT_TIME;
- current_screen = 0;
+ QXcbCursor::queryPointer(connection(), &current_virtual_desktop, 0);
drag_types.clear();
}
@@ -185,6 +191,8 @@ void QXcbDrag::startDrag()
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, connection()->clipboard()->owner(),
atom(QXcbAtom::XdndTypelist),
XCB_ATOM_ATOM, 32, drag_types.size(), (const void *)drag_types.constData());
+
+ setUseCompositing(current_virtual_desktop->compositingActive());
QBasicDrag::startDrag();
}
@@ -297,50 +305,29 @@ 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.
- static const int dpr = int(qApp->devicePixelRatio());
- QBasicDrag::move(me);
- QPoint globalPos = me->globalPos();
if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid())
return;
- const QList<QXcbScreen *> &screens = connection()->screens();
- QXcbScreen *screen = connection()->primaryScreen();
- for (int i = 0; i < screens.size(); ++i) {
- if (screens.at(i)->geometry().contains(globalPos)) {
- screen = screens.at(i);
- break;
- }
- }
- if (screen != current_screen) {
- // ### need to recreate the shaped pixmap window?
-// int screen = QCursor::x11Screen();
-// if ((qt_xdnd_current_screen == -1 && screen != X11->defaultScreen) || (screen != qt_xdnd_current_screen)) {
-// // recreate the pixmap on the new screen...
-// delete xdnd_data.deco;
-// QWidget* parent = object->source()->window()->x11Info().screen() == screen
-// ? object->source()->window() : QApplication::desktop()->screen(screen);
-// xdnd_data.deco = new QShapedPixmapWidget(parent);
-// if (!QWidget::mouseGrabber()) {
-// updatePixmap();
-// xdnd_data.deco->grabMouse();
-// }
-// }
-// xdnd_data.deco->move(QCursor::pos() - xdnd_data.deco->pm_hot);
- current_screen = screen;
- }
+ QXcbVirtualDesktop *virtualDesktop = Q_NULLPTR;
+ QPoint cursorPos;
+ QXcbCursor::queryPointer(connection(), &virtualDesktop, &cursorPos);
+ QXcbScreen *screen = virtualDesktop->screenAt(cursorPos);
+ QPoint deviceIndependentPos = QHighDpiScaling::mapPositionFromNative(globalPos, screen);
+ if (virtualDesktop != current_virtual_desktop) {
+ setUseCompositing(virtualDesktop->compositingActive());
+ recreateShapedPixmapWindow(static_cast<QPlatformScreen*>(screen)->screen(), deviceIndependentPos);
+ current_virtual_desktop = virtualDesktop;
+ } else {
+ QBasicDrag::moveShapedPixmapWindow(deviceIndependentPos);
+ }
-// qt_xdnd_current_screen = screen;
- xcb_window_t rootwin = current_screen->root();
+ xcb_window_t rootwin = current_virtual_desktop->root();
xcb_translate_coordinates_reply_t *translate =
- ::translateCoordinates(connection(), rootwin, rootwin, globalPos.x() * dpr, globalPos.y() * dpr);
+ ::translateCoordinates(connection(), rootwin, rootwin, globalPos.x(), globalPos.y());
if (!translate)
return;
@@ -443,7 +430,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, current_proxy_target);
else if (target)
xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&enter);
waiting_for_status = false;
@@ -463,7 +450,7 @@ void QXcbDrag::move(const QMouseEvent *me)
move.type = atom(QXcbAtom::XdndPosition);
move.data.data32[0] = connection()->clipboard()->owner();
move.data.data32[1] = 0; // flags
- move.data.data32[2] = (globalPos.x() * dpr << 16) + globalPos.y() * dpr;
+ move.data.data32[2] = (globalPos.x() << 16) + globalPos.y();
move.data.data32[3] = connection()->time();
move.data.data32[4] = toXdndAction(defaultAction(currentDrag()->supportedActions(), QGuiApplication::keyboardModifiers()));
DEBUG() << "sending Xdnd position source=" << move.data.data32[0] << "target=" << move.window;
@@ -471,15 +458,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;
@@ -505,7 +492,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()
@@ -518,7 +505,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);
}
@@ -664,7 +651,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, xcb_window_t proxy)
{
Q_UNUSED(window);
DEBUG() << "handleEnter" << window;
@@ -676,6 +663,9 @@ void QXcbDrag::handleEnter(QWindow *window, const xcb_client_message_event_t *ev
return;
xdnd_dragsource = event->data.data32[0];
+ if (!proxy)
+ proxy = xdndProxy(connection(), xdnd_dragsource);
+ current_proxy_target = proxy ? proxy : xdnd_dragsource;
if (event->data.data32[1] & 1) {
// get the types from XdndTypeList
@@ -689,6 +679,7 @@ void QXcbDrag::handleEnter(QWindow *window, const xcb_client_message_event_t *ev
length = xdnd_max_type;
xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply);
+ xdnd_types.reserve(length);
for (int i = 0; i < length; ++i)
xdnd_types.append(atoms[i]);
}
@@ -704,17 +695,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();
- const int dpr = int(w->handle()->devicePixelRatio());
-
- p /= dpr;
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) {
@@ -723,7 +711,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) {
@@ -740,7 +728,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);
@@ -776,7 +764,7 @@ void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t
if (xdnd_dragsource == connection()->clipboard()->owner())
handle_xdnd_status(&response);
else
- Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xdnd_dragsource,
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), false, current_proxy_target,
XCB_EVENT_MASK_NO_EVENT, (const char *)&response));
}
@@ -796,7 +784,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;
@@ -830,12 +818,10 @@ void QXcbDrag::handle_xdnd_status(const xcb_client_message_event_t *event)
updateCursor(Qt::IgnoreAction);
}
- static const int dpr = int(qApp->devicePixelRatio());
-
if ((event->data.data32[1] & 2) == 0) {
QPoint p((event->data.data32[2] & 0xffff0000) >> 16, event->data.data32[2] & 0x0000ffff);
QSize s((event->data.data32[3] & 0xffff0000) >> 16, event->data.data32[3] & 0x0000ffff);
- source_sameanswer = QRect(p / dpr, s / dpr);
+ source_sameanswer = QRect(p, s);
} else {
source_sameanswer = QRect();
}
@@ -861,10 +847,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
// ###
@@ -879,7 +865,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();
@@ -909,7 +895,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);
@@ -920,7 +906,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) {
@@ -970,7 +956,7 @@ void QXcbDrag::handleDrop(QWindow *, const xcb_client_message_event_t *event)
finished.data.data32[0] = currentWindow ? xcb_window(currentWindow.data()) : XCB_NONE;
finished.data.data32[1] = response.isAccepted(); // flags
finished.data.data32[2] = toXdndAction(response.acceptedAction());
- Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xdnd_dragsource,
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), false, current_proxy_target,
XCB_EVENT_MASK_NO_EVENT, (char *)&finished));
xdnd_dragsource = 0;
@@ -1135,7 +1121,11 @@ void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event
}
}
- xcb_send_event(xcb_connection(), false, event->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&notify);
+ xcb_window_t proxy_target = xdndProxy(connection(), event->requestor);
+ if (!proxy_target)
+ proxy_target = event->requestor;
+
+ xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&notify);
}