summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm66
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm14
-rw-r--r--src/plugins/platforms/ios/qiosapplicationdelegate.mm4
-rw-r--r--src/plugins/platforms/ios/qiosdocumentpickercontroller.mm62
-rw-r--r--src/plugins/platforms/ios/qiosfiledialog.mm10
-rw-r--r--src/plugins/platforms/wayland/qwaylandinputcontext.cpp10
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp4
9 files changed, 125 insertions, 49 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 52540666718..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
diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.mm b/src/plugins/platforms/ios/qiosapplicationdelegate.mm
index 380c5a588e6..7cbb4fc40f5 100644
--- a/src/plugins/platforms/ios/qiosapplicationdelegate.mm
+++ b/src/plugins/platforms/ios/qiosapplicationdelegate.mm
@@ -16,6 +16,8 @@
#include <QtCore/QtCore>
+#include <QtCore/private/qdarwinsecurityscopedfileengine_p.h>
+
@interface QIOSWindowSceneDelegate : NSObject<UIWindowSceneDelegate>
@property (nullable, nonatomic, strong) UIWindow *window;
@end
@@ -112,7 +114,7 @@
QIOSServices *iosServices = static_cast<QIOSServices *>(iosIntegration->services());
for (UIOpenURLContext *urlContext in URLContexts) {
- QUrl url = QUrl::fromNSURL(urlContext.URL);
+ QUrl url = qt_apple_urlFromPossiblySecurityScopedURL(urlContext.URL);
if (url.isLocalFile())
QWindowSystemInterface::handleFileOpenEvent(url);
else
diff --git a/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm b/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm
index c173aa426fc..57a5e100c9e 100644
--- a/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm
+++ b/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm
@@ -8,6 +8,7 @@
#include "qiosdocumentpickercontroller.h"
#include <QtCore/qpointer.h>
+#include <QtCore/private/qdarwinsecurityscopedfileengine_p.h>
@implementation QIOSDocumentPickerController {
QPointer<QIOSFileDialog> m_fileDialog;
@@ -17,9 +18,11 @@
{
NSMutableArray <UTType *> *docTypes = [[[NSMutableArray alloc] init] autorelease];
- QStringList nameFilters = fileDialog->options()->nameFilters();
- if (!nameFilters.isEmpty() && (fileDialog->options()->fileMode() != QFileDialogOptions::Directory
- || fileDialog->options()->fileMode() != QFileDialogOptions::DirectoryOnly))
+ const auto options = fileDialog->options();
+
+ const QStringList nameFilters = options->nameFilters();
+ if (!nameFilters.isEmpty() && (options->fileMode() != QFileDialogOptions::Directory
+ || options->fileMode() != QFileDialogOptions::DirectoryOnly))
{
QStringList results;
for (const QString &filter : nameFilters)
@@ -28,21 +31,8 @@
docTypes = [self computeAllowedFileTypes:results];
}
- // FIXME: Handle security scoped URLs instead of copying resource
- bool asCopy = [&]{
- switch (fileDialog->options()->fileMode()) {
- case QFileDialogOptions::AnyFile:
- case QFileDialogOptions::ExistingFile:
- case QFileDialogOptions::ExistingFiles:
- return true;
- default:
- // Folders can't be imported
- return false;
- }
- }();
-
if (!docTypes.count) {
- switch (fileDialog->options()->fileMode()) {
+ switch (options->fileMode()) {
case QFileDialogOptions::AnyFile:
case QFileDialogOptions::ExistingFile:
case QFileDialogOptions::ExistingFiles:
@@ -58,17 +48,39 @@
}
}
- if (self = [super initForOpeningContentTypes:docTypes asCopy:asCopy]) {
- m_fileDialog = fileDialog;
- self.modalPresentationStyle = UIModalPresentationFormSheet;
- self.delegate = self;
- self.presentationController.delegate = self;
+ if (options->acceptMode() == QFileDialogOptions::AcceptSave) {
+ auto selectedUrls = options->initiallySelectedFiles();
+ auto suggestedFileName = !selectedUrls.isEmpty() ? selectedUrls.first().fileName() : "Untitled";
- if (m_fileDialog->options()->fileMode() == QFileDialogOptions::ExistingFiles)
+ // Create an empty dummy file, so that the export dialog will allow us
+ // to choose the export destination, which we are then given access to
+ // write to.
+ NSURL *dummyExportFile = [NSFileManager.defaultManager.temporaryDirectory
+ URLByAppendingPathComponent:suggestedFileName.toNSString()];
+ [NSFileManager.defaultManager createFileAtPath:dummyExportFile.path contents:nil attributes:nil];
+
+ if (!(self = [super initForExportingURLs:@[dummyExportFile]]))
+ return nil;
+
+ // Note, we don't set the directoryURL, as if the directory can't be
+ // accessed, or written to, the file dialog is shown but is empty.
+ // FIXME: See comment below for open dialogs as well
+ } else {
+ if (!(self = [super initForOpeningContentTypes:docTypes asCopy:NO]))
+ return nil;
+
+ if (options->fileMode() == QFileDialogOptions::ExistingFiles)
self.allowsMultipleSelection = YES;
- self.directoryURL = m_fileDialog->options()->initialDirectory().toNSURL();
+ // FIXME: This doesn't seem to have any effect
+ self.directoryURL = options->initialDirectory().toNSURL();
}
+
+ m_fileDialog = fileDialog;
+ self.modalPresentationStyle = UIModalPresentationFormSheet;
+ self.delegate = self;
+ self.presentationController.delegate = self;
+
return self;
}
@@ -81,7 +93,7 @@
QList<QUrl> files;
for (NSURL* url in urls)
- files.append(QUrl::fromNSURL(url));
+ files.append(qt_apple_urlFromPossiblySecurityScopedURL(url));
m_fileDialog->selectedFilesChanged(files);
emit m_fileDialog->accept();
diff --git a/src/plugins/platforms/ios/qiosfiledialog.mm b/src/plugins/platforms/ios/qiosfiledialog.mm
index b7d3e488bbb..6e7c10117ed 100644
--- a/src/plugins/platforms/ios/qiosfiledialog.mm
+++ b/src/plugins/platforms/ios/qiosfiledialog.mm
@@ -49,14 +49,10 @@ bool QIOSFileDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality window
// when converted to QUrl, it becames a scheme.
const QString scheme = initialDir.scheme();
- if (acceptOpen) {
- if (directory.startsWith("assets-library:"_L1) || scheme == "assets-library"_L1)
- return showImagePickerDialog(parent);
- else
- return showNativeDocumentPickerDialog(parent);
- }
+ if (acceptOpen && (directory.startsWith("assets-library:"_L1) || scheme == "assets-library"_L1))
+ return showImagePickerDialog(parent);
- return false;
+ return showNativeDocumentPickerDialog(parent);
}
void QIOSFileDialog::showImagePickerDialog_helper(QWindow *parent)
diff --git a/src/plugins/platforms/wayland/qwaylandinputcontext.cpp b/src/plugins/platforms/wayland/qwaylandinputcontext.cpp
index 5ab285ad97d..0ccc4dba57a 100644
--- a/src/plugins/platforms/wayland/qwaylandinputcontext.cpp
+++ b/src/plugins/platforms/wayland/qwaylandinputcontext.cpp
@@ -192,12 +192,10 @@ void QWaylandInputContext::setFocusObject(QObject *object)
if (window && window->handle()) {
if (mCurrentWindow.data() != window) {
if (!inputMethodAccepted()) {
- if (mCurrentWindow) {
- auto *surface = static_cast<QWaylandWindow *>(mCurrentWindow->handle())->wlSurface();
- if (surface)
- inputInterface->disableSurface(surface);
- mCurrentWindow.clear();
- }
+ auto *surface = static_cast<QWaylandWindow *>(window->handle())->wlSurface();
+ if (surface)
+ inputInterface->disableSurface(surface);
+ mCurrentWindow.clear();
} else {
auto *surface = static_cast<QWaylandWindow *>(window->handle())->wlSurface();
if (surface) {
diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp
index 2bd2f0c9e3d..0236669d6fb 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.cpp
+++ b/src/plugins/platforms/windows/qwindowsscreen.cpp
@@ -704,7 +704,7 @@ void QWindowsScreenManager::initialize()
qCDebug(lcQpaScreen) << "Initializing screen manager";
auto className = QWindowsWindowClassRegistry::instance()->registerWindowClass(
- QLatin1String("ScreenChangeObserverWindow"),
+ "ScreenChangeObserverWindow"_L1,
qDisplayChangeObserverWndProc);
// HWND_MESSAGE windows do not get WM_DISPLAYCHANGE, so we need to create
diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp
index d132bbb6130..b9f60f7713c 100644
--- a/src/plugins/platforms/windows/qwindowstheme.cpp
+++ b/src/plugins/platforms/windows/qwindowstheme.cpp
@@ -549,7 +549,7 @@ QWindowsTheme::QWindowsTheme()
refreshIconPixmapSizes();
auto className = QWindowsWindowClassRegistry::instance()->registerWindowClass(
- QLatin1String("ThemeChangeObserverWindow"),
+ "ThemeChangeObserverWindow"_L1,
qThemeChangeObserverWndProc);
// HWND_MESSAGE windows do not get the required theme events,
// so we use a real top-level window that we never show.
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index ed391009423..b77e985c965 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -61,6 +61,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
using QWindowCreationContextPtr = QSharedPointer<QWindowCreationContext>;
enum {
@@ -889,7 +891,7 @@ QWindowsWindowData
const QString windowClassName = QWindowsWindowClassRegistry::instance()->registerWindowClass(w);
QWindowsWindowClassDescription windowTitlebarDescription;
- windowTitlebarDescription.name = QStringLiteral("_q_titlebar");
+ windowTitlebarDescription.name = "_q_titlebar"_L1;
windowTitlebarDescription.style = CS_VREDRAW | CS_HREDRAW;
windowTitlebarDescription.shouldAddPrefix = false;
const QString windowTitlebarName = QWindowsWindowClassRegistry::instance()->registerWindowClass(windowTitlebarDescription);