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>
This commit is contained in:
parent
70784b9069
commit
3a72a1c7ed
@ -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 \
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QObject *QDragManager::currentTarget()
|
||||
{
|
||||
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();
|
||||
m_currentDropTarget = target;
|
||||
if (!dropped && m_object) {
|
||||
m_object->d_func()->target = target;
|
||||
emit m_object->targetChanged(target);
|
||||
}
|
||||
}
|
||||
|
||||
void QDragManager::updateCursor()
|
||||
QObject *QDragManager::currentTarget() const
|
||||
{
|
||||
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;
|
||||
if (m_object) {
|
||||
qWarning("QDragManager::drag in possibly invalid state");
|
||||
return Qt::IgnoreAction;
|
||||
}
|
||||
|
||||
object = o;
|
||||
if (!shapedPixmapWindow)
|
||||
shapedPixmapWindow = new QShapedPixmapWindow();
|
||||
oldstate = Qt::NoModifier; // #### Should use state that caused the drag
|
||||
// drag_mode = mode;
|
||||
m_object = o;
|
||||
|
||||
possible_actions = dragPrivate()->possible_actions;
|
||||
m_object->d_func()->target = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
beingCancelled = true;
|
||||
|
||||
platformDrag->cancel();
|
||||
|
||||
if (object && deleteSource)
|
||||
object->deleteLater();
|
||||
object = 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
|
||||
|
@ -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;
|
||||
QMimeData *m_platformDropData;
|
||||
QObject *m_currentDropTarget;
|
||||
QPlatformDrag *m_platformDrag;
|
||||
QDrag *m_object;
|
||||
|
||||
Qt::DropAction currentActionForOverrideCursor;
|
||||
QObject *currentDropTarget;
|
||||
|
||||
QPlatformDrag *platformDrag;
|
||||
|
||||
static QDragManager *instance;
|
||||
static QDragManager *m_instance;
|
||||
Q_DISABLE_COPY(QDragManager)
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
Qt::DropAction transformedDefaultDropAction = Qt::IgnoreAction;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -335,6 +329,49 @@ void QDrag::setDragCursor(const QPixmap &cursor, Qt::DropAction action)
|
||||
d->customCursors[action] = cursor;
|
||||
}
|
||||
|
||||
/*!
|
||||
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)
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
187
src/gui/kernel/qplatformdrag_qpa.cpp
Normal file
187
src/gui/kernel/qplatformdrag_qpa.cpp
Normal file
@ -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
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -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 ®ion);
|
||||
|
||||
// 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);
|
||||
|
||||
|
@ -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
|
||||
|
100
src/platformsupport/dnd/qshapedpixmapdndwindow.cpp
Normal file
100
src/platformsupport/dnd/qshapedpixmapdndwindow.cpp
Normal file
@ -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
|
78
src/platformsupport/dnd/qshapedpixmapdndwindow_p.h
Normal file
78
src/platformsupport/dnd/qshapedpixmapdndwindow_p.h
Normal file
@ -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
|
@ -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_drag_icon_window;
|
||||
}
|
||||
|
||||
void QBasicDrag::enableEventFilter()
|
||||
{
|
||||
qApp->installEventFilter(this);
|
||||
}
|
||||
|
||||
void QBasicDrag::disableEventFilter()
|
||||
{
|
||||
qApp->removeEventFilter(this);
|
||||
}
|
||||
|
||||
bool QBasicDrag::eventFilter(QObject *o, QEvent *e)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
resetDndState(true);
|
||||
disableEventFilter();
|
||||
exitDndEventLoop();
|
||||
|
||||
}
|
||||
return true; // Eat all key events
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Qt::DropAction QBasicDrag::drag(QDrag *o)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void QBasicDrag::drop(const QMouseEvent *)
|
||||
{
|
||||
disableEventFilter();
|
||||
m_drag_icon_window->setVisible(false);
|
||||
}
|
||||
|
||||
void QBasicDrag::exitDndEventLoop()
|
||||
{
|
||||
if (m_eventLoop && m_eventLoop->isRunning())
|
||||
m_eventLoop->exit();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
QSimpleDrag::QSimpleDrag() : m_current_window(0)
|
||||
{
|
||||
delete m_dropData;
|
||||
}
|
||||
|
||||
QMimeData *QSimpleDrag::platformDropData()
|
||||
{
|
||||
return m_dropData;
|
||||
if (drag())
|
||||
return drag()->mimeData();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void QSimpleDrag::startDrag()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void QSimpleDrag::cancel()
|
||||
{
|
||||
QDragManager *m = QDragManager::self();
|
||||
// qDebug("QDragManager::cancel");
|
||||
if (m->object->target()) {
|
||||
QDragLeaveEvent dle;
|
||||
QCoreApplication::sendEvent(m->object->target(), &dle);
|
||||
}
|
||||
|
||||
QBasicDrag::cancel();
|
||||
if (drag())
|
||||
QWindowSystemInterface::handleDrag(m_current_window, 0, QPoint(), Qt::IgnoreAction);
|
||||
m_current_window = 0;
|
||||
}
|
||||
|
||||
void QSimpleDrag::move(const QMouseEvent *me)
|
||||
{
|
||||
QBasicDrag::move(me);
|
||||
QWindow *window = QGuiApplication::topLevelAt(me->globalPos());
|
||||
QPoint pos;
|
||||
if (window)
|
||||
pos = me->globalPos() - window->geometry().topLeft();
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
QDragManager *m = QDragManager::self();
|
||||
const QPoint pos = me->globalPos() - window->geometry().topLeft();
|
||||
const QPlatformDragQtResponse qt_response =
|
||||
QWindowSystemInterface::handleDrag(window, drag()->mimeData(), pos, drag()->supportedActions());
|
||||
|
||||
if (me->buttons()) {
|
||||
Qt::DropAction prevAction = m->global_accepted_action;
|
||||
|
||||
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();
|
||||
}
|
||||
if (m->global_accepted_action != prevAction)
|
||||
m->emitActionChanged(m->global_accepted_action);
|
||||
}
|
||||
updateCursor(qt_response.acceptedAction());
|
||||
setCanDrop(qt_response.isAccepted());
|
||||
}
|
||||
|
||||
void QSimpleDrag::drop(const QMouseEvent *me)
|
||||
{
|
||||
QDragManager *m = QDragManager::self();
|
||||
|
||||
QBasicDrag::drop(me);
|
||||
QWindow *window = QGuiApplication::topLevelAt(me->globalPos());
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
if (window) {
|
||||
QPoint pos = me->globalPos() - window->geometry().topLeft();
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
currentWindow = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
QDropData::QDropData()
|
||||
: QInternalMimeData()
|
||||
{
|
||||
}
|
||||
|
||||
QDropData::~QDropData()
|
||||
{
|
||||
}
|
||||
|
||||
QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type type) const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
bool QDropData::hasFormat_sys(const QString &format) const
|
||||
{
|
||||
return formats().contains(format);
|
||||
}
|
||||
|
||||
QStringList QDropData::formats_sys() const
|
||||
{
|
||||
QDrag *object = QDragManager::self()->object;
|
||||
if (object)
|
||||
return object->mimeData()->formats();
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -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 Qt::DropAction drag(QDrag *);
|
||||
virtual bool eventFilter(QObject *o, QEvent *e);
|
||||
|
||||
protected:
|
||||
QBasicDrag();
|
||||
|
||||
virtual void startDrag();
|
||||
virtual void cancel();
|
||||
virtual void move(const QMouseEvent *me);
|
||||
virtual void drop(const QMouseEvent *me);
|
||||
private:
|
||||
QDropData *m_dropData;
|
||||
virtual void endDrag();
|
||||
|
||||
QWindow *currentWindow;
|
||||
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:
|
||||
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();
|
||||
|
||||
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
|
||||
|
@ -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();
|
||||
const QPlatformDropQtResponse response =
|
||||
QWindowSystemInterface::handleDrop(dropWindow, windowsDrag->platformDropData(), m_lastPoint,
|
||||
translateToQDragDropActions(*pdwEffect));
|
||||
|
||||
if (e.isAccepted()) {
|
||||
if (e.dropAction() == Qt::MoveAction || e.dropAction() == Qt::TargetMoveAction) {
|
||||
if (e.dropAction() == Qt::MoveAction)
|
||||
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()
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
// timestamp from the source
|
||||
if (e->data.data32[3] != XCB_NONE)
|
||||
target_time /*= X11->userTime*/ = e->data.data32[3];
|
||||
currentPosition = p;
|
||||
currentWindow = w;
|
||||
|
||||
QDragManager *manager = QDragManager::self();
|
||||
QMimeData *dropData = manager->dropData();
|
||||
// timestamp from the source
|
||||
if (e->data.data32[3] != XCB_NONE) {
|
||||
target_time = e->data.data32[3];
|
||||
}
|
||||
|
||||
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
|
||||
response.data.data32[4] = toXdndAction(qt_response.acceptedAction()); // 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;
|
||||
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);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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 *)¬ify);
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user