summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/cocoa
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/cocoa')
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm66
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm34
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemtrayicon.h2
-rw-r--r--src/plugins/platforms/cocoa/qnsview_mouse.mm3
4 files changed, 95 insertions, 10 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index 7644867700a..7ca3e61dfa5 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -25,6 +25,8 @@
#include <qpa/qwindowsysteminterface.h>
#include <qwindowdefs.h>
+#include <QtCore/private/qdarwinsecurityscopedfileengine_p.h>
+
QT_USE_NAMESPACE
@implementation QCocoaApplicationDelegate {
@@ -194,6 +196,23 @@ QT_USE_NAMESPACE
QCocoaMenuBar::insertWindowMenu();
}
+/*!
+ Tells the delegate to open the specified files
+
+ Sent by the system when the user drags a file to the app's icon
+ in places like Finder or the Dock, or opens a file via the "Open
+ With" menu in Finder.
+
+ These actions can happen when the application is not running,
+ in which case the call comes in between willFinishLaunching
+ and didFinishLaunching. In this case we don't pass on the
+ incoming file paths as file open events, as the paths are
+ also part of the command line arguments, and Qt applications
+ normally expect to handle file opening via those.
+
+ \note The app must register itself as a handler for each file
+ type via the CFBundleDocumentTypes key in the Info.plist.
+ */
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
{
Q_UNUSED(filenames);
@@ -209,7 +228,10 @@ QT_USE_NAMESPACE
if (qApp->arguments().contains(qtFileName))
continue;
}
- QWindowSystemInterface::handleFileOpenEvent(qtFileName);
+ QUrl url = qt_apple_urlFromPossiblySecurityScopedURL([NSURL fileURLWithPath:fileName]);
+ QWindowSystemInterface::handleFileOpenEvent(url);
+ // FIXME: We're supposed to call [NSApp replyToOpenOrPrint:] here, but we
+ // don't know if the open operation succeeded, failed, or was cancelled.
}
if ([reflectionDelegate respondsToSelector:_cmd])
@@ -262,6 +284,17 @@ QT_USE_NAMESPACE
}
}
+/*!
+ Returns a Boolean value that indicates if the app responds
+ to reopen AppleEvents.
+
+ These events are sent whenever the Finder reactivates an already
+ running application because someone double-clicked it again or used
+ the dock to activate it.
+
+ We pass the activation on to Qt, and return YES, to let AppKit
+ follow its normal flow.
+ */
- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag
{
if ([reflectionDelegate respondsToSelector:_cmd])
@@ -309,6 +342,25 @@ QT_USE_NAMESPACE
[self doesNotRecognizeSelector:invocationSelector];
}
+/*!
+ Callback for when the application is asked to pick up a user activity
+ from another app (also known as Handoff, which is part of the bigger
+ Continuity story for Apple operating systems).
+
+ This is normally managed by two apps by the same vendor explicitly
+ initiating a custom NSUserActivity and picking it up in another app
+ on the same or another device, which we don't have APIs for.
+
+ This is also how the system supports Universal Links, where a web page
+ can deep-link into an app. In this case the app needs to claim and
+ validate an associated domain. The resulting link will be delivered
+ as a special NSUserActivityTypeBrowsingWeb activity type, which we
+ treat as QDesktopServices::handleUrl().
+
+ Finally, for NS/UIDocument based apps (which Qt is not), the system
+ automatically handles document hand-off if the application includes
+ the NSUbiquitousDocumentUserActivityType key in its Info.plist.
+ */
- (BOOL)application:(NSApplication *)application continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void(^)(NSArray<id<NSUserActivityRestoring>> *restorableObjects))restorationHandler
{
@@ -331,6 +383,18 @@ QT_USE_NAMESPACE
return NO;
}
+/*!
+ Callback for when the app is asked to open custom URL schemes.
+
+ We register a handler for events of type kInternetEventClass with the
+ NSAppleEventManager during application start.
+
+ The application must include the schemes in the CFBundleURLTypes
+ key of the Info.plist.
+
+ \note This callback is not used for http/https URLs, see
+ continueUserActivity above for how we handle that.
+ */
- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
Q_UNUSED(replyEvent);
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index 4c4e5fac962..a79682e4e14 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -19,6 +19,7 @@
#include <QtCore/qregularexpression.h>
#include <QtCore/qpointer.h>
#include <QtCore/private/qcore_mac_p.h>
+#include <QtCore/private/qdarwinsecurityscopedfileengine_p.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/private/qguiapplication_p.h>
@@ -395,14 +396,15 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
{
if (auto *openPanel = openpanel_cast(m_panel)) {
QList<QUrl> result;
- for (NSURL *url in openPanel.URLs) {
- QString path = QString::fromNSString(url.path).normalized(QString::NormalizationForm_C);
- result << QUrl::fromLocalFile(path);
- }
+ for (NSURL *url in openPanel.URLs)
+ result << qt_apple_urlFromPossiblySecurityScopedURL(url);
return result;
} else {
- QString filename = QString::fromNSString(m_panel.URL.path).normalized(QString::NormalizationForm_C);
- QFileInfo fileInfo(filename);
+ QUrl result = qt_apple_urlFromPossiblySecurityScopedURL(m_panel.URL);
+ if (qt_apple_isSandboxed())
+ return { result }; // Can't tweak suffix
+
+ QFileInfo fileInfo(result.toLocalFile());
if (fileInfo.suffix().isEmpty() && ![self fileInfoMatchesCurrentNameFilter:fileInfo]) {
// We end up in this situation if we accept a file name without extension
@@ -733,6 +735,26 @@ bool QCocoaFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit
return false;
}
+ if (qt_apple_isSandboxed()) {
+ static bool canRead = qt_mac_processHasEntitlement(
+ u"com.apple.security.files.user-selected.read-only"_s);
+ static bool canReadWrite = qt_mac_processHasEntitlement(
+ u"com.apple.security.files.user-selected.read-write"_s);
+
+ if (options()->acceptMode() == QFileDialogOptions::AcceptSave
+ && !canReadWrite) {
+ qWarning() << "Sandboxed application is missing user-selected files"
+ << "read-write entitlement. Falling back to non-native dialog";
+ return false;
+ }
+
+ if (!canReadWrite && !canRead) {
+ qWarning() << "Sandboxed application is missing user-selected files"
+ << "entitlement. Falling back to non-native dialog";
+ return false;
+ }
+ }
+
createNSOpenSavePanelDelegate();
return [m_delegate showPanel:windowModality withParent:parent];
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
index 9a491d4d058..35fb7f24dd5 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
@@ -29,7 +29,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(NSStatusItem);
QT_BEGIN_NAMESPACE
-class Q_GUI_EXPORT QCocoaSystemTrayIcon : public QPlatformSystemTrayIcon
+class QCocoaSystemTrayIcon : public QPlatformSystemTrayIcon
{
public:
QCocoaSystemTrayIcon() {}
diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm
index 56ff5ec313e..ca7e9c808f7 100644
--- a/src/plugins/platforms/cocoa/qnsview_mouse.mm
+++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm
@@ -290,8 +290,7 @@ static const QPointingDevice *pointingDeviceFor(qint64 deviceID)
if (qIsNaN(windowPoint.x) || qIsNaN(windowPoint.y)) {
screenPoint = [NSEvent mouseLocation];
} else {
- NSRect screenRect = [[theEvent window] convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 1, 1)];
- screenPoint = screenRect.origin;
+ screenPoint = [theEvent.window convertPointToScreen:windowPoint];
}
} else {
screenPoint = [NSEvent mouseLocation];