diff options
Diffstat (limited to 'src/plugins/platforms')
18 files changed, 294 insertions, 112 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/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/wasm/qwasminputcontext.cpp b/src/plugins/platforms/wasm/qwasminputcontext.cpp index a0546fdc215..6dfb4284149 100644 --- a/src/plugins/platforms/wasm/qwasminputcontext.cpp +++ b/src/plugins/platforms/wasm/qwasminputcontext.cpp @@ -24,13 +24,13 @@ using namespace qstdweb; void QWasmInputContext::inputCallback(emscripten::val event) { - qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << "isComposing : " << event["isComposing"].as<bool>(); - emscripten::val inputType = event["inputType"]; if (inputType.isNull() || inputType.isUndefined()) return; const auto inputTypeString = inputType.as<std::string>(); + // also may be dataTransfer + // containing rich text emscripten::val inputData = event["data"]; QString inputStr = (!inputData.isNull() && !inputData.isUndefined()) ? QString::fromEcmaString(inputData) : QString(); @@ -44,10 +44,10 @@ void QWasmInputContext::inputCallback(emscripten::val event) QInputMethodQueryEvent queryEvent(Qt::ImQueryAll); QCoreApplication::sendEvent(m_focusObject, &queryEvent); int cursorPosition = queryEvent.value(Qt::ImCursorPosition).toInt(); - int deleteLength = rangesPair.second - rangesPair.first; int deleteFrom = -1; - if (cursorPosition > rangesPair.first) { + + if (cursorPosition >= rangesPair.first) { deleteFrom = -(cursorPosition - rangesPair.first); } QInputMethodEvent e; @@ -65,21 +65,55 @@ void QWasmInputContext::inputCallback(emscripten::val event) event.call<void>("stopImmediatePropagation"); return; } else if (!inputTypeString.compare("insertCompositionText")) { - qCDebug(qLcQpaWasmInputContext) << "inputString : " << inputStr; - insertPreedit(); + qCDebug(qLcQpaWasmInputContext) << "insertCompositionText : " << inputStr; + event.call<void>("stopImmediatePropagation"); + + QInputMethodQueryEvent queryEvent(Qt::ImQueryAll); + QCoreApplication::sendEvent(m_focusObject, &queryEvent); + + int qCursorPosition = queryEvent.value(Qt::ImCursorPosition).toInt() ; + int replaceIndex = (qCursorPosition - rangesPair.first); + int replaceLength = rangesPair.second - rangesPair.first; + + setPreeditString(inputStr, replaceIndex); + insertPreedit(replaceLength); + + rangesPair.first = 0; + rangesPair.second = 0; event.call<void>("stopImmediatePropagation"); return; } else if (!inputTypeString.compare("insertReplacementText")) { - qCDebug(qLcQpaWasmInputContext) << "inputString : " << inputStr; - //auto ranges = event.call<emscripten::val>("getTargetRanges"); - //qCDebug(qLcQpaWasmInputContext) << ranges["length"].as<int>(); - // WA For Korean IME - // insertReplacementText should have targetRanges but - // Safari cannot have it and just it seems to be supposed - // to replace previous input. - insertText(inputStr, true); + // the previous input string up to the space, needs replaced with this + // used on iOS when continuing composition after focus change + // there's no range given + + qCDebug(qLcQpaWasmInputContext) << "insertReplacementText >>>>" << "inputString : " << inputStr; + emscripten::val ranges = event.call<emscripten::val>("getTargetRanges"); + + m_preeditString.clear(); + std::string elementString = m_inputElement["value"].as<std::string>(); + QInputMethodQueryEvent queryEvent(Qt::ImQueryAll); + QCoreApplication::sendEvent(m_focusObject, &queryEvent); + QString textFieldString = queryEvent.value(Qt::ImTextBeforeCursor).toString(); + int qCursorPosition = queryEvent.value(Qt::ImCursorPosition).toInt(); + + if (rangesPair.first != 0 || rangesPair.second != 0) { + + int replaceIndex = (qCursorPosition - rangesPair.first); + int replaceLength = rangesPair.second - rangesPair.first; + replaceText(inputStr, -replaceIndex, replaceLength); + rangesPair.first = 0; + rangesPair.second = 0; + + } else { + int spaceIndex = textFieldString.lastIndexOf(' ') + 1; + int replaceIndex = (qCursorPosition - spaceIndex); + + replaceText(inputStr, -replaceIndex, replaceIndex); + } event.call<void>("stopImmediatePropagation"); + return; } else if (!inputTypeString.compare("deleteCompositionText")) { setPreeditString("", 0); @@ -92,7 +126,25 @@ void QWasmInputContext::inputCallback(emscripten::val event) event.call<void>("stopImmediatePropagation"); return; } else if (!inputTypeString.compare("insertText")) { - insertText(inputStr); + if ((rangesPair.first != 0 || rangesPair.second != 0) + && rangesPair.first != rangesPair.second) { + + QInputMethodQueryEvent queryEvent(Qt::ImQueryAll); + QCoreApplication::sendEvent(m_focusObject, &queryEvent); + + int qCursorPosition = queryEvent.value(Qt::ImCursorPosition).toInt(); + int replaceIndex = (qCursorPosition - rangesPair.first); + int replaceLength = rangesPair.second - rangesPair.first; + + replaceText(inputStr, -replaceIndex, replaceLength); + + rangesPair.first = 0; + rangesPair.second = 0; + + } else { + insertText(inputStr); + } + event.call<void>("stopImmediatePropagation"); #if QT_CONFIG(clipboard) } else if (!inputTypeString.compare("insertFromPaste")) { @@ -112,9 +164,8 @@ void QWasmInputContext::inputCallback(emscripten::val event) void QWasmInputContext::compositionEndCallback(emscripten::val event) { const auto inputStr = QString::fromEcmaString(event["data"]); - qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << inputStr; - if (preeditString().isEmpty()) + if (preeditString().isEmpty()) // we get final results from inputCallback return; if (inputStr != preeditString()) { @@ -127,27 +178,11 @@ void QWasmInputContext::compositionEndCallback(emscripten::val event) void QWasmInputContext::compositionStartCallback(emscripten::val event) { - Q_UNUSED(event); - qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO; + Q_UNUSED(event); // Do nothing when starting composition } -/* -// Test implementation -static void beforeInputCallback(emscripten::val event) -{ - qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO; - - auto ranges = event.call<emscripten::val>("getTargetRanges"); - auto length = ranges["length"].as<int>(); - for (auto i = 0; i < length; i++) { - qCDebug(qLcQpaWasmInputContext) << ranges.call<emscripten::val>("get", i)["startOffset"].as<int>(); - qCDebug(qLcQpaWasmInputContext) << ranges.call<emscripten::val>("get", i)["endOffset"].as<int>(); - } -} -*/ - void QWasmInputContext::compositionUpdateCallback(emscripten::val event) { const auto compositionStr = QString::fromEcmaString(event["data"]); @@ -317,18 +352,21 @@ void QWasmInputContext::hideInputPanel() void QWasmInputContext::setPreeditString(QString preeditStr, int replaceSize) { + qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << preeditStr << replaceSize; m_preeditString = preeditStr; - m_replaceSize = replaceSize; + m_replaceIndex = replaceSize; } -void QWasmInputContext::insertPreedit() +void QWasmInputContext::insertPreedit(int replaceLength) { qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << m_preeditString; + if (replaceLength == 0) + replaceLength = m_preeditString.length(); QList<QInputMethodEvent::Attribute> attributes; { QInputMethodEvent::Attribute attr_cursor(QInputMethodEvent::Cursor, - m_preeditString.length(), + 0, 1); attributes.append(attr_cursor); @@ -336,21 +374,19 @@ void QWasmInputContext::insertPreedit() format.setFontUnderline(true); format.setUnderlineStyle(QTextCharFormat::SingleUnderline); QInputMethodEvent::Attribute attr_format(QInputMethodEvent::TextFormat, - 0, - m_preeditString.length(), format); + 0, + replaceLength, format); attributes.append(attr_format); } QInputMethodEvent e(m_preeditString, attributes); - if (m_replaceSize > 0) - e.setCommitString("", -m_replaceSize, m_replaceSize); + if (m_replaceIndex > 0) + e.setCommitString("", -m_replaceIndex, replaceLength); QCoreApplication::sendEvent(m_focusObject, &e); } void QWasmInputContext::commitPreeditAndClear() { - qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << m_preeditString; - if (m_preeditString.isEmpty()) return; QInputMethodEvent e; @@ -360,7 +396,8 @@ void QWasmInputContext::commitPreeditAndClear() } void QWasmInputContext::insertText(QString inputStr, bool replace) -{ +{ // commitString + qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << inputStr << replace; Q_UNUSED(replace); if (!inputStr.isEmpty()) { const int replaceLen = 0; @@ -370,4 +407,35 @@ void QWasmInputContext::insertText(QString inputStr, bool replace) } } +/* This will replace the text in the focusobject at replaceFrom position, and replaceSize length + with the text in inputStr. */ + + void QWasmInputContext::replaceText(QString inputStr, int replaceFrom, int replaceSize) + { + qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << inputStr << replaceFrom << replaceSize; + + QList<QInputMethodEvent::Attribute> attributes; + { + QInputMethodEvent::Attribute attr_cursor(QInputMethodEvent::Cursor, + 0, // start + 1); // length + attributes.append(attr_cursor); + + QTextCharFormat format; + format.setFontUnderline(true); + format.setUnderlineStyle(QTextCharFormat::SingleUnderline); + QInputMethodEvent::Attribute attr_format(QInputMethodEvent::TextFormat, + 0, + replaceSize, + format); + attributes.append(attr_format); + } + + QInputMethodEvent e1(QString(), attributes); + e1.setCommitString(inputStr, replaceFrom, replaceSize); + QCoreApplication::sendEvent(m_focusObject, &e1); + + m_preeditString.clear(); + } + QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasminputcontext.h b/src/plugins/platforms/wasm/qwasminputcontext.h index 97415451b2a..006a03455d7 100644 --- a/src/plugins/platforms/wasm/qwasminputcontext.h +++ b/src/plugins/platforms/wasm/qwasminputcontext.h @@ -33,10 +33,11 @@ public: const QString preeditString() { return m_preeditString; } void setPreeditString(QString preeditStr, int replaceSize); - void insertPreedit(); + void insertPreedit(int repalcementLength = 0); void commitPreeditAndClear(); void insertText(QString inputStr, bool replace = false); + void replaceText(QString inputString, int replaceFrom, int replaceSize); bool usingTextInput() const { return m_inputMethodAccepted; } void setFocusObject(QObject *object) override; @@ -58,7 +59,7 @@ private: private: QString m_preeditString; - int m_replaceSize = 0; + int m_replaceIndex = 0; bool m_inputMethodAccepted = false; QObject *m_focusObject = nullptr; diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp index a88299975d0..d318c977a90 100644 --- a/src/plugins/platforms/wasm/qwasmwindow.cpp +++ b/src/plugins/platforms/wasm/qwasmwindow.cpp @@ -761,12 +761,10 @@ void QWasmWindow::handleCompositionEndEvent(emscripten::val event) void QWasmWindow::handleBeforeInputEvent(emscripten::val event) { - qWarning() << Q_FUNC_INFO; - if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive()) inputContext->beforeInputCallback(event); - // else - // m_focusHelper.set("innerHTML", std::string()); + else + m_focusHelper.set("innerHTML", std::string()); } void QWasmWindow::handlePointerEnterLeaveEvent(const PointerEvent &event) 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/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 3013de1c068..156351987cb 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -696,7 +696,7 @@ HWND QWindowsContext::createDummyWindow(const QString &classNameIn, { if (!wndProc) wndProc = DefWindowProc; - QString className = d->m_windowClassRegistry.registerWindowClass(QWindowsWindowClassRegistry::classNamePrefix() + classNameIn, wndProc); + QString className = d->m_windowClassRegistry.registerWindowClass(classNameIn, wndProc); return CreateWindowEx(0, reinterpret_cast<LPCWSTR>(className.utf16()), windowName, style, CW_USEDEFAULT, CW_USEDEFAULT, diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 9139ec0c463..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( - QWindowsWindowClassRegistry::classNamePrefix() + 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/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp index a2ce1e86a4d..beeab1a089e 100644 --- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp +++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp @@ -119,9 +119,9 @@ static inline HWND createTrayIconMessageWindow() if (!ctx) return nullptr; // Register window class in the platform plugin. - const QString className = - ctx->registerWindowClass(QWindowsWindowClassRegistry::classNamePrefix() + "TrayIconMessageWindowClass"_L1, - qWindowsTrayIconWndProc); + const QString className = ctx->registerWindowClass( + "TrayIconMessageWindowClass"_L1, + qWindowsTrayIconWndProc); const wchar_t windowName[] = L"QTrayIconMessageWindow"; return CreateWindowEx(0, reinterpret_cast<const wchar_t *>(className.utf16()), windowName, WS_OVERLAPPED, diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 33d7c4124ac..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( - QWindowsWindowClassRegistry::classNamePrefix() + 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 26d0f907b92..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 { @@ -887,9 +889,12 @@ QWindowsWindowData const auto appinst = reinterpret_cast<HINSTANCE>(GetModuleHandle(nullptr)); const QString windowClassName = QWindowsWindowClassRegistry::instance()->registerWindowClass(w); - const QString windowTitlebarName = QWindowsWindowClassRegistry::instance()->registerWindowClass({ - QStringLiteral("_q_titlebar"), DefWindowProc, CS_VREDRAW | CS_HREDRAW - }); + + QWindowsWindowClassDescription windowTitlebarDescription; + windowTitlebarDescription.name = "_q_titlebar"_L1; + windowTitlebarDescription.style = CS_VREDRAW | CS_HREDRAW; + windowTitlebarDescription.shouldAddPrefix = false; + const QString windowTitlebarName = QWindowsWindowClassRegistry::instance()->registerWindowClass(windowTitlebarDescription); const QScreen *screen{}; const QRect rect = QPlatformWindow::initialGeometry(w, data.geometry, diff --git a/src/plugins/platforms/windows/qwindowswindowclassdescription.cpp b/src/plugins/platforms/windows/qwindowswindowclassdescription.cpp index cb862bba47c..e2e46a7b215 100644 --- a/src/plugins/platforms/windows/qwindowswindowclassdescription.cpp +++ b/src/plugins/platforms/windows/qwindowswindowclassdescription.cpp @@ -49,8 +49,7 @@ QWindowsWindowClassDescription QWindowsWindowClassDescription::fromWindow(const break; } // Create a unique name for the flag combination - description.name = QWindowsWindowClassRegistry::classNamePrefix(); - description.name += "QWindow"_L1; + description.name = "QWindow"_L1; switch (type) { case Qt::Tool: description.name += "Tool"_L1; @@ -76,4 +75,14 @@ QWindowsWindowClassDescription QWindowsWindowClassDescription::fromWindow(const return description; } +QDebug operator<<(QDebug dbg, const QWindowsWindowClassDescription &description) +{ + dbg << description.name + << " style=0x" << Qt::hex << description.style << Qt::dec + << " brush=" << description.brush + << " hasIcon=" << description.hasIcon; + + return dbg; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowswindowclassdescription.h b/src/plugins/platforms/windows/qwindowswindowclassdescription.h index ece48e4343c..3acca65b8a2 100644 --- a/src/plugins/platforms/windows/qwindowswindowclassdescription.h +++ b/src/plugins/platforms/windows/qwindowswindowclassdescription.h @@ -22,6 +22,10 @@ struct QWindowsWindowClassDescription unsigned int style{ 0 }; HBRUSH brush{ nullptr }; bool hasIcon{ false }; + bool shouldAddPrefix{ true }; + +private: + friend QDebug operator<<(QDebug dbg, const QWindowsWindowClassDescription &description); }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowswindowclassregistry.cpp b/src/plugins/platforms/windows/qwindowswindowclassregistry.cpp index e367350d55e..9c9ffcfeefa 100644 --- a/src/plugins/platforms/windows/qwindowswindowclassregistry.cpp +++ b/src/plugins/platforms/windows/qwindowswindowclassregistry.cpp @@ -59,6 +59,9 @@ QString QWindowsWindowClassRegistry::registerWindowClass(const QWindowsWindowCla { QString className = description.name; + if (description.shouldAddPrefix) + className = classNamePrefix() + className; + // since multiple Qt versions can be used in one process // each one has to have window class names with a unique name // The first instance gets the unmodified name; if the class @@ -111,9 +114,9 @@ QString QWindowsWindowClassRegistry::registerWindowClass(const QWindowsWindowCla qPrintable(className)); m_registeredWindowClassNames.insert(className); - qCDebug(lcQpaWindowClass).nospace() << __FUNCTION__ << ' ' << className - << " style=0x" << Qt::hex << description.style << Qt::dec - << " brush=" << description.brush << " icon=" << description.hasIcon << " atom=" << atom; + + qCDebug(lcQpaWindowClass).nospace() << __FUNCTION__ << ' ' << className << ' ' << description << " atom=" << atom; + return className; } diff --git a/src/plugins/platforms/windows/qwindowswindowclassregistry.h b/src/plugins/platforms/windows/qwindowswindowclassregistry.h index d1f10310dc8..c19b4f616fb 100644 --- a/src/plugins/platforms/windows/qwindowswindowclassregistry.h +++ b/src/plugins/platforms/windows/qwindowswindowclassregistry.h @@ -27,13 +27,13 @@ public: static QWindowsWindowClassRegistry *instance(); - static QString classNamePrefix(); - QString registerWindowClass(const QWindowsWindowClassDescription &description); QString registerWindowClass(const QWindow *window); QString registerWindowClass(QString name, WNDPROC procedure); private: + static QString classNamePrefix(); + void unregisterWindowClasses(); static QWindowsWindowClassRegistry *m_instance; |
