widgetwindow: send DragMove for every DragEnter

... as specified in the documentation. This was a regression from Qt4
and can cause mouse cursor flickering durig dragging on e.g. custom
widget where some areas of the widget do not accept drag-and-drop.

Task-number: QTBUG-67155
Change-Id: Iaa6f9407181931ed8e3d6a8fec13fd59d3c8625d
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
Gatis Paeglis 2018-05-11 09:45:12 +02:00
parent 7a7c722782
commit f8944a7f07
3 changed files with 70 additions and 48 deletions

View File

@ -311,8 +311,10 @@ bool QWidgetWindow::event(QEvent *event)
#if QT_CONFIG(draganddrop) #if QT_CONFIG(draganddrop)
case QEvent::DragEnter: case QEvent::DragEnter:
handleDragEnterEvent(static_cast<QDragEnterEvent *>(event));
return true;
case QEvent::DragMove: case QEvent::DragMove:
handleDragEnterMoveEvent(static_cast<QDragMoveEvent *>(event)); handleDragMoveEvent(static_cast<QDragMoveEvent *>(event));
return true; return true;
case QEvent::DragLeave: case QEvent::DragLeave:
handleDragLeaveEvent(static_cast<QDragLeaveEvent *>(event)); handleDragLeaveEvent(static_cast<QDragLeaveEvent *>(event));
@ -849,62 +851,80 @@ void QWidgetWindow::handleWheelEvent(QWheelEvent *event)
#if QT_CONFIG(draganddrop) #if QT_CONFIG(draganddrop)
void QWidgetWindow::handleDragEnterMoveEvent(QDragMoveEvent *event) static QWidget *findDnDTarget(QWidget *parent, const QPoint &pos)
{ {
Q_ASSERT(event->type() ==QEvent::DragMove || !m_dragTarget);
// Find a target widget under mouse that accepts drops (QTBUG-22987). // Find a target widget under mouse that accepts drops (QTBUG-22987).
QWidget *widget = m_widget->childAt(event->pos()); QWidget *widget = parent->childAt(pos);
if (!widget) if (!widget)
widget = m_widget; widget = parent;
for ( ; widget && !widget->isWindow() && !widget->acceptDrops(); widget = widget->parentWidget()) ; for ( ; widget && !widget->isWindow() && !widget->acceptDrops(); widget = widget->parentWidget()) ;
if (widget && !widget->acceptDrops()) if (widget && !widget->acceptDrops())
widget = 0; widget = nullptr;
// Target widget unchanged: DragMove return widget;
if (widget && widget == m_dragTarget.data()) { }
Q_ASSERT(event->type() == QEvent::DragMove);
const QPoint mapped = widget->mapFromGlobal(m_widget->mapToGlobal(event->pos())); void QWidgetWindow::handleDragEnterEvent(QDragEnterEvent *event, QWidget *widget)
QDragMoveEvent translated(mapped, event->possibleActions(), event->mimeData(), event->mouseButtons(), event->keyboardModifiers()); {
translated.setDropAction(event->dropAction()); Q_ASSERT(m_dragTarget == nullptr);
if (event->isAccepted()) { // Handling 'DragEnter' should suffice for the application. if (!widget)
translated.accept(); widget = findDnDTarget(m_widget, event->pos());
translated.setDropAction(event->dropAction()); if (!widget) {
} event->ignore();
QGuiApplication::forwardEvent(widget, &translated, event);
if (translated.isAccepted()) {
event->accept();
} else {
event->ignore();
}
event->setDropAction(translated.dropAction());
return; return;
} }
// Target widget changed: Send DragLeave to previous, DragEnter to new if there is any
if (m_dragTarget.data()) {
QDragLeaveEvent le;
QGuiApplication::forwardEvent(m_dragTarget.data(), &le, event);
m_dragTarget = 0;
}
if (!widget) {
event->ignore();
return;
}
m_dragTarget = widget; m_dragTarget = widget;
const QPoint mapped = widget->mapFromGlobal(m_widget->mapToGlobal(event->pos())); const QPoint mapped = widget->mapFromGlobal(m_widget->mapToGlobal(event->pos()));
QDragEnterEvent translated(mapped, event->possibleActions(), event->mimeData(), event->mouseButtons(), event->keyboardModifiers()); QDragEnterEvent translated(mapped, event->possibleActions(), event->mimeData(),
QGuiApplication::forwardEvent(widget, &translated, event); event->mouseButtons(), event->keyboardModifiers());
if (translated.isAccepted()) { translated.setDropAction(event->dropAction());
event->accept(); translated.setAccepted(event->isAccepted());
} else { QGuiApplication::forwardEvent(m_dragTarget, &translated, event);
event->ignore(); event->setAccepted(translated.isAccepted());
}
event->setDropAction(translated.dropAction()); event->setDropAction(translated.dropAction());
} }
void QWidgetWindow::handleDragMoveEvent(QDragMoveEvent *event)
{
auto *widget = findDnDTarget(m_widget, event->pos());
if (!widget) {
event->ignore();
if (m_dragTarget) { // Send DragLeave to previous
QDragLeaveEvent leaveEvent;
QGuiApplication::forwardEvent(m_dragTarget, &leaveEvent, event);
m_dragTarget = nullptr;
}
} else {
const QPoint mapped = widget->mapFromGlobal(m_widget->mapToGlobal(event->pos()));
QDragMoveEvent translated(mapped, event->possibleActions(), event->mimeData(),
event->mouseButtons(), event->keyboardModifiers());
translated.setDropAction(event->dropAction());
translated.setAccepted(event->isAccepted());
if (widget == m_dragTarget) { // Target widget unchanged: Send DragMove
QGuiApplication::forwardEvent(m_dragTarget, &translated, event);
} else {
if (m_dragTarget) { // Send DragLeave to previous
QDragLeaveEvent leaveEvent;
QGuiApplication::forwardEvent(m_dragTarget, &leaveEvent, event);
m_dragTarget = nullptr;
}
// Send DragEnter to new widget.
handleDragEnterEvent(static_cast<QDragEnterEvent*>(event), widget);
// The drag enter event is always immediately followed by a drag move event,
// see QDragEnterEvent documentation.
QGuiApplication::forwardEvent(m_dragTarget, &translated, event);
}
event->setAccepted(translated.isAccepted());
event->setDropAction(translated.dropAction());
}
}
void QWidgetWindow::handleDragLeaveEvent(QDragLeaveEvent *event) void QWidgetWindow::handleDragLeaveEvent(QDragLeaveEvent *event)
{ {
if (m_dragTarget) if (m_dragTarget)
QGuiApplication::forwardEvent(m_dragTarget.data(), event); QGuiApplication::forwardEvent(m_dragTarget, event);
m_dragTarget = 0; m_dragTarget = nullptr;
} }
void QWidgetWindow::handleDropEvent(QDropEvent *event) void QWidgetWindow::handleDropEvent(QDropEvent *event)
@ -914,13 +934,12 @@ void QWidgetWindow::handleDropEvent(QDropEvent *event)
event->ignore(); event->ignore();
return; return;
} }
const QPoint mapped = m_dragTarget.data()->mapFromGlobal(m_widget->mapToGlobal(event->pos())); const QPoint mapped = m_dragTarget->mapFromGlobal(m_widget->mapToGlobal(event->pos()));
QDropEvent translated(mapped, event->possibleActions(), event->mimeData(), event->mouseButtons(), event->keyboardModifiers()); QDropEvent translated(mapped, event->possibleActions(), event->mimeData(), event->mouseButtons(), event->keyboardModifiers());
QGuiApplication::forwardEvent(m_dragTarget.data(), &translated, event); QGuiApplication::forwardEvent(m_dragTarget, &translated, event);
if (translated.isAccepted()) event->setAccepted(translated.isAccepted());
event->accept();
event->setDropAction(translated.dropAction()); event->setDropAction(translated.dropAction());
m_dragTarget = 0; m_dragTarget = nullptr;
} }
#endif // QT_CONFIG(draganddrop) #endif // QT_CONFIG(draganddrop)

View File

@ -96,7 +96,8 @@ protected:
void handleWheelEvent(QWheelEvent *); void handleWheelEvent(QWheelEvent *);
#endif #endif
#if QT_CONFIG(draganddrop) #if QT_CONFIG(draganddrop)
void handleDragEnterMoveEvent(QDragMoveEvent *); void handleDragEnterEvent(QDragEnterEvent *, QWidget *widget = nullptr);
void handleDragMoveEvent(QDragMoveEvent *);
void handleDragLeaveEvent(QDragLeaveEvent *); void handleDragLeaveEvent(QDragLeaveEvent *);
void handleDropEvent(QDropEvent *); void handleDropEvent(QDropEvent *);
#endif #endif

View File

@ -423,6 +423,7 @@ static const char *expectedLogC[] = {
"Event at 11,81 ignored", "Event at 11,81 ignored",
"Event at 11,101 ignored", "Event at 11,101 ignored",
"acceptingDropsWidget1::dragEnterEvent at 1,11 action=1 MIME_DATA_ADDRESS 'testmimetext'", "acceptingDropsWidget1::dragEnterEvent at 1,11 action=1 MIME_DATA_ADDRESS 'testmimetext'",
"acceptingDropsWidget1::dragMoveEvent at 1,11 action=1 MIME_DATA_ADDRESS 'testmimetext'",
"Event at 11,121 accepted", "Event at 11,121 accepted",
"acceptingDropsWidget1::dragMoveEvent at 1,31 action=1 MIME_DATA_ADDRESS 'testmimetext'", "acceptingDropsWidget1::dragMoveEvent at 1,31 action=1 MIME_DATA_ADDRESS 'testmimetext'",
"Event at 11,141 accepted", "Event at 11,141 accepted",
@ -433,6 +434,7 @@ static const char *expectedLogC[] = {
"acceptingDropsWidget1::dragLeaveEvent QDragLeaveEvent", "acceptingDropsWidget1::dragLeaveEvent QDragLeaveEvent",
"Event at 11,201 ignored", "Event at 11,201 ignored",
"acceptingDropsWidget2::dragEnterEvent at 1,11 action=1 MIME_DATA_ADDRESS 'testmimetext'", "acceptingDropsWidget2::dragEnterEvent at 1,11 action=1 MIME_DATA_ADDRESS 'testmimetext'",
"acceptingDropsWidget2::dragMoveEvent at 1,11 action=1 MIME_DATA_ADDRESS 'testmimetext'",
"Event at 11,221 accepted", "Event at 11,221 accepted",
"acceptingDropsWidget2::dragMoveEvent at 1,31 action=1 MIME_DATA_ADDRESS 'testmimetext'", "acceptingDropsWidget2::dragMoveEvent at 1,31 action=1 MIME_DATA_ADDRESS 'testmimetext'",
"Event at 11,241 accepted", "Event at 11,241 accepted",