bluetooth: add bluetooth integration

Missing support for things that require an agent, but has most basics.

Closes #17
This commit is contained in:
outfoxxed 2025-07-01 00:07:20 -07:00
parent 1d02292fbf
commit f681e2016f
No known key found for this signature in database
GPG key ID: 4C88A185FB89301E
22 changed files with 1623 additions and 14 deletions

View file

@ -2,13 +2,24 @@ set_source_files_properties(org.freedesktop.DBus.Properties.xml PROPERTIES
CLASSNAME DBusPropertiesInterface
)
set_source_files_properties(org.freedesktop.DBus.ObjectManager.xml PROPERTIES
CLASSNAME DBusObjectManagerInterface
INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/dbus_objectmanager_types.hpp
)
qt_add_dbus_interface(DBUS_INTERFACES
org.freedesktop.DBus.Properties.xml
dbus_properties
)
qt_add_dbus_interface(DBUS_INTERFACES
org.freedesktop.DBus.ObjectManager.xml
dbus_objectmanager
)
qt_add_library(quickshell-dbus STATIC
properties.cpp
objectmanager.cpp
bus.cpp
${DBUS_INTERFACES}
)

View file

@ -0,0 +1,10 @@
#pragma once
#include <qdbusextratypes.h>
#include <qhash.h>
#include <qmap.h>
#include <qstring.h>
#include <qvariant.h>
using DBusObjectManagerInterfaces = QHash<QString, QVariantMap>;
using DBusObjectManagerObjects = QHash<QDBusObjectPath, DBusObjectManagerInterfaces>;

View file

@ -0,0 +1,86 @@
#include "objectmanager.hpp"
#include <qcontainerfwd.h>
#include <qdbusconnection.h>
#include <qdbusmetatype.h>
#include <qdbuspendingcall.h>
#include <qdbuspendingreply.h>
#include <qlogging.h>
#include <qloggingcategory.h>
#include <qtmetamacros.h>
#include "dbus_objectmanager.h"
#include "dbus_objectmanager_types.hpp"
namespace {
Q_LOGGING_CATEGORY(logDbusObjectManager, "quickshell.dbus.objectmanager", QtWarningMsg);
}
namespace qs::dbus {
DBusObjectManager::DBusObjectManager(QObject* parent): QObject(parent) {
qDBusRegisterMetaType<DBusObjectManagerInterfaces>();
qDBusRegisterMetaType<DBusObjectManagerObjects>();
}
bool DBusObjectManager::setInterface(
const QString& service,
const QString& path,
const QDBusConnection& connection
) {
delete this->mInterface;
this->mInterface = new DBusObjectManagerInterface(service, path, connection, this);
if (!this->mInterface->isValid()) {
qCWarning(logDbusObjectManager) << "Failed to create DBusObjectManagerInterface for" << service
<< path << ":" << this->mInterface->lastError();
delete this->mInterface;
this->mInterface = nullptr;
return false;
}
QObject::connect(
this->mInterface,
&DBusObjectManagerInterface::InterfacesAdded,
this,
&DBusObjectManager::interfacesAdded
);
QObject::connect(
this->mInterface,
&DBusObjectManagerInterface::InterfacesRemoved,
this,
&DBusObjectManager::interfacesRemoved
);
this->fetchInitialObjects();
return true;
}
void DBusObjectManager::fetchInitialObjects() {
if (!this->mInterface) return;
auto reply = this->mInterface->GetManagedObjects();
auto* watcher = new QDBusPendingCallWatcher(reply, this);
QObject::connect(
watcher,
&QDBusPendingCallWatcher::finished,
this,
[this](QDBusPendingCallWatcher* watcher) {
const QDBusPendingReply<DBusObjectManagerObjects> reply = *watcher;
watcher->deleteLater();
if (reply.isError()) {
qCWarning(logDbusObjectManager) << "Failed to get managed objects:" << reply.error();
return;
}
for (const auto& [path, interfaces]: reply.value().asKeyValueRange()) {
emit this->interfacesAdded(path, interfaces);
}
}
);
}
} // namespace qs::dbus

View file

@ -0,0 +1,37 @@
#pragma once
#include <qdbusconnection.h>
#include <qobject.h>
#include <qstring.h>
#include <qtmetamacros.h>
#include "dbus_objectmanager_types.hpp"
class DBusObjectManagerInterface;
namespace qs::dbus {
class DBusObjectManager: public QObject {
Q_OBJECT;
public:
explicit DBusObjectManager(QObject* parent = nullptr);
bool setInterface(
const QString& service,
const QString& path,
const QDBusConnection& connection = QDBusConnection::sessionBus()
);
signals:
void
interfacesAdded(const QDBusObjectPath& objectPath, const DBusObjectManagerInterfaces& interfaces);
void interfacesRemoved(const QDBusObjectPath& objectPath, const QStringList& interfaces);
private:
void fetchInitialObjects();
DBusObjectManagerInterface* mInterface = nullptr;
};
} // namespace qs::dbus

View file

@ -0,0 +1,18 @@
<node>
<interface name="org.freedesktop.DBus.ObjectManager">
<method name="GetManagedObjects">
<arg name="objects" direction="out" type="a{oa{sa{sv}}}"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="DBusObjectManagerObjects"/>
</method>
<signal name="InterfacesAdded">
<arg name="object" type="o"/>
<arg name="interfaces" type="a{sa{sv}}"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="DBusObjectManagerInterfaces"/>
</signal>
<signal name="InterfacesRemoved">
<arg name="object" type="o"/>
<arg name="interfaces" type="as"/>
</signal>
</interface>
</node>

View file

@ -17,6 +17,7 @@
#include <qmetatype.h>
#include <qobject.h>
#include <qtmetamacros.h>
#include <qtversionchecks.h>
#include <qvariant.h>
#include "dbus_properties.h"
@ -326,3 +327,10 @@ void DBusPropertyGroup::onPropertiesChanged(
}
} // namespace qs::dbus
#if QT_VERSION < QT_VERSION_CHECK(6, 8, 0)
QDebug operator<<(QDebug debug, const QDBusObjectPath& path) {
debug.nospace() << "QDBusObjectPath(" << path.path() << ")";
return debug;
}
#endif

View file

@ -20,6 +20,7 @@
#include <qstringview.h>
#include <qtclasshelpermacros.h>
#include <qtmetamacros.h>
#include <qtversionchecks.h>
#include <qvariant.h>
#include "../core/util.hpp"
@ -234,6 +235,7 @@ public:
void attachProperty(DBusPropertyCore* property);
void updateAllDirect();
void updateAllViaGetAll();
void updatePropertySet(const QVariantMap& properties, bool complainMissing = true);
[[nodiscard]] QString toString() const;
[[nodiscard]] bool isConnected() const { return this->interface; }
@ -252,7 +254,6 @@ private slots:
);
private:
void updatePropertySet(const QVariantMap& properties, bool complainMissing);
void tryUpdateProperty(DBusPropertyCore* property, const QVariant& variant) const;
[[nodiscard]] QString propertyString(const DBusPropertyCore* property) const;
@ -265,6 +266,10 @@ private:
} // namespace qs::dbus
#if QT_VERSION < QT_VERSION_CHECK(6, 8, 0)
QDebug operator<<(QDebug debug, const QDBusObjectPath& path);
#endif
// NOLINTBEGIN
#define QS_DBUS_BINDABLE_PROPERTY_GROUP(Class, name) qs::dbus::DBusPropertyGroup name {this};