Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ enable_ddcutil = false
# Per-monitor backend override:
# [brightness.monitor.eDP-1]
# backend = "backlight" # auto | none | backlight | ddcutil
# backlight_device = "intel_backlight" # explicit sysfs device name or path; run: noctalia msg brightness-list-backlight-devices
# [brightness.monitor.DP-1]
# backend = "ddcutil"

Expand Down
1 change: 1 addition & 0 deletions src/config/config_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1081,6 +1081,7 @@ constexpr EnumOption<BrightnessBackendPreference> kBrightnessBackendPreferences[
struct BrightnessMonitorOverride {
std::string match;
std::optional<BrightnessBackendPreference> backend;
std::optional<std::string> backlightDevice; // sysfs device name or path, e.g. "intel_backlight"

bool operator==(const BrightnessMonitorOverride&) const = default;
};
Expand Down
13 changes: 13 additions & 0 deletions src/config/schema/config_schema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,19 @@ namespace noctalia::config::schema {
static const Schema<BrightnessMonitorOverride> s = {
field(&BrightnessMonitorOverride::match, "match"),
optionalEnumField(&BrightnessMonitorOverride::backend, "backend", kBrightnessBackendPreferences),
custom<BrightnessMonitorOverride>(
"backlight_device",
[](const toml::table& tbl, BrightnessMonitorOverride& out, std::string_view, Diagnostics&) {
if (auto v = tbl["backlight_device"].value<std::string>()) {
out.backlightDevice = *v;
}
},
[](toml::table& tbl, const BrightnessMonitorOverride& in) {
if (in.backlightDevice.has_value()) {
tbl.insert_or_assign("backlight_device", *in.backlightDevice);
}
}
),
};
return s;
}
Expand Down
60 changes: 60 additions & 0 deletions src/system/brightness_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,34 @@ namespace {
return BrightnessBackendPreference::Auto;
}

// Returns the explicit backlight device name/path configured for this output, if any.
std::optional<std::string> backlightDeviceForOutput(const BrightnessConfig& config, const WaylandOutput* output) {
if (output == nullptr) {
return std::nullopt;
}

for (const auto& override : config.monitorOverrides) {
if (override.match.empty() || !outputMatchesSelector(override.match, *output)) {
continue;
}
if (override.backlightDevice.has_value()) {
return *override.backlightDevice;
}
break;
}

return std::nullopt;
}

// Returns the sysfs device name from either a bare name ("intel_backlight") or a path.
std::string_view extractBacklightDeviceName(std::string_view deviceSpec) {
const auto lastSlash = deviceSpec.rfind('/');
if (lastSlash != std::string_view::npos) {
return deviceSpec.substr(lastSlash + 1);
}
return deviceSpec;
}

void applyOutputMetadata(BrightnessDisplay& display, const WaylandOutput& output) {
display.label = output.description.empty() ? output.connectorName : output.description;
display.physicalWidth = output.width;
Expand Down Expand Up @@ -841,6 +869,16 @@ struct BrightnessService::Impl {
continue;
}

if (const auto explicitDevice = backlightDeviceForOutput(activeConfig, output); explicitDevice.has_value()) {
if (extractBacklightDeviceName(*explicitDevice) != name) {
kLog.debug(
"skipping backlight '{}' for connector {} (explicit device '{}' configured)", name, connectorName,
*explicitDevice
);
continue;
}
}

if (sessionProxy == nullptr) {
kLog.debug("skipping backlight '{}' because logind brightness control is unavailable", name);
continue;
Expand Down Expand Up @@ -1607,6 +1645,28 @@ void BrightnessService::registerIpc(IpcService& ipc, std::function<void()> onBat
"brightness-down", -1.0f, "brightness-down [current|*|all|monitor-selector] [step]",
"Decrease brightness (defaults to current monitor)"
);

ipc.registerHandler(
"brightness-list-backlight-devices",
[](const std::string& /*args*/) -> std::string {
const std::string backlightDir = "/sys/class/backlight";
DIR* dir = ::opendir(backlightDir.c_str());
if (dir == nullptr) {
return "error: no backlight devices available\n";
}
std::string result;
while (auto* entry = ::readdir(dir)) {
const std::string name = entry->d_name;
if (name == "." || name == "..") {
continue;
}
result += name + "\n";
}
::closedir(dir);
return result.empty() ? "error: no backlight devices available\n" : result;
},
"brightness-list-backlight-devices", "List available sysfs backlight device names"
);
}

void BrightnessService::setChangeCallback(ChangeCallback callback) { m_impl->changeCallback = std::move(callback); }
Expand Down