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.
// 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.
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.
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::jthreadrozwią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. QtNetworklubboost::asiodla 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
Brak komentarzy.