From d988fa049502851241ab6b3325630eea53b1bebb Mon Sep 17 00:00:00 2001 From: Corey Doughty Date: Mon, 10 Aug 2026 11:17:15 -0400 Subject: [PATCH] Initial import. --- .gitignore | 5 + configuration.nix | 280 ++++++++++ hdwr/example.nix | 87 +++ orig/.empty | 0 pkgs/default.nix | 146 +++++ pkgs/qt6ct/default.nix | 13 + pkgs/qt6ct/qt6ct-shenanigans.patch | 831 +++++++++++++++++++++++++++++ schd/example.nix | 140 +++++ vars/example.nix | 26 + 9 files changed, 1528 insertions(+) create mode 100644 .gitignore create mode 100644 configuration.nix create mode 100644 hdwr/example.nix create mode 100644 orig/.empty create mode 100644 pkgs/default.nix create mode 100644 pkgs/qt6ct/default.nix create mode 100644 pkgs/qt6ct/qt6ct-shenanigans.patch create mode 100644 schd/example.nix create mode 100644 vars/example.nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..49d9b01 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +hdwr/default.nix +orig/configuration.nix +orig/hardware-configuration.nix +schd/default.nix +vars/default.nix diff --git a/configuration.nix b/configuration.nix new file mode 100644 index 0000000..d8f057c --- /dev/null +++ b/configuration.nix @@ -0,0 +1,280 @@ +{ config, pkgs, ... }: + +let + # Variable import + vars = import ./vars; +in +{ + # Import + imports = [ ./hdwr ./pkgs ./schd ]; + + # System + # ------ + + # Bootloader + boot.kernelParams = [ "consoleblank=300" "loglevel=3" "quiet" ]; + boot.loader = { + timeout = 2; + systemd-boot = { + enable = true; + consoleMode = "keep"; + configurationLimit = 12; + }; + efi.canTouchEfiVariables = true; + }; + + # Time zone + time.timeZone = vars.timezone; + + # Select internationalisation properties. + i18n.defaultLocale = vars.locale; + + # Configure keymap in X11 + services.xserver.xkb = { + layout = "us"; + variant = ""; + }; + + # udev rules + # brightness: group video can edit some /sys/class files + services.udev.extraRules = '' + ACTION=="add", SUBSYSTEM=="backlight", RUN+="${pkgs.coreutils}/bin/chgrp video $sys$devpath/brightness" + ACTION=="add", SUBSYSTEM=="backlight", RUN+="${pkgs.coreutils}/bin/chmod g+w $sys$devpath/brightness" + ACTION=="add", SUBSYSTEM=="leds", RUN+="${pkgs.coreutils}/bin/chgrp video $sys$devpath/brightness" + ACTION=="add", SUBSYSTEM=="leds", RUN+="${pkgs.coreutils}/bin/chmod g+w $sys$devpath/brightness" + ''; + + # Garbage cleanup + nix.gc = { + automatic = true; + options = "--delete-older-than 28d"; + }; + + + # User + # ---- + + # Don't forget to set a password with ‘passwd’. + users.users = { + "${vars.user.username}" = { + isNormalUser = true; + description = vars.user.fullname; + extraGroups = [ "networkmanager" "video" "wheel" ]; + packages = with pkgs; vars.user.pkgs; + }; + }; + + # Environment variables + environment.sessionVariables = { + # Various + NIXOS_OZONE_WL = "1"; + PYTHONTRACEMALLOC = "1"; + + # Cursor + XCURSOR_THEME = "breeze_cursors"; + XCURSOR_SIZE = "24"; + #HYPRCURSOR_SIZE = "24"; + #WLR_NO_HARDWARE_CURSORS = "1"; + + # Nvidia specific (in hardware config) + #LIBVA_DRIVER_NAME = "nvidia"; + #__GLX_VENDOR_LIBRARY_NAME = "nvidia"; + #GBM_BACKEND = "nvidia-drm"; + + # Plasma/QT settings + PLASMA_USE_QT_SCALING = "1"; + QT_AUTO_SCREEN_SCALE_FACTOR = "1"; + QT_SCALE_FACTOR = "1.0"; + QT_QPA_PLATFORM = "wayland;xcb"; + QT_WAYLAND_DISABLE_WINDOWDECORATION = "1"; + # Enable only when using TWM + QT_QPA_PLATFORMTHEME = "qt6ct"; + # Kind of works; except some icons + #QT_STYLE_OVERRIDE = "Breeze"; + }; + + + # Progams + # ------- + + # Gnome config + programs.dconf = { + enable = true; + profiles.user.databases = [{ + lockAll = false; # prevents overriding + settings = { + "org/gnome/desktop/interface" = { + color-scheme = "prefer-light"; + gtk-theme = "breeze"; + icon-theme = "breeze"; + }; + }; + }]; + }; + + # GnuPG + programs.gnupg.agent = { + enable = true; + enableSSHSupport = false; + }; + + # Network diagnostic tool + programs.mtr.enable = true; + + # Allow running user programs like python, etc. + programs.nix-ld.enable = true; + + # Steam + programs.steam = { + enable = true; + remotePlay.openFirewall = false; # Steam Remote Play + dedicatedServer.openFirewall = false; # Source Dedicated Server + localNetworkGameTransfers.openFirewall = true; # Steam Local Network Game Transfers + }; + + + # Services + # -------- + + # Audio + security.rtkit.enable = true; + services.pulseaudio.enable = false; + services.pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + }; + xdg.sounds.enable = true; + + # Bluetooth + hardware.bluetooth = { + enable = true; + powerOnBoot = true; + settings = { + General = { + Enable = "Source,Sink,Media,Socket"; + }; + }; + }; + + # Desktop Environments + services = { + # Gnome + #displayManager.gdm.enable = true; + #desktopManager.gnome.enable = true; + # KDE Plasma + #displayManager.sddm.enable = true; + #displayManager.sddm.wayland.enable = true; + desktopManager.plasma6.enable = true; + }; + + # Discovery + services.avahi = { + enable = true; + nssmdns4 = true; + openFirewall = true; + }; + + # Firmware + # disabled here but added to pkgs for manual + services.fwupd.enable = false; + + # Logind Settings + services.logind.settings.Login = { + HandleLidSwitch = "suspend"; + HandleLidSwitchExternalPower = "ignore"; + HandleLidSwitchDocked = "ignore"; + }; + + # Networking + services.fail2ban.enable = true; + networking = { + hostName = vars.network.hostname; + networkmanager.enable = true; + wireguard.enable = true; + nftables.enable = true; + firewall = { + enable = true; + allowedTCPPorts = vars.network.firewall.tcp_ports; + allowedUDPPorts = vars.network.firewall.udp_ports; + }; + }; + + # Power Profiles (tuned) + services.tuned.enable = true; + services.upower.enable = true; + + # Printing (cups) + services.printing = { + enable = true; + browsed.enable = false; + }; + + # Secure Shell + services.openssh = { + enable = true; + ports = [ 22 ]; + openFirewall = true; + settings = { + PasswordAuthentication = false; + PermitRootLogin = "no"; + }; + }; + + # Send Mail + programs.msmtp = { + enable = true; + setSendmail = true; + accounts = { + default = { + auth = true; + tls = vars.smtp.tls; + tls_starttls = vars.smtp.tls_starttls; + port = vars.smtp.port; + host = vars.smtp.host; + from = vars.smtp.from; + user = vars.smtp.user; + password = vars.smtp.password; + }; + }; + }; + + # Sync + #services.syncthing = { + # enable = true; + # group = "users"; + # user = "${vars.user.username}"; + # configDir = "/home/${vars.user.username}/.local/state/syncthing"; + #}; + + # Virtualisation + virtualisation.virtualbox.host.enable = true; + users.extraGroups.vboxusers.members = [ "${vars.user.username}" ]; + + # X11 + #services.xserver.enable = false; + + + # Security + # -------- + + # Policy kit + security.polkit.enable = true; + + # Wallet + security.pam.services.login.kwallet.enable = true; + + + # Other + # ----- + + # This value determines the NixOS release from which the default + # settings for stateful data, like file locations and database versions + # on your system were taken. It‘s perfectly fine and recommended to leave + # this value at the release version of the first install of this system. + # Before changing this value read the documentation for this option + # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). + system.stateVersion = "26.05"; # Did you read the comment? + +} diff --git a/hdwr/example.nix b/hdwr/example.nix new file mode 100644 index 0000000..c5477a3 --- /dev/null +++ b/hdwr/example.nix @@ -0,0 +1,87 @@ +{ config, lib, pkgs, modulesPath, ... }: + +{ + # Imports + imports = [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + # hardware general + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + + # boot + boot.kernelPackages = pkgs.linuxPackages_latest; + boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" "sdhci_pci" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + # luks + boot.initrd.luks.devices = { + # drive1: swap + "luks-UUID-1B" = { + device = "/dev/disk/by-uuid/UUID-1B"; + }; + # drive1: root + "luks-UUID-1C" = { + device = "/dev/disk/by-uuid/UUID-1C"; + }; + # drive2: data + "luks-UUID-2A" = { + device = "/dev/disk/by-uuid/UUID-2A"; + allowDiscards = true; + #keyFile = "/crypto_keyfile.bin"; + }; + }; + + # swap + swapDevices = [ { device = "/dev/mapper/luks-UUID-1B"; } ]; + + # file system + fileSystems = { + # drive1: boot + "/boot" = { + device = "/dev/disk/by-uuid/UUID-1A"; + fsType = "vfat"; + options = [ "fmask=0077" "dmask=0077" ]; + }; + # drive1: root + "/" = { + device = "/dev/mapper/UUID-1C"; + fsType = "ext4"; + }; + # drive2: data + "/data" = { + device = "/dev/mapper/luks-UUID-2A"; + fsType = "ext4"; + }; + }; + + # nvidia + services.xserver.videoDrivers = ["nvidia"]; + hardware.nvidia = { + modesetting.enable = true; + open = true; + nvidiaSettings = true; + package = config.boot.kernelPackages.nvidiaPackages.stable; + }; + + # opengl + hardware.graphics.enable = true; + + # nvtop + environment.systemPackages = with pkgs; [ + #nvtopPackages.amd + #nvtopPackages.intel + nvtopPackages.nvidia + ]; + + # nvidia twm environment variables + environment.sessionVariables = { + LIBVA_DRIVER_NAME = "nvidia"; + __GLX_VENDOR_LIBRARY_NAME = "nvidia"; + GBM_BACKEND = "nvidia-drm"; + }; + +} diff --git a/orig/.empty b/orig/.empty new file mode 100644 index 0000000..e69de29 diff --git a/pkgs/default.nix b/pkgs/default.nix new file mode 100644 index 0000000..977d660 --- /dev/null +++ b/pkgs/default.nix @@ -0,0 +1,146 @@ +{ config, pkgs, ... }: + +let + unstable = import {}; +in +{ + imports = [ + ./qt6ct + ]; + + # Allow unfree packages + nixpkgs.config.allowUnfree = true; + + # System Packages + environment.systemPackages = with pkgs; with kdePackages; with libsForQt5; [ + + # pkgs + acpi + alacritty + autotiling + btop + ddcutil + dex + doctl + duplicity + fast-cli-zig + fastfetch + ffmpeg + foot + freecad + fwupd + ghostscript + gimp + git + glib + gnome-themes-extra + gparted + grim + gsettings-desktop-schemas + helix + htop + hunspell + hunspellDicts.en_CA + inkscape + jq + keepassxc + kitty + krita + libappindicator + libnotify + librewolf + luaPackages.luacheck + lxappearance + mailutils + man + man-db + man-pages + man-pages-posix + mesa-demos + mythes + neovim + nextcloud-client + niri + nps + nwg-look + onlyoffice-desktopeditors + openscad + pavucontrol + pcmanfm-qt + pstree + python3 + qownnotes + rsync + ruff + signal-desktop + slurp + sound-theme-freedesktop + speedtest-cli + swayfx + thunderbird + tldr + tor-browser + transmission_4 + unrar + unzip + uv + vim + vlc + wavemon + wget + wireguard-tools + wl-clipboard + wlopm + wlr-which-key + wlr-randr + xdg-desktop-portal-hyprland + yarn + zip + + # kdePackages + ark + dolphin + dolphin-plugins + elisa + ffmpegthumbs + gwenview + kamoso + kate + kcalc + kcolorchooser + kconfig + kdenlive + kompare + ktorrent + okular + partitionmanager + plasma-browser-integration + plasma-workspace-wallpapers + qtbase + + # libsForQt5 + qt5ct + + # unstable + unstable.brave-origin + unstable.hyprland + unstable.noctalia + ]; + + # fonts + fonts.packages = with pkgs; [ + fira-code + fira-code-symbols + noto-fonts + noto-fonts-color-emoji + liberation_ttf + ]; + + # Symlinks from packages + environment.etc = { + "xdg/menus/applications.menu" = { + source = "${pkgs.kdePackages.plasma-workspace}/etc/xdg/menus/plasma-applications.menu"; + }; + }; + +} diff --git a/pkgs/qt6ct/default.nix b/pkgs/qt6ct/default.nix new file mode 100644 index 0000000..bfafe68 --- /dev/null +++ b/pkgs/qt6ct/default.nix @@ -0,0 +1,13 @@ +{ confg, pkgs, ... }: + +{ + environment.systemPackages = with pkgs; with kdePackages; with qt6Packages; [ + (kdePackages.qt6ct.overrideAttrs (oldAttrs: { + name = "qt6ct-kde"; + buildInputs = oldAttrs.buildInputs ++ ([ + qtdeclarative kconfig kcolorscheme kiconthemes + ]); + patches = (oldAttrs.patches or [ ]) ++ [ ./qt6ct-shenanigans.patch ]; + })) + ]; +} diff --git a/pkgs/qt6ct/qt6ct-shenanigans.patch b/pkgs/qt6ct/qt6ct-shenanigans.patch new file mode 100644 index 0000000..15a3012 --- /dev/null +++ b/pkgs/qt6ct/qt6ct-shenanigans.patch @@ -0,0 +1,831 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 475a47f..d4950b3 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -28,15 +28,19 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) + set(CMAKE_BUILD_RPATH_USE_ORIGIN ON) + set(QT_NO_PRIVATE_MODULE_WARNING ON) + +-add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060200 -DUSE_WIDGETS -DQT_DEPRECATED_WARNINGS -DQT_MESSAGELOGCONTEXT) ++add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060200 -DQT_DEPRECATED_WARNINGS -DQT_MESSAGELOGCONTEXT) + 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 OPTIONAL_COMPONENTS Widgets QuickControls2 LinguistTools) + if(Qt6_VERSION VERSION_GREATER_EQUAL 6.10) +- find_package(Qt6 6.10 CONFIG REQUIRED COMPONENTS WidgetsPrivate GuiPrivate) ++ find_package(Qt6 6.10 CONFIG REQUIRED COMPONENTS GuiPrivate OPTIONAL_COMPONENTS WidgetsPrivate) + endif() + ++find_package(KF6Config) ++find_package(KF6ColorScheme) ++find_package(KF6IconThemes) ++ + get_target_property(QT_QTPATHS_EXECUTABLE Qt6::qtpaths IMPORTED_LOCATION) + + if(Qt6LinguistTools_FOUND) +@@ -80,10 +84,12 @@ endif() + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/qt6ct-common) + + add_link_options(-Wl,--no-undefined) +-add_subdirectory(src/qt6ct) + add_subdirectory(src/qt6ct-common) + add_subdirectory(src/qt6ct-qtplugin) +-add_subdirectory(src/qt6ct-style) ++if(Qt6Widgets_FOUND) ++ add_subdirectory(src/qt6ct-style) ++ add_subdirectory(src/qt6ct) ++endif() + + install(DIRECTORY qss DESTINATION ${CMAKE_INSTALL_DATADIR}/qt6ct) + install(DIRECTORY colors DESTINATION ${CMAKE_INSTALL_DATADIR}/qt6ct) +diff --git a/src/qt6ct-common/CMakeLists.txt b/src/qt6ct-common/CMakeLists.txt +index 3b9f0b9..2afce8d 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_compile_definitions(qt6ct-common PRIVATE $<$:KF_CONFIGCORE_LIB> $<$: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 616440b..250987d 100644 +--- a/src/qt6ct-common/qt6ct.cpp ++++ b/src/qt6ct-common/qt6ct.cpp +@@ -34,6 +34,10 @@ + #include + #include + #include ++#if defined KF_CONFIGCORE_LIB && defined KF_COLORSCHEME_LIB ++#include ++#include ++#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(); +@@ -129,6 +136,9 @@ QStringList Qt6CT::sharedColorSchemePaths() + + QString Qt6CT::resolvePath(const QString &path) + { ++ if(path.isEmpty()) ++ return path; ++ + QString tmp = path; + tmp.replace(QLatin1Char('~'), QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); + if(!tmp.contains(QLatin1Char('$'))) +@@ -148,9 +158,21 @@ QString Qt6CT::resolvePath(const QString &path) + return tmp; + } + +-QPalette Qt6CT::loadColorScheme(const QString &filePath, const QPalette &fallback) ++bool Qt6CT::isKColorScheme(const QString &filePath) + { +- QPalette customPalette; ++ return filePath.toLower().endsWith(".colors"); ++} ++ ++std::optional Qt6CT::loadColorScheme(const QString &filePath) ++{ ++ if(filePath.isEmpty()) ++ return std::nullopt; ++ ++#if defined KF_CONFIGCORE_LIB && defined KF_COLORSCHEME_LIB ++ if(isKColorScheme(filePath)) ++ return KColorScheme::createApplicationPalette(KSharedConfig::openConfig(filePath)); ++#endif ++ + QSettings settings(filePath, QSettings::IniFormat); + settings.beginGroup("ColorScheme"_L1); + QStringList activeColors = settings.value("active_colors"_L1).toStringList(); +@@ -158,7 +180,6 @@ QPalette Qt6CT::loadColorScheme(const QString &filePath, const QPalette &fallbac + QStringList disabledColors = settings.value("disabled_colors"_L1).toStringList(); + settings.endGroup(); + +- + #if (QT_VERSION >= QT_VERSION_CHECK(6,6,0)) + if(activeColors.count() == QPalette::Accent) + activeColors << activeColors.at(QPalette::Highlight); +@@ -168,24 +189,19 @@ QPalette Qt6CT::loadColorScheme(const QString &filePath, const QPalette &fallbac + disabledColors << disabledColors.at(QPalette::Highlight); + #endif + ++ if(activeColors.count() < QPalette::NColorRoles || ++ inactiveColors.count() < QPalette::NColorRoles || ++ disabledColors.count() < QPalette::NColorRoles) ++ return std::nullopt; + +- if(activeColors.count() >= QPalette::NColorRoles && +- inactiveColors.count() >= QPalette::NColorRoles && +- disabledColors.count() >= QPalette::NColorRoles) +- { +- for (int i = 0; i < QPalette::NColorRoles; i++) +- { +- QPalette::ColorRole role = QPalette::ColorRole(i); +- customPalette.setColor(QPalette::Active, role, QColor(activeColors.at(i))); +- customPalette.setColor(QPalette::Inactive, role, QColor(inactiveColors.at(i))); +- customPalette.setColor(QPalette::Disabled, role, QColor(disabledColors.at(i))); +- } +- } +- else ++ QPalette customPalette; ++ for (int i = 0; i < QPalette::NColorRoles; i++) + { +- customPalette = fallback; //load fallback palette ++ QPalette::ColorRole role = QPalette::ColorRole(i); ++ customPalette.setColor(QPalette::Active, role, QColor(activeColors.at(i))); ++ customPalette.setColor(QPalette::Inactive, role, QColor(inactiveColors.at(i))); ++ customPalette.setColor(QPalette::Disabled, role, QColor(disabledColors.at(i))); + } +- + return customPalette; + } + +diff --git a/src/qt6ct-common/qt6ct.h b/src/qt6ct-common/qt6ct.h +index f253987..06ea440 100644 +--- a/src/qt6ct-common/qt6ct.h ++++ b/src/qt6ct-common/qt6ct.h +@@ -101,7 +101,8 @@ public: + static QString styleColorSchemeFile(); + static QStringList sharedColorSchemePaths(); + static QString resolvePath(const QString &path); +- static QPalette loadColorScheme(const QString &filePath, const QPalette &fallback); ++ static bool isKColorScheme(const QString &filePath); ++ static std::optional loadColorScheme(const QString &filePath); + + static void registerStyleInstance(StyleInstance *instance); + static void unregisterStyleInstance(StyleInstance *instance); +diff --git a/src/qt6ct-qtplugin/CMakeLists.txt b/src/qt6ct-qtplugin/CMakeLists.txt +index 93a2b84..5e170c5 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::GuiPrivate $ $ qt6ct-common) ++target_compile_definitions(qt6ct-qtplugin PRIVATE $<$:KF_ICONTHEMES_LIB>) + install(TARGETS qt6ct-qtplugin DESTINATION ${PLUGINDIR}/platformthemes) +diff --git a/src/qt6ct-qtplugin/qt6ct-qtplugin.pro b/src/qt6ct-qtplugin/qt6ct-qtplugin.pro +index f3e9ef6..a05a9b7 100644 +--- a/src/qt6ct-qtplugin/qt6ct-qtplugin.pro ++++ b/src/qt6ct-qtplugin/qt6ct-qtplugin.pro +@@ -11,7 +11,7 @@ SOURCES += \ + qt6ctplatformtheme.cpp + + !equals(DISABLE_WIDGETS,1) { +- QT += widgets ++ QT += widgets widgets-private + } + + OTHER_FILES += qt6ct.json +diff --git a/src/qt6ct-qtplugin/qt6ctplatformtheme.cpp b/src/qt6ct-qtplugin/qt6ctplatformtheme.cpp +index 569b13f..78c2eae 100644 +--- a/src/qt6ct-qtplugin/qt6ctplatformtheme.cpp ++++ b/src/qt6ct-qtplugin/qt6ctplatformtheme.cpp +@@ -41,38 +41,68 @@ + #include + #include + #include ++#if QT_CONFIG(graphicsview) ++#include ++#endif ++#include + #endif + #include + #include +-#include ++#ifdef QT_QUICKCONTROLS2_LIB ++#include ++#endif + + #include "qt6ct.h" + #include "qt6ctplatformtheme.h" + + #include + #include ++#include ++ ++#ifdef KF_ICONTHEMES_LIB ++#include ++#include ++#endif + + Q_LOGGING_CATEGORY(lqt6ct, "qt6ct", QtWarningMsg) + + //QT_QPA_PLATFORMTHEME=qt6ct + +-Qt6CTPlatformTheme::Qt6CTPlatformTheme() ++Qt6CTPlatformTheme::Qt6CTPlatformTheme() : ++ m_generalFont(*QGenericUnixTheme::font(QPlatformTheme::SystemFont)), ++ m_fixedFont(*QGenericUnixTheme::font(QPlatformTheme::FixedFont)) + { + Qt6CT::initConfig(); + if(QGuiApplication::desktopSettingsAware()) + { + readSettings(); + QMetaObject::invokeMethod(this, &Qt6CTPlatformTheme::applySettings, Qt::QueuedConnection); +-#ifdef QT_WIDGETS_LIB + QMetaObject::invokeMethod(this, &Qt6CTPlatformTheme::createFSWatcher, Qt::QueuedConnection); ++ //must be applied before Q_COREAPP_STARTUP_FUNCTION execution ++ if(Qt6CT::isKColorScheme(m_schemePath)) ++ qApp->setProperty("KDE_COLOR_SCHEME_PATH", m_schemePath); ++#ifdef QT_WIDGETS_LIB ++ if(hasWidgets()) ++ { ++ //style could use various interfaces aren't initialized yet ++ QTimer::singleShot(0, this, [this] { ++ m_style.reset(QStyleFactory::create(u"qt6ct-style"_s)); ++ applySettings(); ++ }); ++#ifdef QT_QUICKCONTROLS2_LIB ++ //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 ++ } + #endif +- QGuiApplication::setFont(m_generalFont); + } + 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() +@@ -90,10 +120,41 @@ QPlatformDialogHelper *Qt6CTPlatformTheme::createPlatformDialogHelper(DialogType + QGenericUnixTheme::createPlatformDialogHelper(type); + } + ++#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) ++Qt::ColorScheme Qt6CTPlatformTheme::colorScheme() const ++{ ++ //m_inColorScheme prevents QPlatformTheme::palette -> QPlatformThemePrivate::initializeSystemPalette ++ //-> qt_fusionPalette -> Qt6CTPlatformTheme::colorScheme infinite recursion ++ if(m_isIgnored || m_inColorScheme) ++ return QGenericUnixTheme::colorScheme(); ++ ++ m_inColorScheme = true; ++#ifdef QT_WIDGETS_LIB ++ //follow QApplicationPrivate::basePalette() logic ++ QPalette palette = m_style ? m_style->standardPalette() : Qt::gray; ++ if(const QPalette *themePalette = this->palette()) ++ palette = themePalette->resolve(palette); ++ palette.setResolveMask(0); ++ if (m_style) ++ m_style->polish(palette); ++#else ++ //follow QGuiApplicationPrivate::basePalette() logic ++ const QPalette palette = this->palette() ? *this->palette() : Qt::gray; ++#endif ++ m_inColorScheme = false; ++ ++ return palette.windowText().color().lightness() > palette.window().color().lightness() ++ ? Qt::ColorScheme::Dark ++ : palette.windowText().color().lightness() < palette.window().color().lightness() ++ ? Qt::ColorScheme::Light ++ : QGenericUnixTheme::colorScheme(); ++} ++#endif ++ + const QPalette *Qt6CTPlatformTheme::palette(QPlatformTheme::Palette type) const + { +- if (type == QPlatformTheme::SystemPalette && !m_isIgnored) +- return &m_palette; ++ if (type == QPlatformTheme::SystemPalette && m_palette) ++ return &*m_palette; + return QGenericUnixTheme::palette(type); + } + +@@ -148,6 +209,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) +@@ -156,18 +224,18 @@ void Qt6CTPlatformTheme::applySettings() + return; + } + +- 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()) + { +- qApp->setFont(m_generalFont); +- +- //Qt 5.6 or higher should be use themeHint function on application startup. +- //So, there is no need to call this function first time. + if(m_update) + { +- qApp->setWheelScrollLines(m_wheelScrollLines); ++ if(FontHash *hash = qt_app_fonts_hash(); hash && hash->size()) ++ hash->clear(); + Qt6CT::reloadStyleInstanceSettings(); + } + +@@ -193,25 +261,26 @@ void Qt6CTPlatformTheme::applySettings() + + if(m_update) + { +- QIconLoader::instance()->updateSystemTheme(); //apply icons +- QGuiApplication::setPalette(QGuiApplication::palette()); //apply palette ++ QWindowSystemInterface::handleThemeChange(); ++ QCoreApplication::postEvent(qGuiApp, new QEvent(QEvent::ApplicationFontChange)); + } + + #ifdef QT_WIDGETS_LIB + if(hasWidgets() && m_update) + { +- for(QWidget *w : qApp->allWidgets()) +- { +- QEvent e(QEvent::ThemeChange); +- QApplication::sendEvent(w, &e); +- } ++#if QT_CONFIG(graphicsview) ++ for(auto scene : std::as_const(QApplicationPrivate::instance()->scene_list)) ++ QCoreApplication::postEvent(scene, new QEvent(QEvent::ApplicationFontChange)); ++#endif ++ ++ for(QWidget *w : QApplication::allWidgets()) ++ QCoreApplication::postEvent(w, new QEvent(QEvent::ThemeChange)); + } + #endif + + m_update = true; + } + +-#ifdef QT_WIDGETS_LIB + void Qt6CTPlatformTheme::createFSWatcher() + { + QFileSystemWatcher *watcher = new QFileSystemWatcher(this); +@@ -230,21 +299,16 @@ void Qt6CTPlatformTheme::updateSettings() + readSettings(); + applySettings(); + } +-#endif + + void Qt6CTPlatformTheme::readSettings() + { + QSettings settings(Qt6CT::configFile(), QSettings::IniFormat); + + settings.beginGroup("Appearance"_L1); +- m_style = settings.value("style"_L1, u"Fusion"_s).toString(); +- m_palette = *QGenericUnixTheme::palette(SystemPalette); +- QString schemePath = settings.value("color_scheme_path"_L1).toString(); +- if(!schemePath.isEmpty() && settings.value("custom_palette"_L1, false).toBool()) +- { +- schemePath = Qt6CT::resolvePath(schemePath); //replace environment variables +- m_palette = Qt6CT::loadColorScheme(schemePath, m_palette); +- } ++ m_schemePath = !m_isIgnored && settings.value("custom_palette"_L1, false).toBool() ++ ? Qt6CT::resolvePath(settings.value("color_scheme_path"_L1).toString()) //replace environment variables ++ : QString(); ++ m_palette = Qt6CT::loadColorScheme(m_schemePath); + m_iconTheme = settings.value("icon_theme"_L1).toString(); + //load dialogs + if(!m_update) +@@ -252,8 +316,9 @@ void Qt6CTPlatformTheme::readSettings() + //do not mix gtk2 style and gtk3 dialogs + QStringList keys = QPlatformThemeFactory::keys(); + QString dialogs = settings.value("standard_dialogs"_L1, u"default"_s).toString(); ++ QString style = settings.value("style"_L1, u"Fusion"_s).toString(); + +- if(m_style.endsWith(u"gtk2"_s) && dialogs == QLatin1String("gtk3")) ++ if(style.endsWith(u"gtk2"_s) && dialogs == QLatin1String("gtk3")) + dialogs = u"gtk2"_s; + if(keys.contains(dialogs)) + m_theme.reset(QPlatformThemeFactory::create(dialogs)); +@@ -262,10 +327,10 @@ void Qt6CTPlatformTheme::readSettings() + settings.endGroup(); + + settings.beginGroup("Fonts"_L1); +- m_generalFont = QGuiApplication::font(); +- m_generalFont.fromString(settings.value("general"_L1, QGuiApplication::font()).toString()); +- m_fixedFont = QGuiApplication::font(); +- m_fixedFont.fromString(settings.value("fixed"_L1, QGuiApplication::font()).toString()); ++ m_generalFont = *QGenericUnixTheme::font(QPlatformTheme::SystemFont); ++ m_generalFont.fromString(settings.value("general"_L1).toString()); ++ m_fixedFont = *QGenericUnixTheme::font(QPlatformTheme::FixedFont); ++ m_fixedFont.fromString(settings.value("fixed"_L1).toString()); + settings.endGroup(); + + settings.beginGroup("Interface"_L1); +@@ -354,3 +419,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(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 b2a7bcf..9327ef0 100644 +--- a/src/qt6ct-qtplugin/qt6ctplatformtheme.h ++++ b/src/qt6ct-qtplugin/qt6ctplatformtheme.h +@@ -43,6 +43,8 @@ + #include + #include + ++class QStyle; ++ + Q_DECLARE_LOGGING_CATEGORY(lqt6ct) + + class Qt6CTPlatformTheme : public QObject, public QGenericUnixTheme +@@ -58,6 +60,9 @@ public: + //virtual void showPlatformMenuBar() {} + virtual bool usePlatformNativeDialog(DialogType type) const override; + virtual QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const override; ++#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) ++ virtual Qt::ColorScheme colorScheme() const override; ++#endif + virtual const QPalette *palette(Palette type = SystemPalette) const override; + virtual const QFont *font(Font type = SystemFont) const override; + virtual QVariant themeHint(ThemeHint hint) const override; +@@ -66,16 +71,19 @@ 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 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 + void createFSWatcher(); + void updateSettings(); +-#endif + + private: + void readSettings(); +@@ -83,8 +91,8 @@ private: + bool hasWidgets(); + #endif + QString loadStyleSheets(const QStringList &paths); +- QString m_style, m_iconTheme, m_userStyleSheet, m_prevStyleSheet; +- QPalette m_palette; ++ QString m_schemePath, m_iconTheme, m_userStyleSheet, m_prevStyleSheet; ++ std::optional m_palette; + QFont m_generalFont, m_fixedFont; + int m_doubleClickInterval; + int m_cursorFlashTime; +@@ -96,7 +104,11 @@ private: + int m_wheelScrollLines = 3; + bool m_showShortcutsInContextMenus = false; + bool m_isIgnored = false; ++ mutable bool m_inColorScheme = false; + std::unique_ptr m_theme; ++#ifdef QT_WIDGETS_LIB ++ std::unique_ptr m_style; ++#endif + }; + + Q_DECLARE_LOGGING_CATEGORY(lqt6ct) +diff --git a/src/qt6ct-style/CMakeLists.txt b/src/qt6ct-style/CMakeLists.txt +index 5ab1c21..c8870b3 100644 +--- a/src/qt6ct-style/CMakeLists.txt ++++ b/src/qt6ct-style/CMakeLists.txt +@@ -1,7 +1,5 @@ + project(qt6ct-style) + +-add_definitions(-DUSE_WIDGETS) +- + set(app_SRCS + plugin.cpp + qt6ctproxystyle.cpp +diff --git a/src/qt6ct/CMakeLists.txt b/src/qt6ct/CMakeLists.txt +index fb0e1f7..f11071f 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::GuiPrivate $ qt6ct-common) ++target_compile_definitions(qt6ct PRIVATE USE_WIDGETS $<$:KF_CONFIGCORE_LIB> $<$: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 2f1faf8..0c01d4a 100644 +--- a/src/qt6ct/appearancepage.cpp ++++ b/src/qt6ct/appearancepage.cpp +@@ -35,6 +35,9 @@ + #include + #include + #include ++#ifdef KF_CONFIGCORE_LIB ++#include ++#endif + #include + #include + #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); +@@ -157,7 +169,7 @@ void AppearancePage::on_colorSchemeComboBox_activated(int) + } + else + { +- m_customPalette = Qt6CT::loadColorScheme(data, palette()); ++ m_customPalette = Qt6CT::loadColorScheme(data).value_or(palette()); + } + updatePalette(); + } +@@ -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()) + { +@@ -364,8 +377,7 @@ void AppearancePage::readSettings() + QString style = settings.value("style"_L1, u"Fusion"_s).toString(); + m_ui->styleComboBox->setCurrentText(style); + +- QString colorSchemePath = settings.value("color_scheme_path"_L1).toString(); +- colorSchemePath = Qt6CT::resolvePath(colorSchemePath); //replace environment variables ++ QString colorSchemePath = Qt6CT::resolvePath(settings.value("color_scheme_path").toString()); //replace environment variables + + m_ui->colorSchemeComboBox->addItem(tr("Default"), u"system"_s); + m_ui->colorSchemeComboBox->addItem(tr("Style's colors"), u"style"_s); +@@ -382,7 +394,7 @@ void AppearancePage::readSettings() + index = m_ui->colorSchemeComboBox->findData(u"style"_s); + + m_ui->colorSchemeComboBox->setCurrentIndex(index); +- m_customPalette = Qt6CT::loadColorScheme(colorSchemePath, palette()); ++ m_customPalette = Qt6CT::loadColorScheme(colorSchemePath).value_or(palette()); + } + else + { +@@ -428,11 +440,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 e196b62..8e4902e 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/fontspage.cpp b/src/qt6ct/fontspage.cpp +index 75de0fd..ae0f091 100644 +--- a/src/qt6ct/fontspage.cpp ++++ b/src/qt6ct/fontspage.cpp +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -70,12 +71,19 @@ void FontsPage::onFontChangeRequested(QWidget *widget) + { + bool ok = false; + QFont font = QFontDialog::getFont (&ok, widget->font(), this); +- if(ok) +- { +- widget->setProperty("value", font.toString()); +- widget->setFont(font); +- qobject_cast(widget)->setText(font.family () + QChar::Space + QString::number(font.pointSize ())); +- } ++ if(!ok) ++ return; ++ ++ if(font.weight() == QFont::Normal ++ && (font.styleName() == "Regular"_L1 ++ || font.styleName() == "Normal"_L1 ++ || font.styleName() == "Book"_L1 ++ || font.styleName() == "Roman"_L1)) ++ font.setStyleName(QString()); ++ ++ widget->setProperty("value", font.toString()); ++ widget->setFont(font); ++ qobject_cast(widget)->setText(font.family () + QChar::Space + QString::number(font.pointSize ())); + } + + void FontsPage::readSettings() +@@ -89,8 +97,9 @@ void FontsPage::readSettings() + + void FontsPage::loadFont(QSettings *settings, QLabel *label, const QString &key) + { +- QFont font = QApplication::font(); +- font.fromString(settings->value(key, QApplication::font().toString()).toString()); ++ QFont font = settings->value(key, key == "fixed"_L1 ++ ? QFontDatabase::systemFont(QFontDatabase::FixedFont) ++ : QFontDatabase::systemFont(QFontDatabase::GeneralFont)).value(); + label->setText(font.family() + QChar::Space + QString::number(font.pointSize())); + label->setFont(font); + label->setProperty("value", font.toString()); +diff --git a/src/qt6ct/iconthemepage.cpp b/src/qt6ct/iconthemepage.cpp +index 37960f9..9156116 100644 +--- a/src/qt6ct/iconthemepage.cpp ++++ b/src/qt6ct/iconthemepage.cpp +@@ -34,6 +34,9 @@ + #include + #include + #include ++#ifdef KF_CONFIGCORE_LIB ++#include ++#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 8938671..9ad3580 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 122dff2..10296a4 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(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 c77b5a7..c3c2c09 100644 +--- a/src/qt6ct/tabpage.h ++++ b/src/qt6ct/tabpage.h +@@ -32,6 +32,10 @@ + #include + #include + ++#ifdef KF_CONFIGCORE_LIB ++#include ++#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) {} ++#endif + }; + + #endif // TABPAGE_H diff --git a/schd/example.nix b/schd/example.nix new file mode 100644 index 0000000..7e21c24 --- /dev/null +++ b/schd/example.nix @@ -0,0 +1,140 @@ +{ config, pkgs, ... }: + +let + # Variables + vars = import ../vars; +in +{ + # Services + systemd.services = { + + "notify-email@" = { + path = with pkgs; [ systemd system-sendmail ]; + scriptArgs = "%I"; + script = '' + UNIT=$(systemd-escape $1) + TO="${vars.smtp.from}" + FROM="${vars.smtp.from}" + SUBJECT="$UNIT Failed" + HEADERS="To:$TO\nFrom:$FROM\nSubject: $SUBJECT\n" + BODY=$(systemctl status --no-pager $UNIT || true) + echo -e "$HEADERS\n$BODY" | sendmail -t + ''; + serviceConfig = { + Type = "oneshot"; + }; + }; + + "usr-cloud-sync" = { + script = '' + $HOME/.local/bin/pva nextcloud sync \ + > $HOME/.local/log/cloud-sync.log + ''; + serviceConfig = { + Type = "oneshot"; + User = "${vars.user.username}"; + }; + onFailure = [ "notify-email@%n.service" ]; + }; + + "usr-cloud-sync-force" = { + script = '' + $HOME/.local/bin/pva nextcloud kill && \ + $HOME/.local/bin/pva nextcloud sync \ + > $HOME/.local/log/cloud-sync-force.log + ''; + serviceConfig = { + Type = "oneshot"; + User = "${vars.user.username}"; + }; + onFailure = [ "notify-email@%n.service" ]; + }; + + "usr-email-bkg" = { + script = '' + $HOME/.local/bin/pva email tb-background \ + > $HOME/.local/log/email-bkg.log + ''; + serviceConfig = { + Type = "oneshot"; + User = "${vars.user.username}"; + }; + onFailure = [ "notify-email@%n.service" ]; + }; + + "usr-theme" = { + script = '' + $HOME/.local/bin/pva theme text \ + > $HOME/.local/log/theme.log + ''; + serviceConfig = { + Type = "oneshot"; + User = "${vars.user.username}"; + }; + onFailure = [ "notify-email@%n.service" ]; + }; + + "sys-purge" = { + script = '' + /root/.local/bin/sys-purge.sh \ + > /root/.local/log/sys-purge.log + ''; + serviceConfig = { + Type = "oneshot"; + User = "root"; + }; + onFailure = [ "notify-email@%n.service" ]; + }; + + }; + + + # Timers + # DayOfWeek Year-Month-Day Hour:Minute:Second + systemd.timers = { + + "usr-cloud-sync" = { + wantedBy = [ "timers.target" ]; + timerConfig = { + Unit = "usr-cloud-sync.service"; + OnCalendar = "*-*-* 00..22:0/5:00"; + Persistent = true; + }; + }; + + "usr-cloud-sync-force" = { + wantedBy = [ "timers.target" ]; + timerConfig = { + Unit = "usr-cloud-sync-force.service"; + OnCalendar = "*-*-* 23:23:23"; + }; + }; + + "usr-email-bkg" = { + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = "*-*-* 01:20:00"; + Unit = "usr-email-bkg.service"; + }; + }; + + "usr-theme" = { + wantedBy = [ "timers.target" ]; + timerConfig = { + Unit = "usr-theme.service"; + OnBootSec = "15m"; + OnUnitActiveSec = "15m"; + }; + }; + + "sys-purge" = { + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = "*-*-* 02:18:18"; + Unit = "sys-purge.service"; + }; + }; + + }; + +} diff --git a/vars/example.nix b/vars/example.nix new file mode 100644 index 0000000..7aa4590 --- /dev/null +++ b/vars/example.nix @@ -0,0 +1,26 @@ +{ + timezone = "America/New_York"; + locale = "en_US.UTF-8"; + user = { + username = "someuser"; + fullname = "Some User"; + pkgs = []; + }; + network = { + hostname = "somehost"; + firewall = { + tcp_ports = []; + udp_ports = []; + }; + }; + smtp = { + tls = true; + tls_starttls = false; + port = 465; + host = "example.com"; + to = "user2@exaple.com"; + from = "user1@example.com"; + user = "user1@example.com"; + password = "secret"; + }; +}