diff options
Diffstat (limited to 'src/gui/platform')
10 files changed, 235 insertions, 18 deletions
diff --git a/src/gui/platform/darwin/qapplekeymapper.mm b/src/gui/platform/darwin/qapplekeymapper.mm index dcc51bfca6..59cdc4f869 100644 --- a/src/gui/platform/darwin/qapplekeymapper.mm +++ b/src/gui/platform/darwin/qapplekeymapper.mm @@ -360,7 +360,7 @@ QChar QAppleKeyMapper::toCocoaKey(Qt::Key key) { // Prioritize overloaded keys if (key == Qt::Key_Return) - return QChar(NSNewlineCharacter); + return QChar(NSCarriageReturnCharacter); if (key == Qt::Key_Backspace) return QChar(NSBackspaceCharacter); @@ -601,7 +601,6 @@ QList<int> QAppleKeyMapper::possibleKeys(const QKeyEvent *event) const API_AVAILABLE(ios(13.4)) Qt::Key QAppleKeyMapper::fromUIKitKey(NSString *keyCode) { static QHash<NSString *, Qt::Key> uiKitKeys = { -#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_13_4) { UIKeyInputF1, Qt::Key_F1 }, { UIKeyInputF2, Qt::Key_F2 }, { UIKeyInputF3, Qt::Key_F3 }, @@ -618,7 +617,6 @@ API_AVAILABLE(ios(13.4)) Qt::Key QAppleKeyMapper::fromUIKitKey(NSString *keyCode { UIKeyInputEnd, Qt::Key_End }, { UIKeyInputPageUp, Qt::Key_PageUp }, { UIKeyInputPageDown, Qt::Key_PageDown }, -#endif { UIKeyInputEscape, Qt::Key_Escape }, { UIKeyInputUpArrow, Qt::Key_Up }, { UIKeyInputDownArrow, Qt::Key_Down }, diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenuregistrarproxy_p.h b/src/gui/platform/unix/dbusmenu/qdbusmenuregistrarproxy_p.h index 4568fd2aa4..8041f3af0a 100644 --- a/src/gui/platform/unix/dbusmenu/qdbusmenuregistrarproxy_p.h +++ b/src/gui/platform/unix/dbusmenu/qdbusmenuregistrarproxy_p.h @@ -63,7 +63,7 @@ public Q_SLOTS: // METHODS { QDBusMessage reply = call(QDBus::Block, QStringLiteral("GetMenuForWindow"), windowId); QList<QVariant> arguments = reply.arguments(); - if (reply.type() == QDBusMessage::ReplyMessage && arguments.count() == 2) + if (reply.type() == QDBusMessage::ReplyMessage && arguments.size() == 2) menuObjectPath = qdbus_cast<QDBusObjectPath>(arguments.at(1)); return reply; } diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenutypes.cpp b/src/gui/platform/unix/dbusmenu/qdbusmenutypes.cpp index f70ce67d4e..d2469a0d26 100644 --- a/src/gui/platform/unix/dbusmenu/qdbusmenutypes.cpp +++ b/src/gui/platform/unix/dbusmenu/qdbusmenutypes.cpp @@ -204,7 +204,7 @@ QString QDBusMenuItem::convertMnemonic(const QString &label) // convert only the first occurrence of ampersand which is not at the end // dbusmenu uses underscore instead of ampersand int idx = label.indexOf(u'&'); - if (idx < 0 || idx == label.length() - 1) + if (idx < 0 || idx == label.size() - 1) return label; QString ret(label); ret[idx] = u'_'; @@ -271,7 +271,7 @@ QDebug operator<<(QDebug d, const QDBusMenuLayoutItem &item) { QDebugStateSaver saver(d); d.nospace(); - d << "QDBusMenuLayoutItem(id=" << item.m_id << ", properties=" << item.m_properties << ", " << item.m_children.count() << " children)"; + d << "QDBusMenuLayoutItem(id=" << item.m_id << ", properties=" << item.m_properties << ", " << item.m_children.size() << " children)"; return d; } #endif diff --git a/src/gui/platform/unix/dbustray/qdbustraytypes.cpp b/src/gui/platform/unix/dbustray/qdbustraytypes.cpp index b2d87d7b8c..accbd87e7e 100644 --- a/src/gui/platform/unix/dbustray/qdbustraytypes.cpp +++ b/src/gui/platform/unix/dbustray/qdbustraytypes.cpp @@ -45,7 +45,7 @@ QXdgDBusImageVector iconToQXdgDBusImageVector(const QIcon &icon) bool hasSmallIcon = false; bool hasMediumIcon = false; QList<QSize> toRemove; - for (const QSize &size : qAsConst(sizes)) { + for (const QSize &size : std::as_const(sizes)) { int maxSize = qMax(size.width(), size.height()); if (maxSize <= IconNormalSmallSize) hasSmallIcon = true; @@ -54,7 +54,7 @@ QXdgDBusImageVector iconToQXdgDBusImageVector(const QIcon &icon) else if (maxSize > IconSizeLimit) toRemove << size; } - for (const QSize &size : qAsConst(toRemove)) + for (const QSize &size : std::as_const(toRemove)) sizes.removeOne(size); if (!hasSmallIcon) sizes.append(QSize(IconNormalSmallSize, IconNormalSmallSize)); @@ -62,7 +62,7 @@ QXdgDBusImageVector iconToQXdgDBusImageVector(const QIcon &icon) sizes.append(QSize(IconNormalMediumSize, IconNormalMediumSize)); ret.reserve(sizes.size()); - for (const QSize &size : qAsConst(sizes)) { + for (const QSize &size : std::as_const(sizes)) { // Protocol specifies ARGB32 format in network byte order QImage im = engine->pixmap(size, QIcon::Normal, QIcon::Off).toImage().convertToFormat(QImage::Format_ARGB32); // letterbox if necessary to make it square diff --git a/src/gui/platform/unix/dbustray/qstatusnotifieritemadaptor.cpp b/src/gui/platform/unix/dbustray/qstatusnotifieritemadaptor.cpp index 27a14e408a..2f6c13b6cf 100644 --- a/src/gui/platform/unix/dbustray/qstatusnotifieritemadaptor.cpp +++ b/src/gui/platform/unix/dbustray/qstatusnotifieritemadaptor.cpp @@ -136,6 +136,12 @@ void QStatusNotifierItemAdaptor::ContextMenu(int x, int y) emit m_trayIcon->activated(QPlatformSystemTrayIcon::Context); } +void QStatusNotifierItemAdaptor::ProvideXdgActivationToken(const QString &token) +{ + qCDebug(qLcTray) << token; + qputenv("XDG_ACTIVATION_TOKEN", token.toUtf8()); +} + void QStatusNotifierItemAdaptor::Scroll(int w, const QString &s) { qCDebug(qLcTray) << w << s; diff --git a/src/gui/platform/unix/dbustray/qstatusnotifieritemadaptor_p.h b/src/gui/platform/unix/dbustray/qstatusnotifieritemadaptor_p.h index 286aafa9bb..103fc974dd 100644 --- a/src/gui/platform/unix/dbustray/qstatusnotifieritemadaptor_p.h +++ b/src/gui/platform/unix/dbustray/qstatusnotifieritemadaptor_p.h @@ -73,6 +73,9 @@ class QStatusNotifierItemAdaptor: public QDBusAbstractAdaptor " <property access=\"read\" type=\"(sa(iiay)ss)\" name=\"ToolTip\">\n" " <annotation value=\"QXdgDBusToolTipStruct\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n" " </property>\n" +" <method name=\"ProvideXdgActivationToken\">\n" +" <arg name=\"token\" type=\"s\" direction=\"in\"/>\n" +" </method>\n" " <method name=\"ContextMenu\">\n" " <arg direction=\"in\" type=\"i\" name=\"x\"/>\n" " <arg direction=\"in\" type=\"i\" name=\"y\"/>\n" @@ -150,6 +153,7 @@ public: // PROPERTIES public Q_SLOTS: // METHODS void Activate(int x, int y); void ContextMenu(int x, int y); + void ProvideXdgActivationToken(const QString &token); void Scroll(int delta, const QString &orientation); void SecondaryActivate(int x, int y); Q_SIGNALS: // SIGNALS diff --git a/src/gui/platform/unix/dbustray/qxdgnotificationproxy_p.h b/src/gui/platform/unix/dbustray/qxdgnotificationproxy_p.h index fe61723bd2..dfbc64f33b 100644 --- a/src/gui/platform/unix/dbustray/qxdgnotificationproxy_p.h +++ b/src/gui/platform/unix/dbustray/qxdgnotificationproxy_p.h @@ -77,7 +77,7 @@ public Q_SLOTS: // METHODS inline QDBusReply<QString> getServerInformation(QString &vendor, QString &version, QString &specVersion) { QDBusMessage reply = call(QDBus::Block, QStringLiteral("GetServerInformation")); - if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 4) { + if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().size() == 4) { vendor = qdbus_cast<QString>(reply.arguments().at(1)); version = qdbus_cast<QString>(reply.arguments().at(2)); specVersion = qdbus_cast<QString>(reply.arguments().at(3)); diff --git a/src/gui/platform/unix/qgenericunixthemes.cpp b/src/gui/platform/unix/qgenericunixthemes.cpp index d90d5de098..1efd759bcf 100644 --- a/src/gui/platform/unix/qgenericunixthemes.cpp +++ b/src/gui/platform/unix/qgenericunixthemes.cpp @@ -41,6 +41,9 @@ #include <algorithm> QT_BEGIN_NAMESPACE +#ifndef QT_NO_DBUS +Q_LOGGING_CATEGORY(lcQpaThemeDBus, "qt.qpa.theme.dbus") +#endif using namespace Qt::StringLiterals; @@ -98,7 +101,92 @@ static bool isDBusGlobalMenuAvailable() static bool dbusGlobalMenuAvailable = checkDBusGlobalMenuAvailable(); return dbusGlobalMenuAvailable; } -#endif + +/*! + * \internal + * The QGenericUnixThemeDBusListener class listens to the SettingChanged DBus signal + * and translates it into the QDbusSettingType enum. + * Upon construction, it logs success/failure of the DBus connection. + * + * The signal settingChanged delivers the normalized setting type and the new value as a string. + * It is emitted on known setting types only. + */ + +class QGenericUnixThemeDBusListener : public QObject +{ + Q_OBJECT + +public: + QGenericUnixThemeDBusListener(const QString &service, const QString &path, const QString &interface, const QString &signal); + + enum class SettingType { + KdeGlobalTheme, + KdeApplicationStyle, + Unknown + }; + Q_ENUM(SettingType) + + static SettingType toSettingType(const QString &location, const QString &key); + +private Q_SLOTS: + void onSettingChanged(const QString &location, const QString &key, const QDBusVariant &value); + +Q_SIGNALS: + void settingChanged(QGenericUnixThemeDBusListener::SettingType type, const QString &value); + +}; + +QGenericUnixThemeDBusListener::QGenericUnixThemeDBusListener(const QString &service, + const QString &path, const QString &interface, const QString &signal) +{ + QDBusConnection dbus = QDBusConnection::sessionBus(); + const bool dBusRunning = dbus.isConnected(); + bool dBusSignalConnected = false; +#define LOG service << path << interface << signal; + + if (dBusRunning) { + qRegisterMetaType<QDBusVariant>(); + dBusSignalConnected = dbus.connect(service, path, interface, signal, this, + SLOT(onSettingChanged(QString,QString,QDBusVariant))); + } + + if (dBusSignalConnected) { + // Connection successful + qCDebug(lcQpaThemeDBus) << LOG; + } else { + if (dBusRunning) { + // DBus running, but connection failed + qCWarning(lcQpaThemeDBus) << "DBus connection failed:" << LOG; + } else { + // DBus not running + qCWarning(lcQpaThemeDBus) << "Session DBus not running."; + } + qCWarning(lcQpaThemeDBus) << "Application will not react to KDE setting changes.\n" + << "Check your DBus installation."; + } +#undef LOG +} + +QGenericUnixThemeDBusListener::SettingType QGenericUnixThemeDBusListener::toSettingType( + const QString &location, const QString &key) +{ + if (location == QLatin1StringView("org.kde.kdeglobals.KDE") + && key == QLatin1StringView("widgetStyle")) + return SettingType::KdeApplicationStyle; + if (location == QLatin1StringView("org.kde.kdeglobals.General") + && key == QLatin1StringView("ColorScheme")) + return SettingType::KdeGlobalTheme; + return SettingType::Unknown; +} + +void QGenericUnixThemeDBusListener::onSettingChanged(const QString &location, const QString &key, const QDBusVariant &value) +{ + const SettingType type = toSettingType(location, key); + if (type != SettingType::Unknown) + emit settingChanged(type, value.variant().toString()); +} + +#endif //QT_NO_DBUS class QGenericUnixThemePrivate : public QPlatformThemePrivate { @@ -231,11 +319,9 @@ static QIcon xdgFileIcon(const QFileInfo &fileInfo) #if QT_CONFIG(settings) class QKdeThemePrivate : public QPlatformThemePrivate { + public: - QKdeThemePrivate(const QStringList &kdeDirs, int kdeVersion) - : kdeDirs(kdeDirs) - , kdeVersion(kdeVersion) - { } + QKdeThemePrivate(const QStringList &kdeDirs, int kdeVersion); static QString kdeGlobals(const QString &kdeDir, int kdeVersion) { @@ -266,8 +352,59 @@ public: int startDragDist = 10; int startDragTime = 500; int cursorBlinkRate = 1000; + +#ifndef QT_NO_DBUS +private: + std::unique_ptr<QGenericUnixThemeDBusListener> dbus; + bool initDbus(); + void settingChangedHandler(QGenericUnixThemeDBusListener::SettingType type, const QString &value); +#endif // QT_NO_DBUS }; +#ifndef QT_NO_DBUS +void QKdeThemePrivate::settingChangedHandler(QGenericUnixThemeDBusListener::SettingType type, const QString &value) +{ + switch (type) { + case QGenericUnixThemeDBusListener::SettingType::KdeGlobalTheme: + qCDebug(lcQpaThemeDBus) << "KDE global theme changed to:" << value; + break; + case QGenericUnixThemeDBusListener::SettingType::KdeApplicationStyle: + qCDebug(lcQpaThemeDBus) << "KDE application style changed to:" << value; + break; + case QGenericUnixThemeDBusListener::SettingType::Unknown: + Q_UNREACHABLE(); + } + + refresh(); +} + +bool QKdeThemePrivate::initDbus() +{ + constexpr QLatin1StringView service(""); + constexpr QLatin1StringView path("/org/freedesktop/portal/desktop"); + constexpr QLatin1StringView interface("org.freedesktop.portal.Settings"); + constexpr QLatin1StringView signal("SettingChanged"); + + dbus.reset(new QGenericUnixThemeDBusListener(service, path, interface, signal)); + Q_ASSERT(dbus); + + // Wrap slot in a lambda to avoid inheriting QKdeThemePrivate from QObject + auto wrapper = [this](QGenericUnixThemeDBusListener::SettingType type, const QString &value) { + settingChangedHandler(type, value); + }; + + return QObject::connect(dbus.get(), &QGenericUnixThemeDBusListener::settingChanged, wrapper); +} +#endif // QT_NO_DBUS + +QKdeThemePrivate::QKdeThemePrivate(const QStringList &kdeDirs, int kdeVersion) + : kdeDirs(kdeDirs), kdeVersion(kdeVersion) +{ +#ifndef QT_NO_DBUS + initDbus(); +#endif // QT_NO_DBUS +} + void QKdeThemePrivate::refresh() { resources.clear(); @@ -368,6 +505,8 @@ void QKdeThemePrivate::refresh() if (QFont *toolBarFont = kdeFont(readKdeSetting(QStringLiteral("toolBarFont"), kdeDirs, kdeVersion, kdeSettings))) resources.fonts[QPlatformTheme::ToolButtonFont] = toolBarFont; + QWindowSystemInterface::handleThemeChange(); + qCDebug(lcQpaFonts) << "default fonts: system" << resources.fonts[QPlatformTheme::SystemFont] << "fixed" << resources.fonts[QPlatformTheme::FixedFont]; qDeleteAll(kdeSettings); @@ -726,6 +865,8 @@ QVariant QGnomeTheme::themeHint(QPlatformTheme::ThemeHint hint) const case QPlatformTheme::ButtonPressKeys: return QVariant::fromValue( QList<Qt::Key>({ Qt::Key_Space, Qt::Key_Return, Qt::Key_Enter, Qt::Key_Select })); + case QPlatformTheme::PreselectFirstFileInDirectory: + return true; default: break; } @@ -853,3 +994,7 @@ QStringList QGenericUnixTheme::themeNames() } QT_END_NAMESPACE + +#ifndef QT_NO_DBUS +#include "qgenericunixthemes.moc" +#endif // QT_NO_DBUS diff --git a/src/gui/platform/unix/qxkbcommon.cpp b/src/gui/platform/unix/qxkbcommon.cpp index b3ee0f4948..fd368f8282 100644 --- a/src/gui/platform/unix/qxkbcommon.cpp +++ b/src/gui/platform/unix/qxkbcommon.cpp @@ -461,7 +461,7 @@ QList<xkb_keysym_t> QXkbCommon::toKeysym(QKeyEvent *event) // From libxkbcommon keysym-utf.c: // "We allow to represent any UCS character in the range U-00000000 to // U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff." - for (uint utf32 : qAsConst(ucs4)) + for (uint utf32 : std::as_const(ucs4)) keysyms.append(utf32 | 0x01000000); return keysyms; @@ -682,7 +682,7 @@ QList<int> QXkbCommon::possibleKeys(xkb_state *state, const QKeyEvent *event, // catch only more specific shortcuts, i.e. Ctrl+Shift+= also generates Ctrl++ and +, // but Ctrl++ is more specific than +, so we should skip the last one bool ambiguous = false; - for (int shortcut : qAsConst(result)) { + for (int shortcut : std::as_const(result)) { if (int(shortcut & ~Qt::KeyboardModifierMask) == qtKey && (shortcut & mods) == mods) { ambiguous = true; break; diff --git a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp index 172c8f6814..521aa7513b 100644 --- a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp +++ b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp @@ -8,8 +8,12 @@ #include <emscripten/html5.h> #include <emscripten/val.h> +#include <QtCore/qregularexpression.h> + QT_BEGIN_NAMESPACE +using namespace Qt::Literals::StringLiterals; + namespace QWasmLocalFileAccess { void readFiles(const qstdweb::FileList &fileList, @@ -44,6 +48,66 @@ void readFiles(const qstdweb::FileList &fileList, (*readFile)(0); } +std::string acceptListFromQtFormat(const std::string &qtAcceptList) +{ + // copy of qt_make_filter_list() from qfiledialog.cpp + auto make_filter_list = [](const QString &filter) -> QStringList + { + if (filter.isEmpty()) + return QStringList(); + + QString sep(";;"_L1); + if (!filter.contains(sep) && filter.contains(u'\n')) + sep = u'\n'; + + return filter.split(sep); + }; + + const QStringList fileFilter = make_filter_list(QString::fromStdString(qtAcceptList)); + QStringList transformed; + for (const auto &element : fileFilter) { + // Accepts either a string in format: + // GROUP3 + // or in this format: + // GROUP1 (GROUP2) + // Group 1 is treated as the description, whereas group 2 or 3 are treated as the filter + // list. + static QRegularExpression regex( + QString(QStringLiteral("(?:([^(]*)\\(([^()]+)\\)[^)]*)|([^()]+)"))); + static QRegularExpression wordCharacterRegex(QString(QStringLiteral("\\w"))); + const auto match = regex.match(element); + + if (!match.hasMatch()) + continue; + + constexpr size_t FilterListFromParensIndex = 2; + constexpr size_t PlainFilterListIndex = 3; + QString filterList = match.captured(match.hasCaptured(FilterListFromParensIndex) + ? FilterListFromParensIndex + : PlainFilterListIndex); + for (auto singleExtension : filterList.split(QStringLiteral(" "), Qt::SkipEmptyParts)) { + // Checks for a filter that matches everything: + // Any number of asterisks or any number of asterisks with a '.' between them. + // The web filter does not support wildcards. + static QRegularExpression qtAcceptAllRegex(QRegularExpression::anchoredPattern( + QString(QStringLiteral("[*]+|[*]+\\.[*]+")))); + if (qtAcceptAllRegex.match(singleExtension).hasMatch()) + continue; + + // Checks for correctness. The web filter only allows filename extensions and does not + // filter the actual filenames, therefore we check whether the filter provided only + // filters for the extension. + static QRegularExpression qtFilenameMatcherRegex(QRegularExpression::anchoredPattern( + QString(QStringLiteral("(\\*?)(\\.[^*]+)")))); + + auto extensionMatch = qtFilenameMatcherRegex.match(singleExtension); + if (extensionMatch.hasMatch()) + transformed.append(extensionMatch.captured(2)); + } + } + return transformed.join(QStringLiteral(",")).toStdString(); +} + typedef std::function<void (const qstdweb::FileList &fileList)> OpenFileDialogCallback; void openFileDialog(const std::string &accept, FileSelectMode fileSelectMode, const OpenFileDialogCallback &filesSelected) @@ -55,7 +119,7 @@ void openFileDialog(const std::string &accept, FileSelectMode fileSelectMode, emscripten::val input = document.call<emscripten::val>("createElement", std::string("input")); input.set("type", "file"); input.set("style", "display:none"); - input.set("accept", emscripten::val(accept)); + input.set("accept", acceptListFromQtFormat(accept)); input.set("multiple", emscripten::val(fileSelectMode == MultipleFiles)); // Note: there is no event in case the user cancels the file dialog. |