service/upower: add upower service
This commit is contained in:
parent
497c9c4e50
commit
24f54f579f
10 changed files with 638 additions and 0 deletions
|
@ -25,6 +25,7 @@ option(SERVICE_PIPEWIRE "PipeWire service" ON)
|
|||
option(SERVICE_MPRIS "Mpris service" ON)
|
||||
option(SERVICE_PAM "Pam service" ON)
|
||||
option(SERVICE_GREETD "Greet service" ON)
|
||||
option(SERVICE_UPOWER "UPower service" ON)
|
||||
|
||||
message(STATUS "Quickshell configuration")
|
||||
message(STATUS " Jemalloc: ${USE_JEMALLOC}")
|
||||
|
@ -43,6 +44,7 @@ message(STATUS " PipeWire: ${SERVICE_PIPEWIRE}")
|
|||
message(STATUS " Mpris: ${SERVICE_MPRIS}")
|
||||
message(STATUS " Pam: ${SERVICE_PAM}")
|
||||
message(STATUS " Greetd: ${SERVICE_GREETD}")
|
||||
message(STATUS " UPower: ${SERVICE_UPOWER}")
|
||||
message(STATUS " Hyprland: ${HYPRLAND}")
|
||||
if (HYPRLAND)
|
||||
message(STATUS " IPC: ${HYPRLAND_IPC}")
|
||||
|
|
|
@ -17,3 +17,7 @@ endif()
|
|||
if (SERVICE_GREETD)
|
||||
add_subdirectory(greetd)
|
||||
endif()
|
||||
|
||||
if (SERVICE_UPOWER)
|
||||
add_subdirectory(upower)
|
||||
endif()
|
||||
|
|
39
src/services/upower/CMakeLists.txt
Normal file
39
src/services/upower/CMakeLists.txt
Normal file
|
@ -0,0 +1,39 @@
|
|||
set_source_files_properties(org.freedesktop.UPower.xml PROPERTIES
|
||||
CLASSNAME DBusUPowerService
|
||||
NO_NAMESPACE TRUE
|
||||
)
|
||||
|
||||
qt_add_dbus_interface(DBUS_INTERFACES
|
||||
org.freedesktop.UPower.xml
|
||||
dbus_service
|
||||
)
|
||||
|
||||
set_source_files_properties(org.freedesktop.UPower.Device.xml PROPERTIES
|
||||
CLASSNAME DBusUPowerDevice
|
||||
NO_NAMESPACE TRUE
|
||||
)
|
||||
|
||||
qt_add_dbus_interface(DBUS_INTERFACES
|
||||
org.freedesktop.UPower.Device.xml
|
||||
dbus_device
|
||||
)
|
||||
|
||||
qt_add_library(quickshell-service-upower STATIC
|
||||
core.cpp
|
||||
device.cpp
|
||||
${DBUS_INTERFACES}
|
||||
)
|
||||
|
||||
# dbus headers
|
||||
target_include_directories(quickshell-service-upower PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
qt_add_qml_module(quickshell-service-upower
|
||||
URI Quickshell.Services.UPower
|
||||
VERSION 0.1
|
||||
)
|
||||
|
||||
target_link_libraries(quickshell-service-upower PRIVATE ${QT_DEPS} quickshell-dbus)
|
||||
target_link_libraries(quickshell PRIVATE quickshell-service-upowerplugin)
|
||||
|
||||
qs_pch(quickshell-service-upower)
|
||||
qs_pch(quickshell-service-upowerplugin)
|
165
src/services/upower/core.cpp
Normal file
165
src/services/upower/core.cpp
Normal file
|
@ -0,0 +1,165 @@
|
|||
#include "core.hpp"
|
||||
|
||||
#include <qcontainerfwd.h>
|
||||
#include <qdbusconnection.h>
|
||||
#include <qdbusconnectioninterface.h>
|
||||
#include <qdbusextratypes.h>
|
||||
#include <qdbuspendingcall.h>
|
||||
#include <qdbuspendingreply.h>
|
||||
#include <qdbusservicewatcher.h>
|
||||
#include <qlogging.h>
|
||||
#include <qloggingcategory.h>
|
||||
#include <qobject.h>
|
||||
#include <qqmllist.h>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
#include "../../core/model.hpp"
|
||||
#include "../../dbus/properties.hpp"
|
||||
#include "dbus_service.h"
|
||||
#include "device.hpp"
|
||||
|
||||
namespace qs::service::upower {
|
||||
|
||||
Q_LOGGING_CATEGORY(logUPower, "quickshell.service.upower", QtWarningMsg);
|
||||
|
||||
UPower::UPower() {
|
||||
qCDebug(logUPower) << "Starting UPower";
|
||||
|
||||
auto bus = QDBusConnection::systemBus();
|
||||
|
||||
if (!bus.isConnected()) {
|
||||
qCWarning(logUPower) << "Could not connect to DBus. UPower service will not work.";
|
||||
return;
|
||||
}
|
||||
|
||||
this->service =
|
||||
new DBusUPowerService("org.freedesktop.UPower", "/org/freedesktop/UPower", bus, this);
|
||||
|
||||
if (!this->service->isValid()) {
|
||||
qCWarning(logUPower) << "Cannot connect to the UPower service.";
|
||||
return;
|
||||
}
|
||||
|
||||
QObject::connect(
|
||||
&this->pOnBattery,
|
||||
&dbus::AbstractDBusProperty::changed,
|
||||
this,
|
||||
&UPower::onBatteryChanged
|
||||
);
|
||||
|
||||
this->serviceProperties.setInterface(this->service);
|
||||
this->serviceProperties.updateAllViaGetAll();
|
||||
|
||||
this->registerExisting();
|
||||
}
|
||||
|
||||
void UPower::registerExisting() {
|
||||
this->registerDevice("/org/freedesktop/UPower/devices/DisplayDevice");
|
||||
|
||||
auto pending = this->service->EnumerateDevices();
|
||||
auto* call = new QDBusPendingCallWatcher(pending, this);
|
||||
|
||||
auto responseCallback = [this](QDBusPendingCallWatcher* call) {
|
||||
const QDBusPendingReply<QList<QDBusObjectPath>> reply = *call;
|
||||
|
||||
if (reply.isError()) {
|
||||
qCWarning(logUPower) << "Failed to enumerate devices:" << reply.error().message();
|
||||
} else {
|
||||
for (const QDBusObjectPath& devicePath: reply.value()) {
|
||||
this->registerDevice(devicePath.path());
|
||||
}
|
||||
}
|
||||
|
||||
delete call;
|
||||
};
|
||||
|
||||
QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback);
|
||||
}
|
||||
|
||||
void UPower::onDeviceReady() {
|
||||
auto* device = qobject_cast<UPowerDevice*>(this->sender());
|
||||
|
||||
if (device->path() == "/org/freedesktop/UPower/devices/DisplayDevice") {
|
||||
this->mDisplayDevice = device;
|
||||
emit this->displayDeviceChanged();
|
||||
qCDebug(logUPower) << "Display UPowerDevice" << device->path() << "ready";
|
||||
return;
|
||||
}
|
||||
|
||||
this->readyDevices.insertObject(device);
|
||||
qCDebug(logUPower) << "UPowerDevice" << device->path() << "ready";
|
||||
}
|
||||
|
||||
void UPower::onDeviceDestroyed(QObject* object) {
|
||||
auto* device = static_cast<UPowerDevice*>(object); // NOLINT
|
||||
|
||||
this->mDevices.remove(device->path());
|
||||
|
||||
if (device == this->mDisplayDevice) {
|
||||
this->mDisplayDevice = nullptr;
|
||||
emit this->displayDeviceChanged();
|
||||
qCDebug(logUPower) << "Display UPowerDevice" << device->path() << "destroyed";
|
||||
return;
|
||||
}
|
||||
|
||||
this->readyDevices.removeObject(device);
|
||||
qCDebug(logUPower) << "UPowerDevice" << device->path() << "destroyed";
|
||||
}
|
||||
|
||||
void UPower::registerDevice(const QString& path) {
|
||||
if (this->mDevices.contains(path)) {
|
||||
qCDebug(logUPower) << "Skipping duplicate registration of UPowerDevice" << path;
|
||||
return;
|
||||
}
|
||||
|
||||
auto* device = new UPowerDevice(path, this);
|
||||
if (!device->isValid()) {
|
||||
qCWarning(logUPower) << "Ignoring invalid UPowerDevice registration of" << path;
|
||||
delete device;
|
||||
return;
|
||||
}
|
||||
|
||||
this->mDevices.insert(path, device);
|
||||
QObject::connect(device, &UPowerDevice::ready, this, &UPower::onDeviceReady);
|
||||
QObject::connect(device, &QObject::destroyed, this, &UPower::onDeviceDestroyed);
|
||||
|
||||
qCDebug(logUPower) << "Registered UPowerDevice" << path;
|
||||
}
|
||||
|
||||
UPowerDevice* UPower::displayDevice() { return this->mDisplayDevice; }
|
||||
|
||||
ObjectModel<UPowerDevice>* UPower::devices() { return &this->readyDevices; }
|
||||
|
||||
bool UPower::onBattery() const { return this->pOnBattery.get(); }
|
||||
|
||||
UPower* UPower::instance() {
|
||||
static UPower* instance = new UPower(); // NOLINT
|
||||
return instance;
|
||||
}
|
||||
|
||||
UPowerQml::UPowerQml(QObject* parent): QObject(parent) {
|
||||
QObject::connect(
|
||||
UPower::instance(),
|
||||
&UPower::displayDeviceChanged,
|
||||
this,
|
||||
&UPowerQml::displayDeviceChanged
|
||||
);
|
||||
QObject::connect(
|
||||
UPower::instance(),
|
||||
&UPower::onBatteryChanged,
|
||||
this,
|
||||
&UPowerQml::onBatteryChanged
|
||||
);
|
||||
}
|
||||
|
||||
UPowerDevice* UPowerQml::displayDevice() { // NOLINT
|
||||
return UPower::instance()->displayDevice();
|
||||
}
|
||||
|
||||
ObjectModel<UPowerDevice>* UPowerQml::devices() { // NOLINT
|
||||
return UPower::instance()->devices();
|
||||
}
|
||||
|
||||
bool UPowerQml::onBattery() { return UPower::instance()->onBattery(); }
|
||||
|
||||
} // namespace qs::service::upower
|
77
src/services/upower/core.hpp
Normal file
77
src/services/upower/core.hpp
Normal file
|
@ -0,0 +1,77 @@
|
|||
#pragma once
|
||||
|
||||
#include <qdbusservicewatcher.h>
|
||||
#include <qhash.h>
|
||||
#include <qobject.h>
|
||||
#include <qqmlintegration.h>
|
||||
#include <qqmllist.h>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
#include "../../core/model.hpp"
|
||||
#include "../../dbus/properties.hpp"
|
||||
#include "dbus_service.h"
|
||||
#include "device.hpp"
|
||||
|
||||
namespace qs::service::upower {
|
||||
|
||||
class UPower: public QObject {
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
[[nodiscard]] UPowerDevice* displayDevice();
|
||||
[[nodiscard]] ObjectModel<UPowerDevice>* devices();
|
||||
[[nodiscard]] bool onBattery() const;
|
||||
|
||||
static UPower* instance();
|
||||
|
||||
signals:
|
||||
void displayDeviceChanged();
|
||||
void onBatteryChanged();
|
||||
|
||||
private slots:
|
||||
void onDeviceReady();
|
||||
void onDeviceDestroyed(QObject* object);
|
||||
|
||||
private:
|
||||
explicit UPower();
|
||||
|
||||
void registerExisting();
|
||||
void registerDevice(const QString& path);
|
||||
|
||||
UPowerDevice* mDisplayDevice = nullptr;
|
||||
QHash<QString, UPowerDevice*> mDevices;
|
||||
ObjectModel<UPowerDevice> readyDevices {this};
|
||||
|
||||
dbus::DBusPropertyGroup serviceProperties;
|
||||
dbus::DBusProperty<bool> pOnBattery {this->serviceProperties, "OnBattery"};
|
||||
|
||||
DBusUPowerService* service = nullptr;
|
||||
};
|
||||
|
||||
class UPowerQml: public QObject {
|
||||
Q_OBJECT;
|
||||
QML_NAMED_ELEMENT(UPower);
|
||||
QML_SINGLETON;
|
||||
/// UPower's DisplayDevice for your system. Can be `null`.
|
||||
///
|
||||
/// This is an aggregate device and not a physical one, meaning you will not find it in `devices`.
|
||||
/// It is typically the device that is used for displaying information in desktop environments.
|
||||
Q_PROPERTY(UPowerDevice* displayDevice READ displayDevice NOTIFY displayDeviceChanged);
|
||||
/// All connected UPower devices.
|
||||
Q_PROPERTY(ObjectModel<UPowerDevice>* devices READ devices CONSTANT);
|
||||
/// If the system is currently running on battery power, or discharging.
|
||||
Q_PROPERTY(bool onBattery READ onBattery NOTIFY onBatteryChanged);
|
||||
|
||||
public:
|
||||
explicit UPowerQml(QObject* parent = nullptr);
|
||||
|
||||
[[nodiscard]] UPowerDevice* displayDevice();
|
||||
[[nodiscard]] ObjectModel<UPowerDevice>* devices();
|
||||
[[nodiscard]] static bool onBattery();
|
||||
|
||||
signals:
|
||||
void displayDeviceChanged();
|
||||
void onBatteryChanged();
|
||||
};
|
||||
|
||||
} // namespace qs::service::upower
|
134
src/services/upower/device.cpp
Normal file
134
src/services/upower/device.cpp
Normal file
|
@ -0,0 +1,134 @@
|
|||
#include "device.hpp"
|
||||
|
||||
#include <qcontainerfwd.h>
|
||||
#include <qdbusconnection.h>
|
||||
#include <qlogging.h>
|
||||
#include <qloggingcategory.h>
|
||||
#include <qobject.h>
|
||||
#include <qstring.h>
|
||||
#include <qtypes.h>
|
||||
|
||||
#include "../../dbus/properties.hpp"
|
||||
#include "dbus_device.h"
|
||||
|
||||
using namespace qs::dbus;
|
||||
|
||||
namespace qs::service::upower {
|
||||
|
||||
Q_LOGGING_CATEGORY(logUPowerDevice, "quickshell.service.upower.device", QtWarningMsg);
|
||||
|
||||
QString UPowerDeviceState::toString(UPowerDeviceState::Enum status) {
|
||||
switch (status) {
|
||||
case UPowerDeviceState::Unknown: return "Unknown";
|
||||
case UPowerDeviceState::Charging: return "Charging";
|
||||
case UPowerDeviceState::Discharging: return "Discharging";
|
||||
case UPowerDeviceState::Empty: return "Empty";
|
||||
case UPowerDeviceState::FullyCharged: return "Fully Charged";
|
||||
case UPowerDeviceState::PendingCharge: return "Pending Charge";
|
||||
case UPowerDeviceState::PendingDischarge: return "Pending Discharge";
|
||||
default: return "Invalid Status";
|
||||
}
|
||||
}
|
||||
|
||||
QString UPowerDeviceType::toString(UPowerDeviceType::Enum type) {
|
||||
switch (type) {
|
||||
case UPowerDeviceType::Unknown: return "Unknown";
|
||||
case UPowerDeviceType::LinePower: return "Line Power";
|
||||
case UPowerDeviceType::Battery: return "Battery";
|
||||
case UPowerDeviceType::Ups: return "Ups";
|
||||
case UPowerDeviceType::Monitor: return "Monitor";
|
||||
case UPowerDeviceType::Mouse: return "Mouse";
|
||||
case UPowerDeviceType::Keyboard: return "Keyboard";
|
||||
case UPowerDeviceType::Pda: return "Pda";
|
||||
case UPowerDeviceType::Phone: return "Phone";
|
||||
case UPowerDeviceType::MediaPlayer: return "Media Player";
|
||||
case UPowerDeviceType::Tablet: return "Tablet";
|
||||
case UPowerDeviceType::Computer: return "Computer";
|
||||
case UPowerDeviceType::GamingInput: return "Gaming Input";
|
||||
case UPowerDeviceType::Pen: return "Pen";
|
||||
case UPowerDeviceType::Touchpad: return "Touchpad";
|
||||
case UPowerDeviceType::Modem: return "Modem";
|
||||
case UPowerDeviceType::Network: return "Network";
|
||||
case UPowerDeviceType::Headset: return "Headset";
|
||||
case UPowerDeviceType::Speakers: return "Speakers";
|
||||
case UPowerDeviceType::Headphones: return "Headphones";
|
||||
case UPowerDeviceType::Video: return "Video";
|
||||
case UPowerDeviceType::OtherAudio: return "Other Audio";
|
||||
case UPowerDeviceType::RemoteControl: return "Remote Control";
|
||||
case UPowerDeviceType::Printer: return "Printer";
|
||||
case UPowerDeviceType::Scanner: return "Scanner";
|
||||
case UPowerDeviceType::Camera: return "Camera";
|
||||
case UPowerDeviceType::Wearable: return "Wearable";
|
||||
case UPowerDeviceType::Toy: return "Toy";
|
||||
case UPowerDeviceType::BluetoothGeneric: return "Bluetooth Generic";
|
||||
default: return "Invalid Type";
|
||||
}
|
||||
}
|
||||
|
||||
UPowerDevice::UPowerDevice(const QString& path, QObject* parent): QObject(parent) {
|
||||
this->device =
|
||||
new DBusUPowerDevice("org.freedesktop.UPower", path, QDBusConnection::systemBus(), this);
|
||||
|
||||
if (!this->device->isValid()) {
|
||||
qCWarning(logUPowerDevice) << "Cannot create UPowerDevice for" << path;
|
||||
return;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
QObject::connect(&this->pType, &AbstractDBusProperty::changed, this, &UPowerDevice::typeChanged);
|
||||
QObject::connect(&this->pPowerSupply, &AbstractDBusProperty::changed, this, &UPowerDevice::powerSupplyChanged);
|
||||
QObject::connect(&this->pEnergy, &AbstractDBusProperty::changed, this, &UPowerDevice::energyChanged);
|
||||
QObject::connect(&this->pEnergyCapacity, &AbstractDBusProperty::changed, this, &UPowerDevice::energyCapacityChanged);
|
||||
QObject::connect(&this->pChangeRate, &AbstractDBusProperty::changed, this, &UPowerDevice::changeRateChanged);
|
||||
QObject::connect(&this->pTimeToEmpty, &AbstractDBusProperty::changed, this, &UPowerDevice::timeToEmptyChanged);
|
||||
QObject::connect(&this->pTimeToFull, &AbstractDBusProperty::changed, this, &UPowerDevice::timeToFullChanged);
|
||||
QObject::connect(&this->pPercentage, &AbstractDBusProperty::changed, this, &UPowerDevice::percentageChanged);
|
||||
QObject::connect(&this->pIsPresent, &AbstractDBusProperty::changed, this, &UPowerDevice::isPresentChanged);
|
||||
QObject::connect(&this->pState, &AbstractDBusProperty::changed, this, &UPowerDevice::stateChanged);
|
||||
QObject::connect(&this->pHealthPercentage, &AbstractDBusProperty::changed, this, &UPowerDevice::healthPercentageChanged);
|
||||
QObject::connect(&this->pHealthPercentage, &AbstractDBusProperty::changed, this, &UPowerDevice::healthSupportedChanged);
|
||||
QObject::connect(&this->pIconName, &AbstractDBusProperty::changed, this, &UPowerDevice::iconNameChanged);
|
||||
QObject::connect(&this->pType, &AbstractDBusProperty::changed, this, &UPowerDevice::isLaptopBatteryChanged);
|
||||
QObject::connect(&this->pNativePath, &AbstractDBusProperty::changed, this, &UPowerDevice::nativePathChanged);
|
||||
|
||||
QObject::connect(&this->deviceProperties, &DBusPropertyGroup::getAllFinished, this, &UPowerDevice::ready);
|
||||
// clang-format on
|
||||
|
||||
this->deviceProperties.setInterface(this->device);
|
||||
this->deviceProperties.updateAllViaGetAll();
|
||||
}
|
||||
|
||||
bool UPowerDevice::isValid() const { return this->device->isValid(); }
|
||||
QString UPowerDevice::address() const { return this->device->service(); }
|
||||
QString UPowerDevice::path() const { return this->device->path(); }
|
||||
|
||||
UPowerDeviceType::Enum UPowerDevice::type() const {
|
||||
return static_cast<UPowerDeviceType::Enum>(this->pType.get());
|
||||
}
|
||||
|
||||
bool UPowerDevice::powerSupply() const { return this->pPowerSupply.get(); }
|
||||
qreal UPowerDevice::energy() const { return this->pEnergy.get(); }
|
||||
qreal UPowerDevice::energyCapacity() const { return this->pEnergyCapacity.get(); }
|
||||
qreal UPowerDevice::changeRate() const { return this->pChangeRate.get(); }
|
||||
qlonglong UPowerDevice::timeToEmpty() const { return this->pTimeToEmpty.get(); }
|
||||
qlonglong UPowerDevice::timeToFull() const { return this->pTimeToFull.get(); }
|
||||
qreal UPowerDevice::percentage() const { return this->pPercentage.get(); }
|
||||
bool UPowerDevice::isPresent() const { return this->pIsPresent.get(); }
|
||||
|
||||
UPowerDeviceState::Enum UPowerDevice::state() const {
|
||||
return static_cast<UPowerDeviceState::Enum>(this->pState.get());
|
||||
}
|
||||
|
||||
qreal UPowerDevice::healthPercentage() const { return this->pHealthPercentage.get(); }
|
||||
|
||||
bool UPowerDevice::healthSupported() const { return this->healthPercentage() != 0; }
|
||||
|
||||
QString UPowerDevice::iconName() const { return this->pIconName.get(); }
|
||||
|
||||
bool UPowerDevice::isLaptopBattery() const {
|
||||
return this->pType.get() == UPowerDeviceType::Battery && this->pPowerSupply.get();
|
||||
}
|
||||
|
||||
QString UPowerDevice::nativePath() const { return this->pNativePath.get(); }
|
||||
|
||||
} // namespace qs::service::upower
|
187
src/services/upower/device.hpp
Normal file
187
src/services/upower/device.hpp
Normal file
|
@ -0,0 +1,187 @@
|
|||
#pragma once
|
||||
|
||||
#include <qcontainerfwd.h>
|
||||
#include <qobject.h>
|
||||
#include <qqmlintegration.h>
|
||||
#include <qtmetamacros.h>
|
||||
#include <qtypes.h>
|
||||
|
||||
#include "../../core/doc.hpp"
|
||||
#include "../../dbus/properties.hpp"
|
||||
#include "dbus_device.h"
|
||||
|
||||
namespace qs::service::upower {
|
||||
|
||||
class UPowerDeviceState: public QObject {
|
||||
Q_OBJECT;
|
||||
QML_ELEMENT;
|
||||
QML_SINGLETON;
|
||||
|
||||
public:
|
||||
enum Enum {
|
||||
Unknown = 0,
|
||||
Charging = 1,
|
||||
Discharging = 2,
|
||||
Empty = 3,
|
||||
FullyCharged = 4,
|
||||
/// The device is waiting to be charged after it was plugged in.
|
||||
PendingCharge = 5,
|
||||
/// The device is waiting to be discharged after being unplugged.
|
||||
PendingDischarge = 6,
|
||||
};
|
||||
Q_ENUM(Enum);
|
||||
|
||||
Q_INVOKABLE static QString toString(UPowerDeviceState::Enum status);
|
||||
};
|
||||
|
||||
class UPowerDeviceType: public QObject {
|
||||
Q_OBJECT;
|
||||
QML_ELEMENT;
|
||||
QML_SINGLETON;
|
||||
|
||||
public:
|
||||
enum Enum {
|
||||
Unknown = 0,
|
||||
LinePower = 1,
|
||||
Battery = 2,
|
||||
Ups = 3,
|
||||
Monitor = 4,
|
||||
Mouse = 5,
|
||||
Keyboard = 6,
|
||||
Pda = 7,
|
||||
Phone = 8,
|
||||
MediaPlayer = 9,
|
||||
Tablet = 10,
|
||||
Computer = 11,
|
||||
GamingInput = 12,
|
||||
Pen = 13,
|
||||
Touchpad = 14,
|
||||
Modem = 15,
|
||||
Network = 16,
|
||||
Headset = 17,
|
||||
Speakers = 18,
|
||||
Headphones = 19,
|
||||
Video = 20,
|
||||
OtherAudio = 21,
|
||||
RemoteControl = 22,
|
||||
Printer = 23,
|
||||
Scanner = 24,
|
||||
Camera = 25,
|
||||
Wearable = 26,
|
||||
Toy = 27,
|
||||
BluetoothGeneric = 28,
|
||||
};
|
||||
Q_ENUM(Enum);
|
||||
|
||||
Q_INVOKABLE static QString toString(UPowerDeviceType::Enum type);
|
||||
};
|
||||
|
||||
///! A device exposed through the UPower system service.
|
||||
class UPowerDevice: public QObject {
|
||||
Q_OBJECT;
|
||||
// clang-format off
|
||||
/// The type of device.
|
||||
Q_PROPERTY(UPowerDeviceType::Enum type READ type NOTIFY typeChanged);
|
||||
/// If the device is a power supply for your computer and can provide charge.
|
||||
Q_PROPERTY(bool powerSupply READ powerSupply NOTIFY powerSupplyChanged);
|
||||
/// Current energy level of the device in watt-hours.
|
||||
Q_PROPERTY(qreal energy READ energy NOTIFY energyChanged);
|
||||
/// Maximum energy capacity of the device in watt-hours
|
||||
Q_PROPERTY(qreal energyCapacity READ energyCapacity NOTIFY energyCapacityChanged);
|
||||
/// Rate of energy change in watts (positive when charging, negative when discharging).
|
||||
Q_PROPERTY(qreal changeRate READ changeRate NOTIFY changeRateChanged);
|
||||
/// Estimated time until the device is fully discharged, in seconds.
|
||||
///
|
||||
/// Will be set to `0` if charging.
|
||||
Q_PROPERTY(qreal timeToEmpty READ timeToEmpty NOTIFY timeToEmptyChanged);
|
||||
/// Estimated time until the device is fully charged, in seconds.
|
||||
///
|
||||
/// Will be set to `0` if discharging.
|
||||
Q_PROPERTY(qreal timeToFull READ timeToFull NOTIFY timeToFullChanged);
|
||||
/// Current charge level as a percentage.
|
||||
///
|
||||
/// This would be equivalent to `energy / energyCapacity`.
|
||||
Q_PROPERTY(qreal percentage READ percentage NOTIFY percentageChanged);
|
||||
/// If the power source is present in the bay or slot, useful for hot-removable batteries.
|
||||
///
|
||||
/// If the device `type` is not `Battery`, then the property will be invalid.
|
||||
Q_PROPERTY(bool isPresent READ isPresent NOTIFY isPresentChanged);
|
||||
/// Current state of the device.
|
||||
Q_PROPERTY(UPowerDeviceState::Enum state READ state NOTIFY stateChanged);
|
||||
/// Health of the device as a percentage of its original health.
|
||||
Q_PROPERTY(qreal healthPercentage READ healthPercentage NOTIFY healthPercentageChanged);
|
||||
Q_PROPERTY(bool healthSupported READ healthSupported NOTIFY healthSupportedChanged);
|
||||
/// Name of the icon representing the current state of the device, or an empty string if not provided.
|
||||
Q_PROPERTY(QString iconName READ iconName NOTIFY iconNameChanged);
|
||||
/// If the device is a laptop battery or not. Use this to check if your device is a valid battery.
|
||||
///
|
||||
/// This will be equivalent to `type == Battery && powerSupply == true`.
|
||||
Q_PROPERTY(bool isLaptopBattery READ isLaptopBattery NOTIFY isLaptopBatteryChanged);
|
||||
/// Native path of the device specific to your OS.
|
||||
Q_PROPERTY(QString nativePath READ nativePath NOTIFY nativePathChanged);
|
||||
// clang-format on
|
||||
QML_ELEMENT;
|
||||
QML_UNCREATABLE("UPowerDevices can only be acquired from UPower");
|
||||
|
||||
public:
|
||||
explicit UPowerDevice(const QString& path, QObject* parent = nullptr);
|
||||
|
||||
[[nodiscard]] bool isValid() const;
|
||||
[[nodiscard]] QString address() const;
|
||||
[[nodiscard]] QString path() const;
|
||||
|
||||
[[nodiscard]] UPowerDeviceType::Enum type() const;
|
||||
[[nodiscard]] bool powerSupply() const;
|
||||
[[nodiscard]] qreal energy() const;
|
||||
[[nodiscard]] qreal energyCapacity() const;
|
||||
[[nodiscard]] qreal changeRate() const;
|
||||
[[nodiscard]] qlonglong timeToEmpty() const;
|
||||
[[nodiscard]] qlonglong timeToFull() const;
|
||||
[[nodiscard]] qreal percentage() const;
|
||||
[[nodiscard]] bool isPresent() const;
|
||||
[[nodiscard]] UPowerDeviceState::Enum state() const;
|
||||
[[nodiscard]] qreal healthPercentage() const;
|
||||
[[nodiscard]] bool healthSupported() const;
|
||||
[[nodiscard]] QString iconName() const;
|
||||
[[nodiscard]] bool isLaptopBattery() const;
|
||||
[[nodiscard]] QString nativePath() const;
|
||||
|
||||
signals:
|
||||
QSDOC_HIDE void ready();
|
||||
|
||||
void typeChanged();
|
||||
void powerSupplyChanged();
|
||||
void energyChanged();
|
||||
void energyCapacityChanged();
|
||||
void changeRateChanged();
|
||||
void timeToEmptyChanged();
|
||||
void timeToFullChanged();
|
||||
void percentageChanged();
|
||||
void isPresentChanged();
|
||||
void stateChanged();
|
||||
void healthPercentageChanged();
|
||||
void healthSupportedChanged();
|
||||
void iconNameChanged();
|
||||
void isLaptopBatteryChanged();
|
||||
void nativePathChanged();
|
||||
|
||||
private:
|
||||
dbus::DBusPropertyGroup deviceProperties;
|
||||
dbus::DBusProperty<quint32> pType {this->deviceProperties, "Type"};
|
||||
dbus::DBusProperty<bool> pPowerSupply {this->deviceProperties, "PowerSupply"};
|
||||
dbus::DBusProperty<qreal> pEnergy {this->deviceProperties, "Energy"};
|
||||
dbus::DBusProperty<qreal> pEnergyCapacity {this->deviceProperties, "EnergyFull"};
|
||||
dbus::DBusProperty<qreal> pChangeRate {this->deviceProperties, "EnergyRate"};
|
||||
dbus::DBusProperty<qlonglong> pTimeToEmpty {this->deviceProperties, "TimeToEmpty"};
|
||||
dbus::DBusProperty<qlonglong> pTimeToFull {this->deviceProperties, "TimeToFull"};
|
||||
dbus::DBusProperty<qreal> pPercentage {this->deviceProperties, "Percentage"};
|
||||
dbus::DBusProperty<bool> pIsPresent {this->deviceProperties, "IsPresent"};
|
||||
dbus::DBusProperty<quint32> pState {this->deviceProperties, "State"};
|
||||
dbus::DBusProperty<qreal> pHealthPercentage {this->deviceProperties, "Capacity"};
|
||||
dbus::DBusProperty<QString> pIconName {this->deviceProperties, "IconName"};
|
||||
dbus::DBusProperty<QString> pNativePath {this->deviceProperties, "NativePath"};
|
||||
|
||||
DBusUPowerDevice* device = nullptr;
|
||||
};
|
||||
|
||||
} // namespace qs::service::upower
|
7
src/services/upower/module.md
Normal file
7
src/services/upower/module.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
name = "Quickshell.Services.UPower"
|
||||
description = "UPower Service"
|
||||
headers = [
|
||||
"core.hpp",
|
||||
"device.hpp",
|
||||
]
|
||||
-----
|
16
src/services/upower/org.freedesktop.UPower.Device.xml
Normal file
16
src/services/upower/org.freedesktop.UPower.Device.xml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<node>
|
||||
<interface name="org.freedesktop.UPower.Device">
|
||||
<property name="Type" type="u" access="read"/>
|
||||
<property name="PowerSupply" type="b" access="read"/>
|
||||
<property name="Energy" type="d" access="read"/>
|
||||
<property name="EnergyFull" type="d" access="read"/>
|
||||
<property name="EnergyRate" type="d" access="read"/>
|
||||
<property name="TimeToEmpty" type="x" access="read"/>
|
||||
<property name="TimeToFull" type="x" access="read"/>
|
||||
<property name="Percentage" type="d" access="read"/>
|
||||
<property name="IsPresent" type="b" access="read"/>
|
||||
<property name="State" type="u" access="read"/>
|
||||
<property name="Capacity" type = "d" access="read"/>
|
||||
<property name="IconName" type="s" access="read"/>
|
||||
</interface>
|
||||
</node>
|
7
src/services/upower/org.freedesktop.UPower.xml
Normal file
7
src/services/upower/org.freedesktop.UPower.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<node>
|
||||
<interface name="org.freedesktop.UPower">
|
||||
<method name="EnumerateDevices">
|
||||
<arg direction="out" type="ao" name="devices"/>
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
Loading…
Add table
Add a link
Reference in a new issue