fix(backlight): also match the leds subsystem for keyboard backlights
The backlight module only enumerated and monitored the udev "backlight" subsystem, so keyboard-backlight LEDs in the "leds" class (e.g. white:kbd_backlight, platform::kbd_backlight) were never discovered and the module fell back to the default when pointed at one. Enumerate and monitor the "leds" subsystem in addition to "backlight". Those LEDs expose the same brightness/max_brightness attributes, so the read path is unchanged. Each device now records its subsystem so the login1 SetBrightness call targets the correct one. Automatic device selection still prefers a "backlight" device and only falls back to a "leds" device when named explicitly or when no screen backlight exists. Fixes #2848.
This commit is contained in:
@@ -73,6 +73,7 @@ static void upsert_device(std::vector<BacklightDevice>& devices, udev_device* de
|
||||
const char* actual = udev_device_get_sysattr_value(dev, actual_brightness_attr);
|
||||
const char* max = udev_device_get_sysattr_value(dev, "max_brightness");
|
||||
const char* power = udev_device_get_sysattr_value(dev, "bl_power");
|
||||
const char* subsystem = udev_device_get_subsystem(dev);
|
||||
|
||||
auto found = std::find_if(devices.begin(), devices.end(), [name](const BacklightDevice& device) {
|
||||
return device.name() == name;
|
||||
@@ -111,13 +112,18 @@ static void upsert_device(std::vector<BacklightDevice>& devices, udev_device* de
|
||||
if (power != nullptr) power_bool = std::stoi(power) == 0;
|
||||
} catch (const std::exception&) {
|
||||
}
|
||||
devices.emplace_back(name, actual_int, max_int, power_bool);
|
||||
devices.emplace_back(name, actual_int, max_int, power_bool,
|
||||
subsystem != nullptr ? subsystem : "backlight");
|
||||
}
|
||||
}
|
||||
|
||||
static void enumerate_devices(std::vector<BacklightDevice>& devices, udev* udev) {
|
||||
std::unique_ptr<udev_enumerate, UdevEnumerateDeleter> enumerate{udev_enumerate_new(udev)};
|
||||
udev_enumerate_add_match_subsystem(enumerate.get(), "backlight");
|
||||
// Also enumerate keyboard-backlight LEDs (e.g. "white:kbd_backlight"), which
|
||||
// live in the "leds" subsystem but expose the same brightness/max_brightness
|
||||
// attributes the read path uses.
|
||||
udev_enumerate_add_match_subsystem(enumerate.get(), "leds");
|
||||
udev_enumerate_scan_devices(enumerate.get());
|
||||
udev_list_entry* enum_devices = udev_enumerate_get_list_entry(enumerate.get());
|
||||
udev_list_entry* dev_list_entry;
|
||||
@@ -129,11 +135,18 @@ static void enumerate_devices(std::vector<BacklightDevice>& devices, udev* udev)
|
||||
}
|
||||
}
|
||||
|
||||
BacklightDevice::BacklightDevice(std::string name, int actual, int max, bool powered)
|
||||
: name_(std::move(name)), actual_(actual), max_(max), powered_(powered) {}
|
||||
BacklightDevice::BacklightDevice(std::string name, int actual, int max, bool powered,
|
||||
std::string subsystem)
|
||||
: name_(std::move(name)),
|
||||
actual_(actual),
|
||||
max_(max),
|
||||
powered_(powered),
|
||||
subsystem_(std::move(subsystem)) {}
|
||||
|
||||
std::string BacklightDevice::name() const { return name_; }
|
||||
|
||||
std::string BacklightDevice::subsystem() const { return subsystem_; }
|
||||
|
||||
int BacklightDevice::get_actual() const { return actual_; }
|
||||
|
||||
void BacklightDevice::set_actual(int actual) { actual_ = actual; }
|
||||
@@ -178,6 +191,10 @@ BacklightBackend::BacklightBackend(std::chrono::milliseconds interval,
|
||||
check_nn(mon.get(), "udev monitor new failed");
|
||||
check_gte(udev_monitor_filter_add_match_subsystem_devtype(mon.get(), "backlight", nullptr), 0,
|
||||
"udev failed to add monitor filter: ");
|
||||
// Also monitor the "leds" subsystem so keyboard-backlight changes are
|
||||
// reflected live, mirroring the enumeration above.
|
||||
check_gte(udev_monitor_filter_add_match_subsystem_devtype(mon.get(), "leds", nullptr), 0,
|
||||
"udev failed to add monitor filter: ");
|
||||
udev_monitor_enable_receiving(mon.get());
|
||||
|
||||
auto udev_fd = udev_monitor_get_fd(mon.get());
|
||||
@@ -235,9 +252,22 @@ const BacklightDevice* BacklightBackend::best_device(const std::vector<Backlight
|
||||
return &(*found);
|
||||
}
|
||||
|
||||
const auto max = std::max_element(
|
||||
devices.begin(), devices.end(),
|
||||
[](const BacklightDevice& l, const BacklightDevice& r) { return l.get_max() < r.get_max(); });
|
||||
// No device was explicitly configured (or the configured name did not match).
|
||||
// Automatic selection must keep preferring a screen backlight (the "backlight"
|
||||
// subsystem) so that a keyboard-backlight LED, now that the "leds" subsystem is
|
||||
// also enumerated, is never accidentally picked as the default. Only fall back
|
||||
// to other subsystems (e.g. "leds") when no "backlight" device exists at all.
|
||||
const auto max = std::max_element(devices.begin(), devices.end(),
|
||||
[](const BacklightDevice& l, const BacklightDevice& r) {
|
||||
const bool l_backlight = l.subsystem() == "backlight";
|
||||
const bool r_backlight = r.subsystem() == "backlight";
|
||||
if (l_backlight != r_backlight) {
|
||||
// Rank any non-backlight device below every backlight
|
||||
// device.
|
||||
return r_backlight;
|
||||
}
|
||||
return l.get_max() < r.get_max();
|
||||
});
|
||||
|
||||
return max == devices.end() ? nullptr : &(*max);
|
||||
}
|
||||
@@ -260,7 +290,7 @@ void BacklightBackend::set_scaled_brightness(const std::string& preferred_device
|
||||
if (best != nullptr) {
|
||||
const auto max = best->get_max();
|
||||
const auto abs_val = static_cast<int>(std::round(brightness * max / 100.0F));
|
||||
set_brightness_internal(best->name(), abs_val, best->get_max());
|
||||
set_brightness_internal(best->name(), abs_val, best->get_max(), best->subsystem());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,12 +305,12 @@ void BacklightBackend::set_brightness(const std::string& preferred_device, Chang
|
||||
|
||||
const int new_brightness = change_type == ChangeType::Increase ? best->get_actual() + abs_step
|
||||
: best->get_actual() - abs_step;
|
||||
set_brightness_internal(best->name(), new_brightness, max);
|
||||
set_brightness_internal(best->name(), new_brightness, max, best->subsystem());
|
||||
}
|
||||
}
|
||||
|
||||
void BacklightBackend::set_brightness_internal(const std::string& device_name, int brightness,
|
||||
int max_brightness) {
|
||||
int max_brightness, const std::string& subsystem) {
|
||||
if (!login_proxy_) {
|
||||
spdlog::error("Login proxy not available, cannot set brightness");
|
||||
return;
|
||||
@@ -289,7 +319,7 @@ void BacklightBackend::set_brightness_internal(const std::string& device_name, i
|
||||
brightness = std::clamp(brightness, 0, max_brightness);
|
||||
|
||||
auto call_args = Glib::VariantContainerBase(
|
||||
g_variant_new("(ssu)", "backlight", device_name.c_str(), brightness));
|
||||
g_variant_new("(ssu)", subsystem.c_str(), device_name.c_str(), brightness));
|
||||
|
||||
login_proxy_->call_sync("SetBrightness", call_args);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user