summaryrefslogtreecommitdiffstats
path: root/src/gui/platform
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/platform')
-rw-r--r--src/gui/platform/darwin/qapplekeymapper.mm4
-rw-r--r--src/gui/platform/unix/dbusmenu/qdbusmenuregistrarproxy_p.h2
-rw-r--r--src/gui/platform/unix/dbusmenu/qdbusmenutypes.cpp4
-rw-r--r--src/gui/platform/unix/dbustray/qdbustraytypes.cpp6
-rw-r--r--src/gui/platform/unix/dbustray/qstatusnotifieritemadaptor.cpp6
-rw-r--r--src/gui/platform/unix/dbustray/qstatusnotifieritemadaptor_p.h4
-rw-r--r--src/gui/platform/unix/dbustray/qxdgnotificationproxy_p.h2
-rw-r--r--src/gui/platform/unix/qgenericunixthemes.cpp155
-rw-r--r--src/gui/platform/unix/qxkbcommon.cpp4
-rw-r--r--src/gui/platform/wasm/qwasmlocalfileaccess.cpp66
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.