Powrót do strony głównej

C++20 menedżer tapet: D-Bus i RAII

Artykuł omawia architekturę narzędzia CLI Rwal do zarządzania tapetami w różnych DE. Stosowany jest wzorzec Adapter, skrypty D-Bus dla KDE, GSettings dla GNOME, wrapper RAII libcurl i std::jthread C++20. Podano przykłady kodu i CMake.

Rwal: C++20 narzędzie do tapet w KDE i GNOME
Advertisement 728x90

Wieloplatformowy menedżer tapet w C++20: architektura i integracja systemowa

Narzędzie CLI Rwal zarządza tapetami w KDE, GNOME, a planowane jest dla Windows. Kluczowy element to interfejs IWallpaperSetter, implementujący wzorzec Adapter. Izoluje to logikę biznesową od specyfiki środowiska graficznego, minimalizując #ifdef.

// src/wallpaper/IWallpaperSetter.hpp
class IWallpaperSetter {
public:    
  virtual ~IWallpaperSetter() = default;    
  virtual bool setWallpaper(const std::string& path) = 0;
};

Fabryka w czasie wykonywania określa środowisko i zwraca odpowiednią implementację. Obsługa nowego środowiska wymaga tylko nowej klasy pochodnej.

Integracja z KDE Plasma przez D-Bus

KDE wymaga interakcji z org.kde.plasmashell. Implementacja KdeSetter wysyła skrypt JavaScript do zastosowania tapet na wszystkich pulpitach.

Google AdInline article slot
// Uproszczony fragment z src/wallpaper/KdeSetter.cpp
QDBusInterface remoteApp("org.kde.plasmashell", "/PlasmaShell", "org.kde.PlasmaShell");
QString script = QString(
    "var allDesktops = desktops();"
    "for (var i = 0; i < allDesktops.length; i++) {"
    "    var d = allDesktops[i];"
    "    d.wallpaperPlugin = 'org.kde.image';"
    "    d.currentConfigGroup = Array('Wallpapers', 'org.kde.image', 'General');"
    "    d.writeConfig('Image', 'file://%1');"
    "}"
).arg(QString::fromStdString(path));

remoteApp.call("evaluateScript", script);

Skrypt dynamicznie konfiguruje wallpaperPlugin i Image w ustawieniach każdego pulpitu. Obsługa błędów D-Bus zaimplementowana przez QDBusError.

GNOME: GSettings i tryby tematyczne

Dla GNOME używane jest gsettings przez QProcess. Uwzględniane są picture-uri-dark i picture-uri dla ciemnych/jasnych motywów.

// Z src/wallpaper/GnomeSetter.cpp
QProcess::execute("gsettings", {    
  "set", "org.gnome.desktop.background", "picture-uri-dark",     
  QString("file://%1").arg(QString::fromStdString(path))
});

Kod sprawdza obecność gsettings i fallback na bezpośrednie kopiowanie do ~/.config. Zapewnia to stabilność w kontenerach.

Google AdInline article slot

Warstwa sieciowa: RAII-otoczka libcurl

Pobieranie obrazów zaimplementowane przez CurlWrapper z RAII. std::unique_ptr z niestandardowym deleterem gwarantuje czyszczenie.

// src/net/CurlWrapper.hpp
using CurlPtr = std::unique_ptr<CURL, void(*)(CURL*)>;
// Implementacja
CurlWrapper::CurlWrapper() : curl_(curl_easy_init(), curl_easy_cleanup) {    
  if (!curl_) throw std::runtime_error("Failed to initialize CURL");
}

Klasa enkapsuluje CURLOPT_USERAGENT, CURLOPT_TIMEOUT i callbacki postępu. Pobieranie do pamięci używa CURLOPT_WRITEFUNCTION.

CMake: modułowe budowanie C++20

Projekt wymaga C++20 dla std::jthread i planowanego std::format. CMake znajduje Qt5 DBus, CURL, nlohmann_json.

Google AdInline article slot
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt5 REQUIRED COMPONENTS Core DBus Widgets)
find_package(CURL REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
add_subdirectory(src/wallpaper)
target_link_libraries(${PROJECT_NAME} PRIVATE wallpaper_lib Qt5::DBus CURL::libcurl nlohmann_json::nlohmann_json)

Rezygnacja z Docker uprościła dostęp do D-Bus hosta. Statyczne linkowanie CURL minimalizuje zależności.

Asynchroniczność z std::jthread

Pobieranie obrazów 4K blokowało UI. Rozwiązanie to std::jthread C++20:

  • Auto-join przy wyjściu z zakresu.
  • stop_token do anulowania operacji.
  • co_await kompatybilność z korutynami.
std::jthread loader(& {
    // Pobieranie z sprawdzeniem stoken.stop_requested()
});

Kompatybilność międzykompilatorowa: GCC 11+ i Clang 14+ z -fcoroutines.

Co jest ważne

  • Wzorzec Adapter pozwala dodawać środowiska w 15 minut bez refaktoryzacji core.
  • RAII dla libcurl eliminuje wycieki w ścieżkach wyjątków.
  • std::jthread rozwiązuje zamrożenia UI przy operacjach sieciowych.
  • Modułowy CMake zapewnia przenośne budowanie.
  • Skryptowanie D-Bus — jedyny niezawodny sposób dla Plasma.

Decyzje architektoniczne i analiza

Analiza statyczna clang-tidy wykazała sygnały Qt z potencjalnym use-after-free. ADR dokumentują wybór D-Bus nad bezpośrednim edytowaniem config.

Plany rozwoju:

  • Windows WinAPI SystemParametersInfoW.
  • QtNetwork lub boost::asio dla async.
  • Optymalizacja parsowania JSON pod odpowiedzi 100MB+.

Projekt demonstruje programowanie systemowe w C++20 dla średniozaawansowanych deweloperów: od interfejsów do korutyn.

— Editorial Team

Advertisement 728x90

Czytaj dalej