Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qgenericunixthemes.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <QPalette>
7#include <QFont>
8#include <QGuiApplication>
9#include <QDir>
10#include <QFileInfo>
11#include <QFile>
12#include <QDebug>
13#include <QHash>
14#include <QLoggingCategory>
15#include <QVariant>
16#include <QStandardPaths>
17#include <QStringList>
18#if QT_CONFIG(mimetype)
19#include <QMimeDatabase>
20#endif
21#if QT_CONFIG(settings)
22#include <QSettings>
23#endif
24
25#include <qpa/qplatformfontdatabase.h> // lcQpaFonts
26#include <qpa/qplatformintegration.h>
27#include <qpa/qplatformservices.h>
28#include <qpa/qplatformdialoghelper.h>
29#include <qpa/qplatformtheme_p.h>
30
31#include <private/qguiapplication_p.h>
32#ifndef QT_NO_DBUS
33#include <QDBusConnectionInterface>
34#include <private/qdbusplatformmenu_p.h>
35#include <private/qdbusmenubar_p.h>
36#include <private/qflatmap_p.h>
37#include <QJsonDocument>
38#include <QJsonArray>
39#include <QJsonObject>
40#include <QJsonValue>
41#include <QJsonParseError>
42#endif
43#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON)
44#include <private/qdbustrayicon_p.h>
45#endif
46
47#include <algorithm>
48
50#ifndef QT_NO_DBUS
51Q_LOGGING_CATEGORY(lcQpaThemeDBus, "qt.qpa.theme.dbus")
52#endif
53
54using namespace Qt::StringLiterals;
55
57
59{
60 std::fill(palettes, palettes + QPlatformTheme::NPalettes, static_cast<QPalette *>(nullptr));
61 std::fill(fonts, fonts + QPlatformTheme::NFonts, static_cast<QFont *>(nullptr));
62}
63
71
72const char *QGenericUnixTheme::name = "generic";
73
74// Default system font, corresponding to the value returned by 4.8 for
75// XRender/FontConfig which we can now assume as default.
76static const char defaultSystemFontNameC[] = "Sans Serif";
77static const char defaultFixedFontNameC[] = "monospace";
79
80#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON)
81static bool isDBusTrayAvailable() {
82 static bool dbusTrayAvailable = false;
83 static bool dbusTrayAvailableKnown = false;
84 if (!dbusTrayAvailableKnown) {
86 if (conn.isWatcherRegistered())
87 dbusTrayAvailable = true;
88 dbusTrayAvailableKnown = true;
89 qCDebug(qLcTray) << "D-Bus tray available:" << dbusTrayAvailable;
90 }
91 return dbusTrayAvailable;
92}
93#endif
94
96{
97 static QString themeName = qEnvironmentVariable("XCURSOR_THEME");
98 return themeName;
99}
100
102{
103 constexpr int defaultCursorSize = 24;
104 static const int xCursorSize = qEnvironmentVariableIntValue("XCURSOR_SIZE");
105 static const int s = xCursorSize > 0 ? xCursorSize : defaultCursorSize;
106 return QSize(s, s);
107}
108
109#ifndef QT_NO_DBUS
111{
113 static const QString registrarService = QStringLiteral("com.canonical.AppMenu.Registrar");
114 if (const auto iface = connection.interface())
115 return iface->isServiceRegistered(registrarService);
116 return false;
117}
118
120{
121 static bool dbusGlobalMenuAvailable = checkDBusGlobalMenuAvailable();
122 return dbusGlobalMenuAvailable;
123}
124
136{
138
139public:
140
141 enum class Provider {
142 Kde,
143 Gtk,
144 Gnome,
145 };
147
148 enum class Setting {
149 Theme,
152 };
154
156 QGenericUnixThemeDBusListener(const QString &service, const QString &path,
157 const QString &interface, const QString &signal);
158
159private Q_SLOTS:
160 void onSettingChanged(const QString &location, const QString &key, const QDBusVariant &value);
161
165 const QString &value);
166
167private:
168 struct DBusKey
169 {
171 QString key;
172 DBusKey(const QString &loc, const QString &k) : location(loc), key(k) {};
173 bool operator<(const DBusKey &other) const
174 {
175 return location + key < other.location + other.key;
176 }
177 };
178
179 struct ChangeSignal
180 {
181 Provider provider;
182 Setting setting;
183 ChangeSignal(Provider p, Setting s) : provider(p), setting(s) {}
184 ChangeSignal() {}
185 };
186
187 // Json keys
188 static constexpr QLatin1StringView s_dbusLocation = QLatin1StringView("DBusLocation");
189 static constexpr QLatin1StringView s_dbusKey = QLatin1StringView("DBusKey");
190 static constexpr QLatin1StringView s_provider = QLatin1StringView("Provider");
191 static constexpr QLatin1StringView s_setting = QLatin1StringView("Setting");
192 static constexpr QLatin1StringView s_signals = QLatin1StringView("DbusSignals");
193 static constexpr QLatin1StringView s_root = QLatin1StringView("Qt.qpa.DBusSignals");
194
195 QFlatMap <DBusKey, ChangeSignal> m_signalMap;
196
197 void init(const QString &service, const QString &path,
198 const QString &interface, const QString &signal);
199
200 std::optional<ChangeSignal> findSignal(const QString &location, const QString &key) const;
201 void populateSignalMap();
202 void loadJson(const QString &fileName);
203 void saveJson(const QString &fileName) const;
204};
205
207 const QString &path, const QString &interface, const QString &signal)
208{
209 init (service, path, interface, signal);
210}
211
213{
214 static constexpr QLatin1StringView service("");
215 static constexpr QLatin1StringView path("/org/freedesktop/portal/desktop");
216 static constexpr QLatin1StringView interface("org.freedesktop.portal.Settings");
217 static constexpr QLatin1StringView signal("SettingChanged");
218
219 init (service, path, interface, signal);
220}
221
222void QGenericUnixThemeDBusListener::init(const QString &service, const QString &path,
223 const QString &interface, const QString &signal)
224{
226 const bool dBusRunning = dbus.isConnected();
227 bool dBusSignalConnected = false;
228#define LOG service << path << interface << signal;
229
230 if (dBusRunning) {
231 populateSignalMap();
232 qRegisterMetaType<QDBusVariant>();
233 dBusSignalConnected = dbus.connect(service, path, interface, signal, this,
234 SLOT(onSettingChanged(QString,QString,QDBusVariant)));
235 }
236
237 if (dBusSignalConnected) {
238 // Connection successful
239 qCDebug(lcQpaThemeDBus) << LOG;
240 } else {
241 if (dBusRunning) {
242 // DBus running, but connection failed
243 qCWarning(lcQpaThemeDBus) << "DBus connection failed:" << LOG;
244 } else {
245 // DBus not running
246 qCWarning(lcQpaThemeDBus) << "Session DBus not running.";
247 }
248 qCWarning(lcQpaThemeDBus) << "Application will not react to setting changes.\n"
249 << "Check your DBus installation.";
250 }
251#undef LOG
252}
253
254void QGenericUnixThemeDBusListener::loadJson(const QString &fileName)
255{
256 Q_ASSERT(!fileName.isEmpty());
257#define CHECK(cond, warning)\
258 if (!cond) {\
259 qCWarning(lcQpaThemeDBus) << fileName << warning << "Falling back to default.";\
260 return;\
261 }
262
263#define PARSE(var, enumeration, string)\
264 enumeration var;\
265 {\
266 bool success;\
267 const int val = QMetaEnum::fromType<enumeration>().keyToValue(string.toLatin1(), &success);\
268 CHECK(success, "Parse Error: Invalid value" << string << "for" << #var);\
269 var = static_cast<enumeration>(val);\
270 }
271
273 CHECK(file.exists(), fileName << "doesn't exist.");
274 CHECK(file.open(QIODevice::ReadOnly), "could not be opened for reading.");
275
278 CHECK((error.error == QJsonParseError::NoError), error.errorString());
279 CHECK(doc.isObject(), "Parse Error: Expected root object" << s_root);
280
281 const QJsonObject &root = doc.object();
282 CHECK(root.contains(s_root), "Parse Error: Expected root object" << s_root);
283 CHECK(root[s_root][s_signals].isArray(), "Parse Error: Expected array" << s_signals);
284
285 const QJsonArray &sigs = root[s_root][s_signals].toArray();
286 CHECK((sigs.count() > 0), "Parse Error: Found empty array" << s_signals);
287
288 for (auto sig = sigs.constBegin(); sig != sigs.constEnd(); ++sig) {
289 CHECK(sig->isObject(), "Parse Error: Expected object array" << s_signals);
290 const QJsonObject &obj = sig->toObject();
291 CHECK(obj.contains(s_dbusLocation), "Parse Error: Expected key" << s_dbusLocation);
292 CHECK(obj.contains(s_dbusKey), "Parse Error: Expected key" << s_dbusKey);
293 CHECK(obj.contains(s_provider), "Parse Error: Expected key" << s_provider);
294 CHECK(obj.contains(s_setting), "Parse Error: Expected key" << s_setting);
295 const QString &location = obj[s_dbusLocation].toString();
296 const QString &key = obj[s_dbusKey].toString();
297 const QString &providerString = obj[s_provider].toString();
298 const QString &settingString = obj[s_setting].toString();
299 PARSE(provider, Provider, providerString);
300 PARSE(setting, Setting, settingString);
301 const DBusKey dkey(location, key);
302 CHECK (!m_signalMap.contains(dkey), "Duplicate key" << location << key);
303 m_signalMap.insert(dkey, ChangeSignal(provider, setting));
304 }
305#undef PARSE
306#undef CHECK
307
308 if (m_signalMap.count() > 0)
309 qCInfo(lcQpaThemeDBus) << "Successfully imported" << fileName;
310 else
311 qCWarning(lcQpaThemeDBus) << "No data imported from" << fileName << "falling back to default.";
312
313#ifdef QT_DEBUG
314 const int count = m_signalMap.count();
315 if (count == 0)
316 return;
317
318 qCDebug(lcQpaThemeDBus) << "Listening to" << count << "signals:";
319 for (auto it = m_signalMap.constBegin(); it != m_signalMap.constEnd(); ++it) {
320 qDebug() << it.key().key << it.key().location << "mapped to"
321 << it.value().provider << it.value().setting;
322 }
323
324#endif
325}
326
327void QGenericUnixThemeDBusListener::saveJson(const QString &fileName) const
328{
329 Q_ASSERT(!m_signalMap.isEmpty());
330 Q_ASSERT(!fileName.isEmpty());
333 qCWarning(lcQpaThemeDBus) << fileName << "could not be opened for writing.";
334 return;
335 }
336
337 QJsonArray sigs;
338 for (auto sig = m_signalMap.constBegin(); sig != m_signalMap.constEnd(); ++sig) {
339 const DBusKey &dkey = sig.key();
340 const ChangeSignal &csig = sig.value();
342 obj[s_dbusLocation] = dkey.location;
343 obj[s_dbusKey] = dkey.key;
344 obj[s_provider] = QLatin1StringView(QMetaEnum::fromType<Provider>()
345 .valueToKey(static_cast<int>(csig.provider)));
346 obj[s_setting] = QLatin1StringView(QMetaEnum::fromType<Setting>()
347 .valueToKey(static_cast<int>(csig.setting)));
348 sigs.append(obj);
349 }
351 obj[s_signals] = sigs;
352 QJsonObject root;
353 root[s_root] = obj;
354 QJsonDocument doc(root);
355 file.write(doc.toJson());
356 file.close();
357}
358
359void QGenericUnixThemeDBusListener::populateSignalMap()
360{
361 m_signalMap.clear();
362 const QString &loadJsonFile = qEnvironmentVariable("QT_QPA_DBUS_SIGNALS");
363 if (!loadJsonFile.isEmpty())
364 loadJson(loadJsonFile);
365 if (!m_signalMap.isEmpty())
366 return;
367
368 m_signalMap.insert(DBusKey("org.kde.kdeglobals.KDE"_L1, "widgetStyle"_L1),
370
371 m_signalMap.insert(DBusKey("org.kde.kdeglobals.General"_L1, "ColorScheme"_L1),
372 ChangeSignal(Provider::Kde, Setting::Theme));
373
374 m_signalMap.insert(DBusKey("org.gnome.desktop.interface"_L1, "gtk-theme"_L1),
375 ChangeSignal(Provider::Gtk, Setting::Theme));
376
377 m_signalMap.insert(DBusKey("org.freedesktop.appearance"_L1, "color-scheme"_L1),
379
380 const QString &saveJsonFile = qEnvironmentVariable("QT_QPA_DBUS_SIGNALS_SAVE");
381 if (!saveJsonFile.isEmpty())
382 saveJson(saveJsonFile);
383}
384
385std::optional<QGenericUnixThemeDBusListener::ChangeSignal>
386 QGenericUnixThemeDBusListener::findSignal(const QString &location, const QString &key) const
387{
388 const DBusKey dkey(location, key);
389 std::optional<QGenericUnixThemeDBusListener::ChangeSignal> ret;
390 if (m_signalMap.contains(dkey))
391 ret.emplace(m_signalMap.value(dkey));
392
393 return ret;
394}
395
396void QGenericUnixThemeDBusListener::onSettingChanged(const QString &location, const QString &key, const QDBusVariant &value)
397{
398 auto sig = findSignal(location, key);
399 if (!sig.has_value())
400 return;
401
402 emit settingChanged(sig.value().provider, sig.value().setting, value.variant().toString());
403}
404
405#endif //QT_NO_DBUS
406
422
427
429{
430 Q_D(const QGenericUnixTheme);
431 switch (type) {
433 return &d->systemFont;
435 return &d->fixedFont;
436 default:
437 return nullptr;
438 }
439}
440
441// Helper to return the icon theme paths from XDG.
443{
445 // Add home directory first in search path
446 const QFileInfo homeIconDir(QDir::homePath() + "/.icons"_L1);
447 if (homeIconDir.isDir())
448 paths.prepend(homeIconDir.absoluteFilePath());
449
451 QStringLiteral("icons"),
453
454 return paths;
455}
456
458{
460 const QFileInfo pixmapsIconsDir(QStringLiteral("/usr/share/pixmaps"));
461 if (pixmapsIconsDir.isDir())
462 paths.append(pixmapsIconsDir.absoluteFilePath());
463
464 return paths;
465}
466
467#ifndef QT_NO_DBUS
469{
471 return new QDBusMenuBar();
472 return nullptr;
473}
474#endif
475
476#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON)
478{
480 return new QDBusTrayIcon();
481 return nullptr;
482}
483#endif
484
514
515// Helper functions for implementing QPlatformTheme::fileIcon() for XDG icon themes.
516static QList<QSize> availableXdgFileIconSizes()
517{
518 return QIcon::fromTheme(QStringLiteral("inode-directory")).availableSizes();
519}
520
521#if QT_CONFIG(mimetype)
522static QIcon xdgFileIcon(const QFileInfo &fileInfo)
523{
524 QMimeDatabase mimeDatabase;
525 QMimeType mimeType = mimeDatabase.mimeTypeForFile(fileInfo);
526 if (!mimeType.isValid())
527 return QIcon();
528 const QString &iconName = mimeType.iconName();
529 if (!iconName.isEmpty()) {
530 const QIcon icon = QIcon::fromTheme(iconName);
531 if (!icon.isNull())
532 return icon;
533 }
534 const QString &genericIconName = mimeType.genericIconName();
535 return genericIconName.isEmpty() ? QIcon() : QIcon::fromTheme(genericIconName);
536}
537#endif
538
539#if QT_CONFIG(settings)
540class QKdeThemePrivate : public QPlatformThemePrivate
541{
542
543public:
544 QKdeThemePrivate(const QStringList &kdeDirs, int kdeVersion);
545
546 static QString kdeGlobals(const QString &kdeDir, int kdeVersion)
547 {
548 if (kdeVersion > 4)
549 return kdeDir + "/kdeglobals"_L1;
550 return kdeDir + "/share/config/kdeglobals"_L1;
551 }
552
553 void refresh();
554 static QVariant readKdeSetting(const QString &key, const QStringList &kdeDirs, int kdeVersion, QHash<QString, QSettings*> &kdeSettings);
555 static void readKdeSystemPalette(const QStringList &kdeDirs, int kdeVersion, QHash<QString, QSettings*> &kdeSettings, QPalette *pal);
556 static QFont *kdeFont(const QVariant &fontValue);
557 static QStringList kdeIconThemeSearchPaths(const QStringList &kdeDirs);
558
559 const QStringList kdeDirs;
560 const int kdeVersion;
561
562 ResourceHelper resources;
563 QString iconThemeName;
564 QString iconFallbackThemeName;
566 int toolButtonStyle = Qt::ToolButtonTextBesideIcon;
567 int toolBarIconSize = 0;
568 bool singleClick = true;
569 bool showIconsOnPushButtons = true;
570 int wheelScrollLines = 3;
571 int doubleClickInterval = 400;
572 int startDragDist = 10;
573 int startDragTime = 500;
574 int cursorBlinkRate = 1000;
576 void updateColorScheme(const QString &themeName);
577
578#ifndef QT_NO_DBUS
579private:
580 std::unique_ptr<QGenericUnixThemeDBusListener> dbus;
581 bool initDbus();
582 void settingChangedHandler(QGenericUnixThemeDBusListener::Provider provider,
584 const QString &value);
585#endif // QT_NO_DBUS
586};
587
588#ifndef QT_NO_DBUS
589void QKdeThemePrivate::settingChangedHandler(QGenericUnixThemeDBusListener::Provider provider,
591 const QString &value)
592{
594 return;
595
596 switch (setting) {
598 qCDebug(lcQpaThemeDBus) << "KDE color theme changed to:" << value;
599 break;
601 qCDebug(lcQpaThemeDBus) << "KDE global theme changed to:" << value;
602 break;
604 qCDebug(lcQpaThemeDBus) << "KDE application style changed to:" << value;
605 break;
606 }
607
608 refresh();
609}
610
611bool QKdeThemePrivate::initDbus()
612{
614 Q_ASSERT(dbus);
615
616 // Wrap slot in a lambda to avoid inheriting QKdeThemePrivate from QObject
619 const QString &value) {
620 settingChangedHandler(provider, setting, value);
621 };
622
624}
625#endif // QT_NO_DBUS
626
627QKdeThemePrivate::QKdeThemePrivate(const QStringList &kdeDirs, int kdeVersion)
628 : kdeDirs(kdeDirs), kdeVersion(kdeVersion)
629{
630#ifndef QT_NO_DBUS
631 initDbus();
632#endif // QT_NO_DBUS
633}
634
635void QKdeThemePrivate::refresh()
636{
637 resources.clear();
638
639 toolButtonStyle = Qt::ToolButtonTextBesideIcon;
640 toolBarIconSize = 0;
641 styleNames.clear();
642 if (kdeVersion >= 5)
643 styleNames << QStringLiteral("breeze");
644 styleNames << QStringLiteral("Oxygen") << QStringLiteral("Fusion") << QStringLiteral("windows");
645 if (kdeVersion >= 5)
646 iconFallbackThemeName = iconThemeName = QStringLiteral("breeze");
647 else
648 iconFallbackThemeName = iconThemeName = QStringLiteral("oxygen");
649
650 QHash<QString, QSettings*> kdeSettings;
651
652 QPalette systemPalette = QPalette();
653 readKdeSystemPalette(kdeDirs, kdeVersion, kdeSettings, &systemPalette);
654 resources.palettes[QPlatformTheme::SystemPalette] = new QPalette(systemPalette);
655 //## TODO tooltip color
656
657 const QVariant styleValue = readKdeSetting(QStringLiteral("widgetStyle"), kdeDirs, kdeVersion, kdeSettings);
658 if (styleValue.isValid()) {
659 const QString style = styleValue.toString();
660 if (style != styleNames.front())
661 styleNames.push_front(style);
662 }
663
664 const QVariant colorScheme = readKdeSetting(QStringLiteral("ColorScheme"), kdeDirs,
665 kdeVersion, kdeSettings);
666
667 if (colorScheme.isValid())
668 updateColorScheme(colorScheme.toString());
669 else
670 m_colorScheme = Qt::ColorScheme::Unknown;
671
672 const QVariant singleClickValue = readKdeSetting(QStringLiteral("KDE/SingleClick"), kdeDirs, kdeVersion, kdeSettings);
673 if (singleClickValue.isValid())
674 singleClick = singleClickValue.toBool();
675
676 const QVariant showIconsOnPushButtonsValue = readKdeSetting(QStringLiteral("KDE/ShowIconsOnPushButtons"), kdeDirs, kdeVersion, kdeSettings);
677 if (showIconsOnPushButtonsValue.isValid())
678 showIconsOnPushButtons = showIconsOnPushButtonsValue.toBool();
679
680 const QVariant themeValue = readKdeSetting(QStringLiteral("Icons/Theme"), kdeDirs, kdeVersion, kdeSettings);
681 if (themeValue.isValid())
682 iconThemeName = themeValue.toString();
683
684 const QVariant toolBarIconSizeValue = readKdeSetting(QStringLiteral("ToolbarIcons/Size"), kdeDirs, kdeVersion, kdeSettings);
685 if (toolBarIconSizeValue.isValid())
686 toolBarIconSize = toolBarIconSizeValue.toInt();
687
688 const QVariant toolbarStyleValue = readKdeSetting(QStringLiteral("Toolbar style/ToolButtonStyle"), kdeDirs, kdeVersion, kdeSettings);
689 if (toolbarStyleValue.isValid()) {
690 const QString toolBarStyle = toolbarStyleValue.toString();
691 if (toolBarStyle == "TextBesideIcon"_L1)
692 toolButtonStyle = Qt::ToolButtonTextBesideIcon;
693 else if (toolBarStyle == "TextOnly"_L1)
694 toolButtonStyle = Qt::ToolButtonTextOnly;
695 else if (toolBarStyle == "TextUnderIcon"_L1)
696 toolButtonStyle = Qt::ToolButtonTextUnderIcon;
697 }
698
699 const QVariant wheelScrollLinesValue = readKdeSetting(QStringLiteral("KDE/WheelScrollLines"), kdeDirs, kdeVersion, kdeSettings);
700 if (wheelScrollLinesValue.isValid())
701 wheelScrollLines = wheelScrollLinesValue.toInt();
702
703 const QVariant doubleClickIntervalValue = readKdeSetting(QStringLiteral("KDE/DoubleClickInterval"), kdeDirs, kdeVersion, kdeSettings);
704 if (doubleClickIntervalValue.isValid())
705 doubleClickInterval = doubleClickIntervalValue.toInt();
706
707 const QVariant startDragDistValue = readKdeSetting(QStringLiteral("KDE/StartDragDist"), kdeDirs, kdeVersion, kdeSettings);
708 if (startDragDistValue.isValid())
709 startDragDist = startDragDistValue.toInt();
710
711 const QVariant startDragTimeValue = readKdeSetting(QStringLiteral("KDE/StartDragTime"), kdeDirs, kdeVersion, kdeSettings);
712 if (startDragTimeValue.isValid())
713 startDragTime = startDragTimeValue.toInt();
714
715 const QVariant cursorBlinkRateValue = readKdeSetting(QStringLiteral("KDE/CursorBlinkRate"), kdeDirs, kdeVersion, kdeSettings);
716 if (cursorBlinkRateValue.isValid()) {
717 cursorBlinkRate = cursorBlinkRateValue.toInt();
718 cursorBlinkRate = cursorBlinkRate > 0 ? qBound(200, cursorBlinkRate, 2000) : 0;
719 }
720
721 // Read system font, ignore 'smallestReadableFont'
722 if (QFont *systemFont = kdeFont(readKdeSetting(QStringLiteral("font"), kdeDirs, kdeVersion, kdeSettings)))
723 resources.fonts[QPlatformTheme::SystemFont] = systemFont;
724 else
726
727 if (QFont *fixedFont = kdeFont(readKdeSetting(QStringLiteral("fixed"), kdeDirs, kdeVersion, kdeSettings))) {
728 resources.fonts[QPlatformTheme::FixedFont] = fixedFont;
729 } else {
731 fixedFont->setStyleHint(QFont::TypeWriter);
732 resources.fonts[QPlatformTheme::FixedFont] = fixedFont;
733 }
734
735 if (QFont *menuFont = kdeFont(readKdeSetting(QStringLiteral("menuFont"), kdeDirs, kdeVersion, kdeSettings))) {
736 resources.fonts[QPlatformTheme::MenuFont] = menuFont;
737 resources.fonts[QPlatformTheme::MenuBarFont] = new QFont(*menuFont);
738 }
739
740 if (QFont *toolBarFont = kdeFont(readKdeSetting(QStringLiteral("toolBarFont"), kdeDirs, kdeVersion, kdeSettings)))
741 resources.fonts[QPlatformTheme::ToolButtonFont] = toolBarFont;
742
744
745 qCDebug(lcQpaFonts) << "default fonts: system" << resources.fonts[QPlatformTheme::SystemFont]
746 << "fixed" << resources.fonts[QPlatformTheme::FixedFont];
747 qDeleteAll(kdeSettings);
748}
749
750QVariant QKdeThemePrivate::readKdeSetting(const QString &key, const QStringList &kdeDirs, int kdeVersion, QHash<QString, QSettings*> &kdeSettings)
751{
752 for (const QString &kdeDir : kdeDirs) {
753 QSettings *settings = kdeSettings.value(kdeDir);
754 if (!settings) {
755 const QString kdeGlobalsPath = kdeGlobals(kdeDir, kdeVersion);
756 if (QFileInfo(kdeGlobalsPath).isReadable()) {
757 settings = new QSettings(kdeGlobalsPath, QSettings::IniFormat);
758 kdeSettings.insert(kdeDir, settings);
759 }
760 }
761 if (settings) {
762 const QVariant value = settings->value(key);
763 if (value.isValid())
764 return value;
765 }
766 }
767 return QVariant();
768}
769
770// Reads the color from the KDE configuration, and store it in the
771// palette with the given color role if found.
772static inline bool kdeColor(QPalette *pal, QPalette::ColorRole role, const QVariant &value)
773{
774 if (!value.isValid())
775 return false;
776 const QStringList values = value.toStringList();
777 if (values.size() != 3)
778 return false;
779 pal->setBrush(role, QColor(values.at(0).toInt(), values.at(1).toInt(), values.at(2).toInt()));
780 return true;
781}
782
783void QKdeThemePrivate::readKdeSystemPalette(const QStringList &kdeDirs, int kdeVersion, QHash<QString, QSettings*> &kdeSettings, QPalette *pal)
784{
785 if (!kdeColor(pal, QPalette::Button, readKdeSetting(QStringLiteral("Colors:Button/BackgroundNormal"), kdeDirs, kdeVersion, kdeSettings))) {
786 // kcolorscheme.cpp: SetDefaultColors
787 const QColor defaultWindowBackground(214, 210, 208);
788 const QColor defaultButtonBackground(223, 220, 217);
789 *pal = QPalette(defaultButtonBackground, defaultWindowBackground);
790 return;
791 }
792
793 kdeColor(pal, QPalette::Window, readKdeSetting(QStringLiteral("Colors:Window/BackgroundNormal"), kdeDirs, kdeVersion, kdeSettings));
794 kdeColor(pal, QPalette::Text, readKdeSetting(QStringLiteral("Colors:View/ForegroundNormal"), kdeDirs, kdeVersion, kdeSettings));
795 kdeColor(pal, QPalette::WindowText, readKdeSetting(QStringLiteral("Colors:Window/ForegroundNormal"), kdeDirs, kdeVersion, kdeSettings));
796 kdeColor(pal, QPalette::Base, readKdeSetting(QStringLiteral("Colors:View/BackgroundNormal"), kdeDirs, kdeVersion, kdeSettings));
797 kdeColor(pal, QPalette::Highlight, readKdeSetting(QStringLiteral("Colors:Selection/BackgroundNormal"), kdeDirs, kdeVersion, kdeSettings));
798 kdeColor(pal, QPalette::HighlightedText, readKdeSetting(QStringLiteral("Colors:Selection/ForegroundNormal"), kdeDirs, kdeVersion, kdeSettings));
799 kdeColor(pal, QPalette::AlternateBase, readKdeSetting(QStringLiteral("Colors:View/BackgroundAlternate"), kdeDirs, kdeVersion, kdeSettings));
800 kdeColor(pal, QPalette::ButtonText, readKdeSetting(QStringLiteral("Colors:Button/ForegroundNormal"), kdeDirs, kdeVersion, kdeSettings));
801 kdeColor(pal, QPalette::Link, readKdeSetting(QStringLiteral("Colors:View/ForegroundLink"), kdeDirs, kdeVersion, kdeSettings));
802 kdeColor(pal, QPalette::LinkVisited, readKdeSetting(QStringLiteral("Colors:View/ForegroundVisited"), kdeDirs, kdeVersion, kdeSettings));
803 kdeColor(pal, QPalette::ToolTipBase, readKdeSetting(QStringLiteral("Colors:Tooltip/BackgroundNormal"), kdeDirs, kdeVersion, kdeSettings));
804 kdeColor(pal, QPalette::ToolTipText, readKdeSetting(QStringLiteral("Colors:Tooltip/ForegroundNormal"), kdeDirs, kdeVersion, kdeSettings));
805
806 // The above code sets _all_ color roles to "normal" colors. In KDE, the disabled
807 // color roles are calculated by applying various effects described in kdeglobals.
808 // We use a bit simpler approach here, similar logic than in qt_palette_from_color().
809 const QColor button = pal->color(QPalette::Button);
810 int h, s, v;
811 button.getHsv(&h, &s, &v);
812
813 const QBrush whiteBrush = QBrush(Qt::white);
814 const QBrush buttonBrush = QBrush(button);
815 const QBrush buttonBrushDark = QBrush(button.darker(v > 128 ? 200 : 50));
816 const QBrush buttonBrushDark150 = QBrush(button.darker(v > 128 ? 150 : 75));
817 const QBrush buttonBrushLight150 = QBrush(button.lighter(v > 128 ? 150 : 75));
818 const QBrush buttonBrushLight = QBrush(button.lighter(v > 128 ? 200 : 50));
819
820 pal->setBrush(QPalette::Disabled, QPalette::WindowText, buttonBrushDark);
821 pal->setBrush(QPalette::Disabled, QPalette::ButtonText, buttonBrushDark);
822 pal->setBrush(QPalette::Disabled, QPalette::Button, buttonBrush);
823 pal->setBrush(QPalette::Disabled, QPalette::Text, buttonBrushDark);
825 pal->setBrush(QPalette::Disabled, QPalette::Base, buttonBrush);
826 pal->setBrush(QPalette::Disabled, QPalette::Window, buttonBrush);
827 pal->setBrush(QPalette::Disabled, QPalette::Highlight, buttonBrushDark150);
828 pal->setBrush(QPalette::Disabled, QPalette::HighlightedText, buttonBrushLight150);
829
830 // set calculated colors for all groups
831 pal->setBrush(QPalette::Light, buttonBrushLight);
832 pal->setBrush(QPalette::Midlight, buttonBrushLight150);
833 pal->setBrush(QPalette::Mid, buttonBrushDark150);
834 pal->setBrush(QPalette::Dark, buttonBrushDark);
835}
836
845const char *QKdeTheme::name = "kde";
846
847QKdeTheme::QKdeTheme(const QStringList& kdeDirs, int kdeVersion)
848 : QPlatformTheme(new QKdeThemePrivate(kdeDirs,kdeVersion))
849{
850 d_func()->refresh();
851}
852
853QFont *QKdeThemePrivate::kdeFont(const QVariant &fontValue)
854{
855 if (fontValue.isValid()) {
856 // Read font value: Might be a QStringList as KDE stores fonts without quotes.
857 // Also retrieve the family for the constructor since we cannot use the
858 // default constructor of QFont, which accesses QGuiApplication::systemFont()
859 // causing recursion.
860 QString fontDescription;
861 QString fontFamily;
862 if (fontValue.userType() == QMetaType::QStringList) {
863 const QStringList list = fontValue.toStringList();
864 if (!list.isEmpty()) {
865 fontFamily = list.first();
866 fontDescription = list.join(u',');
867 }
868 } else {
869 fontDescription = fontFamily = fontValue.toString();
870 }
871 if (!fontDescription.isEmpty()) {
872 QFont font(fontFamily);
873 if (font.fromString(fontDescription))
874 return new QFont(font);
875 }
876 }
877 return nullptr;
878}
879
880
881QStringList QKdeThemePrivate::kdeIconThemeSearchPaths(const QStringList &kdeDirs)
882{
884 const QString iconPath = QStringLiteral("/share/icons");
885 for (const QString &candidate : kdeDirs) {
886 const QFileInfo fi(candidate + iconPath);
887 if (fi.isDir())
888 paths.append(fi.absoluteFilePath());
889 }
890 return paths;
891}
892
893QVariant QKdeTheme::themeHint(QPlatformTheme::ThemeHint hint) const
894{
895 Q_D(const QKdeTheme);
896 switch (hint) {
898 return QVariant(true);
900 return QVariant(d->showIconsOnPushButtons);
904 return QVariant(d->toolButtonStyle);
906 return QVariant(d->toolBarIconSize);
908 return QVariant(d->iconThemeName);
910 return QVariant(d->iconFallbackThemeName);
912 return QVariant(d->kdeIconThemeSearchPaths(d->kdeDirs));
916 return QVariant(d->styleNames);
918 return QVariant(int(KdeKeyboardScheme));
920 return QVariant(d->singleClick);
922 return QVariant(d->wheelScrollLines);
924 return QVariant(d->doubleClickInterval);
926 return QVariant(d->startDragTime);
928 return QVariant(d->startDragDist);
930 return QVariant(d->cursorBlinkRate);
932 return QVariant(int(HoverEffect));
934 return QVariant(mouseCursorTheme());
936 return QVariant(mouseCursorSize());
937 default:
938 break;
939 }
941}
942
943QIcon QKdeTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions) const
944{
945#if QT_CONFIG(mimetype)
946 return xdgFileIcon(fileInfo);
947#else
948 Q_UNUSED(fileInfo);
949 return QIcon();
950#endif
951}
952
953Qt::ColorScheme QKdeTheme::colorScheme() const
954{
955 return d_func()->m_colorScheme;
956}
957
969void QKdeThemePrivate::updateColorScheme(const QString &themeName)
970{
971 if (themeName.contains(QLatin1StringView("light"), Qt::CaseInsensitive)) {
972 m_colorScheme = Qt::ColorScheme::Light;
973 return;
974 }
975 if (themeName.contains(QLatin1StringView("dark"), Qt::CaseInsensitive)) {
976 m_colorScheme = Qt::ColorScheme::Dark;
977 return;
978 }
979
980 if (systemPalette) {
981 if (systemPalette->text().color().lightness() < systemPalette->base().color().lightness()) {
982 m_colorScheme = Qt::ColorScheme::Light;
983 return;
984 }
985 if (systemPalette->text().color().lightness() > systemPalette->base().color().lightness()) {
986 m_colorScheme = Qt::ColorScheme::Dark;
987 return;
988 }
989 }
990
991 m_colorScheme = Qt::ColorScheme::Unknown;
992}
993
994
995const QPalette *QKdeTheme::palette(Palette type) const
996{
997 Q_D(const QKdeTheme);
998 return d->resources.palettes[type];
999}
1000
1001const QFont *QKdeTheme::font(Font type) const
1002{
1003 Q_D(const QKdeTheme);
1004 return d->resources.fonts[type];
1005}
1006
1007QPlatformTheme *QKdeTheme::createKdeTheme()
1008{
1009 const QByteArray kdeVersionBA = qgetenv("KDE_SESSION_VERSION");
1010 const int kdeVersion = kdeVersionBA.toInt();
1011 if (kdeVersion < 4)
1012 return nullptr;
1013
1014 if (kdeVersion > 4)
1015 // Plasma 5 follows XDG spec
1016 // but uses the same config file format:
1018
1019 // Determine KDE prefixes in the following priority order:
1020 // - KDEHOME and KDEDIRS environment variables
1021 // - ~/.kde(<version>)
1022 // - read prefixes from /etc/kde<version>rc
1023 // - fallback to /etc/kde<version>
1024
1025 QStringList kdeDirs;
1026 const QString kdeHomePathVar = QFile::decodeName(qgetenv("KDEHOME"));
1027 if (!kdeHomePathVar.isEmpty())
1028 kdeDirs += kdeHomePathVar;
1029
1030 const QString kdeDirsVar = QFile::decodeName(qgetenv("KDEDIRS"));
1031 if (!kdeDirsVar.isEmpty())
1032 kdeDirs += kdeDirsVar.split(u':', Qt::SkipEmptyParts);
1033
1034 const QString kdeVersionHomePath = QDir::homePath() + "/.kde"_L1 + QLatin1StringView(kdeVersionBA);
1035 if (QFileInfo(kdeVersionHomePath).isDir())
1036 kdeDirs += kdeVersionHomePath;
1037
1038 const QString kdeHomePath = QDir::homePath() + "/.kde"_L1;
1039 if (QFileInfo(kdeHomePath).isDir())
1040 kdeDirs += kdeHomePath;
1041
1042 const QString kdeRcPath = "/etc/kde"_L1 + QLatin1StringView(kdeVersionBA) + "rc"_L1;
1043 if (QFileInfo(kdeRcPath).isReadable()) {
1044 QSettings kdeSettings(kdeRcPath, QSettings::IniFormat);
1045 kdeSettings.beginGroup(QStringLiteral("Directories-default"));
1046 kdeDirs += kdeSettings.value(QStringLiteral("prefixes")).toStringList();
1047 }
1048
1049 const QString kdeVersionPrefix = "/etc/kde"_L1 + QLatin1StringView(kdeVersionBA);
1050 if (QFileInfo(kdeVersionPrefix).isDir())
1051 kdeDirs += kdeVersionPrefix;
1052
1053 kdeDirs.removeDuplicates();
1054 if (kdeDirs.isEmpty()) {
1055 qWarning("Unable to determine KDE dirs");
1056 return nullptr;
1057 }
1058
1059 return new QKdeTheme(kdeDirs, kdeVersion);
1060}
1061
1062#ifndef QT_NO_DBUS
1063QPlatformMenuBar *QKdeTheme::createPlatformMenuBar() const
1064{
1066 return new QDBusMenuBar();
1067 return nullptr;
1068}
1069#endif
1070
1071#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON)
1072QPlatformSystemTrayIcon *QKdeTheme::createPlatformSystemTrayIcon() const
1073{
1074 if (isDBusTrayAvailable())
1075 return new QDBusTrayIcon();
1076 return nullptr;
1077}
1078#endif
1079
1080#endif // settings
1081
1090const char *QGnomeTheme::name = "gnome";
1091
1093{
1094public:
1097
1098 void configureFonts(const QString &gtkFontName) const
1099 {
1100 Q_ASSERT(!systemFont);
1101 const int split = gtkFontName.lastIndexOf(QChar::Space);
1102 float size = QStringView{gtkFontName}.mid(split + 1).toFloat();
1103 QString fontName = gtkFontName.left(split);
1104
1105 systemFont = new QFont(fontName, size);
1106 fixedFont = new QFont(QLatin1StringView(defaultFixedFontNameC), systemFont->pointSize());
1107 fixedFont->setStyleHint(QFont::TypeWriter);
1108 qCDebug(lcQpaFonts) << "default fonts: system" << systemFont << "fixed" << fixedFont;
1109 }
1110
1111 mutable QFont *systemFont = nullptr;
1112 mutable QFont *fixedFont = nullptr;
1113
1114#ifndef QT_NO_DBUS
1116private:
1117 std::unique_ptr<QGenericUnixThemeDBusListener> dbus;
1118 bool initDbus();
1119 void updateColorScheme(const QString &themeName);
1120#endif // QT_NO_DBUS
1121};
1122
1124{
1125#ifndef QT_NO_DBUS
1126 initDbus();
1127#endif // QT_NO_DBUS
1128}
1130{
1131 if (systemFont)
1132 delete systemFont;
1133 if (fixedFont)
1134 delete fixedFont;
1135}
1136
1137#ifndef QT_NO_DBUS
1138bool QGnomeThemePrivate::initDbus()
1139{
1141 Q_ASSERT(dbus);
1142
1143 // Wrap slot in a lambda to avoid inheriting QGnomeThemePrivate from QObject
1144 auto wrapper = [this](QGenericUnixThemeDBusListener::Provider provider,
1146 const QString &value) {
1149 return;
1150 }
1151
1153 updateColorScheme(value);
1154 };
1155
1157}
1158
1159void QGnomeThemePrivate::updateColorScheme(const QString &themeName)
1160{
1161 const auto oldColorScheme = m_colorScheme;
1162 if (themeName.contains(QLatin1StringView("light"), Qt::CaseInsensitive)) {
1163 m_colorScheme = Qt::ColorScheme::Light;
1164 } else if (themeName.contains(QLatin1StringView("dark"), Qt::CaseInsensitive)) {
1165 m_colorScheme = Qt::ColorScheme::Dark;
1166 } else {
1167 m_colorScheme = Qt::ColorScheme::Unknown;
1168 }
1169
1170 if (oldColorScheme != m_colorScheme)
1172}
1173#endif // QT_NO_DBUS
1174
1179
1181{
1182 switch (hint) {
1184 return QVariant(true);
1188 return QVariant(QStringLiteral("Adwaita"));
1190 return QVariant(QStringLiteral("gnome"));
1197 styleNames << QStringLiteral("Fusion") << QStringLiteral("windows");
1198 return QVariant(styleNames);
1199 }
1201 return QVariant(int(GnomeKeyboardScheme));
1203 return QVariant(QChar(0x2022));
1205 return QVariant(int(HoverEffect));
1207 return QVariant::fromValue(
1210 return true;
1212 return QVariant(mouseCursorTheme());
1214 return QVariant(mouseCursorSize());
1215 default:
1216 break;
1217 }
1219}
1220
1221QIcon QGnomeTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions) const
1222{
1223#if QT_CONFIG(mimetype)
1224 return xdgFileIcon(fileInfo);
1225#else
1226 Q_UNUSED(fileInfo);
1227 return QIcon();
1228#endif
1229}
1230
1232{
1233 Q_D(const QGnomeTheme);
1234 if (!d->systemFont)
1235 d->configureFonts(gtkFontName());
1236 switch (type) {
1238 return d->systemFont;
1240 return d->fixedFont;
1241 default:
1242 return nullptr;
1243 }
1244}
1245
1250
1251#ifndef QT_NO_DBUS
1253{
1255 return new QDBusMenuBar();
1256 return nullptr;
1257}
1258
1260{
1261 return d_func()->m_colorScheme;
1262}
1263
1264#endif
1265
1266#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON)
1268{
1269 if (isDBusTrayAvailable())
1270 return new QDBusTrayIcon();
1271 return nullptr;
1272}
1273#endif
1274
1276{
1277 switch (button) {
1279 return QCoreApplication::translate("QGnomeTheme", "&OK");
1281 return QCoreApplication::translate("QGnomeTheme", "&Save");
1283 return QCoreApplication::translate("QGnomeTheme", "&Cancel");
1285 return QCoreApplication::translate("QGnomeTheme", "&Close");
1287 return QCoreApplication::translate("QGnomeTheme", "Close without Saving");
1288 default:
1289 break;
1290 }
1292}
1293
1299{
1301 return new QGenericUnixTheme;
1302#if QT_CONFIG(settings)
1303 if (name == QLatin1StringView(QKdeTheme::name))
1304 if (QPlatformTheme *kdeTheme = QKdeTheme::createKdeTheme())
1305 return kdeTheme;
1306#endif
1308 return new QGnomeTheme;
1309 return nullptr;
1310}
1311
1313{
1316 const QByteArray desktopEnvironment = QGuiApplicationPrivate::platformIntegration()->services()->desktopEnvironment();
1317 QList<QByteArray> gtkBasedEnvironments;
1318 gtkBasedEnvironments << "GNOME"
1319 << "X-CINNAMON"
1320 << "UNITY"
1321 << "MATE"
1322 << "XFCE"
1323 << "LXDE";
1324 const QList<QByteArray> desktopNames = desktopEnvironment.split(':');
1325 for (const QByteArray &desktopName : desktopNames) {
1326 if (desktopEnvironment == "KDE") {
1327#if QT_CONFIG(settings)
1328 result.push_back(QLatin1StringView(QKdeTheme::name));
1329#endif
1330 } else if (gtkBasedEnvironments.contains(desktopName)) {
1331 // prefer the GTK3 theme implementation with native dialogs etc.
1332 result.push_back(QStringLiteral("gtk3"));
1333 // fallback to the generic Gnome theme if loading the GTK3 theme fails
1335 } else {
1336 // unknown, but lowercase the name (our standard practice) and
1337 // remove any "x-" prefix
1338 QString s = QString::fromLatin1(desktopName.toLower());
1339 result.push_back(s.startsWith("x-"_L1) ? s.mid(2) : s);
1340 }
1341 }
1342 } // desktopSettingsAware
1344 return result;
1345}
1346
1348
1349#ifndef QT_NO_DBUS
1350#include "qgenericunixthemes.moc"
1351#endif // QT_NO_DBUS
\inmodule QtGui
Definition qbrush.h:30
const QColor & color() const
Returns the brush color.
Definition qbrush.h:121
\inmodule QtCore
Definition qbytearray.h:57
QList< QByteArray > split(char sep) const
Splits the byte array into subarrays wherever sep occurs, and returns the list of those arrays.
\inmodule QtCore
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
int lightness() const noexcept
Definition qcolor.cpp:1860
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
\threadsafe
\inmodule QtDBus
static QDBusConnection sessionBus()
Returns a QDBusConnection object opened with the session bus.
\inmodule QtDBus
static QString homePath()
Returns the absolute path of the user's home directory.
Definition qdir.cpp:2103
void close() override
Calls QFileDevice::flush() and closes the file.
\inmodule QtCore
Definition qfile.h:93
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:904
static QString decodeName(const QByteArray &localFileName)
This does the reverse of QFile::encodeName() using localFileName.
Definition qfile.h:162
bool exists() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qfile.cpp:351
bool isEmpty() const noexcept
Definition qflatmap_p.h:579
size_type count() const noexcept
Definition qflatmap_p.h:576
bool contains(const Key &key) const
Definition qflatmap_p.h:625
const_iterator constBegin() const
Definition qflatmap_p.h:772
const_iterator constEnd() const
Definition qflatmap_p.h:776
std::pair< iterator, bool > insert(const Key &key, const T &value)
Definition qflatmap_p.h:678
T value(const Key &key, const T &defaultValue) const
Definition qflatmap_p.h:636
void clear()
Definition qflatmap_p.h:591
\reentrant
Definition qfont.h:22
@ TypeWriter
Definition qfont.h:28
bool fromString(const QString &)
Sets this font to match the description descrip.
Definition qfont.cpp:2190
void setStyleHint(StyleHint, StyleStrategy=PreferDefault)
Sets the style hint and strategy to hint and strategy, respectively.
Definition qfont.cpp:1505
void settingChanged(QGenericUnixThemeDBusListener::Provider provider, QGenericUnixThemeDBusListener::Setting setting, const QString &value)
static const char * name
QVariant themeHint(ThemeHint hint) const override
static QStringList iconFallbackPaths()
const QFont * font(Font type) const override
QPlatformMenuBar * createPlatformMenuBar() const override
static QPlatformTheme * createUnixTheme(const QString &name)
Creates a UNIX theme according to the detected desktop environment.
QPlatformSystemTrayIcon * createPlatformSystemTrayIcon() const override
Factory function for QSystemTrayIcon.
static QStringList xdgIconThemePaths()
static QStringList themeNames()
void configureFonts(const QString &gtkFontName) const
QGnomeTheme is a theme implementation for the Gnome desktop.
QPlatformMenuBar * createPlatformMenuBar() const override
virtual QString gtkFontName() const
QVariant themeHint(ThemeHint hint) const override
QPlatformSystemTrayIcon * createPlatformSystemTrayIcon() const override
Factory function for QSystemTrayIcon.
QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions={ }) const override
Return an icon for fileInfo, observing iconOptions.
Qt::ColorScheme colorScheme() const override
QString standardButtonText(int button) const override
Returns the text of a standard button.
static const char * name
const QFont * font(Font type) const override
static QPlatformIntegration * platformIntegration()
static bool desktopSettingsAware()
Returns true if Qt is set to use the system's standard colors, fonts, etc.; otherwise returns false.
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
The QIcon class provides scalable icons in different modes and states.
Definition qicon.h:20
bool isNull() const
Returns true if the icon is empty; otherwise returns false.
Definition qicon.cpp:1019
static QIcon fromTheme(const QString &name)
Definition qicon.cpp:1344
\inmodule QtCore\reentrant
Definition qjsonarray.h:18
const_iterator constBegin() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item in the array.
Definition qjsonarray.h:258
const_iterator constEnd() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
Definition qjsonarray.h:262
qsizetype count() const
Same as size().
Definition qjsonarray.h:42
void append(const QJsonValue &value)
Inserts value at the end of the array.
\inmodule QtCore\reentrant
QByteArray toJson(JsonFormat format=Indented) const
QJsonObject object() const
Returns the QJsonObject contained in the document.
bool isObject() const
Returns true if the document contains an object.
static QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error=nullptr)
Parses json as a UTF-8 encoded JSON document, and creates a QJsonDocument from it.
\inmodule QtCore\reentrant
Definition qjsonobject.h:20
bool contains(const QString &key) const
Returns true if the object contains key key.
bool isEmpty() const noexcept
Definition qlist.h:401
T & first()
Definition qlist.h:645
void push_back(parameter_type t)
Definition qlist.h:675
\inmodule QtCore
\inmodule QtCore
Definition qmimetype.h:25
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
The QPalette class contains color groups for each widget state.
Definition qpalette.h:19
const QBrush & text() const
Returns the text foreground brush of the current color group.
Definition qpalette.h:88
const QColor & color(ColorGroup cg, ColorRole cr) const
Returns the color in the specified color group, used for the given color role.
Definition qpalette.h:67
void setBrush(ColorRole cr, const QBrush &brush)
Sets the brush for the given color role to the specified brush for all groups in the palette.
Definition qpalette.h:151
@ Disabled
Definition qpalette.h:49
const QBrush & base() const
Returns the base brush of the current color group.
Definition qpalette.h:89
@ HighlightedText
Definition qpalette.h:53
@ ToolTipBase
Definition qpalette.h:57
@ BrightText
Definition qpalette.h:52
@ AlternateBase
Definition qpalette.h:55
@ ButtonText
Definition qpalette.h:52
@ WindowText
Definition qpalette.h:51
@ Highlight
Definition qpalette.h:53
@ ToolTipText
Definition qpalette.h:57
@ Midlight
Definition qpalette.h:51
@ LinkVisited
Definition qpalette.h:54
The QPlatformTheme class allows customizing the UI based on themes.
virtual QVariant themeHint(ThemeHint hint) const
virtual QString standardButtonText(int button) const
Returns the text of a standard button.
ThemeHint
This enum describes the available theme hints.
@ DialogButtonBoxButtonsHaveIcons
@ ItemViewActivateItemOnSingleClick
\inmodule QtCore
Definition qsettings.h:30
QVariant value(QAnyStringView key, const QVariant &defaultValue) const
Returns the value for setting key.
\inmodule QtCore
Definition qsize.h:25
static QStringList locateAll(StandardLocation type, const QString &fileName, LocateOptions options=LocateFile)
[0]
static QStringList standardLocations(StandardLocation type)
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString left(qsizetype n) const &
Definition qstring.h:363
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.h:296
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
QString mid(qsizetype position, qsizetype n=-1) const &
Definition qstring.cpp:5300
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
float toFloat(bool *ok=nullptr) const
Returns the string converted to a float value.
Definition qstring.cpp:7950
\inmodule QtCore
Definition qvariant.h:65
bool isValid() const
Returns true if the storage type of this variant is not QMetaType::UnknownType; otherwise returns fal...
Definition qvariant.h:714
QString toString() const
Returns the variant as a QString if the variant has a userType() including, but not limited to:
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
static void handleThemeChange(QWindow *window=nullptr)
QPalette * palettes[QPlatformTheme::NPalettes]
QFont * fonts[QPlatformTheme::NFonts]
QPushButton * button
[2]
qDeleteAll(list.begin(), list.end())
QSet< QString >::iterator it
auto signal
Combined button and popup list for selecting options.
ColorScheme
Definition qnamespace.h:50
@ white
Definition qnamespace.h:31
@ Key_Select
@ Key_Return
Definition qnamespace.h:667
@ Key_Enter
Definition qnamespace.h:668
@ Key_Space
Definition qnamespace.h:513
@ CaseInsensitive
@ SkipEmptyParts
Definition qnamespace.h:128
@ ToolButtonTextOnly
@ ToolButtonTextUnderIcon
@ ToolButtonTextBesideIcon
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char * interface
DBusConnection const char DBusError * error
DBusConnection * connection
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
const char * mimeType
@ defaultSystemFontSize
#define LOG
static bool isDBusGlobalMenuAvailable()
#define CHECK(cond, warning)
static const char defaultFixedFontNameC[]
static const char defaultSystemFontNameC[]
static QString mouseCursorTheme()
static bool isDBusTrayAvailable()
static QList< QSize > availableXdgFileIconSizes()
#define PARSE(var, enumeration, string)
static bool checkDBusGlobalMenuAvailable()
static QSize mouseCursorSize()
#define qDebug
[1]
Definition qlogging.h:164
#define qWarning
Definition qlogging.h:166
#define Q_LOGGING_CATEGORY(name,...)
#define qCInfo(category,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
return ret
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
#define SLOT(a)
Definition qobjectdefs.h:52
static QString themeName()
GLint location
GLenum GLsizei GLsizei GLint * values
[15]
GLsizei const GLfloat * v
[13]
GLuint64 key
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLenum GLsizei count
GLenum type
GLsizei const GLuint * paths
GLenum const void * fontName
GLuint name
GLfloat GLfloat GLfloat GLfloat h
GLhandleARB obj
[2]
GLdouble s
[6]
Definition qopenglext.h:235
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static void split(QT_FT_Vector *b)
#define QStringLiteral(str)
static QT_BEGIN_NAMESPACE QVariant hint(QPlatformIntegration::StyleHint h)
QString qEnvironmentVariable(const char *varName, const QString &defaultValue)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
return device isReadable() ? device -> read(static_cast< char * >(buf), size) :-1
#define Q_ENUM(x)
#define Q_OBJECT
#define Q_SLOTS
#define Q_SIGNALS
#define emit
#define Q_UNUSED(x)
static QStringList styleNames()
QList< int > list
[14]
QFile file
[0]
QSettings settings("MySoft", "Star Runner")
[0]
QSharedPointer< T > other(t)
[5]
void dbus()
[0-0]
\inmodule QtCore\reentrant
void wrapper()