summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>2012-02-22 10:58:28 +0100
committerQt by Nokia <qt-info@nokia.com>2012-02-29 20:10:30 +0100
commit3a72a1c7ed5adcdf3e473b50cc9c932e9290ee81 (patch)
treec9c6ab476e935c1141675382c051ef86e003440d
parent70784b9069fbd1c73eddbbfc83ffb44b2ca15854 (diff)
Refactor the QPA dnd interface.
- Give QPlatformDrag a synchronous drag() function returning the Qt::DropAction - Move the base functionality for asynchronous event handling to the platformsupport library as QBasicDrag (extendable base class handling drag icon and providing new virtuals) and QSimpleDrag (sample implementation for drag within the Qt application). - Change the Windows implementation accordingly. - Change XCB to be based on QBasicDrag. - Clean up QDragManager. Change-Id: I654f76f0e55a385ba189bd74f3ceaded6a8fe318 Reviewed-by: Morten Johan Sørvig <morten.sorvig@nokia.com>
-rw-r--r--src/gui/kernel/kernel.pri1
-rw-r--r--src/gui/kernel/qdnd.cpp402
-rw-r--r--src/gui/kernel/qdnd_p.h87
-rw-r--r--src/gui/kernel/qdrag.cpp89
-rw-r--r--src/gui/kernel/qdrag.h5
-rw-r--r--src/gui/kernel/qevent.cpp5
-rw-r--r--src/gui/kernel/qguiapplication.cpp57
-rw-r--r--src/gui/kernel/qguiapplication_p.h6
-rw-r--r--src/gui/kernel/qplatformdrag_qpa.cpp187
-rw-r--r--src/gui/kernel/qplatformdrag_qpa.h49
-rw-r--r--src/gui/kernel/qwindowsysteminterface_qpa.cpp9
-rw-r--r--src/gui/kernel/qwindowsysteminterface_qpa.h6
-rw-r--r--src/platformsupport/dnd/dnd.pri6
-rw-r--r--src/platformsupport/dnd/qshapedpixmapdndwindow.cpp100
-rw-r--r--src/platformsupport/dnd/qshapedpixmapdndwindow_p.h78
-rw-r--r--src/platformsupport/dnd/qsimpledrag.cpp318
-rw-r--r--src/platformsupport/dnd/qsimpledrag_p.h64
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.cpp278
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.h14
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp4
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.cpp396
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.h45
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp6
-rw-r--r--src/widgets/itemviews/qitemdelegate.cpp6
-rw-r--r--src/widgets/itemviews/qstyleditemdelegate.cpp6
25 files changed, 1154 insertions, 1070 deletions
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri
index 9c5f3b10da..2656d8ffdb 100644
--- a/src/gui/kernel/kernel.pri
+++ b/src/gui/kernel/kernel.pri
@@ -66,6 +66,7 @@ SOURCES += \
kernel/qwindowsysteminterface_qpa.cpp \
kernel/qplatforminputcontext_qpa.cpp \
kernel/qplatformintegration_qpa.cpp \
+ kernel/qplatformdrag_qpa.cpp \
kernel/qplatformscreen_qpa.cpp \
kernel/qplatformintegrationfactory_qpa.cpp \
kernel/qplatformintegrationplugin_qpa.cpp \
diff --git a/src/gui/kernel/qdnd.cpp b/src/gui/kernel/qdnd.cpp
index 2fb250cf18..1ed4a96192 100644
--- a/src/gui/kernel/qdnd.cpp
+++ b/src/gui/kernel/qdnd.cpp
@@ -125,417 +125,79 @@ QString KeyboardModifiersToString(Qt::KeyboardModifiers moderfies)
#endif
// the universe's only drag manager
-QDragManager *QDragManager::instance = 0;
+QDragManager *QDragManager::m_instance = 0;
QDragManager::QDragManager()
- : QObject(qApp)
+ : QObject(qApp), m_platformDropData(0), m_currentDropTarget(0),
+ m_platformDrag(QGuiApplicationPrivate::platformIntegration()->drag()),
+ m_object(0)
{
- Q_ASSERT(!instance);
+ Q_ASSERT(!m_instance);
- object = 0;
- beingCancelled = false;
- restoreCursor = false;
- willDrop = false;
- eventLoop = 0;
- currentDropTarget = 0;
- shapedPixmapWindow = 0;
-
- possible_actions = Qt::IgnoreAction;
-
- QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration();
- platformDrag = pi->drag();
-
- platformDropData = 0;
- if (platformDrag)
- platformDropData = platformDrag->platformDropData();
+ if (m_platformDrag)
+ m_platformDropData = m_platformDrag->platformDropData();
}
QDragManager::~QDragManager()
{
-#ifndef QT_NO_CURSOR
- if (restoreCursor)
- QGuiApplication::restoreOverrideCursor();
-#endif
- instance = 0;
+ m_instance = 0;
}
QDragManager *QDragManager::self()
{
- if (!instance && !QGuiApplication::closingDown())
- instance = new QDragManager;
- return instance;
+ if (!m_instance && !QGuiApplication::closingDown())
+ m_instance = new QDragManager;
+ return m_instance;
}
-QPixmap QDragManager::dragCursor(Qt::DropAction action) const
+QObject *QDragManager::source() const
{
- typedef QMap<Qt::DropAction, QPixmap>::const_iterator Iterator;
-
- if (const QDragPrivate *d = dragPrivate()) {
- const Iterator it = d->customCursors.constFind(action);
- if (it != d->customCursors.constEnd())
- return it.value();
- }
-
- Qt::CursorShape shape = Qt::ForbiddenCursor;
- switch (action) {
- case Qt::MoveAction:
- shape = Qt::DragMoveCursor;
- break;
- case Qt::CopyAction:
- shape = Qt::DragCopyCursor;
- break;
- case Qt::LinkAction:
- shape = Qt::DragLinkCursor;
- break;
- default:
- shape = Qt::ForbiddenCursor;
- }
- return QGuiApplicationPrivate::instance()->getPixmapCursor(shape);
-}
-
-Qt::DropAction QDragManager::defaultAction(Qt::DropActions possibleActions,
- Qt::KeyboardModifiers modifiers) const
-{
-#ifdef QDND_DEBUG
- qDebug("QDragManager::defaultAction(Qt::DropActions possibleActions)");
- qDebug("keyboard modifiers : %s", KeyboardModifiersToString(modifiers).latin1());
-#endif
-
- QDragPrivate *d = dragPrivate();
- Qt::DropAction defaultAction = d ? d->defaultDropAction : Qt::IgnoreAction;
-
- if (defaultAction == Qt::IgnoreAction) {
- //This means that the drag was initiated by QDrag::start and we need to
- //preserve the old behavior
- defaultAction = Qt::CopyAction;
- }
-
- if (modifiers & Qt::ControlModifier && modifiers & Qt::ShiftModifier)
- defaultAction = Qt::LinkAction;
- else if (modifiers & Qt::ControlModifier)
- defaultAction = Qt::CopyAction;
- else if (modifiers & Qt::ShiftModifier)
- defaultAction = Qt::MoveAction;
- else if (modifiers & Qt::AltModifier)
- defaultAction = Qt::LinkAction;
-
-#ifdef QDND_DEBUG
- qDebug("possible actions : %s", dragActionsToString(possibleActions).latin1());
-#endif
-
- // Check if the action determined is allowed
- if (!(possibleActions & defaultAction)) {
- if (possibleActions & Qt::CopyAction)
- defaultAction = Qt::CopyAction;
- else if (possibleActions & Qt::MoveAction)
- defaultAction = Qt::MoveAction;
- else if (possibleActions & Qt::LinkAction)
- defaultAction = Qt::LinkAction;
- else
- defaultAction = Qt::IgnoreAction;
- }
-
-#ifdef QDND_DEBUG
- qDebug("default action : %s", dragActionsToString(defaultAction).latin1());
-#endif
-
- return defaultAction;
+ if (m_object)
+ return m_object->source();
+ return 0;
}
void QDragManager::setCurrentTarget(QObject *target, bool dropped)
{
- if (currentDropTarget == target)
+ if (m_currentDropTarget == target)
return;
- currentDropTarget = target;
- if (!dropped && object) {
- object->d_func()->target = target;
- emit object->targetChanged(target);
+ m_currentDropTarget = target;
+ if (!dropped && m_object) {
+ m_object->d_func()->target = target;
+ emit m_object->targetChanged(target);
}
-
}
-QObject *QDragManager::currentTarget()
+QObject *QDragManager::currentTarget() const
{
- return currentDropTarget;
-}
-
-
-static const int default_pm_hotx = -2;
-static const int default_pm_hoty = -16;
-static const char *const default_pm[] = {
-"13 9 3 1",
-". c None",
-" c #000000",
-"X c #FFFFFF",
-"X X X X X X X",
-" X X X X X X ",
-"X ......... X",
-" X.........X ",
-"X ......... X",
-" X.........X ",
-"X ......... X",
-" X X X X X X ",
-"X X X X X X X",
-};
-
-
-QShapedPixmapWindow::QShapedPixmapWindow()
- : QWindow()
-{
- setSurfaceType(RasterSurface);
- setWindowFlags(Qt::Tool | Qt::FramelessWindowHint |
- Qt::X11BypassWindowManagerHint | Qt::WindowTransparentForInput);
- create();
- backingStore = new QBackingStore(this);
-}
-
-void QShapedPixmapWindow::render()
-{
- QRect rect(QPoint(), geometry().size());
- backingStore->resize(rect.size());
-
- backingStore->beginPaint(rect);
-
- QPaintDevice *device = backingStore->paintDevice();
-
- {
- QPainter p(device);
- p.drawPixmap(0, 0, pixmap);
- }
-
- backingStore->endPaint();
- backingStore->flush(rect);
-}
-
-
-
-
-static Qt::KeyboardModifiers oldstate;
-
-void QDragManager::updatePixmap()
-{
- if (shapedPixmapWindow) {
- shapedPixmapWindow->pixmap = QPixmap();
- shapedPixmapWindow->hotSpot = QPoint(default_pm_hotx,default_pm_hoty);
- if (object) {
- shapedPixmapWindow->pixmap = object->pixmap();
- if (!shapedPixmapWindow->pixmap.isNull())
- shapedPixmapWindow->hotSpot = object->hotSpot();
- }
- if (shapedPixmapWindow->pixmap.isNull())
- shapedPixmapWindow->pixmap = QPixmap(default_pm);
- shapedPixmapWindow->setGeometry(QRect(QCursor::pos() - shapedPixmapWindow->hotSpot, shapedPixmapWindow->pixmap.size()));
- shapedPixmapWindow->show();
- shapedPixmapWindow->render();
- }
-}
-
-void QDragManager::updateCursor()
-{
- if (shapedPixmapWindow) {
- shapedPixmapWindow->render(); // ### Hack
- shapedPixmapWindow->move(QCursor::pos() - shapedPixmapWindow->hotSpot);
- }
-
- Qt::CursorShape cursorShape = Qt::ForbiddenCursor;
- if (willDrop) {
- if (global_accepted_action == Qt::CopyAction) {
- cursorShape = Qt::DragCopyCursor;
- } else if (global_accepted_action == Qt::LinkAction) {
- cursorShape = Qt::DragLinkCursor;
- } else {
- cursorShape = Qt::DragMoveCursor;
- }
- }
- QCursor *cursor = qApp->overrideCursor();
- if (cursor && cursorShape != cursor->shape())
- qApp->changeOverrideCursor(QCursor(cursorShape));
-}
-
-
-bool QDragManager::eventFilter(QObject *o, QEvent *e)
-{
- if (beingCancelled) {
- if (e->type() == QEvent::KeyRelease && static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) {
- qApp->removeEventFilter(this);
- Q_ASSERT(object == 0);
- beingCancelled = false;
- eventLoop->exit();
- return true; // block the key release
- }
- return false;
- }
-
- Q_ASSERT(object != 0);
-
- if (!qobject_cast<QWindow *>(o))
- return false;
-
- switch(e->type()) {
- case QEvent::ShortcutOverride:
- // prevent accelerators from firing while dragging
- e->accept();
- return true;
-
- case QEvent::KeyPress:
- case QEvent::KeyRelease:
- {
- QKeyEvent *ke = static_cast<QKeyEvent *>(e);
- if (ke->key() == Qt::Key_Escape && e->type() == QEvent::KeyPress) {
- cancel();
- qApp->removeEventFilter(this);
- beingCancelled = false;
- eventLoop->exit();
- } else {
- // ### x11 forces move!
- updateCursor();
- }
- return true; // Eat all key events
- }
-
- case QEvent::MouseMove:
- move(static_cast<QMouseEvent *>(e));
- return true; // Eat all mouse events
-
- case QEvent::MouseButtonRelease:
- qApp->removeEventFilter(this);
- if (willDrop)
- drop(static_cast<QMouseEvent *>(e));
- else
- cancel();
- beingCancelled = false;
- eventLoop->exit();
- return true; // Eat all mouse events
-
- case QEvent::MouseButtonPress:
- case QEvent::MouseButtonDblClick:
- case QEvent::Wheel:
- return true;
- default:
- break;
- }
- return false;
+ return m_currentDropTarget;
}
Qt::DropAction QDragManager::drag(QDrag *o)
{
- if (!o || object == o)
+ if (!o || m_object == o)
return Qt::IgnoreAction;
- if (!platformDrag || !o->source()) {
+ if (!m_platformDrag || !o->source()) {
o->deleteLater();
return Qt::IgnoreAction;
}
- if (object) {
- cancel();
- qApp->removeEventFilter(this);
- beingCancelled = false;
- }
-
- object = o;
- if (!shapedPixmapWindow)
- shapedPixmapWindow = new QShapedPixmapWindow();
- oldstate = Qt::NoModifier; // #### Should use state that caused the drag
-// drag_mode = mode;
-
- possible_actions = dragPrivate()->possible_actions;
-
- willDrop = false;
- object->d_func()->target = 0;
- qApp->installEventFilter(this);
-
- global_accepted_action = Qt::CopyAction;
-#ifndef QT_NO_CURSOR
- qApp->setOverrideCursor(Qt::DragCopyCursor);
- restoreCursor = true;
- updateCursor();
-#endif
- updatePixmap();
-
- platformDrag->startDrag();
-
- eventLoop = new QEventLoop;
- (void) eventLoop->exec();
- delete eventLoop;
- eventLoop = 0;
-
- delete shapedPixmapWindow;
- shapedPixmapWindow = 0;
-
- return global_accepted_action;
-}
-
-void QDragManager::move(const QMouseEvent *me)
-{
- if (!platformDrag)
- return;
-
- platformDrag->move(me);
-}
-
-void QDragManager::drop(const QMouseEvent *me)
-{
- if (!platformDrag)
- return;
-
-#ifndef QT_NO_CURSOR
- if (restoreCursor) {
- QGuiApplication::restoreOverrideCursor();
- restoreCursor = false;
- }
-#endif
- willDrop = false;
-
- platformDrag->drop(me);
-
- if (object)
- object->deleteLater();
- object = 0;
-}
-
-void QDragManager::cancel(bool deleteSource)
-{
- if (!platformDrag)
- return;
-
-#ifndef QT_NO_CURSOR
- if (restoreCursor) {
- QGuiApplication::restoreOverrideCursor();
- restoreCursor = false;
+ if (m_object) {
+ qWarning("QDragManager::drag in possibly invalid state");
+ return Qt::IgnoreAction;
}
-#endif
-
- beingCancelled = true;
- platformDrag->cancel();
+ m_object = o;
- if (object && deleteSource)
- object->deleteLater();
- object = 0;
+ m_object->d_func()->target = 0;
- global_accepted_action = Qt::IgnoreAction;
-}
-
-/*!
- Called from startDrag() in QPlatformDrag implementations that do not need
- the desktop-oriented stuff provided by the event filter (e.g. because their
- drag is not based on mouse events). Instead, they will manage everything on
- their own, will not rely on move/drop/cancel, and will call stopDrag() to stop
- the event loop when the drag is over.
- */
-void QDragManager::unmanageEvents()
-{
- qApp->removeEventFilter(this);
-}
-
-void QDragManager::stopDrag()
-{
- if (eventLoop)
- eventLoop->exit();
+ const Qt::DropAction result = m_platformDrag->drag(m_object);
+ m_object = 0;
+ return result;
}
#endif // QT_NO_DRAGANDDROP
diff --git a/src/gui/kernel/qdnd_p.h b/src/gui/kernel/qdnd_p.h
index 857be34d10..764b73c06f 100644
--- a/src/gui/kernel/qdnd_p.h
+++ b/src/gui/kernel/qdnd_p.h
@@ -98,100 +98,45 @@ protected:
class QDragPrivate : public QObjectPrivate
{
public:
+ QDragPrivate()
+ : source(0)
+ , target(0)
+ , data(0)
+ { }
QObject *source;
QObject *target;
QMimeData *data;
QPixmap pixmap;
QPoint hotspot;
- Qt::DropActions possible_actions;
Qt::DropAction executed_action;
+ Qt::DropActions supported_actions;
+ Qt::DropAction default_action;
QMap<Qt::DropAction, QPixmap> customCursors;
- Qt::DropAction defaultDropAction;
};
-class QShapedPixmapWindow : public QWindow
-{
-public:
- QShapedPixmapWindow();
-
- void exposeEvent(QExposeEvent *)
- {
- render();
- }
-
- void render();
-
- QBackingStore *backingStore;
- QPixmap pixmap;
- QPoint hotSpot;
-};
-
-
class Q_GUI_EXPORT QDragManager : public QObject {
Q_OBJECT
- // only friend classes can use QDragManager.
- friend class QDrag;
- friend class QDragMoveEvent;
- friend class QDropEvent;
- friend class QApplication;
-
- bool eventFilter(QObject *, QEvent *);
-
public:
QDragManager();
~QDragManager();
static QDragManager *self();
- virtual Qt::DropAction drag(QDrag *);
-
- virtual void cancel(bool deleteSource = true);
- virtual void move(const QMouseEvent *me);
- virtual void drop(const QMouseEvent *me);
-
- void updatePixmap();
- void updateCursor();
-
- Qt::DropAction defaultAction(Qt::DropActions possibleActions,
- Qt::KeyboardModifiers modifiers) const;
-
- QPixmap dragCursor(Qt::DropAction action) const;
-
- QDragPrivate *dragPrivate() const { return object ? object->d_func() : 0; }
-
- inline QMimeData *dropData()
- { return object ? dragPrivate()->data : platformDropData; }
-
- void emitActionChanged(Qt::DropAction newAction) { if (object) emit object->actionChanged(newAction); }
+ Qt::DropAction drag(QDrag *);
void setCurrentTarget(QObject *target, bool dropped = false);
- QObject *currentTarget();
+ QObject *currentTarget() const;
- QDrag *object;
-
- bool beingCancelled;
- bool restoreCursor;
- bool willDrop;
- QEventLoop *eventLoop;
-
- Qt::DropActions possible_actions;
- // Shift/Ctrl handling, and final drop status
- Qt::DropAction global_accepted_action;
-
- QShapedPixmapWindow *shapedPixmapWindow;
-
- void unmanageEvents();
- void stopDrag();
+ QDrag *object() const { return m_object; }
+ QObject *source() const;
private:
- QMimeData *platformDropData;
-
- Qt::DropAction currentActionForOverrideCursor;
- QObject *currentDropTarget;
-
- QPlatformDrag *platformDrag;
+ QMimeData *m_platformDropData;
+ QObject *m_currentDropTarget;
+ QPlatformDrag *m_platformDrag;
+ QDrag *m_object;
- static QDragManager *instance;
+ static QDragManager *m_instance;
Q_DISABLE_COPY(QDragManager)
};
diff --git a/src/gui/kernel/qdrag.cpp b/src/gui/kernel/qdrag.cpp
index 694b12a180..ead0805bd1 100644
--- a/src/gui/kernel/qdrag.cpp
+++ b/src/gui/kernel/qdrag.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include <qdrag.h>
+#include "private/qguiapplication_p.h"
#include <qpixmap.h>
#include <qpoint.h>
#include "qdnd_p.h"
@@ -114,9 +115,9 @@ QDrag::QDrag(QObject *dragSource)
d->target = 0;
d->data = 0;
d->hotspot = QPoint(-10, -10);
- d->possible_actions = Qt::CopyAction;
d->executed_action = Qt::IgnoreAction;
- d->defaultDropAction = Qt::IgnoreAction;
+ d->supported_actions = Qt::IgnoreAction;
+ d->default_action = Qt::IgnoreAction;
}
/*!
@@ -126,9 +127,6 @@ QDrag::~QDrag()
{
Q_D(QDrag);
delete d->data;
- QDragManager *manager = QDragManager::self();
- if (manager && manager->object == this)
- manager->cancel(false);
}
/*!
@@ -264,24 +262,22 @@ Qt::DropAction QDrag::exec(Qt::DropActions supportedActions, Qt::DropAction defa
qWarning("QDrag: No mimedata set before starting the drag");
return d->executed_action;
}
- QDragManager *manager = QDragManager::self();
- d->defaultDropAction = Qt::IgnoreAction;
- d->possible_actions = supportedActions;
-
- if (manager) {
- if (defaultDropAction == Qt::IgnoreAction) {
- if (supportedActions & Qt::MoveAction) {
- d->defaultDropAction = Qt::MoveAction;
- } else if (supportedActions & Qt::CopyAction) {
- d->defaultDropAction = Qt::CopyAction;
- } else if (supportedActions & Qt::LinkAction) {
- d->defaultDropAction = Qt::LinkAction;
- }
- } else {
- d->defaultDropAction = defaultDropAction;
+ Qt::DropAction transformedDefaultDropAction = Qt::IgnoreAction;
+
+ if (defaultDropAction == Qt::IgnoreAction) {
+ if (supportedActions & Qt::MoveAction) {
+ transformedDefaultDropAction = Qt::MoveAction;
+ } else if (supportedActions & Qt::CopyAction) {
+ transformedDefaultDropAction = Qt::CopyAction;
+ } else if (supportedActions & Qt::LinkAction) {
+ transformedDefaultDropAction = Qt::LinkAction;
}
- d->executed_action = manager->drag(this);
+ } else {
+ transformedDefaultDropAction = defaultDropAction;
}
+ d->supported_actions = supportedActions;
+ d->default_action = transformedDefaultDropAction;
+ d->executed_action = QDragManager::self()->drag(this);
return d->executed_action;
}
@@ -308,11 +304,9 @@ Qt::DropAction QDrag::start(Qt::DropActions request)
qWarning("QDrag: No mimedata set before starting the drag");
return d->executed_action;
}
- QDragManager *manager = QDragManager::self();
- d->defaultDropAction = Qt::IgnoreAction;
- d->possible_actions = request | Qt::CopyAction;
- if (manager)
- d->executed_action = manager->drag(this);
+ d->supported_actions = request | Qt::CopyAction;
+ d->default_action = Qt::IgnoreAction;
+ d->executed_action = QDragManager::self()->drag(this);
return d->executed_action;
}
@@ -336,6 +330,49 @@ void QDrag::setDragCursor(const QPixmap &cursor, Qt::DropAction action)
}
/*!
+ Returns the drag cursor for the \a action.
+
+ \since 5.0
+*/
+
+QPixmap QDrag::dragCursor(Qt::DropAction action) const
+{
+ typedef QMap<Qt::DropAction, QPixmap>::const_iterator Iterator;
+
+ Q_D(const QDrag);
+ const Iterator it = d->customCursors.constFind(action);
+ if (it != d->customCursors.constEnd())
+ return it.value();
+
+ Qt::CursorShape shape = Qt::ForbiddenCursor;
+ switch (action) {
+ case Qt::MoveAction:
+ shape = Qt::DragMoveCursor;
+ break;
+ case Qt::CopyAction:
+ shape = Qt::DragCopyCursor;
+ break;
+ case Qt::LinkAction:
+ shape = Qt::DragLinkCursor;
+ break;
+ default:
+ shape = Qt::ForbiddenCursor;
+ }
+ return QGuiApplicationPrivate::instance()->getPixmapCursor(shape);
+}
+
+Qt::DropActions QDrag::supportedActions() const
+{
+ Q_D(const QDrag);
+ return d->supported_actions;
+}
+
+Qt::DropAction QDrag::defaultAction() const
+{
+ Q_D(const QDrag);
+ return d->default_action;
+}
+/*!
\fn void QDrag::actionChanged(Qt::DropAction action)
This signal is emitted when the \a action associated with the
diff --git a/src/gui/kernel/qdrag.h b/src/gui/kernel/qdrag.h
index 0a1ddff2d9..de84b6588b 100644
--- a/src/gui/kernel/qdrag.h
+++ b/src/gui/kernel/qdrag.h
@@ -56,6 +56,7 @@ class QPixmap;
class QPoint;
class QDragManager;
+
class Q_GUI_EXPORT QDrag : public QObject
{
Q_OBJECT
@@ -81,6 +82,10 @@ public:
Qt::DropAction exec(Qt::DropActions supportedActions, Qt::DropAction defaultAction);
void setDragCursor(const QPixmap &cursor, Qt::DropAction action);
+ QPixmap dragCursor(Qt::DropAction action) const;
+
+ Qt::DropActions supportedActions() const;
+ Qt::DropAction defaultAction() const;
Q_SIGNALS:
void actionChanged(Qt::DropAction action);
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index 281d4f61bc..ee121f2071 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -2295,8 +2295,9 @@ QDropEvent::~QDropEvent()
*/
QObject* QDropEvent::source() const
{
- QDragManager *manager = QDragManager::self();
- return (manager && manager->object) ? manager->object->source() : 0;
+ if (const QDragManager *manager = QDragManager::self())
+ return manager->source();
+ return 0;
}
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 1cd448a6bb..09d4e98c3c 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -73,8 +73,11 @@
#include "private/qwindowsysteminterface_qpa_p.h"
#include "private/qwindow_p.h"
#include "private/qcursor_p.h"
+
#include "private/qdnd_p.h"
#include <private/qplatformthemefactory_qpa_p.h>
+#include "qplatformdrag_qpa.h"
+
#ifndef QT_NO_CURSOR
#include "qplatformcursor_qpa.h"
#endif
@@ -326,8 +329,7 @@ QGuiApplication::QGuiApplication(int &argc, char **argv, int flags)
QGuiApplication::QGuiApplication(QGuiApplicationPrivate &p)
: QCoreApplication(p)
{
- d_func()->init();
-}
+ d_func()->init(); }
/*!
Destructs the application.
@@ -1547,49 +1549,62 @@ void QGuiApplicationPrivate::processExposeEvent(QWindowSystemInterfacePrivate::E
QCoreApplication::sendSpontaneousEvent(window, &exposeEvent);
}
-Qt::DropAction QGuiApplicationPrivate::processDrag(QWindow *w, QMimeData *dropData, const QPoint &p)
+QPlatformDragQtResponse QGuiApplicationPrivate::processDrag(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions)
{
static QPointer<QWindow> currentDragWindow;
- QDragManager *manager = QDragManager::self();
+ static Qt::DropAction lastAcceptedDropAction = Qt::IgnoreAction;
+ QPlatformDrag *platformDrag = platformIntegration()->drag();
+ if (!platformDrag) {
+ lastAcceptedDropAction = Qt::IgnoreAction;
+ return QPlatformDragQtResponse(false, lastAcceptedDropAction, QRect());
+ }
+
if (!dropData) {
if (currentDragWindow.data() == w)
currentDragWindow = 0;
QDragLeaveEvent e;
QGuiApplication::sendEvent(w, &e);
- manager->global_accepted_action = Qt::IgnoreAction;
- return Qt::IgnoreAction;
+ lastAcceptedDropAction = Qt::IgnoreAction;
+ return QPlatformDragQtResponse(false, lastAcceptedDropAction, QRect());
}
- QDragMoveEvent me(p, manager->possible_actions, dropData,
+ QDragMoveEvent me(p, supportedActions, dropData,
QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
+
if (w != currentDragWindow) {
+ lastAcceptedDropAction = Qt::IgnoreAction;
if (currentDragWindow) {
QDragLeaveEvent e;
QGuiApplication::sendEvent(currentDragWindow, &e);
- manager->global_accepted_action = Qt::IgnoreAction;
}
currentDragWindow = w;
- QDragEnterEvent e(p, manager->possible_actions, dropData,
+ QDragEnterEvent e(p, supportedActions, dropData,
QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
QGuiApplication::sendEvent(w, &e);
- manager->global_accepted_action = e.isAccepted() ? e.dropAction() : Qt::IgnoreAction;
- if (manager->global_accepted_action != Qt::IgnoreAction) {
- me.setDropAction(manager->global_accepted_action);
- me.accept();
- }
+ if (e.isAccepted() && e.dropAction() != Qt::IgnoreAction)
+ lastAcceptedDropAction = e.dropAction();
+ }
+
+ // Handling 'DragEnter' should suffice for the application.
+ if (lastAcceptedDropAction != Qt::IgnoreAction
+ && (supportedActions & lastAcceptedDropAction)) {
+ me.setDropAction(lastAcceptedDropAction);
+ me.accept();
}
QGuiApplication::sendEvent(w, &me);
- manager->global_accepted_action = me.isAccepted() ? me.dropAction() : Qt::IgnoreAction;
- return manager->global_accepted_action;
+ lastAcceptedDropAction = me.isAccepted() ?
+ me.dropAction() : Qt::IgnoreAction;
+ return QPlatformDragQtResponse(me.isAccepted(), lastAcceptedDropAction, me.answerRect());
}
-Qt::DropAction QGuiApplicationPrivate::processDrop(QWindow *w, QMimeData *dropData, const QPoint &p)
+QPlatformDropQtResponse QGuiApplicationPrivate::processDrop(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions)
{
- QDragManager *manager = QDragManager::self();
- QDropEvent de(p, manager->possible_actions, dropData,
+ QDropEvent de(p, supportedActions, dropData,
QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
QGuiApplication::sendEvent(w, &de);
- manager->global_accepted_action = de.isAccepted() ? de.dropAction() : Qt::IgnoreAction;
- return manager->global_accepted_action;
+
+ Qt::DropAction acceptedAction = de.isAccepted() ? de.dropAction() : Qt::IgnoreAction;
+ QPlatformDropQtResponse response(de.isAccepted(),acceptedAction);
+ return response;
}
#ifndef QT_NO_CLIPBOARD
diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h
index 68546ce0cf..d9477a3e9e 100644
--- a/src/gui/kernel/qguiapplication_p.h
+++ b/src/gui/kernel/qguiapplication_p.h
@@ -53,6 +53,8 @@
#include "private/qwindowsysteminterface_qpa_p.h"
#include "private/qshortcutmap_p.h"
+#include "qplatformdrag_qpa.h"
+
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
@@ -121,8 +123,8 @@ public:
static void processExposeEvent(QWindowSystemInterfacePrivate::ExposeEvent *e);
- static Qt::DropAction processDrag(QWindow *w, QMimeData *dropData, const QPoint &p);
- static Qt::DropAction processDrop(QWindow *w, QMimeData *dropData, const QPoint &p);
+ static QPlatformDragQtResponse processDrag(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions);
+ static QPlatformDropQtResponse processDrop(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions);
static bool processNativeEvent(QWindow *window, const QByteArray &eventType, void *message, long *result);
diff --git a/src/gui/kernel/qplatformdrag_qpa.cpp b/src/gui/kernel/qplatformdrag_qpa.cpp
new file mode 100644
index 0000000000..832b91db7e
--- /dev/null
+++ b/src/gui/kernel/qplatformdrag_qpa.cpp
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdrag_qpa.h"
+
+#include <QtGui/private/qdnd_p.h>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QGuiApplication>
+#include <QtCore/QEventLoop>
+
+QT_BEGIN_NAMESPACE
+
+QPlatformDropQtResponse::QPlatformDropQtResponse(bool accepted, Qt::DropAction acceptedAction)
+ : m_accepted(accepted)
+ , m_accepted_action(acceptedAction)
+{
+}
+
+bool QPlatformDropQtResponse::isAccepted() const
+{
+ return m_accepted;
+}
+
+Qt::DropAction QPlatformDropQtResponse::acceptedAction() const
+{
+ return m_accepted_action;
+}
+
+QPlatformDragQtResponse::QPlatformDragQtResponse(bool accepted, Qt::DropAction acceptedAction, QRect answerRect)
+ : QPlatformDropQtResponse(accepted,acceptedAction)
+ , m_answer_rect(answerRect)
+{
+}
+
+QRect QPlatformDragQtResponse::answerRect() const
+{
+ return m_answer_rect;
+}
+
+class QPlatformDragPrivate {
+public:
+ QPlatformDragPrivate() : cursor_drop_action(Qt::IgnoreAction) {}
+
+ Qt::DropAction cursor_drop_action;
+};
+
+QPlatformDrag::QPlatformDrag() : d_ptr(new QPlatformDragPrivate)
+{
+}
+
+QPlatformDrag::~QPlatformDrag()
+{
+}
+
+QDrag *QPlatformDrag::currentDrag() const
+{
+ return QDragManager::self()->object();
+}
+
+Qt::DropAction QPlatformDrag::defaultAction(Qt::DropActions possibleActions,
+ Qt::KeyboardModifiers modifiers) const
+{
+#ifdef QDND_DEBUG
+ qDebug("QDragManager::defaultAction(Qt::DropActions possibleActions)");
+ qDebug("keyboard modifiers : %s", KeyboardModifiersToString(modifiers).latin1());
+#endif
+
+ Qt::DropAction default_action = Qt::IgnoreAction;
+
+ if (currentDrag()) {
+ default_action = currentDrag()->defaultAction();
+ }
+
+
+ if (default_action == Qt::IgnoreAction) {
+ //This means that the drag was initiated by QDrag::start and we need to
+ //preserve the old behavior
+ default_action = Qt::CopyAction;
+ }
+
+ if (modifiers & Qt::ControlModifier && modifiers & Qt::ShiftModifier)
+ default_action = Qt::LinkAction;
+ else if (modifiers & Qt::ControlModifier)
+ default_action = Qt::CopyAction;
+ else if (modifiers & Qt::ShiftModifier)
+ default_action = Qt::MoveAction;
+ else if (modifiers & Qt::AltModifier)
+ default_action = Qt::LinkAction;
+
+#ifdef QDND_DEBUG
+ qDebug("possible actions : %s", dragActionsToString(possibleActions).latin1());
+#endif
+
+ // Check if the action determined is allowed
+ if (!(possibleActions & default_action)) {
+ if (possibleActions & Qt::CopyAction)
+ default_action = Qt::CopyAction;
+ else if (possibleActions & Qt::MoveAction)
+ default_action = Qt::MoveAction;
+ else if (possibleActions & Qt::LinkAction)
+ default_action = Qt::LinkAction;
+ else
+ default_action = Qt::IgnoreAction;
+ }
+
+#ifdef QDND_DEBUG
+ qDebug("default action : %s", dragActionsToString(defaultAction).latin1());
+#endif
+
+ return default_action;
+}
+
+/*!
+ \brief Called to notify QDrag about changes of the current action.
+ */
+
+void QPlatformDrag::updateAction(Qt::DropAction action)
+{
+ Q_D(QPlatformDrag);
+ if (d->cursor_drop_action != action) {
+ d->cursor_drop_action = action;
+ emit currentDrag()->actionChanged(action);
+ }
+}
+
+static const char *const default_pm[] = {
+"13 9 3 1",
+". c None",
+" c #000000",
+"X c #FFFFFF",
+"X X X X X X X",
+" X X X X X X ",
+"X ......... X",
+" X.........X ",
+"X ......... X",
+" X.........X ",
+"X ......... X",
+" X X X X X X ",
+"X X X X X X X",
+};
+
+Q_GLOBAL_STATIC_WITH_ARGS(QPixmap,qt_drag_default_pixmap,(default_pm))
+
+QPixmap QPlatformDrag::defaultPixmap()
+{
+ return *qt_drag_default_pixmap();
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformdrag_qpa.h b/src/gui/kernel/qplatformdrag_qpa.h
index 0c215071d3..7d22c69947 100644
--- a/src/gui/kernel/qplatformdrag_qpa.h
+++ b/src/gui/kernel/qplatformdrag_qpa.h
@@ -43,6 +43,7 @@
#define QPLATFORMDRAG_H
#include <QtCore/qglobal.h>
+#include <QtGui/QPixmap>
QT_BEGIN_HEADER
@@ -51,18 +52,54 @@ QT_BEGIN_NAMESPACE
class QMimeData;
class QMouseEvent;
+class QDrag;
+class QObject;
+class QEvent;
+class QPlatformDragPrivate;
-class QPlatformDrag
+class Q_GUI_EXPORT QPlatformDropQtResponse
{
public:
- virtual ~QPlatformDrag() {}
+ QPlatformDropQtResponse(bool accepted, Qt::DropAction acceptedAction);
+ bool isAccepted() const;
+ Qt::DropAction acceptedAction() const;
+private:
+ bool m_accepted;
+ Qt::DropAction m_accepted_action;
+
+};
+
+class Q_GUI_EXPORT QPlatformDragQtResponse : public QPlatformDropQtResponse
+{
+public:
+ QPlatformDragQtResponse(bool accepted, Qt::DropAction acceptedAction, QRect answerRect);
+
+ QRect answerRect() const;
+
+private:
+ QRect m_answer_rect;
+};
+
+class Q_GUI_EXPORT QPlatformDrag
+{
+ Q_DECLARE_PRIVATE(QPlatformDrag)
+public:
+ QPlatformDrag();
+ virtual ~QPlatformDrag();
+
+ QDrag *currentDrag() const;
virtual QMimeData *platformDropData() = 0;
- virtual void startDrag() {}
- virtual void move(const QMouseEvent *me) = 0;
- virtual void drop(const QMouseEvent *me) = 0;
- virtual void cancel() = 0;
+ virtual Qt::DropAction drag(QDrag *m_drag) = 0;
+ void updateAction(Qt::DropAction action);
+
+ Qt::DropAction defaultAction(Qt::DropActions possibleActions, Qt::KeyboardModifiers modifiers) const;
+
+ static QPixmap defaultPixmap();
+
+private:
+ QPlatformDragPrivate *d_ptr;
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qwindowsysteminterface_qpa.cpp b/src/gui/kernel/qwindowsysteminterface_qpa.cpp
index 40a4ec07a6..5b77d97950 100644
--- a/src/gui/kernel/qwindowsysteminterface_qpa.cpp
+++ b/src/gui/kernel/qwindowsysteminterface_qpa.cpp
@@ -43,6 +43,7 @@
#include "private/qguiapplication_p.h"
#include "private/qtouchdevice_p.h"
#include <QAbstractEventDispatcher>
+#include <QPlatformDrag>
#include <qdebug.h>
QT_BEGIN_NAMESPACE
@@ -447,14 +448,14 @@ int QWindowSystemInterface::windowSystemEventsQueued()
return QWindowSystemInterfacePrivate::windowSystemEventsQueued();
}
-Qt::DropAction QWindowSystemInterface::handleDrag(QWindow *w, QMimeData *dropData, const QPoint &p)
+QPlatformDragQtResponse QWindowSystemInterface::handleDrag(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions)
{
- return QGuiApplicationPrivate::processDrag(w, dropData, p);
+ return QGuiApplicationPrivate::processDrag(w, dropData, p,supportedActions);
}
-Qt::DropAction QWindowSystemInterface::handleDrop(QWindow *w, QMimeData *dropData, const QPoint &p)
+QPlatformDropQtResponse QWindowSystemInterface::handleDrop(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions)
{
- return QGuiApplicationPrivate::processDrop(w, dropData, p);
+ return QGuiApplicationPrivate::processDrop(w, dropData, p,supportedActions);
}
/*!
diff --git a/src/gui/kernel/qwindowsysteminterface_qpa.h b/src/gui/kernel/qwindowsysteminterface_qpa.h
index 836fb40bd7..6dae11ea81 100644
--- a/src/gui/kernel/qwindowsysteminterface_qpa.h
+++ b/src/gui/kernel/qwindowsysteminterface_qpa.h
@@ -59,6 +59,8 @@ QT_BEGIN_NAMESPACE
class QMimeData;
class QTouchDevice;
+class QPlatformDragQtResponse;
+class QPlatformDropQtResponse;
class Q_GUI_EXPORT QWindowSystemInterface
@@ -122,8 +124,8 @@ public:
static void handleSynchronousExposeEvent(QWindow *tlw, const QRegion &region);
// Drag and drop. These events are sent immediately.
- static Qt::DropAction handleDrag(QWindow *w, QMimeData *dropData, const QPoint &p);
- static Qt::DropAction handleDrop(QWindow *w, QMimeData *dropData, const QPoint &p);
+ static QPlatformDragQtResponse handleDrag(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions);
+ static QPlatformDropQtResponse handleDrop(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions);
static bool handleNativeEvent(QWindow *window, const QByteArray &eventType, void *message, long *result);
diff --git a/src/platformsupport/dnd/dnd.pri b/src/platformsupport/dnd/dnd.pri
index e100dd10cb..47feb81ef2 100644
--- a/src/platformsupport/dnd/dnd.pri
+++ b/src/platformsupport/dnd/dnd.pri
@@ -1,4 +1,6 @@
HEADERS += \
- $$PWD/qsimpledrag_p.h
+ $$PWD/qsimpledrag_p.h \
+ $$PWD/qshapedpixmapdndwindow_p.h
SOURCES += \
- $$PWD/qsimpledrag.cpp
+ $$PWD/qsimpledrag.cpp \
+ $$PWD/qshapedpixmapdndwindow.cpp
diff --git a/src/platformsupport/dnd/qshapedpixmapdndwindow.cpp b/src/platformsupport/dnd/qshapedpixmapdndwindow.cpp
new file mode 100644
index 0000000000..4eed1e7d85
--- /dev/null
+++ b/src/platformsupport/dnd/qshapedpixmapdndwindow.cpp
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qshapedpixmapdndwindow_p.h"
+
+#include <QtGui/QPainter>
+#include <QtGui/QCursor>
+
+QT_BEGIN_NAMESPACE
+
+QShapedPixmapWindow::QShapedPixmapWindow()
+ : QWindow(),
+ m_backingStore(0)
+{
+ setSurfaceType(RasterSurface);
+ setWindowFlags(Qt::ToolTip | Qt::FramelessWindowHint |
+ Qt::X11BypassWindowManagerHint | Qt::WindowTransparentForInput);
+ create();
+ m_backingStore = new QBackingStore(this);
+}
+
+void QShapedPixmapWindow::render()
+{
+ QRect rect(QPoint(), geometry().size());
+
+ m_backingStore->beginPaint(rect);
+
+ QPaintDevice *device = m_backingStore->paintDevice();
+
+ {
+ QPainter p(device);
+ p.drawPixmap(0, 0, m_pixmap);
+ }
+
+ m_backingStore->endPaint();
+ m_backingStore->flush(rect);
+}
+
+void QShapedPixmapWindow::setPixmap(const QPixmap &pixmap)
+{
+ m_pixmap = pixmap;
+}
+
+void QShapedPixmapWindow::setHotspot(const QPoint &hotspot)
+{
+ m_hotSpot = hotspot;
+}
+
+void QShapedPixmapWindow::updateGeometry()
+{
+ QRect rect(QCursor::pos() - m_hotSpot, m_pixmap.size());
+ if (m_backingStore->size() != m_pixmap.size())
+ m_backingStore->resize(m_pixmap.size());
+ setGeometry(rect);
+}
+
+void QShapedPixmapWindow::exposeEvent(QExposeEvent *)
+{
+ render();
+}
+
+QT_END_NAMESPACE
diff --git a/src/platformsupport/dnd/qshapedpixmapdndwindow_p.h b/src/platformsupport/dnd/qshapedpixmapdndwindow_p.h
new file mode 100644
index 0000000000..36ca6040dd
--- /dev/null
+++ b/src/platformsupport/dnd/qshapedpixmapdndwindow_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSHAPEDPIXMAPDNDWINDOW_H
+#define QSHAPEDPIXMAPDNDWINDOW_H
+
+#include <QtGui/QWindow>
+#include <QtGui/QPixmap>
+#include <QtGui/QBackingStore>
+
+QT_BEGIN_NAMESPACE
+
+QT_BEGIN_HEADER
+
+class QShapedPixmapWindow : public QWindow
+{
+public:
+ QShapedPixmapWindow();
+
+ void render();
+
+ void setPixmap(const QPixmap &pixmap);
+ void setHotspot(const QPoint &hotspot);
+
+ void updateGeometry();
+
+protected:
+ void exposeEvent(QExposeEvent *);
+
+private:
+ QBackingStore *m_backingStore;
+ QPixmap m_pixmap;
+ QPoint m_hotSpot;
+};
+
+QT_END_HEADER
+
+QT_END_NAMESPACE
+
+#endif // QSHAPEDPIXMAPDNDWINDOW_H
diff --git a/src/platformsupport/dnd/qsimpledrag.cpp b/src/platformsupport/dnd/qsimpledrag.cpp
index d0d08c2445..d3cecd4e44 100644
--- a/src/platformsupport/dnd/qsimpledrag.cpp
+++ b/src/platformsupport/dnd/qsimpledrag.cpp
@@ -56,147 +56,283 @@
#include "qimagereader.h"
#include "qimagewriter.h"
+#include <QtCore/QEventLoop>
+#include <QtCore/QDebug>
+
#include <private/qguiapplication_p.h>
#include <private/qdnd_p.h>
+#include <QtPlatformSupport/private/qshapedpixmapdndwindow_p.h>
+
QT_BEGIN_NAMESPACE
-class QDropData : public QInternalMimeData
-{
-public:
- QDropData();
- ~QDropData();
+/*!
+ \class QBasicDrag
+ \brief QBasicDrag is a base class for implementing platform drag and drop.
+ \since 5.0
+ \internal
+ \ingroup qpa
-protected:
- bool hasFormat_sys(const QString &mimeType) const;
- QStringList formats_sys() const;
- QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type) const;
-};
+ QBasicDrag implements QPlatformDrag::drag() by running a local event loop in which
+ it tracks mouse movements and moves the drag icon (QShapedPixmapWindow) accordingly.
+ It provides new virtuals allowing for querying whether the receiving window
+ (within the Qt application or outside) accepts the drag and sets the state accordingly.
+*/
-QSimpleDrag::QSimpleDrag()
+QBasicDrag::QBasicDrag() :
+ m_restoreCursor(false), m_eventLoop(0),
+ m_executed_drop_action(Qt::IgnoreAction), m_can_drop(false),
+ m_drag(0), m_drag_icon_window(0), m_cursor_drop_action(Qt::IgnoreAction)
{
- m_dropData = new QDropData();
- currentWindow = 0;
}
-QSimpleDrag::~QSimpleDrag()
+QBasicDrag::~QBasicDrag()
{
- delete m_dropData;
+ delete m_drag_icon_window;
}
-QMimeData *QSimpleDrag::platformDropData()
+void QBasicDrag::enableEventFilter()
{
- return m_dropData;
+ qApp->installEventFilter(this);
}
-void QSimpleDrag::cancel()
+void QBasicDrag::disableEventFilter()
{
- QDragManager *m = QDragManager::self();
-// qDebug("QDragManager::cancel");
- if (m->object->target()) {
- QDragLeaveEvent dle;
- QCoreApplication::sendEvent(m->object->target(), &dle);
- }
-
+ qApp->removeEventFilter(this);
}
-void QSimpleDrag::move(const QMouseEvent *me)
+bool QBasicDrag::eventFilter(QObject *o, QEvent *e)
{
- QWindow *window = QGuiApplication::topLevelAt(me->globalPos());
- QPoint pos;
- if (window)
- pos = me->globalPos() - window->geometry().topLeft();
+ if (!m_drag) {
+ if (e->type() == QEvent::KeyRelease && static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) {
+ disableEventFilter();
+ exitDndEventLoop();
+ return true; // block the key release
+ }
+ return false;
+ }
- QDragManager *m = QDragManager::self();
+ if (!qobject_cast<QWindow *>(o))
+ return false;
- if (me->buttons()) {
- Qt::DropAction prevAction = m->global_accepted_action;
+ switch (e->type()) {
+ case QEvent::ShortcutOverride:
+ // prevent accelerators from firing while dragging
+ e->accept();
+ return true;
+
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ {
+ QKeyEvent *ke = static_cast<QKeyEvent *>(e);
+ if (ke->key() == Qt::Key_Escape && e->type() == QEvent::KeyPress) {
+ cancel();
+ resetDndState(true);
+ disableEventFilter();
+ exitDndEventLoop();
- if (currentWindow != window) {
- if (currentWindow) {
- QDragLeaveEvent dle;
- QCoreApplication::sendEvent(currentWindow, &dle);
- m->willDrop = false;
- m->global_accepted_action = Qt::IgnoreAction;
- }
- currentWindow = window;
- if (currentWindow) {
- QDragEnterEvent dee(pos, m->possible_actions, m->dropData(), me->buttons(), me->modifiers());
- QCoreApplication::sendEvent(currentWindow, &dee);
- m->willDrop = dee.isAccepted() && dee.dropAction() != Qt::IgnoreAction;
- m->global_accepted_action = m->willDrop ? dee.dropAction() : Qt::IgnoreAction;
- }
- m->updateCursor();
- } else if (window) {
- Q_ASSERT(currentWindow);
- QDragMoveEvent dme(pos, m->possible_actions, m->dropData(), me->buttons(), me->modifiers());
- if (m->global_accepted_action != Qt::IgnoreAction) {
- dme.setDropAction(m->global_accepted_action);
- dme.accept();
}
- QCoreApplication::sendEvent(currentWindow, &dme);
- m->willDrop = dme.isAccepted();
- m->global_accepted_action = m->willDrop ? dme.dropAction() : Qt::IgnoreAction;
- m->updatePixmap();
- m->updateCursor();
+ return true; // Eat all key events
}
- if (m->global_accepted_action != prevAction)
- m->emitActionChanged(m->global_accepted_action);
+
+ case QEvent::MouseMove:
+ move(static_cast<QMouseEvent *>(e));
+ return true; // Eat all mouse events
+
+ case QEvent::MouseButtonRelease:
+ disableEventFilter();
+
+ if (canDrop()) {
+ drop(static_cast<QMouseEvent *>(e));
+ resetDndState(false);
+ } else {
+ cancel();
+ resetDndState(true);
+ }
+ exitDndEventLoop();
+ return true; // Eat all mouse events
+
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::Wheel:
+ return true;
+ default:
+ break;
}
+ return false;
}
-void QSimpleDrag::drop(const QMouseEvent *me)
+Qt::DropAction QBasicDrag::drag(QDrag *o)
{
- QDragManager *m = QDragManager::self();
+ m_drag = o;
+ m_executed_drop_action = Qt::IgnoreAction;
+ m_can_drop = false;
+ m_restoreCursor = true;
+#ifndef QT_NO_CURSOR
+ qApp->setOverrideCursor(Qt::DragCopyCursor);
+ updateCursor(m_executed_drop_action);
+#endif
+ startDrag();
+ m_eventLoop = new QEventLoop;
+ m_eventLoop->exec();
+ delete m_eventLoop;
+ m_eventLoop = 0;
+ m_drag = 0;
+ endDrag();
+ return m_executed_drop_action;
+}
- QWindow *window = QGuiApplication::topLevelAt(me->globalPos());
+void QBasicDrag::resetDndState(bool /* deleteSource */)
+{
+ if (m_restoreCursor) {
+#ifndef QT_NO_CURSOR
+ QGuiApplication::restoreOverrideCursor();
+#endif
+ m_restoreCursor = false;
+ }
+}
+
+void QBasicDrag::startDrag()
+{
+ if (!m_drag_icon_window)
+ m_drag_icon_window = new QShapedPixmapWindow();
+
+ m_drag_icon_window->setPixmap(m_drag->pixmap());
+ m_drag_icon_window->setHotspot(m_drag->hotSpot());
+ m_drag_icon_window->updateGeometry();
+ m_drag_icon_window->setVisible(true);
+
+ enableEventFilter();
+}
+
+void QBasicDrag::endDrag()
+{
+}
+
+void QBasicDrag::cancel()
+{
+ disableEventFilter();
+ m_drag_icon_window->setVisible(false);
+}
+
+void QBasicDrag::move(const QMouseEvent *)
+{
+ if (m_drag)
+ m_drag_icon_window->updateGeometry();
+}
- if (window) {
- QPoint pos = me->globalPos() - window->geometry().topLeft();
+void QBasicDrag::drop(const QMouseEvent *)
+{
+ disableEventFilter();
+ m_drag_icon_window->setVisible(false);
+}
+
+void QBasicDrag::exitDndEventLoop()
+{
+ if (m_eventLoop && m_eventLoop->isRunning())
+ m_eventLoop->exit();
+}
- QDropEvent de(pos, m->possible_actions, m->dropData(), me->buttons(), me->modifiers());
- QCoreApplication::sendEvent(window, &de);
- if (de.isAccepted())
- m->global_accepted_action = de.dropAction();
- else
- m->global_accepted_action = Qt::IgnoreAction;
+void QBasicDrag::updateCursor(Qt::DropAction action)
+{
+ Qt::CursorShape cursorShape = Qt::ForbiddenCursor;
+ if (canDrop()) {
+ switch (action) {
+ case Qt::CopyAction:
+ cursorShape = Qt::DragCopyCursor;
+ break;
+ case Qt::LinkAction:
+ cursorShape = Qt::DragLinkCursor;
+ break;
+ default:
+ cursorShape = Qt::DragMoveCursor;
+ break;
+ }
}
- currentWindow = 0;
+
+ QCursor *cursor = qApp->overrideCursor();
+ if (cursor && cursorShape != cursor->shape()) {
+ qApp->changeOverrideCursor(QCursor(cursorShape));
+ }
+ updateAction(action);
}
+/*!
+ \class QSimpleDrag
+ \brief QSimpleDrag implements QBasicDrag for Drag and Drop operations within the Qt Application itself.
+ \since 5.0
+ \internal
+ \ingroup qpa
+ The class checks whether the receiving window is a window of the Qt application
+ and sets the state accordingly. It does not take windows of other applications
+ into account.
+*/
-QDropData::QDropData()
- : QInternalMimeData()
+QSimpleDrag::QSimpleDrag() : m_current_window(0)
{
}
-QDropData::~QDropData()
+QMimeData *QSimpleDrag::platformDropData()
{
+ if (drag())
+ return drag()->mimeData();
+ return 0;
}
-QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type type) const
+void QSimpleDrag::startDrag()
{
- QDrag *object = QDragManager::self()->object;
- if (!object)
- return QVariant();
- QByteArray data = object->mimeData()->data(mimetype);
- if (type == QVariant::String)
- return QString::fromUtf8(data);
- return data;
+ QBasicDrag::startDrag();
+ m_current_window = QGuiApplication::topLevelAt(QCursor::pos());
+ if (m_current_window) {
+ QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_current_window, drag()->mimeData(), QCursor::pos(), drag()->supportedActions());
+ setCanDrop(response.isAccepted());
+ updateCursor(response.acceptedAction());
+ } else {
+ setCanDrop(false);
+ updateCursor(Qt::IgnoreAction);
+ }
+ setExecutedDropAction(Qt::IgnoreAction);
}
-bool QDropData::hasFormat_sys(const QString &format) const
+void QSimpleDrag::cancel()
{
- return formats().contains(format);
+ QBasicDrag::cancel();
+ if (drag())
+ QWindowSystemInterface::handleDrag(m_current_window, 0, QPoint(), Qt::IgnoreAction);
+ m_current_window = 0;
}
-QStringList QDropData::formats_sys() const
+void QSimpleDrag::move(const QMouseEvent *me)
{
- QDrag *object = QDragManager::self()->object;
- if (object)
- return object->mimeData()->formats();
- return QStringList();
+ QBasicDrag::move(me);
+ QWindow *window = QGuiApplication::topLevelAt(me->globalPos());
+ if (!window)
+ return;
+
+ const QPoint pos = me->globalPos() - window->geometry().topLeft();
+ const QPlatformDragQtResponse qt_response =
+ QWindowSystemInterface::handleDrag(window, drag()->mimeData(), pos, drag()->supportedActions());
+
+ updateCursor(qt_response.acceptedAction());
+ setCanDrop(qt_response.isAccepted());
+}
+
+void QSimpleDrag::drop(const QMouseEvent *me)
+{
+ QBasicDrag::drop(me);
+ QWindow *window = QGuiApplication::topLevelAt(me->globalPos());
+ if (!window)
+ return;
+
+ const QPoint pos = me->globalPos() - window->geometry().topLeft();
+ const QPlatformDropQtResponse response =
+ QWindowSystemInterface::handleDrop(window, drag()->mimeData(),pos, drag()->supportedActions());
+ if (response.isAccepted()) {
+ setExecutedDropAction(response.acceptedAction());
+ } else {
+ setExecutedDropAction(Qt::IgnoreAction);
+ }
}
QT_END_NAMESPACE
diff --git a/src/platformsupport/dnd/qsimpledrag_p.h b/src/platformsupport/dnd/qsimpledrag_p.h
index 536ae241ff..7270684082 100644
--- a/src/platformsupport/dnd/qsimpledrag_p.h
+++ b/src/platformsupport/dnd/qsimpledrag_p.h
@@ -44,32 +44,80 @@
#include <qplatformdrag_qpa.h>
+#include <QtCore/QObject>
+
QT_BEGIN_NAMESPACE
+QT_BEGIN_HEADER
+
class QMouseEvent;
class QWindow;
-
+class QEventLoop;
class QDropData;
+class QShapedPixmapWindow;
-class QSimpleDrag : public QPlatformDrag
+class QBasicDrag : public QPlatformDrag, public QObject
{
public:
- QSimpleDrag();
- ~QSimpleDrag();
+ virtual ~QBasicDrag();
- virtual QMimeData *platformDropData();
+ virtual Qt::DropAction drag(QDrag *drag);
+
+ virtual bool eventFilter(QObject *o, QEvent *e);
-// virtual Qt::DropAction drag(QDrag *);
+protected:
+ QBasicDrag();
+ virtual void startDrag();
virtual void cancel();
virtual void move(const QMouseEvent *me);
virtual void drop(const QMouseEvent *me);
+ virtual void endDrag();
+
+ QShapedPixmapWindow *shapedPixmapWindow() const { return m_drag_icon_window; }
+ void updateCursor(Qt::DropAction action);
+
+ bool canDrop() const { return m_can_drop; }
+ void setCanDrop(bool c) { m_can_drop = c; }
+
+ Qt::DropAction executedDropAction() const { return m_executed_drop_action; }
+ void setExecutedDropAction(Qt::DropAction da) { m_executed_drop_action = da; }
+
+ QDrag *drag() const { return m_drag; }
+
private:
- QDropData *m_dropData;
+ void enableEventFilter();
+ void disableEventFilter();
+ void resetDndState(bool deleteSource);
+ void exitDndEventLoop();
+
+ bool m_restoreCursor;
+ QEventLoop *m_eventLoop;
+ Qt::DropAction m_executed_drop_action;
+ bool m_can_drop;
+ QDrag *m_drag;
+ QShapedPixmapWindow *m_drag_icon_window;
+ Qt::DropAction m_cursor_drop_action;
+};
+
+class QSimpleDrag : public QBasicDrag
+{
+public:
+ QSimpleDrag();
+ virtual QMimeData *platformDropData();
- QWindow *currentWindow;
+protected:
+ virtual void startDrag();
+ virtual void cancel();
+ virtual void move(const QMouseEvent *me);
+ virtual void drop(const QMouseEvent *me);
+
+private:
+ QWindow *m_current_window;
};
+QT_END_HEADER
+
QT_END_NAMESPACE
#endif
diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp
index 9f2a1dc00c..89ca6204a8 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.cpp
+++ b/src/plugins/platforms/windows/qwindowsdrag.cpp
@@ -53,8 +53,11 @@
#include <QtGui/QPixmap>
#include <QtGui/QPainter>
#include <QtGui/QGuiApplication>
+#include <QtGui/private/qwindowsysteminterface_qpa_p.h>
+#include <QtGui/private/qguiapplication_p.h>
#include <QtCore/QDebug>
+#include <QtCore/QBuffer>
#include <QtCore/QPoint>
#include <shlobj.h>
@@ -300,14 +303,13 @@ private:
QWindowsDrag *m_drag;
Qt::MouseButtons m_currentButtons;
- Qt::DropAction m_currentAction;
ActionCursorMap m_cursors;
ULONG m_refs;
};
QWindowsOleDropSource::QWindowsOleDropSource(QWindowsDrag *drag) :
- m_drag(drag), m_currentButtons(Qt::NoButton), m_currentAction(Qt::IgnoreAction),
+ m_drag(drag), m_currentButtons(Qt::NoButton),
m_refs(1)
{
if (QWindowsContext::verboseOLE)
@@ -321,24 +323,26 @@ QWindowsOleDropSource::~QWindowsOleDropSource()
qDebug("%s", __FUNCTION__);
}
+/*!
+ \brief Blend custom pixmap with cursors.
+*/
+
void QWindowsOleDropSource::createCursors()
{
- QDragManager *manager = QDragManager::self();
- if (!manager || !manager->object)
- return;
- const QPixmap pixmap = manager->object->pixmap();
+ const QDrag *drag = m_drag->currentDrag();
+ const QPixmap pixmap = drag->pixmap();
const bool hasPixmap = !pixmap.isNull();
- if (!hasPixmap && manager->dragPrivate()->customCursors.isEmpty())
+ if (!hasPixmap)
return;
QList<Qt::DropAction> actions;
actions << Qt::MoveAction << Qt::CopyAction << Qt::LinkAction;
if (hasPixmap)
actions << Qt::IgnoreAction;
- const QPoint hotSpot = manager->object->hotSpot();
+ const QPoint hotSpot = drag->hotSpot();
for (int cnum = 0; cnum < actions.size(); ++cnum) {
const Qt::DropAction action = actions.at(cnum);
- QPixmap cpm = manager->dragCursor(action);
+ QPixmap cpm = drag->dragCursor(action);
if (cpm.isNull())
cpm = m_drag->defaultCursor(action);
if (cpm.isNull()) {
@@ -361,7 +365,7 @@ void QWindowsOleDropSource::createCursors()
const QPoint newHotSpot = hotSpot;
QPixmap newCursor(w, h);
if (hasPixmap) {
- newCursor.fill(QColor(0, 0, 0, 0));
+ newCursor.fill(Qt::transparent);
QPainter p(&newCursor);
const QRect srcRect = pixmap.rect();
const QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y()));
@@ -375,7 +379,7 @@ void QWindowsOleDropSource::createCursors()
const int hotY = hasPixmap ? qMax(0,newHotSpot.y()) : 0;
if (const HCURSOR sysCursor = QWindowsCursor::createPixmapCursor(newCursor, hotX, hotY))
- m_cursors.insert(action, sysCursor);
+ m_cursors.insert(actions.at(cnum), sysCursor);
}
if (QWindowsContext::verboseOLE)
qDebug("%s %d cursors", __FUNCTION__, m_cursors.size());
@@ -432,7 +436,7 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
{
HRESULT hr = S_OK;
do {
- if (fEscapePressed || QWindowsDrag::instance()->dragBeingCancelled()) {
+ if (fEscapePressed) {
hr = ResultFromScode(DRAGDROP_S_CANCEL);
break;
}
@@ -461,13 +465,11 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
} while (false);
- QDragManager::self()->willDrop = hr == DRAGDROP_S_DROP;
-
if (QWindowsContext::verboseOLE
&& (QWindowsContext::verboseOLE > 1 || hr != S_OK))
- qDebug("%s fEscapePressed=%d, grfKeyState=%lu buttons=%d willDrop = %d returns 0x%x",
+ qDebug("%s fEscapePressed=%d, grfKeyState=%lu buttons=%d returns 0x%x",
__FUNCTION__, fEscapePressed,grfKeyState, int(m_currentButtons),
- QDragManager::self()->willDrop, int(hr));
+ int(hr));
return hr;
}
@@ -479,16 +481,12 @@ QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
QWindowsOleDropSource::GiveFeedback(DWORD dwEffect)
{
const Qt::DropAction action = translateToQDragDropAction(dwEffect);
+ m_drag->updateAction(action);
if (QWindowsContext::verboseOLE > 2)
qDebug("%s dwEffect=%lu, action=%d", __FUNCTION__, dwEffect, action);
- if (m_currentAction != action) {
- m_currentAction = action;
- QDragManager::self()->emitActionChanged(m_currentAction);
- }
-
- const ActionCursorMap::const_iterator it = m_cursors.constFind(m_currentAction);
+ const ActionCursorMap::const_iterator it = m_cursors.constFind(action);
if (it != m_cursors.constEnd()) {
SetCursor(it.value());
return ResultFromScode(S_OK);
@@ -510,7 +508,7 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect)
*/
QWindowsOleDropTarget::QWindowsOleDropTarget(QWindow *w) :
- m_refs(1), m_window(w), m_currentWindow(0), m_chosenEffect(0), m_lastKeyState(0)
+ m_refs(1), m_window(w), m_chosenEffect(0), m_lastKeyState(0)
{
if (QWindowsContext::verboseOLE)
qDebug() << __FUNCTION__ << this << w;
@@ -558,6 +556,38 @@ QWindow *QWindowsOleDropTarget::findDragOverWindow(const POINTL &pt) const
return m_window;
}
+void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState,
+ const QPoint &point, LPDWORD pdwEffect)
+{
+ Q_ASSERT(window);
+ m_lastPoint = point;
+ m_lastKeyState = grfKeyState;
+
+ QWindowsDrag *windowsDrag = QWindowsDrag::instance();
+ const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect);
+ QGuiApplicationPrivate::modifier_buttons = toQtKeyboardModifiers(grfKeyState);
+ QGuiApplicationPrivate::mouse_buttons = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState);
+
+ const QPlatformDragQtResponse response =
+ QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), m_lastPoint, actions);
+
+ m_answerRect = response.answerRect();
+ const Qt::DropAction action = response.acceptedAction();
+ if (response.isAccepted()) {
+ m_chosenEffect = translateToWinDragEffects(action);
+ } else {
+ m_chosenEffect = DROPEFFECT_NONE;
+ }
+ *pdwEffect = m_chosenEffect;
+ if (QWindowsContext::verboseOLE)
+ qDebug() << __FUNCTION__ << m_window
+ << windowsDrag->dropData() << " supported actions=" << actions
+ << " mods=" << QGuiApplicationPrivate::modifier_buttons
+ << " mouse=" << QGuiApplicationPrivate::mouse_buttons
+ << " accepted: " << response.isAccepted() << action
+ << m_answerRect << " effect" << *pdwEffect;
+}
+
QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
QWindowsOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState,
POINTL pt, LPDWORD pdwEffect)
@@ -567,124 +597,28 @@ QWindowsOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState,
QWindowsDrag::instance()->setDropDataObject(pDataObj);
pDataObj->AddRef();
- m_currentWindow = m_window;
- sendDragEnterEvent(m_window, grfKeyState, pt, pdwEffect);
- *pdwEffect = m_chosenEffect;
+ const QPoint point = QWindowsGeometryHint::mapFromGlobal(m_window, QPoint(pt.x,pt.y));
+ handleDrag(m_window, grfKeyState, point, pdwEffect);
return NOERROR;
}
-void QWindowsOleDropTarget::sendDragEnterEvent(QWindow *dragEnterWidget,
- DWORD grfKeyState,
- POINTL pt, LPDWORD pdwEffect)
-{
- Q_ASSERT(dragEnterWidget);
-
- m_lastPoint = QWindowsGeometryHint::mapFromGlobal(dragEnterWidget, QPoint(pt.x,pt.y));
- m_lastKeyState = grfKeyState;
-
- m_chosenEffect = DROPEFFECT_NONE;
-
- QDragManager *manager = QDragManager::self();
- QMimeData *md = manager->dropData();
- const Qt::MouseButtons mouseButtons
- = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState);
- const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect);
- const Qt::KeyboardModifiers keyMods = toQtKeyboardModifiers(grfKeyState);
- QDragEnterEvent enterEvent(m_lastPoint, actions, md, mouseButtons, keyMods);
- QGuiApplication::sendEvent(m_currentWindow, &enterEvent);
- m_answerRect = enterEvent.answerRect();
- if (QWindowsContext::verboseOLE)
- qDebug() << __FUNCTION__ << " sent drag enter to " << m_window
- << *md << " actions=" << actions
- << " mods=" << keyMods << " accepted: "
- << enterEvent.isAccepted();
-
- if (enterEvent.isAccepted())
- m_chosenEffect = translateToWinDragEffects(enterEvent.dropAction());
- // Documentation states that a drag move event is sent immediately after
- // a drag enter event. This will honor widgets overriding dragMoveEvent only:
- if (enterEvent.isAccepted()) {
- QDragMoveEvent moveEvent(m_lastPoint, actions, md, mouseButtons, keyMods);
- m_answerRect = enterEvent.answerRect();
- moveEvent.setDropAction(enterEvent.dropAction());
- moveEvent.accept(); // accept by default, since enter event was accepted.
-
- QGuiApplication::sendEvent(dragEnterWidget, &moveEvent);
- if (moveEvent.isAccepted()) {
- m_answerRect = moveEvent.answerRect();
- m_chosenEffect = translateToWinDragEffects(moveEvent.dropAction());
- } else {
- m_chosenEffect = DROPEFFECT_NONE;
- }
- }
-}
-
QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
QWindowsOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
{
QWindow *dragOverWindow = findDragOverWindow(pt);
-
+ if (QWindowsContext::verboseOLE)
+ qDebug("%s widget=%p key=%lu, pt=%ld,%ld", __FUNCTION__, dragOverWindow, grfKeyState, pt.x, pt.y);
const QPoint tmpPoint = QWindowsGeometryHint::mapFromGlobal(dragOverWindow, QPoint(pt.x,pt.y));
// see if we should compress this event
if ((tmpPoint == m_lastPoint || m_answerRect.contains(tmpPoint))
&& m_lastKeyState == grfKeyState) {
*pdwEffect = m_chosenEffect;
+ if (QWindowsContext::verboseOLE)
+ qDebug("%s: compressed event", __FUNCTION__);
return NOERROR;
}
- if (QWindowsContext::verboseOLE > 1)
- qDebug().nospace() << '>' << __FUNCTION__ << ' ' << m_window << " current "
- << dragOverWindow << " key=" << grfKeyState
- << " pt=" <<pt.x << ',' << pt.y;
-
- if (dragOverWindow != m_currentWindow) {
- QPointer<QWindow> dragOverWindowGuard(dragOverWindow);
- // Send drag leave event to the previous drag widget.
- // Drag-Over widget might be deleted in DragLeave,
- // (tasktracker 218353).
- QDragLeaveEvent dragLeave;
- if (m_currentWindow)
- QGuiApplication::sendEvent(m_currentWindow, &dragLeave);
- if (!dragOverWindowGuard) {
- dragOverWindow = findDragOverWindow(pt);
- }
- // Send drag enter event to the current drag widget.
- m_currentWindow = dragOverWindow;
- sendDragEnterEvent(dragOverWindow, grfKeyState, pt, pdwEffect);
- }
-
- QDragManager *manager = QDragManager::self();
- QMimeData *md = manager->dropData();
-
- const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect);
-
- QDragMoveEvent oldEvent(m_lastPoint, actions, md,
- QWindowsMouseHandler::keyStateToMouseButtons(m_lastKeyState),
- toQtKeyboardModifiers(m_lastKeyState));
-
- m_lastPoint = tmpPoint;
- m_lastKeyState = grfKeyState;
-
- QDragMoveEvent e(tmpPoint, actions, md,
- QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState),
- toQtKeyboardModifiers(grfKeyState));
- if (m_chosenEffect != DROPEFFECT_NONE) {
- if (oldEvent.dropAction() == e.dropAction() &&
- oldEvent.keyboardModifiers() == e.keyboardModifiers())
- e.setDropAction(translateToQDragDropAction(m_chosenEffect));
- e.accept();
- }
- QGuiApplication::sendEvent(dragOverWindow, &e);
-
- m_answerRect = e.answerRect();
- if (e.isAccepted())
- m_chosenEffect = translateToWinDragEffects(e.dropAction());
- else
- m_chosenEffect = DROPEFFECT_NONE;
- *pdwEffect = m_chosenEffect;
-
- if (QWindowsContext::verboseOLE > 1)
- qDebug("<%s effect=0x%lx", __FUNCTION__, m_chosenEffect);
+ handleDrag(dragOverWindow, grfKeyState, tmpPoint, pdwEffect);
return NOERROR;
}
@@ -694,9 +628,7 @@ QWindowsOleDropTarget::DragLeave()
if (QWindowsContext::verboseOLE)
qDebug().nospace() <<__FUNCTION__ << ' ' << m_window;
- m_currentWindow = 0;
- QDragLeaveEvent e;
- QGuiApplication::sendEvent(m_window, &e);
+ QWindowSystemInterface::handleDrag(m_window, 0, QPoint(), Qt::IgnoreAction);
QWindowsDrag::instance()->releaseDropDataObject();
return NOERROR;
@@ -724,21 +656,15 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState,
m_lastKeyState = grfKeyState;
QWindowsDrag *windowsDrag = QWindowsDrag::instance();
- QDragManager *manager = QDragManager::self();
- QMimeData *md = manager->dropData();
- QDropEvent e(m_lastPoint, translateToQDragDropActions(*pdwEffect), md,
- QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState),
- toQtKeyboardModifiers(grfKeyState));
- if (m_chosenEffect != DROPEFFECT_NONE)
- e.setDropAction(translateToQDragDropAction(m_chosenEffect));
-
- QGuiApplication::sendEvent(dropWindow, &e);
- if (m_chosenEffect != DROPEFFECT_NONE)
- e.accept();
-
- if (e.isAccepted()) {
- if (e.dropAction() == Qt::MoveAction || e.dropAction() == Qt::TargetMoveAction) {
- if (e.dropAction() == Qt::MoveAction)
+
+ const QPlatformDropQtResponse response =
+ QWindowSystemInterface::handleDrop(dropWindow, windowsDrag->platformDropData(), m_lastPoint,
+ translateToQDragDropActions(*pdwEffect));
+
+ if (response.isAccepted()) {
+ const Qt::DropAction action = response.acceptedAction();
+ if (action == Qt::MoveAction || action == Qt::TargetMoveAction) {
+ if (action == Qt::MoveAction)
m_chosenEffect = DROPEFFECT_MOVE;
else
m_chosenEffect = DROPEFFECT_COPY;
@@ -760,7 +686,7 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState,
windowsDrag->dropDataObject()->SetData(&format, &medium, true);
}
} else {
- m_chosenEffect = translateToWinDragEffects(e.dropAction());
+ m_chosenEffect = translateToWinDragEffects(action);
}
} else {
m_chosenEffect = DROPEFFECT_NONE;
@@ -778,7 +704,7 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState,
\ingroup qt-lighthouse-win
*/
-QWindowsDrag::QWindowsDrag() : m_dropDataObject(0), m_dragBeingCancelled(false)
+QWindowsDrag::QWindowsDrag() : m_dropDataObject(0)
{
}
@@ -786,6 +712,17 @@ QWindowsDrag::~QWindowsDrag()
{
}
+/*!
+ \brief Return data for a drop in process. If it stems from a current drag, use a shortcut.
+*/
+
+QMimeData *QWindowsDrag::dropData()
+{
+ if (const QDrag *drag = currentDrag())
+ return drag->mimeData();
+ return &m_dropData;
+}
+
QPixmap QWindowsDrag::defaultCursor(Qt::DropAction action) const
{
switch (action) {
@@ -810,69 +747,46 @@ QPixmap QWindowsDrag::defaultCursor(Qt::DropAction action) const
return m_ignoreDragCursor;
}
-void QWindowsDrag::startDrag()
+Qt::DropAction QWindowsDrag::drag(QDrag *drag)
{
// TODO: Accessibility handling?
- QDragManager *dragManager = QDragManager::self();
- QMimeData *dropData = dragManager->dropData();
- m_dragBeingCancelled = false;
+ QMimeData *dropData = drag->mimeData();
+ Qt::DropAction dragResult = Qt::IgnoreAction;
DWORD resultEffect;
QWindowsOleDropSource *windowDropSource = new QWindowsOleDropSource(this);
windowDropSource->createCursors();
QWindowsOleDataObject *dropDataObject = new QWindowsOleDataObject(dropData);
- const Qt::DropActions possibleActions = dragManager->possible_actions;
+ const Qt::DropActions possibleActions = drag->supportedActions();
const DWORD allowedEffects = translateToWinDragEffects(possibleActions);
if (QWindowsContext::verboseOLE)
qDebug(">%s possible Actions=%x, effects=0x%lx", __FUNCTION__,
int(possibleActions), allowedEffects);
const HRESULT r = DoDragDrop(dropDataObject, windowDropSource, allowedEffects, &resultEffect);
const DWORD reportedPerformedEffect = dropDataObject->reportedPerformedEffect();
- Qt::DropAction ret = Qt::IgnoreAction;
if (r == DRAGDROP_S_DROP) {
if (reportedPerformedEffect == DROPEFFECT_MOVE && resultEffect != DROPEFFECT_MOVE) {
- ret = Qt::TargetMoveAction;
+ dragResult = Qt::TargetMoveAction;
resultEffect = DROPEFFECT_MOVE;
} else {
- ret = translateToQDragDropAction(resultEffect);
+ dragResult = translateToQDragDropAction(resultEffect);
}
// Force it to be a copy if an unsupported operation occurred.
// This indicates a bug in the drop target.
- if (resultEffect != DROPEFFECT_NONE && !(resultEffect & allowedEffects))
- ret = Qt::CopyAction;
- } else {
- dragManager->setCurrentTarget(0);
+ if (resultEffect != DROPEFFECT_NONE && !(resultEffect & allowedEffects)) {
+ qWarning("%s: Forcing Qt::CopyAction", __FUNCTION__);
+ dragResult = Qt::CopyAction;
+ }
}
-
// clean up
dropDataObject->releaseQt();
dropDataObject->Release(); // Will delete obj if refcount becomes 0
windowDropSource->Release(); // Will delete src if refcount becomes 0
if (QWindowsContext::verboseOLE)
qDebug("<%s allowedEffects=0x%lx, reportedPerformedEffect=0x%lx, resultEffect=0x%lx, hr=0x%x, dropAction=%d",
- __FUNCTION__, allowedEffects, reportedPerformedEffect, resultEffect, int(r), ret);
-}
-
-void QWindowsDrag::move(const QMouseEvent *me)
-{
- const QPoint pos = me->pos();
- if (QWindowsContext::verboseOLE)
- qDebug("%s %d %d", __FUNCTION__, pos.x(), pos.y());
-}
-
-void QWindowsDrag::drop(const QMouseEvent *me)
-{
- const QPoint pos = me->pos();
- if (QWindowsContext::verboseOLE)
- qDebug("%s %d %d", __FUNCTION__, pos.x(), pos.y());
-}
-
-void QWindowsDrag::cancel()
-{
- // TODO: Accessibility handling?
- if (QWindowsContext::verboseOLE)
- qDebug("%s", __FUNCTION__);
- m_dragBeingCancelled = true;
+ __FUNCTION__, allowedEffects, reportedPerformedEffect,
+ resultEffect, int(r), dragResult);
+ return dragResult;
}
QWindowsDrag *QWindowsDrag::instance()
diff --git a/src/plugins/platforms/windows/qwindowsdrag.h b/src/plugins/platforms/windows/qwindowsdrag.h
index 86b5539f92..7b629baccc 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.h
+++ b/src/plugins/platforms/windows/qwindowsdrag.h
@@ -45,9 +45,9 @@
#include "qwindowsinternalmimedata.h"
#include <QtGui/QPlatformDrag>
+#include <QtGui/QPixmap>
QT_BEGIN_NAMESPACE
-
class QWindowsDropMimeData : public QWindowsInternalMimeData {
public:
QWindowsDropMimeData() {}
@@ -73,11 +73,10 @@ public:
private:
inline QWindow *findDragOverWindow(const POINTL &pt) const;
- void sendDragEnterEvent(QWindow *to, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);
+ void handleDrag(QWindow *window, DWORD grfKeyState, const QPoint &, LPDWORD pdwEffect);
ULONG m_refs;
QWindow *const m_window;
- QWindow *m_currentWindow;
QRect m_answerRect;
QPoint m_lastPoint;
DWORD m_chosenEffect;
@@ -92,25 +91,20 @@ public:
virtual QMimeData *platformDropData() { return &m_dropData; }
- virtual void startDrag();
- virtual void move(const QMouseEvent *me);
- virtual void drop(const QMouseEvent *me);
- virtual void cancel();
+ virtual Qt::DropAction drag(QDrag *drag);
static QWindowsDrag *instance();
IDataObject *dropDataObject() const { return m_dropDataObject; }
void setDropDataObject(IDataObject *dataObject) { m_dropDataObject = dataObject; }
void releaseDropDataObject();
-
- bool dragBeingCancelled() const { return m_dragBeingCancelled; }
+ QMimeData *dropData();
QPixmap defaultCursor(Qt::DropAction action) const;
private:
QWindowsDropMimeData m_dropData;
IDataObject *m_dropDataObject;
- bool m_dragBeingCancelled;
mutable QPixmap m_copyDragCursor;
mutable QPixmap m_moveDragCursor;
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index fdc2c76fea..04c43eb97f 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -714,9 +714,9 @@ void QXcbConnection::handleClientMessageEvent(const xcb_client_message_event_t *
return;
if (event->type == atom(QXcbAtom::XdndStatus)) {
- drag()->handleStatus(event, false);
+ drag()->handleStatus(event);
} else if (event->type == atom(QXcbAtom::XdndFinished)) {
- drag()->handleFinished(event, false);
+ drag()->handleFinished(event);
}
QXcbWindow *window = platformWindowFromId(event->window);
diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp
index e928fe2d0a..0e3807cd7b 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.cpp
+++ b/src/plugins/platforms/xcb/qxcbdrag.cpp
@@ -52,6 +52,12 @@
#include <qevent.h>
#include <qguiapplication.h>
#include <qrect.h>
+#include <qpainter.h>
+
+#include <QtGui/QWindowSystemInterface>
+
+#include <QtPlatformSupport/private/qshapedpixmapdndwindow_p.h>
+#include <QtPlatformSupport/private/qsimpledrag_p.h>
QT_BEGIN_NAMESPACE
@@ -109,12 +115,11 @@ static xcb_window_t xdndProxy(QXcbConnection *c, xcb_window_t w)
return proxy;
}
-
-class QDropData : public QXcbMime
+class QXcbDropData : public QXcbMime
{
public:
- QDropData(QXcbDrag *d);
- ~QDropData();
+ QXcbDropData(QXcbDrag *d);
+ ~QXcbDropData();
protected:
bool hasFormat_sys(const QString &mimeType) const;
@@ -127,10 +132,9 @@ protected:
};
-QXcbDrag::QXcbDrag(QXcbConnection *c)
- : QXcbObject(c)
+QXcbDrag::QXcbDrag(QXcbConnection *c) : QXcbObject(c)
{
- dropData = new QDropData(this);
+ dropData = new QXcbDropData(this);
init();
heartbeat = -1;
@@ -147,13 +151,13 @@ void QXcbDrag::init()
{
currentWindow.clear();
+ accepted_drop_action = Qt::IgnoreAction;
+
xdnd_dragsource = XCB_NONE;
- last_target_accepted_action = Qt::IgnoreAction;
waiting_for_status = false;
current_target = XCB_NONE;
current_proxy_target = XCB_NONE;
- xdnd_dragging = false;
source_time = XCB_CURRENT_TIME;
target_time = XCB_CURRENT_TIME;
@@ -169,16 +173,17 @@ QMimeData *QXcbDrag::platformDropData()
void QXcbDrag::startDrag()
{
+ // #fixme enableEventFilter();
+
init();
heartbeat = startTimer(200);
- xdnd_dragging = true;
+
xcb_set_selection_owner(xcb_connection(), connection()->clipboard()->owner(),
atom(QXcbAtom::XdndSelection), connection()->time());
- QDragManager *manager = QDragManager::self();
- QStringList fmts = QXcbMime::formatsHelper(manager->dropData());
+ QStringList fmts = QXcbMime::formatsHelper(drag()->mimeData());
for (int i = 0; i < fmts.size(); ++i) {
QList<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), fmts.at(i));
for (int j = 0; j < atoms.size(); ++j) {
@@ -190,23 +195,16 @@ 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());
-
- QPointF pos = QCursor::pos();
- QMouseEvent me(QEvent::MouseMove, pos, pos, pos, Qt::LeftButton,
- QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
- move(&me);
-
-// if (!QWidget::mouseGrabber())
-// manager->shapedPixmapWindow->grabMouse();
+ QBasicDrag::startDrag();
}
void QXcbDrag::endDrag()
{
- Q_ASSERT(heartbeat != -1);
- killTimer(heartbeat);
- heartbeat = -1;
-
- xdnd_dragging = false;
+ if (heartbeat != -1) {
+ killTimer(heartbeat);
+ heartbeat = -1;
+ }
+ QBasicDrag::endDrag();
}
static xcb_translate_coordinates_reply_t *
@@ -219,7 +217,7 @@ translateCoordinates(QXcbConnection *c, xcb_window_t from, xcb_window_t to, int
xcb_window_t QXcbDrag::findRealWindow(const QPoint & pos, xcb_window_t w, int md)
{
- if (w == QDragManager::self()->shapedPixmapWindow->handle()->winId())
+ if (w == shapedPixmapWindow()->handle()->winId())
return 0;
if (md) {
@@ -296,9 +294,7 @@ xcb_window_t QXcbDrag::findRealWindow(const QPoint & pos, xcb_window_t w, int md
void QXcbDrag::move(const QMouseEvent *me)
{
- DEBUG() << "QDragManager::move enter" << me->globalPos();
-
- // ###
+ QBasicDrag::move(me);
QPoint globalPos = me->globalPos();
if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid())
@@ -337,15 +333,13 @@ void QXcbDrag::move(const QMouseEvent *me)
::translateCoordinates(connection(), rootwin, rootwin, globalPos.x(), globalPos.y());
if (!translate)
return;
+
xcb_window_t target = translate->child;
int lx = translate->dst_x;
int ly = translate->dst_y;
free (translate);
- if (target == rootwin) {
- // Ok.
- } else if (target) {
- //me
+ if (target && target != rootwin) {
xcb_window_t src = rootwin;
while (target != 0) {
DNDDEBUG << "checking target for XdndAware" << target << lx << ly;
@@ -376,7 +370,7 @@ void QXcbDrag::move(const QMouseEvent *me)
target = child;
}
- if (!target || target == QDragManager::self()->shapedPixmapWindow->handle()->winId()) {
+ if (!target || target == shapedPixmapWindow()->handle()->winId()) {
DNDDEBUG << "need to find real window";
target = findRealWindow(globalPos, rootwin, 6);
DNDDEBUG << "real window found" << target;
@@ -393,9 +387,6 @@ void QXcbDrag::move(const QMouseEvent *me)
target = rootwin;
}
- DNDDEBUG << "and the final target is " << target;
- DNDDEBUG << "the widget w is" << (w ? w->window() : 0);
-
xcb_window_t proxy_target = xdndProxy(connection(), target);
if (!proxy_target)
proxy_target = target;
@@ -414,7 +405,6 @@ void QXcbDrag::move(const QMouseEvent *me)
free(reply);
}
- DEBUG() << "target=" << target << "current_target=" << current_target;
if (target != current_target) {
if (current_target)
send_leave();
@@ -447,11 +437,10 @@ void QXcbDrag::move(const QMouseEvent *me)
waiting_for_status = false;
}
}
+
if (waiting_for_status)
return;
- QDragManager *m = QDragManager::self();
-
if (target) {
waiting_for_status = true;
@@ -465,28 +454,21 @@ void QXcbDrag::move(const QMouseEvent *me)
move.data.data32[1] = 0; // flags
move.data.data32[2] = (globalPos.x() << 16) + globalPos.y();
move.data.data32[3] = connection()->time();
- move.data.data32[4] = toXdndAction(m->defaultAction(m->dragPrivate()->possible_actions, QGuiApplication::keyboardModifiers()));
+ move.data.data32[4] = toXdndAction(defaultAction(currentDrag()->supportedActions(), QGuiApplication::keyboardModifiers()));
DEBUG() << "sending Xdnd position source=" << move.data.data32[0] << "target=" << move.window;
source_time = connection()->time();
if (w)
- handle_xdnd_position(w->window(), &move, false);
+ handle_xdnd_position(w->window(), &move);
else
xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&move);
- } else {
- if (m->willDrop) {
- m->willDrop = false;
- }
}
- m->updateCursor();
- DEBUG() << "QDragManager::move leave";
}
-void QXcbDrag::drop(const QMouseEvent *)
+void QXcbDrag::drop(const QMouseEvent *event)
{
- endDrag();
-
+ QBasicDrag::drop(event);
if (!current_target)
return;
@@ -500,14 +482,13 @@ void QXcbDrag::drop(const QMouseEvent *)
drop.data.data32[2] = connection()->time();
drop.data.data32[3] = 0;
- drop.data.data32[4] = 0;
+ drop.data.data32[4] = currentDrag()->supportedActions();
QXcbWindow *w = connection()->platformWindowFromId(current_proxy_target);
if (w && (w->window()->windowType() == Qt::Desktop) /*&& !w->acceptDrops()*/)
w = 0;
- QDragManager *manager = QDragManager::self();
Transaction t = {
connection()->time(),
@@ -515,21 +496,22 @@ void QXcbDrag::drop(const QMouseEvent *)
current_proxy_target,
(w ? w->window() : 0),
// current_embedding_widget,
- manager->object
+ currentDrag()
};
transactions.append(t);
restartDropExpiryTimer();
- if (w)
- handleDrop(w->window(), &drop, false);
- else
+ if (w) {
+ handleDrop(w->window(), &drop);
+ } else {
xcb_send_event(xcb_connection(), false, current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&drop);
+ }
current_target = 0;
current_proxy_target = 0;
source_time = 0;
// current_embedding_widget = 0;
- manager->object = 0;
+ // #fixme resetDndState(false);
}
Qt::DropAction QXcbDrag::toDropAction(xcb_atom_t a) const
@@ -719,7 +701,7 @@ 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, bool passive)
+void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *e)
{
QPoint p((e->data.data32[2] & 0xffff0000) >> 16, e->data.data32[2] & 0x0000ffff);
Q_ASSERT(w);
@@ -727,11 +709,7 @@ void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t
p -= geometry.topLeft();
- // ####
-// if (!passive && checkEmbedded(w, e))
-// return;
-
- if (!w || (/*!w->acceptDrops() &&*/ (w->windowType() == Qt::Desktop)))
+ if (!w || (w->windowType() == Qt::Desktop))
return;
if (e->data.data32[0] != xdnd_dragsource) {
@@ -739,12 +717,27 @@ void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t
return;
}
+ currentPosition = p;
+ currentWindow = w;
+
// timestamp from the source
- if (e->data.data32[3] != XCB_NONE)
- target_time /*= X11->userTime*/ = e->data.data32[3];
+ if (e->data.data32[3] != XCB_NONE) {
+ target_time = e->data.data32[3];
+ }
- QDragManager *manager = QDragManager::self();
- QMimeData *dropData = manager->dropData();
+ QMimeData *dropData = 0;
+ Qt::DropActions supported_actions = Qt::IgnoreAction;
+ if (currentDrag()) {
+ dropData = currentDrag()->mimeData();
+ supported_actions = currentDrag()->supportedActions();
+ } else {
+ dropData = platformDropData();
+ supported_actions = Qt::DropActions(toDropAction(e->data.data32[4]));
+ }
+
+ QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(w,dropData,p,supported_actions);
+ QRect answerRect(p + geometry.topLeft(), QSize(1,1));
+ answerRect = qt_response.answerRect().translated(geometry.topLeft()).intersected(geometry);
xcb_client_message_event_t response;
response.response_type = XCB_CLIENT_MESSAGE;
@@ -752,83 +745,33 @@ void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t
response.format = 32;
response.type = atom(QXcbAtom::XdndStatus);
response.data.data32[0] = xcb_window(w);
- response.data.data32[1] = 0; // flags
+ response.data.data32[1] = qt_response.isAccepted(); // flags
response.data.data32[2] = 0; // x, y
response.data.data32[3] = 0; // w, h
- response.data.data32[4] = 0; // action
-
- if (!passive) { // otherwise just reject
- QRect answerRect(p + geometry.topLeft(), QSize(1,1));
-
- if (manager->object) {
- manager->possible_actions = manager->dragPrivate()->possible_actions;
- } else {
- manager->possible_actions = Qt::DropActions(toDropAction(e->data.data32[4]));
- }
- QDragMoveEvent me(p, manager->possible_actions, dropData,
- QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
-
- Qt::DropAction accepted_action = Qt::IgnoreAction;
+ response.data.data32[4] = toXdndAction(qt_response.acceptedAction()); // action
- currentPosition = p;
- if (w != currentWindow.data()) {
- if (currentWindow) {
- QDragLeaveEvent e;
- QGuiApplication::sendEvent(currentWindow.data(), &e);
- }
- currentWindow = w;
- last_target_accepted_action = Qt::IgnoreAction;
- QDragEnterEvent de(p, manager->possible_actions, dropData,
- QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
- QGuiApplication::sendEvent(w, &de);
- if (de.isAccepted() && de.dropAction() != Qt::IgnoreAction)
- last_target_accepted_action = de.dropAction();
- }
+ if (answerRect.left() < 0)
+ answerRect.setLeft(0);
+ if (answerRect.right() > 4096)
+ answerRect.setRight(4096);
+ if (answerRect.top() < 0)
+ answerRect.setTop(0);
+ if (answerRect.bottom() > 4096)
+ answerRect.setBottom(4096);
+ if (answerRect.width() < 0)
+ answerRect.setWidth(0);
+ if (answerRect.height() < 0)
+ answerRect.setHeight(0);
- DEBUG() << "qt_handle_xdnd_position action=" << connection()->atomName(e->data.data32[4]);
-
- if (last_target_accepted_action != Qt::IgnoreAction) {
- me.setDropAction(last_target_accepted_action);
- me.accept();
- }
- QGuiApplication::sendEvent(w, &me);
- if (me.isAccepted()) {
- response.data.data32[1] = 1; // yes
- accepted_action = me.dropAction();
- last_target_accepted_action = accepted_action;
- } else {
- response.data.data32[0] = 0;
- last_target_accepted_action = Qt::IgnoreAction;
- }
- answerRect = me.answerRect().translated(geometry.topLeft()).intersected(geometry);
-
- if (answerRect.left() < 0)
- answerRect.setLeft(0);
- if (answerRect.right() > 4096)
- answerRect.setRight(4096);
- if (answerRect.top() < 0)
- answerRect.setTop(0);
- if (answerRect.bottom() > 4096)
- answerRect.setBottom(4096);
- if (answerRect.width() < 0)
- answerRect.setWidth(0);
- if (answerRect.height() < 0)
- answerRect.setHeight(0);
-
-// response.data.data32[2] = (answerRect.x() << 16) + answerRect.y();
-// response.data.data32[3] = (answerRect.width() << 16) + answerRect.height();
- response.data.data32[4] = toXdndAction(accepted_action);
- }
+ response.data.data32[4] = toXdndAction(qt_response.acceptedAction());
// reset
target_time = XCB_CURRENT_TIME;
- DEBUG() << "sending XdndStatus" << (xdnd_dragsource == connection()->clipboard()->owner()) << xdnd_dragsource
- << response.data.data32[1] << connection()->atomName(response.data.data32[4]);
if (xdnd_dragsource == connection()->clipboard()->owner())
- handle_xdnd_status(&response, passive);
+ handle_xdnd_status(&response);
else
Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xdnd_dragsource,
XCB_EVENT_MASK_NO_EVENT, (const char *)&response));
@@ -850,7 +793,7 @@ namespace
};
}
-void QXcbDrag::handlePosition(QWindow * w, const xcb_client_message_event_t *event, bool passive)
+void QXcbDrag::handlePosition(QWindow * 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;
@@ -861,19 +804,28 @@ void QXcbDrag::handlePosition(QWindow * w, const xcb_client_message_event_t *eve
lastEvent = (xcb_client_message_event_t *)nextEvent;
}
- handle_xdnd_position(w, lastEvent, passive);
+ handle_xdnd_position(w, lastEvent);
if (lastEvent != event)
free(lastEvent);
}
-void QXcbDrag::handle_xdnd_status(const xcb_client_message_event_t *event, bool)
+void QXcbDrag::handle_xdnd_status(const xcb_client_message_event_t *event)
{
DEBUG("xdndHandleStatus");
+ waiting_for_status = false;
// ignore late status messages
if (event->data.data32[0] && event->data.data32[0] != current_proxy_target)
return;
- Qt::DropAction newAction = (event->data.data32[1] & 0x1) ? toDropAction(event->data.data32[4]) : Qt::IgnoreAction;
+ const bool dropPossible = event->data.data32[1];
+ setCanDrop(dropPossible);
+
+ if (dropPossible) {
+ accepted_drop_action = toDropAction(event->data.data32[4]);
+ updateCursor(accepted_drop_action);
+ } else {
+ updateCursor(Qt::IgnoreAction);
+ }
if ((event->data.data32[1] & 2) == 0) {
QPoint p((event->data.data32[2] & 0xffff0000) >> 16, event->data.data32[2] & 0x0000ffff);
@@ -882,18 +834,9 @@ void QXcbDrag::handle_xdnd_status(const xcb_client_message_event_t *event, bool)
} else {
source_sameanswer = QRect();
}
- QDragManager *manager = QDragManager::self();
- manager->willDrop = (event->data.data32[1] & 0x1);
- if (manager->global_accepted_action != newAction) {
- manager->global_accepted_action = newAction;
- manager->emitActionChanged(newAction);
- }
- DEBUG() << "willDrop=" << manager->willDrop << "action=" << newAction;
- manager->updateCursor();
- waiting_for_status = false;
}
-void QXcbDrag::handleStatus(const xcb_client_message_event_t *event, bool passive)
+void QXcbDrag::handleStatus(const xcb_client_message_event_t *event)
{
if (event->window != connection()->clipboard()->owner())
return;
@@ -907,13 +850,13 @@ void QXcbDrag::handleStatus(const xcb_client_message_event_t *event, bool passiv
lastEvent = (xcb_client_message_event_t *)nextEvent;
}
- handle_xdnd_status(lastEvent, passive);
+ handle_xdnd_status(lastEvent);
if (lastEvent != event)
free(lastEvent);
DEBUG("xdndHandleStatus end");
}
-void QXcbDrag::handleLeave(QWindow *w, const xcb_client_message_event_t *event, bool /*passive*/)
+void QXcbDrag::handleLeave(QWindow *w, const xcb_client_message_event_t *event)
{
DEBUG("xdnd leave");
if (!currentWindow || w != currentWindow.data())
@@ -931,8 +874,8 @@ 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);
}
- QDragLeaveEvent e;
- QGuiApplication::sendEvent(currentWindow.data(), &e);
+ QWindowSystemInterface::handleDrag(w,0,QPoint(),Qt::IgnoreAction);
+ updateAction(Qt::IgnoreAction);
xdnd_dragsource = 0;
xdnd_types.clear();
@@ -944,7 +887,6 @@ void QXcbDrag::send_leave()
if (!current_target)
return;
- QDragManager *manager = QDragManager::self();
xcb_client_message_event_t leave;
leave.response_type = XCB_CLIENT_MESSAGE;
@@ -963,24 +905,18 @@ void QXcbDrag::send_leave()
w = 0;
if (w)
- handleLeave(w->window(), (const xcb_client_message_event_t *)&leave, false);
+ handleLeave(w->window(), (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);
- // reset the drag manager state
- manager->willDrop = false;
- if (manager->global_accepted_action != Qt::IgnoreAction)
- manager->emitActionChanged(Qt::IgnoreAction);
- manager->global_accepted_action = Qt::IgnoreAction;
- manager->updateCursor();
current_target = 0;
current_proxy_target = 0;
source_time = XCB_CURRENT_TIME;
waiting_for_status = false;
}
-void QXcbDrag::handleDrop(QWindow *, const xcb_client_message_event_t *event, bool passive)
+void QXcbDrag::handleDrop(QWindow *, const xcb_client_message_event_t *event)
{
DEBUG("xdndHandleDrop");
if (!currentWindow) {
@@ -988,16 +924,8 @@ void QXcbDrag::handleDrop(QWindow *, const xcb_client_message_event_t *event, bo
return; // sanity
}
- // ###
-// if (!passive && checkEmbedded(currentWindow, xe)){
-// current_embedding_widget = 0;
-// xdnd_dragsource = 0;
-// currentWindow = 0;
-// return;
-// }
const uint32_t *l = event->data.data32;
- QDragManager *manager = QDragManager::self();
DEBUG("xdnd drop");
if (l[0] != xdnd_dragsource) {
@@ -1009,50 +937,39 @@ void QXcbDrag::handleDrop(QWindow *, const xcb_client_message_event_t *event, bo
if (l[2] != 0)
target_time = /*X11->userTime =*/ l[2];
- if (!passive) {
- // this could be a same-application drop, just proxied due to
- // some XEMBEDding, so try to find the real QMimeData used
- // based on the timestamp for this drop.
- QMimeData *dropData = 0;
- // ###
-// int at = findXdndDropTransactionByTime(target_time);
-// if (at != -1)
-// dropData = QDragManager::dragPrivate(X11->dndDropTransactions.at(at).object)->data;
- // if we can't find it, then use the data in the drag manager
- if (!dropData)
- dropData = manager->dropData();
-
- // Drop coming from another app? Update keyboard modifiers.
-// if (!qt_xdnd_dragging) {
-// QApplicationPrivate::modifier_buttons = currentKeyboardModifiers();
-// }
-
- QDropEvent de(currentPosition, manager->possible_actions, dropData,
- QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
- QGuiApplication::sendEvent(currentWindow.data(), &de);
- if (!de.isAccepted()) {
- // Ignore a failed drag
- manager->global_accepted_action = Qt::IgnoreAction;
- } else {
- manager->global_accepted_action = de.dropAction();
- }
- xcb_client_message_event_t finished;
- finished.response_type = XCB_CLIENT_MESSAGE;
- finished.window = xdnd_dragsource;
- finished.format = 32;
- finished.type = atom(QXcbAtom::XdndFinished);
- DNDDEBUG << "xdndHandleDrop"
- << "currentWindow" << currentWindow.data()
- << (currentWindow ? xcb_window(currentWindow.data()) : 0);
- finished.data.data32[0] = currentWindow ? xcb_window(currentWindow.data()) : XCB_NONE;
- finished.data.data32[1] = de.isAccepted() ? 1 : 0; // flags
- finished.data.data32[2] = toXdndAction(manager->global_accepted_action);
- Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xdnd_dragsource,
- XCB_EVENT_MASK_NO_EVENT, (char *)&finished));
+ // this could be a same-application drop, just proxied due to
+ // some XEMBEDding, so try to find the real QMimeData used
+ // based on the timestamp for this drop.
+ Qt::DropActions supported_drop_actions(l[4]);
+ QMimeData *dropData = 0;
+ if (currentDrag()) {
+ dropData = currentDrag()->mimeData();
} else {
- QDragLeaveEvent e;
- QGuiApplication::sendEvent(currentWindow.data(), &e);
+ dropData = platformDropData();
}
+
+ if (!dropData)
+ return;
+ // ###
+ // int at = findXdndDropTransactionByTime(target_time);
+ // if (at != -1)
+ // 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);
+ setExecutedDropAction(response.acceptedAction());
+
+ xcb_client_message_event_t finished;
+ finished.response_type = XCB_CLIENT_MESSAGE;
+ finished.window = xdnd_dragsource;
+ finished.format = 32;
+ finished.type = atom(QXcbAtom::XdndFinished);
+ 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,
+ XCB_EVENT_MASK_NO_EVENT, (char *)&finished));
+
xdnd_dragsource = 0;
currentWindow.clear();
waiting_for_status = false;
@@ -1062,7 +979,7 @@ void QXcbDrag::handleDrop(QWindow *, const xcb_client_message_event_t *event, bo
}
-void QXcbDrag::handleFinished(const xcb_client_message_event_t *event, bool)
+void QXcbDrag::handleFinished(const xcb_client_message_event_t *event)
{
DEBUG("xdndHandleFinished");
if (event->window != connection()->clipboard()->owner())
@@ -1099,8 +1016,8 @@ void QXcbDrag::handleFinished(const xcb_client_message_event_t *event, bool)
// current_target = 0;
// current_proxy_target = 0;
- if (t.object)
- t.object->deleteLater();
+ if (t.drag)
+ t.drag->deleteLater();
// current_target = target;
// current_proxy_target = proxy_target;
@@ -1126,7 +1043,7 @@ void QXcbDrag::timerEvent(QTimerEvent* e)
// dnd within the same process, don't delete these
continue;
}
- t.object->deleteLater();
+ t.drag->deleteLater();
transactions.removeAt(i--);
}
@@ -1138,12 +1055,9 @@ void QXcbDrag::timerEvent(QTimerEvent* e)
void QXcbDrag::cancel()
{
DEBUG("QXcbDrag::cancel");
- endDrag();
-
+ QBasicDrag::cancel();
if (current_target)
send_leave();
-
- current_target = 0;
}
@@ -1157,14 +1071,11 @@ void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event
notify.property = XCB_NONE;
notify.time = event->time;
- QDragManager *manager = QDragManager::self();
- QDrag *currentObject = manager->object;
-
// which transaction do we use? (note: -2 means use current manager->object)
int at = -1;
// figure out which data the requestor is really interested in
- if (manager->object && event->time == source_time) {
+ if (currentDrag() && event->time == source_time) {
// requestor wants the current drag data
at = -2;
} else {
@@ -1188,20 +1099,18 @@ void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event
// }
// }
}
+
+ QDrag *transactionDrag = 0;
if (at >= 0) {
restartDropExpiryTimer();
- // use the drag object from an XdndDrop tansaction
- manager->object = transactions.at(at).object;
- } else if (at != -2) {
- // no transaction found, we'll have to reject the request
- manager->object = 0;
+ transactionDrag = transactions.at(at).drag;
}
- if (manager->object) {
+ if (transactionDrag) {
xcb_atom_t atomFormat = event->target;
int dataFormat = 0;
QByteArray data;
- if (QXcbMime::mimeDataForAtom(connection(), event->target, manager->dragPrivate()->data,
+ if (QXcbMime::mimeDataForAtom(connection(), event->target, transactionDrag->mimeData(),
&data, &atomFormat, &dataFormat)) {
int dataSize = data.size() / (dataFormat / 8);
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, event->requestor, event->property,
@@ -1211,9 +1120,6 @@ void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event
}
}
- // reset manager->object in case we modified it above
- manager->object = currentObject;
-
xcb_send_event(xcb_connection(), false, event->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&notify);
}
@@ -1268,20 +1174,17 @@ bool QXcbDrag::dndEnable(QXcbWindow *w, bool on)
}
}
-
-
-
-QDropData::QDropData(QXcbDrag *d)
+QXcbDropData::QXcbDropData(QXcbDrag *d)
: QXcbMime(),
drag(d)
{
}
-QDropData::~QDropData()
+QXcbDropData::~QXcbDropData()
{
}
-QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type requestedType) const
+QVariant QXcbDropData::retrieveData_sys(const QString &mimetype, QVariant::Type requestedType) const
{
QByteArray mime = mimetype.toLatin1();
QVariant data = /*X11->motifdnd_active
@@ -1290,17 +1193,16 @@ QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type req
return data;
}
-QVariant QDropData::xdndObtainData(const QByteArray &format, QVariant::Type requestedType) const
+QVariant QXcbDropData::xdndObtainData(const QByteArray &format, QVariant::Type requestedType) const
{
QByteArray result;
- QDragManager *manager = QDragManager::self();
QXcbConnection *c = drag->connection();
QXcbWindow *xcb_window = c->platformWindowFromId(drag->xdnd_dragsource);
- if (xcb_window && manager->object && xcb_window->window()->windowType() != Qt::Desktop) {
- QDragPrivate *o = manager->dragPrivate();
- if (o->data->hasFormat(QLatin1String(format)))
- result = o->data->data(QLatin1String(format));
+ if (xcb_window && drag->currentDrag() && xcb_window->window()->windowType() != Qt::Desktop) {
+ QMimeData *data = drag->currentDrag()->mimeData();
+ if (data->hasFormat(QLatin1String(format)))
+ result = data->data(QLatin1String(format));
return result;
}
@@ -1320,12 +1222,12 @@ QVariant QDropData::xdndObtainData(const QByteArray &format, QVariant::Type requ
}
-bool QDropData::hasFormat_sys(const QString &format) const
+bool QXcbDropData::hasFormat_sys(const QString &format) const
{
return formats().contains(format);
}
-QStringList QDropData::formats_sys() const
+QStringList QXcbDropData::formats_sys() const
{
QStringList formats;
// if (X11->motifdnd_active) {
diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h
index e32e630548..710a07a5a4 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.h
+++ b/src/plugins/platforms/xcb/qxcbdrag.h
@@ -43,6 +43,7 @@
#define QXCBDRAG_H
#include <qplatformdrag_qpa.h>
+#include <QtPlatformSupport/private/qsimpledrag_p.h>
#include <qxcbobject.h>
#include <xcb/xcb.h>
#include <qlist.h>
@@ -51,17 +52,23 @@
#include <qsharedpointer.h>
#include <qvector.h>
+#include <qpixmap.h>
+#include <qbackingstore.h>
+
+#include <QtCore/QDebug>
+
QT_BEGIN_NAMESPACE
class QMouseEvent;
class QWindow;
class QXcbConnection;
class QXcbWindow;
-class QDropData;
+class QXcbDropData;
class QXcbScreen;
class QDrag;
+class QShapedPixmapWindow;
-class QXcbDrag : public QObject, public QXcbObject, public QPlatformDrag
+class QXcbDrag : public QXcbObject, public QBasicDrag
{
public:
QXcbDrag(QXcbConnection *c);
@@ -69,35 +76,36 @@ public:
virtual QMimeData *platformDropData();
-// virtual Qt::DropAction drag(QDrag *);
- virtual void startDrag();
- virtual void cancel();
- virtual void move(const QMouseEvent *me);
- virtual void drop(const QMouseEvent *me);
+ void startDrag();
+ void cancel();
+ void move(const QMouseEvent *me);
+ void drop(const QMouseEvent *me);
void endDrag();
void handleEnter(QWindow *window, const xcb_client_message_event_t *event);
- void handlePosition(QWindow *w, const xcb_client_message_event_t *event, bool passive);
- void handleLeave(QWindow *w, const xcb_client_message_event_t *event, bool /*passive*/);
- void handleDrop(QWindow *, const xcb_client_message_event_t *event, bool passive);
+ void handlePosition(QWindow *w, const xcb_client_message_event_t *event);
+ void handleLeave(QWindow *w, const xcb_client_message_event_t *event);
+ void handleDrop(QWindow *, const xcb_client_message_event_t *event);
- void handleStatus(const xcb_client_message_event_t *event, bool passive);
+ void handleStatus(const xcb_client_message_event_t *event);
void handleSelectionRequest(const xcb_selection_request_event_t *event);
- void handleFinished(const xcb_client_message_event_t *event, bool passive);
+ void handleFinished(const xcb_client_message_event_t *event);
bool dndEnable(QXcbWindow *win, bool on);
+ void updatePixmap();
+
protected:
void timerEvent(QTimerEvent* e);
private:
- friend class QDropData;
+ friend class QXcbDropData;
void init();
- void handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *event, bool passive);
- void handle_xdnd_status(const xcb_client_message_event_t *event, bool);
+ void handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *event);
+ void handle_xdnd_status(const xcb_client_message_event_t *event);
void send_leave();
Qt::DropAction toDropAction(xcb_atom_t atom) const;
@@ -106,7 +114,8 @@ private:
QWeakPointer<QWindow> currentWindow;
QPoint currentPosition;
- QDropData *dropData;
+ QXcbDropData *dropData;
+ Qt::DropAction accepted_drop_action;
QWindow *desktop_proxy;
@@ -118,7 +127,6 @@ private:
xcb_timestamp_t target_time;
xcb_timestamp_t source_time;
- Qt::DropAction last_target_accepted_action;
// rectangle in which the answer will be the same
QRect source_sameanswer;
@@ -132,7 +140,6 @@ private:
QXcbScreen *current_screen;
int heartbeat;
- bool xdnd_dragging;
QVector<xcb_atom_t> drag_types;
@@ -143,7 +150,7 @@ private:
xcb_window_t proxy_target;
QWindow *targetWindow;
// QWidget *embedding_widget;
- QDrag *object;
+ QDrag *drag;
};
QList<Transaction> transactions;
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 067cb775c8..6b7e73d02f 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -1257,11 +1257,11 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
} else if (event->type == atom(QXcbAtom::XdndEnter)) {
connection()->drag()->handleEnter(window(), event);
} else if (event->type == atom(QXcbAtom::XdndPosition)) {
- connection()->drag()->handlePosition(window(), event, false);
+ connection()->drag()->handlePosition(window(), event);
} else if (event->type == atom(QXcbAtom::XdndLeave)) {
- connection()->drag()->handleLeave(window(), event, false);
+ connection()->drag()->handleLeave(window(), event);
} else if (event->type == atom(QXcbAtom::XdndDrop)) {
- connection()->drag()->handleDrop(window(), event, false);
+ connection()->drag()->handleDrop(window(), event);
} else {
qWarning() << "unhandled client message:" << connection()->atomName(event->type);
}
diff --git a/src/widgets/itemviews/qitemdelegate.cpp b/src/widgets/itemviews/qitemdelegate.cpp
index a5351301a7..feec3fcbc5 100644
--- a/src/widgets/itemviews/qitemdelegate.cpp
+++ b/src/widgets/itemviews/qitemdelegate.cpp
@@ -44,6 +44,8 @@
#ifndef QT_NO_ITEMVIEWS
#include <qabstractitemmodel.h>
#include <qapplication.h>
+#include <qplatformintegration_qpa.h>
+#include <private/qguiapplication_p.h>
#include <qbrush.h>
#include <qlineedit.h>
#include <qtextedit.h>
@@ -1224,8 +1226,10 @@ bool QItemDelegate::eventFilter(QObject *object, QEvent *event)
#ifndef QT_NO_DRAGANDDROP
// The window may lose focus during an drag operation.
// i.e when dragging involves the taskbar on Windows.
- if (QDragManager::self() && QDragManager::self()->object != 0)
+ QPlatformDrag *platformDrag = QGuiApplicationPrivate::instance()->platformIntegration()->drag();
+ if (platformDrag && platformDrag->currentDrag()) {
return false;
+ }
#endif
emit commitData(editor);
diff --git a/src/widgets/itemviews/qstyleditemdelegate.cpp b/src/widgets/itemviews/qstyleditemdelegate.cpp
index ca4c684e98..d54d78512a 100644
--- a/src/widgets/itemviews/qstyleditemdelegate.cpp
+++ b/src/widgets/itemviews/qstyleditemdelegate.cpp
@@ -44,6 +44,8 @@
#ifndef QT_NO_ITEMVIEWS
#include <qabstractitemmodel.h>
#include <qapplication.h>
+#include <qplatformintegration_qpa.h>
+#include <private/qguiapplication_p.h>
#include <qbrush.h>
#include <qlineedit.h>
#include <qtextedit.h>
@@ -689,8 +691,10 @@ bool QStyledItemDelegate::eventFilter(QObject *object, QEvent *event)
#ifndef QT_NO_DRAGANDDROP
// The window may lose focus during an drag operation.
// i.e when dragging involves the taskbar on Windows.
- if (QDragManager::self() && QDragManager::self()->object != 0)
+ QPlatformDrag *platformDrag = QGuiApplicationPrivate::instance()->platformIntegration()->drag();
+ if (platformDrag && platformDrag->currentDrag()) {
return false;
+ }
#endif
emit commitData(editor);