forked from quickshell/quickshell
		
	dbus/properties: add QObjectBindableProperty based dbus property
Many times more lightweight than the original QObject-based one.
This commit is contained in:
		
							parent
							
								
									4163713bc4
								
							
						
					
					
						commit
						1955deee74
					
				
					 3 changed files with 151 additions and 15 deletions
				
			
		| 
						 | 
					@ -2,22 +2,45 @@
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <type_traits>
 | 
					#include <type_traits>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <bit>
 | 
				
			||||||
#include <qlatin1stringview.h>
 | 
					#include <qlatin1stringview.h>
 | 
				
			||||||
#include <qobject.h>
 | 
					#include <qobject.h>
 | 
				
			||||||
#include <qproperty.h>
 | 
					#include <qproperty.h>
 | 
				
			||||||
 | 
					#include <qstringview.h>
 | 
				
			||||||
#include <qtclasshelpermacros.h>
 | 
					#include <qtclasshelpermacros.h>
 | 
				
			||||||
#include <qtmetamacros.h>
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <size_t Length>
 | 
					template <size_t length>
 | 
				
			||||||
struct StringLiteral {
 | 
					struct StringLiteral {
 | 
				
			||||||
	constexpr StringLiteral(const char (&str)[Length]) { // NOLINT
 | 
						constexpr StringLiteral(const char (&str)[length]) { // NOLINT
 | 
				
			||||||
		std::copy_n(str, Length, this->value);
 | 
							std::copy_n(str, length, this->value);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	constexpr operator const char*() const noexcept { return this->value; }
 | 
						constexpr operator const char*() const noexcept { return this->value; }
 | 
				
			||||||
	operator QLatin1StringView() const { return QLatin1String(this->value, Length); }
 | 
						operator QLatin1StringView() const { return QLatin1String(this->value, length); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char value[Length]; // NOLINT
 | 
						char value[length]; // NOLINT
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <size_t length>
 | 
				
			||||||
 | 
					struct StringLiteral16 {
 | 
				
			||||||
 | 
						constexpr StringLiteral16(const char16_t (&str)[length]) { // NOLINT
 | 
				
			||||||
 | 
							std::copy_n(str, length, this->value);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] constexpr const QChar* qCharPtr() const noexcept {
 | 
				
			||||||
 | 
							return std::bit_cast<const QChar*>(&this->value);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] Q_ALWAYS_INLINE operator QString() const noexcept {
 | 
				
			||||||
 | 
							return QString::fromRawData(this->qCharPtr(), static_cast<qsizetype>(length - 1));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] Q_ALWAYS_INLINE operator QStringView() const noexcept {
 | 
				
			||||||
 | 
							return QStringView(this->qCharPtr(), static_cast<qsizetype>(length - 1));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char16_t value[length]; // NOLINT
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NOLINTBEGIN
 | 
					// NOLINTBEGIN
 | 
				
			||||||
| 
						 | 
					@ -149,11 +172,10 @@ private:
 | 
				
			||||||
// NOLINTEND
 | 
					// NOLINTEND
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
class MemberPointerTraits;
 | 
					struct MemberPointerTraits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename T, typename C>
 | 
					template <typename T, typename C>
 | 
				
			||||||
class MemberPointerTraits<T C::*> {
 | 
					struct MemberPointerTraits<T C::*> {
 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	using Class = C;
 | 
						using Class = C;
 | 
				
			||||||
	using Type = T;
 | 
						using Type = T;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -162,6 +162,10 @@ void DBusPropertyGroup::attachProperty(AbstractDBusProperty* property) {
 | 
				
			||||||
	property->group = this;
 | 
						property->group = this;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DBusPropertyGroup::attachProperty(DBusPropertyCore* property) {
 | 
				
			||||||
 | 
						this->properties.append(property);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DBusPropertyGroup::updateAllDirect() {
 | 
					void DBusPropertyGroup::updateAllDirect() {
 | 
				
			||||||
	qCDebug(logDbusProperties).noquote()
 | 
						qCDebug(logDbusProperties).noquote()
 | 
				
			||||||
	    << "Updating all properties of" << this->toString() << "via individual queries";
 | 
						    << "Updating all properties of" << this->toString() << "via individual queries";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
#include <utility>
 | 
					#include <utility>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <bit>
 | 
				
			||||||
#include <qcontainerfwd.h>
 | 
					#include <qcontainerfwd.h>
 | 
				
			||||||
#include <qdbusabstractinterface.h>
 | 
					#include <qdbusabstractinterface.h>
 | 
				
			||||||
#include <qdbuserror.h>
 | 
					#include <qdbuserror.h>
 | 
				
			||||||
| 
						 | 
					@ -14,10 +15,14 @@
 | 
				
			||||||
#include <qlogging.h>
 | 
					#include <qlogging.h>
 | 
				
			||||||
#include <qloggingcategory.h>
 | 
					#include <qloggingcategory.h>
 | 
				
			||||||
#include <qobject.h>
 | 
					#include <qobject.h>
 | 
				
			||||||
 | 
					#include <qoverload.h>
 | 
				
			||||||
 | 
					#include <qstringview.h>
 | 
				
			||||||
#include <qtclasshelpermacros.h>
 | 
					#include <qtclasshelpermacros.h>
 | 
				
			||||||
#include <qtmetamacros.h>
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
#include <qvariant.h>
 | 
					#include <qvariant.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../core/util.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DBusPropertiesInterface;
 | 
					class DBusPropertiesInterface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Q_DECLARE_LOGGING_CATEGORY(logDbusProperties);
 | 
					Q_DECLARE_LOGGING_CATEGORY(logDbusProperties);
 | 
				
			||||||
| 
						 | 
					@ -132,21 +137,94 @@ private:
 | 
				
			||||||
	friend class DBusPropertyGroup;
 | 
						friend class DBusPropertyGroup;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace bindable_p {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					struct BindableParams;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <template <typename, typename, auto, auto> class B, typename C, typename T, auto O, auto S>
 | 
				
			||||||
 | 
					struct BindableParams<B<C, T, O, S>> {
 | 
				
			||||||
 | 
						using Class = C;
 | 
				
			||||||
 | 
						using Type = T;
 | 
				
			||||||
 | 
						static constexpr size_t OFFSET = O;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace bindable_p
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <
 | 
				
			||||||
 | 
					    auto offset,
 | 
				
			||||||
 | 
					    auto bindablePtr,
 | 
				
			||||||
 | 
					    auto updatedPtr,
 | 
				
			||||||
 | 
					    auto groupPtr,
 | 
				
			||||||
 | 
					    StringLiteral16 Name,
 | 
				
			||||||
 | 
					    bool required>
 | 
				
			||||||
 | 
					class DBusBindableProperty: public DBusPropertyCore {
 | 
				
			||||||
 | 
						using PtrMeta = MemberPointerTraits<decltype(bindablePtr)>;
 | 
				
			||||||
 | 
						using Bindable = PtrMeta::Type;
 | 
				
			||||||
 | 
						using Owner = PtrMeta::Class;
 | 
				
			||||||
 | 
						using BindableMeta = bindable_p::BindableParams<Bindable>;
 | 
				
			||||||
 | 
						using DataType = BindableMeta::Type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						explicit DBusBindableProperty() { this->group()->attachProperty(this); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] QString name() const override { return Name; };
 | 
				
			||||||
 | 
						[[nodiscard]] QStringView nameRef() const override { return Name; };
 | 
				
			||||||
 | 
						[[nodiscard]] bool isRequired() const override { return required; };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] QString valueString() override {
 | 
				
			||||||
 | 
							QString str;
 | 
				
			||||||
 | 
							QDebug(&str) << this->bindable()->value();
 | 
				
			||||||
 | 
							return str;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void write() { this->group()->pushPropertyUpdate(this); }
 | 
				
			||||||
 | 
						void requestUpdate() { this->group()->requestPropertyUpdate(this); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						QDBusError store(const QVariant& variant) override {
 | 
				
			||||||
 | 
							auto result = demarshallVariant<DataType>(variant);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (result.isValid()) {
 | 
				
			||||||
 | 
								this->bindable()->setValue(std::move(result.value));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if constexpr (updatedPtr != nullptr) {
 | 
				
			||||||
 | 
									(this->owner()->*updatedPtr)();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return result.error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						QVariant serialize() override { return QVariant::fromValue(this->bindable()->value()); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						[[nodiscard]] constexpr Owner* owner() const {
 | 
				
			||||||
 | 
							auto* self = std::bit_cast<char*>(this);
 | 
				
			||||||
 | 
							return std::bit_cast<Owner*>(self - offset()); // NOLINT
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] constexpr DBusPropertyGroup* group() const { return &(this->owner()->*groupPtr); }
 | 
				
			||||||
 | 
						[[nodiscard]] constexpr Bindable* bindable() const { return &(this->owner()->*bindablePtr); }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DBusPropertyGroup: public QObject {
 | 
					class DBusPropertyGroup: public QObject {
 | 
				
			||||||
	Q_OBJECT;
 | 
						Q_OBJECT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	explicit DBusPropertyGroup(
 | 
						explicit DBusPropertyGroup(QVector<DBusPropertyCore*> properties = {}, QObject* parent = nullptr);
 | 
				
			||||||
	    QVector<DBusPropertyCore*> properties = QVector<DBusPropertyCore*>(),
 | 
						explicit DBusPropertyGroup(QObject* parent): DBusPropertyGroup({}, parent) {}
 | 
				
			||||||
	    QObject* parent = nullptr
 | 
					 | 
				
			||||||
	);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void setInterface(QDBusAbstractInterface* interface);
 | 
						void setInterface(QDBusAbstractInterface* interface);
 | 
				
			||||||
	void attachProperty(AbstractDBusProperty* property);
 | 
						void attachProperty(AbstractDBusProperty* property);
 | 
				
			||||||
 | 
						void attachProperty(DBusPropertyCore* property);
 | 
				
			||||||
	void updateAllDirect();
 | 
						void updateAllDirect();
 | 
				
			||||||
	void updateAllViaGetAll();
 | 
						void updateAllViaGetAll();
 | 
				
			||||||
	[[nodiscard]] QString toString() const;
 | 
						[[nodiscard]] QString toString() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void pushPropertyUpdate(DBusPropertyCore* property);
 | 
				
			||||||
 | 
						void requestPropertyUpdate(DBusPropertyCore* property);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
signals:
 | 
					signals:
 | 
				
			||||||
	void getAllFinished();
 | 
						void getAllFinished();
 | 
				
			||||||
	void getAllFailed(QDBusError error);
 | 
						void getAllFailed(QDBusError error);
 | 
				
			||||||
| 
						 | 
					@ -160,8 +238,6 @@ private slots:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	void updatePropertySet(const QVariantMap& properties, bool complainMissing);
 | 
						void updatePropertySet(const QVariantMap& properties, bool complainMissing);
 | 
				
			||||||
	void requestPropertyUpdate(DBusPropertyCore* property);
 | 
					 | 
				
			||||||
	void pushPropertyUpdate(DBusPropertyCore* property);
 | 
					 | 
				
			||||||
	void tryUpdateProperty(DBusPropertyCore* property, const QVariant& variant) const;
 | 
						void tryUpdateProperty(DBusPropertyCore* property, const QVariant& variant) const;
 | 
				
			||||||
	[[nodiscard]] QString propertyString(const DBusPropertyCore* property) const;
 | 
						[[nodiscard]] QString propertyString(const DBusPropertyCore* property) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -224,7 +300,41 @@ protected:
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	T value;
 | 
						T value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	friend class DBusPropertyGroup;
 | 
						friend class DBusPropertyCore;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace qs::dbus
 | 
					} // namespace qs::dbus
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NOLINTBEGIN
 | 
				
			||||||
 | 
					#define QS_DBUS_BINDABLE_PROPERTY_GROUP(Class, name) qs::dbus::DBusPropertyGroup name {this};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define QS_DBUS_PROPERTY_BINDING_P(Class, property, bindable, updated, group, name, required)      \
 | 
				
			||||||
 | 
						static constexpr size_t _qs_property_##property##_offset() { return offsetof(Class, property); } \
 | 
				
			||||||
 | 
					                                                                                                   \
 | 
				
			||||||
 | 
						qs::dbus::DBusBindableProperty<                                                                  \
 | 
				
			||||||
 | 
						    &Class::_qs_property_##property##_offset,                                                    \
 | 
				
			||||||
 | 
						    &Class::bindable,                                                                            \
 | 
				
			||||||
 | 
						    updated,                                                                                     \
 | 
				
			||||||
 | 
						    &Class::group,                                                                               \
 | 
				
			||||||
 | 
						    u##name,                                                                                     \
 | 
				
			||||||
 | 
						    required>                                                                                    \
 | 
				
			||||||
 | 
						    property;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define QS_DBUS_PROPERTY_BINDING_7(Class, property, bindable, updated, group, name, required)      \
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING_P(Class, property, bindable, &Class::updated, group, name, required)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define QS_DBUS_PROPERTY_BINDING_6(Class, property, bindable, group, name, required)               \
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING_P(Class, property, bindable, nullptr, group, name, required)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define QS_DBUS_PROPERTY_BINDING_5(Class, property, bindable, group, name)                         \
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING_6(Class, property, bindable, group, name, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Q_OBJECT_BINDABLE_PROPERTY elides the warning for the exact same reason,
 | 
				
			||||||
 | 
					// so we consider it safe to disable the warning.
 | 
				
			||||||
 | 
					// clang-format off
 | 
				
			||||||
 | 
					#define QS_DBUS_PROPERTY_BINDING(...) \
 | 
				
			||||||
 | 
						QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
 | 
				
			||||||
 | 
						QT_OVERLOADED_MACRO(QS_DBUS_PROPERTY_BINDING, __VA_ARGS__) \
 | 
				
			||||||
 | 
						QT_WARNING_POP
 | 
				
			||||||
 | 
					// clang-format on
 | 
				
			||||||
 | 
					// NOLINTEND
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue