From a7ff484793ef69c7f97a99de2bec02640d681e83 Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Thu, 3 Jul 2025 13:06:21 -0500 Subject: [PATCH 01/25] init: NetworkManager service --- CMakeLists.txt | 3 +- src/services/CMakeLists.txt | 4 ++ src/services/networkmanager/CMakeLists.txt | 42 ++++++++++++++ src/services/networkmanager/core.cpp | 57 +++++++++++++++++++ src/services/networkmanager/core.hpp | 21 +++++++ .../org.freedesktop.NetworkManager.Device.xml | 16 ++++++ .../org.freedesktop.NetworkManager.xml | 20 +++++++ 7 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 src/services/networkmanager/CMakeLists.txt create mode 100644 src/services/networkmanager/core.cpp create mode 100644 src/services/networkmanager/core.hpp create mode 100644 src/services/networkmanager/org.freedesktop.NetworkManager.Device.xml create mode 100644 src/services/networkmanager/org.freedesktop.NetworkManager.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index 7161c4e4..7c827c3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,7 @@ boption(X11 "X11" ON) boption(I3 "I3/Sway" ON) boption(I3_IPC " I3/Sway IPC" ON REQUIRES I3) boption(SERVICE_STATUS_NOTIFIER "System Tray" ON) +boption(SERVICE_NETWORKMANAGER "NetworkManager" ON) boption(SERVICE_PIPEWIRE "PipeWire" ON) boption(SERVICE_MPRIS "Mpris" ON) boption(SERVICE_PAM "Pam" ON) @@ -117,7 +118,7 @@ if (WAYLAND) list(APPEND QT_FPDEPS WaylandClient) endif() -if (SERVICE_STATUS_NOTIFIER OR SERVICE_MPRIS OR SERVICE_UPOWER OR SERVICE_NOTIFICATIONS OR BLUETOOTH) +if (SERVICE.NETWORKMANAGER OR SERVICE_STATUS_NOTIFIER OR SERVICE_MPRIS OR SERVICE_UPOWER OR SERVICE_NOTIFICATIONS OR BLUETOOTH) set(DBUS ON) endif() diff --git a/src/services/CMakeLists.txt b/src/services/CMakeLists.txt index 5ab5c550..13198bb7 100644 --- a/src/services/CMakeLists.txt +++ b/src/services/CMakeLists.txt @@ -25,3 +25,7 @@ endif() if (SERVICE_NOTIFICATIONS) add_subdirectory(notifications) endif() + +if (SERVICE_NETWORKMANAGER) + add_subdirectory(networkmanager) +endif() diff --git a/src/services/networkmanager/CMakeLists.txt b/src/services/networkmanager/CMakeLists.txt new file mode 100644 index 00000000..d7843847 --- /dev/null +++ b/src/services/networkmanager/CMakeLists.txt @@ -0,0 +1,42 @@ +set_source_files_properties(org.freedesktop.NetworkManager.xml PROPERTIES + CLASSNAME DBusNetworkManagerService + NO_NAMESPACE TRUE +) + +qt_add_dbus_interface(DBUS_INTERFACES + org.freedesktop.NetworkManager.xml + dbus_service +) + +set_source_files_properties(org.freedesktop.NetworkManager.Device.xml PROPERTIES + CLASSNAME DBusNetworkManagerDevice + NO_NAMESPACE TRUE +) + +qt_add_dbus_interface(DBUS_INTERFACES + org.freedesktop.NetworkManager.Device.xml + dbus_device +) + +qt_add_library(quickshell-service-networkmanager STATIC + core.cpp + ${DBUS_INTERFACES} +) + +# dbus headers +target_include_directories(quickshell-service-networkmanager PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + +qt_add_qml_module(quickshell-service-networkmanager + URI Quickshell.Services.NetworkManager + VERSION 0.1 + DEPENDENCIES QtQml +) + +qs_add_module_deps_light(quickshell-service-networkmanager NetworkManager) +install_qml_module(quickshell-service-networkmanager) + +target_link_libraries(quickshell-service-networkmanager PRIVATE Qt::Qml Qt::DBus) +qs_add_link_dependencies(quickshell-service-networkmanager quickshell-dbus) +target_link_libraries(quickshell PRIVATE quickshell-service-networkmanagerplugin) + +qs_module_pch(quickshell-service-networkmanager SET dbus) diff --git a/src/services/networkmanager/core.cpp b/src/services/networkmanager/core.cpp new file mode 100644 index 00000000..3f8129e8 --- /dev/null +++ b/src/services/networkmanager/core.cpp @@ -0,0 +1,57 @@ +#include "core.hpp" + +#include + +#include "../../dbus/bus.hpp" +#include "dbus_service.h" + +namespace qs::service::networkmanager { + +const QString NM_SERVICE = "org.freedesktop.NetworkManager"; +const QString NM_PATH = "/org/freedesktop/NetworkManager"; + +namespace { +Q_LOGGING_CATEGORY(logNetworkManager, "quickshell.service.networkmanager", QtWarningMsg); +} + +NetworkManager::NetworkManager() { + qCDebug(logNetworkManager) << "Starting NetworkManager Service"; + + auto bus = QDBusConnection::systemBus(); + if (!bus.isConnected()) { + qCWarning(logNetworkManager + ) << "Could not connect to DBus. NetworkManager service will not work."; + return; + } + + this->service = new DBusNetworkManagerService(NM_SERVICE, NM_PATH, bus, this); + + if (!this->service->isValid()) { + qCDebug(logNetworkManager + ) << "NetworkManager service is not currently running, attempting to start it."; + + dbus::tryLaunchService(this, bus, NM_SERVICE, [this](bool success) { + if (success) { + qCDebug(logNetworkManager) << "Successfully launched NetworkManager service."; + this->init(); + } else { + qCWarning(logNetworkManager) + << "Could not start NetworkManager. The NetworkManager service will not work."; + } + }); + } else { + this->init(); + } +} + +void NetworkManager::init() {} + +NetworkManager* NetworkManager::instance() { + static NetworkManager* instance = nullptr; + if (!instance) { + instance = new NetworkManager(); + } + return instance; +} + +} // namespace qs::service::networkmanager diff --git a/src/services/networkmanager/core.hpp b/src/services/networkmanager/core.hpp new file mode 100644 index 00000000..5f5ee007 --- /dev/null +++ b/src/services/networkmanager/core.hpp @@ -0,0 +1,21 @@ +#pragma once +#include +#include + +#include "dbus_service.h" + +namespace qs::service::networkmanager { + +class NetworkManager: public QObject { + Q_OBJECT; + +public: + static NetworkManager* instance(); + +private: + explicit NetworkManager(); + void init(); + DBusNetworkManagerService* service = nullptr; +}; + +} // namespace qs::service::networkmanager diff --git a/src/services/networkmanager/org.freedesktop.NetworkManager.Device.xml b/src/services/networkmanager/org.freedesktop.NetworkManager.Device.xml new file mode 100644 index 00000000..dbd3be2c --- /dev/null +++ b/src/services/networkmanager/org.freedesktop.NetworkManager.Device.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/services/networkmanager/org.freedesktop.NetworkManager.xml b/src/services/networkmanager/org.freedesktop.NetworkManager.xml new file mode 100644 index 00000000..473ff329 --- /dev/null +++ b/src/services/networkmanager/org.freedesktop.NetworkManager.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + From e92a9ec6e9fc32dcebca9dc4951d0f86eb89eb3f Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Thu, 3 Jul 2025 20:06:28 -0500 Subject: [PATCH 02/25] fix: CMake typo --- src/services/networkmanager/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/networkmanager/CMakeLists.txt b/src/services/networkmanager/CMakeLists.txt index d7843847..d04c091f 100644 --- a/src/services/networkmanager/CMakeLists.txt +++ b/src/services/networkmanager/CMakeLists.txt @@ -32,7 +32,7 @@ qt_add_qml_module(quickshell-service-networkmanager DEPENDENCIES QtQml ) -qs_add_module_deps_light(quickshell-service-networkmanager NetworkManager) +qs_add_module_deps_light(quickshell-service-networkmanager Quickshell) install_qml_module(quickshell-service-networkmanager) target_link_libraries(quickshell-service-networkmanager PRIVATE Qt::Qml Qt::DBus) From 66fa5dc76eae9d165529583070de786c34ace6a8 Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Thu, 3 Jul 2025 20:06:58 -0500 Subject: [PATCH 03/25] feat: NetworkManager.state --- src/services/networkmanager/core.cpp | 84 +++++++++++++++- src/services/networkmanager/core.hpp | 95 +++++++++++++++++++ .../org.freedesktop.NetworkManager.xml | 5 +- 3 files changed, 180 insertions(+), 4 deletions(-) diff --git a/src/services/networkmanager/core.cpp b/src/services/networkmanager/core.cpp index 3f8129e8..803552fe 100644 --- a/src/services/networkmanager/core.cpp +++ b/src/services/networkmanager/core.cpp @@ -1,8 +1,15 @@ #include "core.hpp" +#include +#include +#include +#include +#include +#include #include #include "../../dbus/bus.hpp" +#include "../../dbus/properties.hpp" #include "dbus_service.h" namespace qs::service::networkmanager { @@ -14,6 +21,14 @@ namespace { Q_LOGGING_CATEGORY(logNetworkManager, "quickshell.service.networkmanager", QtWarningMsg); } +QString NetworkManagerState::toString(NetworkManagerState::Enum state) { + auto metaEnum = QMetaEnum::fromType(); + if (metaEnum.valueToKey(state)) { + return QString(metaEnum.valueToKey(state)); + } + return "Invalid state"; +} + NetworkManager::NetworkManager() { qCDebug(logNetworkManager) << "Starting NetworkManager Service"; @@ -44,7 +59,55 @@ NetworkManager::NetworkManager() { } } -void NetworkManager::init() {} +void NetworkManager::init() { + // QObject::connect( + // this->service, + // &DBusNetworkManagerService::DeviceAdded, + // this, + // &NetworkManager::onDeviceAdded + // ); + // + // QObject::connect( + // this->service, + // &DBusNetworkManagerService::DeviceRemoved, + // this, + // &NetworkManager::onDeviceRemoved + // ); + + this->serviceProperties.setInterface(this->service); + this->serviceProperties.updateAllViaGetAll(); + + // this->registerDevices(); +} + +// void NetworkManager::registerDevices() { +// auto pending = this->service->GetDevices(); +// auto* call = new QDBusPendingCallWatcher(pending, this); +// +// auto responseCallback = [this](QDBusPendingCallWatcher* call) { +// const QDBusPendingReply> reply = *call; +// +// if (reply.isError()) { +// qCWarning(logNetworkManager) << "Failed to get devices: " << reply.error().message(); +// } else { +// for (const QDBusObjectPath& devicePath: reply.value()) { +// qCDebug(logNetworkManager) << "Device added:" << devicePath.path(); +// } +// } +// +// delete call; +// }; +// +// QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback); +// } +// +// void NetworkManager::onDeviceAdded(const QDBusObjectPath& path) { +// qCDebug(logNetworkManager) << "Device added:" << path; +// } +// +// void NetworkManager::onDeviceRemoved(const QDBusObjectPath& path) { +// qCDebug(logNetworkManager) << "Device removed:" << path; +// } NetworkManager* NetworkManager::instance() { static NetworkManager* instance = nullptr; @@ -54,4 +117,23 @@ NetworkManager* NetworkManager::instance() { return instance; } +NetworkManagerQml::NetworkManagerQml(QObject* parent): QObject(parent) { + QObject::connect( + NetworkManager::instance(), + &NetworkManager::stateChanged, + this, + &NetworkManagerQml::stateChanged + ); +} + } // namespace qs::service::networkmanager + +namespace qs::dbus { +using namespace qs::service::networkmanager; + +DBusResult +DBusDataTransform::fromWire(quint32 wire) { + return DBusResult(static_cast(wire)); +} + +} // namespace qs::dbus diff --git a/src/services/networkmanager/core.hpp b/src/services/networkmanager/core.hpp index 5f5ee007..77aa59ff 100644 --- a/src/services/networkmanager/core.hpp +++ b/src/services/networkmanager/core.hpp @@ -1,21 +1,116 @@ #pragma once + +#include +#include +#include +#include #include +#include +#include #include +#include +#include "../../dbus/properties.hpp" #include "dbus_service.h" namespace qs::service::networkmanager { +class NetworkManagerState: public QObject { + Q_OBJECT; + QML_ELEMENT; + QML_SINGLETON; + +public: + enum Enum : quint8 { + Unknown = 0, + Asleep = 10, + Disconnected = 20, + Disconnecting = 30, + Connecting = 40, + ConnectedLocal = 50, + ConnectedSite = 60, + ConnectedGlobal = 70, + }; + Q_ENUM(Enum); + Q_INVOKABLE static QString toString(qs::service::networkmanager::NetworkManagerState::Enum state); +}; + +} // namespace qs::service::networkmanager + +namespace qs::dbus { + +template <> +struct DBusDataTransform { + using Wire = quint32; + using Data = qs::service::networkmanager::NetworkManagerState::Enum; + static DBusResult fromWire(Wire wire); +}; + +} // namespace qs::dbus + +namespace qs::service::networkmanager { + class NetworkManager: public QObject { Q_OBJECT; public: + [[nodiscard]] QBindable bindableState() const { + return &this->bState; + }; + static NetworkManager* instance(); +signals: + void stateChanged(); + +private slots: + // void onDeviceAdded(const QDBusObjectPath& path); + // void onDeviceRemoved(const QDBusObjectPath& path); + private: explicit NetworkManager(); + void init(); + void registerDevices(); + void registerDevice(const QString& path); + + Q_OBJECT_BINDABLE_PROPERTY( + NetworkManager, + NetworkManagerState::Enum, + bState, + &NetworkManager::stateChanged + ); + + QS_DBUS_BINDABLE_PROPERTY_GROUP(NetworkManager, serviceProperties); + QS_DBUS_PROPERTY_BINDING(NetworkManager, pState, bState, serviceProperties, "State"); + DBusNetworkManagerService* service = nullptr; }; +///! Provides access to the NetworkManager service. +/// An interface to the [NetworkManager daemon], which can be used to +/// view and configure network interfaces and connections. +/// +/// > [!NOTE] The NetworkManager daemon must be installed to use this service. +/// +/// [NetworkManager daemon]: https://networkmanager.dev +class NetworkManagerQml: public QObject { + Q_OBJECT; + QML_NAMED_ELEMENT(NetworkManager); + QML_SINGLETON; + // clang-format off + Q_PROPERTY(NetworkManagerState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState); + // clang-format on + +public: + explicit NetworkManagerQml(QObject* parent = nullptr); + + [[nodiscard]] static QBindable bindableState() { + return NetworkManager::instance()->bindableState(); + } + +signals: + void stateChanged(); +}; + } // namespace qs::service::networkmanager diff --git a/src/services/networkmanager/org.freedesktop.NetworkManager.xml b/src/services/networkmanager/org.freedesktop.NetworkManager.xml index 473ff329..4f9ca03e 100644 --- a/src/services/networkmanager/org.freedesktop.NetworkManager.xml +++ b/src/services/networkmanager/org.freedesktop.NetworkManager.xml @@ -7,14 +7,13 @@ + + - - - From c3e1280139d7bf0681dcd47136f992c6e7aebef5 Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Sat, 5 Jul 2025 22:07:27 -0500 Subject: [PATCH 04/25] feat: devices, wifiDevice, device properties --- src/services/networkmanager/CMakeLists.txt | 1 + src/services/networkmanager/core.cpp | 134 +++++++++++------- src/services/networkmanager/core.hpp | 24 +++- src/services/networkmanager/device.cpp | 86 +++++++++++ src/services/networkmanager/device.hpp | 157 +++++++++++++++++++++ src/services/upower/device.cpp | 7 - 6 files changed, 349 insertions(+), 60 deletions(-) create mode 100644 src/services/networkmanager/device.cpp create mode 100644 src/services/networkmanager/device.hpp diff --git a/src/services/networkmanager/CMakeLists.txt b/src/services/networkmanager/CMakeLists.txt index d04c091f..2deebf85 100644 --- a/src/services/networkmanager/CMakeLists.txt +++ b/src/services/networkmanager/CMakeLists.txt @@ -20,6 +20,7 @@ qt_add_dbus_interface(DBUS_INTERFACES qt_add_library(quickshell-service-networkmanager STATIC core.cpp + device.cpp ${DBUS_INTERFACES} ) diff --git a/src/services/networkmanager/core.cpp b/src/services/networkmanager/core.cpp index 803552fe..e91dd5fc 100644 --- a/src/services/networkmanager/core.cpp +++ b/src/services/networkmanager/core.cpp @@ -8,6 +8,7 @@ #include #include +#include "../../core/model.hpp" #include "../../dbus/bus.hpp" #include "../../dbus/properties.hpp" #include "dbus_service.h" @@ -60,69 +61,102 @@ NetworkManager::NetworkManager() { } void NetworkManager::init() { - // QObject::connect( - // this->service, - // &DBusNetworkManagerService::DeviceAdded, - // this, - // &NetworkManager::onDeviceAdded - // ); - // - // QObject::connect( - // this->service, - // &DBusNetworkManagerService::DeviceRemoved, - // this, - // &NetworkManager::onDeviceRemoved - // ); + QObject::connect( + this->service, + &DBusNetworkManagerService::DeviceAdded, + this, + &NetworkManager::onDeviceAdded + ); + + QObject::connect( + this->service, + &DBusNetworkManagerService::DeviceRemoved, + this, + &NetworkManager::onDeviceRemoved + ); this->serviceProperties.setInterface(this->service); this->serviceProperties.updateAllViaGetAll(); - // this->registerDevices(); + this->registerDevices(); } -// void NetworkManager::registerDevices() { -// auto pending = this->service->GetDevices(); -// auto* call = new QDBusPendingCallWatcher(pending, this); -// -// auto responseCallback = [this](QDBusPendingCallWatcher* call) { -// const QDBusPendingReply> reply = *call; -// -// if (reply.isError()) { -// qCWarning(logNetworkManager) << "Failed to get devices: " << reply.error().message(); -// } else { -// for (const QDBusObjectPath& devicePath: reply.value()) { -// qCDebug(logNetworkManager) << "Device added:" << devicePath.path(); -// } -// } -// -// delete call; -// }; -// -// QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback); -// } -// -// void NetworkManager::onDeviceAdded(const QDBusObjectPath& path) { -// qCDebug(logNetworkManager) << "Device added:" << path; -// } -// -// void NetworkManager::onDeviceRemoved(const QDBusObjectPath& path) { -// qCDebug(logNetworkManager) << "Device removed:" << path; -// } +void NetworkManager::registerDevices() { + auto pending = this->service->GetDevices(); + auto* call = new QDBusPendingCallWatcher(pending, this); -NetworkManager* NetworkManager::instance() { - static NetworkManager* instance = nullptr; - if (!instance) { - instance = new NetworkManager(); + auto responseCallback = [this](QDBusPendingCallWatcher* call) { + const QDBusPendingReply> reply = *call; + + if (reply.isError()) { + qCWarning(logNetworkManager) << "Failed to get 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 NetworkManager::onDeviceAdded(const QDBusObjectPath& path) { + this->registerDevice(path.path()); +} + +void NetworkManager::onDeviceRemoved(const QDBusObjectPath& path) { + auto iter = this->mDeviceHash.find(path.path()); + + if (iter == this->mDeviceHash.end()) { + qCWarning(logNetworkManager) << "NetworkManager service sent removal signal for" << path.path() + << "which is not registered."; + } else { + auto* device = iter.value(); + this->mDeviceHash.erase(iter); + this->mDevices.removeObject(device); + qCDebug(logNetworkManager) << "NetworkManagerDevice" << device->path() << "removed."; + } +} + +void NetworkManager::registerDevice(const QString& path) { + if (this->mDeviceHash.contains(path)) { + qCDebug(logNetworkManager) << "Skipping duplicate registration of NetworkManagerDevice" << path; + return; } + + auto* device = new NetworkManagerDevice(this); + device->init(path); + + if (!device->isValid()) { + qCWarning(logNetworkManager) << "Ignoring invalid NetworkManagerDevice registration of" << path; + delete device; + return; + } + if (device->bindableType().value() == NetworkManagerDeviceType::Wifi) { + mWifiDevice = device; + } + + this->mDeviceHash.insert(path, device); + this->mDevices.insertObject(device); + qCDebug(logNetworkManager) << "Registered NetworkManagerDevice" << path; +} + +ObjectModel* NetworkManager::devices() { return &this->mDevices; } +NetworkManagerDevice* NetworkManager::wifiDevice() { return this->mWifiDevice; } + +NetworkManager* NetworkManager::instance() { + static NetworkManager* instance = new NetworkManager(); // NOLINT return instance; } NetworkManagerQml::NetworkManagerQml(QObject* parent): QObject(parent) { QObject::connect( - NetworkManager::instance(), - &NetworkManager::stateChanged, - this, - &NetworkManagerQml::stateChanged + NetworkManager::instance(), + &NetworkManager::stateChanged, + this, + &NetworkManagerQml::stateChanged ); } diff --git a/src/services/networkmanager/core.hpp b/src/services/networkmanager/core.hpp index 77aa59ff..7b1790aa 100644 --- a/src/services/networkmanager/core.hpp +++ b/src/services/networkmanager/core.hpp @@ -10,8 +10,10 @@ #include #include +#include "../../core/model.hpp" #include "../../dbus/properties.hpp" #include "dbus_service.h" +#include "device.hpp" namespace qs::service::networkmanager { @@ -54,6 +56,8 @@ class NetworkManager: public QObject { Q_OBJECT; public: + [[nodiscard]] NetworkManagerDevice* wifiDevice(); + [[nodiscard]] ObjectModel* devices(); [[nodiscard]] QBindable bindableState() const { return &this->bState; }; @@ -64,15 +68,19 @@ class NetworkManager: public QObject { void stateChanged(); private slots: - // void onDeviceAdded(const QDBusObjectPath& path); - // void onDeviceRemoved(const QDBusObjectPath& path); + void onDeviceAdded(const QDBusObjectPath& path); + void onDeviceRemoved(const QDBusObjectPath& path); private: explicit NetworkManager(); void init(); - void registerDevices(); void registerDevice(const QString& path); + void registerDevices(); + + QHash mDeviceHash; + ObjectModel mDevices {this}; + NetworkManagerDevice* mWifiDevice = nullptr; Q_OBJECT_BINDABLE_PROPERTY( NetworkManager, @@ -98,12 +106,22 @@ class NetworkManagerQml: public QObject { Q_OBJECT; QML_NAMED_ELEMENT(NetworkManager); QML_SINGLETON; + Q_PROPERTY(qs::service::networkmanager::NetworkManagerDevice* wifiDevice READ wifiDevice); + QSDOC_TYPE_OVERRIDE(ObjectModel*); + Q_PROPERTY(UntypedObjectModel* devices READ devices CONSTANT); // clang-format off Q_PROPERTY(NetworkManagerState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState); // clang-format on public: explicit NetworkManagerQml(QObject* parent = nullptr); + [[nodiscard]] static NetworkManagerDevice* wifiDevice() { + return NetworkManager::instance()->wifiDevice(); + } + + [[nodiscard]] static ObjectModel* devices() { + return NetworkManager::instance()->devices(); + } [[nodiscard]] static QBindable bindableState() { return NetworkManager::instance()->bindableState(); diff --git a/src/services/networkmanager/device.cpp b/src/services/networkmanager/device.cpp new file mode 100644 index 00000000..a2e7c5f7 --- /dev/null +++ b/src/services/networkmanager/device.cpp @@ -0,0 +1,86 @@ + +#include "device.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include "../../dbus/properties.hpp" +#include "dbus_device.h" + +using namespace qs::dbus; + +namespace qs::service::networkmanager { + +namespace { +Q_LOGGING_CATEGORY( + logNetworkManagerDevice, + "quickshell.service.networkmanager.device", + QtWarningMsg +); +} + +QString NetworkManagerDeviceState::toString(NetworkManagerDeviceState::Enum state) { + auto metaEnum = QMetaEnum::fromType(); + if (metaEnum.valueToKey(state)) { + return QString(metaEnum.valueToKey(state)); + } + return "Invalid state"; +} + +QString NetworkManagerDeviceType::toString(NetworkManagerDeviceType::Enum type) { + auto metaEnum = QMetaEnum::fromType(); + if (metaEnum.valueToKey(type)) { + return QString(metaEnum.valueToKey(type)); + } + return "Invalid type"; +} + +NetworkManagerDevice::NetworkManagerDevice(QObject* parent): QObject(parent) {} + +void NetworkManagerDevice::init(const QString& path) { + this->device = new DBusNetworkManagerDevice( + "org.freedesktop.NetworkManager", + path, + QDBusConnection::systemBus(), + this + ); + + if (!this->device->isValid()) { + qCWarning(logNetworkManagerDevice) << "Cannot create NetworkManagerDevice for" << path; + return; + } + + this->deviceProperties.setInterface(this->device); + this->deviceProperties.updateAllViaGetAll(); +} + +bool NetworkManagerDevice::isValid() const { return this->device && this->device->isValid(); } +QString NetworkManagerDevice::address() const { + return this->device ? this->device->service() : QString(); +} +QString NetworkManagerDevice::path() const { + return this->device ? this->device->path() : QString(); +} + +} // namespace qs::service::networkmanager + +namespace qs::dbus { + +using namespace qs::service::networkmanager; + +DBusResult +DBusDataTransform::fromWire(quint32 wire) { + return DBusResult(static_cast(wire)); +} + +DBusResult +DBusDataTransform::fromWire(quint32 wire) { + return DBusResult(static_cast(wire)); +} + +} // namespace qs::dbus diff --git a/src/services/networkmanager/device.hpp b/src/services/networkmanager/device.hpp new file mode 100644 index 00000000..ed9b3549 --- /dev/null +++ b/src/services/networkmanager/device.hpp @@ -0,0 +1,157 @@ +#pragma once +#include +#include +#include +#include +#include + +#include "../../dbus/properties.hpp" +#include "dbus_device.h" + +namespace qs::service::networkmanager { + +class NetworkManagerDeviceType: public QObject { + Q_OBJECT; + QML_ELEMENT; + QML_SINGLETON; + +public: + enum Enum : quint8 { + Ethernet = 1, + Wifi = 2, + Unused1 = 3, + Unused2 = 4, + Bluetooth = 5, + OLPCMesh = 6, + WiMAX = 7, + Modem = 8, + InfiniBand = 9, + Bond = 10, + VLAN = 11, + ADSL = 12, + Bridge = 13, + Team = 14, + TUN = 16, + Tunnel = 17, + MACVLAN = 18, + VXLAN = 19, + VETH = 20, + MACsec = 21, + Dummy = 22, + PPP = 23, + OVSInterface = 24, + OVSPort = 25, + OVSBridge = 26, + WPAN = 27, + SixLoWPAN = 28, + WireGuard = 29, + WifiP2P = 30, + VRF = 31, + Loopback = 32, + HSR = 33, + IPVLAN = 34, + }; + Q_ENUM(Enum); + Q_INVOKABLE static QString toString(NetworkManagerDeviceType::Enum type); +}; + +class NetworkManagerDeviceState: public QObject { + Q_OBJECT; + QML_ELEMENT; + QML_SINGLETON; + +public: + enum Enum : quint8 { + Unknown = 0, + Unmanaged = 10, + Unavailable = 20, + Disconnected = 30, + Prepare = 40, + Config = 50, + NeedAuth = 60, + IPConfig = 70, + IPCheck = 80, + Secondaries = 90, + Activated = 100, + Deactivating = 110, + Failed = 120, + }; + Q_ENUM(Enum); + Q_INVOKABLE static QString toString(NetworkManagerDeviceState::Enum state); +}; + +} // namespace qs::service::networkmanager + +namespace qs::dbus { + +template <> +struct DBusDataTransform { + using Wire = quint32; + using Data = qs::service::networkmanager::NetworkManagerDeviceState::Enum; + static DBusResult fromWire(Wire wire); +}; + +template <> +struct DBusDataTransform { + using Wire = quint32; + using Data = qs::service::networkmanager::NetworkManagerDeviceType::Enum; + static DBusResult fromWire(Wire wire); +}; + +} // namespace qs::dbus + +namespace qs::service::networkmanager { + +class NetworkManagerDevice: public QObject { + Q_OBJECT; + // clang-format off + Q_PROPERTY(NetworkManagerDeviceType::Enum type READ default NOTIFY typeChanged BINDABLE bindableType); + Q_PROPERTY(NetworkManagerDeviceState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState); + Q_PROPERTY(QString interface READ default NOTIFY interfaceChanged BINDABLE bindableInterface); + Q_PROPERTY(bool managed READ default NOTIFY managedChanged BINDABLE bindableManaged); + // clang-format on + QML_ELEMENT; + QML_UNCREATABLE("NetworkManagerDevices can only be acquired from NetworkManager"); + +public: + explicit NetworkManagerDevice(QObject* parent = nullptr); + + void init(const QString& path); + + [[nodiscard]] bool isValid() const; + [[nodiscard]] QString path() const; + [[nodiscard]] QString address() const; + + [[nodiscard]] QBindable bindableType() const { + return &this->bType; + }; + [[nodiscard]] QBindable bindableState() const { + return &this->bState; + }; + [[nodiscard]] QBindable bindableManaged() const { return &this->bManaged; }; + [[nodiscard]] QBindable bindableInterface() const { return &this->bInterface; }; + +signals: + void typeChanged(); + void stateChanged(); + void interfaceChanged(); + void managedChanged(); + +private: + // clang-format off + Q_OBJECT_BINDABLE_PROPERTY(NetworkManagerDevice, NetworkManagerDeviceType::Enum, bType, &NetworkManagerDevice::typeChanged); + Q_OBJECT_BINDABLE_PROPERTY(NetworkManagerDevice, NetworkManagerDeviceState::Enum, bState, &NetworkManagerDevice::stateChanged); + Q_OBJECT_BINDABLE_PROPERTY(NetworkManagerDevice, bool, bManaged, &NetworkManagerDevice::managedChanged); + Q_OBJECT_BINDABLE_PROPERTY(NetworkManagerDevice, QString, bInterface, &NetworkManagerDevice::interfaceChanged); + + QS_DBUS_BINDABLE_PROPERTY_GROUP(NetworkManagerDevice, deviceProperties); + QS_DBUS_PROPERTY_BINDING(NetworkManagerDevice, pType, bType, deviceProperties, "DeviceType"); + QS_DBUS_PROPERTY_BINDING(NetworkManagerDevice, pState, bState, deviceProperties, "State"); + QS_DBUS_PROPERTY_BINDING(NetworkManagerDevice, pManaged, bManaged, deviceProperties, "Managed"); + QS_DBUS_PROPERTY_BINDING(NetworkManagerDevice, pInterface, bInterface, deviceProperties, "Interface"); + // clang-format on + + DBusNetworkManagerDevice* device = nullptr; +}; + +} // namespace qs::service::networkmanager diff --git a/src/services/upower/device.cpp b/src/services/upower/device.cpp index b7c61e12..8055ccf1 100644 --- a/src/services/upower/device.cpp +++ b/src/services/upower/device.cpp @@ -84,13 +84,6 @@ void UPowerDevice::init(const QString& path) { return; } - QObject::connect( - &this->deviceProperties, - &DBusPropertyGroup::getAllFinished, - this, - &UPowerDevice::onGetAllFinished - ); - this->deviceProperties.setInterface(this->device); this->deviceProperties.updateAllViaGetAll(); } From 6ee3cb54a32b19ac2a8ba70d85c1882a8cc08324 Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Sat, 5 Jul 2025 22:13:48 -0500 Subject: [PATCH 05/25] hotfix: revert unintended change to upower --- src/services/upower/device.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/services/upower/device.cpp b/src/services/upower/device.cpp index 8055ccf1..b7c61e12 100644 --- a/src/services/upower/device.cpp +++ b/src/services/upower/device.cpp @@ -84,6 +84,13 @@ void UPowerDevice::init(const QString& path) { return; } + QObject::connect( + &this->deviceProperties, + &DBusPropertyGroup::getAllFinished, + this, + &UPowerDevice::onGetAllFinished + ); + this->deviceProperties.setInterface(this->device); this->deviceProperties.updateAllViaGetAll(); } From 8679f79d32fa86dcc0547c19c6c3c3f5966a14fc Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Wed, 9 Jul 2025 12:36:10 -0500 Subject: [PATCH 06/25] feat(nix): nm buildInput --- default.nix | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/default.nix b/default.nix index 73cd8d16..33250cc9 100644 --- a/default.nix +++ b/default.nix @@ -20,6 +20,7 @@ libdrm, libgbm ? null, pipewire, + networkmanager, pam, gitRev ? (let @@ -40,6 +41,7 @@ withWayland ? true, withX11 ? true, withPipewire ? true, + withNetworkManager ? true, withPam ? true, withHyprland ? true, withI3 ? true, @@ -70,7 +72,8 @@ ++ lib.optionals (withWayland && libgbm != null) [ libdrm libgbm ] ++ lib.optional withX11 xorg.libxcb ++ lib.optional withPam pam - ++ lib.optional withPipewire pipewire; + ++ lib.optional withPipewire pipewire + ++ lib.optional withNetworkManager networkmanager; cmakeBuildType = if debug then "Debug" else "RelWithDebInfo"; @@ -84,6 +87,7 @@ (lib.cmakeBool "WAYLAND" withWayland) (lib.cmakeBool "SCREENCOPY" (libgbm != null)) (lib.cmakeBool "SERVICE_PIPEWIRE" withPipewire) + (lib.cmakeBool "SERVICE_NETWORKMANAGER" withNetworkManager) (lib.cmakeBool "SERVICE_PAM" withPam) (lib.cmakeBool "HYPRLAND" withHyprland) (lib.cmakeBool "I3" withI3) From 3c32d881d7369cb6eebfbc626bc9537d5d11b6a2 Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Wed, 9 Jul 2025 13:07:00 -0500 Subject: [PATCH 07/25] test: device basics --- src/services/networkmanager/test/nm.qml | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/services/networkmanager/test/nm.qml diff --git a/src/services/networkmanager/test/nm.qml b/src/services/networkmanager/test/nm.qml new file mode 100644 index 00000000..cea56de2 --- /dev/null +++ b/src/services/networkmanager/test/nm.qml @@ -0,0 +1,32 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Widgets +import Quickshell.Services.NetworkManager + +FloatingWindow { + color: contentItem.palette.window + ListView { + anchors.fill: parent + anchors.margins: 5 + model: NetworkManager.devices + delegate: WrapperRectangle { + width: parent.width + color: "transparent" + border.color: palette.button + border.width: 1 + margin: 5 + + ColumnLayout { + Label { + text: `Device ${index}: ${modelData.interface}` + font.bold: true + } + Label { text: "Type: " + NetworkManagerDeviceType.toString(modelData.type) } + Label { text: "State: " + NetworkManagerDeviceState.toString(modelData.state) } + Label { text: `Managed: ${modelData.managed}` } + } + } + } +} From 0391e027b00d32b3723155cffe27eaec3b05b6bb Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Wed, 9 Jul 2025 13:16:34 -0500 Subject: [PATCH 08/25] test: nm state --- src/services/networkmanager/test/nm.qml | 52 +++++++++++++++++-------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/src/services/networkmanager/test/nm.qml b/src/services/networkmanager/test/nm.qml index cea56de2..0b46d740 100644 --- a/src/services/networkmanager/test/nm.qml +++ b/src/services/networkmanager/test/nm.qml @@ -7,25 +7,43 @@ import Quickshell.Services.NetworkManager FloatingWindow { color: contentItem.palette.window - ListView { + + ColumnLayout { anchors.fill: parent - anchors.margins: 5 - model: NetworkManager.devices - delegate: WrapperRectangle { - width: parent.width - color: "transparent" - border.color: palette.button - border.width: 1 - margin: 5 - - ColumnLayout { - Label { - text: `Device ${index}: ${modelData.interface}` - font.bold: true + anchors.margins: 10 + spacing: 10 + + + ColumnLayout { + Label { + text: "NetworkManager Service Test" + font.bold: true + } + + Label { text: "Current state: " + NetworkManagerState.toString(NetworkManager.state) } + } + + ListView { + Layout.fillWidth: true + Layout.fillHeight: true + model: NetworkManager.devices + + delegate: WrapperRectangle { + width: parent.width + color: "transparent" + border.color: palette.button + border.width: 1 + margin: 10 + + ColumnLayout { + Label { + text: `Device ${index}: ${modelData.interface}` + font.bold: true + } + Label { text: "Type: " + NetworkManagerDeviceType.toString(modelData.type) } + Label { text: "State: " + NetworkManagerDeviceState.toString(modelData.state) } + Label { text: `Managed: ${modelData.managed}` } } - Label { text: "Type: " + NetworkManagerDeviceType.toString(modelData.type) } - Label { text: "State: " + NetworkManagerDeviceState.toString(modelData.state) } - Label { text: `Managed: ${modelData.managed}` } } } } From fdbdf1d4f2ab7349ca0fcac6ba4bc277fade4db8 Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Wed, 9 Jul 2025 13:36:40 -0500 Subject: [PATCH 09/25] fix: devicetype enum matches NMDeviceType in spec --- src/services/networkmanager/device.hpp | 42 +++++++++++++------------ src/services/networkmanager/test/nm.qml | 6 ++-- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/services/networkmanager/device.hpp b/src/services/networkmanager/device.hpp index ed9b3549..8d59263c 100644 --- a/src/services/networkmanager/device.hpp +++ b/src/services/networkmanager/device.hpp @@ -17,39 +17,41 @@ class NetworkManagerDeviceType: public QObject { public: enum Enum : quint8 { + Unknown = 0, + Generic = 14, Ethernet = 1, Wifi = 2, Unused1 = 3, Unused2 = 4, Bluetooth = 5, - OLPCMesh = 6, - WiMAX = 7, + OlpcMesh = 6, + Wimax = 7, Modem = 8, - InfiniBand = 9, + Infiniband = 9, Bond = 10, - VLAN = 11, - ADSL = 12, + Vlan = 11, + Adsl = 12, Bridge = 13, - Team = 14, - TUN = 16, + Team = 15, + Tun = 16, Tunnel = 17, - MACVLAN = 18, - VXLAN = 19, - VETH = 20, - MACsec = 21, + Macvlan = 18, + Vxlan = 19, + Veth = 20, + Macsec = 21, Dummy = 22, - PPP = 23, - OVSInterface = 24, - OVSPort = 25, - OVSBridge = 26, - WPAN = 27, - SixLoWPAN = 28, + Ppp = 23, + OvsInterface = 24, + OvsPort = 25, + OvsBridge = 26, + Wpan = 27, + Lowpan = 28, WireGuard = 29, WifiP2P = 30, - VRF = 31, + Vrf = 31, Loopback = 32, - HSR = 33, - IPVLAN = 34, + Hsr = 33, + Ipvlan = 34, }; Q_ENUM(Enum); Q_INVOKABLE static QString toString(NetworkManagerDeviceType::Enum type); diff --git a/src/services/networkmanager/test/nm.qml b/src/services/networkmanager/test/nm.qml index 0b46d740..91e83d07 100644 --- a/src/services/networkmanager/test/nm.qml +++ b/src/services/networkmanager/test/nm.qml @@ -20,7 +20,7 @@ FloatingWindow { font.bold: true } - Label { text: "Current state: " + NetworkManagerState.toString(NetworkManager.state) } + Label { text: "Current state: " + NMState.toString(NetworkManager.state) } } ListView { @@ -40,8 +40,8 @@ FloatingWindow { text: `Device ${index}: ${modelData.interface}` font.bold: true } - Label { text: "Type: " + NetworkManagerDeviceType.toString(modelData.type) } - Label { text: "State: " + NetworkManagerDeviceState.toString(modelData.state) } + Label { text: "Type: " + NMState.toString(modelData.type) } + Label { text: "State: " + NMState.toString(modelData.state) } Label { text: `Managed: ${modelData.managed}` } } } From 208cfd001fc2668b2b00c40825448d12c135dc10 Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Wed, 9 Jul 2025 13:56:59 -0500 Subject: [PATCH 10/25] style: shorten to NM --- src/services/networkmanager/CMakeLists.txt | 2 +- src/services/networkmanager/core.cpp | 16 +++---- src/services/networkmanager/core.hpp | 17 +++---- src/services/networkmanager/device.cpp | 36 +++++++-------- src/services/networkmanager/device.hpp | 52 +++++++++++----------- 5 files changed, 62 insertions(+), 61 deletions(-) diff --git a/src/services/networkmanager/CMakeLists.txt b/src/services/networkmanager/CMakeLists.txt index 2deebf85..aa38a3b7 100644 --- a/src/services/networkmanager/CMakeLists.txt +++ b/src/services/networkmanager/CMakeLists.txt @@ -9,7 +9,7 @@ qt_add_dbus_interface(DBUS_INTERFACES ) set_source_files_properties(org.freedesktop.NetworkManager.Device.xml PROPERTIES - CLASSNAME DBusNetworkManagerDevice + CLASSNAME DBusNMDevice NO_NAMESPACE TRUE ) diff --git a/src/services/networkmanager/core.cpp b/src/services/networkmanager/core.cpp index e91dd5fc..2b5a86fc 100644 --- a/src/services/networkmanager/core.cpp +++ b/src/services/networkmanager/core.cpp @@ -116,35 +116,35 @@ void NetworkManager::onDeviceRemoved(const QDBusObjectPath& path) { auto* device = iter.value(); this->mDeviceHash.erase(iter); this->mDevices.removeObject(device); - qCDebug(logNetworkManager) << "NetworkManagerDevice" << device->path() << "removed."; + qCDebug(logNetworkManager) << "NMDevice" << device->path() << "removed."; } } void NetworkManager::registerDevice(const QString& path) { if (this->mDeviceHash.contains(path)) { - qCDebug(logNetworkManager) << "Skipping duplicate registration of NetworkManagerDevice" << path; + qCDebug(logNetworkManager) << "Skipping duplicate registration of NMDevice" << path; return; } - auto* device = new NetworkManagerDevice(this); + auto* device = new NMDevice(this); device->init(path); if (!device->isValid()) { - qCWarning(logNetworkManager) << "Ignoring invalid NetworkManagerDevice registration of" << path; + qCWarning(logNetworkManager) << "Ignoring invalid NMDevice registration of" << path; delete device; return; } - if (device->bindableType().value() == NetworkManagerDeviceType::Wifi) { + if (device->bindableType().value() == NMDeviceType::Wifi) { mWifiDevice = device; } this->mDeviceHash.insert(path, device); this->mDevices.insertObject(device); - qCDebug(logNetworkManager) << "Registered NetworkManagerDevice" << path; + qCDebug(logNetworkManager) << "Registered NMDevice" << path; } -ObjectModel* NetworkManager::devices() { return &this->mDevices; } -NetworkManagerDevice* NetworkManager::wifiDevice() { return this->mWifiDevice; } +ObjectModel* NetworkManager::devices() { return &this->mDevices; } +NMDevice* NetworkManager::wifiDevice() { return this->mWifiDevice; } NetworkManager* NetworkManager::instance() { static NetworkManager* instance = new NetworkManager(); // NOLINT diff --git a/src/services/networkmanager/core.hpp b/src/services/networkmanager/core.hpp index 7b1790aa..c0fc4fc5 100644 --- a/src/services/networkmanager/core.hpp +++ b/src/services/networkmanager/core.hpp @@ -56,8 +56,8 @@ class NetworkManager: public QObject { Q_OBJECT; public: - [[nodiscard]] NetworkManagerDevice* wifiDevice(); - [[nodiscard]] ObjectModel* devices(); + [[nodiscard]] NMDevice* wifiDevice(); + [[nodiscard]] ObjectModel* devices(); [[nodiscard]] QBindable bindableState() const { return &this->bState; }; @@ -76,11 +76,12 @@ private slots: void init(); void registerDevice(const QString& path); + void createDevice(const QString& path); void registerDevices(); - QHash mDeviceHash; - ObjectModel mDevices {this}; - NetworkManagerDevice* mWifiDevice = nullptr; + QHash mDeviceHash; + ObjectModel mDevices {this}; + NMDevice* mWifiDevice = nullptr; Q_OBJECT_BINDABLE_PROPERTY( NetworkManager, @@ -106,7 +107,7 @@ class NetworkManagerQml: public QObject { Q_OBJECT; QML_NAMED_ELEMENT(NetworkManager); QML_SINGLETON; - Q_PROPERTY(qs::service::networkmanager::NetworkManagerDevice* wifiDevice READ wifiDevice); + Q_PROPERTY(qs::service::networkmanager::NMDevice* wifiDevice READ wifiDevice); QSDOC_TYPE_OVERRIDE(ObjectModel*); Q_PROPERTY(UntypedObjectModel* devices READ devices CONSTANT); // clang-format off @@ -115,11 +116,11 @@ class NetworkManagerQml: public QObject { public: explicit NetworkManagerQml(QObject* parent = nullptr); - [[nodiscard]] static NetworkManagerDevice* wifiDevice() { + [[nodiscard]] static NMDevice* wifiDevice() { return NetworkManager::instance()->wifiDevice(); } - [[nodiscard]] static ObjectModel* devices() { + [[nodiscard]] static ObjectModel* devices() { return NetworkManager::instance()->devices(); } diff --git a/src/services/networkmanager/device.cpp b/src/services/networkmanager/device.cpp index a2e7c5f7..2b9a9ae4 100644 --- a/src/services/networkmanager/device.cpp +++ b/src/services/networkmanager/device.cpp @@ -18,32 +18,32 @@ namespace qs::service::networkmanager { namespace { Q_LOGGING_CATEGORY( - logNetworkManagerDevice, + logNMDevice, "quickshell.service.networkmanager.device", QtWarningMsg ); } -QString NetworkManagerDeviceState::toString(NetworkManagerDeviceState::Enum state) { - auto metaEnum = QMetaEnum::fromType(); +QString NMDeviceState::toString(NMDeviceState::Enum state) { + auto metaEnum = QMetaEnum::fromType(); if (metaEnum.valueToKey(state)) { return QString(metaEnum.valueToKey(state)); } return "Invalid state"; } -QString NetworkManagerDeviceType::toString(NetworkManagerDeviceType::Enum type) { - auto metaEnum = QMetaEnum::fromType(); +QString NMDeviceType::toString(NMDeviceType::Enum type) { + auto metaEnum = QMetaEnum::fromType(); if (metaEnum.valueToKey(type)) { return QString(metaEnum.valueToKey(type)); } return "Invalid type"; } -NetworkManagerDevice::NetworkManagerDevice(QObject* parent): QObject(parent) {} +NMDevice::NMDevice(QObject* parent): QObject(parent) {} -void NetworkManagerDevice::init(const QString& path) { - this->device = new DBusNetworkManagerDevice( +void NMDevice::init(const QString& path) { + this->device = new DBusNMDevice( "org.freedesktop.NetworkManager", path, QDBusConnection::systemBus(), @@ -51,7 +51,7 @@ void NetworkManagerDevice::init(const QString& path) { ); if (!this->device->isValid()) { - qCWarning(logNetworkManagerDevice) << "Cannot create NetworkManagerDevice for" << path; + qCWarning(logNMDevice) << "Cannot create NMDevice for" << path; return; } @@ -59,11 +59,11 @@ void NetworkManagerDevice::init(const QString& path) { this->deviceProperties.updateAllViaGetAll(); } -bool NetworkManagerDevice::isValid() const { return this->device && this->device->isValid(); } -QString NetworkManagerDevice::address() const { +bool NMDevice::isValid() const { return this->device && this->device->isValid(); } +QString NMDevice::address() const { return this->device ? this->device->service() : QString(); } -QString NetworkManagerDevice::path() const { +QString NMDevice::path() const { return this->device ? this->device->path() : QString(); } @@ -73,14 +73,14 @@ namespace qs::dbus { using namespace qs::service::networkmanager; -DBusResult -DBusDataTransform::fromWire(quint32 wire) { - return DBusResult(static_cast(wire)); +DBusResult +DBusDataTransform::fromWire(quint32 wire) { + return DBusResult(static_cast(wire)); } -DBusResult -DBusDataTransform::fromWire(quint32 wire) { - return DBusResult(static_cast(wire)); +DBusResult +DBusDataTransform::fromWire(quint32 wire) { + return DBusResult(static_cast(wire)); } } // namespace qs::dbus diff --git a/src/services/networkmanager/device.hpp b/src/services/networkmanager/device.hpp index 8d59263c..aabeb321 100644 --- a/src/services/networkmanager/device.hpp +++ b/src/services/networkmanager/device.hpp @@ -10,7 +10,7 @@ namespace qs::service::networkmanager { -class NetworkManagerDeviceType: public QObject { +class NMDeviceType: public QObject { Q_OBJECT; QML_ELEMENT; QML_SINGLETON; @@ -54,10 +54,10 @@ class NetworkManagerDeviceType: public QObject { Ipvlan = 34, }; Q_ENUM(Enum); - Q_INVOKABLE static QString toString(NetworkManagerDeviceType::Enum type); + Q_INVOKABLE static QString toString(NMDeviceType::Enum type); }; -class NetworkManagerDeviceState: public QObject { +class NMDeviceState: public QObject { Q_OBJECT; QML_ELEMENT; QML_SINGLETON; @@ -79,7 +79,7 @@ class NetworkManagerDeviceState: public QObject { Failed = 120, }; Q_ENUM(Enum); - Q_INVOKABLE static QString toString(NetworkManagerDeviceState::Enum state); + Q_INVOKABLE static QString toString(NMDeviceState::Enum state); }; } // namespace qs::service::networkmanager @@ -87,16 +87,16 @@ class NetworkManagerDeviceState: public QObject { namespace qs::dbus { template <> -struct DBusDataTransform { +struct DBusDataTransform { using Wire = quint32; - using Data = qs::service::networkmanager::NetworkManagerDeviceState::Enum; + using Data = qs::service::networkmanager::NMDeviceState::Enum; static DBusResult fromWire(Wire wire); }; template <> -struct DBusDataTransform { +struct DBusDataTransform { using Wire = quint32; - using Data = qs::service::networkmanager::NetworkManagerDeviceType::Enum; + using Data = qs::service::networkmanager::NMDeviceType::Enum; static DBusResult fromWire(Wire wire); }; @@ -104,19 +104,19 @@ struct DBusDataTransform bindableType() const { + [[nodiscard]] QBindable bindableType() const { return &this->bType; }; - [[nodiscard]] QBindable bindableState() const { + [[nodiscard]] QBindable bindableState() const { return &this->bState; }; [[nodiscard]] QBindable bindableManaged() const { return &this->bManaged; }; @@ -141,19 +141,19 @@ class NetworkManagerDevice: public QObject { private: // clang-format off - Q_OBJECT_BINDABLE_PROPERTY(NetworkManagerDevice, NetworkManagerDeviceType::Enum, bType, &NetworkManagerDevice::typeChanged); - Q_OBJECT_BINDABLE_PROPERTY(NetworkManagerDevice, NetworkManagerDeviceState::Enum, bState, &NetworkManagerDevice::stateChanged); - Q_OBJECT_BINDABLE_PROPERTY(NetworkManagerDevice, bool, bManaged, &NetworkManagerDevice::managedChanged); - Q_OBJECT_BINDABLE_PROPERTY(NetworkManagerDevice, QString, bInterface, &NetworkManagerDevice::interfaceChanged); - - QS_DBUS_BINDABLE_PROPERTY_GROUP(NetworkManagerDevice, deviceProperties); - QS_DBUS_PROPERTY_BINDING(NetworkManagerDevice, pType, bType, deviceProperties, "DeviceType"); - QS_DBUS_PROPERTY_BINDING(NetworkManagerDevice, pState, bState, deviceProperties, "State"); - QS_DBUS_PROPERTY_BINDING(NetworkManagerDevice, pManaged, bManaged, deviceProperties, "Managed"); - QS_DBUS_PROPERTY_BINDING(NetworkManagerDevice, pInterface, bInterface, deviceProperties, "Interface"); + Q_OBJECT_BINDABLE_PROPERTY(NMDevice, NMDeviceType::Enum, bType, &NMDevice::typeChanged); + Q_OBJECT_BINDABLE_PROPERTY(NMDevice, NMDeviceState::Enum, bState, &NMDevice::stateChanged); + Q_OBJECT_BINDABLE_PROPERTY(NMDevice, bool, bManaged, &NMDevice::managedChanged); + Q_OBJECT_BINDABLE_PROPERTY(NMDevice, QString, bInterface, &NMDevice::interfaceChanged); + + QS_DBUS_BINDABLE_PROPERTY_GROUP(NMDevice, deviceProperties); + QS_DBUS_PROPERTY_BINDING(NMDevice, pType, bType, deviceProperties, "DeviceType"); + QS_DBUS_PROPERTY_BINDING(NMDevice, pState, bState, deviceProperties, "State"); + QS_DBUS_PROPERTY_BINDING(NMDevice, pManaged, bManaged, deviceProperties, "Managed"); + QS_DBUS_PROPERTY_BINDING(NMDevice, pInterface, bInterface, deviceProperties, "Interface"); // clang-format on - DBusNetworkManagerDevice* device = nullptr; + DBusNMDevice* device = nullptr; }; } // namespace qs::service::networkmanager From 25042100012a5caaab1d02f779e7798d691d66d4 Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Wed, 9 Jul 2025 14:55:10 -0500 Subject: [PATCH 11/25] Revert "feat(nix): nm buildInput" This reverts commit 8679f79d32fa86dcc0547c19c6c3c3f5966a14fc. --- default.nix | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/default.nix b/default.nix index 33250cc9..73cd8d16 100644 --- a/default.nix +++ b/default.nix @@ -20,7 +20,6 @@ libdrm, libgbm ? null, pipewire, - networkmanager, pam, gitRev ? (let @@ -41,7 +40,6 @@ withWayland ? true, withX11 ? true, withPipewire ? true, - withNetworkManager ? true, withPam ? true, withHyprland ? true, withI3 ? true, @@ -72,8 +70,7 @@ ++ lib.optionals (withWayland && libgbm != null) [ libdrm libgbm ] ++ lib.optional withX11 xorg.libxcb ++ lib.optional withPam pam - ++ lib.optional withPipewire pipewire - ++ lib.optional withNetworkManager networkmanager; + ++ lib.optional withPipewire pipewire; cmakeBuildType = if debug then "Debug" else "RelWithDebInfo"; @@ -87,7 +84,6 @@ (lib.cmakeBool "WAYLAND" withWayland) (lib.cmakeBool "SCREENCOPY" (libgbm != null)) (lib.cmakeBool "SERVICE_PIPEWIRE" withPipewire) - (lib.cmakeBool "SERVICE_NETWORKMANAGER" withNetworkManager) (lib.cmakeBool "SERVICE_PAM" withPam) (lib.cmakeBool "HYPRLAND" withHyprland) (lib.cmakeBool "I3" withI3) From d3238817084017690113e31a2d3f5c78c5aca6bc Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Wed, 9 Jul 2025 15:00:06 -0500 Subject: [PATCH 12/25] feat: AP, Wireless xml --- ....freedesktop.NetworkManager.AccessPoint.xml | 11 +++++++++++ ...edesktop.NetworkManager.Device.Wireless.xml | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/services/networkmanager/org.freedesktop.NetworkManager.AccessPoint.xml create mode 100644 src/services/networkmanager/org.freedesktop.NetworkManager.Device.Wireless.xml diff --git a/src/services/networkmanager/org.freedesktop.NetworkManager.AccessPoint.xml b/src/services/networkmanager/org.freedesktop.NetworkManager.AccessPoint.xml new file mode 100644 index 00000000..33872050 --- /dev/null +++ b/src/services/networkmanager/org.freedesktop.NetworkManager.AccessPoint.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/services/networkmanager/org.freedesktop.NetworkManager.Device.Wireless.xml b/src/services/networkmanager/org.freedesktop.NetworkManager.Device.Wireless.xml new file mode 100644 index 00000000..17b712bb --- /dev/null +++ b/src/services/networkmanager/org.freedesktop.NetworkManager.Device.Wireless.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + arg name="access_ponit" type="o"/> + + + From 470579656aa17a75b2c5b2c2131275bd8be78eaf Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Wed, 9 Jul 2025 15:04:30 -0500 Subject: [PATCH 13/25] fix test --- src/services/networkmanager/test/nm.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/services/networkmanager/test/nm.qml b/src/services/networkmanager/test/nm.qml index 91e83d07..5a66e94f 100644 --- a/src/services/networkmanager/test/nm.qml +++ b/src/services/networkmanager/test/nm.qml @@ -20,7 +20,7 @@ FloatingWindow { font.bold: true } - Label { text: "Current state: " + NMState.toString(NetworkManager.state) } + Label { text: "Current state: " + NetworkManagerState.toString(NetworkManager.state) } } ListView { @@ -40,8 +40,8 @@ FloatingWindow { text: `Device ${index}: ${modelData.interface}` font.bold: true } - Label { text: "Type: " + NMState.toString(modelData.type) } - Label { text: "State: " + NMState.toString(modelData.state) } + Label { text: "Type: " + NMDeviceType.toString(modelData.type) } + Label { text: "State: " + NMDeviceState.toString(modelData.state) } Label { text: `Managed: ${modelData.managed}` } } } From a1515c191d169a2166775cc6c83557383ed32fbb Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Wed, 9 Jul 2025 17:07:44 -0500 Subject: [PATCH 14/25] feat: begin wireless NMWireless will be a property of Device (if DeviceType==Wifi). In the future if many org.freedesktop.networkmanager.Device.* are implemented, we can use the factory pattern to create an NMDevice with its subdevice properties and methods. --- src/services/networkmanager/CMakeLists.txt | 11 ++++ src/services/networkmanager/core.hpp | 6 +- src/services/networkmanager/device.hpp | 9 +-- src/services/networkmanager/wireless.cpp | 39 +++++++++++ src/services/networkmanager/wireless.hpp | 77 ++++++++++++++++++++++ 5 files changed, 131 insertions(+), 11 deletions(-) create mode 100644 src/services/networkmanager/wireless.cpp create mode 100644 src/services/networkmanager/wireless.hpp diff --git a/src/services/networkmanager/CMakeLists.txt b/src/services/networkmanager/CMakeLists.txt index aa38a3b7..7947ab5d 100644 --- a/src/services/networkmanager/CMakeLists.txt +++ b/src/services/networkmanager/CMakeLists.txt @@ -18,9 +18,20 @@ qt_add_dbus_interface(DBUS_INTERFACES dbus_device ) +set_source_files_properties(org.freedesktop.NetworkManager.Device.Wireless.xml PROPERTIES + CLASSNAME DBusNMWireless + NO_NAMESPACE TRUE +) + +qt_add_dbus_interface(DBUS_INTERFACES + org.freedesktop.NetworkManager.Device.Wireless.xml + dbus_wireless +) + qt_add_library(quickshell-service-networkmanager STATIC core.cpp device.cpp + wireless.cpp ${DBUS_INTERFACES} ) diff --git a/src/services/networkmanager/core.hpp b/src/services/networkmanager/core.hpp index c0fc4fc5..50f49a15 100644 --- a/src/services/networkmanager/core.hpp +++ b/src/services/networkmanager/core.hpp @@ -107,7 +107,7 @@ class NetworkManagerQml: public QObject { Q_OBJECT; QML_NAMED_ELEMENT(NetworkManager); QML_SINGLETON; - Q_PROPERTY(qs::service::networkmanager::NMDevice* wifiDevice READ wifiDevice); + Q_PROPERTY(qs::service::networkmanager::NMDevice* wifiDevice READ wifiDevice CONSTANT); QSDOC_TYPE_OVERRIDE(ObjectModel*); Q_PROPERTY(UntypedObjectModel* devices READ devices CONSTANT); // clang-format off @@ -116,9 +116,7 @@ class NetworkManagerQml: public QObject { public: explicit NetworkManagerQml(QObject* parent = nullptr); - [[nodiscard]] static NMDevice* wifiDevice() { - return NetworkManager::instance()->wifiDevice(); - } + [[nodiscard]] static NMDevice* wifiDevice() { return NetworkManager::instance()->wifiDevice(); } [[nodiscard]] static ObjectModel* devices() { return NetworkManager::instance()->devices(); diff --git a/src/services/networkmanager/device.hpp b/src/services/networkmanager/device.hpp index aabeb321..99b473c4 100644 --- a/src/services/networkmanager/device.hpp +++ b/src/services/networkmanager/device.hpp @@ -117,19 +117,14 @@ class NMDevice: public QObject { public: explicit NMDevice(QObject* parent = nullptr); - void init(const QString& path); [[nodiscard]] bool isValid() const; [[nodiscard]] QString path() const; [[nodiscard]] QString address() const; - [[nodiscard]] QBindable bindableType() const { - return &this->bType; - }; - [[nodiscard]] QBindable bindableState() const { - return &this->bState; - }; + [[nodiscard]] QBindable bindableType() const { return &this->bType; }; + [[nodiscard]] QBindable bindableState() const { return &this->bState; }; [[nodiscard]] QBindable bindableManaged() const { return &this->bManaged; }; [[nodiscard]] QBindable bindableInterface() const { return &this->bInterface; }; diff --git a/src/services/networkmanager/wireless.cpp b/src/services/networkmanager/wireless.cpp new file mode 100644 index 00000000..a490035c --- /dev/null +++ b/src/services/networkmanager/wireless.cpp @@ -0,0 +1,39 @@ +#include "wireless.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include "../../dbus/properties.hpp" +#include "dbus_wireless.h" + +namespace qs::service::networkmanager { + +NMWireless::NMWireless(QObject* parent): QObject(parent) {} + +QString NMWirelessMode::toString(NMWirelessMode::Enum mode) { + switch (mode) { + case NMWirelessMode::Unknown: return "Unknown"; + case NMWirelessMode::Adhoc: return "Adhoc"; + case NMWirelessMode::Infra: return "Infra"; + case NMWirelessMode::AP: return "AP"; + case NMWirelessMode::Mesh: return "Mesh"; + default: return "Unknown"; + } +} + +} // namespace qs::service::networkmanager + +namespace qs::dbus { + +using namespace qs::service::networkmanager; + +DBusResult DBusDataTransform::fromWire(quint32 wire) { + return DBusResult(static_cast(wire)); +} + +} // namespace qs::dbus diff --git a/src/services/networkmanager/wireless.hpp b/src/services/networkmanager/wireless.hpp new file mode 100644 index 00000000..4c875141 --- /dev/null +++ b/src/services/networkmanager/wireless.hpp @@ -0,0 +1,77 @@ +#pragma once +#include +#include +#include +#include +#include + +#include "../../dbus/properties.hpp" +#include "dbus_wireless.h" + +namespace qs::service::networkmanager { + +class NMWirelessMode: public QObject { + Q_OBJECT; + QML_ELEMENT; + QML_SINGLETON; + +public: + enum Enum : quint8 { + Unknown = 0, + Adhoc = 1, + Infra = 2, + AP = 3, + Mesh = 4, + }; + Q_ENUM(Enum); + Q_INVOKABLE static QString toString(NMWirelessMode::Enum mode); +}; + +} // namespace qs::service::networkmanager + +namespace qs::dbus { + +template <> +struct DBusDataTransform { + using Wire = quint32; + using Data = qs::service::networkmanager::NMWirelessMode::Enum; + static DBusResult fromWire(Wire wire); +}; + +} // namespace qs::dbus + +namespace qs::service::networkmanager { + +class NMWireless: public QObject { + Q_OBJECT + QML_ELEMENT; + QML_UNCREATABLE("NMWireless can only be acquired from NMDevice"); + //clang-format off + Q_PROPERTY(NMWirelessMode::Enum mode READ default NOTIFY modeChanged BINDABLE bindableMode); + Q_PROPERTY(quint32 bitrate READ default NOTIFY bitrateChanged BINDABLE bindableBitrate); + +public: + explicit NMWireless(QObject* parent = nullptr); + void init(const QString& path); + + [[nodiscard]] bool isValid() const; + [[nodiscard]] QString path() const; + [[nodiscard]] QBindable bindableMode() const { return &this->bMode; }; + [[nodiscard]] QBindable bindableBitrate() const { return &this->bBitrate; }; + +signals: + void modeChanged(); + void bitrateChanged(); + +private: + Q_OBJECT_BINDABLE_PROPERTY(NMWireless, NMWirelessMode::Enum, bMode, &NMWireless::modeChanged); + Q_OBJECT_BINDABLE_PROPERTY(NMWireless, quint32, bBitrate, &NMWireless::bitrateChanged); + + QS_DBUS_BINDABLE_PROPERTY_GROUP(NMWireless, deviceProperties); + QS_DBUS_PROPERTY_BINDING(NMWireless, pMode, bMode, deviceProperties, "Mode"); + QS_DBUS_PROPERTY_BINDING(NMWireless, pBitrate, bBitrate, deviceProperties, "Bitrate"); + + DBusNMWireless* wireless = nullptr; +}; + +} // namespace qs::service::networkmanager From e445c9bd70b282e0649ff1e4a1f178c7d74cf72a Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Fri, 11 Jul 2025 03:03:38 -0500 Subject: [PATCH 15/25] Quickshell.Network --- CMakeLists.txt | 4 +- src/CMakeLists.txt | 4 + src/network/CMakeLists.txt | 54 ++++++ src/network/api.cpp | 38 +++++ src/network/api.hpp | 77 +++++++++ .../core.cpp => network/nm.cpp} | 116 +++++-------- src/network/nm.hpp | 48 ++++++ src/network/nmdevice.cpp | 41 +++++ src/network/nmdevice.hpp | 36 ++++ src/network/note | 12 ++ ...freedesktop.NetworkManager.AccessPoint.xml | 0 ...desktop.NetworkManager.Device.Wireless.xml | 0 .../org.freedesktop.NetworkManager.Device.xml | 8 + .../org.freedesktop.NetworkManager.xml | 0 .../test/nm.qml => network/test/network.qml} | 20 +-- src/services/CMakeLists.txt | 4 - src/services/networkmanager/CMakeLists.txt | 54 ------ src/services/networkmanager/core.hpp | 133 --------------- src/services/networkmanager/device.cpp | 86 ---------- src/services/networkmanager/device.hpp | 154 ------------------ .../org.freedesktop.NetworkManager.Device.xml | 16 -- src/services/networkmanager/wireless.cpp | 39 ----- src/services/networkmanager/wireless.hpp | 77 --------- 23 files changed, 366 insertions(+), 655 deletions(-) create mode 100644 src/network/CMakeLists.txt create mode 100644 src/network/api.cpp create mode 100644 src/network/api.hpp rename src/{services/networkmanager/core.cpp => network/nm.cpp} (58%) create mode 100644 src/network/nm.hpp create mode 100644 src/network/nmdevice.cpp create mode 100644 src/network/nmdevice.hpp create mode 100644 src/network/note rename src/{services/networkmanager => network}/org.freedesktop.NetworkManager.AccessPoint.xml (100%) rename src/{services/networkmanager => network}/org.freedesktop.NetworkManager.Device.Wireless.xml (100%) create mode 100644 src/network/org.freedesktop.NetworkManager.Device.xml rename src/{services/networkmanager => network}/org.freedesktop.NetworkManager.xml (100%) rename src/{services/networkmanager/test/nm.qml => network/test/network.qml} (50%) delete mode 100644 src/services/networkmanager/CMakeLists.txt delete mode 100644 src/services/networkmanager/core.hpp delete mode 100644 src/services/networkmanager/device.cpp delete mode 100644 src/services/networkmanager/device.hpp delete mode 100644 src/services/networkmanager/org.freedesktop.NetworkManager.Device.xml delete mode 100644 src/services/networkmanager/wireless.cpp delete mode 100644 src/services/networkmanager/wireless.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c827c3c..d85a2db5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,7 +64,6 @@ boption(X11 "X11" ON) boption(I3 "I3/Sway" ON) boption(I3_IPC " I3/Sway IPC" ON REQUIRES I3) boption(SERVICE_STATUS_NOTIFIER "System Tray" ON) -boption(SERVICE_NETWORKMANAGER "NetworkManager" ON) boption(SERVICE_PIPEWIRE "PipeWire" ON) boption(SERVICE_MPRIS "Mpris" ON) boption(SERVICE_PAM "Pam" ON) @@ -72,6 +71,7 @@ boption(SERVICE_GREETD "Greetd" ON) boption(SERVICE_UPOWER "UPower" ON) boption(SERVICE_NOTIFICATIONS "Notifications" ON) boption(BLUETOOTH "Bluetooth" ON) +boption(NETWORK "Network" ON) include(cmake/install-qml-module.cmake) include(cmake/util.cmake) @@ -118,7 +118,7 @@ if (WAYLAND) list(APPEND QT_FPDEPS WaylandClient) endif() -if (SERVICE.NETWORKMANAGER OR SERVICE_STATUS_NOTIFIER OR SERVICE_MPRIS OR SERVICE_UPOWER OR SERVICE_NOTIFICATIONS OR BLUETOOTH) +if (SERVICE_STATUS_NOTIFIER OR SERVICE_MPRIS OR SERVICE_UPOWER OR SERVICE_NOTIFICATIONS OR BLUETOOTH OR NETWORK) set(DBUS ON) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 52db00a5..c95ecf71 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -33,3 +33,7 @@ add_subdirectory(services) if (BLUETOOTH) add_subdirectory(bluetooth) endif() + +if (NETWORK) + add_subdirectory(network) +endif() diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt new file mode 100644 index 00000000..62bcca2f --- /dev/null +++ b/src/network/CMakeLists.txt @@ -0,0 +1,54 @@ +set_source_files_properties(org.freedesktop.NetworkManager.xml PROPERTIES + CLASSNAME DBusNetworkManager + NO_NAMESPACE TRUE +) + +qt_add_dbus_interface(DBUS_INTERFACES + org.freedesktop.NetworkManager.xml + dbus_nm_service +) + +set_source_files_properties(org.freedesktop.NetworkManager.Device.xml PROPERTIES + CLASSNAME DBusNMDevice + NO_NAMESPACE TRUE +) + +qt_add_dbus_interface(DBUS_INTERFACES + org.freedesktop.NetworkManager.Device.xml + dbus_nm_device +) + +set_source_files_properties(org.freedesktop.NetworkManager.Device.Wireless.xml PROPERTIES + CLASSNAME DBusNMWireless + NO_NAMESPACE TRUE +) + +qt_add_dbus_interface(DBUS_INTERFACES + org.freedesktop.NetworkManager.Device.Wireless.xml + dbus_nm_wireless +) + +qt_add_library(quickshell-network STATIC + api.cpp + nm.cpp + nmdevice.cpp + ${DBUS_INTERFACES} +) + +# dbus headers +target_include_directories(quickshell-network PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + +qt_add_qml_module(quickshell-network + URI Quickshell.Network + VERSION 0.1 + DEPENDENCIES QtQml +) + +qs_add_module_deps_light(quickshell-network Quickshell) +install_qml_module(quickshell-network) + +target_link_libraries(quickshell-network PRIVATE Qt::Qml Qt::DBus) +qs_add_link_dependencies(quickshell-network quickshell-dbus) +target_link_libraries(quickshell PRIVATE quickshell-networkplugin) + +qs_module_pch(quickshell-network SET dbus) diff --git a/src/network/api.cpp b/src/network/api.cpp new file mode 100644 index 00000000..69caad51 --- /dev/null +++ b/src/network/api.cpp @@ -0,0 +1,38 @@ +#include "api.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include "../core/model.hpp" +#include "../dbus/bus.hpp" +#include "../dbus/properties.hpp" +#include "nm.hpp" + +namespace qs::network { + +namespace { +Q_LOGGING_CATEGORY(logNetwork, "quickshell.service.network", QtWarningMsg); +} + +Device::Device(QObject* parent): QObject(parent) {}; + +Network::Network(QObject* parent): QObject(parent) { + // Try each backend + + // NetworkManager + auto* nm = new NetworkManager(); + if (nm->isAvailable()) { + this->backend = nm; + } else { + // None found + this->backend = nullptr; + qCDebug(logNetwork) << "Network will not work. Could not find an available backend."; + } +} + +} // namespace qs::network diff --git a/src/network/api.hpp b/src/network/api.hpp new file mode 100644 index 00000000..ac52e566 --- /dev/null +++ b/src/network/api.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../core/model.hpp" +#include "../dbus/properties.hpp" + +namespace qs::network { + +class Device: public QObject { + Q_OBJECT; + Q_PROPERTY(QString name READ default NOTIFY nameChanged BINDABLE bindableName); + Q_PROPERTY(QString address READ default NOTIFY addressChanged BINDABLE bindableAddress); + Q_PROPERTY(bool powered READ default NOTIFY poweredChanged BINDABLE bindablePowered); + + QML_ELEMENT; + QML_UNCREATABLE("Devices can only be acquired through Network"); + +public: + [[nodiscard]] QBindable bindableName() const { return &this->bName; }; + [[nodiscard]] QBindable bindableAddress() const { return &this->bAddress; }; + [[nodiscard]] QBindable bindablePowered() const { return &this->bPowered; }; + +signals: + void nameChanged(); + void addressChanged(); + void poweredChanged(); + +protected: + explicit Device(QObject* parent = nullptr); + Q_OBJECT_BINDABLE_PROPERTY(Device, QString, bName, &Device::nameChanged); + Q_OBJECT_BINDABLE_PROPERTY(Device, bool, bPowered, &Device::poweredChanged); + Q_OBJECT_BINDABLE_PROPERTY(Device, QString, bAddress, &Device::addressChanged); + QS_DBUS_BINDABLE_PROPERTY_GROUP(Device, deviceProperties); +}; + +// class WirelessDevice; + +class NetworkBackend: public QObject { + Q_OBJECT; + +public: + [[nodiscard]] virtual bool isAvailable() const = 0; + virtual Device* wireless() = 0; + virtual UntypedObjectModel* allDevices() = 0; + +protected: + explicit NetworkBackend(QObject* parent = nullptr): QObject(parent) {}; +}; + +class Network: public QObject { + Q_OBJECT; + QML_NAMED_ELEMENT(Network); + QML_SINGLETON; + + Q_PROPERTY(Device* wireless READ wireless CONSTANT); + Q_PROPERTY(UntypedObjectModel* allDevices READ allDevices CONSTANT); + +public: + explicit Network(QObject* parent = nullptr); + [[nodiscard]] Device* wireless() { return backend ? backend->wireless() : nullptr; } + [[nodiscard]] UntypedObjectModel* allDevices() { return backend ? backend->allDevices() : nullptr; } + +private: + void findBackend(); + class NetworkBackend* backend = nullptr; +}; + +} // namespace qs::network diff --git a/src/services/networkmanager/core.cpp b/src/network/nm.cpp similarity index 58% rename from src/services/networkmanager/core.cpp rename to src/network/nm.cpp index 2b5a86fc..1530bc9f 100644 --- a/src/services/networkmanager/core.cpp +++ b/src/network/nm.cpp @@ -1,46 +1,40 @@ -#include "core.hpp" +#include "nm.hpp" -#include -#include +#include #include -#include -#include #include -#include +#include +#include +#include +#include +#include +#include -#include "../../core/model.hpp" -#include "../../dbus/bus.hpp" -#include "../../dbus/properties.hpp" -#include "dbus_service.h" +#include "../dbus/bus.hpp" +#include "../dbus/properties.hpp" +#include "api.hpp" +#include "dbus_nm_service.h" -namespace qs::service::networkmanager { - -const QString NM_SERVICE = "org.freedesktop.NetworkManager"; -const QString NM_PATH = "/org/freedesktop/NetworkManager"; +namespace qs::network { namespace { Q_LOGGING_CATEGORY(logNetworkManager, "quickshell.service.networkmanager", QtWarningMsg); } -QString NetworkManagerState::toString(NetworkManagerState::Enum state) { - auto metaEnum = QMetaEnum::fromType(); - if (metaEnum.valueToKey(state)) { - return QString(metaEnum.valueToKey(state)); - } - return "Invalid state"; -} +const QString NM_SERVICE = "org.freedesktop.NetworkManager"; +const QString NM_PATH = "/org/freedesktop/NetworkManager"; -NetworkManager::NetworkManager() { - qCDebug(logNetworkManager) << "Starting NetworkManager Service"; +NetworkManager::NetworkManager(QObject* parent): NetworkBackend(parent) { + qCDebug(logNetworkManager) << "Starting NetworkManager Network Backend"; auto bus = QDBusConnection::systemBus(); if (!bus.isConnected()) { qCWarning(logNetworkManager - ) << "Could not connect to DBus. NetworkManager service will not work."; + ) << "Could not connect to DBus. NetworkManager backend will not work."; return; } - this->service = new DBusNetworkManagerService(NM_SERVICE, NM_PATH, bus, this); + this->service = new DBusNetworkManager(NM_SERVICE, NM_PATH, bus, this); if (!this->service->isValid()) { qCDebug(logNetworkManager @@ -48,11 +42,11 @@ NetworkManager::NetworkManager() { dbus::tryLaunchService(this, bus, NM_SERVICE, [this](bool success) { if (success) { - qCDebug(logNetworkManager) << "Successfully launched NetworkManager service."; + qCDebug(logNetworkManager) << "Successfully launched NetworkManager backend."; this->init(); } else { qCWarning(logNetworkManager) - << "Could not start NetworkManager. The NetworkManager service will not work."; + << "Could not start NetworkManager. The NetworkManager backend will not work."; } }); } else { @@ -63,14 +57,14 @@ NetworkManager::NetworkManager() { void NetworkManager::init() { QObject::connect( this->service, - &DBusNetworkManagerService::DeviceAdded, + &DBusNetworkManager::DeviceAdded, this, &NetworkManager::onDeviceAdded ); QObject::connect( this->service, - &DBusNetworkManagerService::DeviceRemoved, + &DBusNetworkManager::DeviceRemoved, this, &NetworkManager::onDeviceRemoved ); @@ -82,7 +76,7 @@ void NetworkManager::init() { } void NetworkManager::registerDevices() { - auto pending = this->service->GetDevices(); + auto pending = this->service->GetAllDevices(); auto* call = new QDBusPendingCallWatcher(pending, this); auto responseCallback = [this](QDBusPendingCallWatcher* call) { @@ -102,24 +96,6 @@ void NetworkManager::registerDevices() { QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback); } -void NetworkManager::onDeviceAdded(const QDBusObjectPath& path) { - this->registerDevice(path.path()); -} - -void NetworkManager::onDeviceRemoved(const QDBusObjectPath& path) { - auto iter = this->mDeviceHash.find(path.path()); - - if (iter == this->mDeviceHash.end()) { - qCWarning(logNetworkManager) << "NetworkManager service sent removal signal for" << path.path() - << "which is not registered."; - } else { - auto* device = iter.value(); - this->mDeviceHash.erase(iter); - this->mDevices.removeObject(device); - qCDebug(logNetworkManager) << "NMDevice" << device->path() << "removed."; - } -} - void NetworkManager::registerDevice(const QString& path) { if (this->mDeviceHash.contains(path)) { qCDebug(logNetworkManager) << "Skipping duplicate registration of NMDevice" << path; @@ -134,40 +110,32 @@ void NetworkManager::registerDevice(const QString& path) { delete device; return; } - if (device->bindableType().value() == NMDeviceType::Wifi) { - mWifiDevice = device; - } this->mDeviceHash.insert(path, device); this->mDevices.insertObject(device); qCDebug(logNetworkManager) << "Registered NMDevice" << path; } -ObjectModel* NetworkManager::devices() { return &this->mDevices; } -NMDevice* NetworkManager::wifiDevice() { return this->mWifiDevice; } - -NetworkManager* NetworkManager::instance() { - static NetworkManager* instance = new NetworkManager(); // NOLINT - return instance; -} - -NetworkManagerQml::NetworkManagerQml(QObject* parent): QObject(parent) { - QObject::connect( - NetworkManager::instance(), - &NetworkManager::stateChanged, - this, - &NetworkManagerQml::stateChanged - ); +void NetworkManager::onDeviceAdded(const QDBusObjectPath& path) { + this->registerDevice(path.path()); } -} // namespace qs::service::networkmanager - -namespace qs::dbus { -using namespace qs::service::networkmanager; +void NetworkManager::onDeviceRemoved(const QDBusObjectPath& path) { + auto iter = this->mDeviceHash.find(path.path()); -DBusResult -DBusDataTransform::fromWire(quint32 wire) { - return DBusResult(static_cast(wire)); + if (iter == this->mDeviceHash.end()) { + qCWarning(logNetworkManager) << "NetworkManager backend sent removal signal for" << path.path() + << "which is not registered."; + } else { + auto* device = iter.value(); + this->mDeviceHash.erase(iter); + this->mDevices.removeObject(device); + qCDebug(logNetworkManager) << "NMDevice" << device->path() << "removed."; + } } -} // namespace qs::dbus +UntypedObjectModel* NetworkManager::allDevices() { return &this->mDevices; } +NMDevice* NetworkManager::wireless() { return &this->mWireless; } +bool NetworkManager::isAvailable() const { return this->service && this->service->isValid(); } + +} // namespace qs::network diff --git a/src/network/nm.hpp b/src/network/nm.hpp new file mode 100644 index 00000000..33177a17 --- /dev/null +++ b/src/network/nm.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../dbus/properties.hpp" +#include "api.hpp" +#include "dbus_nm_service.h" +#include "nmdevice.hpp" + +namespace qs::network { + +class NetworkManager: public NetworkBackend { + Q_OBJECT; + +public: + explicit NetworkManager(QObject* parent = nullptr); + + UntypedObjectModel* allDevices() override; + NMDevice* wireless() override; + [[nodiscard]] bool isAvailable() const override; + +private slots: + void onDeviceAdded(const QDBusObjectPath& path); + void onDeviceRemoved(const QDBusObjectPath& path); + +private: + void init(); + void registerDevice(const QString& path); + void registerDevices(); + + QHash mDeviceHash; + ObjectModel mDevices {this}; + NMDevice mWireless; + + QS_DBUS_BINDABLE_PROPERTY_GROUP(NetworkManager, serviceProperties); + + DBusNetworkManager* service = nullptr; +}; + +} // namespace qs::network diff --git a/src/network/nmdevice.cpp b/src/network/nmdevice.cpp new file mode 100644 index 00000000..7baa89fd --- /dev/null +++ b/src/network/nmdevice.cpp @@ -0,0 +1,41 @@ +#include "nmdevice.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include "../dbus/properties.hpp" +#include "dbus_nm_device.h" + +using namespace qs::dbus; + +namespace qs::network { + +namespace { +Q_LOGGING_CATEGORY(logNMDevice, "quickshell.service.networkmanager.device", QtWarningMsg); +} + +NMDevice::NMDevice(QObject* parent): Device(parent) {} + +void NMDevice::init(const QString& path) { + this->device = + new DBusNMDevice("org.freedesktop.NetworkManager", path, QDBusConnection::systemBus(), this); + + if (!this->device->isValid()) { + qCWarning(logNMDevice) << "Cannot create NMDevice for" << path; + return; + } + + this->deviceProperties.setInterface(this->device); + this->deviceProperties.updateAllViaGetAll(); +} + +bool NMDevice::isValid() const { return this->device && this->device->isValid(); } +QString NMDevice::address() const { return this->device ? this->device->service() : QString(); } +QString NMDevice::path() const { return this->device ? this->device->path() : QString(); } + +} // namespace qs::network diff --git a/src/network/nmdevice.hpp b/src/network/nmdevice.hpp new file mode 100644 index 00000000..fbd75476 --- /dev/null +++ b/src/network/nmdevice.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../dbus/properties.hpp" +#include "api.hpp" +#include "dbus_nm_device.h" + +namespace qs::network { + +class NMDevice: public Device { + Q_OBJECT; + +public: + explicit NMDevice(QObject* parent = nullptr); + void init(const QString& path); + [[nodiscard]] bool isValid() const; + [[nodiscard]] QString path() const; + [[nodiscard]] QString address() const; + +private: + QS_DBUS_PROPERTY_BINDING(NMDevice, pName, bName, deviceProperties, "Interface"); + QS_DBUS_PROPERTY_BINDING(NMDevice, pAddress, bAddress, deviceProperties, "HwAddress"); + + DBusNMDevice* device = nullptr; +}; + +} // namespace qs::network diff --git a/src/network/note b/src/network/note new file mode 100644 index 00000000..ef97d8b7 --- /dev/null +++ b/src/network/note @@ -0,0 +1,12 @@ +Network + - Device(s) + - Name + - Address + - Powered (True/False) + - Wireless: Track the default/current wireless station + - Extends Device + - Disconnect + - Active AccessPoint + - AccessPoints + - Scan + - State Connected,Disconnected,Connecting,Disconnecting,Unknown diff --git a/src/services/networkmanager/org.freedesktop.NetworkManager.AccessPoint.xml b/src/network/org.freedesktop.NetworkManager.AccessPoint.xml similarity index 100% rename from src/services/networkmanager/org.freedesktop.NetworkManager.AccessPoint.xml rename to src/network/org.freedesktop.NetworkManager.AccessPoint.xml diff --git a/src/services/networkmanager/org.freedesktop.NetworkManager.Device.Wireless.xml b/src/network/org.freedesktop.NetworkManager.Device.Wireless.xml similarity index 100% rename from src/services/networkmanager/org.freedesktop.NetworkManager.Device.Wireless.xml rename to src/network/org.freedesktop.NetworkManager.Device.Wireless.xml diff --git a/src/network/org.freedesktop.NetworkManager.Device.xml b/src/network/org.freedesktop.NetworkManager.Device.xml new file mode 100644 index 00000000..9a2b6914 --- /dev/null +++ b/src/network/org.freedesktop.NetworkManager.Device.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/services/networkmanager/org.freedesktop.NetworkManager.xml b/src/network/org.freedesktop.NetworkManager.xml similarity index 100% rename from src/services/networkmanager/org.freedesktop.NetworkManager.xml rename to src/network/org.freedesktop.NetworkManager.xml diff --git a/src/services/networkmanager/test/nm.qml b/src/network/test/network.qml similarity index 50% rename from src/services/networkmanager/test/nm.qml rename to src/network/test/network.qml index 5a66e94f..139ff9f9 100644 --- a/src/services/networkmanager/test/nm.qml +++ b/src/network/test/network.qml @@ -3,7 +3,7 @@ import QtQuick.Controls import QtQuick.Layouts import Quickshell import Quickshell.Widgets -import Quickshell.Services.NetworkManager +import Quickshell.Network FloatingWindow { color: contentItem.palette.window @@ -13,20 +13,10 @@ FloatingWindow { anchors.margins: 10 spacing: 10 - - ColumnLayout { - Label { - text: "NetworkManager Service Test" - font.bold: true - } - - Label { text: "Current state: " + NetworkManagerState.toString(NetworkManager.state) } - } - ListView { Layout.fillWidth: true Layout.fillHeight: true - model: NetworkManager.devices + model: Network.allDevices delegate: WrapperRectangle { width: parent.width @@ -37,12 +27,10 @@ FloatingWindow { ColumnLayout { Label { - text: `Device ${index}: ${modelData.interface}` + text: `Device ${index}: ${modelData.name}` font.bold: true } - Label { text: "Type: " + NMDeviceType.toString(modelData.type) } - Label { text: "State: " + NMDeviceState.toString(modelData.state) } - Label { text: `Managed: ${modelData.managed}` } + Label { text: "Hardware Address: " + modelData.address } } } } diff --git a/src/services/CMakeLists.txt b/src/services/CMakeLists.txt index 13198bb7..5ab5c550 100644 --- a/src/services/CMakeLists.txt +++ b/src/services/CMakeLists.txt @@ -25,7 +25,3 @@ endif() if (SERVICE_NOTIFICATIONS) add_subdirectory(notifications) endif() - -if (SERVICE_NETWORKMANAGER) - add_subdirectory(networkmanager) -endif() diff --git a/src/services/networkmanager/CMakeLists.txt b/src/services/networkmanager/CMakeLists.txt deleted file mode 100644 index 7947ab5d..00000000 --- a/src/services/networkmanager/CMakeLists.txt +++ /dev/null @@ -1,54 +0,0 @@ -set_source_files_properties(org.freedesktop.NetworkManager.xml PROPERTIES - CLASSNAME DBusNetworkManagerService - NO_NAMESPACE TRUE -) - -qt_add_dbus_interface(DBUS_INTERFACES - org.freedesktop.NetworkManager.xml - dbus_service -) - -set_source_files_properties(org.freedesktop.NetworkManager.Device.xml PROPERTIES - CLASSNAME DBusNMDevice - NO_NAMESPACE TRUE -) - -qt_add_dbus_interface(DBUS_INTERFACES - org.freedesktop.NetworkManager.Device.xml - dbus_device -) - -set_source_files_properties(org.freedesktop.NetworkManager.Device.Wireless.xml PROPERTIES - CLASSNAME DBusNMWireless - NO_NAMESPACE TRUE -) - -qt_add_dbus_interface(DBUS_INTERFACES - org.freedesktop.NetworkManager.Device.Wireless.xml - dbus_wireless -) - -qt_add_library(quickshell-service-networkmanager STATIC - core.cpp - device.cpp - wireless.cpp - ${DBUS_INTERFACES} -) - -# dbus headers -target_include_directories(quickshell-service-networkmanager PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) - -qt_add_qml_module(quickshell-service-networkmanager - URI Quickshell.Services.NetworkManager - VERSION 0.1 - DEPENDENCIES QtQml -) - -qs_add_module_deps_light(quickshell-service-networkmanager Quickshell) -install_qml_module(quickshell-service-networkmanager) - -target_link_libraries(quickshell-service-networkmanager PRIVATE Qt::Qml Qt::DBus) -qs_add_link_dependencies(quickshell-service-networkmanager quickshell-dbus) -target_link_libraries(quickshell PRIVATE quickshell-service-networkmanagerplugin) - -qs_module_pch(quickshell-service-networkmanager SET dbus) diff --git a/src/services/networkmanager/core.hpp b/src/services/networkmanager/core.hpp deleted file mode 100644 index 50f49a15..00000000 --- a/src/services/networkmanager/core.hpp +++ /dev/null @@ -1,133 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../core/model.hpp" -#include "../../dbus/properties.hpp" -#include "dbus_service.h" -#include "device.hpp" - -namespace qs::service::networkmanager { - -class NetworkManagerState: public QObject { - Q_OBJECT; - QML_ELEMENT; - QML_SINGLETON; - -public: - enum Enum : quint8 { - Unknown = 0, - Asleep = 10, - Disconnected = 20, - Disconnecting = 30, - Connecting = 40, - ConnectedLocal = 50, - ConnectedSite = 60, - ConnectedGlobal = 70, - }; - Q_ENUM(Enum); - Q_INVOKABLE static QString toString(qs::service::networkmanager::NetworkManagerState::Enum state); -}; - -} // namespace qs::service::networkmanager - -namespace qs::dbus { - -template <> -struct DBusDataTransform { - using Wire = quint32; - using Data = qs::service::networkmanager::NetworkManagerState::Enum; - static DBusResult fromWire(Wire wire); -}; - -} // namespace qs::dbus - -namespace qs::service::networkmanager { - -class NetworkManager: public QObject { - Q_OBJECT; - -public: - [[nodiscard]] NMDevice* wifiDevice(); - [[nodiscard]] ObjectModel* devices(); - [[nodiscard]] QBindable bindableState() const { - return &this->bState; - }; - - static NetworkManager* instance(); - -signals: - void stateChanged(); - -private slots: - void onDeviceAdded(const QDBusObjectPath& path); - void onDeviceRemoved(const QDBusObjectPath& path); - -private: - explicit NetworkManager(); - - void init(); - void registerDevice(const QString& path); - void createDevice(const QString& path); - void registerDevices(); - - QHash mDeviceHash; - ObjectModel mDevices {this}; - NMDevice* mWifiDevice = nullptr; - - Q_OBJECT_BINDABLE_PROPERTY( - NetworkManager, - NetworkManagerState::Enum, - bState, - &NetworkManager::stateChanged - ); - - QS_DBUS_BINDABLE_PROPERTY_GROUP(NetworkManager, serviceProperties); - QS_DBUS_PROPERTY_BINDING(NetworkManager, pState, bState, serviceProperties, "State"); - - DBusNetworkManagerService* service = nullptr; -}; - -///! Provides access to the NetworkManager service. -/// An interface to the [NetworkManager daemon], which can be used to -/// view and configure network interfaces and connections. -/// -/// > [!NOTE] The NetworkManager daemon must be installed to use this service. -/// -/// [NetworkManager daemon]: https://networkmanager.dev -class NetworkManagerQml: public QObject { - Q_OBJECT; - QML_NAMED_ELEMENT(NetworkManager); - QML_SINGLETON; - Q_PROPERTY(qs::service::networkmanager::NMDevice* wifiDevice READ wifiDevice CONSTANT); - QSDOC_TYPE_OVERRIDE(ObjectModel*); - Q_PROPERTY(UntypedObjectModel* devices READ devices CONSTANT); - // clang-format off - Q_PROPERTY(NetworkManagerState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState); - // clang-format on - -public: - explicit NetworkManagerQml(QObject* parent = nullptr); - [[nodiscard]] static NMDevice* wifiDevice() { return NetworkManager::instance()->wifiDevice(); } - - [[nodiscard]] static ObjectModel* devices() { - return NetworkManager::instance()->devices(); - } - - [[nodiscard]] static QBindable bindableState() { - return NetworkManager::instance()->bindableState(); - } - -signals: - void stateChanged(); -}; - -} // namespace qs::service::networkmanager diff --git a/src/services/networkmanager/device.cpp b/src/services/networkmanager/device.cpp deleted file mode 100644 index 2b9a9ae4..00000000 --- a/src/services/networkmanager/device.cpp +++ /dev/null @@ -1,86 +0,0 @@ - -#include "device.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include "../../dbus/properties.hpp" -#include "dbus_device.h" - -using namespace qs::dbus; - -namespace qs::service::networkmanager { - -namespace { -Q_LOGGING_CATEGORY( - logNMDevice, - "quickshell.service.networkmanager.device", - QtWarningMsg -); -} - -QString NMDeviceState::toString(NMDeviceState::Enum state) { - auto metaEnum = QMetaEnum::fromType(); - if (metaEnum.valueToKey(state)) { - return QString(metaEnum.valueToKey(state)); - } - return "Invalid state"; -} - -QString NMDeviceType::toString(NMDeviceType::Enum type) { - auto metaEnum = QMetaEnum::fromType(); - if (metaEnum.valueToKey(type)) { - return QString(metaEnum.valueToKey(type)); - } - return "Invalid type"; -} - -NMDevice::NMDevice(QObject* parent): QObject(parent) {} - -void NMDevice::init(const QString& path) { - this->device = new DBusNMDevice( - "org.freedesktop.NetworkManager", - path, - QDBusConnection::systemBus(), - this - ); - - if (!this->device->isValid()) { - qCWarning(logNMDevice) << "Cannot create NMDevice for" << path; - return; - } - - this->deviceProperties.setInterface(this->device); - this->deviceProperties.updateAllViaGetAll(); -} - -bool NMDevice::isValid() const { return this->device && this->device->isValid(); } -QString NMDevice::address() const { - return this->device ? this->device->service() : QString(); -} -QString NMDevice::path() const { - return this->device ? this->device->path() : QString(); -} - -} // namespace qs::service::networkmanager - -namespace qs::dbus { - -using namespace qs::service::networkmanager; - -DBusResult -DBusDataTransform::fromWire(quint32 wire) { - return DBusResult(static_cast(wire)); -} - -DBusResult -DBusDataTransform::fromWire(quint32 wire) { - return DBusResult(static_cast(wire)); -} - -} // namespace qs::dbus diff --git a/src/services/networkmanager/device.hpp b/src/services/networkmanager/device.hpp deleted file mode 100644 index 99b473c4..00000000 --- a/src/services/networkmanager/device.hpp +++ /dev/null @@ -1,154 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include - -#include "../../dbus/properties.hpp" -#include "dbus_device.h" - -namespace qs::service::networkmanager { - -class NMDeviceType: public QObject { - Q_OBJECT; - QML_ELEMENT; - QML_SINGLETON; - -public: - enum Enum : quint8 { - Unknown = 0, - Generic = 14, - Ethernet = 1, - Wifi = 2, - Unused1 = 3, - Unused2 = 4, - Bluetooth = 5, - OlpcMesh = 6, - Wimax = 7, - Modem = 8, - Infiniband = 9, - Bond = 10, - Vlan = 11, - Adsl = 12, - Bridge = 13, - Team = 15, - Tun = 16, - Tunnel = 17, - Macvlan = 18, - Vxlan = 19, - Veth = 20, - Macsec = 21, - Dummy = 22, - Ppp = 23, - OvsInterface = 24, - OvsPort = 25, - OvsBridge = 26, - Wpan = 27, - Lowpan = 28, - WireGuard = 29, - WifiP2P = 30, - Vrf = 31, - Loopback = 32, - Hsr = 33, - Ipvlan = 34, - }; - Q_ENUM(Enum); - Q_INVOKABLE static QString toString(NMDeviceType::Enum type); -}; - -class NMDeviceState: public QObject { - Q_OBJECT; - QML_ELEMENT; - QML_SINGLETON; - -public: - enum Enum : quint8 { - Unknown = 0, - Unmanaged = 10, - Unavailable = 20, - Disconnected = 30, - Prepare = 40, - Config = 50, - NeedAuth = 60, - IPConfig = 70, - IPCheck = 80, - Secondaries = 90, - Activated = 100, - Deactivating = 110, - Failed = 120, - }; - Q_ENUM(Enum); - Q_INVOKABLE static QString toString(NMDeviceState::Enum state); -}; - -} // namespace qs::service::networkmanager - -namespace qs::dbus { - -template <> -struct DBusDataTransform { - using Wire = quint32; - using Data = qs::service::networkmanager::NMDeviceState::Enum; - static DBusResult fromWire(Wire wire); -}; - -template <> -struct DBusDataTransform { - using Wire = quint32; - using Data = qs::service::networkmanager::NMDeviceType::Enum; - static DBusResult fromWire(Wire wire); -}; - -} // namespace qs::dbus - -namespace qs::service::networkmanager { - -class NMDevice: public QObject { - Q_OBJECT; - // clang-format off - Q_PROPERTY(NMDeviceType::Enum type READ default NOTIFY typeChanged BINDABLE bindableType); - Q_PROPERTY(NMDeviceState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState); - Q_PROPERTY(QString interface READ default NOTIFY interfaceChanged BINDABLE bindableInterface); - Q_PROPERTY(bool managed READ default NOTIFY managedChanged BINDABLE bindableManaged); - // clang-format on - QML_ELEMENT; - QML_UNCREATABLE("NMDevices can only be acquired from NetworkManager"); - -public: - explicit NMDevice(QObject* parent = nullptr); - void init(const QString& path); - - [[nodiscard]] bool isValid() const; - [[nodiscard]] QString path() const; - [[nodiscard]] QString address() const; - - [[nodiscard]] QBindable bindableType() const { return &this->bType; }; - [[nodiscard]] QBindable bindableState() const { return &this->bState; }; - [[nodiscard]] QBindable bindableManaged() const { return &this->bManaged; }; - [[nodiscard]] QBindable bindableInterface() const { return &this->bInterface; }; - -signals: - void typeChanged(); - void stateChanged(); - void interfaceChanged(); - void managedChanged(); - -private: - // clang-format off - Q_OBJECT_BINDABLE_PROPERTY(NMDevice, NMDeviceType::Enum, bType, &NMDevice::typeChanged); - Q_OBJECT_BINDABLE_PROPERTY(NMDevice, NMDeviceState::Enum, bState, &NMDevice::stateChanged); - Q_OBJECT_BINDABLE_PROPERTY(NMDevice, bool, bManaged, &NMDevice::managedChanged); - Q_OBJECT_BINDABLE_PROPERTY(NMDevice, QString, bInterface, &NMDevice::interfaceChanged); - - QS_DBUS_BINDABLE_PROPERTY_GROUP(NMDevice, deviceProperties); - QS_DBUS_PROPERTY_BINDING(NMDevice, pType, bType, deviceProperties, "DeviceType"); - QS_DBUS_PROPERTY_BINDING(NMDevice, pState, bState, deviceProperties, "State"); - QS_DBUS_PROPERTY_BINDING(NMDevice, pManaged, bManaged, deviceProperties, "Managed"); - QS_DBUS_PROPERTY_BINDING(NMDevice, pInterface, bInterface, deviceProperties, "Interface"); - // clang-format on - - DBusNMDevice* device = nullptr; -}; - -} // namespace qs::service::networkmanager diff --git a/src/services/networkmanager/org.freedesktop.NetworkManager.Device.xml b/src/services/networkmanager/org.freedesktop.NetworkManager.Device.xml deleted file mode 100644 index dbd3be2c..00000000 --- a/src/services/networkmanager/org.freedesktop.NetworkManager.Device.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/src/services/networkmanager/wireless.cpp b/src/services/networkmanager/wireless.cpp deleted file mode 100644 index a490035c..00000000 --- a/src/services/networkmanager/wireless.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "wireless.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include "../../dbus/properties.hpp" -#include "dbus_wireless.h" - -namespace qs::service::networkmanager { - -NMWireless::NMWireless(QObject* parent): QObject(parent) {} - -QString NMWirelessMode::toString(NMWirelessMode::Enum mode) { - switch (mode) { - case NMWirelessMode::Unknown: return "Unknown"; - case NMWirelessMode::Adhoc: return "Adhoc"; - case NMWirelessMode::Infra: return "Infra"; - case NMWirelessMode::AP: return "AP"; - case NMWirelessMode::Mesh: return "Mesh"; - default: return "Unknown"; - } -} - -} // namespace qs::service::networkmanager - -namespace qs::dbus { - -using namespace qs::service::networkmanager; - -DBusResult DBusDataTransform::fromWire(quint32 wire) { - return DBusResult(static_cast(wire)); -} - -} // namespace qs::dbus diff --git a/src/services/networkmanager/wireless.hpp b/src/services/networkmanager/wireless.hpp deleted file mode 100644 index 4c875141..00000000 --- a/src/services/networkmanager/wireless.hpp +++ /dev/null @@ -1,77 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include - -#include "../../dbus/properties.hpp" -#include "dbus_wireless.h" - -namespace qs::service::networkmanager { - -class NMWirelessMode: public QObject { - Q_OBJECT; - QML_ELEMENT; - QML_SINGLETON; - -public: - enum Enum : quint8 { - Unknown = 0, - Adhoc = 1, - Infra = 2, - AP = 3, - Mesh = 4, - }; - Q_ENUM(Enum); - Q_INVOKABLE static QString toString(NMWirelessMode::Enum mode); -}; - -} // namespace qs::service::networkmanager - -namespace qs::dbus { - -template <> -struct DBusDataTransform { - using Wire = quint32; - using Data = qs::service::networkmanager::NMWirelessMode::Enum; - static DBusResult fromWire(Wire wire); -}; - -} // namespace qs::dbus - -namespace qs::service::networkmanager { - -class NMWireless: public QObject { - Q_OBJECT - QML_ELEMENT; - QML_UNCREATABLE("NMWireless can only be acquired from NMDevice"); - //clang-format off - Q_PROPERTY(NMWirelessMode::Enum mode READ default NOTIFY modeChanged BINDABLE bindableMode); - Q_PROPERTY(quint32 bitrate READ default NOTIFY bitrateChanged BINDABLE bindableBitrate); - -public: - explicit NMWireless(QObject* parent = nullptr); - void init(const QString& path); - - [[nodiscard]] bool isValid() const; - [[nodiscard]] QString path() const; - [[nodiscard]] QBindable bindableMode() const { return &this->bMode; }; - [[nodiscard]] QBindable bindableBitrate() const { return &this->bBitrate; }; - -signals: - void modeChanged(); - void bitrateChanged(); - -private: - Q_OBJECT_BINDABLE_PROPERTY(NMWireless, NMWirelessMode::Enum, bMode, &NMWireless::modeChanged); - Q_OBJECT_BINDABLE_PROPERTY(NMWireless, quint32, bBitrate, &NMWireless::bitrateChanged); - - QS_DBUS_BINDABLE_PROPERTY_GROUP(NMWireless, deviceProperties); - QS_DBUS_PROPERTY_BINDING(NMWireless, pMode, bMode, deviceProperties, "Mode"); - QS_DBUS_PROPERTY_BINDING(NMWireless, pBitrate, bBitrate, deviceProperties, "Bitrate"); - - DBusNMWireless* wireless = nullptr; -}; - -} // namespace qs::service::networkmanager From c4d8fc2743a8657f99cf785d4989101a3d62623a Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Fri, 11 Jul 2025 03:40:47 -0500 Subject: [PATCH 16/25] clean --- src/network/note | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 src/network/note diff --git a/src/network/note b/src/network/note deleted file mode 100644 index ef97d8b7..00000000 --- a/src/network/note +++ /dev/null @@ -1,12 +0,0 @@ -Network - - Device(s) - - Name - - Address - - Powered (True/False) - - Wireless: Track the default/current wireless station - - Extends Device - - Disconnect - - Active AccessPoint - - AccessPoints - - Scan - - State Connected,Disconnected,Connecting,Disconnecting,Unknown From 28bf2d756b0725c13cf3c050c34c7f838071b95d Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Fri, 11 Jul 2025 12:54:38 -0500 Subject: [PATCH 17/25] refactor: nm dir --- src/network/CMakeLists.txt | 19 ++++++----- src/network/api.cpp | 5 +-- src/network/nm/CMakeLists.txt | 32 +++++++++++++++++++ src/network/{nm.cpp => nm/backend.cpp} | 10 +++--- src/network/{nm.hpp => nm/backend.hpp} | 8 ++--- src/network/{nmdevice.cpp => nm/device.cpp} | 2 +- src/network/{nmdevice.hpp => nm/device.hpp} | 4 +-- ...freedesktop.NetworkManager.AccessPoint.xml | 11 +++++++ ...desktop.NetworkManager.Device.Wireless.xml | 18 +++++++++++ .../org.freedesktop.NetworkManager.Device.xml | 8 +++++ .../nm/org.freedesktop.NetworkManager.xml | 19 +++++++++++ 11 files changed, 112 insertions(+), 24 deletions(-) create mode 100644 src/network/nm/CMakeLists.txt rename src/network/{nm.cpp => nm/backend.cpp} (96%) rename src/network/{nm.hpp => nm/backend.hpp} (89%) rename src/network/{nmdevice.cpp => nm/device.cpp} (97%) rename src/network/{nmdevice.hpp => nm/device.hpp} (93%) create mode 100644 src/network/nm/org.freedesktop.NetworkManager.AccessPoint.xml create mode 100644 src/network/nm/org.freedesktop.NetworkManager.Device.Wireless.xml create mode 100644 src/network/nm/org.freedesktop.NetworkManager.Device.xml create mode 100644 src/network/nm/org.freedesktop.NetworkManager.xml diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 62bcca2f..c5b556a3 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -1,11 +1,12 @@ +# NetworkManager DBus set_source_files_properties(org.freedesktop.NetworkManager.xml PROPERTIES CLASSNAME DBusNetworkManager NO_NAMESPACE TRUE ) -qt_add_dbus_interface(DBUS_INTERFACES +qt_add_dbus_interface(NM_DBUS_INTERFACES org.freedesktop.NetworkManager.xml - dbus_nm_service + dbus_nm_backend ) set_source_files_properties(org.freedesktop.NetworkManager.Device.xml PROPERTIES @@ -13,7 +14,7 @@ set_source_files_properties(org.freedesktop.NetworkManager.Device.xml PROPERTIES NO_NAMESPACE TRUE ) -qt_add_dbus_interface(DBUS_INTERFACES +qt_add_dbus_interface(NM_DBUS_INTERFACES org.freedesktop.NetworkManager.Device.xml dbus_nm_device ) @@ -23,20 +24,22 @@ set_source_files_properties(org.freedesktop.NetworkManager.Device.Wireless.xml P NO_NAMESPACE TRUE ) -qt_add_dbus_interface(DBUS_INTERFACES +qt_add_dbus_interface(NM_DBUS_INTERFACES org.freedesktop.NetworkManager.Device.Wireless.xml dbus_nm_wireless ) qt_add_library(quickshell-network STATIC api.cpp - nm.cpp - nmdevice.cpp - ${DBUS_INTERFACES} + nm/backend.cpp + nm/device.cpp + ${NM_DBUS_INTERFACES} ) # dbus headers -target_include_directories(quickshell-network PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_include_directories(quickshell-network PRIVATE + ${CMAKE_CURRENT_BINARY_DIR} +) qt_add_qml_module(quickshell-network URI Quickshell.Network diff --git a/src/network/api.cpp b/src/network/api.cpp index 69caad51..3ca36a1a 100644 --- a/src/network/api.cpp +++ b/src/network/api.cpp @@ -8,10 +8,7 @@ #include #include -#include "../core/model.hpp" -#include "../dbus/bus.hpp" -#include "../dbus/properties.hpp" -#include "nm.hpp" +#include "nm/backend.hpp" namespace qs::network { diff --git a/src/network/nm/CMakeLists.txt b/src/network/nm/CMakeLists.txt new file mode 100644 index 00000000..0ad7bdcc --- /dev/null +++ b/src/network/nm/CMakeLists.txt @@ -0,0 +1,32 @@ +set_source_files_properties(org.freedesktop.NetworkManager.xml PROPERTIES + CLASSNAME DBusNetworkManager + NO_NAMESPACE TRUE +) + +qt_add_dbus_interface(NM_DBUS_INTERFACES + org.freedesktop.NetworkManager.xml + dbus_nm_backend +) + +set_source_files_properties(org.freedesktop.NetworkManager.Device.xml PROPERTIES + CLASSNAME DBusNMDevice + NO_NAMESPACE TRUE +) + +qt_add_dbus_interface(NM_DBUS_INTERFACES + org.freedesktop.NetworkManager.Device.xml + dbus_nm_device +) + +set_source_files_properties(org.freedesktop.NetworkManager.Device.Wireless.xml PROPERTIES + CLASSNAME DBusNMWireless + NO_NAMESPACE TRUE +) + +qt_add_dbus_interface(NM_DBUS_INTERFACES + org.freedesktop.NetworkManager.Device.Wireless.xml + dbus_nm_wireless +) + +set(NM_DBUS_INTERFACES ${NM_DBUS_INTERFACES} PARENT_SCOPE) +set(NM_DBUS_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE) diff --git a/src/network/nm.cpp b/src/network/nm/backend.cpp similarity index 96% rename from src/network/nm.cpp rename to src/network/nm/backend.cpp index 1530bc9f..d6034b48 100644 --- a/src/network/nm.cpp +++ b/src/network/nm/backend.cpp @@ -1,4 +1,4 @@ -#include "nm.hpp" +#include "backend.hpp" #include #include @@ -10,10 +10,10 @@ #include #include -#include "../dbus/bus.hpp" -#include "../dbus/properties.hpp" -#include "api.hpp" -#include "dbus_nm_service.h" +#include "../../dbus/bus.hpp" +#include "../../dbus/properties.hpp" +#include "../api.hpp" +#include "dbus_nm_backend.h" namespace qs::network { diff --git a/src/network/nm.hpp b/src/network/nm/backend.hpp similarity index 89% rename from src/network/nm.hpp rename to src/network/nm/backend.hpp index 33177a17..b875b68d 100644 --- a/src/network/nm.hpp +++ b/src/network/nm/backend.hpp @@ -10,10 +10,10 @@ #include #include -#include "../dbus/properties.hpp" -#include "api.hpp" -#include "dbus_nm_service.h" -#include "nmdevice.hpp" +#include "../../dbus/properties.hpp" +#include "../api.hpp" +#include "dbus_nm_backend.h" +#include "device.hpp" namespace qs::network { diff --git a/src/network/nmdevice.cpp b/src/network/nm/device.cpp similarity index 97% rename from src/network/nmdevice.cpp rename to src/network/nm/device.cpp index 7baa89fd..67f762a8 100644 --- a/src/network/nmdevice.cpp +++ b/src/network/nm/device.cpp @@ -1,4 +1,4 @@ -#include "nmdevice.hpp" +#include "device.hpp" #include #include diff --git a/src/network/nmdevice.hpp b/src/network/nm/device.hpp similarity index 93% rename from src/network/nmdevice.hpp rename to src/network/nm/device.hpp index fbd75476..0c7e8a39 100644 --- a/src/network/nmdevice.hpp +++ b/src/network/nm/device.hpp @@ -10,8 +10,8 @@ #include #include -#include "../dbus/properties.hpp" -#include "api.hpp" +#include "../../dbus/properties.hpp" +#include "../api.hpp" #include "dbus_nm_device.h" namespace qs::network { diff --git a/src/network/nm/org.freedesktop.NetworkManager.AccessPoint.xml b/src/network/nm/org.freedesktop.NetworkManager.AccessPoint.xml new file mode 100644 index 00000000..33872050 --- /dev/null +++ b/src/network/nm/org.freedesktop.NetworkManager.AccessPoint.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/network/nm/org.freedesktop.NetworkManager.Device.Wireless.xml b/src/network/nm/org.freedesktop.NetworkManager.Device.Wireless.xml new file mode 100644 index 00000000..17b712bb --- /dev/null +++ b/src/network/nm/org.freedesktop.NetworkManager.Device.Wireless.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + arg name="access_ponit" type="o"/> + + + diff --git a/src/network/nm/org.freedesktop.NetworkManager.Device.xml b/src/network/nm/org.freedesktop.NetworkManager.Device.xml new file mode 100644 index 00000000..9a2b6914 --- /dev/null +++ b/src/network/nm/org.freedesktop.NetworkManager.Device.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/network/nm/org.freedesktop.NetworkManager.xml b/src/network/nm/org.freedesktop.NetworkManager.xml new file mode 100644 index 00000000..4f9ca03e --- /dev/null +++ b/src/network/nm/org.freedesktop.NetworkManager.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + From 1d02e1cc462d3c0e7077c40cb28a71a9dfb216bb Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Fri, 11 Jul 2025 13:02:16 -0500 Subject: [PATCH 18/25] fix: log names --- src/network/api.cpp | 11 ++++++----- src/network/nm/device.cpp | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/network/api.cpp b/src/network/api.cpp index 3ca36a1a..9771f28d 100644 --- a/src/network/api.cpp +++ b/src/network/api.cpp @@ -13,7 +13,7 @@ namespace qs::network { namespace { -Q_LOGGING_CATEGORY(logNetwork, "quickshell.service.network", QtWarningMsg); +Q_LOGGING_CATEGORY(logNetwork, "quickshell.network", QtWarningMsg); } Device::Device(QObject* parent): QObject(parent) {}; @@ -25,11 +25,12 @@ Network::Network(QObject* parent): QObject(parent) { auto* nm = new NetworkManager(); if (nm->isAvailable()) { this->backend = nm; - } else { - // None found - this->backend = nullptr; - qCDebug(logNetwork) << "Network will not work. Could not find an available backend."; + return; } + + // None found + this->backend = nullptr; + qCDebug(logNetwork) << "Network will not work. Could not find an available backend."; } } // namespace qs::network diff --git a/src/network/nm/device.cpp b/src/network/nm/device.cpp index 67f762a8..89e31192 100644 --- a/src/network/nm/device.cpp +++ b/src/network/nm/device.cpp @@ -16,7 +16,7 @@ using namespace qs::dbus; namespace qs::network { namespace { -Q_LOGGING_CATEGORY(logNMDevice, "quickshell.service.networkmanager.device", QtWarningMsg); +Q_LOGGING_CATEGORY(logNMDevice, "quickshell.network.networkmanager.device", QtWarningMsg); } NMDevice::NMDevice(QObject* parent): Device(parent) {} From 112eb66b83eb6aebc01366efad0f4b9ec082a851 Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Fri, 11 Jul 2025 16:24:49 -0500 Subject: [PATCH 19/25] feat: Wireless --- src/network/api.hpp | 79 +++++++++++++++---- src/network/nm/backend.cpp | 22 +++--- src/network/nm/backend.hpp | 13 +-- src/network/nm/device.cpp | 18 +++++ src/network/nm/device.hpp | 12 +++ .../org.freedesktop.NetworkManager.Device.xml | 3 +- src/network/nm/wireless.cpp | 41 ++++++++++ src/network/nm/wireless.hpp | 35 ++++++++ src/network/test/network.qml | 2 +- 9 files changed, 193 insertions(+), 32 deletions(-) create mode 100644 src/network/nm/wireless.cpp create mode 100644 src/network/nm/wireless.hpp diff --git a/src/network/api.hpp b/src/network/api.hpp index ac52e566..a5dfbd21 100644 --- a/src/network/api.hpp +++ b/src/network/api.hpp @@ -15,42 +15,93 @@ namespace qs::network { +// -- Device -- + class Device: public QObject { Q_OBJECT; - Q_PROPERTY(QString name READ default NOTIFY nameChanged BINDABLE bindableName); - Q_PROPERTY(QString address READ default NOTIFY addressChanged BINDABLE bindableAddress); - Q_PROPERTY(bool powered READ default NOTIFY poweredChanged BINDABLE bindablePowered); - QML_ELEMENT; QML_UNCREATABLE("Devices can only be acquired through Network"); + // clang-format off + Q_PROPERTY(QString name READ default NOTIFY nameChanged BINDABLE bindableName); + Q_PROPERTY(QString address READ default NOTIFY addressChanged BINDABLE bindableAddress); + // clang-format on + public: [[nodiscard]] QBindable bindableName() const { return &this->bName; }; [[nodiscard]] QBindable bindableAddress() const { return &this->bAddress; }; - [[nodiscard]] QBindable bindablePowered() const { return &this->bPowered; }; signals: void nameChanged(); void addressChanged(); - void poweredChanged(); protected: explicit Device(QObject* parent = nullptr); Q_OBJECT_BINDABLE_PROPERTY(Device, QString, bName, &Device::nameChanged); - Q_OBJECT_BINDABLE_PROPERTY(Device, bool, bPowered, &Device::poweredChanged); Q_OBJECT_BINDABLE_PROPERTY(Device, QString, bAddress, &Device::addressChanged); QS_DBUS_BINDABLE_PROPERTY_GROUP(Device, deviceProperties); }; -// class WirelessDevice; +// -- Wireless Device -- + +class WirelessState: public QObject { + Q_OBJECT; + QML_ELEMENT; + QML_SINGLETON; + +public: + enum Enum : quint8 { + Unknown = 0, + Disconnected = 10, + Connecting = 20, + Connected = 30, + Disconnecting = 40, + }; + Q_ENUM(Enum); +}; + +class Wireless: public QObject { + Q_OBJECT; + // clang-format off + Q_PROPERTY(bool powered READ powered WRITE setPowered NOTIFY poweredChanged); + Q_PROPERTY(WirelessState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState); + //clang-format on + +public: + Q_INVOKABLE virtual void disconnect() = 0; + Q_INVOKABLE virtual void scan() = 0; + + [[nodiscard]] bool powered() const { return this->bPowered; }; + virtual void setPowered(bool powered) = 0; + + [[nodiscard]] QBindable bindablePowered() { return &this->bPowered; }; + [[nodiscard]] QBindable bindableState() const { return &this->bState; }; + +signals: + void poweredChanged(); + void stateChanged(); + +protected: + explicit Wireless(QObject* parent = nullptr); + Q_OBJECT_BINDABLE_PROPERTY(Wireless, bool, bPowered, &Wireless::poweredChanged); + Q_OBJECT_BINDABLE_PROPERTY( + Wireless, + WirelessState::Enum, + bState, + &Wireless::stateChanged + ); + QS_DBUS_BINDABLE_PROPERTY_GROUP(Wireless, wirelessProperties); +}; + +// -- Network -- class NetworkBackend: public QObject { Q_OBJECT; public: [[nodiscard]] virtual bool isAvailable() const = 0; - virtual Device* wireless() = 0; - virtual UntypedObjectModel* allDevices() = 0; + virtual Device* wifiDevice() = 0; + virtual UntypedObjectModel* devices() = 0; protected: explicit NetworkBackend(QObject* parent = nullptr): QObject(parent) {}; @@ -61,13 +112,13 @@ class Network: public QObject { QML_NAMED_ELEMENT(Network); QML_SINGLETON; - Q_PROPERTY(Device* wireless READ wireless CONSTANT); - Q_PROPERTY(UntypedObjectModel* allDevices READ allDevices CONSTANT); + Q_PROPERTY(Device* wifiDevice READ wifiDevice CONSTANT); + Q_PROPERTY(UntypedObjectModel* devices READ devices CONSTANT); public: explicit Network(QObject* parent = nullptr); - [[nodiscard]] Device* wireless() { return backend ? backend->wireless() : nullptr; } - [[nodiscard]] UntypedObjectModel* allDevices() { return backend ? backend->allDevices() : nullptr; } + [[nodiscard]] Device* wifiDevice() { return backend ? backend->wifiDevice() : nullptr; } + [[nodiscard]] UntypedObjectModel* devices() { return backend ? backend->devices() : nullptr; } private: void findBackend(); diff --git a/src/network/nm/backend.cpp b/src/network/nm/backend.cpp index d6034b48..dd60f6cc 100644 --- a/src/network/nm/backend.cpp +++ b/src/network/nm/backend.cpp @@ -18,7 +18,7 @@ namespace qs::network { namespace { -Q_LOGGING_CATEGORY(logNetworkManager, "quickshell.service.networkmanager", QtWarningMsg); +Q_LOGGING_CATEGORY(logNetworkManager, "quickshell.network.networkmanager", QtWarningMsg); } const QString NM_SERVICE = "org.freedesktop.NetworkManager"; @@ -34,9 +34,9 @@ NetworkManager::NetworkManager(QObject* parent): NetworkBackend(parent) { return; } - this->service = new DBusNetworkManager(NM_SERVICE, NM_PATH, bus, this); + this->dbus = new DBusNetworkManager(NM_SERVICE, NM_PATH, bus, this); - if (!this->service->isValid()) { + if (!this->dbus->isValid()) { qCDebug(logNetworkManager ) << "NetworkManager service is not currently running, attempting to start it."; @@ -56,27 +56,27 @@ NetworkManager::NetworkManager(QObject* parent): NetworkBackend(parent) { void NetworkManager::init() { QObject::connect( - this->service, + this->dbus, &DBusNetworkManager::DeviceAdded, this, &NetworkManager::onDeviceAdded ); QObject::connect( - this->service, + this->dbus, &DBusNetworkManager::DeviceRemoved, this, &NetworkManager::onDeviceRemoved ); - this->serviceProperties.setInterface(this->service); - this->serviceProperties.updateAllViaGetAll(); + this->dbusProperties.setInterface(this->dbus); + this->dbusProperties.updateAllViaGetAll(); this->registerDevices(); } void NetworkManager::registerDevices() { - auto pending = this->service->GetAllDevices(); + auto pending = this->dbus->GetAllDevices(); auto* call = new QDBusPendingCallWatcher(pending, this); auto responseCallback = [this](QDBusPendingCallWatcher* call) { @@ -134,8 +134,8 @@ void NetworkManager::onDeviceRemoved(const QDBusObjectPath& path) { } } -UntypedObjectModel* NetworkManager::allDevices() { return &this->mDevices; } -NMDevice* NetworkManager::wireless() { return &this->mWireless; } -bool NetworkManager::isAvailable() const { return this->service && this->service->isValid(); } +UntypedObjectModel* NetworkManager::devices() { return &this->mDevices; } +NMDevice* NetworkManager::wifiDevice() { return &this->mWifi; } +bool NetworkManager::isAvailable() const { return this->dbus && this->dbus->isValid(); } } // namespace qs::network diff --git a/src/network/nm/backend.hpp b/src/network/nm/backend.hpp index b875b68d..81f86633 100644 --- a/src/network/nm/backend.hpp +++ b/src/network/nm/backend.hpp @@ -23,10 +23,13 @@ class NetworkManager: public NetworkBackend { public: explicit NetworkManager(QObject* parent = nullptr); - UntypedObjectModel* allDevices() override; - NMDevice* wireless() override; + UntypedObjectModel* devices() override; + NMDevice* wifiDevice() override; [[nodiscard]] bool isAvailable() const override; +signals: + void wifiPoweredChanged(); + private slots: void onDeviceAdded(const QDBusObjectPath& path); void onDeviceRemoved(const QDBusObjectPath& path); @@ -38,11 +41,11 @@ private slots: QHash mDeviceHash; ObjectModel mDevices {this}; - NMDevice mWireless; + NMDevice mWifi; - QS_DBUS_BINDABLE_PROPERTY_GROUP(NetworkManager, serviceProperties); + QS_DBUS_BINDABLE_PROPERTY_GROUP(NetworkManager, dbusProperties); - DBusNetworkManager* service = nullptr; + DBusNetworkManager* dbus = nullptr; }; } // namespace qs::network diff --git a/src/network/nm/device.cpp b/src/network/nm/device.cpp index 89e31192..74cfa8e7 100644 --- a/src/network/nm/device.cpp +++ b/src/network/nm/device.cpp @@ -10,6 +10,7 @@ #include "../dbus/properties.hpp" #include "dbus_nm_device.h" +#include "wireless.hpp" using namespace qs::dbus; @@ -30,10 +31,27 @@ void NMDevice::init(const QString& path) { return; } + // If device type is wifi + if (this->device->property("type").toUInt() == 2) { + registerWireless(path); + } this->deviceProperties.setInterface(this->device); this->deviceProperties.updateAllViaGetAll(); } +void NMDevice::registerWireless(const QString& path) { + auto* device = new NMDevice(this); + device->init(path); + + if (!device->isValid()) { + qCWarning(logNMDevice) << "Ignoring invalid NMWireless registration of" << path; + delete device; + return; + } + + qCDebug(logNMDevice) << "Registered NMDevice" << path; +} + bool NMDevice::isValid() const { return this->device && this->device->isValid(); } QString NMDevice::address() const { return this->device ? this->device->service() : QString(); } QString NMDevice::path() const { return this->device ? this->device->path() : QString(); } diff --git a/src/network/nm/device.hpp b/src/network/nm/device.hpp index 0c7e8a39..ee5085f6 100644 --- a/src/network/nm/device.hpp +++ b/src/network/nm/device.hpp @@ -13,6 +13,7 @@ #include "../../dbus/properties.hpp" #include "../api.hpp" #include "dbus_nm_device.h" +#include "wireless.hpp" namespace qs::network { @@ -22,15 +23,26 @@ class NMDevice: public Device { public: explicit NMDevice(QObject* parent = nullptr); void init(const QString& path); + void registerWireless(const QString& path); [[nodiscard]] bool isValid() const; [[nodiscard]] QString path() const; [[nodiscard]] QString address() const; +signals: + void typeChanged(); + private: + // Needed to check if WiFi + [[nodiscard]] QBindable bindableType() const { return &this->bType; }; + Q_PROPERTY(quint32 type READ default NOTIFY typeChanged BINDABLE bindableType); + Q_OBJECT_BINDABLE_PROPERTY(NMDevice, quint32, bType, &Device::nameChanged); + QS_DBUS_PROPERTY_BINDING(NMDevice, pType, bType, deviceProperties, "DeviceType"); + QS_DBUS_PROPERTY_BINDING(NMDevice, pName, bName, deviceProperties, "Interface"); QS_DBUS_PROPERTY_BINDING(NMDevice, pAddress, bAddress, deviceProperties, "HwAddress"); DBusNMDevice* device = nullptr; + NMWireless* wireless = nullptr; }; } // namespace qs::network diff --git a/src/network/nm/org.freedesktop.NetworkManager.Device.xml b/src/network/nm/org.freedesktop.NetworkManager.Device.xml index 9a2b6914..f230778f 100644 --- a/src/network/nm/org.freedesktop.NetworkManager.Device.xml +++ b/src/network/nm/org.freedesktop.NetworkManager.Device.xml @@ -2,7 +2,8 @@ + + - diff --git a/src/network/nm/wireless.cpp b/src/network/nm/wireless.cpp new file mode 100644 index 00000000..21feae6f --- /dev/null +++ b/src/network/nm/wireless.cpp @@ -0,0 +1,41 @@ +#include "wireless.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include "../dbus/properties.hpp" +#include "dbus_nm_wireless.h" + +using namespace qs::dbus; + +namespace qs::network { + +namespace { +Q_LOGGING_CATEGORY(logNMDevice, "quickshell.network.networkmanager.wireless", QtWarningMsg); +} + +NMWireless::NMWireless(QObject* parent): Wireless(parent) {} + +void NMWireless::init(const QString& path) { + this->wireless = + new DBusNMWireless("org.freedesktop.NetworkManager", path, QDBusConnection::systemBus(), this); + + if (!this->wireless->isValid()) { + qCWarning(logNMDevice) << "Cannot create NMDevice for" << path; + return; + } + + this->wirelessProperties.setInterface(this->wireless); + this->wirelessProperties.updateAllViaGetAll(); +} + +bool NMWireless::isValid() const { return this->wireless && this->wireless->isValid(); } +QString NMWireless::address() const { return this->wireless ? this->wireless->service() : QString(); } +QString NMWireless::path() const { return this->wireless ? this->wireless->path() : QString(); } + +} // namespace qs::network diff --git a/src/network/nm/wireless.hpp b/src/network/nm/wireless.hpp new file mode 100644 index 00000000..b8b0364b --- /dev/null +++ b/src/network/nm/wireless.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../api.hpp" +#include "dbus_nm_wireless.h" + +namespace qs::network { + +class NMWireless: public Wireless { + Q_OBJECT; + +public: + explicit NMWireless(QObject* parent = nullptr); + void disconnect() override; + void scan() override; + void setPowered(bool powered) override; + void init(const QString& path); + [[nodiscard]] bool isValid() const; + [[nodiscard]] QString path() const; + [[nodiscard]] QString address() const; + +private: + DBusNMWireless* wireless = nullptr; +}; + +} // namespace qs::network diff --git a/src/network/test/network.qml b/src/network/test/network.qml index 139ff9f9..6284c3bd 100644 --- a/src/network/test/network.qml +++ b/src/network/test/network.qml @@ -16,7 +16,7 @@ FloatingWindow { ListView { Layout.fillWidth: true Layout.fillHeight: true - model: Network.allDevices + model: Network.devices delegate: WrapperRectangle { width: parent.width From 87787dce24518a7e2286b3ee961596531568a3e7 Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Mon, 14 Jul 2025 11:33:44 -0500 Subject: [PATCH 20/25] feat: frontend slots --- src/network/CMakeLists.txt | 8 ++--- src/network/api.cpp | 18 +++++++++++ src/network/api.hpp | 49 ++++++++++++++++------------- src/network/nm/CMakeLists.txt | 32 ------------------- src/network/nm/adapters.cpp | 47 ++++++++++++++++++++++++++++ src/network/nm/adapters.hpp | 46 +++++++++++++++++++++++++++ src/network/nm/backend.cpp | 43 +++++++++++++++---------- src/network/nm/backend.hpp | 13 +++----- src/network/nm/device.cpp | 59 ----------------------------------- src/network/nm/device.hpp | 48 ---------------------------- src/network/nm/wireless.cpp | 41 ------------------------ src/network/nm/wireless.hpp | 35 --------------------- 12 files changed, 172 insertions(+), 267 deletions(-) delete mode 100644 src/network/nm/CMakeLists.txt create mode 100644 src/network/nm/adapters.cpp create mode 100644 src/network/nm/adapters.hpp delete mode 100644 src/network/nm/device.cpp delete mode 100644 src/network/nm/device.hpp delete mode 100644 src/network/nm/wireless.cpp delete mode 100644 src/network/nm/wireless.hpp diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index c5b556a3..718665b0 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -1,6 +1,6 @@ # NetworkManager DBus set_source_files_properties(org.freedesktop.NetworkManager.xml PROPERTIES - CLASSNAME DBusNetworkManager + CLASSNAME DBusNetworkManagerProxy NO_NAMESPACE TRUE ) @@ -10,7 +10,7 @@ qt_add_dbus_interface(NM_DBUS_INTERFACES ) set_source_files_properties(org.freedesktop.NetworkManager.Device.xml PROPERTIES - CLASSNAME DBusNMDevice + CLASSNAME DBusNMDeviceProxy NO_NAMESPACE TRUE ) @@ -20,7 +20,7 @@ qt_add_dbus_interface(NM_DBUS_INTERFACES ) set_source_files_properties(org.freedesktop.NetworkManager.Device.Wireless.xml PROPERTIES - CLASSNAME DBusNMWireless + CLASSNAME DBusNMWirelessProxy NO_NAMESPACE TRUE ) @@ -32,7 +32,7 @@ qt_add_dbus_interface(NM_DBUS_INTERFACES qt_add_library(quickshell-network STATIC api.cpp nm/backend.cpp - nm/device.cpp + nm/adapters.cpp ${NM_DBUS_INTERFACES} ) diff --git a/src/network/api.cpp b/src/network/api.cpp index 9771f28d..43c1dbf8 100644 --- a/src/network/api.cpp +++ b/src/network/api.cpp @@ -18,6 +18,24 @@ Q_LOGGING_CATEGORY(logNetwork, "quickshell.network", QtWarningMsg); Device::Device(QObject* parent): QObject(parent) {}; +void Device::setName(const QString& name) { + if (name != this->bName) { + this->bName = name; + } +} + +void Device::setAddress(const QString& address) { + if (address != this->bAddress) { + this->bAddress = address; + } +} + +void WirelessDevice::setState(WirelessState::Enum state) { + if (state != this->bState) { + this->bState = state; + } +} + Network::Network(QObject* parent): QObject(parent) { // Try each backend diff --git a/src/network/api.hpp b/src/network/api.hpp index a5dfbd21..67c4319a 100644 --- a/src/network/api.hpp +++ b/src/network/api.hpp @@ -11,7 +11,6 @@ #include #include "../core/model.hpp" -#include "../dbus/properties.hpp" namespace qs::network { @@ -27,19 +26,22 @@ class Device: public QObject { Q_PROPERTY(QString address READ default NOTIFY addressChanged BINDABLE bindableAddress); // clang-format on -public: - [[nodiscard]] QBindable bindableName() const { return &this->bName; }; - [[nodiscard]] QBindable bindableAddress() const { return &this->bAddress; }; - signals: void nameChanged(); void addressChanged(); -protected: +public slots: + void setName(const QString& name); + void setAddress(const QString& address); + +public: explicit Device(QObject* parent = nullptr); + [[nodiscard]] QBindable bindableName() const { return &this->bName; }; + [[nodiscard]] QBindable bindableAddress() const { return &this->bAddress; }; + +private: Q_OBJECT_BINDABLE_PROPERTY(Device, QString, bName, &Device::nameChanged); Q_OBJECT_BINDABLE_PROPERTY(Device, QString, bAddress, &Device::addressChanged); - QS_DBUS_BINDABLE_PROPERTY_GROUP(Device, deviceProperties); }; // -- Wireless Device -- @@ -60,14 +62,24 @@ class WirelessState: public QObject { Q_ENUM(Enum); }; -class Wireless: public QObject { +class WirelessDevice: public Device { Q_OBJECT; + // clang-format off Q_PROPERTY(bool powered READ powered WRITE setPowered NOTIFY poweredChanged); Q_PROPERTY(WirelessState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState); //clang-format on +signals: + void poweredChanged(); + void stateChanged(); + +private slots: + void setState(WirelessState::Enum state); + public: + explicit WirelessDevice(QObject* parent = nullptr); + Q_INVOKABLE virtual void disconnect() = 0; Q_INVOKABLE virtual void scan() = 0; @@ -77,20 +89,14 @@ class Wireless: public QObject { [[nodiscard]] QBindable bindablePowered() { return &this->bPowered; }; [[nodiscard]] QBindable bindableState() const { return &this->bState; }; -signals: - void poweredChanged(); - void stateChanged(); - -protected: - explicit Wireless(QObject* parent = nullptr); - Q_OBJECT_BINDABLE_PROPERTY(Wireless, bool, bPowered, &Wireless::poweredChanged); +private: + Q_OBJECT_BINDABLE_PROPERTY(WirelessDevice, bool, bPowered, &WirelessDevice::poweredChanged); Q_OBJECT_BINDABLE_PROPERTY( - Wireless, + WirelessDevice, WirelessState::Enum, bState, - &Wireless::stateChanged + &WirelessDevice::stateChanged ); - QS_DBUS_BINDABLE_PROPERTY_GROUP(Wireless, wirelessProperties); }; // -- Network -- @@ -100,7 +106,7 @@ class NetworkBackend: public QObject { public: [[nodiscard]] virtual bool isAvailable() const = 0; - virtual Device* wifiDevice() = 0; + // virtual WirelessDevice* wifiDevice() = 0; virtual UntypedObjectModel* devices() = 0; protected: @@ -112,16 +118,15 @@ class Network: public QObject { QML_NAMED_ELEMENT(Network); QML_SINGLETON; - Q_PROPERTY(Device* wifiDevice READ wifiDevice CONSTANT); + // Q_PROPERTY(WirelessDevice* wifi READ wifiDevice CONSTANT); Q_PROPERTY(UntypedObjectModel* devices READ devices CONSTANT); public: explicit Network(QObject* parent = nullptr); - [[nodiscard]] Device* wifiDevice() { return backend ? backend->wifiDevice() : nullptr; } + // [[nodiscard]] WirelessDevice* wifi() { return backend ? backend->wifiDevice() : nullptr; } [[nodiscard]] UntypedObjectModel* devices() { return backend ? backend->devices() : nullptr; } private: - void findBackend(); class NetworkBackend* backend = nullptr; }; diff --git a/src/network/nm/CMakeLists.txt b/src/network/nm/CMakeLists.txt deleted file mode 100644 index 0ad7bdcc..00000000 --- a/src/network/nm/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -set_source_files_properties(org.freedesktop.NetworkManager.xml PROPERTIES - CLASSNAME DBusNetworkManager - NO_NAMESPACE TRUE -) - -qt_add_dbus_interface(NM_DBUS_INTERFACES - org.freedesktop.NetworkManager.xml - dbus_nm_backend -) - -set_source_files_properties(org.freedesktop.NetworkManager.Device.xml PROPERTIES - CLASSNAME DBusNMDevice - NO_NAMESPACE TRUE -) - -qt_add_dbus_interface(NM_DBUS_INTERFACES - org.freedesktop.NetworkManager.Device.xml - dbus_nm_device -) - -set_source_files_properties(org.freedesktop.NetworkManager.Device.Wireless.xml PROPERTIES - CLASSNAME DBusNMWireless - NO_NAMESPACE TRUE -) - -qt_add_dbus_interface(NM_DBUS_INTERFACES - org.freedesktop.NetworkManager.Device.Wireless.xml - dbus_nm_wireless -) - -set(NM_DBUS_INTERFACES ${NM_DBUS_INTERFACES} PARENT_SCOPE) -set(NM_DBUS_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE) diff --git a/src/network/nm/adapters.cpp b/src/network/nm/adapters.cpp new file mode 100644 index 00000000..a7f9c78a --- /dev/null +++ b/src/network/nm/adapters.cpp @@ -0,0 +1,47 @@ +#include "adapters.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include "../dbus/properties.hpp" +#include "dbus_nm_device.h" + +using namespace qs::dbus; + +namespace qs::network { + +namespace { +Q_LOGGING_CATEGORY(logNMDevice, "quickshell.network.networkmanager.device", QtWarningMsg); +} + +NMDeviceAdapter::NMDeviceAdapter(QObject* parent): QObject(parent) {} + +void NMDeviceAdapter::init(const QString& path) { + this->proxy = new DBusNMDeviceProxy( + "org.freedesktop.NetworkManager", + path, + QDBusConnection::systemBus(), + this + ); + + if (!this->proxy->isValid()) { + qCWarning(logNMDevice) << "Cannot create NMDevice for" << path; + return; + } + + this->deviceProperties.setInterface(this->proxy); + this->deviceProperties.updateAllViaGetAll(); +} + +bool NMDeviceAdapter::isValid() const { return this->proxy && this->proxy->isValid(); } +QString NMDeviceAdapter::address() const { + return this->proxy ? this->proxy->service() : QString(); +} +QString NMDeviceAdapter::path() const { return this->proxy ? this->proxy->path() : QString(); } + +} // namespace qs::network diff --git a/src/network/nm/adapters.hpp b/src/network/nm/adapters.hpp new file mode 100644 index 00000000..cbbedced --- /dev/null +++ b/src/network/nm/adapters.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../dbus/properties.hpp" +#include "../api.hpp" +#include "dbus_nm_device.h" + +namespace qs::network { + +class NMDeviceAdapter: public QObject { + Q_OBJECT; + +public: + explicit NMDeviceAdapter(QObject* parent = nullptr); + void init(const QString& path); + [[nodiscard]] bool isValid() const; + [[nodiscard]] QString path() const; + [[nodiscard]] QString address() const; + [[nodiscard]] QString getInterface() { return this->bInterface; }; + [[nodiscard]] QString getHwAddress() { return this->bHwAddress; }; + +signals: + void interfaceChanged(const QString& interface); + void hwAddressChanged(const QString& hwAddress); + +private: + Q_OBJECT_BINDABLE_PROPERTY(NMDeviceAdapter, QString, bInterface, &NMDeviceAdapter::interfaceChanged); + Q_OBJECT_BINDABLE_PROPERTY(NMDeviceAdapter, QString, bHwAddress, &NMDeviceAdapter::hwAddressChanged); + + QS_DBUS_BINDABLE_PROPERTY_GROUP(NMDeviceAdapter, deviceProperties); + QS_DBUS_PROPERTY_BINDING(NMDeviceAdapter, pName, bInterface, deviceProperties, "Interface"); + QS_DBUS_PROPERTY_BINDING(NMDeviceAdapter, pAddress, bHwAddress, deviceProperties, "HwAddress"); + + DBusNMDeviceProxy* proxy = nullptr; +}; + +} // namespace qs::network diff --git a/src/network/nm/backend.cpp b/src/network/nm/backend.cpp index dd60f6cc..af55c75c 100644 --- a/src/network/nm/backend.cpp +++ b/src/network/nm/backend.cpp @@ -14,6 +14,7 @@ #include "../../dbus/properties.hpp" #include "../api.hpp" #include "dbus_nm_backend.h" +#include "adapters.hpp" namespace qs::network { @@ -34,9 +35,9 @@ NetworkManager::NetworkManager(QObject* parent): NetworkBackend(parent) { return; } - this->dbus = new DBusNetworkManager(NM_SERVICE, NM_PATH, bus, this); + this->proxy = new DBusNetworkManagerProxy(NM_SERVICE, NM_PATH, bus, this); - if (!this->dbus->isValid()) { + if (!this->proxy->isValid()) { qCDebug(logNetworkManager ) << "NetworkManager service is not currently running, attempting to start it."; @@ -56,27 +57,27 @@ NetworkManager::NetworkManager(QObject* parent): NetworkBackend(parent) { void NetworkManager::init() { QObject::connect( - this->dbus, - &DBusNetworkManager::DeviceAdded, + this->proxy, + &DBusNetworkManagerProxy::DeviceAdded, this, &NetworkManager::onDeviceAdded ); QObject::connect( - this->dbus, - &DBusNetworkManager::DeviceRemoved, + this->proxy, + &DBusNetworkManagerProxy::DeviceRemoved, this, &NetworkManager::onDeviceRemoved ); - this->dbusProperties.setInterface(this->dbus); + this->dbusProperties.setInterface(this->proxy); this->dbusProperties.updateAllViaGetAll(); this->registerDevices(); } void NetworkManager::registerDevices() { - auto pending = this->dbus->GetAllDevices(); + auto pending = this->proxy->GetAllDevices(); auto* call = new QDBusPendingCallWatcher(pending, this); auto responseCallback = [this](QDBusPendingCallWatcher* call) { @@ -98,22 +99,30 @@ void NetworkManager::registerDevices() { void NetworkManager::registerDevice(const QString& path) { if (this->mDeviceHash.contains(path)) { - qCDebug(logNetworkManager) << "Skipping duplicate registration of NMDevice" << path; + qCDebug(logNetworkManager) << "Skipping duplicate registration of device" << path; return; } - auto* device = new NMDevice(this); - device->init(path); + auto* device = new Device(this); + auto* deviceAdapter = new NMDeviceAdapter(device); - if (!device->isValid()) { - qCWarning(logNetworkManager) << "Ignoring invalid NMDevice registration of" << path; + deviceAdapter->init(path); + + if (!deviceAdapter->isValid()) { + qCWarning(logNetworkManager) << "Ignoring invalid Device registration of" << path; delete device; return; } + + device->setAddress(deviceAdapter->getHwAddress()); + device->setName(deviceAdapter->getInterface()); + QObject::connect(deviceAdapter, &NMDeviceAdapter::hwAddressChanged, device, &Device::setAddress); + QObject::connect(deviceAdapter, &NMDeviceAdapter::interfaceChanged, device, &Device::setName); + this->mDeviceHash.insert(path, device); this->mDevices.insertObject(device); - qCDebug(logNetworkManager) << "Registered NMDevice" << path; + qCDebug(logNetworkManager) << "Registered Device" << path; } void NetworkManager::onDeviceAdded(const QDBusObjectPath& path) { @@ -130,12 +139,12 @@ void NetworkManager::onDeviceRemoved(const QDBusObjectPath& path) { auto* device = iter.value(); this->mDeviceHash.erase(iter); this->mDevices.removeObject(device); - qCDebug(logNetworkManager) << "NMDevice" << device->path() << "removed."; + qCDebug(logNetworkManager) << "Device" << path.path() << "removed."; } } UntypedObjectModel* NetworkManager::devices() { return &this->mDevices; } -NMDevice* NetworkManager::wifiDevice() { return &this->mWifi; } -bool NetworkManager::isAvailable() const { return this->dbus && this->dbus->isValid(); } +// WirelessDevice* NetworkManager::wifiDevice() { return &this->mWifi; } +bool NetworkManager::isAvailable() const { return this->proxy && this->proxy->isValid(); } } // namespace qs::network diff --git a/src/network/nm/backend.hpp b/src/network/nm/backend.hpp index 81f86633..4b597d3d 100644 --- a/src/network/nm/backend.hpp +++ b/src/network/nm/backend.hpp @@ -13,7 +13,6 @@ #include "../../dbus/properties.hpp" #include "../api.hpp" #include "dbus_nm_backend.h" -#include "device.hpp" namespace qs::network { @@ -24,12 +23,9 @@ class NetworkManager: public NetworkBackend { explicit NetworkManager(QObject* parent = nullptr); UntypedObjectModel* devices() override; - NMDevice* wifiDevice() override; + // WirelessDevice* wifiDevice() override; [[nodiscard]] bool isAvailable() const override; -signals: - void wifiPoweredChanged(); - private slots: void onDeviceAdded(const QDBusObjectPath& path); void onDeviceRemoved(const QDBusObjectPath& path); @@ -39,13 +35,12 @@ private slots: void registerDevice(const QString& path); void registerDevices(); - QHash mDeviceHash; - ObjectModel mDevices {this}; - NMDevice mWifi; + QHash mDeviceHash; + ObjectModel mDevices {this}; QS_DBUS_BINDABLE_PROPERTY_GROUP(NetworkManager, dbusProperties); - DBusNetworkManager* dbus = nullptr; + DBusNetworkManagerProxy* proxy = nullptr; }; } // namespace qs::network diff --git a/src/network/nm/device.cpp b/src/network/nm/device.cpp deleted file mode 100644 index 74cfa8e7..00000000 --- a/src/network/nm/device.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "device.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include "../dbus/properties.hpp" -#include "dbus_nm_device.h" -#include "wireless.hpp" - -using namespace qs::dbus; - -namespace qs::network { - -namespace { -Q_LOGGING_CATEGORY(logNMDevice, "quickshell.network.networkmanager.device", QtWarningMsg); -} - -NMDevice::NMDevice(QObject* parent): Device(parent) {} - -void NMDevice::init(const QString& path) { - this->device = - new DBusNMDevice("org.freedesktop.NetworkManager", path, QDBusConnection::systemBus(), this); - - if (!this->device->isValid()) { - qCWarning(logNMDevice) << "Cannot create NMDevice for" << path; - return; - } - - // If device type is wifi - if (this->device->property("type").toUInt() == 2) { - registerWireless(path); - } - this->deviceProperties.setInterface(this->device); - this->deviceProperties.updateAllViaGetAll(); -} - -void NMDevice::registerWireless(const QString& path) { - auto* device = new NMDevice(this); - device->init(path); - - if (!device->isValid()) { - qCWarning(logNMDevice) << "Ignoring invalid NMWireless registration of" << path; - delete device; - return; - } - - qCDebug(logNMDevice) << "Registered NMDevice" << path; -} - -bool NMDevice::isValid() const { return this->device && this->device->isValid(); } -QString NMDevice::address() const { return this->device ? this->device->service() : QString(); } -QString NMDevice::path() const { return this->device ? this->device->path() : QString(); } - -} // namespace qs::network diff --git a/src/network/nm/device.hpp b/src/network/nm/device.hpp deleted file mode 100644 index ee5085f6..00000000 --- a/src/network/nm/device.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../dbus/properties.hpp" -#include "../api.hpp" -#include "dbus_nm_device.h" -#include "wireless.hpp" - -namespace qs::network { - -class NMDevice: public Device { - Q_OBJECT; - -public: - explicit NMDevice(QObject* parent = nullptr); - void init(const QString& path); - void registerWireless(const QString& path); - [[nodiscard]] bool isValid() const; - [[nodiscard]] QString path() const; - [[nodiscard]] QString address() const; - -signals: - void typeChanged(); - -private: - // Needed to check if WiFi - [[nodiscard]] QBindable bindableType() const { return &this->bType; }; - Q_PROPERTY(quint32 type READ default NOTIFY typeChanged BINDABLE bindableType); - Q_OBJECT_BINDABLE_PROPERTY(NMDevice, quint32, bType, &Device::nameChanged); - QS_DBUS_PROPERTY_BINDING(NMDevice, pType, bType, deviceProperties, "DeviceType"); - - QS_DBUS_PROPERTY_BINDING(NMDevice, pName, bName, deviceProperties, "Interface"); - QS_DBUS_PROPERTY_BINDING(NMDevice, pAddress, bAddress, deviceProperties, "HwAddress"); - - DBusNMDevice* device = nullptr; - NMWireless* wireless = nullptr; -}; - -} // namespace qs::network diff --git a/src/network/nm/wireless.cpp b/src/network/nm/wireless.cpp deleted file mode 100644 index 21feae6f..00000000 --- a/src/network/nm/wireless.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "wireless.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include "../dbus/properties.hpp" -#include "dbus_nm_wireless.h" - -using namespace qs::dbus; - -namespace qs::network { - -namespace { -Q_LOGGING_CATEGORY(logNMDevice, "quickshell.network.networkmanager.wireless", QtWarningMsg); -} - -NMWireless::NMWireless(QObject* parent): Wireless(parent) {} - -void NMWireless::init(const QString& path) { - this->wireless = - new DBusNMWireless("org.freedesktop.NetworkManager", path, QDBusConnection::systemBus(), this); - - if (!this->wireless->isValid()) { - qCWarning(logNMDevice) << "Cannot create NMDevice for" << path; - return; - } - - this->wirelessProperties.setInterface(this->wireless); - this->wirelessProperties.updateAllViaGetAll(); -} - -bool NMWireless::isValid() const { return this->wireless && this->wireless->isValid(); } -QString NMWireless::address() const { return this->wireless ? this->wireless->service() : QString(); } -QString NMWireless::path() const { return this->wireless ? this->wireless->path() : QString(); } - -} // namespace qs::network diff --git a/src/network/nm/wireless.hpp b/src/network/nm/wireless.hpp deleted file mode 100644 index b8b0364b..00000000 --- a/src/network/nm/wireless.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../api.hpp" -#include "dbus_nm_wireless.h" - -namespace qs::network { - -class NMWireless: public Wireless { - Q_OBJECT; - -public: - explicit NMWireless(QObject* parent = nullptr); - void disconnect() override; - void scan() override; - void setPowered(bool powered) override; - void init(const QString& path); - [[nodiscard]] bool isValid() const; - [[nodiscard]] QString path() const; - [[nodiscard]] QString address() const; - -private: - DBusNMWireless* wireless = nullptr; -}; - -} // namespace qs::network From bdaaa5f633bd8e3246a71aea3844f77a0cef3e62 Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Mon, 14 Jul 2025 18:28:04 -0500 Subject: [PATCH 21/25] feat: state, working subdevices --- src/network/CMakeLists.txt | 4 +- src/network/api.cpp | 22 ++- src/network/api.hpp | 79 ++++---- src/network/nm/adapters.cpp | 47 ----- src/network/nm/adapters.hpp | 46 ----- ...freedesktop.NetworkManager.AccessPoint.xml | 11 -- ...desktop.NetworkManager.Device.Wireless.xml | 18 -- .../org.freedesktop.NetworkManager.Device.xml | 9 - .../nm/org.freedesktop.NetworkManager.xml | 19 -- src/network/nm_adapters.cpp | 95 ++++++++++ src/network/nm_adapters.hpp | 168 ++++++++++++++++++ .../{nm/backend.cpp => nm_backend.cpp} | 92 ++++++++-- .../{nm/backend.hpp => nm_backend.hpp} | 14 +- .../org.freedesktop.NetworkManager.Device.xml | 3 +- src/network/test/network.qml | 1 + 15 files changed, 409 insertions(+), 219 deletions(-) delete mode 100644 src/network/nm/adapters.cpp delete mode 100644 src/network/nm/adapters.hpp delete mode 100644 src/network/nm/org.freedesktop.NetworkManager.AccessPoint.xml delete mode 100644 src/network/nm/org.freedesktop.NetworkManager.Device.Wireless.xml delete mode 100644 src/network/nm/org.freedesktop.NetworkManager.Device.xml delete mode 100644 src/network/nm/org.freedesktop.NetworkManager.xml create mode 100644 src/network/nm_adapters.cpp create mode 100644 src/network/nm_adapters.hpp rename src/network/{nm/backend.cpp => nm_backend.cpp} (62%) rename src/network/{nm/backend.hpp => nm_backend.hpp} (64%) diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 718665b0..42f43d5d 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -31,8 +31,8 @@ qt_add_dbus_interface(NM_DBUS_INTERFACES qt_add_library(quickshell-network STATIC api.cpp - nm/backend.cpp - nm/adapters.cpp + nm_backend.cpp + nm_adapters.cpp ${NM_DBUS_INTERFACES} ) diff --git a/src/network/api.cpp b/src/network/api.cpp index 43c1dbf8..67efebcc 100644 --- a/src/network/api.cpp +++ b/src/network/api.cpp @@ -8,7 +8,7 @@ #include #include -#include "nm/backend.hpp" +#include "nm_backend.hpp" namespace qs::network { @@ -17,6 +17,18 @@ Q_LOGGING_CATEGORY(logNetwork, "quickshell.network", QtWarningMsg); } Device::Device(QObject* parent): QObject(parent) {}; +WirelessDevice::WirelessDevice(QObject* parent): Device(parent) {}; + +QString DeviceState::toString(DeviceState::Enum state) { + switch (state) { + case DeviceState::Unknown: return QStringLiteral("Unknown"); + case DeviceState::Disconnected: return QStringLiteral("Disconnected"); + case DeviceState::Connecting: return QStringLiteral("Connecting"); + case DeviceState::Connected: return QStringLiteral("Connected"); + case DeviceState::Disconnecting: return QStringLiteral("Disconnecting"); + default: return QStringLiteral("Unknown"); + } +} void Device::setName(const QString& name) { if (name != this->bName) { @@ -30,12 +42,18 @@ void Device::setAddress(const QString& address) { } } -void WirelessDevice::setState(WirelessState::Enum state) { +void Device::setState(DeviceState::Enum state) { if (state != this->bState) { this->bState = state; } } +void WirelessDevice::setLastScan(qint64 lastScan) { + if (lastScan != this->bLastScan) { + this->bLastScan = lastScan; + } +} + Network::Network(QObject* parent): QObject(parent) { // Try each backend diff --git a/src/network/api.hpp b/src/network/api.hpp index 67c4319a..b12e25ac 100644 --- a/src/network/api.hpp +++ b/src/network/api.hpp @@ -16,6 +16,23 @@ namespace qs::network { // -- Device -- +class DeviceState: public QObject { + Q_OBJECT; + QML_ELEMENT; + QML_SINGLETON; + +public: + enum Enum : quint8 { + Unknown = 0, + Disconnected = 10, + Connecting = 20, + Connected = 30, + Disconnecting = 40, + }; + Q_ENUM(Enum); + Q_INVOKABLE static QString toString(DeviceState::Enum state); +}; + class Device: public QObject { Q_OBJECT; QML_ELEMENT; @@ -24,79 +41,57 @@ class Device: public QObject { // clang-format off Q_PROPERTY(QString name READ default NOTIFY nameChanged BINDABLE bindableName); Q_PROPERTY(QString address READ default NOTIFY addressChanged BINDABLE bindableAddress); + Q_PROPERTY(DeviceState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState); // clang-format on signals: void nameChanged(); void addressChanged(); + void stateChanged(); public slots: void setName(const QString& name); void setAddress(const QString& address); + void setState(DeviceState::Enum state); public: explicit Device(QObject* parent = nullptr); [[nodiscard]] QBindable bindableName() const { return &this->bName; }; [[nodiscard]] QBindable bindableAddress() const { return &this->bAddress; }; + [[nodiscard]] QBindable bindableState() const { return &this->bState; }; private: Q_OBJECT_BINDABLE_PROPERTY(Device, QString, bName, &Device::nameChanged); Q_OBJECT_BINDABLE_PROPERTY(Device, QString, bAddress, &Device::addressChanged); + Q_OBJECT_BINDABLE_PROPERTY(Device, DeviceState::Enum, bState, &Device::stateChanged); }; // -- Wireless Device -- - -class WirelessState: public QObject { - Q_OBJECT; - QML_ELEMENT; - QML_SINGLETON; - -public: - enum Enum : quint8 { - Unknown = 0, - Disconnected = 10, - Connecting = 20, - Connected = 30, - Disconnecting = 40, - }; - Q_ENUM(Enum); -}; - class WirelessDevice: public Device { Q_OBJECT; // clang-format off - Q_PROPERTY(bool powered READ powered WRITE setPowered NOTIFY poweredChanged); - Q_PROPERTY(WirelessState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState); + Q_PROPERTY(qint64 lastScan READ default NOTIFY lastScanChanged BINDABLE bindableLastScan); //clang-format on signals: - void poweredChanged(); - void stateChanged(); + void lastScanChanged(); -private slots: - void setState(WirelessState::Enum state); +public slots: + void setLastScan(qint64 lastScan); public: explicit WirelessDevice(QObject* parent = nullptr); - Q_INVOKABLE virtual void disconnect() = 0; - Q_INVOKABLE virtual void scan() = 0; + // Q_INVOKABLE void disconnect(); + // Q_INVOKABLE void scan(); - [[nodiscard]] bool powered() const { return this->bPowered; }; - virtual void setPowered(bool powered) = 0; - - [[nodiscard]] QBindable bindablePowered() { return &this->bPowered; }; - [[nodiscard]] QBindable bindableState() const { return &this->bState; }; + [[nodiscard]] QBindable bindableLastScan() { return &this->bLastScan; }; private: - Q_OBJECT_BINDABLE_PROPERTY(WirelessDevice, bool, bPowered, &WirelessDevice::poweredChanged); - Q_OBJECT_BINDABLE_PROPERTY( - WirelessDevice, - WirelessState::Enum, - bState, - &WirelessDevice::stateChanged - ); + // clang-format off + Q_OBJECT_BINDABLE_PROPERTY(WirelessDevice, qint64, bLastScan, &WirelessDevice::lastScanChanged); + // clang-format on }; // -- Network -- @@ -106,8 +101,8 @@ class NetworkBackend: public QObject { public: [[nodiscard]] virtual bool isAvailable() const = 0; - // virtual WirelessDevice* wifiDevice() = 0; virtual UntypedObjectModel* devices() = 0; + virtual WirelessDevice* defaultWifiDevice() = 0; protected: explicit NetworkBackend(QObject* parent = nullptr): QObject(parent) {}; @@ -118,13 +113,15 @@ class Network: public QObject { QML_NAMED_ELEMENT(Network); QML_SINGLETON; - // Q_PROPERTY(WirelessDevice* wifi READ wifiDevice CONSTANT); + Q_PROPERTY(WirelessDevice* defaultWifiDevice READ defaultWifiDevice CONSTANT); Q_PROPERTY(UntypedObjectModel* devices READ devices CONSTANT); public: explicit Network(QObject* parent = nullptr); - // [[nodiscard]] WirelessDevice* wifi() { return backend ? backend->wifiDevice() : nullptr; } - [[nodiscard]] UntypedObjectModel* devices() { return backend ? backend->devices() : nullptr; } + [[nodiscard]] UntypedObjectModel* devices() { return backend ? backend->devices() : nullptr; }; + [[nodiscard]] WirelessDevice* defaultWifiDevice() { + return backend ? backend->defaultWifiDevice() : nullptr; + }; private: class NetworkBackend* backend = nullptr; diff --git a/src/network/nm/adapters.cpp b/src/network/nm/adapters.cpp deleted file mode 100644 index a7f9c78a..00000000 --- a/src/network/nm/adapters.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "adapters.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include "../dbus/properties.hpp" -#include "dbus_nm_device.h" - -using namespace qs::dbus; - -namespace qs::network { - -namespace { -Q_LOGGING_CATEGORY(logNMDevice, "quickshell.network.networkmanager.device", QtWarningMsg); -} - -NMDeviceAdapter::NMDeviceAdapter(QObject* parent): QObject(parent) {} - -void NMDeviceAdapter::init(const QString& path) { - this->proxy = new DBusNMDeviceProxy( - "org.freedesktop.NetworkManager", - path, - QDBusConnection::systemBus(), - this - ); - - if (!this->proxy->isValid()) { - qCWarning(logNMDevice) << "Cannot create NMDevice for" << path; - return; - } - - this->deviceProperties.setInterface(this->proxy); - this->deviceProperties.updateAllViaGetAll(); -} - -bool NMDeviceAdapter::isValid() const { return this->proxy && this->proxy->isValid(); } -QString NMDeviceAdapter::address() const { - return this->proxy ? this->proxy->service() : QString(); -} -QString NMDeviceAdapter::path() const { return this->proxy ? this->proxy->path() : QString(); } - -} // namespace qs::network diff --git a/src/network/nm/adapters.hpp b/src/network/nm/adapters.hpp deleted file mode 100644 index cbbedced..00000000 --- a/src/network/nm/adapters.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../dbus/properties.hpp" -#include "../api.hpp" -#include "dbus_nm_device.h" - -namespace qs::network { - -class NMDeviceAdapter: public QObject { - Q_OBJECT; - -public: - explicit NMDeviceAdapter(QObject* parent = nullptr); - void init(const QString& path); - [[nodiscard]] bool isValid() const; - [[nodiscard]] QString path() const; - [[nodiscard]] QString address() const; - [[nodiscard]] QString getInterface() { return this->bInterface; }; - [[nodiscard]] QString getHwAddress() { return this->bHwAddress; }; - -signals: - void interfaceChanged(const QString& interface); - void hwAddressChanged(const QString& hwAddress); - -private: - Q_OBJECT_BINDABLE_PROPERTY(NMDeviceAdapter, QString, bInterface, &NMDeviceAdapter::interfaceChanged); - Q_OBJECT_BINDABLE_PROPERTY(NMDeviceAdapter, QString, bHwAddress, &NMDeviceAdapter::hwAddressChanged); - - QS_DBUS_BINDABLE_PROPERTY_GROUP(NMDeviceAdapter, deviceProperties); - QS_DBUS_PROPERTY_BINDING(NMDeviceAdapter, pName, bInterface, deviceProperties, "Interface"); - QS_DBUS_PROPERTY_BINDING(NMDeviceAdapter, pAddress, bHwAddress, deviceProperties, "HwAddress"); - - DBusNMDeviceProxy* proxy = nullptr; -}; - -} // namespace qs::network diff --git a/src/network/nm/org.freedesktop.NetworkManager.AccessPoint.xml b/src/network/nm/org.freedesktop.NetworkManager.AccessPoint.xml deleted file mode 100644 index 33872050..00000000 --- a/src/network/nm/org.freedesktop.NetworkManager.AccessPoint.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/src/network/nm/org.freedesktop.NetworkManager.Device.Wireless.xml b/src/network/nm/org.freedesktop.NetworkManager.Device.Wireless.xml deleted file mode 100644 index 17b712bb..00000000 --- a/src/network/nm/org.freedesktop.NetworkManager.Device.Wireless.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - arg name="access_ponit" type="o"/> - - - diff --git a/src/network/nm/org.freedesktop.NetworkManager.Device.xml b/src/network/nm/org.freedesktop.NetworkManager.Device.xml deleted file mode 100644 index f230778f..00000000 --- a/src/network/nm/org.freedesktop.NetworkManager.Device.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/network/nm/org.freedesktop.NetworkManager.xml b/src/network/nm/org.freedesktop.NetworkManager.xml deleted file mode 100644 index 4f9ca03e..00000000 --- a/src/network/nm/org.freedesktop.NetworkManager.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/src/network/nm_adapters.cpp b/src/network/nm_adapters.cpp new file mode 100644 index 00000000..96d82225 --- /dev/null +++ b/src/network/nm_adapters.cpp @@ -0,0 +1,95 @@ +#include "nm_adapters.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include "../dbus/properties.hpp" +#include "dbus_nm_device.h" + +using namespace qs::dbus; + +namespace qs::network { + +namespace { +Q_LOGGING_CATEGORY(logNMDevice, "quickshell.network.networkmanager.device", QtWarningMsg); +} + +NMDeviceAdapter::NMDeviceAdapter(QObject* parent): QObject(parent) {} + +void NMDeviceAdapter::init(const QString& path) { + this->proxy = new DBusNMDeviceProxy( + "org.freedesktop.NetworkManager", + path, + QDBusConnection::systemBus(), + this + ); + + if (!this->proxy->isValid()) { + qCWarning(logNMDevice) << "Cannot create NMDeviceAdapter for" << path; + return; + } + + this->deviceProperties.setInterface(this->proxy); + this->deviceProperties.updateAllViaGetAll(); +} + +bool NMDeviceAdapter::isValid() const { return this->proxy && this->proxy->isValid(); } +QString NMDeviceAdapter::address() const { + return this->proxy ? this->proxy->service() : QString(); +} +QString NMDeviceAdapter::path() const { return this->proxy ? this->proxy->path() : QString(); } + +DeviceState::Enum NMDeviceState::translate(NMDeviceState::Enum state) { + switch(state) { + case 0 ... 20: return DeviceState::Unknown; + case 30: return DeviceState::Disconnected; + case 40 ... 90: return DeviceState::Connecting; + case 100: return DeviceState::Connected; + case 110 ... 120: return DeviceState::Disconnecting; + } +} + +NMWirelessAdapter::NMWirelessAdapter(QObject* parent): QObject(parent) {} + +void NMWirelessAdapter::init(const QString& path) { + this->proxy = new DBusNMWirelessProxy( + "org.freedesktop.NetworkManager", + path, + QDBusConnection::systemBus(), + this + ); + + if (!this->proxy->isValid()) { + qCWarning(logNMDevice) << "Cannot create NMWirelessAdapter for" << path; + return; + } + + this->wirelessProperties.setInterface(this->proxy); + this->wirelessProperties.updateAllViaGetAll(); +} + +bool NMWirelessAdapter::isValid() const { return this->proxy && this->proxy->isValid(); } +QString NMWirelessAdapter::address() const { + return this->proxy ? this->proxy->service() : QString(); +} +QString NMWirelessAdapter::path() const { return this->proxy ? this->proxy->path() : QString(); } +} // namespace qs::network + +namespace qs::dbus { + +DBusResult +DBusDataTransform::fromWire(quint32 wire) { + return DBusResult(static_cast(wire)); +} + +DBusResult +DBusDataTransform::fromWire(quint32 wire) { + return DBusResult(static_cast(wire)); +} + +} // namespace qs::dbus diff --git a/src/network/nm_adapters.hpp b/src/network/nm_adapters.hpp new file mode 100644 index 00000000..f12e8609 --- /dev/null +++ b/src/network/nm_adapters.hpp @@ -0,0 +1,168 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../dbus/properties.hpp" +#include "api.hpp" +#include "dbus_nm_device.h" +#include "dbus_nm_wireless.h" + +namespace qs::network { + +class NMDeviceState: public QObject { + Q_OBJECT; + +public: + enum Enum : quint8 { + Unkown = 0, + Unmanaged = 10, + Unavailable = 20, + Disconnected = 30, + Prepare = 40, + Config = 50, + NeedAuth = 60, + IPConfig = 70, + IPCheck = 80, + Secondaries = 90, + Activated = 100, + Deactivating = 110, + Failed = 120, + }; + Q_ENUM(Enum); + + static DeviceState::Enum translate(NMDeviceState::Enum state); +}; + +class NMDeviceType: public QObject { + Q_OBJECT; + +public: + enum Enum : quint8 { + Unknown = 0, + Generic = 14, + Ethernet = 1, + Wifi = 2, + Unused1 = 3, + Unused2 = 4, + Bluetooth = 5, + OlpcMesh = 6, + Wimax = 7, + Modem = 8, + Infiniband = 9, + Bond = 10, + Vlan = 11, + Adsl = 12, + Bridge = 13, + Team = 15, + Tun = 16, + Tunnel = 17, + Macvlan = 18, + Vxlan = 19, + Veth = 20, + Macsec = 21, + Dummy = 22, + Ppp = 23, + OvsInterface = 24, + OvsPort = 25, + OvsBridge = 26, + Wpan = 27, + Lowpan = 28, + WireGuard = 29, + WifiP2P = 30, + Vrf = 31, + Loopback = 32, + Hsr = 33, + Ipvlan = 34, + }; + Q_ENUM(Enum); +}; + +} // namespace qs::network + +namespace qs::dbus { + +template <> +struct DBusDataTransform { + using Wire = quint32; + using Data = qs::network::NMDeviceType::Enum; + static DBusResult fromWire(Wire wire); +}; + +template <> +struct DBusDataTransform { + using Wire = quint32; + using Data = qs::network::NMDeviceState::Enum; + static DBusResult fromWire(Wire wire); +}; + +} // namespace qs::dbus + +namespace qs::network { + +class NMDeviceAdapter: public QObject { + Q_OBJECT; + +public: + explicit NMDeviceAdapter(QObject* parent = nullptr); + void init(const QString& path); + [[nodiscard]] bool isValid() const; + [[nodiscard]] QString path() const; + [[nodiscard]] QString address() const; + [[nodiscard]] QString getInterface() { return this->bInterface; }; + [[nodiscard]] QString getHwAddress() { return this->bHwAddress; }; + [[nodiscard]] NMDeviceType::Enum getType() { return this->bType; }; + +signals: + void interfaceChanged(const QString& interface); + void hwAddressChanged(const QString& hwAddress); + void typeChanged(NMDeviceType::Enum type); + void stateChanged(NMDeviceState::Enum state); + +private: + // clang-format off + Q_OBJECT_BINDABLE_PROPERTY(NMDeviceAdapter, QString, bInterface, &NMDeviceAdapter::interfaceChanged); + Q_OBJECT_BINDABLE_PROPERTY(NMDeviceAdapter, QString, bHwAddress, &NMDeviceAdapter::hwAddressChanged); + Q_OBJECT_BINDABLE_PROPERTY(NMDeviceAdapter, NMDeviceState::Enum, bState, &NMDeviceAdapter::stateChanged); + Q_OBJECT_BINDABLE_PROPERTY(NMDeviceAdapter, NMDeviceType::Enum, bType, &NMDeviceAdapter::typeChanged); + + QS_DBUS_BINDABLE_PROPERTY_GROUP(NMDeviceAdapter, deviceProperties); + QS_DBUS_PROPERTY_BINDING(NMDeviceAdapter, pName, bInterface, deviceProperties, "Interface"); + QS_DBUS_PROPERTY_BINDING(NMDeviceAdapter, pAddress, bHwAddress, deviceProperties, "HwAddress"); + QS_DBUS_PROPERTY_BINDING(NMDeviceAdapter, pType, bType, deviceProperties, "DeviceType"); + QS_DBUS_PROPERTY_BINDING(NMDeviceAdapter, pState, bState, deviceProperties, "State"); + + DBusNMDeviceProxy* proxy = nullptr; +}; + +class NMWirelessAdapter: public QObject { + Q_OBJECT; + +public: + explicit NMWirelessAdapter(QObject* parent = nullptr); + void init(const QString& path); + [[nodiscard]] bool isValid() const; + [[nodiscard]] QString path() const; + [[nodiscard]] QString address() const; + [[nodiscard]] qint64 getLastScan() { return this->bLastScan; }; + +signals: + void lastScanChanged(qint64 time); + +private: + // clang-format off + Q_OBJECT_BINDABLE_PROPERTY(NMWirelessAdapter, qint64, bLastScan, &NMWirelessAdapter::lastScanChanged); + + QS_DBUS_BINDABLE_PROPERTY_GROUP(NMWirelessAdapter, wirelessProperties); + QS_DBUS_PROPERTY_BINDING(NMWirelessAdapter, pLastScan, bLastScan, wirelessProperties, "LastScan"); + + DBusNMWirelessProxy* proxy = nullptr; +}; +} // namespace qs::network diff --git a/src/network/nm/backend.cpp b/src/network/nm_backend.cpp similarity index 62% rename from src/network/nm/backend.cpp rename to src/network/nm_backend.cpp index af55c75c..c04cc2a2 100644 --- a/src/network/nm/backend.cpp +++ b/src/network/nm_backend.cpp @@ -1,4 +1,4 @@ -#include "backend.hpp" +#include "nm_backend.hpp" #include #include @@ -10,11 +10,11 @@ #include #include -#include "../../dbus/bus.hpp" -#include "../../dbus/properties.hpp" -#include "../api.hpp" +#include "../dbus/bus.hpp" +#include "../dbus/properties.hpp" +#include "api.hpp" #include "dbus_nm_backend.h" -#include "adapters.hpp" +#include "nm_adapters.hpp" namespace qs::network { @@ -87,7 +87,7 @@ void NetworkManager::registerDevices() { qCWarning(logNetworkManager) << "Failed to get devices: " << reply.error().message(); } else { for (const QDBusObjectPath& devicePath: reply.value()) { - this->registerDevice(devicePath.path()); + this->queueDeviceRegistration(devicePath.path()); } } @@ -97,36 +97,87 @@ void NetworkManager::registerDevices() { QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback); } -void NetworkManager::registerDevice(const QString& path) { +void NetworkManager::queueDeviceRegistration(const QString& path) { if (this->mDeviceHash.contains(path)) { qCDebug(logNetworkManager) << "Skipping duplicate registration of device" << path; return; } - auto* device = new Device(this); - auto* deviceAdapter = new NMDeviceAdapter(device); - + // Create a device adapter + auto* deviceAdapter = new NMDeviceAdapter(); deviceAdapter->init(path); if (!deviceAdapter->isValid()) { - qCWarning(logNetworkManager) << "Ignoring invalid Device registration of" << path; - delete device; + qCWarning(logNetworkManager) << "Ignoring invalid registration of" << path; return; } - - device->setAddress(deviceAdapter->getHwAddress()); - device->setName(deviceAdapter->getInterface()); + + // Wait for DBus to tell us the device type + QObject::connect( + deviceAdapter, + &NMDeviceAdapter::typeChanged, + this, + [this, deviceAdapter, path](NMDeviceType::Enum type) { + this->registerDevice(deviceAdapter, type, path); + } + ); +} + +// Register the device +void NetworkManager::registerDevice( + NMDeviceAdapter* deviceAdapter, + NMDeviceType::Enum type, + const QString& path +) { + Device* device = createDeviceVariant(type, path); + + // Bind backend NMDeviceAdapter to frontend Device + deviceAdapter->setParent(device); QObject::connect(deviceAdapter, &NMDeviceAdapter::hwAddressChanged, device, &Device::setAddress); QObject::connect(deviceAdapter, &NMDeviceAdapter::interfaceChanged, device, &Device::setName); - + QObject::connect( + deviceAdapter, + &NMDeviceAdapter::stateChanged, + device, + [device](NMDeviceState::Enum state) { device->setState(NMDeviceState::translate(state)); } + ); this->mDeviceHash.insert(path, device); this->mDevices.insertObject(device); - qCDebug(logNetworkManager) << "Registered Device" << path; + + qCDebug(logNetworkManager) << "Registered device at path" << path; +} + +// Create a derived device class based on the NMDeviceType of the NMDeviceAdapter +Device* NetworkManager::createDeviceVariant(NMDeviceType::Enum type, const QString& path) { + switch (type) { + case NMDeviceType::Wifi: return this->bindWirelessDevice(path); + default: return new Device(); + } +} + +// Create a frontend WirelessDevice and bind the backend wireless adapter to it +WirelessDevice* NetworkManager::bindWirelessDevice(const QString& path) { + auto* device = new WirelessDevice(this); + + auto* wirelessAdapter = new NMWirelessAdapter(device); + wirelessAdapter->init(path); + + QObject::connect( + wirelessAdapter, + &NMWirelessAdapter::lastScanChanged, + device, + &WirelessDevice::setLastScan + ); + + if (this->mWifi == nullptr) { + this->mWifi = device; + }; + return device; } void NetworkManager::onDeviceAdded(const QDBusObjectPath& path) { - this->registerDevice(path.path()); + this->queueDeviceRegistration(path.path()); } void NetworkManager::onDeviceRemoved(const QDBusObjectPath& path) { @@ -137,6 +188,9 @@ void NetworkManager::onDeviceRemoved(const QDBusObjectPath& path) { << "which is not registered."; } else { auto* device = iter.value(); + if (this->mWifi == device) { + this->mWifi = nullptr; + }; this->mDeviceHash.erase(iter); this->mDevices.removeObject(device); qCDebug(logNetworkManager) << "Device" << path.path() << "removed."; @@ -144,7 +198,7 @@ void NetworkManager::onDeviceRemoved(const QDBusObjectPath& path) { } UntypedObjectModel* NetworkManager::devices() { return &this->mDevices; } -// WirelessDevice* NetworkManager::wifiDevice() { return &this->mWifi; } +WirelessDevice* NetworkManager::defaultWifiDevice() { return this->mWifi; } bool NetworkManager::isAvailable() const { return this->proxy && this->proxy->isValid(); } } // namespace qs::network diff --git a/src/network/nm/backend.hpp b/src/network/nm_backend.hpp similarity index 64% rename from src/network/nm/backend.hpp rename to src/network/nm_backend.hpp index 4b597d3d..5aeef00d 100644 --- a/src/network/nm/backend.hpp +++ b/src/network/nm_backend.hpp @@ -10,9 +10,10 @@ #include #include -#include "../../dbus/properties.hpp" -#include "../api.hpp" +#include "../dbus/properties.hpp" +#include "api.hpp" #include "dbus_nm_backend.h" +#include "nm_adapters.hpp" namespace qs::network { @@ -23,7 +24,7 @@ class NetworkManager: public NetworkBackend { explicit NetworkManager(QObject* parent = nullptr); UntypedObjectModel* devices() override; - // WirelessDevice* wifiDevice() override; + WirelessDevice* defaultWifiDevice() override; [[nodiscard]] bool isAvailable() const override; private slots: @@ -32,11 +33,16 @@ private slots: private: void init(); - void registerDevice(const QString& path); + void registerDevice(NMDeviceAdapter* deviceAdapter, NMDeviceType::Enum type, const QString& path); void registerDevices(); + void queueDeviceRegistration(const QString& path); + Device* createDeviceVariant(NMDeviceType::Enum type, const QString& path); + WirelessDevice* bindWirelessDevice(const QString& path); + Device* bindDevice(NMDeviceAdapter* deviceAdapter); QHash mDeviceHash; ObjectModel mDevices {this}; + WirelessDevice* mWifi = nullptr; QS_DBUS_BINDABLE_PROPERTY_GROUP(NetworkManager, dbusProperties); diff --git a/src/network/org.freedesktop.NetworkManager.Device.xml b/src/network/org.freedesktop.NetworkManager.Device.xml index 9a2b6914..f230778f 100644 --- a/src/network/org.freedesktop.NetworkManager.Device.xml +++ b/src/network/org.freedesktop.NetworkManager.Device.xml @@ -2,7 +2,8 @@ + + - diff --git a/src/network/test/network.qml b/src/network/test/network.qml index 6284c3bd..60b797ca 100644 --- a/src/network/test/network.qml +++ b/src/network/test/network.qml @@ -31,6 +31,7 @@ FloatingWindow { font.bold: true } Label { text: "Hardware Address: " + modelData.address } + Label { text: "State: " + DeviceState.toString(modelData.state) } } } } From c9ece29b92ce36a4173312cb2ffcc1ddc03b482d Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Tue, 15 Jul 2025 11:49:37 -0500 Subject: [PATCH 22/25] disconnect --- src/network/api.cpp | 17 +++++++++++++++++ src/network/api.hpp | 25 +++++++++++++++++++++---- src/network/nm_adapters.cpp | 1 + src/network/nm_adapters.hpp | 3 +++ src/network/nm_backend.cpp | 6 +++++- src/network/test/network.qml | 4 ++++ 6 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/network/api.cpp b/src/network/api.cpp index 67efebcc..9114ea7c 100644 --- a/src/network/api.cpp +++ b/src/network/api.cpp @@ -13,6 +13,7 @@ namespace qs::network { namespace { +Q_LOGGING_CATEGORY(logNetworkDevice, "quickshell.network.device", QtWarningMsg); Q_LOGGING_CATEGORY(logNetwork, "quickshell.network", QtWarningMsg); } @@ -48,6 +49,22 @@ void Device::setState(DeviceState::Enum state) { } } +void Device::disconnect() { + if (this->bState == DeviceState::Disconnected) { + qCCritical(logNetworkDevice) << "Device" << this << "is already disconnected"; + return; + } + + if (this->bState == DeviceState::Disconnecting) { + qCCritical(logNetworkDevice) << "Device" << this << "is already disconnecting"; + return; + } + + qCDebug(logNetworkDevice) << "Disconnecting from device" << this; + + signalDisconnect(); +} + void WirelessDevice::setLastScan(qint64 lastScan) { if (lastScan != this->bLastScan) { this->bLastScan = lastScan; diff --git a/src/network/api.hpp b/src/network/api.hpp index b12e25ac..cdcfff02 100644 --- a/src/network/api.hpp +++ b/src/network/api.hpp @@ -23,39 +23,56 @@ class DeviceState: public QObject { public: enum Enum : quint8 { + /// The device state is unknown. Unknown = 0, - Disconnected = 10, - Connecting = 20, - Connected = 30, - Disconnecting = 40, + /// The device is not connected. + Disconnected = 1, + /// The device is connected. + Connected = 2, + /// The device is disconnecting. + Disconnecting = 3, + /// The device is connecting. + Connecting = 4, }; Q_ENUM(Enum); Q_INVOKABLE static QString toString(DeviceState::Enum state); }; +///! A tracked network device. class Device: public QObject { Q_OBJECT; QML_ELEMENT; QML_UNCREATABLE("Devices can only be acquired through Network"); // clang-format off + /// The name of the device's interface. Q_PROPERTY(QString name READ default NOTIFY nameChanged BINDABLE bindableName); + /// The hardware address of the device's interface in the XX:XX:XX:XX:XX:XX format. Q_PROPERTY(QString address READ default NOTIFY addressChanged BINDABLE bindableAddress); + /// Connection state of the device. Q_PROPERTY(DeviceState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState); // clang-format on signals: + void signalDisconnect(); + + // Frontend-facing signals void nameChanged(); void addressChanged(); void stateChanged(); public slots: + // Slots for the backend to connect signals to void setName(const QString& name); void setAddress(const QString& address); void setState(DeviceState::Enum state); public: explicit Device(QObject* parent = nullptr); + + /// Disconnects the device and prevents it from automatically activating further connections. + Q_INVOKABLE void disconnect(); + [[nodiscard]] QBindable bindableName() const { return &this->bName; }; [[nodiscard]] QBindable bindableAddress() const { return &this->bAddress; }; [[nodiscard]] QBindable bindableState() const { return &this->bState; }; diff --git a/src/network/nm_adapters.cpp b/src/network/nm_adapters.cpp index 96d82225..42bd3863 100644 --- a/src/network/nm_adapters.cpp +++ b/src/network/nm_adapters.cpp @@ -38,6 +38,7 @@ void NMDeviceAdapter::init(const QString& path) { this->deviceProperties.updateAllViaGetAll(); } +void NMDeviceAdapter::disconnect() { this->proxy->Disconnect(); } bool NMDeviceAdapter::isValid() const { return this->proxy && this->proxy->isValid(); } QString NMDeviceAdapter::address() const { return this->proxy ? this->proxy->service() : QString(); diff --git a/src/network/nm_adapters.hpp b/src/network/nm_adapters.hpp index f12e8609..ce942986 100644 --- a/src/network/nm_adapters.hpp +++ b/src/network/nm_adapters.hpp @@ -120,6 +120,9 @@ class NMDeviceAdapter: public QObject { [[nodiscard]] QString getHwAddress() { return this->bHwAddress; }; [[nodiscard]] NMDeviceType::Enum getType() { return this->bType; }; +public slots: + void disconnect(); + signals: void interfaceChanged(const QString& interface); void hwAddressChanged(const QString& hwAddress); diff --git a/src/network/nm_backend.cpp b/src/network/nm_backend.cpp index c04cc2a2..49b5d644 100644 --- a/src/network/nm_backend.cpp +++ b/src/network/nm_backend.cpp @@ -131,7 +131,7 @@ void NetworkManager::registerDevice( ) { Device* device = createDeviceVariant(type, path); - // Bind backend NMDeviceAdapter to frontend Device + // deviceAdapter signal -> Device slot deviceAdapter->setParent(device); QObject::connect(deviceAdapter, &NMDeviceAdapter::hwAddressChanged, device, &Device::setAddress); QObject::connect(deviceAdapter, &NMDeviceAdapter::interfaceChanged, device, &Device::setName); @@ -142,6 +142,10 @@ void NetworkManager::registerDevice( [device](NMDeviceState::Enum state) { device->setState(NMDeviceState::translate(state)); } ); + // Device signal -> deviceAdapter slot + QObject::connect(device, &Device::signalDisconnect, deviceAdapter, &NMDeviceAdapter::disconnect); + + // Track device this->mDeviceHash.insert(path, device); this->mDevices.insertObject(device); diff --git a/src/network/test/network.qml b/src/network/test/network.qml index 60b797ca..4a95e760 100644 --- a/src/network/test/network.qml +++ b/src/network/test/network.qml @@ -32,6 +32,10 @@ FloatingWindow { } Label { text: "Hardware Address: " + modelData.address } Label { text: "State: " + DeviceState.toString(modelData.state) } + Button { + text: "Disconnect" + onClicked: modelData.disconnect() + } } } } From 997f45b4a2de7c20439d95ca237407b293215803 Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Tue, 15 Jul 2025 13:54:30 -0500 Subject: [PATCH 23/25] feat: scan, lastScan, NetworkDeviceType --- src/network/api.cpp | 70 +++++++++++++++++++---------- src/network/api.hpp | 86 +++++++++++++++++++++++++----------- src/network/nm_adapters.cpp | 13 +++--- src/network/nm_adapters.hpp | 8 ++-- src/network/nm_backend.cpp | 55 +++++++++++++++++------ src/network/nm_backend.hpp | 14 +++--- src/network/test/network.qml | 22 +++++++-- 7 files changed, 184 insertions(+), 84 deletions(-) diff --git a/src/network/api.cpp b/src/network/api.cpp index 9114ea7c..4de72484 100644 --- a/src/network/api.cpp +++ b/src/network/api.cpp @@ -13,62 +13,86 @@ namespace qs::network { namespace { -Q_LOGGING_CATEGORY(logNetworkDevice, "quickshell.network.device", QtWarningMsg); +Q_LOGGING_CATEGORY(logNetworkNetworkDevice, "quickshell.network.device", QtWarningMsg); Q_LOGGING_CATEGORY(logNetwork, "quickshell.network", QtWarningMsg); -} +} // namespace -Device::Device(QObject* parent): QObject(parent) {}; -WirelessDevice::WirelessDevice(QObject* parent): Device(parent) {}; +NetworkDevice::NetworkDevice(QObject* parent): QObject(parent) {}; +WirelessNetworkDevice::WirelessNetworkDevice(QObject* parent): NetworkDevice(parent) {}; -QString DeviceState::toString(DeviceState::Enum state) { +QString NetworkDeviceState::toString(NetworkDeviceState::Enum state) { switch (state) { - case DeviceState::Unknown: return QStringLiteral("Unknown"); - case DeviceState::Disconnected: return QStringLiteral("Disconnected"); - case DeviceState::Connecting: return QStringLiteral("Connecting"); - case DeviceState::Connected: return QStringLiteral("Connected"); - case DeviceState::Disconnecting: return QStringLiteral("Disconnecting"); + case NetworkDeviceState::Unknown: return QStringLiteral("Unknown"); + case NetworkDeviceState::Disconnected: return QStringLiteral("Disconnected"); + case NetworkDeviceState::Connecting: return QStringLiteral("Connecting"); + case NetworkDeviceState::Connected: return QStringLiteral("Connected"); + case NetworkDeviceState::Disconnecting: return QStringLiteral("Disconnecting"); + default: return QStringLiteral("Unknown"); + } +} + +QString NetworkDeviceType::toString(NetworkDeviceType::Enum type) { + switch (type) { + case NetworkDeviceType::Other: return QStringLiteral("Other"); + case NetworkDeviceType::Wireless: return QStringLiteral("Wireless"); + case NetworkDeviceType::Ethernet: return QStringLiteral("Ethernet"); default: return QStringLiteral("Unknown"); } } -void Device::setName(const QString& name) { +void NetworkDevice::setName(const QString& name) { if (name != this->bName) { this->bName = name; } } -void Device::setAddress(const QString& address) { +void NetworkDevice::setAddress(const QString& address) { if (address != this->bAddress) { this->bAddress = address; } } -void Device::setState(DeviceState::Enum state) { +void NetworkDevice::setState(NetworkDeviceState::Enum state) { if (state != this->bState) { this->bState = state; } } -void Device::disconnect() { - if (this->bState == DeviceState::Disconnected) { - qCCritical(logNetworkDevice) << "Device" << this << "is already disconnected"; +void NetworkDevice::disconnect() { + if (this->bState == NetworkDeviceState::Disconnected) { + qCCritical(logNetworkNetworkDevice) << "NetworkDevice" << this << "is already disconnected"; return; } - if (this->bState == DeviceState::Disconnecting) { - qCCritical(logNetworkDevice) << "Device" << this << "is already disconnecting"; + if (this->bState == NetworkDeviceState::Disconnecting) { + qCCritical(logNetworkNetworkDevice) << "NetworkDevice" << this << "is already disconnecting"; return; } - qCDebug(logNetworkDevice) << "Disconnecting from device" << this; - + qCDebug(logNetworkNetworkDevice) << "Disconnecting from device" << this; + signalDisconnect(); } -void WirelessDevice::setLastScan(qint64 lastScan) { - if (lastScan != this->bLastScan) { - this->bLastScan = lastScan; +void WirelessNetworkDevice::scanComplete(qint64 lastScan) { + this->bLastScan = lastScan; + emit this->lastScanChanged(); + + if (this->bScanning) { + this->bScanning = false; + emit this->scanningChanged(); + } +} + +void WirelessNetworkDevice::scan() { + if (this->bScanning) { + qCCritical(logNetworkNetworkDevice) << "NetworkDevice" << this << "is already scanning"; + return; } + + qCDebug(logNetworkNetworkDevice) << "Requesting scan on wireless device" << this; + this->bScanning = true; + signalScan(); } Network::Network(QObject* parent): QObject(parent) { diff --git a/src/network/api.hpp b/src/network/api.hpp index cdcfff02..ef5d8f4c 100644 --- a/src/network/api.hpp +++ b/src/network/api.hpp @@ -14,9 +14,28 @@ namespace qs::network { -// -- Device -- -class DeviceState: public QObject { +///! Type of network device. +class NetworkDeviceType: public QObject { + Q_OBJECT; + QML_ELEMENT; + QML_SINGLETON; + +public: + enum Enum : quint8 { + ///! A generic device. + Other = 0, + ///! An 802.11 Wi-Fi device. + Wireless = 1, + ///! A wired ethernet device. + Ethernet = 2 + }; + Q_ENUM(Enum); + Q_INVOKABLE static QString toString(NetworkDeviceType::Enum type); +}; + +///! State of a network device. +class NetworkDeviceState: public QObject { Q_OBJECT; QML_ELEMENT; QML_SINGLETON; @@ -35,14 +54,14 @@ class DeviceState: public QObject { Connecting = 4, }; Q_ENUM(Enum); - Q_INVOKABLE static QString toString(DeviceState::Enum state); + Q_INVOKABLE static QString toString(NetworkDeviceState::Enum state); }; ///! A tracked network device. -class Device: public QObject { +class NetworkDevice: public QObject { Q_OBJECT; QML_ELEMENT; - QML_UNCREATABLE("Devices can only be acquired through Network"); + QML_UNCREATABLE("NetworkDevices can only be acquired through Network"); // clang-format off /// The name of the device's interface. @@ -50,76 +69,89 @@ class Device: public QObject { /// The hardware address of the device's interface in the XX:XX:XX:XX:XX:XX format. Q_PROPERTY(QString address READ default NOTIFY addressChanged BINDABLE bindableAddress); /// Connection state of the device. - Q_PROPERTY(DeviceState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState); + Q_PROPERTY(NetworkDeviceState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState); + /// Type of device. + Q_PROPERTY(NetworkDeviceType::Enum type READ type CONSTANT); // clang-format on signals: - void signalDisconnect(); - - // Frontend-facing signals void nameChanged(); void addressChanged(); void stateChanged(); + // For backend slots + void signalDisconnect(); + public slots: - // Slots for the backend to connect signals to + // For backend signals void setName(const QString& name); void setAddress(const QString& address); - void setState(DeviceState::Enum state); + void setState(NetworkDeviceState::Enum state); public: - explicit Device(QObject* parent = nullptr); + explicit NetworkDevice(QObject* parent = nullptr); /// Disconnects the device and prevents it from automatically activating further connections. Q_INVOKABLE void disconnect(); + [[nodiscard]] virtual NetworkDeviceType::Enum type() const { return NetworkDeviceType::Other; }; [[nodiscard]] QBindable bindableName() const { return &this->bName; }; [[nodiscard]] QBindable bindableAddress() const { return &this->bAddress; }; - [[nodiscard]] QBindable bindableState() const { return &this->bState; }; + [[nodiscard]] QBindable bindableState() const { return &this->bState; }; private: - Q_OBJECT_BINDABLE_PROPERTY(Device, QString, bName, &Device::nameChanged); - Q_OBJECT_BINDABLE_PROPERTY(Device, QString, bAddress, &Device::addressChanged); - Q_OBJECT_BINDABLE_PROPERTY(Device, DeviceState::Enum, bState, &Device::stateChanged); + Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, QString, bName, &NetworkDevice::nameChanged); + Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, QString, bAddress, &NetworkDevice::addressChanged); + Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, NetworkDeviceState::Enum, bState, &NetworkDevice::stateChanged); }; -// -- Wireless Device -- -class WirelessDevice: public Device { +///! Wireless variant of a tracked network device. +class WirelessNetworkDevice: public NetworkDevice { Q_OBJECT; // clang-format off + /// The timestamp (in CLOCK_BOOTTIME milliseconds) for the last finished network scan. Q_PROPERTY(qint64 lastScan READ default NOTIFY lastScanChanged BINDABLE bindableLastScan); + /// True if the wireless device is currently scanning for available wifi networks. + Q_PROPERTY(bool scanning READ default NOTIFY scanningChanged BINDABLE bindableScanning); //clang-format on signals: + void signalScan(); + + // Frontend-facing signals void lastScanChanged(); + void scanningChanged(); public slots: - void setLastScan(qint64 lastScan); + // For backend signals + void scanComplete(qint64 lastScan); public: - explicit WirelessDevice(QObject* parent = nullptr); + explicit WirelessNetworkDevice(QObject* parent = nullptr); + [[nodiscard]] NetworkDeviceType::Enum type() const override { return NetworkDeviceType::Wireless; }; - // Q_INVOKABLE void disconnect(); - // Q_INVOKABLE void scan(); + /// Request the wireless device to scan for available WiFi networks. + Q_INVOKABLE void scan(); + [[nodiscard]] QBindable bindableScanning() { return &this->bScanning; }; [[nodiscard]] QBindable bindableLastScan() { return &this->bLastScan; }; private: // clang-format off - Q_OBJECT_BINDABLE_PROPERTY(WirelessDevice, qint64, bLastScan, &WirelessDevice::lastScanChanged); + Q_OBJECT_BINDABLE_PROPERTY(WirelessNetworkDevice, bool, bScanning, &WirelessNetworkDevice::scanningChanged); + Q_OBJECT_BINDABLE_PROPERTY(WirelessNetworkDevice, qint64, bLastScan, &WirelessNetworkDevice::lastScanChanged); // clang-format on }; // -- Network -- - class NetworkBackend: public QObject { Q_OBJECT; public: [[nodiscard]] virtual bool isAvailable() const = 0; virtual UntypedObjectModel* devices() = 0; - virtual WirelessDevice* defaultWifiDevice() = 0; + virtual WirelessNetworkDevice* defaultWifiDevice() = 0; protected: explicit NetworkBackend(QObject* parent = nullptr): QObject(parent) {}; @@ -130,13 +162,13 @@ class Network: public QObject { QML_NAMED_ELEMENT(Network); QML_SINGLETON; - Q_PROPERTY(WirelessDevice* defaultWifiDevice READ defaultWifiDevice CONSTANT); + Q_PROPERTY(WirelessNetworkDevice* defaultWifiNetworkDevice READ defaultWifiNetworkDevice CONSTANT); Q_PROPERTY(UntypedObjectModel* devices READ devices CONSTANT); public: explicit Network(QObject* parent = nullptr); [[nodiscard]] UntypedObjectModel* devices() { return backend ? backend->devices() : nullptr; }; - [[nodiscard]] WirelessDevice* defaultWifiDevice() { + [[nodiscard]] WirelessNetworkDevice* defaultWifiNetworkDevice() { return backend ? backend->defaultWifiDevice() : nullptr; }; diff --git a/src/network/nm_adapters.cpp b/src/network/nm_adapters.cpp index 42bd3863..5ab7cfe4 100644 --- a/src/network/nm_adapters.cpp +++ b/src/network/nm_adapters.cpp @@ -45,13 +45,13 @@ QString NMDeviceAdapter::address() const { } QString NMDeviceAdapter::path() const { return this->proxy ? this->proxy->path() : QString(); } -DeviceState::Enum NMDeviceState::translate(NMDeviceState::Enum state) { +NetworkDeviceState::Enum NMDeviceState::translate(NMDeviceState::Enum state) { switch(state) { - case 0 ... 20: return DeviceState::Unknown; - case 30: return DeviceState::Disconnected; - case 40 ... 90: return DeviceState::Connecting; - case 100: return DeviceState::Connected; - case 110 ... 120: return DeviceState::Disconnecting; + case 0 ... 20: return NetworkDeviceState::Unknown; + case 30: return NetworkDeviceState::Disconnected; + case 40 ... 90: return NetworkDeviceState::Connecting; + case 100: return NetworkDeviceState::Connected; + case 110 ... 120: return NetworkDeviceState::Disconnecting; } } @@ -74,6 +74,7 @@ void NMWirelessAdapter::init(const QString& path) { this->wirelessProperties.updateAllViaGetAll(); } +void NMWirelessAdapter::scan() { this->proxy->RequestScan(); } bool NMWirelessAdapter::isValid() const { return this->proxy && this->proxy->isValid(); } QString NMWirelessAdapter::address() const { return this->proxy ? this->proxy->service() : QString(); diff --git a/src/network/nm_adapters.hpp b/src/network/nm_adapters.hpp index ce942986..170ffc22 100644 --- a/src/network/nm_adapters.hpp +++ b/src/network/nm_adapters.hpp @@ -38,7 +38,7 @@ class NMDeviceState: public QObject { }; Q_ENUM(Enum); - static DeviceState::Enum translate(NMDeviceState::Enum state); + static NetworkDeviceState::Enum translate(NMDeviceState::Enum state); }; class NMDeviceType: public QObject { @@ -156,8 +156,11 @@ class NMWirelessAdapter: public QObject { [[nodiscard]] QString address() const; [[nodiscard]] qint64 getLastScan() { return this->bLastScan; }; +public slots: + void scan(); + signals: - void lastScanChanged(qint64 time); + void lastScanChanged(qint64 lastScan); private: // clang-format off @@ -165,7 +168,6 @@ class NMWirelessAdapter: public QObject { QS_DBUS_BINDABLE_PROPERTY_GROUP(NMWirelessAdapter, wirelessProperties); QS_DBUS_PROPERTY_BINDING(NMWirelessAdapter, pLastScan, bLastScan, wirelessProperties, "LastScan"); - DBusNMWirelessProxy* proxy = nullptr; }; } // namespace qs::network diff --git a/src/network/nm_backend.cpp b/src/network/nm_backend.cpp index 49b5d644..2c53c7c5 100644 --- a/src/network/nm_backend.cpp +++ b/src/network/nm_backend.cpp @@ -129,12 +129,22 @@ void NetworkManager::registerDevice( NMDeviceType::Enum type, const QString& path ) { - Device* device = createDeviceVariant(type, path); + NetworkDevice* device = createDeviceVariant(type, path); - // deviceAdapter signal -> Device slot + // NMDeviceAdapter signal -> NetworkDevice slot deviceAdapter->setParent(device); - QObject::connect(deviceAdapter, &NMDeviceAdapter::hwAddressChanged, device, &Device::setAddress); - QObject::connect(deviceAdapter, &NMDeviceAdapter::interfaceChanged, device, &Device::setName); + QObject::connect( + deviceAdapter, + &NMDeviceAdapter::hwAddressChanged, + device, + &NetworkDevice::setAddress + ); + QObject::connect( + deviceAdapter, + &NMDeviceAdapter::interfaceChanged, + device, + &NetworkDevice::setName + ); QObject::connect( deviceAdapter, &NMDeviceAdapter::stateChanged, @@ -142,8 +152,13 @@ void NetworkManager::registerDevice( [device](NMDeviceState::Enum state) { device->setState(NMDeviceState::translate(state)); } ); - // Device signal -> deviceAdapter slot - QObject::connect(device, &Device::signalDisconnect, deviceAdapter, &NMDeviceAdapter::disconnect); + // NetworkDevice signal -> NMDeviceAdapter slot + QObject::connect( + device, + &NetworkDevice::signalDisconnect, + deviceAdapter, + &NMDeviceAdapter::disconnect + ); // Track device this->mDeviceHash.insert(path, device); @@ -153,25 +168,37 @@ void NetworkManager::registerDevice( } // Create a derived device class based on the NMDeviceType of the NMDeviceAdapter -Device* NetworkManager::createDeviceVariant(NMDeviceType::Enum type, const QString& path) { +NetworkDevice* NetworkManager::createDeviceVariant(NMDeviceType::Enum type, const QString& path) { switch (type) { case NMDeviceType::Wifi: return this->bindWirelessDevice(path); - default: return new Device(); + default: return new NetworkDevice(); } } -// Create a frontend WirelessDevice and bind the backend wireless adapter to it -WirelessDevice* NetworkManager::bindWirelessDevice(const QString& path) { - auto* device = new WirelessDevice(this); +// Create a frontend WirelessNetworkDevice and bind the backend wireless adapter to it +WirelessNetworkDevice* NetworkManager::bindWirelessDevice(const QString& path) { + auto* device = new WirelessNetworkDevice(this); auto* wirelessAdapter = new NMWirelessAdapter(device); wirelessAdapter->init(path); + // NMWirelessAdapter signal -> WirelessNetworkDevice slot QObject::connect( wirelessAdapter, &NMWirelessAdapter::lastScanChanged, device, - &WirelessDevice::setLastScan + [device](qint64 lastScan) { + device->scanComplete(lastScan); + qCDebug(logNetworkManager) << lastScan; + } + ); + + // WirelessNetworkDevice signal -> NMWirelessAdapter slot + QObject::connect( + device, + &WirelessNetworkDevice::signalScan, + wirelessAdapter, + &NMWirelessAdapter::scan ); if (this->mWifi == nullptr) { @@ -197,12 +224,12 @@ void NetworkManager::onDeviceRemoved(const QDBusObjectPath& path) { }; this->mDeviceHash.erase(iter); this->mDevices.removeObject(device); - qCDebug(logNetworkManager) << "Device" << path.path() << "removed."; + qCDebug(logNetworkManager) << "NetworkDevice" << path.path() << "removed."; } } UntypedObjectModel* NetworkManager::devices() { return &this->mDevices; } -WirelessDevice* NetworkManager::defaultWifiDevice() { return this->mWifi; } +WirelessNetworkDevice* NetworkManager::defaultWifiDevice() { return this->mWifi; } bool NetworkManager::isAvailable() const { return this->proxy && this->proxy->isValid(); } } // namespace qs::network diff --git a/src/network/nm_backend.hpp b/src/network/nm_backend.hpp index 5aeef00d..3e96b3e3 100644 --- a/src/network/nm_backend.hpp +++ b/src/network/nm_backend.hpp @@ -24,7 +24,7 @@ class NetworkManager: public NetworkBackend { explicit NetworkManager(QObject* parent = nullptr); UntypedObjectModel* devices() override; - WirelessDevice* defaultWifiDevice() override; + WirelessNetworkDevice* defaultWifiDevice() override; [[nodiscard]] bool isAvailable() const override; private slots: @@ -36,13 +36,13 @@ private slots: void registerDevice(NMDeviceAdapter* deviceAdapter, NMDeviceType::Enum type, const QString& path); void registerDevices(); void queueDeviceRegistration(const QString& path); - Device* createDeviceVariant(NMDeviceType::Enum type, const QString& path); - WirelessDevice* bindWirelessDevice(const QString& path); - Device* bindDevice(NMDeviceAdapter* deviceAdapter); + NetworkDevice* createDeviceVariant(NMDeviceType::Enum type, const QString& path); + WirelessNetworkDevice* bindWirelessDevice(const QString& path); + NetworkDevice* bindDevice(NMDeviceAdapter* deviceAdapter); - QHash mDeviceHash; - ObjectModel mDevices {this}; - WirelessDevice* mWifi = nullptr; + QHash mDeviceHash; + ObjectModel mDevices {this}; + WirelessNetworkDevice* mWifi = nullptr; QS_DBUS_BINDABLE_PROPERTY_GROUP(NetworkManager, dbusProperties); diff --git a/src/network/test/network.qml b/src/network/test/network.qml index 4a95e760..357daa54 100644 --- a/src/network/test/network.qml +++ b/src/network/test/network.qml @@ -31,10 +31,24 @@ FloatingWindow { font.bold: true } Label { text: "Hardware Address: " + modelData.address } - Label { text: "State: " + DeviceState.toString(modelData.state) } - Button { - text: "Disconnect" - onClicked: modelData.disconnect() + Label { text: "Device type: " + NetworkDeviceType.toString(modelData.type) } + + RowLayout { + Label { text: "State: " + NetworkDeviceState.toString(modelData.state) } + Button { + text: "Disconnect" + onClicked: modelData.disconnect() + visible: modelData.state === NetworkDeviceState.Connected + } + } + RowLayout { + Label { text: "Last scan: " + modelData.lastScan } + Button { + text: "Scan" + onClicked: modelData.scan() + visible: modelData.scanning === false; + } + visible: modelData.type === NetworkDeviceType.Wireless } } } From 560232c16ae51375b4ffa45306665d5b5dd061c4 Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Wed, 16 Jul 2025 14:24:38 -0500 Subject: [PATCH 24/25] feat: accessPoints --- src/network/CMakeLists.txt | 10 ++ src/network/api.cpp | 55 ++++++- src/network/api.hpp | 72 +++++++-- src/network/nm_adapters.cpp | 144 ++++++++++++++++-- src/network/nm_adapters.hpp | 59 ++++++- src/network/nm_backend.cpp | 44 +++--- src/network/nm_backend.hpp | 10 +- ...freedesktop.NetworkManager.AccessPoint.xml | 5 - ...desktop.NetworkManager.Device.Wireless.xml | 7 +- src/network/test/network.qml | 31 +++- 10 files changed, 365 insertions(+), 72 deletions(-) diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 42f43d5d..1de97dd2 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -29,6 +29,16 @@ qt_add_dbus_interface(NM_DBUS_INTERFACES dbus_nm_wireless ) +set_source_files_properties(org.freedesktop.NetworkManager.AccessPoint.xml PROPERTIES + CLASSNAME DBusNMAccessPointProxy + NO_NAMESPACE TRUE +) + +qt_add_dbus_interface(NM_DBUS_INTERFACES + org.freedesktop.NetworkManager.AccessPoint.xml + dbus_nm_accesspoint +) + qt_add_library(quickshell-network STATIC api.cpp nm_backend.cpp diff --git a/src/network/api.cpp b/src/network/api.cpp index 4de72484..2eb7a5ce 100644 --- a/src/network/api.cpp +++ b/src/network/api.cpp @@ -13,12 +13,13 @@ namespace qs::network { namespace { -Q_LOGGING_CATEGORY(logNetworkNetworkDevice, "quickshell.network.device", QtWarningMsg); +Q_LOGGING_CATEGORY(logNetworkDevice, "quickshell.network.device", QtWarningMsg); Q_LOGGING_CATEGORY(logNetwork, "quickshell.network", QtWarningMsg); } // namespace +// NetworkDevice + NetworkDevice::NetworkDevice(QObject* parent): QObject(parent) {}; -WirelessNetworkDevice::WirelessNetworkDevice(QObject* parent): NetworkDevice(parent) {}; QString NetworkDeviceState::toString(NetworkDeviceState::Enum state) { switch (state) { @@ -60,20 +61,24 @@ void NetworkDevice::setState(NetworkDeviceState::Enum state) { void NetworkDevice::disconnect() { if (this->bState == NetworkDeviceState::Disconnected) { - qCCritical(logNetworkNetworkDevice) << "NetworkDevice" << this << "is already disconnected"; + qCCritical(logNetworkDevice) << "Device" << this << "is already disconnected"; return; } if (this->bState == NetworkDeviceState::Disconnecting) { - qCCritical(logNetworkNetworkDevice) << "NetworkDevice" << this << "is already disconnecting"; + qCCritical(logNetworkDevice) << "Device" << this << "is already disconnecting"; return; } - qCDebug(logNetworkNetworkDevice) << "Disconnecting from device" << this; + qCDebug(logNetworkDevice) << "Disconnecting from device" << this; signalDisconnect(); } +// WirelessNetworkDevice + +WirelessNetworkDevice::WirelessNetworkDevice(QObject* parent): NetworkDevice(parent) {}; + void WirelessNetworkDevice::scanComplete(qint64 lastScan) { this->bLastScan = lastScan; emit this->lastScanChanged(); @@ -86,28 +91,62 @@ void WirelessNetworkDevice::scanComplete(qint64 lastScan) { void WirelessNetworkDevice::scan() { if (this->bScanning) { - qCCritical(logNetworkNetworkDevice) << "NetworkDevice" << this << "is already scanning"; + qCCritical(logNetworkDevice) << "Wireless device" << this << "is already scanning"; return; } - qCDebug(logNetworkNetworkDevice) << "Requesting scan on wireless device" << this; + qCDebug(logNetworkDevice) << "Requesting scan on wireless device" << this; this->bScanning = true; signalScan(); } +void WirelessNetworkDevice::addAccessPoint(NetworkAccessPoint* ap) { + mAccessPoints.insertObject(ap); +} + +void WirelessNetworkDevice::removeAccessPoint(NetworkAccessPoint* ap) { + mAccessPoints.removeObject(ap); +} + +// NetworkAccessPoint + +NetworkAccessPoint::NetworkAccessPoint(QObject* parent): QObject(parent) {}; + +void NetworkAccessPoint::setSsid(const QString& ssid) { + if (this->bSsid != ssid) { + this->bSsid = ssid; + emit ssidChanged(); + } +} + +void NetworkAccessPoint::setSignal(quint8 signal) { + if (this->bSignal != signal) { + this->bSignal = signal; + emit signalChanged(); + } +} + +// Network + Network::Network(QObject* parent): QObject(parent) { // Try each backend // NetworkManager auto* nm = new NetworkManager(); if (nm->isAvailable()) { + QObject::connect(nm, &NetworkManager::deviceAdded, this, &Network::addDevice); + QObject::connect(nm, &NetworkManager::deviceRemoved, this, &Network::removeDevice); this->backend = nm; return; } // None found this->backend = nullptr; - qCDebug(logNetwork) << "Network will not work. Could not find an available backend."; + qCCritical(logNetwork) << "Network will not work. Could not find an available backend."; } +void Network::addDevice(NetworkDevice* device) { this->mDevices.insertObject(device); } + +void Network::removeDevice(NetworkDevice* device) { this->mDevices.removeObject(device); } + } // namespace qs::network diff --git a/src/network/api.hpp b/src/network/api.hpp index ef5d8f4c..63eb9628 100644 --- a/src/network/api.hpp +++ b/src/network/api.hpp @@ -14,6 +14,36 @@ namespace qs::network { +///! A tracked access point on the network +class NetworkAccessPoint: public QObject { + Q_OBJECT; + QML_ELEMENT; + QML_UNCREATABLE("WirelessNetwork can only be acquired through Network"); + // clang-format off + /// The service set identifier of the access point. + Q_PROPERTY(QString ssid READ default NOTIFY ssidChanged BINDABLE bindableSsid); + // The current signal quality of the access point, in percent. + Q_PROPERTY(quint8 signal READ default NOTIFY signalChanged BINDABLE bindableSignal); + //clang-format on + +signals: + void ssidChanged(); + void signalChanged(); + +public slots: + void setSsid(const QString& ssid); + void setSignal(quint8 signal); + +public: + explicit NetworkAccessPoint(QObject* parent = nullptr); + + [[nodiscard]] QBindable bindableSsid() const { return &this->bSsid; }; + [[nodiscard]] QBindable bindableSignal() const { return &this->bSignal; }; + +private: + Q_OBJECT_BINDABLE_PROPERTY(NetworkAccessPoint, QString, bSsid, &NetworkAccessPoint::ssidChanged); + Q_OBJECT_BINDABLE_PROPERTY(NetworkAccessPoint, quint8, bSignal, &NetworkAccessPoint::signalChanged); +}; ///! Type of network device. class NetworkDeviceType: public QObject { @@ -79,11 +109,9 @@ class NetworkDevice: public QObject { void addressChanged(); void stateChanged(); - // For backend slots void signalDisconnect(); public slots: - // For backend signals void setName(const QString& name); void setAddress(const QString& address); void setState(NetworkDeviceState::Enum state); @@ -102,7 +130,12 @@ public slots: private: Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, QString, bName, &NetworkDevice::nameChanged); Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, QString, bAddress, &NetworkDevice::addressChanged); - Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, NetworkDeviceState::Enum, bState, &NetworkDevice::stateChanged); + Q_OBJECT_BINDABLE_PROPERTY( + NetworkDevice, + NetworkDeviceState::Enum, + bState, + &NetworkDevice::stateChanged + ); }; ///! Wireless variant of a tracked network device. @@ -114,18 +147,21 @@ class WirelessNetworkDevice: public NetworkDevice { Q_PROPERTY(qint64 lastScan READ default NOTIFY lastScanChanged BINDABLE bindableLastScan); /// True if the wireless device is currently scanning for available wifi networks. Q_PROPERTY(bool scanning READ default NOTIFY scanningChanged BINDABLE bindableScanning); + /// A list of all available access points + Q_PROPERTY(UntypedObjectModel* accessPoints READ accessPoints CONSTANT); + QSDOC_TYPE_OVERRIDE(ObjectModel*) //clang-format on signals: void signalScan(); - // Frontend-facing signals void lastScanChanged(); void scanningChanged(); public slots: - // For backend signals void scanComplete(qint64 lastScan); + void addAccessPoint(NetworkAccessPoint* ap); + void removeAccessPoint(NetworkAccessPoint* ap); public: explicit WirelessNetworkDevice(QObject* parent = nullptr); @@ -137,11 +173,12 @@ public slots: [[nodiscard]] QBindable bindableScanning() { return &this->bScanning; }; [[nodiscard]] QBindable bindableLastScan() { return &this->bLastScan; }; + UntypedObjectModel* accessPoints() { return &this->mAccessPoints; }; + private: - // clang-format off + ObjectModel mAccessPoints{this}; Q_OBJECT_BINDABLE_PROPERTY(WirelessNetworkDevice, bool, bScanning, &WirelessNetworkDevice::scanningChanged); Q_OBJECT_BINDABLE_PROPERTY(WirelessNetworkDevice, qint64, bLastScan, &WirelessNetworkDevice::lastScanChanged); - // clang-format on }; // -- Network -- @@ -150,29 +187,36 @@ class NetworkBackend: public QObject { public: [[nodiscard]] virtual bool isAvailable() const = 0; - virtual UntypedObjectModel* devices() = 0; - virtual WirelessNetworkDevice* defaultWifiDevice() = 0; protected: explicit NetworkBackend(QObject* parent = nullptr): QObject(parent) {}; }; +///! Network manager +/// Provides access to network devices. class Network: public QObject { Q_OBJECT; QML_NAMED_ELEMENT(Network); QML_SINGLETON; - Q_PROPERTY(WirelessNetworkDevice* defaultWifiNetworkDevice READ defaultWifiNetworkDevice CONSTANT); + // clang-format off + /// The default wifi device. Usually there is only one. This defaults to the first wifi device registered. + // Q_PROPERTY(WirelessNetworkDevice* defaultWifiDevice READ defaultWifiDevice CONSTANT); + /// A list of all network devices. Q_PROPERTY(UntypedObjectModel* devices READ devices CONSTANT); + QSDOC_TYPE_OVERRIDE(ObjectModel*); + // clang-format on + +public slots: + void addDevice(NetworkDevice* device); + void removeDevice(NetworkDevice* device); public: explicit Network(QObject* parent = nullptr); - [[nodiscard]] UntypedObjectModel* devices() { return backend ? backend->devices() : nullptr; }; - [[nodiscard]] WirelessNetworkDevice* defaultWifiNetworkDevice() { - return backend ? backend->defaultWifiDevice() : nullptr; - }; + [[nodiscard]] UntypedObjectModel* devices() { return backend ? &this->mDevices : nullptr; }; private: + ObjectModel mDevices {this}; class NetworkBackend* backend = nullptr; }; diff --git a/src/network/nm_adapters.cpp b/src/network/nm_adapters.cpp index 5ab7cfe4..13c89532 100644 --- a/src/network/nm_adapters.cpp +++ b/src/network/nm_adapters.cpp @@ -9,16 +9,20 @@ #include #include "../dbus/properties.hpp" +#include "dbus_nm_accesspoint.h" #include "dbus_nm_device.h" +#include "dbus_nm_wireless.h" using namespace qs::dbus; namespace qs::network { namespace { -Q_LOGGING_CATEGORY(logNMDevice, "quickshell.network.networkmanager.device", QtWarningMsg); +Q_LOGGING_CATEGORY(logNetworkManager, "quickshell.network.networkmanager", QtWarningMsg); } +// Device + NMDeviceAdapter::NMDeviceAdapter(QObject* parent): QObject(parent) {} void NMDeviceAdapter::init(const QString& path) { @@ -30,7 +34,7 @@ void NMDeviceAdapter::init(const QString& path) { ); if (!this->proxy->isValid()) { - qCWarning(logNMDevice) << "Cannot create NMDeviceAdapter for" << path; + qCWarning(logNetworkManager) << "Cannot create NMDeviceAdapter for" << path; return; } @@ -46,15 +50,17 @@ QString NMDeviceAdapter::address() const { QString NMDeviceAdapter::path() const { return this->proxy ? this->proxy->path() : QString(); } NetworkDeviceState::Enum NMDeviceState::translate(NMDeviceState::Enum state) { - switch(state) { - case 0 ... 20: return NetworkDeviceState::Unknown; - case 30: return NetworkDeviceState::Disconnected; - case 40 ... 90: return NetworkDeviceState::Connecting; - case 100: return NetworkDeviceState::Connected; - case 110 ... 120: return NetworkDeviceState::Disconnecting; + switch (state) { + case 0 ... 20: return NetworkDeviceState::Unknown; + case 30: return NetworkDeviceState::Disconnected; + case 40 ... 90: return NetworkDeviceState::Connecting; + case 100: return NetworkDeviceState::Connected; + case 110 ... 120: return NetworkDeviceState::Disconnecting; } } +// Wireless + NMWirelessAdapter::NMWirelessAdapter(QObject* parent): QObject(parent) {} void NMWirelessAdapter::init(const QString& path) { @@ -66,20 +72,138 @@ void NMWirelessAdapter::init(const QString& path) { ); if (!this->proxy->isValid()) { - qCWarning(logNMDevice) << "Cannot create NMWirelessAdapter for" << path; + qCWarning(logNetworkManager) << "Cannot create NMWirelessAdapter for" << path; return; } + QObject::connect( + this->proxy, + &DBusNMWirelessProxy::AccessPointAdded, + this, + &NMWirelessAdapter::onAccessPointAdded + ); + + QObject::connect( + this->proxy, + &DBusNMWirelessProxy::AccessPointRemoved, + this, + &NMWirelessAdapter::onAccessPointRemoved + ); + this->wirelessProperties.setInterface(this->proxy); this->wirelessProperties.updateAllViaGetAll(); + + this->registerAccessPoints(); } -void NMWirelessAdapter::scan() { this->proxy->RequestScan(); } +void NMWirelessAdapter::onAccessPointAdded(const QDBusObjectPath& path) { + this->registerAccessPoint(path.path()); +} + +void NMWirelessAdapter::onAccessPointRemoved(const QDBusObjectPath& path) { + auto iter = this->mAPHash.find(path.path()); + if (iter == this->mAPHash.end()) { + qCWarning(logNetworkManager) << "NMWirelessAdapter sent removal signal for" << path.path() + << "which is not registered."; + } else { + auto* ap = iter.value(); + this->mAPHash.erase(iter); + emit accessPointRemoved(ap); + qCDebug(logNetworkManager) << "Access point" << path.path() << "removed."; + } +} + +void NMWirelessAdapter::registerAccessPoints() { + auto pending = this->proxy->GetAllAccessPoints(); + auto* call = new QDBusPendingCallWatcher(pending, this); + + auto responseCallback = [this](QDBusPendingCallWatcher* call) { + const QDBusPendingReply> reply = *call; + + if (reply.isError()) { + qCWarning(logNetworkManager) << "Failed to get access points: " << reply.error().message(); + } else { + for (const QDBusObjectPath& devicePath: reply.value()) { + this->registerAccessPoint(devicePath.path()); + } + } + + delete call; + }; + + QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback); +} + +void NMWirelessAdapter::registerAccessPoint(const QString& path) { + if (this->mAPHash.contains(path)) { + qCDebug(logNetworkManager) << "Skipping duplicate registration of access point" << path; + return; + } + + // Create an access point adapter + auto* apAdapter = new NMAccessPointAdapter(); + apAdapter->init(path); + + if (!apAdapter->isValid()) { + qCWarning(logNetworkManager) << "Cannot create NMAccessPointAdapter for" << path; + delete apAdapter; + return; + } + auto* ap = new NetworkAccessPoint(this); + apAdapter->setParent(ap); + + // NMAccessPointAdapter signal -> NetworkAccessPoint slot + QObject::connect(apAdapter, &NMAccessPointAdapter::ssidChanged, ap, &NetworkAccessPoint::setSsid); + QObject::connect( + apAdapter, + &NMAccessPointAdapter::signalChanged, + ap, + &NetworkAccessPoint::setSignal + ); + + this->mAPHash.insert(path, ap); + emit accessPointAdded(ap); + qCDebug(logNetworkManager) << "Registered access point" << path; +} + +void NMWirelessAdapter::scan() { this->proxy->RequestScan({}); } bool NMWirelessAdapter::isValid() const { return this->proxy && this->proxy->isValid(); } QString NMWirelessAdapter::address() const { return this->proxy ? this->proxy->service() : QString(); } QString NMWirelessAdapter::path() const { return this->proxy ? this->proxy->path() : QString(); } + +// Access Point + +namespace { +Q_LOGGING_CATEGORY(logNMAccessPoint, "quickshell.network.networkmanager.accesspoint", QtWarningMsg); +} + +NMAccessPointAdapter::NMAccessPointAdapter(QObject* parent): QObject(parent) {} + +void NMAccessPointAdapter::init(const QString& path) { + this->proxy = new DBusNMAccessPointProxy( + "org.freedesktop.NetworkManager", + path, + QDBusConnection::systemBus(), + this + ); + + if (!this->proxy->isValid()) { + qCWarning(logNMAccessPoint) << "Cannot create NMWirelessAdapter for" << path; + return; + } + + this->accessPointProperties.setInterface(this->proxy); + this->accessPointProperties.updateAllViaGetAll(); +} + +bool NMAccessPointAdapter::isValid() const { return this->proxy && this->proxy->isValid(); } +QString NMAccessPointAdapter::address() const { + return this->proxy ? this->proxy->service() : QString(); +} +QString NMAccessPointAdapter::path() const { return this->proxy ? this->proxy->path() : QString(); } + } // namespace qs::network namespace qs::dbus { diff --git a/src/network/nm_adapters.hpp b/src/network/nm_adapters.hpp index 170ffc22..cea6793c 100644 --- a/src/network/nm_adapters.hpp +++ b/src/network/nm_adapters.hpp @@ -12,6 +12,7 @@ #include "../dbus/properties.hpp" #include "api.hpp" +#include "dbus_nm_accesspoint.h" #include "dbus_nm_device.h" #include "dbus_nm_wireless.h" @@ -113,6 +114,7 @@ class NMDeviceAdapter: public QObject { public: explicit NMDeviceAdapter(QObject* parent = nullptr); void init(const QString& path); + [[nodiscard]] bool isValid() const; [[nodiscard]] QString path() const; [[nodiscard]] QString address() const; @@ -141,6 +143,7 @@ public slots: QS_DBUS_PROPERTY_BINDING(NMDeviceAdapter, pAddress, bHwAddress, deviceProperties, "HwAddress"); QS_DBUS_PROPERTY_BINDING(NMDeviceAdapter, pType, bType, deviceProperties, "DeviceType"); QS_DBUS_PROPERTY_BINDING(NMDeviceAdapter, pState, bState, deviceProperties, "State"); + // clang-format on DBusNMDeviceProxy* proxy = nullptr; }; @@ -151,6 +154,10 @@ class NMWirelessAdapter: public QObject { public: explicit NMWirelessAdapter(QObject* parent = nullptr); void init(const QString& path); + void registerAccessPoint(const QString& path); + void registerAccessPoints(); + QHash mAPHash; + [[nodiscard]] bool isValid() const; [[nodiscard]] QString path() const; [[nodiscard]] QString address() const; @@ -161,13 +168,63 @@ public slots: signals: void lastScanChanged(qint64 lastScan); + void accessPointAdded(NetworkAccessPoint* ap); + void accessPointRemoved(NetworkAccessPoint* ap); + +private slots: + void onAccessPointAdded(const QDBusObjectPath& path); + void onAccessPointRemoved(const QDBusObjectPath& path); private: // clang-format off Q_OBJECT_BINDABLE_PROPERTY(NMWirelessAdapter, qint64, bLastScan, &NMWirelessAdapter::lastScanChanged); - + QS_DBUS_BINDABLE_PROPERTY_GROUP(NMWirelessAdapter, wirelessProperties); QS_DBUS_PROPERTY_BINDING(NMWirelessAdapter, pLastScan, bLastScan, wirelessProperties, "LastScan"); + // clang-format on + DBusNMWirelessProxy* proxy = nullptr; }; + +class NMAccessPointAdapter: public QObject { + Q_OBJECT; + +public: + explicit NMAccessPointAdapter(QObject* parent = nullptr); + void init(const QString& path); + [[nodiscard]] bool isValid() const; + [[nodiscard]] QString path() const; + [[nodiscard]] QString address() const; + +signals: + void ssidChanged(QByteArray ssid); + void signalChanged(uchar signal); + +private: + //clang-format off + Q_OBJECT_BINDABLE_PROPERTY( + NMAccessPointAdapter, + QByteArray, + bSsid, + &NMAccessPointAdapter::ssidChanged + ); + Q_OBJECT_BINDABLE_PROPERTY( + NMAccessPointAdapter, + uchar, + bSignal, + &NMAccessPointAdapter::signalChanged + ); + + QS_DBUS_BINDABLE_PROPERTY_GROUP(NMAccessPointAdapter, accessPointProperties); + QS_DBUS_PROPERTY_BINDING(NMAccessPointAdapter, pSsid, bSsid, accessPointProperties, "Ssid"); + QS_DBUS_PROPERTY_BINDING( + NMAccessPointAdapter, + pSignal, + bSignal, + accessPointProperties, + "Strength" + ); + + DBusNMAccessPointProxy* proxy = nullptr; +}; } // namespace qs::network diff --git a/src/network/nm_backend.cpp b/src/network/nm_backend.cpp index 2c53c7c5..22a84cb5 100644 --- a/src/network/nm_backend.cpp +++ b/src/network/nm_backend.cpp @@ -47,7 +47,7 @@ NetworkManager::NetworkManager(QObject* parent): NetworkBackend(parent) { this->init(); } else { qCWarning(logNetworkManager) - << "Could not start NetworkManager. The NetworkManager backend will not work."; + << "Could not start NetworkManager. This network backend will not work."; } }); } else { @@ -56,13 +56,13 @@ NetworkManager::NetworkManager(QObject* parent): NetworkBackend(parent) { } void NetworkManager::init() { + // Proxy signals -> NetworkManager slots QObject::connect( this->proxy, &DBusNetworkManagerProxy::DeviceAdded, this, &NetworkManager::onDeviceAdded ); - QObject::connect( this->proxy, &DBusNetworkManagerProxy::DeviceRemoved, @@ -109,10 +109,11 @@ void NetworkManager::queueDeviceRegistration(const QString& path) { if (!deviceAdapter->isValid()) { qCWarning(logNetworkManager) << "Ignoring invalid registration of" << path; + delete deviceAdapter; return; } - // Wait for DBus to tell us the device type + // Wait for DBus to send us the device type QObject::connect( deviceAdapter, &NMDeviceAdapter::typeChanged, @@ -130,9 +131,9 @@ void NetworkManager::registerDevice( const QString& path ) { NetworkDevice* device = createDeviceVariant(type, path); + deviceAdapter->setParent(device); // NMDeviceAdapter signal -> NetworkDevice slot - deviceAdapter->setParent(device); QObject::connect( deviceAdapter, &NMDeviceAdapter::hwAddressChanged, @@ -162,7 +163,7 @@ void NetworkManager::registerDevice( // Track device this->mDeviceHash.insert(path, device); - this->mDevices.insertObject(device); + emit deviceAdded(device); qCDebug(logNetworkManager) << "Registered device at path" << path; } @@ -175,22 +176,33 @@ NetworkDevice* NetworkManager::createDeviceVariant(NMDeviceType::Enum type, cons } } -// Create a frontend WirelessNetworkDevice and bind the backend wireless adapter to it +// Create a WirelessNetworkDevice and bind the NMWirelessAdapter WirelessNetworkDevice* NetworkManager::bindWirelessDevice(const QString& path) { auto* device = new WirelessNetworkDevice(this); auto* wirelessAdapter = new NMWirelessAdapter(device); wirelessAdapter->init(path); + // TODO: Check isValid() - throw error + // NMWirelessAdapter signal -> WirelessNetworkDevice slot QObject::connect( wirelessAdapter, &NMWirelessAdapter::lastScanChanged, device, - [device](qint64 lastScan) { - device->scanComplete(lastScan); - qCDebug(logNetworkManager) << lastScan; - } + &WirelessNetworkDevice::scanComplete + ); + QObject::connect( + wirelessAdapter, + &NMWirelessAdapter::accessPointAdded, + device, + &WirelessNetworkDevice::addAccessPoint + ); + QObject::connect( + wirelessAdapter, + &NMWirelessAdapter::accessPointRemoved, + device, + &WirelessNetworkDevice::removeAccessPoint ); // WirelessNetworkDevice signal -> NMWirelessAdapter slot @@ -201,9 +213,6 @@ WirelessNetworkDevice* NetworkManager::bindWirelessDevice(const QString& path) { &NMWirelessAdapter::scan ); - if (this->mWifi == nullptr) { - this->mWifi = device; - }; return device; } @@ -219,17 +228,12 @@ void NetworkManager::onDeviceRemoved(const QDBusObjectPath& path) { << "which is not registered."; } else { auto* device = iter.value(); - if (this->mWifi == device) { - this->mWifi = nullptr; - }; this->mDeviceHash.erase(iter); - this->mDevices.removeObject(device); - qCDebug(logNetworkManager) << "NetworkDevice" << path.path() << "removed."; + emit deviceRemoved(device); + qCDebug(logNetworkManager) << "Device" << path.path() << "removed."; } } -UntypedObjectModel* NetworkManager::devices() { return &this->mDevices; } -WirelessNetworkDevice* NetworkManager::defaultWifiDevice() { return this->mWifi; } bool NetworkManager::isAvailable() const { return this->proxy && this->proxy->isValid(); } } // namespace qs::network diff --git a/src/network/nm_backend.hpp b/src/network/nm_backend.hpp index 3e96b3e3..5c1c5659 100644 --- a/src/network/nm_backend.hpp +++ b/src/network/nm_backend.hpp @@ -20,11 +20,12 @@ namespace qs::network { class NetworkManager: public NetworkBackend { Q_OBJECT; +signals: + void deviceAdded(NetworkDevice* device); + void deviceRemoved(NetworkDevice* device); + public: explicit NetworkManager(QObject* parent = nullptr); - - UntypedObjectModel* devices() override; - WirelessNetworkDevice* defaultWifiDevice() override; [[nodiscard]] bool isAvailable() const override; private slots: @@ -41,11 +42,8 @@ private slots: NetworkDevice* bindDevice(NMDeviceAdapter* deviceAdapter); QHash mDeviceHash; - ObjectModel mDevices {this}; - WirelessNetworkDevice* mWifi = nullptr; QS_DBUS_BINDABLE_PROPERTY_GROUP(NetworkManager, dbusProperties); - DBusNetworkManagerProxy* proxy = nullptr; }; diff --git a/src/network/org.freedesktop.NetworkManager.AccessPoint.xml b/src/network/org.freedesktop.NetworkManager.AccessPoint.xml index 33872050..0f5dcf2f 100644 --- a/src/network/org.freedesktop.NetworkManager.AccessPoint.xml +++ b/src/network/org.freedesktop.NetworkManager.AccessPoint.xml @@ -1,11 +1,6 @@ - - - - - diff --git a/src/network/org.freedesktop.NetworkManager.Device.Wireless.xml b/src/network/org.freedesktop.NetworkManager.Device.Wireless.xml index 17b712bb..cc83004a 100644 --- a/src/network/org.freedesktop.NetworkManager.Device.Wireless.xml +++ b/src/network/org.freedesktop.NetworkManager.Device.Wireless.xml @@ -6,13 +6,16 @@ - + + + + - arg name="access_ponit" type="o"/> + diff --git a/src/network/test/network.qml b/src/network/test/network.qml index 357daa54..08c5da7a 100644 --- a/src/network/test/network.qml +++ b/src/network/test/network.qml @@ -41,12 +41,31 @@ FloatingWindow { visible: modelData.state === NetworkDeviceState.Connected } } - RowLayout { - Label { text: "Last scan: " + modelData.lastScan } - Button { - text: "Scan" - onClicked: modelData.scan() - visible: modelData.scanning === false; + ColumnLayout { + RowLayout { + Label { text: "Last scan: " + modelData.lastScan } + Button { + text: "Scan" + onClicked: modelData.scan() + visible: modelData.scanning === false; + } + } + Label { text: "Available access points: " } + Repeater { + model: modelData.accessPoints + + delegate: WrapperRectangle { + height: apLabel.implicitHeight + 8 + color: "transparent" + border.color: palette.button + border.width: 1 + + Label { + id: apLabel + anchors.centerIn: parent + text: "SSID: " + (modelData.ssid || "[Hidden]") + ` SIGNAL: ${modelData.signal}` + } + } } visible: modelData.type === NetworkDeviceType.Wireless } From 70906334c20b93ce1d7b5926393504097d3f0b91 Mon Sep 17 00:00:00 2001 From: Carson Powers Date: Wed, 16 Jul 2025 17:09:39 -0500 Subject: [PATCH 25/25] fix: annotate RequestScan a{sv} for qdbusxml2cpp --- src/network/nm_adapters.cpp | 3 ++- src/network/org.freedesktop.NetworkManager.Device.Wireless.xml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/network/nm_adapters.cpp b/src/network/nm_adapters.cpp index 13c89532..1ce02f0c 100644 --- a/src/network/nm_adapters.cpp +++ b/src/network/nm_adapters.cpp @@ -104,7 +104,7 @@ void NMWirelessAdapter::onAccessPointRemoved(const QDBusObjectPath& path) { auto iter = this->mAPHash.find(path.path()); if (iter == this->mAPHash.end()) { qCWarning(logNetworkManager) << "NMWirelessAdapter sent removal signal for" << path.path() - << "which is not registered."; + << "which is not registered."; } else { auto* ap = iter.value(); this->mAPHash.erase(iter); @@ -167,6 +167,7 @@ void NMWirelessAdapter::registerAccessPoint(const QString& path) { } void NMWirelessAdapter::scan() { this->proxy->RequestScan({}); } + bool NMWirelessAdapter::isValid() const { return this->proxy && this->proxy->isValid(); } QString NMWirelessAdapter::address() const { return this->proxy ? this->proxy->service() : QString(); diff --git a/src/network/org.freedesktop.NetworkManager.Device.Wireless.xml b/src/network/org.freedesktop.NetworkManager.Device.Wireless.xml index cc83004a..5814185d 100644 --- a/src/network/org.freedesktop.NetworkManager.Device.Wireless.xml +++ b/src/network/org.freedesktop.NetworkManager.Device.Wireless.xml @@ -8,7 +8,8 @@ - + +