diff options
Diffstat (limited to 'src/gui/kernel/qsimpledrag.cpp')
-rw-r--r-- | src/gui/kernel/qsimpledrag.cpp | 132 |
1 files changed, 76 insertions, 56 deletions
diff --git a/src/gui/kernel/qsimpledrag.cpp b/src/gui/kernel/qsimpledrag.cpp index 12e204a09f..a84f873437 100644 --- a/src/gui/kernel/qsimpledrag.cpp +++ b/src/gui/kernel/qsimpledrag.cpp @@ -94,11 +94,7 @@ static QWindow* topLevelAt(const QPoint &pos) (within the Qt application or outside) accepts the drag and sets the state accordingly. */ -QBasicDrag::QBasicDrag() : - m_current_window(nullptr), m_restoreCursor(false), m_eventLoop(nullptr), - m_executed_drop_action(Qt::IgnoreAction), m_can_drop(false), - m_drag(nullptr), m_drag_icon_window(nullptr), m_useCompositing(true), - m_screen(nullptr) +QBasicDrag::QBasicDrag() { } @@ -158,7 +154,8 @@ bool QBasicDrag::eventFilter(QObject *o, QEvent *e) case QEvent::MouseMove: { QPoint nativePosition = getNativeMousePos(e, m_drag_icon_window); - move(nativePosition); + auto mouseMove = static_cast<QMouseEvent *>(e); + move(nativePosition, mouseMove->buttons(), mouseMove->modifiers()); return true; // Eat all mouse move events } case QEvent::MouseButtonRelease: @@ -166,7 +163,8 @@ bool QBasicDrag::eventFilter(QObject *o, QEvent *e) disableEventFilter(); if (canDrop()) { QPoint nativePosition = getNativeMousePos(e, m_drag_icon_window); - drop(nativePosition); + auto mouseRelease = static_cast<QMouseEvent *>(e); + drop(nativePosition, mouseRelease->buttons(), mouseRelease->modifiers()); } else { cancel(); } @@ -179,9 +177,9 @@ bool QBasicDrag::eventFilter(QObject *o, QEvent *e) // make the event relative to the window where the drag started. (QTBUG-66103) const QMouseEvent *release = static_cast<QMouseEvent *>(e); const QWindow *releaseWindow = topLevelAt(release->globalPos()); - qCDebug(lcDnd) << "mouse released over" << releaseWindow << "after drag from" << m_current_window << "globalPos" << release->globalPos(); + qCDebug(lcDnd) << "mouse released over" << releaseWindow << "after drag from" << m_sourceWindow << "globalPos" << release->globalPos(); if (!releaseWindow) - releaseWindow = m_current_window; + releaseWindow = m_sourceWindow; QPoint releaseWindowPos = (releaseWindow ? releaseWindow->mapFromGlobal(release->globalPos()) : release->globalPos()); QMouseEvent *newRelease = new QMouseEvent(release->type(), releaseWindowPos, releaseWindowPos, release->screenPos(), @@ -204,18 +202,15 @@ 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; + m_eventLoop = nullptr; + m_drag = nullptr; endDrag(); + return m_executed_drop_action; } @@ -227,16 +222,6 @@ void QBasicDrag::cancelDrag() } } -void QBasicDrag::restoreCursor() -{ - if (m_restoreCursor) { -#ifndef QT_NO_CURSOR - QGuiApplication::restoreOverrideCursor(); -#endif - m_restoreCursor = false; - } -} - void QBasicDrag::startDrag() { QPoint pos; @@ -287,7 +272,7 @@ void QBasicDrag::moveShapedPixmapWindow(const QPoint &globalPos) m_drag_icon_window->updateGeometry(globalPos); } -void QBasicDrag::drop(const QPoint &) +void QBasicDrag::drop(const QPoint &, Qt::MouseButtons, Qt::KeyboardModifiers) { disableEventFilter(); restoreCursor(); @@ -318,25 +303,34 @@ void QBasicDrag::updateCursor(Qt::DropAction action) } } - QCursor *cursor = QGuiApplication::overrideCursor(); QPixmap pixmap = m_drag->dragCursor(action); - if (!cursor) { - QGuiApplication::changeOverrideCursor((pixmap.isNull()) ? QCursor(cursorShape) : QCursor(pixmap)); + + if (!m_dndHasSetOverrideCursor) { + QCursor newCursor = !pixmap.isNull() ? QCursor(pixmap) : QCursor(cursorShape); + QGuiApplication::setOverrideCursor(newCursor); + m_dndHasSetOverrideCursor = true; } else { + QCursor *cursor = QGuiApplication::overrideCursor(); if (!pixmap.isNull()) { - if ((cursor->pixmap().cacheKey() != pixmap.cacheKey())) { + if (cursor->pixmap().cacheKey() != pixmap.cacheKey()) QGuiApplication::changeOverrideCursor(QCursor(pixmap)); - } - } else { - if (cursorShape != cursor->shape()) { - QGuiApplication::changeOverrideCursor(QCursor(cursorShape)); - } + } else if (cursorShape != cursor->shape()) { + QGuiApplication::changeOverrideCursor(QCursor(cursorShape)); } } #endif updateAction(action); } +void QBasicDrag::restoreCursor() +{ +#ifndef QT_NO_CURSOR + if (m_dndHasSetOverrideCursor) { + QGuiApplication::restoreOverrideCursor(); + m_dndHasSetOverrideCursor = false; + } +#endif +} static inline QPoint fromNativeGlobalPixels(const QPoint &point) { @@ -374,57 +368,83 @@ QSimpleDrag::QSimpleDrag() void QSimpleDrag::startDrag() { + setExecutedDropAction(Qt::IgnoreAction); + QBasicDrag::startDrag(); - m_current_window = topLevelAt(QCursor::pos()); - if (m_current_window) { - QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_current_window, drag()->mimeData(), QHighDpi::toNativePixels(QCursor::pos(), m_current_window), drag()->supportedActions()); - setCanDrop(response.isAccepted()); - updateCursor(response.acceptedAction()); + // Here we can be fairly sure that QGuiApplication::mouseButtons/keyboardModifiers() will + // contain sensible values as startDrag() normally is called from mouse event handlers + // by QDrag::exec(). A better API would be if we could pass something like "input device + // pointer" to QDrag::exec(). My guess is that something like that might be required for + // QTBUG-52430. + m_sourceWindow = topLevelAt(QCursor::pos()); + m_windowUnderCursor = m_sourceWindow; + if (m_sourceWindow) { + auto nativePixelPos = QHighDpi::toNativePixels(QCursor::pos(), m_sourceWindow); + move(nativePixelPos, QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); } else { setCanDrop(false); updateCursor(Qt::IgnoreAction); } - setExecutedDropAction(Qt::IgnoreAction); - qCDebug(lcDnd) << "drag began from" << m_current_window<< "cursor pos" << QCursor::pos() << "can drop?" << canDrop(); + + qCDebug(lcDnd) << "drag began from" << m_sourceWindow << "cursor pos" << QCursor::pos() << "can drop?" << canDrop(); +} + +static void sendDragLeave(QWindow *window) +{ + QWindowSystemInterface::handleDrag(window, nullptr, QPoint(), Qt::IgnoreAction, 0, 0); } void QSimpleDrag::cancel() { QBasicDrag::cancel(); - if (drag() && m_current_window) { - QWindowSystemInterface::handleDrag(m_current_window, 0, QPoint(), Qt::IgnoreAction); - m_current_window = 0; + if (drag() && m_sourceWindow) { + sendDragLeave(m_sourceWindow); + m_sourceWindow = nullptr; } } -void QSimpleDrag::move(const QPoint &nativeGlobalPos) +void QSimpleDrag::move(const QPoint &nativeGlobalPos, Qt::MouseButtons buttons, + Qt::KeyboardModifiers modifiers) { QPoint globalPos = fromNativeGlobalPixels(nativeGlobalPos); moveShapedPixmapWindow(globalPos); QWindow *window = topLevelAt(globalPos); - if (!window) - return; + + if (!window || window != m_windowUnderCursor) { + if (m_windowUnderCursor) + sendDragLeave(m_windowUnderCursor); + m_windowUnderCursor = window; + if (!window) { + // QSimpleDrag supports only in-process dnd, we can't drop anywhere else. + setCanDrop(false); + updateCursor(Qt::IgnoreAction); + return; + } + } const QPoint pos = nativeGlobalPos - window->handle()->geometry().topLeft(); - const QPlatformDragQtResponse qt_response = - QWindowSystemInterface::handleDrag(window, drag()->mimeData(), pos, drag()->supportedActions()); + const QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag( + window, drag()->mimeData(), pos, drag()->supportedActions(), + buttons, modifiers); - updateCursor(qt_response.acceptedAction()); setCanDrop(qt_response.isAccepted()); + updateCursor(qt_response.acceptedAction()); } -void QSimpleDrag::drop(const QPoint &nativeGlobalPos) +void QSimpleDrag::drop(const QPoint &nativeGlobalPos, Qt::MouseButtons buttons, + Qt::KeyboardModifiers modifiers) { QPoint globalPos = fromNativeGlobalPixels(nativeGlobalPos); - QBasicDrag::drop(nativeGlobalPos); + QBasicDrag::drop(nativeGlobalPos, buttons, modifiers); QWindow *window = topLevelAt(globalPos); if (!window) return; const QPoint pos = nativeGlobalPos - window->handle()->geometry().topLeft(); - const QPlatformDropQtResponse response = - QWindowSystemInterface::handleDrop(window, drag()->mimeData(),pos, drag()->supportedActions()); + const QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop( + window, drag()->mimeData(), pos, drag()->supportedActions(), + buttons, modifiers); if (response.isAccepted()) { setExecutedDropAction(response.acceptedAction()); } else { |