summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel/qguiapplication.cpp
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/gui/kernel/qguiapplication.cpp
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/gui/kernel/qguiapplication.cpp')
-rw-r--r--src/gui/kernel/qguiapplication.cpp67
1 files changed, 58 insertions, 9 deletions
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index caa8aaca4b..22f4cdeaa3 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -1679,7 +1679,7 @@ Qt::KeyboardModifiers QGuiApplication::queryKeyboardModifiers()
/*!
Returns the current state of the buttons on the mouse. The current state is
- updated syncronously as the event queue is emptied of events that will
+ updated synchronously as the event queue is emptied of events that will
spontaneously change the mouse state (QEvent::MouseButtonPress and
QEvent::MouseButtonRelease events).
@@ -3036,8 +3036,56 @@ void QGuiApplicationPrivate::processExposeEvent(QWindowSystemInterfacePrivate::E
#ifndef QT_NO_DRAGANDDROP
-QPlatformDragQtResponse QGuiApplicationPrivate::processDrag(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions)
+/*! \internal
+
+ This function updates an internal state to keep the source compatibility. Documentation of
+ QGuiApplication::mouseButtons() states - "The current state is updated synchronously as
+ the event queue is emptied of events that will spontaneously change the mouse state
+ (QEvent::MouseButtonPress and QEvent::MouseButtonRelease events)". But internally we have
+ been updating these state variables from various places to keep buttons returned by
+ mouseButtons() in sync with the systems state. This is not the documented behavior.
+
+ ### Qt6 - Remove QGuiApplication::mouseButtons()/keyboardModifiers() API? And here
+ are the reasons:
+
+ - It is an easy to misuse API by:
+
+ a) Application developers: The only place where the values of this API can be trusted is
+ when using within mouse handling callbacks. In these callbacks we work with the state
+ that was provided directly by the windowing system. Anywhere else it might not reflect what
+ user wrongly expects. We might not always receive a matching mouse release for a press event
+ (e.g. When dismissing a popup window on X11. Or when dnd enter Qt application with mouse
+ button down, we update mouse_buttons and then dnd leaves Qt application and does a drop
+ somewhere else) and hence mouseButtons() will be out-of-sync from users perspective, see
+ for example QTBUG-33161. BUT THIS IS NOT HOW THE API IS SUPPOSED TO BE USED. Since the only
+ safe place to use this API is from mouse event handlers, we might as well deprecate it and
+ pass down the button state if we are not already doing that everywhere where it matters.
+
+ b) Qt framework developers:
+
+ We see users complaining, we start adding hacks everywhere just to keep buttons in sync ;)
+ There are corner cases that can not be solved and adding this kind of hacks is never ending
+ task.
+
+ - Real mouse events, tablet mouse events, etc: all go through QGuiApplication::processMouseEvent,
+ and all share mouse_buttons. What if we want to support multiple mice in future? The API must
+ go.
+
+ - Motivation why this API is public is not clear. Could the same be achieved by a user by
+ installing an event filter?
+*/
+static void updateMouseAndModifierButtonState(Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
+{
+ QGuiApplicationPrivate::mouse_buttons = buttons;
+ QGuiApplicationPrivate::modifier_buttons = modifiers;
+}
+
+QPlatformDragQtResponse QGuiApplicationPrivate::processDrag(QWindow *w, const QMimeData *dropData,
+ const QPoint &p, Qt::DropActions supportedActions,
+ Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
{
+ updateMouseAndModifierButtonState(buttons, modifiers);
+
static QPointer<QWindow> currentDragWindow;
static Qt::DropAction lastAcceptedDropAction = Qt::IgnoreAction;
QPlatformDrag *platformDrag = platformIntegration()->drag();
@@ -3054,8 +3102,7 @@ QPlatformDragQtResponse QGuiApplicationPrivate::processDrag(QWindow *w, const QM
lastAcceptedDropAction = Qt::IgnoreAction;
return QPlatformDragQtResponse(false, lastAcceptedDropAction, QRect());
}
- QDragMoveEvent me(p, supportedActions, dropData,
- QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
+ QDragMoveEvent me(p, supportedActions, dropData, buttons, modifiers);
if (w != currentDragWindow) {
lastAcceptedDropAction = Qt::IgnoreAction;
@@ -3064,8 +3111,7 @@ QPlatformDragQtResponse QGuiApplicationPrivate::processDrag(QWindow *w, const QM
QGuiApplication::sendEvent(currentDragWindow, &e);
}
currentDragWindow = w;
- QDragEnterEvent e(p, supportedActions, dropData,
- QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
+ QDragEnterEvent e(p, supportedActions, dropData, buttons, modifiers);
QGuiApplication::sendEvent(w, &e);
if (e.isAccepted() && e.dropAction() != Qt::IgnoreAction)
lastAcceptedDropAction = e.dropAction();
@@ -3083,10 +3129,13 @@ QPlatformDragQtResponse QGuiApplicationPrivate::processDrag(QWindow *w, const QM
return QPlatformDragQtResponse(me.isAccepted(), lastAcceptedDropAction, me.answerRect());
}
-QPlatformDropQtResponse QGuiApplicationPrivate::processDrop(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions)
+QPlatformDropQtResponse QGuiApplicationPrivate::processDrop(QWindow *w, const QMimeData *dropData,
+ const QPoint &p, Qt::DropActions supportedActions,
+ Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
{
- QDropEvent de(p, supportedActions, dropData,
- QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
+ updateMouseAndModifierButtonState(buttons, modifiers);
+
+ QDropEvent de(p, supportedActions, dropData, buttons, modifiers);
QGuiApplication::sendEvent(w, &de);
Qt::DropAction acceptedAction = de.isAccepted() ? de.dropAction() : Qt::IgnoreAction;