diff --git a/quicksettings/flashlight/CMakeLists.txt b/quicksettings/flashlight/CMakeLists.txt index aaa7bbb3..79cf9e5d 100644 --- a/quicksettings/flashlight/CMakeLists.txt +++ b/quicksettings/flashlight/CMakeLists.txt @@ -19,6 +19,7 @@ target_link_libraries(flashlightplugin KF6::ConfigGui KF6::I18n KF6::Notifications + udev ) set_property(TARGET flashlightplugin PROPERTY LIBRARY_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/org/kde/plasma/quicksetting/flashlight) diff --git a/quicksettings/flashlight/flashlightutil.cpp b/quicksettings/flashlight/flashlightutil.cpp index bff7fc3d..49859159 100644 --- a/quicksettings/flashlight/flashlightutil.cpp +++ b/quicksettings/flashlight/flashlightutil.cpp @@ -7,32 +7,44 @@ #include "flashlightutil.h" +#include #include +#include #include #include #include -// FIXME this is hardcoded to the PinePhone for now -static const char *FLASH_SYSFS_PATH = "/sys/devices/platform/led-controller/leds/white:flash/brightness"; +#define TORCH_SUBSYSTEM "leds" FlashlightUtil::FlashlightUtil(QObject *parent) : QObject{parent} - , m_torchEnabled{false} + , m_device{nullptr} + , m_isAvailable{false} { + findTorchDevice(); +} + +FlashlightUtil::~FlashlightUtil() +{ + if (m_device != nullptr) { + udev_device_unref(m_device); + } } void FlashlightUtil::toggleTorch() { - int fd = open(FLASH_SYSFS_PATH, O_WRONLY); - - if (fd < 0) { - qWarning() << "Unable to open file %s" << FLASH_SYSFS_PATH; + if (!isAvailable()) { + qWarning() << "Flashlight not available"; + return; + } + + int ret = udev_device_set_sysattr_value(m_device, "brightness", const_cast(m_torchEnabled ? "0" : m_maxBrightness)); + if (ret < 0) { + qWarning() << "Flashlight can't be toggled"; return; } - write(fd, m_torchEnabled ? "0" : "1", 1); - close(fd); m_torchEnabled = !m_torchEnabled; Q_EMIT torchChanged(m_torchEnabled); } @@ -44,5 +56,66 @@ bool FlashlightUtil::torchEnabled() const bool FlashlightUtil::isAvailable() const { - return QFileInfo::exists(FLASH_SYSFS_PATH); + return m_isAvailable; } + +void FlashlightUtil::findTorchDevice() +{ + if (m_device != nullptr) { + udev_device_unref(m_device); + } + m_device = nullptr; + m_isAvailable = false; + + struct udev *udev = udev_new(); + struct udev_enumerate *enumerate = udev_enumerate_new(udev); + + udev_enumerate_add_match_subsystem(enumerate, TORCH_SUBSYSTEM); + udev_enumerate_add_match_sysname(enumerate, "*:torch"); + udev_enumerate_add_match_sysname(enumerate, "*:flash"); + udev_enumerate_scan_devices(enumerate); + + struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate); + struct udev_list_entry *entry = udev_list_entry_get_next(devices); + + if (entry == nullptr) { + qWarning() << "No flashlight found"; + return; + } + + const char *path = udev_list_entry_get_name(entry); + + if (path == nullptr) { + qWarning() << "Failed to get path from udev entry"; + return; + } + + struct udev_device *device = udev_device_new_from_syspath(udev, path); + + if (device == nullptr) { + qWarning() << "Failed to get udev device"; + return; + } + + const char *maxBrightness = udev_device_get_sysattr_value(device, "max_brightness"); + + if (maxBrightness == nullptr) { + qWarning() << "Failed to read max_brightness from udev device"; + return; + } + + const char *brightness = udev_device_get_sysattr_value(device, "brightness"); + + if (brightness == nullptr) { + qWarning() << "Failed to read brightness from udev device"; + return; + } + + m_maxBrightness = maxBrightness; + m_device = device; + m_isAvailable = true; + m_torchEnabled = std::strcmp(brightness, "0") != 0; + + udev_enumerate_unref(enumerate); + udev_unref(udev); +} \ No newline at end of file diff --git a/quicksettings/flashlight/flashlightutil.h b/quicksettings/flashlight/flashlightutil.h index fa14102b..c2daa303 100644 --- a/quicksettings/flashlight/flashlightutil.h +++ b/quicksettings/flashlight/flashlightutil.h @@ -7,6 +7,7 @@ #pragma once #include +#include class FlashlightUtil : public QObject { @@ -16,6 +17,7 @@ class FlashlightUtil : public QObject public: FlashlightUtil(QObject *parent = nullptr); + ~FlashlightUtil(); Q_INVOKABLE void toggleTorch(); bool torchEnabled() const; @@ -25,5 +27,10 @@ Q_SIGNALS: void torchChanged(bool value); private: - bool m_torchEnabled; + struct udev_device *m_device{nullptr}; + const char *m_maxBrightness{nullptr}; + bool m_isAvailable{false}; + bool m_torchEnabled{false}; + + void findTorchDevice(); };