Fixed Drag and Drop driven by touch-synthesized mouse events.

When dragging by touch driven by synthesized mouse events, the cursor
is suppressed. Use a popup window to show the drag cursor instead.

[ChangeLog][QDrag][Windows] Fixed Drag and Drop driven by touch-synthesized mouse events.

Change-Id: Id8c1aab79a091c89986ee7ee62ded44a3267fd3f
Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com>
This commit is contained in:
Friedemann Kleint 2014-01-27 13:36:35 +01:00 committed by The Qt Project
parent a46198a7b3
commit 8545ba9366

View File

@ -54,6 +54,9 @@
#include <QtGui/QMouseEvent>
#include <QtGui/QPixmap>
#include <QtGui/QPainter>
#include <QtGui/QPaintDevice>
#include <QtGui/QBackingStore>
#include <QtGui/QWindow>
#include <QtGui/QGuiApplication>
#include <qpa/qwindowsysteminterface_p.h>
#include <QtGui/private/qguiapplication_p.h>
@ -206,6 +209,77 @@ static const char * const ignoreDragCursorXpmC[] = {
".............XXaaaaXX...",
"...............XXXX....."};
/*!
\class QWindowsDragCursorWindow
\brief A toplevel window showing the drag icon in case of touch drag.
\sa QWindowsOleDropSource
\internal
\ingroup qt-lighthouse-win
*/
class QWindowsDragCursorWindow : public QWindow
{
public:
explicit QWindowsDragCursorWindow(QWindow *parent = 0);
void setPixmap(const QPixmap &p);
protected:
void exposeEvent(QExposeEvent *);
private:
void render();
QBackingStore m_backingStore;
QPixmap m_pixmap;
};
QWindowsDragCursorWindow::QWindowsDragCursorWindow(QWindow *parent)
: QWindow(parent)
, m_backingStore(this)
{
QSurfaceFormat windowFormat = format();
windowFormat.setAlphaBufferSize(8);
setFormat(windowFormat);
setObjectName(QStringLiteral("QWindowsDragCursorWindow"));
setFlags(Qt::Popup | Qt::NoDropShadowWindowHint
| Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint
| Qt::WindowDoesNotAcceptFocus | Qt::WindowTransparentForInput);
}
void QWindowsDragCursorWindow::setPixmap(const QPixmap &p)
{
if (p.cacheKey() == m_pixmap.cacheKey())
return;
const QSize oldSize = m_pixmap.size();
const QSize newSize = p.size();
qCDebug(lcQpaMime) << __FUNCTION__ << p.cacheKey() << newSize;
m_pixmap = p;
if (oldSize != newSize) {
resize(newSize);
m_backingStore.resize(newSize);
}
if (isVisible())
render();
}
void QWindowsDragCursorWindow::exposeEvent(QExposeEvent *)
{
Q_ASSERT(!m_pixmap.isNull());
render();
}
void QWindowsDragCursorWindow::render()
{
const QRect rect(QPoint(0, 0), m_pixmap.size());
m_backingStore.beginPaint(rect);
QPainter painter(m_backingStore.paintDevice());
painter.drawPixmap(0, 0, m_pixmap);
m_backingStore.endPaint();
m_backingStore.flush(rect);
}
/*!
\class QWindowsDropMimeData
\brief Special mime data class for data retrieval from Drag operations.
@ -286,6 +360,11 @@ static inline Qt::KeyboardModifiers toQtKeyboardModifiers(DWORD keyState)
class QWindowsOleDropSource : public IDropSource
{
public:
enum Mode {
MouseDrag,
TouchDrag // Mouse cursor suppressed, use window as cursor.
};
explicit QWindowsOleDropSource(QWindowsDrag *drag);
virtual ~QWindowsOleDropSource();
@ -325,9 +404,11 @@ private:
typedef ActionCursorMap::Iterator ActionCursorMapIt;
typedef ActionCursorMap::ConstIterator ActionCursorMapConstIt;
const Mode m_mode;
QWindowsDrag *m_drag;
Qt::MouseButtons m_currentButtons;
ActionCursorMap m_cursors;
QWindowsDragCursorWindow *m_touchDragWindow;
ULONG m_refs;
#ifndef QT_NO_DEBUG_OUTPUT
@ -335,16 +416,20 @@ private:
#endif
};
QWindowsOleDropSource::QWindowsOleDropSource(QWindowsDrag *drag) :
m_drag(drag), m_currentButtons(Qt::NoButton),
m_refs(1)
QWindowsOleDropSource::QWindowsOleDropSource(QWindowsDrag *drag)
: m_mode(QWindowsCursor::cursorState() != QWindowsCursor::CursorSuppressed ? MouseDrag : TouchDrag)
, m_drag(drag)
, m_currentButtons(Qt::NoButton)
, m_touchDragWindow(0)
, m_refs(1)
{
qCDebug(lcQpaMime) << __FUNCTION__;
qCDebug(lcQpaMime) << __FUNCTION__ << m_mode;
}
QWindowsOleDropSource::~QWindowsOleDropSource()
{
m_cursors.clear();
delete m_touchDragWindow;
qCDebug(lcQpaMime) << __FUNCTION__;
}
@ -517,7 +602,19 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect)
if (it != m_cursors.constEnd()) {
const CursorEntry &e = it.value();
SetCursor(e.cursor->cursor);
switch (m_mode) {
case MouseDrag:
SetCursor(e.cursor->cursor);
break;
case TouchDrag:
if (!m_touchDragWindow)
m_touchDragWindow = new QWindowsDragCursorWindow;
m_touchDragWindow->setPixmap(e.pixmap);
m_touchDragWindow->setFramePosition(QWindowsCursor::mousePosition() - e.hotSpot);
if (!m_touchDragWindow->isVisible())
m_touchDragWindow->show();
break;
}
return ResultFromScode(S_OK);
}