forked from quickshell/quickshell
		
	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