diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d8aeaecf9d09fef34ec962e6a80cb7b4f8b2ae7..0d88aeb7727487ec7ba0121838e51e962d7d8fd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,10 @@ add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060200 -DUSE_WIDGETS -DQT_DEPRE add_compile_options(-Wall -Wextra) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) -find_package(Qt6 6.2 CONFIG REQUIRED COMPONENTS BuildInternals Core Widgets OPTIONAL_COMPONENTS LinguistTools) +find_package(Qt6 6.2 CONFIG REQUIRED COMPONENTS BuildInternals Core Widgets OPTIONAL_COMPONENTS QuickControls2 LinguistTools) +find_package(KF6Config) +find_package(KF6ColorScheme) +find_package(KF6IconThemes) get_target_property(QT_QTPATHS_EXECUTABLE Qt6::qtpaths IMPORTED_LOCATION) diff --git a/src/qt6ct-common/CMakeLists.txt b/src/qt6ct-common/CMakeLists.txt index 3b9f0b9ce3067eeb38f219c586eec6d58a837b04..2afce8d4c9e1b22e09adc295880df7b4cbb076ae 100644 --- a/src/qt6ct-common/CMakeLists.txt +++ b/src/qt6ct-common/CMakeLists.txt @@ -24,5 +24,6 @@ set(app_SRCS add_library(qt6ct-common SHARED ${app_SRCS}) set_target_properties(qt6ct-common PROPERTIES VERSION ${QT6CT_VERSION}) -target_link_libraries(qt6ct-common PRIVATE Qt6::Gui) +target_link_libraries(qt6ct-common PRIVATE Qt6::Gui $<TARGET_NAME_IF_EXISTS:KF6::ConfigCore> $<TARGET_NAME_IF_EXISTS:KF6::ColorScheme>) +target_compile_definitions(qt6ct-common PRIVATE $<$<TARGET_EXISTS:KF6::ConfigCore>:KF_CONFIGCORE_LIB> $<$<TARGET_EXISTS:KF6::ColorScheme>:KF_COLORSCHEME_LIB>) install(TARGETS qt6ct-common DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/src/qt6ct-common/qt6ct.cpp b/src/qt6ct-common/qt6ct.cpp index 616440b8acf57ef8d62cd44f91524a896ceb7d94..896895da7da04e4cd8abba9df3d4a2bd98d6c8e1 100644 --- a/src/qt6ct-common/qt6ct.cpp +++ b/src/qt6ct-common/qt6ct.cpp @@ -34,6 +34,10 @@ #include <QFile> #include <QSettings> #include <QtDebug> +#if defined KF_CONFIGCORE_LIB && defined KF_COLORSCHEME_LIB +#include <KSharedConfig> +#include <KColorScheme> +#endif #include "qt6ct.h" #ifndef QT6CT_DATADIR @@ -121,6 +125,9 @@ QStringList Qt6CT::sharedColorSchemePaths() for(const QString &p : QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation)) { paths << (p + QStringLiteral("/qt6ct/colors")); +#if defined KF_CONFIGCORE_LIB && defined KF_COLORSCHEME_LIB + paths << (p + QStringLiteral("/color-schemes")); +#endif } paths << QStringLiteral(QT6CT_DATADIR"/qt6ct/colors"); paths.removeDuplicates(); @@ -148,8 +155,18 @@ QString Qt6CT::resolvePath(const QString &path) return tmp; } +bool Qt6CT::isKColorScheme(const QString &filePath) +{ + return filePath.toLower().endsWith(".colors"); +} + QPalette Qt6CT::loadColorScheme(const QString &filePath, const QPalette &fallback) { +#if defined KF_CONFIGCORE_LIB && defined KF_COLORSCHEME_LIB + if(isKColorScheme(filePath)) + return KColorScheme::createApplicationPalette(KSharedConfig::openConfig(filePath)); +#endif + QPalette customPalette; QSettings settings(filePath, QSettings::IniFormat); settings.beginGroup("ColorScheme"_L1); diff --git a/src/qt6ct-common/qt6ct.h b/src/qt6ct-common/qt6ct.h index f2539879f016f72d51cac27cebc956aefcaa2d92..7d6b28375c530a209aaecf978b8c7ea729e4dfb8 100644 --- a/src/qt6ct-common/qt6ct.h +++ b/src/qt6ct-common/qt6ct.h @@ -101,6 +101,7 @@ public: static QString styleColorSchemeFile(); static QStringList sharedColorSchemePaths(); static QString resolvePath(const QString &path); + static bool isKColorScheme(const QString &filePath); static QPalette loadColorScheme(const QString &filePath, const QPalette &fallback); static void registerStyleInstance(StyleInstance *instance); diff --git a/src/qt6ct-qtplugin/CMakeLists.txt b/src/qt6ct-qtplugin/CMakeLists.txt index 93a2b84b99819abc6eeae65d766c0f9190901988..e5366ef13b2927c4839971d182e0e2f59455fe4e 100644 --- a/src/qt6ct-qtplugin/CMakeLists.txt +++ b/src/qt6ct-qtplugin/CMakeLists.txt @@ -7,5 +7,6 @@ set(app_SRCS add_library(qt6ct-qtplugin MODULE ${app_SRCS}) set_target_properties(qt6ct-qtplugin PROPERTIES OUTPUT_NAME qt6ct) -target_link_libraries(qt6ct-qtplugin PRIVATE Qt6::Widgets Qt6::GuiPrivate qt6ct-common) +target_link_libraries(qt6ct-qtplugin PRIVATE Qt6::Widgets Qt6::GuiPrivate $<TARGET_NAME_IF_EXISTS:Qt6::QuickControls2> $<TARGET_NAME_IF_EXISTS:KF6::IconThemes> qt6ct-common) +target_compile_definitions(qt6ct-qtplugin PRIVATE $<$<TARGET_EXISTS:KF6::IconThemes>:KF_ICONTHEMES_LIB>) install(TARGETS qt6ct-qtplugin DESTINATION ${PLUGINDIR}/platformthemes) diff --git a/src/qt6ct-qtplugin/qt6ctplatformtheme.cpp b/src/qt6ct-qtplugin/qt6ctplatformtheme.cpp index b90c801c6d18874266d5482c6851298367a011e6..cfcc9ecc355caeb38ed1168d8e1f1649d6429d11 100644 --- a/src/qt6ct-qtplugin/qt6ctplatformtheme.cpp +++ b/src/qt6ct-qtplugin/qt6ctplatformtheme.cpp @@ -44,6 +44,9 @@ #endif #include <QFile> #include <QFileSystemWatcher> +#ifdef QT_QUICKCONTROLS2_LIB +#include <QQuickStyle> +#endif #include <private/qiconloader_p.h> #include "qt6ct.h" @@ -52,6 +55,11 @@ #include <QStringList> #include <qpa/qplatformthemefactory_p.h> +#ifdef KF_ICONTHEMES_LIB +#include <KIconEngine> +#include <KIconLoader> +#endif + Q_LOGGING_CATEGORY(lqt6ct, "qt6ct", QtWarningMsg) //QT_QPA_PLATFORMTHEME=qt6ct @@ -67,12 +75,22 @@ Qt6CTPlatformTheme::Qt6CTPlatformTheme() QMetaObject::invokeMethod(this, &Qt6CTPlatformTheme::createFSWatcher, Qt::QueuedConnection); #endif QGuiApplication::setFont(m_generalFont); + //must be applied before Q_COREAPP_STARTUP_FUNCTION execution + if(Qt6CT::isKColorScheme(m_schemePath)) + qApp->setProperty("KDE_COLOR_SCHEME_PATH", m_schemePath); +#if defined QT_WIDGETS_LIB && defined QT_QUICKCONTROLS2_LIB + if(hasWidgets()) + //don't override the value explicitly set by the user + if(QQuickStyle::name().isEmpty() || QQuickStyle::name() == QLatin1String("Fusion")) + QQuickStyle::setStyle(QLatin1String("org.kde.desktop")); +#endif } qCDebug(lqt6ct) << "using qt6ct plugin"; #ifdef QT_WIDGETS_LIB if(!QStyleFactory::keys().contains(u"qt6ct-style"_s)) qCCritical(lqt6ct) << "unable to find qt6ct proxy style"; #endif + QCoreApplication::instance()->installEventFilter(this); } Qt6CTPlatformTheme::~Qt6CTPlatformTheme() @@ -148,6 +166,13 @@ QIcon Qt6CTPlatformTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::Ic return QIcon::fromTheme(type.iconName()); } +#ifdef KF_ICONTHEMES_LIB +QIconEngine *Qt6CTPlatformTheme::createIconEngine(const QString &iconName) const +{ + return new KIconEngine(iconName, KIconLoader::global()); +} +#endif + void Qt6CTPlatformTheme::applySettings() { if(!QGuiApplication::desktopSettingsAware() || m_isIgnored) @@ -158,6 +183,11 @@ void Qt6CTPlatformTheme::applySettings() QGuiApplication::setFont(m_generalFont); //apply font + if(Qt6CT::isKColorScheme(m_schemePath)) + qApp->setProperty("KDE_COLOR_SCHEME_PATH", m_schemePath); + else if(m_update) + qApp->setProperty("KDE_COLOR_SCHEME_PATH", QVariant()); + #ifdef QT_WIDGETS_LIB if(hasWidgets()) { @@ -234,6 +264,8 @@ void Qt6CTPlatformTheme::updateSettings() void Qt6CTPlatformTheme::readSettings() { + m_schemePath.clear(); + QSettings settings(Qt6CT::configFile(), QSettings::IniFormat); settings.beginGroup("Appearance"_L1); @@ -243,6 +275,7 @@ void Qt6CTPlatformTheme::readSettings() if(!schemePath.isEmpty() && settings.value("custom_palette"_L1, false).toBool()) { schemePath = Qt6CT::resolvePath(schemePath); //replace environment variables + m_schemePath = schemePath; m_palette = Qt6CT::loadColorScheme(schemePath, m_palette); } m_iconTheme = settings.value("icon_theme"_L1).toString(); @@ -352,3 +385,17 @@ QString Qt6CTPlatformTheme::loadStyleSheets(const QStringList &paths) content.replace(regExp, u"\n"_s); return content; } + +//There's such a thing as KColorSchemeManager that lets the user to change the color scheme +//application-wide and we should re-apply the color scheme if KCSM resets it to the default +//which leads KColorScheme to get the color scheme from kdeglobals which won't help us. +bool Qt6CTPlatformTheme::eventFilter(QObject *obj, QEvent *e) +{ + if(obj == qApp && + e->type() == QEvent::DynamicPropertyChange && + static_cast<QDynamicPropertyChangeEvent*>(e)->propertyName() == "KDE_COLOR_SCHEME_PATH" && + qApp->property("KDE_COLOR_SCHEME_PATH").toString().isEmpty() && + Qt6CT::isKColorScheme(m_schemePath)) + applySettings(); + return QObject::eventFilter(obj, e); +} diff --git a/src/qt6ct-qtplugin/qt6ctplatformtheme.h b/src/qt6ct-qtplugin/qt6ctplatformtheme.h index 5312a644fcb797712ccc3a2ec644e62bdf89c351..db66d33ee69d536304c8bca567916cb8f5c99721 100644 --- a/src/qt6ct-qtplugin/qt6ctplatformtheme.h +++ b/src/qt6ct-qtplugin/qt6ctplatformtheme.h @@ -62,10 +62,15 @@ public: //virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, // QPlatformTheme::IconOptions iconOptions = 0) const; - //virtual QIconEngine *createIconEngine(const QString &iconName) const; +#ifdef KF_ICONTHEMES_LIB + virtual QIconEngine *createIconEngine(const QString &iconName) const override; +#endif //virtual QList<QKeySequence> keyBindings(QKeySequence::StandardKey key) const; //virtual QString standardButtonText(int button) const; +protected: + bool eventFilter(QObject *obj, QEvent *e) override; + private slots: void applySettings(); #ifdef QT_WIDGETS_LIB @@ -79,7 +84,7 @@ private: bool hasWidgets(); #endif QString loadStyleSheets(const QStringList &paths); - QString m_style, m_iconTheme, m_userStyleSheet, m_prevStyleSheet; + QString m_style, m_schemePath, m_iconTheme, m_userStyleSheet, m_prevStyleSheet; QPalette m_palette; QFont m_generalFont, m_fixedFont; int m_doubleClickInterval; diff --git a/src/qt6ct/CMakeLists.txt b/src/qt6ct/CMakeLists.txt index fb0e1f7ae89a375420ba7c4027e1cc8fa3687aec..578f3b02f71b9f83584746d35c9bb47480140be2 100644 --- a/src/qt6ct/CMakeLists.txt +++ b/src/qt6ct/CMakeLists.txt @@ -31,6 +31,7 @@ if(Qt6LinguistTools_FOUND) endif() add_executable(qt6ct ${app_SRCS}) -target_link_libraries(qt6ct PRIVATE Qt6::Widgets Qt6::WidgetsPrivate qt6ct-common) +target_link_libraries(qt6ct PRIVATE Qt6::Widgets Qt6::WidgetsPrivate $<TARGET_NAME_IF_EXISTS:KF6::ConfigCore> qt6ct-common) +target_compile_definitions(qt6ct PRIVATE $<$<TARGET_EXISTS:KF6::ConfigCore>:KF_CONFIGCORE_LIB> $<$<TARGET_EXISTS:KF6::ColorScheme>:KF_COLORSCHEME_LIB>) install(TARGETS qt6ct DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES qt6ct.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) diff --git a/src/qt6ct/appearancepage.cpp b/src/qt6ct/appearancepage.cpp index 2f1faf8507581ac2c585d29d200c7c8e15be8199..09f753abbd0260bcf04363f771f2ef7dbd2adf86 100644 --- a/src/qt6ct/appearancepage.cpp +++ b/src/qt6ct/appearancepage.cpp @@ -35,6 +35,9 @@ #include <QMenu> #include <QIcon> #include <QStringList> +#ifdef KF_CONFIGCORE_LIB +#include <KConfigGroup> +#endif #include <qpa/qplatformthemefactory_p.h> #include <qpa/qplatformtheme.h> #include "qt6ct.h" @@ -70,7 +73,7 @@ AppearancePage::AppearancePage(QWidget *parent) : QMenu *menu = new QMenu(this); menu->addAction(QIcon::fromTheme(u"document-new"_s), tr("Create"), this, qOverload<>(&AppearancePage::createColorScheme)); m_changeColorSchemeAction = menu->addAction(QIcon::fromTheme(u"accessories-text-editor"_s), tr("Edit"), this, &AppearancePage::changeColorScheme); - menu->addAction(QIcon::fromTheme(u"edit-copy"_s), tr("Create a Copy"), this, &AppearancePage::copyColorScheme); + m_copyColorSchemeAction = menu->addAction(QIcon::fromTheme(u"edit-copy"_s), tr("Create a Copy"), this, &AppearancePage::copyColorScheme); m_renameColorSchemeAction = menu->addAction(tr("Rename"), this, &AppearancePage::renameColorScheme); menu->addSeparator(); m_removeColorSchemeAction = menu->addAction(QIcon::fromTheme(u"edit-delete"_s), tr("Remove"), this, &AppearancePage::removeColorScheme); @@ -126,6 +129,15 @@ void AppearancePage::writeSettings(QSettings *settings) settings->endGroup(); } +#ifdef KF_CONFIGCORE_LIB +void AppearancePage::writeSettings(KSharedConfigPtr config) +{ + KConfigGroup group(config, "KDE"); + group.writeEntry("widgetStyle", "qt6ct-style"); + group.sync(); +} +#endif + void AppearancePage::on_styleComboBox_textActivated(const QString &text) { QStyle *style = QStyleFactory::create(text); @@ -333,6 +345,7 @@ void AppearancePage::setPreviewPalette(const QPalette &p) void AppearancePage::updateActions() { + m_copyColorSchemeAction->setVisible(!Qt6CT::isKColorScheme(m_ui->colorSchemeComboBox->currentData().toString())); if(m_ui->colorSchemeComboBox->count() == 0 || !QFileInfo(m_ui->colorSchemeComboBox->currentData().toString()).isWritable()) { @@ -428,11 +441,26 @@ void AppearancePage::findColorSchemes(const QString &path) { QDir dir(path); dir.setFilter(QDir::Files); - dir.setNameFilters({ u"*.conf"_s }); + QStringList nameFilters; + nameFilters << u"*.conf"_s; +#if defined KF_CONFIGCORE_LIB && defined KF_COLORSCHEME_LIB + nameFilters << u"*.colors"_s; +#endif + dir.setNameFilters(nameFilters); for(const QFileInfo &info : dir.entryInfoList()) { - m_ui->colorSchemeComboBox->addItem(info.baseName(), info.filePath()); + QString name = info.baseName(); + QString path = info.filePath(); +#if defined KF_CONFIGCORE_LIB && defined KF_COLORSCHEME_LIB + if(Qt6CT::isKColorScheme(path)) + { + KSharedConfigPtr config = KSharedConfig::openConfig(path, KConfig::SimpleConfig); + KConfigGroup group(config, "General"); + name = group.readEntry("Name", name) + " (KColorScheme)"; + } +#endif + m_ui->colorSchemeComboBox->addItem(name, path); } } diff --git a/src/qt6ct/appearancepage.h b/src/qt6ct/appearancepage.h index e196b620dc99d954e8a94529917c7e6668e2aae4..8e4902e4173c9442e0e53f95cfbbcf568eac1e60 100644 --- a/src/qt6ct/appearancepage.h +++ b/src/qt6ct/appearancepage.h @@ -49,6 +49,10 @@ public: void writeSettings(QSettings *settings) override; +#ifdef KF_CONFIGCORE_LIB + void writeSettings(KSharedConfigPtr config) override; +#endif + private slots: void on_styleComboBox_textActivated(const QString &text); void on_colorSchemeComboBox_activated(int); @@ -73,7 +77,7 @@ private: QStyle *m_selectedStyle = nullptr; QPalette m_customPalette; QWidget *m_previewWidget; - QAction *m_changeColorSchemeAction, *m_renameColorSchemeAction, *m_removeColorSchemeAction; + QAction *m_changeColorSchemeAction, *m_copyColorSchemeAction, *m_renameColorSchemeAction, *m_removeColorSchemeAction; Ui::PreviewForm *m_previewUi; }; diff --git a/src/qt6ct/iconthemepage.cpp b/src/qt6ct/iconthemepage.cpp index 37960f92588299e3bee6df3589af2eb100f87e11..915611689bfc0727524f51b90542177ffa760f49 100644 --- a/src/qt6ct/iconthemepage.cpp +++ b/src/qt6ct/iconthemepage.cpp @@ -34,6 +34,9 @@ #include <QProgressBar> #include <QMetaObject> #include <QThread> +#ifdef KF_CONFIGCORE_LIB +#include <KConfigGroup> +#endif #include "qt6ct.h" #include "iconthemepage.h" #include "ui_iconthemepage.h" @@ -71,6 +74,19 @@ void IconThemePage::writeSettings(QSettings *settings) settings->setValue("Appearance/icon_theme"_L1, item->data(3, Qt::UserRole)); } +#ifdef KF_CONFIGCORE_LIB +void IconThemePage::writeSettings(KSharedConfigPtr config) +{ + QTreeWidgetItem *item = m_ui->treeWidget->currentItem(); + if(!item) + return; + + KConfigGroup group(config, "Icons"); + group.writeEntry("Theme", item->data(3, Qt::UserRole)); + group.sync(); +} +#endif + void IconThemePage::onFinished() { m_ui->treeWidget->addTopLevelItems(m_items); diff --git a/src/qt6ct/iconthemepage.h b/src/qt6ct/iconthemepage.h index 8938671f9922185c45a5610705d988173f694515..9ad3580a1d493613e60cc4eaaeccd58ca55b1c64 100644 --- a/src/qt6ct/iconthemepage.h +++ b/src/qt6ct/iconthemepage.h @@ -51,6 +51,10 @@ public: void writeSettings(QSettings *settings) override; +#ifdef KF_CONFIGCORE_LIB + void writeSettings(KSharedConfigPtr config) override; +#endif + private slots: void onFinished(); diff --git a/src/qt6ct/mainwindow.cpp b/src/qt6ct/mainwindow.cpp index 122dff21626301e98d10363feba72a957c1ab9fe..10296a4eff9c657ae91710ea30616a253737295d 100644 --- a/src/qt6ct/mainwindow.cpp +++ b/src/qt6ct/mainwindow.cpp @@ -91,11 +91,19 @@ void MainWindow::on_buttonBox_clicked(QAbstractButton *button) if(id == QDialogButtonBox::Ok || id == QDialogButtonBox::Apply) { QSettings settings(Qt6CT::configFile(), QSettings::IniFormat); +#ifdef KF_CONFIGCORE_LIB + KSharedConfigPtr config = KSharedConfig::openConfig("kdeglobals"); +#endif for(int i = 0; i < m_ui->tabWidget->count(); ++i) { TabPage *p = qobject_cast<TabPage*>(m_ui->tabWidget->widget(i)); if(p) + { p->writeSettings(&settings); +#ifdef KF_CONFIGCORE_LIB + p->writeSettings(config); +#endif + } } } diff --git a/src/qt6ct/tabpage.h b/src/qt6ct/tabpage.h index c77b5a7e49d5522fc9a5ab1450c4df29ccb0f964..4e46ddd3a07866e250e96a493174f641a57a7304 100644 --- a/src/qt6ct/tabpage.h +++ b/src/qt6ct/tabpage.h @@ -32,6 +32,10 @@ #include <QWidget> #include <QSettings> +#ifdef KF_CONFIGCORE_LIB +#include <KSharedConfig> +#endif + class TabPage : public QWidget { Q_OBJECT @@ -39,6 +43,10 @@ public: explicit TabPage(QWidget *parent = nullptr); virtual void writeSettings(QSettings *settings) = 0; + +#ifdef KF_CONFIGCORE_LIB + virtual void writeSettings(KSharedConfigPtr config) {} +#endif }; #endif // TABPAGE_H