7#include <QtGui/qdrag.h>
9@implementation QNSView (Dragging)
11-(
void)registerDragTypes
13 QMacAutoReleasePool pool;
15 NSString *
const mimeTypeGeneric = @
"com.trolltech.qt.MimeTypeName";
16 NSMutableArray<NSString *> *supportedTypes = [NSMutableArray<NSString *> arrayWithArray:@[
17 NSPasteboardTypeColor, NSPasteboardTypeString,
18 NSPasteboardTypeFileURL, @
"com.adobe.encapsulated-postscript", NSPasteboardTypeTIFF,
19 NSPasteboardTypeRTF, NSPasteboardTypeTabularText, NSPasteboardTypeFont,
20 NSPasteboardTypeRuler, NSFileContentsPboardType,
21 NSPasteboardTypeRTFD , NSPasteboardTypeHTML,
22 NSPasteboardTypeURL, NSPasteboardTypePDF, UTTypeVCard.identifier,
23 (NSString *)kPasteboardTypeFileURLPromise,
24 NSPasteboardTypeMultipleTextSelection, mimeTypeGeneric]];
27 for (
const QString &customType : QMacMimeRegistry::enabledDraggedTypes())
28 [supportedTypes addObject:customType.toNSString()];
30 [self registerForDraggedTypes:supportedTypes];
33static QWindow *findEventTargetWindow(QWindow *candidate)
36 if (!(candidate->flags() & Qt::WindowTransparentForInput))
38 candidate = candidate->parent();
43static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint point)
45 return target->mapFromGlobal(source->mapToGlobal(point));
48- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context
53 QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
54 return qt_mac_mapDropActions(nativeDrag->currentDrag()->supportedActions());
57- (BOOL)ignoreModifierKeysForDraggingSession:(NSDraggingSession *)session
71- (BOOL)wantsPeriodicDraggingUpdates
85- (BOOL)wantsPeriodicDraggingUpdates:(
void *)dummy
96- (
void)updateCursorFromDragResponse:(QPlatformDragQtResponse)response drag:(QCocoaDrag *)drag
98 const QPixmap pixmapCursor = drag->currentDrag()->dragCursor(response.acceptedAction());
99 NSCursor *nativeCursor = nil;
101 if (pixmapCursor.isNull()) {
102 switch (response.acceptedAction()) {
104 nativeCursor = [NSCursor dragCopyCursor];
107 nativeCursor = [NSCursor dragLinkCursor];
109 case Qt::IgnoreAction:
112
115 nativeCursor = [NSCursor arrowCursor];
119 auto *nsimage = [NSImage imageFromQImage:pixmapCursor.toImage()];
120 nativeCursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSZeroPoint];
129 if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave)
135 QCFType<CGEventRef> moveEvent = CGEventCreateMouseEvent(
136 nullptr, kCGEventMouseMoved, QCursor::pos().toCGPoint(),
139 CGEventPost(kCGHIDEventTap, moveEvent);
142- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
144 return [self handleDrag:(QEvent::DragEnter) sender:sender];
147- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender
149 QScopedValueRollback<
bool> rollback(m_updatingDrag,
true);
150 return [self handleDrag:(QEvent::DragMove) sender:sender];
154- (NSDragOperation)handleDrag:(QEvent::Type)dragType sender:(id<NSDraggingInfo>)sender
156 if (!m_platformWindow)
157 return NSDragOperationNone;
159 QPoint windowPoint = QPointF::fromCGPoint([self convertPoint:sender.draggingLocation fromView:nil]).toPoint();
161 Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(sender.draggingSourceOperationMask);
163 QWindow *target = findEventTargetWindow(m_platformWindow->window());
165 return NSDragOperationNone;
167 const auto modifiers = QAppleKeyMapper::fromCocoaModifiers(NSApp.currentEvent.modifierFlags);
168 const auto buttons = currentlyPressedMouseButtons();
169 const auto point = mapWindowCoordinates(m_platformWindow->window(), target, windowPoint);
171 if (dragType == QEvent::DragEnter)
172 qCDebug(lcQpaMouse) << dragType << self <<
"at" << windowPoint;
174 qCDebug(lcQpaMouse) << dragType <<
"at" << windowPoint <<
"with" << buttons;
176 QPlatformDragQtResponse response(
false, Qt::IgnoreAction, QRect());
177 QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
178 if (nativeDrag->currentDrag()) {
180 response = QWindowSystemInterface::handleDrag(target, nativeDrag->dragMimeData(),
181 point, qtAllowed, buttons, modifiers);
182 [self updateCursorFromDragResponse:response drag:nativeDrag];
184 QCocoaDropData mimeData(sender.draggingPasteboard);
185 response = QWindowSystemInterface::handleDrag(target, &mimeData,
186 point, qtAllowed, buttons, modifiers);
189 return qt_mac_mapDropAction(response.acceptedAction());
192- (
void)draggingExited:(id<NSDraggingInfo>)sender
194 if (!m_platformWindow)
197 QWindow *target = findEventTargetWindow(m_platformWindow->window());
201 auto *nativeDrag = QCocoaIntegration::instance()->drag();
202 Q_ASSERT(nativeDrag);
203 nativeDrag->exitDragLoop();
205 QPoint windowPoint = QPointF::fromCGPoint([self convertPoint:sender.draggingLocation fromView:nil]).toPoint();
207 qCDebug(lcQpaMouse) << QEvent::DragLeave << self <<
"at" << windowPoint;
210 QWindowSystemInterface::handleDrag(target,
nullptr,
211 mapWindowCoordinates(m_platformWindow->window(), target, windowPoint),
212 Qt::IgnoreAction, Qt::NoButton, Qt::NoModifier);
216- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender
218 if (!m_platformWindow)
221 QWindow *target = findEventTargetWindow(m_platformWindow->window());
225 QPoint windowPoint = QPointF::fromCGPoint([self convertPoint:sender.draggingLocation fromView:nil]).toPoint();
227 Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(sender.draggingSourceOperationMask);
229 QPlatformDropQtResponse response(
false, Qt::IgnoreAction);
230 QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
231 const auto modifiers = QAppleKeyMapper::fromCocoaModifiers(NSApp.currentEvent.modifierFlags);
232 const auto buttons = currentlyPressedMouseButtons();
233 const auto point = mapWindowCoordinates(m_platformWindow->window(), target, windowPoint);
235 qCDebug(lcQpaMouse) << QEvent::Drop <<
"at" << windowPoint <<
"with" << buttons;
237 if (nativeDrag->currentDrag()) {
239 response = QWindowSystemInterface::handleDrop(target, nativeDrag->dragMimeData(),
240 point, qtAllowed, buttons, modifiers);
241 nativeDrag->setAcceptedAction(response.acceptedAction());
243 QCocoaDropData mimeData(sender.draggingPasteboard);
244 response = QWindowSystemInterface::handleDrop(target, &mimeData,
245 point, qtAllowed, buttons, modifiers);
247 return response.isAccepted();
250- (
void)draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation
253 Q_UNUSED(screenPoint);
256 if (!m_platformWindow)
259 QWindow *target = findEventTargetWindow(m_platformWindow->window());
263 QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
264 Q_ASSERT(nativeDrag);
265 nativeDrag->exitDragLoop();
267 if (!nativeDrag->currentDrag())
268 nativeDrag->setAcceptedAction(qt_mac_mapNSDragOperation(operation));
273 m_buttons = currentlyPressedMouseButtons();
274 const auto modifiers = QAppleKeyMapper::fromCocoaModifiers(NSApp.currentEvent.modifierFlags);
276 NSPoint windowPoint = [self.window convertRectFromScreen:NSMakeRect(screenPoint.x, screenPoint.y, 1, 1)].origin;
277 NSPoint nsViewPoint = [self convertPoint: windowPoint fromView: nil];
279 QPoint qtWindowPoint(nsViewPoint.x, nsViewPoint.y);
280 QPoint qtScreenPoint = QCocoaScreen::mapFromNative(screenPoint).toPoint();
282 QWindowSystemInterface::handleMouseEvent(
284 mapWindowCoordinates(m_platformWindow->window(), target, qtWindowPoint),
288 QEvent::MouseButtonRelease,
291 qCDebug(lcQpaMouse) <<
"Drag session" << session <<
"ended, with" << m_buttons;