diff --git a/src/services/upower/core.cpp b/src/services/upower/core.cpp index b8ba9abe..06cd23ab 100644 --- a/src/services/upower/core.cpp +++ b/src/services/upower/core.cpp @@ -53,13 +53,6 @@ UPower::UPower() { } void UPower::init() { - QObject::connect( - &this->pOnBattery, - &dbus::AbstractDBusProperty::changed, - this, - &UPower::onBatteryChanged - ); - this->serviceProperties.setInterface(this->service); this->serviceProperties.updateAllViaGetAll(); @@ -143,8 +136,6 @@ UPowerDevice* UPower::displayDevice() { return this->mDisplayDevice; } ObjectModel* UPower::devices() { return &this->readyDevices; } -bool UPower::onBattery() const { return this->pOnBattery.get(); } - UPower* UPower::instance() { static UPower* instance = new UPower(); // NOLINT return instance; @@ -173,6 +164,4 @@ ObjectModel* UPowerQml::devices() { // NOLINT return UPower::instance()->devices(); } -bool UPowerQml::onBattery() { return UPower::instance()->onBattery(); } - } // namespace qs::service::upower diff --git a/src/services/upower/core.hpp b/src/services/upower/core.hpp index 302311ea..46ff6e20 100644 --- a/src/services/upower/core.hpp +++ b/src/services/upower/core.hpp @@ -21,7 +21,7 @@ class UPower: public QObject { public: [[nodiscard]] UPowerDevice* displayDevice(); [[nodiscard]] ObjectModel* devices(); - [[nodiscard]] bool onBattery() const; + QS_BINDABLE_GETTER(bool, bOnBattery, onBattery, bindableOnBattery); static UPower* instance(); @@ -44,8 +44,10 @@ private: QHash mDevices; ObjectModel readyDevices {this}; - dbus::DBusPropertyGroup serviceProperties; - dbus::DBusProperty pOnBattery {this->serviceProperties, "OnBattery"}; + Q_OBJECT_BINDABLE_PROPERTY(UPower, bool, bOnBattery, &UPower::onBatteryChanged); + + QS_DBUS_BINDABLE_PROPERTY_GROUP(UPower, serviceProperties); + QS_DBUS_PROPERTY_BINDING(UPower, pOnBattery, bOnBattery, serviceProperties, "OnBattery"); DBusUPowerService* service = nullptr; }; @@ -64,7 +66,7 @@ class UPowerQml: public QObject { QSDOC_TYPE_OVERRIDE(ObjectModel*); Q_PROPERTY(UntypedObjectModel* devices READ devices CONSTANT); /// If the system is currently running on battery power, or discharging. - Q_PROPERTY(bool onBattery READ onBattery NOTIFY onBatteryChanged); + Q_PROPERTY(bool onBattery READ onBattery NOTIFY onBatteryChanged BINDABLE bindableOnBattery); // clang-format on public: @@ -72,7 +74,11 @@ public: [[nodiscard]] UPowerDevice* displayDevice(); [[nodiscard]] ObjectModel* devices(); - [[nodiscard]] static bool onBattery(); + [[nodiscard]] static bool onBattery() { return UPower::instance()->onBattery(); } + + [[nodiscard]] static QBindable bindableOnBattery() { + return UPower::instance()->bindableOnBattery(); + } signals: void displayDeviceChanged(); diff --git a/src/services/upower/device.cpp b/src/services/upower/device.cpp index 8d205b6f..cd97fbbb 100644 --- a/src/services/upower/device.cpp +++ b/src/services/upower/device.cpp @@ -74,25 +74,18 @@ UPowerDevice::UPowerDevice(const QString& path, QObject* parent): QObject(parent 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); + this->bIsLaptopBattery.setBinding([this]() { + return this->bType == UPowerDeviceType::Battery && this->bPowerSupply; + }); - QObject::connect(&this->deviceProperties, &DBusPropertyGroup::getAllFinished, this, &UPowerDevice::ready); - // clang-format on + this->bHealthSupported.setBinding([this]() { return this->bHealthPercentage != 0; }); + + QObject::connect( + &this->deviceProperties, + &DBusPropertyGroup::getAllFinished, + this, + &UPowerDevice::ready + ); this->deviceProperties.setInterface(this->device); this->deviceProperties.updateAllViaGetAll(); @@ -102,33 +95,48 @@ 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(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() / 100; } -bool UPowerDevice::isPresent() const { return this->pIsPresent.get(); } - -UPowerDeviceState::Enum UPowerDevice::state() const { - return static_cast(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 + +namespace qs::dbus { + +using namespace qs::service::upower; + +DBusResult DBusDataTransform::fromWire(qreal wire) { + return DBusResult(wire * 0.01); +} + +qreal DBusDataTransform::toWire(const qreal& value) { return value * 100; } + +DBusResult +DBusDataTransform::fromWire(quint32 wire) { + if (wire != UPowerDeviceType::Battery && wire >= UPowerDeviceState::Unknown + && wire <= UPowerDeviceState::PendingDischarge) + { + return DBusResult(static_cast(wire)); + } + + return DBusResult( + QDBusError(QDBusError::InvalidArgs, QString("Invalid UPowerDeviceState: %1").arg(wire)) + ); +} + +quint32 DBusDataTransform::toWire(const UPowerDeviceState::Enum& value) { + return static_cast(value); +} + +DBusResult DBusDataTransform::fromWire(quint32 wire +) { + if (wire >= UPowerDeviceType::Unknown && wire <= UPowerDeviceType::BluetoothGeneric) { + return DBusResult(static_cast(wire)); + } + + return DBusResult( + QDBusError(QDBusError::InvalidArgs, QString("Invalid UPowerDeviceType: %1").arg(wire)) + ); +} + +quint32 DBusDataTransform::toWire(const UPowerDeviceType::Enum& value) { + return static_cast(value); +} + +} // namespace qs::dbus diff --git a/src/services/upower/device.hpp b/src/services/upower/device.hpp index c971dd0e..8610bbcf 100644 --- a/src/services/upower/device.hpp +++ b/src/services/upower/device.hpp @@ -80,49 +80,83 @@ public: Q_INVOKABLE static QString toString(qs::service::upower::UPowerDeviceType::Enum type); }; +struct PowerPercentage; + +} // namespace qs::service::upower + +namespace qs::dbus { + +template <> +struct DBusDataTransform { + using Wire = quint32; + using Data = qs::service::upower::UPowerDeviceState::Enum; + static DBusResult fromWire(Wire wire); + static Wire toWire(const Data& value); +}; + +template <> +struct DBusDataTransform { + using Wire = quint32; + using Data = qs::service::upower::UPowerDeviceType::Enum; + static DBusResult fromWire(Wire wire); + static Wire toWire(const Data& value); +}; + +template <> +struct DBusDataTransform { + using Wire = qreal; + using Data = qreal; + static DBusResult fromWire(Wire wire); + static Wire toWire(const Data& value); +}; + +} // namespace qs::dbus + +namespace qs::service::upower { + ///! A device exposed through the UPower system service. class UPowerDevice: public QObject { Q_OBJECT; // clang-format off /// The type of device. - Q_PROPERTY(qs::service::upower::UPowerDeviceType::Enum type READ type NOTIFY typeChanged); + Q_PROPERTY(qs::service::upower::UPowerDeviceType::Enum type READ type NOTIFY typeChanged BINDABLE bindableType); /// If the device is a power supply for your computer and can provide charge. - Q_PROPERTY(bool powerSupply READ powerSupply NOTIFY powerSupplyChanged); + Q_PROPERTY(bool powerSupply READ powerSupply NOTIFY powerSupplyChanged BINDABLE bindablePowerSupply); /// Current energy level of the device in watt-hours. - Q_PROPERTY(qreal energy READ energy NOTIFY energyChanged); + Q_PROPERTY(qreal energy READ energy NOTIFY energyChanged BINDABLE bindableEnergy); /// Maximum energy capacity of the device in watt-hours - Q_PROPERTY(qreal energyCapacity READ energyCapacity NOTIFY energyCapacityChanged); + Q_PROPERTY(qreal energyCapacity READ energyCapacity NOTIFY energyCapacityChanged BINDABLE bindableEnergyCapacity); /// Rate of energy change in watts (positive when charging, negative when discharging). - Q_PROPERTY(qreal changeRate READ changeRate NOTIFY changeRateChanged); + Q_PROPERTY(qreal changeRate READ changeRate NOTIFY changeRateChanged BINDABLE bindableChangeRate); /// 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); + Q_PROPERTY(qreal timeToEmpty READ timeToEmpty NOTIFY timeToEmptyChanged BINDABLE bindableTimeToEmpty); /// 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); + Q_PROPERTY(qreal timeToFull READ timeToFull NOTIFY timeToFullChanged BINDABLE bindableTimeToFull); /// Current charge level as a percentage. /// /// This would be equivalent to @@energy / @@energyCapacity. - Q_PROPERTY(qreal percentage READ percentage NOTIFY percentageChanged); + Q_PROPERTY(qreal percentage READ percentage NOTIFY percentageChanged BINDABLE bindablePercentage); /// 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); + Q_PROPERTY(bool isPresent READ isPresent NOTIFY isPresentChanged BINDABLE bindableIsPresent); /// Current state of the device. - Q_PROPERTY(qs::service::upower::UPowerDeviceState::Enum state READ state NOTIFY stateChanged); + Q_PROPERTY(qs::service::upower::UPowerDeviceState::Enum state READ state NOTIFY stateChanged BINDABLE bindableState); /// 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); + Q_PROPERTY(qreal healthPercentage READ healthPercentage NOTIFY healthPercentageChanged BINDABLE bindableHealthPercentage); + Q_PROPERTY(bool healthSupported READ healthSupported NOTIFY healthSupportedChanged BINDABLE bindableHealthSupported); /// 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); + Q_PROPERTY(QString iconName READ iconName NOTIFY iconNameChanged BINDABLE bindableIconName); /// 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); + Q_PROPERTY(bool isLaptopBattery READ isLaptopBattery NOTIFY isLaptopBatteryChanged BINDABLE bindableIsLaptopBattery); /// Native path of the device specific to your OS. - Q_PROPERTY(QString nativePath READ nativePath NOTIFY nativePathChanged); + Q_PROPERTY(QString nativePath READ nativePath NOTIFY nativePathChanged BINDABLE bindableNativePath); // clang-format on QML_ELEMENT; QML_UNCREATABLE("UPowerDevices can only be acquired from UPower"); @@ -134,21 +168,21 @@ public: [[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; + QS_BINDABLE_GETTER(UPowerDeviceType::Enum, bType, type, bindableType); + QS_BINDABLE_GETTER(bool, bPowerSupply, powerSupply, bindablePowerSupply); + QS_BINDABLE_GETTER(qreal, bEnergy, energy, bindableEnergy); + QS_BINDABLE_GETTER(qreal, bEnergyCapacity, energyCapacity, bindableEnergyCapacity); + QS_BINDABLE_GETTER(qreal, bChangeRate, changeRate, bindableChangeRate); + QS_BINDABLE_GETTER(qlonglong, bTimeToEmpty, timeToEmpty, bindableTimeToEmpty); + QS_BINDABLE_GETTER(qlonglong, bTimeToFull, timeToFull, bindableTimeToFull); + QS_BINDABLE_GETTER(qreal, bPercentage, percentage, bindablePercentage); + QS_BINDABLE_GETTER(bool, bIsPresent, isPresent, bindableIsPresent); + QS_BINDABLE_GETTER(UPowerDeviceState::Enum, bState, state, bindableState); + QS_BINDABLE_GETTER(qreal, bHealthPercentage, healthPercentage, bindableHealthPercentage); + QS_BINDABLE_GETTER(bool, bHealthSupported, healthSupported, bindableHealthSupported); + QS_BINDABLE_GETTER(QString, bIconName, iconName, bindableIconName); + QS_BINDABLE_GETTER(bool, bIsLaptopBattery, isLaptopBattery, bindableIsLaptopBattery); + QS_BINDABLE_GETTER(QString, bNativePath, nativePath, bindableNativePath); signals: QSDOC_HIDE void ready(); @@ -170,20 +204,38 @@ signals: void nativePathChanged(); private: - dbus::DBusPropertyGroup deviceProperties; - dbus::DBusProperty pType {this->deviceProperties, "Type"}; - dbus::DBusProperty pPowerSupply {this->deviceProperties, "PowerSupply"}; - dbus::DBusProperty pEnergy {this->deviceProperties, "Energy"}; - dbus::DBusProperty pEnergyCapacity {this->deviceProperties, "EnergyFull"}; - dbus::DBusProperty pChangeRate {this->deviceProperties, "EnergyRate"}; - dbus::DBusProperty pTimeToEmpty {this->deviceProperties, "TimeToEmpty"}; - dbus::DBusProperty pTimeToFull {this->deviceProperties, "TimeToFull"}; - dbus::DBusProperty pPercentage {this->deviceProperties, "Percentage"}; - dbus::DBusProperty pIsPresent {this->deviceProperties, "IsPresent"}; - dbus::DBusProperty pState {this->deviceProperties, "State"}; - dbus::DBusProperty pHealthPercentage {this->deviceProperties, "Capacity"}; - dbus::DBusProperty pIconName {this->deviceProperties, "IconName"}; - dbus::DBusProperty pNativePath {this->deviceProperties, "NativePath"}; + // clang-format off + Q_OBJECT_BINDABLE_PROPERTY(UPowerDevice, UPowerDeviceType::Enum, bType, &UPowerDevice::typeChanged); + Q_OBJECT_BINDABLE_PROPERTY(UPowerDevice, bool, bPowerSupply, &UPowerDevice::powerSupplyChanged); + Q_OBJECT_BINDABLE_PROPERTY(UPowerDevice, qreal, bEnergy, &UPowerDevice::energyChanged); + Q_OBJECT_BINDABLE_PROPERTY(UPowerDevice, qreal, bEnergyCapacity, &UPowerDevice::energyCapacityChanged); + Q_OBJECT_BINDABLE_PROPERTY(UPowerDevice, qreal, bChangeRate, &UPowerDevice::changeRateChanged); + Q_OBJECT_BINDABLE_PROPERTY(UPowerDevice, qlonglong, bTimeToEmpty, &UPowerDevice::timeToEmptyChanged); + Q_OBJECT_BINDABLE_PROPERTY(UPowerDevice, qlonglong, bTimeToFull, &UPowerDevice::timeToFullChanged); + Q_OBJECT_BINDABLE_PROPERTY(UPowerDevice, qreal, bPercentage, &UPowerDevice::percentageChanged); + Q_OBJECT_BINDABLE_PROPERTY(UPowerDevice, bool, bIsPresent, &UPowerDevice::isPresentChanged); + Q_OBJECT_BINDABLE_PROPERTY(UPowerDevice, UPowerDeviceState::Enum, bState, &UPowerDevice::stateChanged); + Q_OBJECT_BINDABLE_PROPERTY(UPowerDevice, qreal, bHealthPercentage, &UPowerDevice::healthPercentageChanged); + Q_OBJECT_BINDABLE_PROPERTY(UPowerDevice, bool, bHealthSupported, &UPowerDevice::healthSupportedChanged); + Q_OBJECT_BINDABLE_PROPERTY(UPowerDevice, QString, bIconName, &UPowerDevice::iconNameChanged); + Q_OBJECT_BINDABLE_PROPERTY(UPowerDevice, bool, bIsLaptopBattery, &UPowerDevice::isLaptopBatteryChanged); + Q_OBJECT_BINDABLE_PROPERTY(UPowerDevice, QString, bNativePath, &UPowerDevice::nativePathChanged); + + QS_DBUS_BINDABLE_PROPERTY_GROUP(UPowerDevice, deviceProperties); + QS_DBUS_PROPERTY_BINDING(UPowerDevice, pType, bType, deviceProperties, "Type"); + QS_DBUS_PROPERTY_BINDING(UPowerDevice, pPowerSupply, bPowerSupply, deviceProperties, "PowerSupply"); + QS_DBUS_PROPERTY_BINDING(UPowerDevice, pEnergy, bEnergy, deviceProperties, "Energy"); + QS_DBUS_PROPERTY_BINDING(UPowerDevice, pEnergyCapacity, bEnergyCapacity, deviceProperties, "EnergyFull"); + QS_DBUS_PROPERTY_BINDING(UPowerDevice, pChangeRate, bChangeRate, deviceProperties, "EnergyRate"); + QS_DBUS_PROPERTY_BINDING(UPowerDevice, pTimeToEmpty, bTimeToEmpty, deviceProperties, "TimeToEmpty"); + QS_DBUS_PROPERTY_BINDING(UPowerDevice, pTimeToFull, bTimeToFull, deviceProperties, "TimeToFull"); + QS_DBUS_PROPERTY_BINDING(UPowerDevice, PowerPercentage, pPercentage, bPercentage, deviceProperties, "Percentage", true); + QS_DBUS_PROPERTY_BINDING(UPowerDevice, pIsPresent, bIsPresent, deviceProperties, "IsPresent"); + QS_DBUS_PROPERTY_BINDING(UPowerDevice, pState, bState, deviceProperties, "State"); + QS_DBUS_PROPERTY_BINDING(UPowerDevice, pHealthPercentage, bHealthPercentage, deviceProperties, "Capacity"); + QS_DBUS_PROPERTY_BINDING(UPowerDevice, pIconName, bIconName, deviceProperties, "IconName"); + QS_DBUS_PROPERTY_BINDING(UPowerDevice, pNativePath, bNativePath, deviceProperties, "NativePath"); + // clang-format on DBusUPowerDevice* device = nullptr; };