From 6f65ddbc217a8c82b091d31e88faf3dc23baa13b Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 10 Jul 2015 13:35:11 +0200 Subject: Implement canceling of Qt-initiated drags. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add new virtual QPlatformDrag::cancelDrag() [avoiding a conflict with existing QBasicDrag::cancel()] - Implement on Windows by returning DRAGDROP_S_CANCEL from IOleDropSource::QueryContinueDrag() as suggested on report. - Implement in QBasicDrag by calling QBasicDrag::cancel() and quitting the event loop. - Add new API static void QDrag::cancel() for it. Task-number: QTBUG-47004 Change-Id: I4b4bb52e5fc226c8e04688ac1b0f9550daaf918e Reviewed-by: Jørgen Lind Reviewed-by: David Faure --- src/gui/kernel/qdrag.cpp | 19 +++++++++++++++++++ src/gui/kernel/qdrag.h | 2 ++ src/gui/kernel/qplatformdrag.cpp | 14 ++++++++++++++ src/gui/kernel/qplatformdrag.h | 1 + src/gui/kernel/qsimpledrag.cpp | 8 ++++++++ src/gui/kernel/qsimpledrag_p.h | 1 + src/plugins/platforms/windows/qwindowsdrag.cpp | 5 ++++- src/plugins/platforms/windows/qwindowsdrag.h | 4 ++++ 8 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/gui/kernel/qdrag.cpp b/src/gui/kernel/qdrag.cpp index 2736fac8e0..36527966b7 100644 --- a/src/gui/kernel/qdrag.cpp +++ b/src/gui/kernel/qdrag.cpp @@ -33,6 +33,8 @@ #include #include "private/qguiapplication_p.h" +#include "qpa/qplatformintegration.h" +#include "qpa/qplatformdrag.h" #include #include #include "qdnd_p.h" @@ -223,6 +225,8 @@ QObject *QDrag::target() const loop. Other events are still delivered to the application while the operation is performed. On Windows, the Qt event loop is blocked during the operation. + + \sa cancel() */ Qt::DropAction QDrag::exec(Qt::DropActions supportedActions) @@ -377,6 +381,21 @@ Qt::DropAction QDrag::defaultAction() const Q_D(const QDrag); return d->default_action; } + +/*! + Cancels a drag operation initiated by Qt. + + \note This is currently implemented on Windows and X11. + + \since 5.6 + \sa exec() +*/ +void QDrag::cancel() +{ + if (QPlatformDrag *platformDrag = QGuiApplicationPrivate::platformIntegration()->drag()) + platformDrag->cancelDrag(); +} + /*! \fn void QDrag::actionChanged(Qt::DropAction action) diff --git a/src/gui/kernel/qdrag.h b/src/gui/kernel/qdrag.h index 0672cb00f9..961d7c89d9 100644 --- a/src/gui/kernel/qdrag.h +++ b/src/gui/kernel/qdrag.h @@ -77,6 +77,8 @@ public: Qt::DropActions supportedActions() const; Qt::DropAction defaultAction() const; + static void cancel(); + Q_SIGNALS: void actionChanged(Qt::DropAction action); void targetChanged(QObject *newTarget); diff --git a/src/gui/kernel/qplatformdrag.cpp b/src/gui/kernel/qplatformdrag.cpp index d789c75d1d..11230194fc 100644 --- a/src/gui/kernel/qplatformdrag.cpp +++ b/src/gui/kernel/qplatformdrag.cpp @@ -154,6 +154,20 @@ Qt::DropAction QPlatformDrag::defaultAction(Qt::DropActions possibleActions, return default_action; } +/*! + \brief Cancels the currently active drag (only for drags of + the current application initiated by QPlatformDrag::drag()). + + The default implementation does nothing. + + \since 5.6 + */ + +void QPlatformDrag::cancelDrag() +{ + Q_UNIMPLEMENTED(); +} + /*! \brief Called to notify QDrag about changes of the current action. */ diff --git a/src/gui/kernel/qplatformdrag.h b/src/gui/kernel/qplatformdrag.h index 10ee88477f..72e28d2745 100644 --- a/src/gui/kernel/qplatformdrag.h +++ b/src/gui/kernel/qplatformdrag.h @@ -92,6 +92,7 @@ public: virtual QMimeData *platformDropData() = 0; virtual Qt::DropAction drag(QDrag *m_drag) = 0; + virtual void cancelDrag(); void updateAction(Qt::DropAction action); virtual Qt::DropAction defaultAction(Qt::DropActions possibleActions, Qt::KeyboardModifiers modifiers) const; diff --git a/src/gui/kernel/qsimpledrag.cpp b/src/gui/kernel/qsimpledrag.cpp index 6acac4cade..d2efeaca28 100644 --- a/src/gui/kernel/qsimpledrag.cpp +++ b/src/gui/kernel/qsimpledrag.cpp @@ -191,6 +191,14 @@ Qt::DropAction QBasicDrag::drag(QDrag *o) return m_executed_drop_action; } +void QBasicDrag::cancelDrag() +{ + if (m_eventLoop) { + cancel(); + m_eventLoop->quit(); + } +} + void QBasicDrag::restoreCursor() { if (m_restoreCursor) { diff --git a/src/gui/kernel/qsimpledrag_p.h b/src/gui/kernel/qsimpledrag_p.h index 4c9edbae05..34679a7540 100644 --- a/src/gui/kernel/qsimpledrag_p.h +++ b/src/gui/kernel/qsimpledrag_p.h @@ -66,6 +66,7 @@ public: virtual ~QBasicDrag(); virtual Qt::DropAction drag(QDrag *drag) Q_DECL_OVERRIDE; + void cancelDrag() Q_DECL_OVERRIDE; virtual bool eventFilter(QObject *o, QEvent *e) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 955f5792a9..719553fa7c 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -397,7 +397,7 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) { HRESULT hr = S_OK; do { - if (fEscapePressed) { + if (fEscapePressed || QWindowsDrag::isCanceled()) { hr = ResultFromScode(DRAGDROP_S_CANCEL); break; } @@ -677,6 +677,8 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, \ingroup qt-lighthouse-win */ +bool QWindowsDrag::m_canceled = false; + QWindowsDrag::QWindowsDrag() : m_dropDataObject(0), m_cachedDropTargetHelper(0) { @@ -806,6 +808,7 @@ Qt::DropAction QWindowsDrag::drag(QDrag *drag) Qt::DropAction dragResult = Qt::IgnoreAction; DWORD resultEffect; + QWindowsDrag::m_canceled = false; QWindowsOleDropSource *windowDropSource = new QWindowsOleDropSource(this); windowDropSource->createCursors(); QWindowsOleDataObject *dropDataObject = new QWindowsOleDataObject(dropData); diff --git a/src/plugins/platforms/windows/qwindowsdrag.h b/src/plugins/platforms/windows/qwindowsdrag.h index 9a5e0b17f2..b031faa884 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.h +++ b/src/plugins/platforms/windows/qwindowsdrag.h @@ -87,6 +87,8 @@ public: Qt::DropAction drag(QDrag *drag) Q_DECL_OVERRIDE; static QWindowsDrag *instance(); + void cancelDrag() Q_DECL_OVERRIDE { QWindowsDrag::m_canceled = true; } + static bool isCanceled() { return QWindowsDrag::m_canceled; } IDataObject *dropDataObject() const { return m_dropDataObject; } void setDropDataObject(IDataObject *dataObject) { m_dropDataObject = dataObject; } @@ -98,6 +100,8 @@ public: QPixmap defaultCursor(Qt::DropAction action) const; private: + static bool m_canceled; + QWindowsDropMimeData m_dropData; IDataObject *m_dropDataObject; -- cgit v1.2.3