summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/platforms/cocoa/qcocoadrag.h6
-rw-r--r--src/plugins/platforms/cocoa/qcocoadrag.mm90
-rw-r--r--src/plugins/platforms/cocoa/qnsview_dragging.mm9
3 files changed, 104 insertions, 1 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoadrag.h b/src/plugins/platforms/cocoa/qcocoadrag.h
index 5a5b985c6e..975741c270 100644
--- a/src/plugins/platforms/cocoa/qcocoadrag.h
+++ b/src/plugins/platforms/cocoa/qcocoadrag.h
@@ -48,6 +48,8 @@
#include <QtGui/private/qdnd_p.h>
#include <QtGui/private/qinternalmimedata_p.h>
+#include <QtCore/qeventloop.h>
+
QT_BEGIN_NAMESPACE
class QCocoaDrag : public QPlatformDrag
@@ -69,11 +71,15 @@ public:
void setLastMouseEvent(NSEvent *event, NSView *view);
void setAcceptedAction(Qt::DropAction act);
+ void exitDragLoop();
private:
QDrag *m_drag;
NSEvent *m_lastEvent;
NSView *m_lastView;
Qt::DropAction m_executed_drop_action;
+ QEventLoop internalDragLoop;
+
+ bool maybeDragMultipleItems();
QPixmap dragPixmap(QDrag *drag, QPoint &hotSpot) const;
};
diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm
index 3525fddfd1..cf48c50caf 100644
--- a/src/plugins/platforms/cocoa/qcocoadrag.mm
+++ b/src/plugins/platforms/cocoa/qcocoadrag.mm
@@ -41,6 +41,9 @@
#include "qmacclipboard.h"
#include "qcocoahelpers.h"
#include <QtGui/private/qcoregraphics_p.h>
+#include <QtCore/qsysinfo.h>
+
+#include <vector>
QT_BEGIN_NAMESPACE
@@ -125,6 +128,9 @@ Qt::DropAction QCocoaDrag::drag(QDrag *o)
m_drag = o;
m_executed_drop_action = Qt::IgnoreAction;
+ if (maybeDragMultipleItems())
+ return m_executed_drop_action;
+
QPoint hotSpot = m_drag->hotSpot();
QPixmap pm = dragPixmap(m_drag, hotSpot);
NSImage *dragImage = [NSImage imageFromQImage:pm.toImage()];
@@ -155,11 +161,95 @@ Qt::DropAction QCocoaDrag::drag(QDrag *o)
return m_executed_drop_action;
}
+bool QCocoaDrag::maybeDragMultipleItems()
+{
+ Q_ASSERT(m_drag && m_drag->mimeData());
+ Q_ASSERT(m_executed_drop_action == Qt::IgnoreAction);
+
+ if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSMojave) {
+ // -dragImage: stopped working in 10.14 first.
+ return false;
+ }
+
+ const QMacAutoReleasePool pool;
+
+ NSWindow *theWindow = [m_lastEvent window];
+ Q_ASSERT(theWindow);
+
+ if (![theWindow.contentView respondsToSelector:@selector(draggingSession:sourceOperationMaskForDraggingContext:)])
+ return false;
+
+ auto *sourceView = static_cast<NSView<NSDraggingSource>*>(theWindow.contentView);
+
+ const auto &qtUrls = m_drag->mimeData()->urls();
+ NSPasteboard *dragBoard = [NSPasteboard pasteboardWithName:NSPasteboardNameDrag];
+
+ if (int(dragBoard.pasteboardItems.count) == 1 && qtUrls.size() <= 1) {
+ // Good old -dragImage: works perfectly for this ...
+ return false;
+ }
+
+ std::vector<NSPasteboardItem *> nonUrls;
+ for (NSPasteboardItem *item in dragBoard.pasteboardItems) {
+ bool isUrl = false;
+ for (NSPasteboardType type in item.types) {
+ using NSStringRef = NSString *;
+ if ([type isEqualToString:NSStringRef(kUTTypeFileURL)]) {
+ isUrl = true;
+ break;
+ }
+ }
+
+ if (!isUrl)
+ nonUrls.push_back(item);
+ }
+
+ QPoint hotSpot = m_drag->hotSpot();
+ const auto pixmap = dragPixmap(m_drag, hotSpot);
+ NSImage *dragImage = [NSImage imageFromQImage:pixmap.toImage()];
+ Q_ASSERT(dragImage);
+
+ NSMutableArray<NSDraggingItem *> *dragItems = [[[NSMutableArray alloc] init] autorelease];
+ const NSPoint itemLocation = m_drag->hotSpot().toCGPoint();
+ // 0. We start from URLs, which can be actually in a list (thus technically
+ // only ONE item in the pasteboard. The fact it's only one does not help, we are
+ // still getting an exception because of the number of items/images mismatch ...
+ for (const auto &qtUrl : qtUrls) {
+ NSURL *nsUrl = qtUrl.toNSURL();
+ auto *newItem = [[[NSDraggingItem alloc] initWithPasteboardWriter:nsUrl] autorelease];
+ const NSRect itemFrame = NSMakeRect(itemLocation.x, itemLocation.y,
+ dragImage.size.width,
+ dragImage.size.height);
+ [newItem setDraggingFrame:itemFrame contents:dragImage];
+ [dragItems addObject:newItem];
+ }
+ // 1. Repeat for non-url items, if any:
+ for (auto *pbItem : nonUrls) {
+ auto *newItem = [[[NSDraggingItem alloc] initWithPasteboardWriter:pbItem] autorelease];
+ const NSRect itemFrame = NSMakeRect(itemLocation.x, itemLocation.y,
+ dragImage.size.width,
+ dragImage.size.height);
+ [newItem setDraggingFrame:itemFrame contents:dragImage];
+ [dragItems addObject:newItem];
+ }
+
+ [sourceView beginDraggingSessionWithItems:dragItems event:m_lastEvent source:sourceView];
+ internalDragLoop.exec();
+ return true;
+}
+
void QCocoaDrag::setAcceptedAction(Qt::DropAction act)
{
m_executed_drop_action = act;
}
+void QCocoaDrag::exitDragLoop()
+{
+ if (internalDragLoop.isRunning())
+ internalDragLoop.exit();
+}
+
+
QPixmap QCocoaDrag::dragPixmap(QDrag *drag, QPoint &hotSpot) const
{
const QMimeData* data = drag->mimeData();
diff --git a/src/plugins/platforms/cocoa/qnsview_dragging.mm b/src/plugins/platforms/cocoa/qnsview_dragging.mm
index 2e88b6a08f..44ffc87f7a 100644
--- a/src/plugins/platforms/cocoa/qnsview_dragging.mm
+++ b/src/plugins/platforms/cocoa/qnsview_dragging.mm
@@ -231,6 +231,10 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
if (!target)
return;
+ auto *nativeDrag = QCocoaIntegration::instance()->drag();
+ Q_ASSERT(nativeDrag);
+ nativeDrag->exitDragLoop();
+
QPoint windowPoint = QPointF::fromCGPoint([self convertPoint:sender.draggingLocation fromView:nil]).toPoint();
qCDebug(lcQpaMouse) << QEvent::DragLeave << self << "at" << windowPoint;
@@ -289,7 +293,10 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
if (!target)
return;
- QCocoaIntegration::instance()->drag();
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
+ Q_ASSERT(nativeDrag);
+ nativeDrag->exitDragLoop();
+ nativeDrag->setAcceptedAction(qt_mac_mapNSDragOperation(operation));
// Qt starts drag-and-drop on a mouse button press event. Cococa in
// this case won't send the matching release event, so we have to