summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorGatis Paeglis <gatis.paeglis@qt.io>2017-05-15 16:23:49 +0200
committerGatis Paeglis <gatis.paeglis@qt.io>2018-05-04 10:44:15 +0000
commit10b3286313c78fa380b5fe676a7c14f3ae84f017 (patch)
treec42b5d2173c2b31775bfaa4185e9c59f55f22f0e /src/plugins
parentbd52d9d73be83d5e4d2e16e45fe369dc79ae2117 (diff)
qpa: improve API to support DnDs from other processes
... instead of using a hack of directly accessing QGuiApplication members. The current QPA API was bad for two reasons: 1) It expects platform plugin authors to know about internals of Qt Gui, particularly that QGuiApplication uses QGuiApplication::{mouseButtons,keyboardModifiers} to construct QDragMoveEvent and QDropEvent events. Which results in the second reason why this is bad. 2) Platform plugins should not directly access member variables of QGuiApplication, just to make sure that QDragMoveEvent and QDropEvent events contain correct state. Platform plugins should instead use QWindowSystemInterface to communicate with Qt Gui (which is also the solution here). The solution is to extend QWindowSystemInterface::handle{Drag,Drop} to require mouse/keyboard state. We already do this for some of the other methods, so it is nothing extraordinary. This type of interface is also _required_ to support drag-n-drops from other processes. We can't use QGuiApplication::{mouseButtons,keyboardModifiers} when the drag originates from another process, instead we need to query mouse/keyboard state from the system. This patch fixes drag-n-drops from others processes on XCB platform plugin. Task-number: QTBUG-57168 Change-Id: I3f8b0d2f76e9a32ae157622fef801829d629921d Reviewed-by: Mikhail Svetkin <mikhail.svetkin@qt.io> Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io> Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp15
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h3
-rw-r--r--src/plugins/platforms/xcb/qxcbcursor.cpp6
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.cpp37
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.h10
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp5
6 files changed, 54 insertions, 22 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 6f1a3e3c19..7d59496db3 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -53,6 +53,7 @@
#include "qxcbsystemtraytracker.h"
#include "qxcbglintegrationfactory.h"
#include "qxcbglintegration.h"
+#include "qxcbcursor.h"
#include <QSocketNotifier>
#include <QAbstractEventDispatcher>
@@ -2275,6 +2276,20 @@ bool QXcbConnection::xEmbedSystemTrayVisualHasAlphaChannel()
return connection->systemTrayTracker() && connection->systemTrayTracker()->visualHasAlphaChannel();
}
+Qt::MouseButtons QXcbConnection::queryMouseButtons() const
+{
+ int stateMask = 0;
+ QXcbCursor::queryPointer(connection(), 0, 0, &stateMask);
+ return translateMouseButtons(stateMask);
+}
+
+Qt::KeyboardModifiers QXcbConnection::queryKeyboardModifiers() const
+{
+ int stateMask = 0;
+ QXcbCursor::queryPointer(connection(), 0, 0, &stateMask);
+ return keyboard()->translateModifiers(stateMask);
+}
+
bool QXcbConnection::event(QEvent *e)
{
if (e->type() == QEvent::User + 1) {
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 3b42d7cf22..6bf4ad0b6c 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -506,6 +506,9 @@ public:
static bool xEmbedSystemTrayAvailable();
static bool xEmbedSystemTrayVisualHasAlphaChannel();
+ Qt::MouseButtons queryMouseButtons() const;
+ Qt::KeyboardModifiers queryKeyboardModifiers() const;
+
#if QT_CONFIG(xcb_xinput)
void xi2SelectStateEvents();
void xi2SelectDeviceEvents(xcb_window_t window);
diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp
index 8d151b760b..6795cb8905 100644
--- a/src/plugins/platforms/xcb/qxcbcursor.cpp
+++ b/src/plugins/platforms/xcb/qxcbcursor.cpp
@@ -626,6 +626,12 @@ xcb_cursor_t QXcbCursor::createBitmapCursor(QCursor *cursor)
}
#endif
+/*! \internal
+
+ Note that the logical state of a device (as seen by means of the protocol) may
+ lag the physical state if device event processing is frozen. See QueryPointer
+ in X11 protocol specification.
+*/
void QXcbCursor::queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask)
{
if (pos)
diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp
index 8ea0ebf966..10a827cfd9 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.cpp
+++ b/src/plugins/platforms/xcb/qxcbdrag.cpp
@@ -309,7 +309,7 @@ xcb_window_t QXcbDrag::findRealWindow(const QPoint & pos, xcb_window_t w, int md
return 0;
}
-void QXcbDrag::move(const QPoint &globalPos)
+void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
{
if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid())
@@ -470,15 +470,15 @@ void QXcbDrag::move(const QPoint &globalPos)
source_time = connection()->time();
if (w)
- handle_xdnd_position(w, &move);
+ handle_xdnd_position(w, &move, b, mods);
else
xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&move);
}
}
-void QXcbDrag::drop(const QPoint &globalPos)
+void QXcbDrag::drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
{
- QBasicDrag::drop(globalPos);
+ QBasicDrag::drop(globalPos, b, mods);
if (!current_target)
return;
@@ -522,7 +522,7 @@ void QXcbDrag::drop(const QPoint &globalPos)
}
if (w) {
- handleDrop(w, &drop);
+ handleDrop(w, &drop, b, mods);
} else {
xcb_send_event(xcb_connection(), false, current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&drop);
}
@@ -710,7 +710,8 @@ void QXcbDrag::handleEnter(QPlatformWindow *window, const xcb_client_message_eve
DEBUG() << " " << connection()->atomName(xdnd_types.at(i));
}
-void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *e)
+void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *e,
+ Qt::MouseButtons b, Qt::KeyboardModifiers mods)
{
QPoint p((e->data.data32[2] & 0xffff0000) >> 16, e->data.data32[2] & 0x0000ffff);
Q_ASSERT(w);
@@ -743,7 +744,12 @@ void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message
supported_actions = Qt::DropActions(toDropAction(e->data.data32[4]));
}
- QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(w->window(),dropData,p,supported_actions);
+ auto buttons = currentDrag() ? b : connection()->queryMouseButtons();
+ auto modifiers = currentDrag() ? mods : connection()->queryKeyboardModifiers();
+
+ QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(
+ w->window(), dropData, p, supported_actions, buttons, modifiers);
+
QRect answerRect(p + geometry.topLeft(), QSize(1,1));
answerRect = qt_response.answerRect().translated(geometry.topLeft()).intersected(geometry);
@@ -887,7 +893,7 @@ void QXcbDrag::handleLeave(QPlatformWindow *w, const xcb_client_message_event_t
DEBUG("xdnd drag leave from unexpected source (%x not %x", event->data.data32[0], xdnd_dragsource);
}
- QWindowSystemInterface::handleDrag(w->window(),0,QPoint(),Qt::IgnoreAction);
+ QWindowSystemInterface::handleDrag(w->window(), nullptr, QPoint(), Qt::IgnoreAction, 0, 0);
xdnd_dragsource = 0;
xdnd_types.clear();
@@ -899,7 +905,6 @@ void QXcbDrag::send_leave()
if (!current_target)
return;
-
xcb_client_message_event_t leave;
leave.response_type = XCB_CLIENT_MESSAGE;
leave.sequence = 0;
@@ -933,7 +938,8 @@ void QXcbDrag::send_leave()
waiting_for_status = false;
}
-void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *event)
+void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *event,
+ Qt::MouseButtons b, Qt::KeyboardModifiers mods)
{
DEBUG("xdndHandleDrop");
if (!currentWindow) {
@@ -962,9 +968,6 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e
} else {
dropData = m_dropData;
supported_drop_actions = accepted_drop_action;
-
- // Drop coming from another app? Update keyboard modifiers.
- QGuiApplicationPrivate::modifier_buttons = QGuiApplication::queryKeyboardModifiers();
}
if (!dropData)
@@ -975,7 +978,13 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e
// dropData = QDragManager::dragPrivate(X11->dndDropTransactions.at(at).object)->data;
// if we can't find it, then use the data in the drag manager
- QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(currentWindow.data(),dropData,currentPosition,supported_drop_actions);
+ auto buttons = currentDrag() ? b : connection()->queryMouseButtons();
+ auto modifiers = currentDrag() ? mods : connection()->queryKeyboardModifiers();
+
+ QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(
+ currentWindow.data(), dropData, currentPosition, supported_drop_actions,
+ buttons, modifiers);
+
setExecutedDropAction(response.acceptedAction());
xcb_client_message_event_t finished;
diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h
index 31f1c47d83..138625476a 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.h
+++ b/src/plugins/platforms/xcb/qxcbdrag.h
@@ -78,14 +78,15 @@ public:
void startDrag() override;
void cancel() override;
- void move(const QPoint &globalPos) override;
- void drop(const QPoint &globalPos) override;
+ void move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
+ void drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
void endDrag() override;
void handleEnter(QPlatformWindow *window, const xcb_client_message_event_t *event, xcb_window_t proxy = 0);
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 handleDrop(QPlatformWindow *, const xcb_client_message_event_t *event,
+ Qt::MouseButtons b = 0, Qt::KeyboardModifiers mods = 0);
void handleStatus(const xcb_client_message_event_t *event);
void handleSelectionRequest(const xcb_selection_request_event_t *event);
@@ -105,7 +106,8 @@ private:
void init();
- void handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *event);
+ void handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *event,
+ Qt::MouseButtons b = 0, Qt::KeyboardModifiers mods = 0);
void handle_xdnd_status(const xcb_client_message_event_t *event);
void send_leave();
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index 143ea799b0..9e553666b2 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -410,10 +410,7 @@ QPlatformServices *QXcbIntegration::services() const
Qt::KeyboardModifiers QXcbIntegration::queryKeyboardModifiers() const
{
- int keybMask = 0;
- QXcbConnection *conn = m_connections.at(0);
- QXcbCursor::queryPointer(conn, 0, 0, &keybMask);
- return conn->keyboard()->translateModifiers(keybMask);
+ return m_connections.at(0)->queryKeyboardModifiers();
}
QList<int> QXcbIntegration::possibleKeys(const QKeyEvent *e) const