Cocoa: Fix DnD when using native widgets.

Adding a native widget such as QGLWidget often causes
other widgets to become native, through native ancestor
and sibling propagation.

This includes QFocusFrame, which typically sits on
top of item views. QFocusFrame is mostly transparent
(except for the frame) and also has the WA_TransparentForMouseEvents
flag set. Its window has the corresponding
WindowTransparentForInput flag set.

Cocoa does not know about WindowTransparentForInput.
Forward the drag calls to the correct window.

Task-number: QTBUG-37077
Change-Id: I02201c7027915b1e82d0cd7e9c2e787ca6b2338b
Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@digia.com>
This commit is contained in:
Morten Johan Sørvig 2014-02-26 12:33:29 +01:00 committed by The Qt Project
parent 1a6011e09f
commit 000693018b

View File

@ -1648,6 +1648,21 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
}
}
static QWindow *findEventTargetWindow(QWindow *candidate)
{
while (candidate) {
if (!(candidate->flags() & Qt::WindowTransparentForInput))
return candidate;
candidate = candidate->parent();
}
return candidate;
}
static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint point)
{
return target->mapFromGlobal(source->mapToGlobal(point));
}
- (NSDragOperation) draggingSourceOperationMaskForLocal:(BOOL)isLocal
{
Q_UNUSED(isLocal);
@ -1677,16 +1692,18 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]);
QWindow *target = findEventTargetWindow(m_window);
// update these so selecting move/copy/link works
QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers: [[NSApp currentEvent] modifierFlags]];
QPlatformDragQtResponse response(false, Qt::IgnoreAction, QRect());
if ([sender draggingSource] != nil) {
QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
response = QWindowSystemInterface::handleDrag(m_window, nativeDrag->platformDropData(), qt_windowPoint, qtAllowed);
response = QWindowSystemInterface::handleDrag(target, nativeDrag->platformDropData(), mapWindowCoordinates(m_window, target, qt_windowPoint), qtAllowed);
} else {
QCocoaDropData mimeData([sender draggingPasteboard]);
response = QWindowSystemInterface::handleDrag(m_window, &mimeData, qt_windowPoint, qtAllowed);
response = QWindowSystemInterface::handleDrag(target, &mimeData, mapWindowCoordinates(m_window, target, qt_windowPoint), qtAllowed);
}
return qt_mac_mapDropAction(response.acceptedAction());
@ -1694,16 +1711,20 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (void)draggingExited:(id <NSDraggingInfo>)sender
{
QWindow *target = findEventTargetWindow(m_window);
NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
// Send 0 mime data to indicate drag exit
QWindowSystemInterface::handleDrag(m_window, 0 ,qt_windowPoint, Qt::IgnoreAction);
QWindowSystemInterface::handleDrag(target, 0, mapWindowCoordinates(m_window, target, qt_windowPoint), Qt::IgnoreAction);
}
// called on drop, send the drop to Qt and return if it was accepted.
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
QWindow *target = findEventTargetWindow(m_window);
NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]);
@ -1711,10 +1732,10 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
QPlatformDropQtResponse response(false, Qt::IgnoreAction);
if ([sender draggingSource] != nil) {
QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
response = QWindowSystemInterface::handleDrop(m_window, nativeDrag->platformDropData(), qt_windowPoint, qtAllowed);
response = QWindowSystemInterface::handleDrop(target, nativeDrag->platformDropData(), mapWindowCoordinates(m_window, target, qt_windowPoint), qtAllowed);
} else {
QCocoaDropData mimeData([sender draggingPasteboard]);
response = QWindowSystemInterface::handleDrop(m_window, &mimeData, qt_windowPoint, qtAllowed);
response = QWindowSystemInterface::handleDrop(target, &mimeData, mapWindowCoordinates(m_window, target, qt_windowPoint), qtAllowed);
}
if (response.isAccepted()) {
QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
@ -1727,6 +1748,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
{
Q_UNUSED(img);
Q_UNUSED(operation);
QWindow *target = findEventTargetWindow(m_window);
// keep our state, and QGuiApplication state (buttons member) in-sync,
// or future mouse events will be processed incorrectly
@ -1739,7 +1761,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
NSPoint screenPoint = [window convertBaseToScreen :point];
QPoint qtScreenPoint = QPoint(screenPoint.x, qt_mac_flipYCoordinate(screenPoint.y));
QWindowSystemInterface::handleMouseEvent(m_window, qtWindowPoint, qtScreenPoint, m_buttons);
QWindowSystemInterface::handleMouseEvent(target, mapWindowCoordinates(m_window, target, qtWindowPoint), qtScreenPoint, m_buttons);
}
@end