summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPrasanth Ullattil <prasanth.ullattil@nokia.com>2009-07-02 16:25:44 +0200
committerPrasanth Ullattil <prasanth.ullattil@nokia.com>2009-07-02 16:58:13 +0200
commitc6cc00316b2ce95adddc9fdb658d737057b40682 (patch)
tree7351a8ecee8f1548df02239e65c3b26b7018aea6 /src
parent097476afe24d69bac65b84b70ed2f93e88875b40 (diff)
Drag and drop events are not delivered correctly in Cocoa
Drag and drop events should consider the WA_TransparentForMouseEvents attribute like the mouse events. If this attribute is set for a widget, the event has to be passed to right widget under mouse. The widget is identified by calling hitTest. In such cases the leave event has to be delivered to the widget which actually accepted the enter event. Task-number: 252088 Reviewed-by: Norwegian Rock Cat
Diffstat (limited to 'src')
-rw-r--r--src/gui/kernel/qcocoaview_mac.mm49
-rw-r--r--src/gui/kernel/qcocoaview_mac_p.h2
2 files changed, 43 insertions, 8 deletions
diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm
index 81e06a964f..44795318c3 100644
--- a/src/gui/kernel/qcocoaview_mac.mm
+++ b/src/gui/kernel/qcocoaview_mac.mm
@@ -288,11 +288,18 @@ extern "C" {
{
if (qwidget->testAttribute(Qt::WA_DropSiteRegistered) == false)
return NSDragOperationNone;
+ NSPoint windowPoint = [sender draggingLocation];
+ if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
+ // pass the drag enter event to the view underneath.
+ NSView *candidateView = [[[self window] contentView] hitTest:windowPoint];
+ if (candidateView && candidateView != self)
+ return [candidateView draggingEntered:sender];
+ }
+ dragEnterSequence = [sender draggingSequenceNumber];
[self addDropData:sender];
QMimeData *mimeData = dropData;
if (QDragManager::self()->source())
mimeData = QDragManager::self()->dragPrivate()->data;
- NSPoint windowPoint = [sender draggingLocation];
NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
QPoint posDrag(localPoint.x, localPoint.y);
@@ -316,6 +323,9 @@ extern "C" {
[self removeDropData];
return NSDragOperationNone;
} else {
+ // save the mouse position, used by draggingExited handler.
+ DnDParams *dndParams = [QCocoaView currentMouseEvent];
+ dndParams->activeDragEnterPos = windowPoint;
// send a drag move event immediately after a drag enter event (as per documentation).
QDragMoveEvent qDMEvent(posDrag, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
qDMEvent.setDropAction(qDEEvent.dropAction());
@@ -336,11 +346,22 @@ extern "C" {
- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender
{
- // drag enter event was rejected, so ignore the move event.
+ NSPoint windowPoint = [sender draggingLocation];
+ if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
+ // pass the drag move event to the view underneath.
+ NSView *candidateView = [[[self window] contentView] hitTest:windowPoint];
+ if (candidateView && candidateView != self)
+ return [candidateView draggingUpdated:sender];
+ }
+ // in cases like QFocusFrame, the view under the mouse might
+ // not have received the drag enter. Generate a synthetic
+ // drag enter event for that view.
+ if (dragEnterSequence != [sender draggingSequenceNumber])
+ [self draggingEntered:sender];
+ // drag enter event was rejected, so ignore the move event.
if (dropData == 0)
return NSDragOperationNone;
// return last value, if we are still in the answerRect.
- NSPoint windowPoint = [sender draggingLocation];
NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
NSDragOperation nsActions = [sender draggingSourceOperationMask];
@@ -379,21 +400,34 @@ extern "C" {
- (void)draggingExited:(id < NSDraggingInfo >)sender
{
- Q_UNUSED(sender)
- // drag enter event was rejected, so ignore the move event.
+ dragEnterSequence = -1;
+ if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
+ // try sending the leave event to the last view which accepted drag enter.
+ DnDParams *dndParams = [QCocoaView currentMouseEvent];
+ NSView *candidateView = [[[self window] contentView] hitTest:dndParams->activeDragEnterPos];
+ if (candidateView && candidateView != self)
+ return [candidateView draggingExited:sender];
+ }
+ // drag enter event was rejected, so ignore the move event.
if (dropData) {
QDragLeaveEvent de;
QApplication::sendEvent(qwidget, &de);
[self removeDropData];
}
-
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
+ NSPoint windowPoint = [sender draggingLocation];
+ dragEnterSequence = -1;
+ if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
+ // pass the drop event to the view underneath.
+ NSView *candidateView = [[[self window] contentView] hitTest:windowPoint];
+ if (candidateView && candidateView != self)
+ return [candidateView performDragOperation:sender];
+ }
[self addDropData:sender];
- NSPoint windowPoint = [sender draggingLocation];
NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
QPoint posDrop(localPoint.x, localPoint.y);
@@ -688,7 +722,6 @@ extern "C" {
}
if (!lowerView) // Low as we can be at this point.
candidateView = viewForDescent;
-
// Try to go deeper, will also exit out of the loop, if we found the point.
viewForDescent = lowerView;
lowerView = nil;
diff --git a/src/gui/kernel/qcocoaview_mac_p.h b/src/gui/kernel/qcocoaview_mac_p.h
index b4a60b6528..7c227cc13a 100644
--- a/src/gui/kernel/qcocoaview_mac_p.h
+++ b/src/gui/kernel/qcocoaview_mac_p.h
@@ -68,6 +68,7 @@ struct DnDParams
NSEvent *theEvent;
NSPoint localPoint;
NSDragOperation performedAction;
+ NSPoint activeDragEnterPos;
};
QT_END_NAMESPACE
@@ -85,6 +86,7 @@ Q_GUI_EXPORT
int composingLength;
bool sendKeyEvents;
QStringList *currentCustomTypes;
+ NSInteger dragEnterSequence;
}
- (id)initWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate;
- (void) finishInitWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate;