diff --git a/overlay/osx/qt5-base/patches/QCocoaDrag-avoid-using-the-deprecated-API-if-possibl.patch b/overlay/osx/qt5-base/patches/QCocoaDrag-avoid-using-the-deprecated-API-if-possibl.patch new file mode 100644 index 00000000000000..5bb1fa2a3ee1eb --- /dev/null +++ b/overlay/osx/qt5-base/patches/QCocoaDrag-avoid-using-the-deprecated-API-if-possibl.patch @@ -0,0 +1,278 @@ +From c220a61c0324ef32e85523494d09edc6be54ceff Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= +Date: Mon, 3 Jan 2022 10:23:23 +0100 +Subject: [PATCH] QCocoaDrag - avoid using the deprecated API if possible +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The -dragImage stopped to work in 10.14 first with change in behavior +documented and the new API (AppKit) proposed/advised. Then after +some update the old behavior was restored and D&D for multiple +URLs was working again without us having to change anything. +In 10.15 it's not working anymore and we have to properly fix +it and switch to the API advised. The new API is non-blocking, +but QCocoaDrag::drag is expected to be blocking so we have to +add a nested event loop to emulate the old behavior. Dragging +image is a bit problematic (the exception is thrown because +number of images (1) and number of items in NSPasteboard +are not equal): creating separate images for different +drag items looks really messy. So ... we use the same image +again and again with the same frame. + +Fixes: QTBUG-71939 +Change-Id: I02c2a10eab280cf4a55513adaf29c22fff934c01 +Reviewed-by: Tor Arne Vestbø +(cherry picked from commit 8481a9f) +Reviewed-by: Timur Pocheptsov +--- + src/plugins/platforms/cocoa/qcocoadrag.h | 6 + + src/plugins/platforms/cocoa/qcocoadrag.mm | 105 ++++++++++++++++-- + .../platforms/cocoa/qnsview_dragging.mm | 14 ++- + 3 files changed, 112 insertions(+), 13 deletions(-) + +diff --git a/src/plugins/platforms/cocoa/qcocoadrag.h b/src/plugins/platforms/cocoa/qcocoadrag.h +index 5a5b985c..975741c2 100644 +--- a/src/plugins/platforms/cocoa/qcocoadrag.h ++++ b/src/plugins/platforms/cocoa/qcocoadrag.h +@@ -48,6 +48,8 @@ + #include + #include + ++#include ++ + 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 09433194..ab6863a4 100644 +--- a/src/plugins/platforms/cocoa/qcocoadrag.mm ++++ b/src/plugins/platforms/cocoa/qcocoadrag.mm +@@ -44,6 +44,9 @@ + #include + #endif + #include ++#include ++ ++#include + + QT_BEGIN_NAMESPACE + +@@ -128,13 +131,15 @@ 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); +- QSize pmDeviceIndependentSize = pm.size() / pm.devicePixelRatio(); +- NSImage *nsimage = qt_mac_create_nsimage(pm); +- [nsimage setSize:NSSizeFromCGSize(pmDeviceIndependentSize.toCGSize())]; ++ NSImage *dragImage = [NSImage imageFromQImage:pm.toImage()]; ++ Q_ASSERT(dragImage); + +- QMacPasteboard dragBoard((CFStringRef) NSDragPboard, QMacInternalPasteboardMime::MIME_DND); ++ QMacPasteboard dragBoard(CFStringRef(NSDragPboard), QMacInternalPasteboardMime::MIME_DND); + m_drag->mimeData()->setData(QLatin1String("application/x-qt-mime-type-name"), QByteArray("dummy")); + dragBoard.setMimeData(m_drag->mimeData(), QMacPasteboard::LazyRequest); + +@@ -142,12 +147,12 @@ Qt::DropAction QCocoaDrag::drag(QDrag *o) + NSWindow *theWindow = [m_lastEvent window]; + Q_ASSERT(theWindow); + event_location.x -= hotSpot.x(); +- CGFloat flippedY = pmDeviceIndependentSize.height() - hotSpot.y(); ++ CGFloat flippedY = dragImage.size.height - hotSpot.y(); + event_location.y -= flippedY; + NSSize mouseOffset_unused = NSMakeSize(0.0, 0.0); +- NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard]; ++ NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard]; + +- [theWindow dragImage:nsimage ++ [theWindow dragImage:dragImage + at:event_location + offset:mouseOffset_unused + event:m_lastEvent +@@ -155,17 +160,99 @@ Qt::DropAction QCocoaDrag::drag(QDrag *o) + source:m_lastView + slideBack:YES]; + +- [nsimage release]; +- + m_drag = nullptr; + 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*>(theWindow.contentView); ++ ++ const auto &qtUrls = m_drag->mimeData()->urls(); ++ NSPasteboard *dragBoard = [NSPasteboard pasteboardWithName:NSDragPboard]; ++ ++ if (int(dragBoard.pasteboardItems.count) == 1 && qtUrls.size() <= 1) { ++ // Good old -dragImage: works perfectly for this ... ++ return false; ++ } ++ ++ std::vector 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 *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 37e972db..978d73f7 100644 +--- a/src/plugins/platforms/cocoa/qnsview_dragging.mm ++++ b/src/plugins/platforms/cocoa/qnsview_dragging.mm +@@ -39,7 +39,7 @@ + + // This file is included from qnsview.mm, and only used to organize the code + +-@implementation QT_MANGLE_NAMESPACE(QNSView) (Dragging) ++@implementation QNSView (Dragging) + + -(void)registerDragTypes + { +@@ -150,10 +150,8 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin + break; + } + } else { +- NSImage *nsimage = qt_mac_create_nsimage(pixmapCursor); +- nsimage.size = NSSizeFromCGSize((pixmapCursor.size() / pixmapCursor.devicePixelRatioF()).toCGSize()); ++ auto *nsimage = [NSImage imageFromQImage:pixmapCursor.toImage()]; + nativeCursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSZeroPoint]; +- [nsimage release]; + } + + // Change the cursor +@@ -234,6 +232,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; +@@ -270,6 +272,7 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin + // The drag was started from within the application + response = QWindowSystemInterface::handleDrop(target, nativeDrag->dragMimeData(), + point, qtAllowed, buttons, modifiers); ++ nativeDrag->setAcceptedAction(response.acceptedAction()); + } else { + QCocoaDropData mimeData(sender.draggingPasteboard); + response = QWindowSystemInterface::handleDrop(target, &mimeData, +@@ -282,6 +285,7 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin + { + Q_UNUSED(session); + Q_UNUSED(screenPoint); ++ Q_UNUSED(operation); + + if (!m_platformWindow) + return; +@@ -291,6 +295,8 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin + return; + + 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 +-- +2.25.1 + diff --git a/overlay/osx/qt5-base/patches/nsimage_qimage.patch b/overlay/osx/qt5-base/patches/nsimage_qimage.patch new file mode 100644 index 00000000000000..865f4a8520d923 --- /dev/null +++ b/overlay/osx/qt5-base/patches/nsimage_qimage.patch @@ -0,0 +1,177 @@ +From c1bf37971f3aef7b1da1027665ea7c06fc343718 Mon Sep 17 00:00:00 2001 +From: fwcd +Date: Mon, 10 Jan 2022 19:55:42 +0100 +Subject: [PATCH] macOS: Streamline QImage to NSImage conversion +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Co-authored-by: Tor Arne Vestbø +--- + src/gui/painting/qcoregraphics.mm | 41 ++++++++++++------- + src/gui/painting/qcoregraphics_p.h | 8 +++- + src/plugins/platforms/cocoa/qcocoacursor.mm | 13 ++---- + .../platforms/cocoa/qcocoaintegration.mm | 3 +- + .../platforms/cocoa/qcocoasystemtrayicon.mm | 3 +- + src/plugins/platforms/cocoa/qcocoawindow.mm | 3 +- + 6 files changed, 40 insertions(+), 31 deletions(-) + +diff --git a/src/gui/painting/qcoregraphics.mm b/src/gui/painting/qcoregraphics.mm +index e2497eaadb..b5620535fb 100644 +--- a/src/gui/painting/qcoregraphics.mm ++++ b/src/gui/painting/qcoregraphics.mm +@@ -47,6 +47,8 @@ + #include + #include + ++QT_USE_NAMESPACE ++ + QT_BEGIN_NAMESPACE + + // ---------------------- Images ---------------------- +@@ -124,23 +126,34 @@ QImage qt_mac_toQImage(CGImageRef image) + + #ifdef Q_OS_MACOS + +-static NSImage *qt_mac_cgimage_to_nsimage(CGImageRef image) +-{ +- NSImage *newImage = [[NSImage alloc] initWithCGImage:image size:NSZeroSize]; +- return newImage; +-} ++QT_END_NAMESPACE + +-NSImage *qt_mac_create_nsimage(const QPixmap &pm) ++@implementation NSImage (QtExtras) +++ (instancetype)imageFromQImage:(const QImage &)image + { +- if (pm.isNull()) +- return 0; +- QImage image = pm.toImage(); +- CGImageRef cgImage = qt_mac_toCGImage(image); +- NSImage *nsImage = qt_mac_cgimage_to_nsimage(cgImage); +- nsImage.size = (pm.size() / pm.devicePixelRatioF()).toCGSize(); +- CGImageRelease(cgImage); +- return nsImage; ++ if (image.isNull()) ++ return nil; ++ ++ QCFType cgImage = image.toCGImage(); ++ if (!cgImage) ++ return nil; ++ ++ // We set up the NSImage using an explicit NSBitmapImageRep, instead of ++ // [NSImage initWithCGImage:size:], as the former allows us to correctly ++ // set the size of the representation to account for the device pixel ++ // ratio of the original image, which in turn will be reflected by the ++ // NSImage. ++ auto nsImage = [[NSImage alloc] initWithSize:NSZeroSize]; ++ auto *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; ++ imageRep.size = (image.size() / image.devicePixelRatioF()).toCGSize(); ++ [nsImage addRepresentation:[imageRep autorelease]]; ++ Q_ASSERT(CGSizeEqualToSize(nsImage.size, imageRep.size)); ++ ++ return [nsImage autorelease]; + } ++@end ++ ++QT_BEGIN_NAMESPACE + + NSImage *qt_mac_create_nsimage(const QIcon &icon, int defaultSize) + { +diff --git a/src/gui/painting/qcoregraphics_p.h b/src/gui/painting/qcoregraphics_p.h +index ba2cde8325..e1697b0f38 100644 +--- a/src/gui/painting/qcoregraphics_p.h ++++ b/src/gui/painting/qcoregraphics_p.h +@@ -69,9 +69,15 @@ QT_BEGIN_NAMESPACE + Q_GUI_EXPORT CGBitmapInfo qt_mac_bitmapInfoForImage(const QImage &image); + + #ifdef HAVE_APPKIT +-Q_GUI_EXPORT NSImage *qt_mac_create_nsimage(const QPixmap &pm); + Q_GUI_EXPORT NSImage *qt_mac_create_nsimage(const QIcon &icon, int defaultSize = 0); + Q_GUI_EXPORT QPixmap qt_mac_toQPixmap(const NSImage *image, const QSizeF &size); ++ ++QT_END_NAMESPACE ++@interface NSImage (QtExtras) +++ (instancetype)imageFromQImage:(const QT_PREPEND_NAMESPACE(QImage) &)image; ++@end ++QT_BEGIN_NAMESPACE ++ + #endif + Q_GUI_EXPORT CGImageRef qt_mac_toCGImage(const QImage &qImage); + Q_GUI_EXPORT CGImageRef qt_mac_toCGImageMask(const QImage &qImage); +diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm +index e0d623fc4c..658a7670f0 100644 +--- a/src/plugins/platforms/cocoa/qcocoacursor.mm ++++ b/src/plugins/platforms/cocoa/qcocoacursor.mm +@@ -340,19 +340,12 @@ NSCursor *QCocoaCursor::createCursorFromPixmap(const QPixmap pixmap, const QPoin + QSize layoutSize = pixmap.size() / pixmap.devicePixelRatio(); + QPixmap scaledPixmap = pixmap.scaled(layoutSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + scaledPixmap.setDevicePixelRatio(1.0); +- nsimage = static_cast(qt_mac_create_nsimage(scaledPixmap)); +- CGImageRef cgImage = qt_mac_toCGImage(pixmap.toImage()); +- NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; +- [nsimage addRepresentation:imageRep]; +- [imageRep release]; +- CGImageRelease(cgImage); ++ nsimage = [NSImage imageFromQImage:scaledPixmap.toImage()]; + } else { +- nsimage = static_cast(qt_mac_create_nsimage(pixmap)); ++ nsimage = [NSImage imageFromQImage:pixmap.toImage()]; + } + +- NSCursor *nsCursor = [[NSCursor alloc] initWithImage:nsimage hotSpot: hotSpot]; +- [nsimage release]; +- return nsCursor; ++ return [[NSCursor alloc] initWithImage:nsimage hotSpot:hotSpot]; + } + + QT_END_NAMESPACE +diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm +index 61308d6bf9..1e578e5052 100644 +--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm ++++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm +@@ -476,10 +476,9 @@ void QCocoaIntegration::setApplicationIcon(const QIcon &icon) const + if (!icon.isNull()) { + NSSize size = [[[NSApplication sharedApplication] dockTile] size]; + QPixmap pixmap = icon.pixmap(size.width, size.height); +- image = static_cast(qt_mac_create_nsimage(pixmap)); ++ image = [NSImage imageFromQImage:pixmap.toImage()]; + } + [[NSApplication sharedApplication] setApplicationIconImage:image]; +- [image release]; + } + + void QCocoaIntegration::beep() const +diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +index 559188aa5f..d8caf92a5c 100644 +--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm ++++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +@@ -228,10 +228,9 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon) + p.drawPixmap(r, pixmap); + } + +- NSImage *nsimage = static_cast(qt_mac_create_nsimage(fullHeightPixmap)); ++ auto *nsimage = [NSImage imageFromQImage:fullHeightPixmap.toImage()]; + [nsimage setTemplate:icon.isMask()]; + [(NSImageView*)[[m_sys->item item] view] setImage: nsimage]; +- [nsimage release]; + } + + void QCocoaSystemTrayIcon::updateMenu(QPlatformMenu *menu) +diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm +index 2fbaec2c56..6ba0cee310 100644 +--- a/src/plugins/platforms/cocoa/qcocoawindow.mm ++++ b/src/plugins/platforms/cocoa/qcocoawindow.mm +@@ -899,8 +899,7 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon) + [iconButton setImage:[workspace iconForFile:m_view.window.representedFilename]]; + } else { + QPixmap pixmap = icon.pixmap(QSize(22, 22)); +- NSImage *image = static_cast(qt_mac_create_nsimage(pixmap)); +- [iconButton setImage:[image autorelease]]; ++ iconButton.image = [NSImage imageFromQImage:pixmap.toImage()]; + } + } + +-- +2.34.0 + diff --git a/overlay/osx/qt5-base/portfile.cmake b/overlay/osx/qt5-base/portfile.cmake index 032abe1d7314b6..dd7b07534b86cc 100644 --- a/overlay/osx/qt5-base/portfile.cmake +++ b/overlay/osx/qt5-base/portfile.cmake @@ -31,6 +31,8 @@ qt_download_submodule( OUT_SOURCE_PATH SOURCE_PATH #patches/static_opengl.patch #Use this patch if you really want to statically link angle on windows (e.g. using -opengl es2 and -static). #Be carefull since it requires definining _GDI32_ for all dependent projects due to redefinition errors in the #the windows supplied gl.h header and the angle gl.h otherwise. + patches/nsimage_qimage.patch # add [NSImage imageFromQImage:] (required for the QCocoaDrag patch) + patches/QCocoaDrag-avoid-using-the-deprecated-API-if-possibl.patch # allow Apple SDK >= 10.14 ) # Remove vendored dependencies to ensure they are not picked up by the build diff --git a/overlay/osx/qt5-base/vcpkg.json b/overlay/osx/qt5-base/vcpkg.json index cb3d9f8ccdb434..e0e07ffd12e739 100644 --- a/overlay/osx/qt5-base/vcpkg.json +++ b/overlay/osx/qt5-base/vcpkg.json @@ -1,7 +1,7 @@ { "name": "qt5-base", "version-semver": "5.12.4", - "port-version": 12, + "port-version": 13, "description": "Qt5 Application Framework Base Module. Includes Core, GUI, Widgets, Networking, SQL, Concurrent and other essential qt components.", "homepage": "https://www.qt.io/", "dependencies": [