feat(dependencies): gate ddcutil via DependencyService across settings etc

This commit is contained in:
Ly-sec
2026-05-06 13:26:37 +02:00
parent e0a865d678
commit d4c16f31ec
11 changed files with 34 additions and 13 deletions
+2 -1
View File
@@ -1464,7 +1464,8 @@
},
"ddcutil": {
"label": "DDC/CI (ddcutil)",
"description": "Control external monitor brightness via DDC/CI"
"description": "Control external monitor brightness via DDC/CI",
"requires-ddcutil": "Install ddcutil to enable DDC/CI brightness control"
},
"night-light": {
"label": "Night Light",
+2 -2
View File
@@ -578,8 +578,8 @@ void Application::initServices() {
}
try {
m_brightnessService =
std::make_unique<BrightnessService>(m_systemBus.get(), m_wayland, m_configService.config().brightness);
m_brightnessService = std::make_unique<BrightnessService>(
m_systemBus.get(), m_wayland, m_configService.config().brightness, &m_dependencyService);
m_brightnessService->setChangeCallback([this, shouldRefreshControlCenter]() {
m_brightnessOsd.onBrightnessChanged(*m_brightnessService);
m_bar.refresh();
@@ -1,10 +1,12 @@
#include "shell/control_center/control_center_panel.h"
#include "config/config_service.h"
#include "i18n/i18n.h"
#include "notification/notification_manager.h"
#include "render/core/renderer.h"
#include "render/scene/input_area.h"
#include "shell/panel/panel_manager.h"
#include "system/brightness_service.h"
#include "system/dependency_service.h"
#include "ui/controls/button.h"
#include "ui/controls/flex.h"
@@ -22,6 +24,8 @@ ControlCenterPanel::ControlCenterPanel(
SystemMonitorService* sysmon, NightLightManager* nightLight, noctalia::theme::ThemeService* theme,
IdleInhibitor* idleInhibitor, DependencyService* dependencies, WaylandConnection* wayland, Wallpaper* wallpaper) {
(void)upower;
m_config = config;
m_brightness = brightness;
m_notificationManager = notifications;
m_dependencies = dependencies;
m_tabs[tabIndex(TabId::Overview)] =
@@ -243,6 +247,9 @@ void ControlCenterPanel::onOpen(std::string_view context) {
if (m_dependencies != nullptr) {
m_dependencies->rescan();
}
if (m_brightness != nullptr && m_config != nullptr) {
m_brightness->reload(m_config->config().brightness);
}
selectTab(tabFromContext(context));
}
@@ -135,6 +135,8 @@ private:
std::array<Flex*, kTabCount> m_tabContainers{};
std::array<Flex*, kTabCount> m_tabHeaderActions{};
TabId m_activeTab = TabId::Overview;
ConfigService* m_config = nullptr;
BrightnessService* m_brightness = nullptr;
NotificationManager* m_notificationManager = nullptr;
DependencyService* m_dependencies = nullptr;
};
+5 -2
View File
@@ -620,8 +620,11 @@ namespace settings {
{"shell", "mpris", "blacklist"}, ListSetting{.items = cfg.shell.mpris.blacklist},
"mpris media player dbus session blacklist"));
entries.push_back(makeEntry("services", "brightness", tr("settings.schema.services.ddcutil.label"),
tr("settings.schema.services.ddcutil.description"), {"brightness", "enable_ddcutil"},
ToggleSetting{cfg.brightness.enableDdcutil}, "monitor ddcutil"));
env.ddcutilAvailable ? tr("settings.schema.services.ddcutil.description")
: tr("settings.schema.services.ddcutil.requires-ddcutil"),
{"brightness", "enable_ddcutil"},
ToggleSetting{.checked = cfg.brightness.enableDdcutil, .enabled = env.ddcutilAvailable},
"monitor ddcutil"));
if (!env.wlsunsetAvailable) {
// Show only the master toggle in a disabled state so users can discover the feature
// and learn the dependency requirement. The remaining settings are hidden until wlsunset is installed.
+1
View File
@@ -111,6 +111,7 @@ namespace settings {
// Runtime conditions that gate optional sections (e.g. compositor-specific features).
struct RegistryEnvironment {
bool niriBackdropSupported = false; // hide the [backdrop] section when false
bool ddcutilAvailable = false; // disable ddcutil toggle when ddcutil is not on PATH
bool wlsunsetAvailable = false; // hide night-light entries when wlsunset is not on PATH
std::vector<SelectOption> availableOutputs; // monitor selectors available on this machine
std::vector<SelectOption> communityPalettes;
+1
View File
@@ -948,6 +948,7 @@ void SettingsWindow::buildScene(std::uint32_t width, std::uint32_t height) {
}
settings::RegistryEnvironment env;
env.niriBackdropSupported = (m_wayland != nullptr && compositors::isNiri());
env.ddcutilAvailable = (m_dependencies != nullptr && m_dependencies->hasDdcutil());
env.wlsunsetAvailable = (m_dependencies != nullptr && m_dependencies->hasWlsunset());
for (const auto& paletteInfo : noctalia::theme::availableCommunityPalettes()) {
env.communityPalettes.push_back(settings::SelectOption{paletteInfo.name, paletteInfo.name});
+8 -6
View File
@@ -2,11 +2,11 @@
#include "config/config_service.h"
#include "core/log.h"
#include "core/process.h"
#include "core/timer_manager.h"
#include "dbus/system_bus.h"
#include "ipc/ipc_arg_parse.h"
#include "ipc/ipc_service.h"
#include "system/dependency_service.h"
#include "wayland/wayland_connection.h"
#include <algorithm>
@@ -586,6 +586,7 @@ namespace {
struct BrightnessService::Impl {
SystemBus* bus = nullptr;
WaylandConnection& wayland;
DependencyService* dependencies = nullptr;
BrightnessConfig activeConfig;
ChangeCallback changeCallback;
@@ -613,8 +614,8 @@ struct BrightnessService::Impl {
std::unordered_map<std::string, DdcJob> pendingRefreshes;
std::queue<WorkerCompletion> completions;
Impl(SystemBus* systemBus, WaylandConnection& wl, const BrightnessConfig& config)
: bus(systemBus), wayland(wl), activeConfig(config) {
Impl(SystemBus* systemBus, WaylandConnection& wl, const BrightnessConfig& config, DependencyService* deps)
: bus(systemBus), wayland(wl), dependencies(deps), activeConfig(config) {
setupPollFds();
workerThread = std::thread([this]() { workerLoop(); });
}
@@ -816,7 +817,7 @@ struct BrightnessService::Impl {
if (!activeConfig.enableDdcutil) {
return;
}
if (!process::commandExists("ddcutil")) {
if (dependencies != nullptr && !dependencies->hasDdcutil()) {
if (!warnedMissingDdcutil) {
kLog.warn("brightness.enable_ddcutil is set but ddcutil is not installed");
warnedMissingDdcutil = true;
@@ -1307,8 +1308,9 @@ struct BrightnessService::Impl {
}
};
BrightnessService::BrightnessService(SystemBus* bus, WaylandConnection& wayland, const BrightnessConfig& config)
: m_impl(new Impl(bus, wayland, config)) {
BrightnessService::BrightnessService(SystemBus* bus, WaylandConnection& wayland, const BrightnessConfig& config,
DependencyService* dependencies)
: m_impl(new Impl(bus, wayland, config, dependencies)) {
m_impl->rebuildState(false);
}
+3 -1
View File
@@ -6,6 +6,7 @@
#include <vector>
class IpcService;
class DependencyService;
class SystemBus;
class WaylandConnection;
struct BrightnessConfig;
@@ -29,7 +30,8 @@ class BrightnessService {
public:
using ChangeCallback = std::function<void()>;
BrightnessService(SystemBus* bus, WaylandConnection& wayland, const BrightnessConfig& config);
BrightnessService(SystemBus* bus, WaylandConnection& wayland, const BrightnessConfig& config,
DependencyService* dependencies = nullptr);
~BrightnessService();
BrightnessService(const BrightnessService&) = delete;
+2 -1
View File
@@ -11,7 +11,8 @@ namespace {
constexpr Logger kLog("dependencies");
// Optional CLI tools the shell knows about. Adding a new tracked tool is one line.
constexpr std::array<const char*, 1> kTrackedTools = {
constexpr std::array<const char*, 2> kTrackedTools = {
"ddcutil",
"wlsunset",
};
+1
View File
@@ -9,6 +9,7 @@ public:
DependencyService();
[[nodiscard]] bool has(std::string_view name) const;
[[nodiscard]] bool hasDdcutil() const { return has("ddcutil"); }
[[nodiscard]] bool hasWlsunset() const { return has("wlsunset"); }
void rescan();