diff options
Diffstat (limited to 'src/platformsupport')
-rw-r--r-- | src/platformsupport/dnd/dnd.pri | 6 | ||||
-rw-r--r-- | src/platformsupport/dnd/qshapedpixmapdndwindow.cpp | 100 | ||||
-rw-r--r-- | src/platformsupport/dnd/qshapedpixmapdndwindow_p.h | 78 | ||||
-rw-r--r-- | src/platformsupport/dnd/qsimpledrag.cpp | 318 | ||||
-rw-r--r-- | src/platformsupport/dnd/qsimpledrag_p.h | 64 |
5 files changed, 465 insertions, 101 deletions
diff --git a/src/platformsupport/dnd/dnd.pri b/src/platformsupport/dnd/dnd.pri index e100dd10cb..47feb81ef2 100644 --- a/src/platformsupport/dnd/dnd.pri +++ b/src/platformsupport/dnd/dnd.pri @@ -1,4 +1,6 @@ HEADERS += \ - $$PWD/qsimpledrag_p.h + $$PWD/qsimpledrag_p.h \ + $$PWD/qshapedpixmapdndwindow_p.h SOURCES += \ - $$PWD/qsimpledrag.cpp + $$PWD/qsimpledrag.cpp \ + $$PWD/qshapedpixmapdndwindow.cpp diff --git a/src/platformsupport/dnd/qshapedpixmapdndwindow.cpp b/src/platformsupport/dnd/qshapedpixmapdndwindow.cpp new file mode 100644 index 0000000000..4eed1e7d85 --- /dev/null +++ b/src/platformsupport/dnd/qshapedpixmapdndwindow.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qshapedpixmapdndwindow_p.h" + +#include <QtGui/QPainter> +#include <QtGui/QCursor> + +QT_BEGIN_NAMESPACE + +QShapedPixmapWindow::QShapedPixmapWindow() + : QWindow(), + m_backingStore(0) +{ + setSurfaceType(RasterSurface); + setWindowFlags(Qt::ToolTip | Qt::FramelessWindowHint | + Qt::X11BypassWindowManagerHint | Qt::WindowTransparentForInput); + create(); + m_backingStore = new QBackingStore(this); +} + +void QShapedPixmapWindow::render() +{ + QRect rect(QPoint(), geometry().size()); + + m_backingStore->beginPaint(rect); + + QPaintDevice *device = m_backingStore->paintDevice(); + + { + QPainter p(device); + p.drawPixmap(0, 0, m_pixmap); + } + + m_backingStore->endPaint(); + m_backingStore->flush(rect); +} + +void QShapedPixmapWindow::setPixmap(const QPixmap &pixmap) +{ + m_pixmap = pixmap; +} + +void QShapedPixmapWindow::setHotspot(const QPoint &hotspot) +{ + m_hotSpot = hotspot; +} + +void QShapedPixmapWindow::updateGeometry() +{ + QRect rect(QCursor::pos() - m_hotSpot, m_pixmap.size()); + if (m_backingStore->size() != m_pixmap.size()) + m_backingStore->resize(m_pixmap.size()); + setGeometry(rect); +} + +void QShapedPixmapWindow::exposeEvent(QExposeEvent *) +{ + render(); +} + +QT_END_NAMESPACE diff --git a/src/platformsupport/dnd/qshapedpixmapdndwindow_p.h b/src/platformsupport/dnd/qshapedpixmapdndwindow_p.h new file mode 100644 index 0000000000..36ca6040dd --- /dev/null +++ b/src/platformsupport/dnd/qshapedpixmapdndwindow_p.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSHAPEDPIXMAPDNDWINDOW_H +#define QSHAPEDPIXMAPDNDWINDOW_H + +#include <QtGui/QWindow> +#include <QtGui/QPixmap> +#include <QtGui/QBackingStore> + +QT_BEGIN_NAMESPACE + +QT_BEGIN_HEADER + +class QShapedPixmapWindow : public QWindow +{ +public: + QShapedPixmapWindow(); + + void render(); + + void setPixmap(const QPixmap &pixmap); + void setHotspot(const QPoint &hotspot); + + void updateGeometry(); + +protected: + void exposeEvent(QExposeEvent *); + +private: + QBackingStore *m_backingStore; + QPixmap m_pixmap; + QPoint m_hotSpot; +}; + +QT_END_HEADER + +QT_END_NAMESPACE + +#endif // QSHAPEDPIXMAPDNDWINDOW_H diff --git a/src/platformsupport/dnd/qsimpledrag.cpp b/src/platformsupport/dnd/qsimpledrag.cpp index d0d08c2445..d3cecd4e44 100644 --- a/src/platformsupport/dnd/qsimpledrag.cpp +++ b/src/platformsupport/dnd/qsimpledrag.cpp @@ -56,147 +56,283 @@ #include "qimagereader.h" #include "qimagewriter.h" +#include <QtCore/QEventLoop> +#include <QtCore/QDebug> + #include <private/qguiapplication_p.h> #include <private/qdnd_p.h> +#include <QtPlatformSupport/private/qshapedpixmapdndwindow_p.h> + QT_BEGIN_NAMESPACE -class QDropData : public QInternalMimeData -{ -public: - QDropData(); - ~QDropData(); +/*! + \class QBasicDrag + \brief QBasicDrag is a base class for implementing platform drag and drop. + \since 5.0 + \internal + \ingroup qpa -protected: - bool hasFormat_sys(const QString &mimeType) const; - QStringList formats_sys() const; - QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type) const; -}; + QBasicDrag implements QPlatformDrag::drag() by running a local event loop in which + it tracks mouse movements and moves the drag icon (QShapedPixmapWindow) accordingly. + It provides new virtuals allowing for querying whether the receiving window + (within the Qt application or outside) accepts the drag and sets the state accordingly. +*/ -QSimpleDrag::QSimpleDrag() +QBasicDrag::QBasicDrag() : + m_restoreCursor(false), m_eventLoop(0), + m_executed_drop_action(Qt::IgnoreAction), m_can_drop(false), + m_drag(0), m_drag_icon_window(0), m_cursor_drop_action(Qt::IgnoreAction) { - m_dropData = new QDropData(); - currentWindow = 0; } -QSimpleDrag::~QSimpleDrag() +QBasicDrag::~QBasicDrag() { - delete m_dropData; + delete m_drag_icon_window; } -QMimeData *QSimpleDrag::platformDropData() +void QBasicDrag::enableEventFilter() { - return m_dropData; + qApp->installEventFilter(this); } -void QSimpleDrag::cancel() +void QBasicDrag::disableEventFilter() { - QDragManager *m = QDragManager::self(); -// qDebug("QDragManager::cancel"); - if (m->object->target()) { - QDragLeaveEvent dle; - QCoreApplication::sendEvent(m->object->target(), &dle); - } - + qApp->removeEventFilter(this); } -void QSimpleDrag::move(const QMouseEvent *me) +bool QBasicDrag::eventFilter(QObject *o, QEvent *e) { - QWindow *window = QGuiApplication::topLevelAt(me->globalPos()); - QPoint pos; - if (window) - pos = me->globalPos() - window->geometry().topLeft(); + if (!m_drag) { + if (e->type() == QEvent::KeyRelease && static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) { + disableEventFilter(); + exitDndEventLoop(); + return true; // block the key release + } + return false; + } - QDragManager *m = QDragManager::self(); + if (!qobject_cast<QWindow *>(o)) + return false; - if (me->buttons()) { - Qt::DropAction prevAction = m->global_accepted_action; + switch (e->type()) { + case QEvent::ShortcutOverride: + // prevent accelerators from firing while dragging + e->accept(); + return true; + + case QEvent::KeyPress: + case QEvent::KeyRelease: + { + QKeyEvent *ke = static_cast<QKeyEvent *>(e); + if (ke->key() == Qt::Key_Escape && e->type() == QEvent::KeyPress) { + cancel(); + resetDndState(true); + disableEventFilter(); + exitDndEventLoop(); - if (currentWindow != window) { - if (currentWindow) { - QDragLeaveEvent dle; - QCoreApplication::sendEvent(currentWindow, &dle); - m->willDrop = false; - m->global_accepted_action = Qt::IgnoreAction; - } - currentWindow = window; - if (currentWindow) { - QDragEnterEvent dee(pos, m->possible_actions, m->dropData(), me->buttons(), me->modifiers()); - QCoreApplication::sendEvent(currentWindow, &dee); - m->willDrop = dee.isAccepted() && dee.dropAction() != Qt::IgnoreAction; - m->global_accepted_action = m->willDrop ? dee.dropAction() : Qt::IgnoreAction; - } - m->updateCursor(); - } else if (window) { - Q_ASSERT(currentWindow); - QDragMoveEvent dme(pos, m->possible_actions, m->dropData(), me->buttons(), me->modifiers()); - if (m->global_accepted_action != Qt::IgnoreAction) { - dme.setDropAction(m->global_accepted_action); - dme.accept(); } - QCoreApplication::sendEvent(currentWindow, &dme); - m->willDrop = dme.isAccepted(); - m->global_accepted_action = m->willDrop ? dme.dropAction() : Qt::IgnoreAction; - m->updatePixmap(); - m->updateCursor(); + return true; // Eat all key events } - if (m->global_accepted_action != prevAction) - m->emitActionChanged(m->global_accepted_action); + + case QEvent::MouseMove: + move(static_cast<QMouseEvent *>(e)); + return true; // Eat all mouse events + + case QEvent::MouseButtonRelease: + disableEventFilter(); + + if (canDrop()) { + drop(static_cast<QMouseEvent *>(e)); + resetDndState(false); + } else { + cancel(); + resetDndState(true); + } + exitDndEventLoop(); + return true; // Eat all mouse events + + case QEvent::MouseButtonPress: + case QEvent::MouseButtonDblClick: + case QEvent::Wheel: + return true; + default: + break; } + return false; } -void QSimpleDrag::drop(const QMouseEvent *me) +Qt::DropAction QBasicDrag::drag(QDrag *o) { - QDragManager *m = QDragManager::self(); + m_drag = o; + m_executed_drop_action = Qt::IgnoreAction; + m_can_drop = false; + m_restoreCursor = true; +#ifndef QT_NO_CURSOR + qApp->setOverrideCursor(Qt::DragCopyCursor); + updateCursor(m_executed_drop_action); +#endif + startDrag(); + m_eventLoop = new QEventLoop; + m_eventLoop->exec(); + delete m_eventLoop; + m_eventLoop = 0; + m_drag = 0; + endDrag(); + return m_executed_drop_action; +} - QWindow *window = QGuiApplication::topLevelAt(me->globalPos()); +void QBasicDrag::resetDndState(bool /* deleteSource */) +{ + if (m_restoreCursor) { +#ifndef QT_NO_CURSOR + QGuiApplication::restoreOverrideCursor(); +#endif + m_restoreCursor = false; + } +} + +void QBasicDrag::startDrag() +{ + if (!m_drag_icon_window) + m_drag_icon_window = new QShapedPixmapWindow(); + + m_drag_icon_window->setPixmap(m_drag->pixmap()); + m_drag_icon_window->setHotspot(m_drag->hotSpot()); + m_drag_icon_window->updateGeometry(); + m_drag_icon_window->setVisible(true); + + enableEventFilter(); +} + +void QBasicDrag::endDrag() +{ +} + +void QBasicDrag::cancel() +{ + disableEventFilter(); + m_drag_icon_window->setVisible(false); +} + +void QBasicDrag::move(const QMouseEvent *) +{ + if (m_drag) + m_drag_icon_window->updateGeometry(); +} - if (window) { - QPoint pos = me->globalPos() - window->geometry().topLeft(); +void QBasicDrag::drop(const QMouseEvent *) +{ + disableEventFilter(); + m_drag_icon_window->setVisible(false); +} + +void QBasicDrag::exitDndEventLoop() +{ + if (m_eventLoop && m_eventLoop->isRunning()) + m_eventLoop->exit(); +} - QDropEvent de(pos, m->possible_actions, m->dropData(), me->buttons(), me->modifiers()); - QCoreApplication::sendEvent(window, &de); - if (de.isAccepted()) - m->global_accepted_action = de.dropAction(); - else - m->global_accepted_action = Qt::IgnoreAction; +void QBasicDrag::updateCursor(Qt::DropAction action) +{ + Qt::CursorShape cursorShape = Qt::ForbiddenCursor; + if (canDrop()) { + switch (action) { + case Qt::CopyAction: + cursorShape = Qt::DragCopyCursor; + break; + case Qt::LinkAction: + cursorShape = Qt::DragLinkCursor; + break; + default: + cursorShape = Qt::DragMoveCursor; + break; + } } - currentWindow = 0; + + QCursor *cursor = qApp->overrideCursor(); + if (cursor && cursorShape != cursor->shape()) { + qApp->changeOverrideCursor(QCursor(cursorShape)); + } + updateAction(action); } +/*! + \class QSimpleDrag + \brief QSimpleDrag implements QBasicDrag for Drag and Drop operations within the Qt Application itself. + \since 5.0 + \internal + \ingroup qpa + The class checks whether the receiving window is a window of the Qt application + and sets the state accordingly. It does not take windows of other applications + into account. +*/ -QDropData::QDropData() - : QInternalMimeData() +QSimpleDrag::QSimpleDrag() : m_current_window(0) { } -QDropData::~QDropData() +QMimeData *QSimpleDrag::platformDropData() { + if (drag()) + return drag()->mimeData(); + return 0; } -QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type type) const +void QSimpleDrag::startDrag() { - QDrag *object = QDragManager::self()->object; - if (!object) - return QVariant(); - QByteArray data = object->mimeData()->data(mimetype); - if (type == QVariant::String) - return QString::fromUtf8(data); - return data; + QBasicDrag::startDrag(); + m_current_window = QGuiApplication::topLevelAt(QCursor::pos()); + if (m_current_window) { + QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_current_window, drag()->mimeData(), QCursor::pos(), drag()->supportedActions()); + setCanDrop(response.isAccepted()); + updateCursor(response.acceptedAction()); + } else { + setCanDrop(false); + updateCursor(Qt::IgnoreAction); + } + setExecutedDropAction(Qt::IgnoreAction); } -bool QDropData::hasFormat_sys(const QString &format) const +void QSimpleDrag::cancel() { - return formats().contains(format); + QBasicDrag::cancel(); + if (drag()) + QWindowSystemInterface::handleDrag(m_current_window, 0, QPoint(), Qt::IgnoreAction); + m_current_window = 0; } -QStringList QDropData::formats_sys() const +void QSimpleDrag::move(const QMouseEvent *me) { - QDrag *object = QDragManager::self()->object; - if (object) - return object->mimeData()->formats(); - return QStringList(); + QBasicDrag::move(me); + QWindow *window = QGuiApplication::topLevelAt(me->globalPos()); + if (!window) + return; + + const QPoint pos = me->globalPos() - window->geometry().topLeft(); + const QPlatformDragQtResponse qt_response = + QWindowSystemInterface::handleDrag(window, drag()->mimeData(), pos, drag()->supportedActions()); + + updateCursor(qt_response.acceptedAction()); + setCanDrop(qt_response.isAccepted()); +} + +void QSimpleDrag::drop(const QMouseEvent *me) +{ + QBasicDrag::drop(me); + QWindow *window = QGuiApplication::topLevelAt(me->globalPos()); + if (!window) + return; + + const QPoint pos = me->globalPos() - window->geometry().topLeft(); + const QPlatformDropQtResponse response = + QWindowSystemInterface::handleDrop(window, drag()->mimeData(),pos, drag()->supportedActions()); + if (response.isAccepted()) { + setExecutedDropAction(response.acceptedAction()); + } else { + setExecutedDropAction(Qt::IgnoreAction); + } } QT_END_NAMESPACE diff --git a/src/platformsupport/dnd/qsimpledrag_p.h b/src/platformsupport/dnd/qsimpledrag_p.h index 536ae241ff..7270684082 100644 --- a/src/platformsupport/dnd/qsimpledrag_p.h +++ b/src/platformsupport/dnd/qsimpledrag_p.h @@ -44,32 +44,80 @@ #include <qplatformdrag_qpa.h> +#include <QtCore/QObject> + QT_BEGIN_NAMESPACE +QT_BEGIN_HEADER + class QMouseEvent; class QWindow; - +class QEventLoop; class QDropData; +class QShapedPixmapWindow; -class QSimpleDrag : public QPlatformDrag +class QBasicDrag : public QPlatformDrag, public QObject { public: - QSimpleDrag(); - ~QSimpleDrag(); + virtual ~QBasicDrag(); - virtual QMimeData *platformDropData(); + virtual Qt::DropAction drag(QDrag *drag); + + virtual bool eventFilter(QObject *o, QEvent *e); -// virtual Qt::DropAction drag(QDrag *); +protected: + QBasicDrag(); + virtual void startDrag(); virtual void cancel(); virtual void move(const QMouseEvent *me); virtual void drop(const QMouseEvent *me); + virtual void endDrag(); + + QShapedPixmapWindow *shapedPixmapWindow() const { return m_drag_icon_window; } + void updateCursor(Qt::DropAction action); + + bool canDrop() const { return m_can_drop; } + void setCanDrop(bool c) { m_can_drop = c; } + + Qt::DropAction executedDropAction() const { return m_executed_drop_action; } + void setExecutedDropAction(Qt::DropAction da) { m_executed_drop_action = da; } + + QDrag *drag() const { return m_drag; } + private: - QDropData *m_dropData; + void enableEventFilter(); + void disableEventFilter(); + void resetDndState(bool deleteSource); + void exitDndEventLoop(); + + bool m_restoreCursor; + QEventLoop *m_eventLoop; + Qt::DropAction m_executed_drop_action; + bool m_can_drop; + QDrag *m_drag; + QShapedPixmapWindow *m_drag_icon_window; + Qt::DropAction m_cursor_drop_action; +}; + +class QSimpleDrag : public QBasicDrag +{ +public: + QSimpleDrag(); + virtual QMimeData *platformDropData(); - QWindow *currentWindow; +protected: + virtual void startDrag(); + virtual void cancel(); + virtual void move(const QMouseEvent *me); + virtual void drop(const QMouseEvent *me); + +private: + QWindow *m_current_window; }; +QT_END_HEADER + QT_END_NAMESPACE #endif |