mirror of
https://git.outfoxxed.me/quickshell/quickshell.git
synced 2026-04-10 06:11:54 +10:00
networking: add PSK, settings and connection status support
This commit is contained in:
parent
92b336c80c
commit
20c691cdf1
34 changed files with 2200 additions and 881 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
project(quickshell VERSION "0.2.1" LANGUAGES CXX C)
|
project(quickshell VERSION "0.2.1" LANGUAGES CXX C)
|
||||||
|
|
||||||
set(UNRELEASED_FEATURES)
|
set(UNRELEASED_FEATURES "network.2")
|
||||||
|
|
||||||
set(QT_MIN_VERSION "6.6.0")
|
set(QT_MIN_VERSION "6.6.0")
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ set shell id.
|
||||||
- Added the ability to handle move and resize events to FloatingWindow.
|
- Added the ability to handle move and resize events to FloatingWindow.
|
||||||
- Pipewire service now reconnects if pipewire dies or a protocol error occurs.
|
- Pipewire service now reconnects if pipewire dies or a protocol error occurs.
|
||||||
- Added pipewire audio peak detection.
|
- Added pipewire audio peak detection.
|
||||||
- Added initial support for network management.
|
- Added network management support.
|
||||||
- Added support for grabbing focus from popup windows.
|
- Added support for grabbing focus from popup windows.
|
||||||
- Added support for IPC signal listeners.
|
- Added support for IPC signal listeners.
|
||||||
- Added Quickshell version checking and version gated preprocessing.
|
- Added Quickshell version checking and version gated preprocessing.
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ qt_add_library(quickshell-network STATIC
|
||||||
network.cpp
|
network.cpp
|
||||||
device.cpp
|
device.cpp
|
||||||
wifi.cpp
|
wifi.cpp
|
||||||
|
enums.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(quickshell-network PRIVATE
|
target_include_directories(quickshell-network PRIVATE
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
|
|
||||||
#include "../core/logcat.hpp"
|
#include "../core/logcat.hpp"
|
||||||
|
#include "enums.hpp"
|
||||||
|
|
||||||
namespace qs::network {
|
namespace qs::network {
|
||||||
|
|
||||||
|
|
@ -15,49 +16,9 @@ namespace {
|
||||||
QS_LOGGING_CATEGORY(logNetworkDevice, "quickshell.network.device", QtWarningMsg);
|
QS_LOGGING_CATEGORY(logNetworkDevice, "quickshell.network.device", QtWarningMsg);
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
QString DeviceConnectionState::toString(DeviceConnectionState::Enum state) {
|
|
||||||
switch (state) {
|
|
||||||
case Unknown: return QStringLiteral("Unknown");
|
|
||||||
case Connecting: return QStringLiteral("Connecting");
|
|
||||||
case Connected: return QStringLiteral("Connected");
|
|
||||||
case Disconnecting: return QStringLiteral("Disconnecting");
|
|
||||||
case Disconnected: return QStringLiteral("Disconnected");
|
|
||||||
default: return QStringLiteral("Unknown");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString DeviceType::toString(DeviceType::Enum type) {
|
|
||||||
switch (type) {
|
|
||||||
case None: return QStringLiteral("None");
|
|
||||||
case Wifi: return QStringLiteral("Wifi");
|
|
||||||
default: return QStringLiteral("Unknown");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString NMDeviceState::toString(NMDeviceState::Enum state) {
|
|
||||||
switch (state) {
|
|
||||||
case Unknown: return QStringLiteral("Unknown");
|
|
||||||
case Unmanaged: return QStringLiteral("Not managed by NetworkManager");
|
|
||||||
case Unavailable: return QStringLiteral("Unavailable");
|
|
||||||
case Disconnected: return QStringLiteral("Disconnected");
|
|
||||||
case Prepare: return QStringLiteral("Preparing to connect");
|
|
||||||
case Config: return QStringLiteral("Connecting to a network");
|
|
||||||
case NeedAuth: return QStringLiteral("Waiting for authentication");
|
|
||||||
case IPConfig: return QStringLiteral("Requesting IPv4 and/or IPv6 addresses from the network");
|
|
||||||
case IPCheck:
|
|
||||||
return QStringLiteral("Checking if further action is required for the requested connection");
|
|
||||||
case Secondaries:
|
|
||||||
return QStringLiteral("Waiting for a required secondary connection to activate");
|
|
||||||
case Activated: return QStringLiteral("Connected");
|
|
||||||
case Deactivating: return QStringLiteral("Disconnecting");
|
|
||||||
case Failed: return QStringLiteral("Failed to connect");
|
|
||||||
default: return QStringLiteral("Unknown");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
NetworkDevice::NetworkDevice(DeviceType::Enum type, QObject* parent): QObject(parent), mType(type) {
|
NetworkDevice::NetworkDevice(DeviceType::Enum type, QObject* parent): QObject(parent), mType(type) {
|
||||||
this->bindableConnected().setBinding([this]() {
|
this->bindableConnected().setBinding([this]() {
|
||||||
return this->bState == DeviceConnectionState::Connected;
|
return this->bState == ConnectionState::Connected;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -66,12 +27,17 @@ void NetworkDevice::setAutoconnect(bool autoconnect) {
|
||||||
emit this->requestSetAutoconnect(autoconnect);
|
emit this->requestSetAutoconnect(autoconnect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkDevice::setNmManaged(bool managed) {
|
||||||
|
if (this->bNmManaged == managed) return;
|
||||||
|
emit this->requestSetNmManaged(managed);
|
||||||
|
}
|
||||||
|
|
||||||
void NetworkDevice::disconnect() {
|
void NetworkDevice::disconnect() {
|
||||||
if (this->bState == DeviceConnectionState::Disconnected) {
|
if (this->bState == ConnectionState::Disconnected) {
|
||||||
qCCritical(logNetworkDevice) << "Device" << this << "is already disconnected";
|
qCCritical(logNetworkDevice) << "Device" << this << "is already disconnected";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this->bState == DeviceConnectionState::Disconnecting) {
|
if (this->bState == ConnectionState::Disconnecting) {
|
||||||
qCCritical(logNetworkDevice) << "Device" << this << "is already disconnecting";
|
qCCritical(logNetworkDevice) << "Device" << this << "is already disconnecting";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,76 +6,22 @@
|
||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
#include <qtypes.h>
|
#include <qtypes.h>
|
||||||
|
|
||||||
|
#include "../core/doc.hpp"
|
||||||
|
#include "enums.hpp"
|
||||||
|
|
||||||
namespace qs::network {
|
namespace qs::network {
|
||||||
|
|
||||||
///! Connection state of a NetworkDevice.
|
|
||||||
class DeviceConnectionState: public QObject {
|
|
||||||
Q_OBJECT;
|
|
||||||
QML_ELEMENT;
|
|
||||||
QML_SINGLETON;
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum Enum : quint8 {
|
|
||||||
Unknown = 0,
|
|
||||||
Connecting = 1,
|
|
||||||
Connected = 2,
|
|
||||||
Disconnecting = 3,
|
|
||||||
Disconnected = 4,
|
|
||||||
};
|
|
||||||
Q_ENUM(Enum);
|
|
||||||
Q_INVOKABLE static QString toString(DeviceConnectionState::Enum state);
|
|
||||||
};
|
|
||||||
|
|
||||||
///! Type of network device.
|
|
||||||
class DeviceType: public QObject {
|
|
||||||
Q_OBJECT;
|
|
||||||
QML_ELEMENT;
|
|
||||||
QML_SINGLETON;
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum Enum : quint8 {
|
|
||||||
None = 0,
|
|
||||||
Wifi = 1,
|
|
||||||
};
|
|
||||||
Q_ENUM(Enum);
|
|
||||||
Q_INVOKABLE static QString toString(DeviceType::Enum type);
|
|
||||||
};
|
|
||||||
|
|
||||||
///! NetworkManager-specific device state.
|
|
||||||
/// In sync with https://networkmanager.dev/docs/api/latest/nm-dbus-types.html#NMDeviceState.
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
///! A network device.
|
///! A network device.
|
||||||
/// When @@type is `Wifi`, the device is a @@WifiDevice, which can be used to scan for and connect to access points.
|
/// The @@type property may be used to determine if this device is a @@WifiDevice.
|
||||||
class NetworkDevice: public QObject {
|
class NetworkDevice: public QObject {
|
||||||
Q_OBJECT;
|
Q_OBJECT;
|
||||||
QML_ELEMENT;
|
QML_ELEMENT;
|
||||||
QML_UNCREATABLE("Devices can only be acquired through Network");
|
QML_UNCREATABLE("Devices can only be acquired through Network");
|
||||||
// clang-format off
|
// clang-format off
|
||||||
/// The device type.
|
/// The device type.
|
||||||
|
///
|
||||||
|
/// When the device type is `Wifi`, the device object is a @@WifiDevice which exposes wifi network
|
||||||
|
/// connection and scanning.
|
||||||
Q_PROPERTY(DeviceType::Enum type READ type CONSTANT);
|
Q_PROPERTY(DeviceType::Enum type READ type CONSTANT);
|
||||||
/// The name of the device's control interface.
|
/// The name of the device's control interface.
|
||||||
Q_PROPERTY(QString name READ name NOTIFY nameChanged BINDABLE bindableName);
|
Q_PROPERTY(QString name READ name NOTIFY nameChanged BINDABLE bindableName);
|
||||||
|
|
@ -84,10 +30,12 @@ class NetworkDevice: public QObject {
|
||||||
/// True if the device is connected.
|
/// True if the device is connected.
|
||||||
Q_PROPERTY(bool connected READ default NOTIFY connectedChanged BINDABLE bindableConnected);
|
Q_PROPERTY(bool connected READ default NOTIFY connectedChanged BINDABLE bindableConnected);
|
||||||
/// Connection state of the device.
|
/// Connection state of the device.
|
||||||
Q_PROPERTY(qs::network::DeviceConnectionState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState);
|
Q_PROPERTY(qs::network::ConnectionState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState);
|
||||||
/// A more specific device state when the backend is NetworkManager.
|
/// True if the device is managed by NetworkManager.
|
||||||
Q_PROPERTY(qs::network::NMDeviceState::Enum nmState READ default NOTIFY nmStateChanged BINDABLE bindableNmState);
|
///
|
||||||
/// True if the device is allowed to autoconnect.
|
/// > [!WARNING] Only valid for the NetworkManager backend.
|
||||||
|
Q_PROPERTY(bool nmManaged READ nmManaged WRITE setNmManaged NOTIFY nmManagedChanged)
|
||||||
|
/// True if the device is allowed to autoconnect to a network.
|
||||||
Q_PROPERTY(bool autoconnect READ autoconnect WRITE setAutoconnect NOTIFY autoconnectChanged);
|
Q_PROPERTY(bool autoconnect READ autoconnect WRITE setAutoconnect NOTIFY autoconnectChanged);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|
@ -97,25 +45,28 @@ public:
|
||||||
/// Disconnects the device and prevents it from automatically activating further connections.
|
/// Disconnects the device and prevents it from automatically activating further connections.
|
||||||
Q_INVOKABLE void disconnect();
|
Q_INVOKABLE void disconnect();
|
||||||
|
|
||||||
[[nodiscard]] DeviceType::Enum type() const { return this->mType; };
|
[[nodiscard]] DeviceType::Enum type() const { return this->mType; }
|
||||||
QBindable<QString> bindableName() { return &this->bName; };
|
QBindable<QString> bindableName() { return &this->bName; }
|
||||||
[[nodiscard]] QString name() const { return this->bName; };
|
[[nodiscard]] QString name() const { return this->bName; }
|
||||||
QBindable<QString> bindableAddress() { return &this->bAddress; };
|
QBindable<QString> bindableAddress() { return &this->bAddress; }
|
||||||
QBindable<bool> bindableConnected() { return &this->bConnected; };
|
QBindable<bool> bindableConnected() { return &this->bConnected; }
|
||||||
QBindable<DeviceConnectionState::Enum> bindableState() { return &this->bState; };
|
QBindable<ConnectionState::Enum> bindableState() { return &this->bState; }
|
||||||
QBindable<NMDeviceState::Enum> bindableNmState() { return &this->bNmState; };
|
QBindable<bool> bindableNmManaged() { return &this->bNmManaged; }
|
||||||
[[nodiscard]] bool autoconnect() const { return this->bAutoconnect; };
|
[[nodiscard]] bool nmManaged() { return this->bNmManaged; }
|
||||||
QBindable<bool> bindableAutoconnect() { return &this->bAutoconnect; };
|
void setNmManaged(bool managed);
|
||||||
|
QBindable<bool> bindableAutoconnect() { return &this->bAutoconnect; }
|
||||||
|
[[nodiscard]] bool autoconnect() { return this->bAutoconnect; }
|
||||||
void setAutoconnect(bool autoconnect);
|
void setAutoconnect(bool autoconnect);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void requestDisconnect();
|
QSDOC_HIDE void requestDisconnect();
|
||||||
void requestSetAutoconnect(bool autoconnect);
|
QSDOC_HIDE void requestSetAutoconnect(bool autoconnect);
|
||||||
|
QSDOC_HIDE void requestSetNmManaged(bool managed);
|
||||||
void nameChanged();
|
void nameChanged();
|
||||||
void addressChanged();
|
void addressChanged();
|
||||||
void connectedChanged();
|
void connectedChanged();
|
||||||
void stateChanged();
|
void stateChanged();
|
||||||
void nmStateChanged();
|
void nmManagedChanged();
|
||||||
void autoconnectChanged();
|
void autoconnectChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -124,8 +75,8 @@ private:
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, QString, bName, &NetworkDevice::nameChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, QString, bName, &NetworkDevice::nameChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, QString, bAddress, &NetworkDevice::addressChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, QString, bAddress, &NetworkDevice::addressChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, bool, bConnected, &NetworkDevice::connectedChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, bool, bConnected, &NetworkDevice::connectedChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, DeviceConnectionState::Enum, bState, &NetworkDevice::stateChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, ConnectionState::Enum, bState, &NetworkDevice::stateChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, NMDeviceState::Enum, bNmState, &NetworkDevice::nmStateChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, bool, bNmManaged, &NetworkDevice::nmManagedChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, bool, bAutoconnect, &NetworkDevice::autoconnectChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, bool, bAutoconnect, &NetworkDevice::autoconnectChanged);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
};
|
};
|
||||||
|
|
|
||||||
86
src/network/enums.cpp
Normal file
86
src/network/enums.cpp
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
#include "enums.hpp"
|
||||||
|
|
||||||
|
#include <qstring.h>
|
||||||
|
|
||||||
|
namespace qs::network {
|
||||||
|
|
||||||
|
QString NetworkConnectivity::toString(NetworkConnectivity::Enum conn) {
|
||||||
|
switch (conn) {
|
||||||
|
case Unknown: return QStringLiteral("Unknown");
|
||||||
|
case None: return QStringLiteral("Not connected to a network");
|
||||||
|
case Portal: return QStringLiteral("Connection intercepted by a captive portal");
|
||||||
|
case Limited: return QStringLiteral("Partial internet connectivity");
|
||||||
|
case Full: return QStringLiteral("Full internet connectivity");
|
||||||
|
default: return QStringLiteral("Unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString NetworkBackendType::toString(NetworkBackendType::Enum type) {
|
||||||
|
switch (type) {
|
||||||
|
case NetworkBackendType::None: return "None";
|
||||||
|
case NetworkBackendType::NetworkManager: return "NetworkManager";
|
||||||
|
default: return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ConnectionState::toString(ConnectionState::Enum state) {
|
||||||
|
switch (state) {
|
||||||
|
case Unknown: return QStringLiteral("Unknown");
|
||||||
|
case Connecting: return QStringLiteral("Connecting");
|
||||||
|
case Connected: return QStringLiteral("Connected");
|
||||||
|
case Disconnecting: return QStringLiteral("Disconnecting");
|
||||||
|
case Disconnected: return QStringLiteral("Disconnected");
|
||||||
|
default: return QStringLiteral("Unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ConnectionFailReason::toString(ConnectionFailReason::Enum reason) {
|
||||||
|
switch (reason) {
|
||||||
|
case Unknown: return QStringLiteral("Unknown");
|
||||||
|
case NoSecrets: return QStringLiteral("Secrets were required but not provided");
|
||||||
|
case WifiClientDisconnected: return QStringLiteral("Wi-Fi supplicant diconnected");
|
||||||
|
case WifiClientFailed: return QStringLiteral("Wi-Fi supplicant failed");
|
||||||
|
case WifiAuthTimeout: return QStringLiteral("Wi-Fi connection took too long to authenticate");
|
||||||
|
case WifiNetworkLost: return QStringLiteral("Wi-Fi network could not be found");
|
||||||
|
default: return QStringLiteral("Unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DeviceType::toString(DeviceType::Enum type) {
|
||||||
|
switch (type) {
|
||||||
|
case None: return QStringLiteral("None");
|
||||||
|
case Wifi: return QStringLiteral("Wifi");
|
||||||
|
default: return QStringLiteral("Unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString WifiSecurityType::toString(WifiSecurityType::Enum type) {
|
||||||
|
switch (type) {
|
||||||
|
case Unknown: return QStringLiteral("Unknown");
|
||||||
|
case Wpa3SuiteB192: return QStringLiteral("WPA3 Suite B 192-bit");
|
||||||
|
case Sae: return QStringLiteral("WPA3");
|
||||||
|
case Wpa2Eap: return QStringLiteral("WPA2 Enterprise");
|
||||||
|
case Wpa2Psk: return QStringLiteral("WPA2");
|
||||||
|
case WpaEap: return QStringLiteral("WPA Enterprise");
|
||||||
|
case WpaPsk: return QStringLiteral("WPA");
|
||||||
|
case StaticWep: return QStringLiteral("WEP");
|
||||||
|
case DynamicWep: return QStringLiteral("Dynamic WEP");
|
||||||
|
case Leap: return QStringLiteral("LEAP");
|
||||||
|
case Owe: return QStringLiteral("OWE");
|
||||||
|
case Open: return QStringLiteral("Open");
|
||||||
|
default: return QStringLiteral("Unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString WifiDeviceMode::toString(WifiDeviceMode::Enum mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case Unknown: return QStringLiteral("Unknown");
|
||||||
|
case AdHoc: return QStringLiteral("Ad-Hoc");
|
||||||
|
case Station: return QStringLiteral("Station");
|
||||||
|
case AccessPoint: return QStringLiteral("Access Point");
|
||||||
|
case Mesh: return QStringLiteral("Mesh");
|
||||||
|
default: return QStringLiteral("Unknown");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace qs::network
|
||||||
154
src/network/enums.hpp
Normal file
154
src/network/enums.hpp
Normal file
|
|
@ -0,0 +1,154 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qobject.h>
|
||||||
|
#include <qqmlintegration.h>
|
||||||
|
#include <qtypes.h>
|
||||||
|
|
||||||
|
namespace qs::network {
|
||||||
|
|
||||||
|
///! The degree to which the host can reach the internet.
|
||||||
|
class NetworkConnectivity: public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
QML_ELEMENT;
|
||||||
|
QML_SINGLETON;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Enum : quint8 {
|
||||||
|
/// Network connectivity is unknown. This means the connectivity checks are disabled or have not run yet.
|
||||||
|
Unknown = 0,
|
||||||
|
/// The host is not connected to any network.
|
||||||
|
None = 1,
|
||||||
|
/// The internet connection is hijacked by a captive portal gateway.
|
||||||
|
/// This indicates the shell should open a sandboxed web browser window for the purpose of authenticating to a gateway.
|
||||||
|
Portal = 2,
|
||||||
|
/// The host is connected to a network but does not appear to be able to reach the full internet.
|
||||||
|
Limited = 3,
|
||||||
|
/// The host is connected to a network and appears to be able to reach the full internet.
|
||||||
|
Full = 4,
|
||||||
|
};
|
||||||
|
Q_ENUM(Enum);
|
||||||
|
Q_INVOKABLE static QString toString(NetworkConnectivity::Enum conn);
|
||||||
|
};
|
||||||
|
|
||||||
|
///! The backend supplying the Network service.
|
||||||
|
class NetworkBackendType: public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
QML_ELEMENT;
|
||||||
|
QML_SINGLETON;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Enum : quint8 {
|
||||||
|
None = 0,
|
||||||
|
NetworkManager = 1,
|
||||||
|
};
|
||||||
|
Q_ENUM(Enum);
|
||||||
|
Q_INVOKABLE static QString toString(NetworkBackendType::Enum type);
|
||||||
|
};
|
||||||
|
|
||||||
|
///! The connection state of a device or network.
|
||||||
|
class ConnectionState: public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
QML_ELEMENT;
|
||||||
|
QML_SINGLETON;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Enum : quint8 {
|
||||||
|
Unknown = 0,
|
||||||
|
Connecting = 1,
|
||||||
|
Connected = 2,
|
||||||
|
Disconnecting = 3,
|
||||||
|
Disconnected = 4,
|
||||||
|
};
|
||||||
|
Q_ENUM(Enum);
|
||||||
|
Q_INVOKABLE static QString toString(ConnectionState::Enum state);
|
||||||
|
};
|
||||||
|
|
||||||
|
///! The reason a connection failed.
|
||||||
|
class ConnectionFailReason: public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
QML_ELEMENT;
|
||||||
|
QML_SINGLETON;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Enum : quint8 {
|
||||||
|
/// The connection failed for an unknown reason.
|
||||||
|
Unknown = 0,
|
||||||
|
/// Secrets were required, but not provided.
|
||||||
|
NoSecrets = 1,
|
||||||
|
/// The Wi-Fi supplicant disconnected.
|
||||||
|
WifiClientDisconnected = 2,
|
||||||
|
/// The Wi-Fi supplicant failed.
|
||||||
|
WifiClientFailed = 3,
|
||||||
|
/// The Wi-Fi connection took too long to authenticate.
|
||||||
|
WifiAuthTimeout = 4,
|
||||||
|
/// The Wi-Fi network could not be found.
|
||||||
|
WifiNetworkLost = 5,
|
||||||
|
};
|
||||||
|
Q_ENUM(Enum);
|
||||||
|
Q_INVOKABLE static QString toString(ConnectionFailReason::Enum reason);
|
||||||
|
};
|
||||||
|
|
||||||
|
///! Type of a @@NetworkDevice.
|
||||||
|
class DeviceType: public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
QML_ELEMENT;
|
||||||
|
QML_SINGLETON;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Enum : quint8 {
|
||||||
|
None = 0,
|
||||||
|
Wifi = 1,
|
||||||
|
};
|
||||||
|
Q_ENUM(Enum);
|
||||||
|
Q_INVOKABLE static QString toString(DeviceType::Enum type);
|
||||||
|
};
|
||||||
|
|
||||||
|
///! The security type of a @@WifiNetwork.
|
||||||
|
class WifiSecurityType: public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
QML_ELEMENT;
|
||||||
|
QML_SINGLETON;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Enum : quint8 {
|
||||||
|
Wpa3SuiteB192 = 0,
|
||||||
|
Sae = 1,
|
||||||
|
Wpa2Eap = 2,
|
||||||
|
Wpa2Psk = 3,
|
||||||
|
WpaEap = 4,
|
||||||
|
WpaPsk = 5,
|
||||||
|
StaticWep = 6,
|
||||||
|
DynamicWep = 7,
|
||||||
|
Leap = 8,
|
||||||
|
Owe = 9,
|
||||||
|
Open = 10,
|
||||||
|
Unknown = 11,
|
||||||
|
};
|
||||||
|
Q_ENUM(Enum);
|
||||||
|
Q_INVOKABLE static QString toString(WifiSecurityType::Enum type);
|
||||||
|
};
|
||||||
|
|
||||||
|
///! The 802.11 mode of a @@WifiDevice.
|
||||||
|
class WifiDeviceMode: public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
QML_ELEMENT;
|
||||||
|
QML_SINGLETON;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Enum : quint8 {
|
||||||
|
/// The device is part of an Ad-Hoc network without a central access point.
|
||||||
|
AdHoc = 0,
|
||||||
|
/// The device is a station that can connect to networks.
|
||||||
|
Station = 1,
|
||||||
|
/// The device is a local hotspot/access point.
|
||||||
|
AccessPoint = 2,
|
||||||
|
/// The device is an 802.11s mesh point.
|
||||||
|
Mesh = 3,
|
||||||
|
/// The device mode is unknown.
|
||||||
|
Unknown = 4,
|
||||||
|
};
|
||||||
|
Q_ENUM(Enum);
|
||||||
|
Q_INVOKABLE static QString toString(WifiDeviceMode::Enum mode);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace qs::network
|
||||||
|
|
@ -4,6 +4,8 @@ headers = [
|
||||||
"network.hpp",
|
"network.hpp",
|
||||||
"device.hpp",
|
"device.hpp",
|
||||||
"wifi.hpp",
|
"wifi.hpp",
|
||||||
|
"enums.hpp",
|
||||||
|
"nm/settings.hpp",
|
||||||
]
|
]
|
||||||
-----
|
-----
|
||||||
This module exposes Network management APIs provided by a supported network backend.
|
This module exposes Network management APIs provided by a supported network backend.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "network.hpp"
|
#include "network.hpp"
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include <qdebug.h>
|
||||||
#include <qlogging.h>
|
#include <qlogging.h>
|
||||||
#include <qloggingcategory.h>
|
#include <qloggingcategory.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
|
|
@ -9,7 +10,9 @@
|
||||||
|
|
||||||
#include "../core/logcat.hpp"
|
#include "../core/logcat.hpp"
|
||||||
#include "device.hpp"
|
#include "device.hpp"
|
||||||
|
#include "enums.hpp"
|
||||||
#include "nm/backend.hpp"
|
#include "nm/backend.hpp"
|
||||||
|
#include "nm/settings.hpp"
|
||||||
|
|
||||||
namespace qs::network {
|
namespace qs::network {
|
||||||
|
|
||||||
|
|
@ -17,25 +20,22 @@ namespace {
|
||||||
QS_LOGGING_CATEGORY(logNetwork, "quickshell.network", QtWarningMsg);
|
QS_LOGGING_CATEGORY(logNetwork, "quickshell.network", QtWarningMsg);
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
QString NetworkState::toString(NetworkState::Enum state) {
|
|
||||||
switch (state) {
|
|
||||||
case NetworkState::Connecting: return QStringLiteral("Connecting");
|
|
||||||
case NetworkState::Connected: return QStringLiteral("Connected");
|
|
||||||
case NetworkState::Disconnecting: return QStringLiteral("Disconnecting");
|
|
||||||
case NetworkState::Disconnected: return QStringLiteral("Disconnected");
|
|
||||||
default: return QStringLiteral("Unknown");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Networking::Networking(QObject* parent): QObject(parent) {
|
Networking::Networking(QObject* parent): QObject(parent) {
|
||||||
// Try to create the NetworkManager backend and bind to it.
|
// Try to create the NetworkManager backend and bind to it.
|
||||||
auto* nm = new NetworkManager(this);
|
auto* nm = new NetworkManager(this);
|
||||||
if (nm->isAvailable()) {
|
if (nm->isAvailable()) {
|
||||||
|
// clang-format off
|
||||||
QObject::connect(nm, &NetworkManager::deviceAdded, this, &Networking::deviceAdded);
|
QObject::connect(nm, &NetworkManager::deviceAdded, this, &Networking::deviceAdded);
|
||||||
QObject::connect(nm, &NetworkManager::deviceRemoved, this, &Networking::deviceRemoved);
|
QObject::connect(nm, &NetworkManager::deviceRemoved, this, &Networking::deviceRemoved);
|
||||||
QObject::connect(this, &Networking::requestSetWifiEnabled, nm, &NetworkManager::setWifiEnabled);
|
QObject::connect(this, &Networking::requestSetWifiEnabled, nm, &NetworkManager::setWifiEnabled);
|
||||||
|
QObject::connect(this, &Networking::requestSetConnectivityCheckEnabled, nm, &NetworkManager::setConnectivityCheckEnabled);
|
||||||
|
QObject::connect(this, &Networking::requestCheckConnectivity, nm, &NetworkManager::checkConnectivity);
|
||||||
this->bindableWifiEnabled().setBinding([nm]() { return nm->wifiEnabled(); });
|
this->bindableWifiEnabled().setBinding([nm]() { return nm->wifiEnabled(); });
|
||||||
this->bindableWifiHardwareEnabled().setBinding([nm]() { return nm->wifiHardwareEnabled(); });
|
this->bindableWifiHardwareEnabled().setBinding([nm]() { return nm->wifiHardwareEnabled(); });
|
||||||
|
this->bindableCanCheckConnectivity().setBinding([nm]() { return nm->connectivityCheckAvailable(); });
|
||||||
|
this->bindableConnectivityCheckEnabled().setBinding([nm]() { return nm->connectivityCheckEnabled(); });
|
||||||
|
this->bindableConnectivity().setBinding([nm]() { return static_cast<NetworkConnectivity::Enum>(nm->connectivity()); });
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
this->mBackend = nm;
|
this->mBackend = nm;
|
||||||
this->mBackendType = NetworkBackendType::NetworkManager;
|
this->mBackendType = NetworkBackendType::NetworkManager;
|
||||||
|
|
@ -43,23 +43,89 @@ Networking::Networking(QObject* parent): QObject(parent) {
|
||||||
} else {
|
} else {
|
||||||
delete nm;
|
delete nm;
|
||||||
}
|
}
|
||||||
|
|
||||||
qCCritical(logNetwork) << "Network will not work. Could not find an available backend.";
|
qCCritical(logNetwork) << "Network will not work. Could not find an available backend.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Networking* Networking::instance() {
|
||||||
|
static Networking* instance = new Networking(); // NOLINT
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
void Networking::deviceAdded(NetworkDevice* dev) { this->mDevices.insertObject(dev); }
|
void Networking::deviceAdded(NetworkDevice* dev) { this->mDevices.insertObject(dev); }
|
||||||
void Networking::deviceRemoved(NetworkDevice* dev) { this->mDevices.removeObject(dev); }
|
void Networking::deviceRemoved(NetworkDevice* dev) { this->mDevices.removeObject(dev); }
|
||||||
|
|
||||||
|
void Networking::checkConnectivity() {
|
||||||
|
if (!this->bConnectivityCheckEnabled || !this->bCanCheckConnectivity) return;
|
||||||
|
emit this->requestCheckConnectivity();
|
||||||
|
}
|
||||||
|
|
||||||
void Networking::setWifiEnabled(bool enabled) {
|
void Networking::setWifiEnabled(bool enabled) {
|
||||||
if (this->bWifiEnabled == enabled) return;
|
if (this->bWifiEnabled == enabled) return;
|
||||||
emit this->requestSetWifiEnabled(enabled);
|
emit this->requestSetWifiEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Networking::setConnectivityCheckEnabled(bool enabled) {
|
||||||
|
if (this->bConnectivityCheckEnabled == enabled) return;
|
||||||
|
emit this->requestSetConnectivityCheckEnabled(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkingQml::NetworkingQml(QObject* parent): QObject(parent) {
|
||||||
|
// clang-format off
|
||||||
|
QObject::connect(Networking::instance(), &Networking::wifiEnabledChanged, this, &NetworkingQml::wifiEnabledChanged);
|
||||||
|
QObject::connect(Networking::instance(), &Networking::wifiHardwareEnabledChanged, this, &NetworkingQml::wifiHardwareEnabledChanged);
|
||||||
|
QObject::connect(Networking::instance(), &Networking::canCheckConnectivityChanged, this, &NetworkingQml::canCheckConnectivityChanged);
|
||||||
|
QObject::connect(Networking::instance(), &Networking::connectivityCheckEnabledChanged, this, &NetworkingQml::connectivityCheckEnabledChanged);
|
||||||
|
QObject::connect(Networking::instance(), &Networking::connectivityChanged, this, &NetworkingQml::connectivityChanged);
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkingQml::checkConnectivity() { Networking::instance()->checkConnectivity(); }
|
||||||
|
|
||||||
Network::Network(QString name, QObject* parent): QObject(parent), mName(std::move(name)) {
|
Network::Network(QString name, QObject* parent): QObject(parent), mName(std::move(name)) {
|
||||||
this->bStateChanging.setBinding([this] {
|
this->bStateChanging.setBinding([this] {
|
||||||
auto state = this->bState.value();
|
auto state = this->bState.value();
|
||||||
return state == NetworkState::Connecting || state == NetworkState::Disconnecting;
|
return state == ConnectionState::Connecting || state == ConnectionState::Disconnecting;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void Network::connect() {
|
||||||
|
if (this->bConnected) {
|
||||||
|
qCCritical(logNetwork) << this << "is already connected.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->requestConnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Network::connectWithSettings(NMSettings* settings) {
|
||||||
|
if (this->bConnected) {
|
||||||
|
qCCritical(logNetwork) << this << "is already connected.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this->bNmSettings.value().indexOf(settings) == -1) return;
|
||||||
|
this->requestConnectWithSettings(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Network::disconnect() {
|
||||||
|
if (!this->bConnected) {
|
||||||
|
qCCritical(logNetwork) << this << "is not currently connected";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->requestDisconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Network::forget() { this->requestForget(); }
|
||||||
|
|
||||||
|
void Network::settingsAdded(NMSettings* settings) {
|
||||||
|
auto list = this->bNmSettings.value();
|
||||||
|
if (list.contains(settings)) return;
|
||||||
|
list.append(settings);
|
||||||
|
this->bNmSettings = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Network::settingsRemoved(NMSettings* settings) {
|
||||||
|
auto list = this->bNmSettings.value();
|
||||||
|
list.removeOne(settings);
|
||||||
|
this->bNmSettings = list;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace qs::network
|
} // namespace qs::network
|
||||||
|
|
|
||||||
|
|
@ -6,43 +6,14 @@
|
||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
#include <qtypes.h>
|
#include <qtypes.h>
|
||||||
|
|
||||||
|
#include "../core/doc.hpp"
|
||||||
#include "../core/model.hpp"
|
#include "../core/model.hpp"
|
||||||
#include "device.hpp"
|
#include "device.hpp"
|
||||||
|
#include "enums.hpp"
|
||||||
|
#include "nm/settings.hpp"
|
||||||
|
|
||||||
namespace qs::network {
|
namespace qs::network {
|
||||||
|
|
||||||
///! The connection state of a Network.
|
|
||||||
class NetworkState: public QObject {
|
|
||||||
Q_OBJECT;
|
|
||||||
QML_ELEMENT;
|
|
||||||
QML_SINGLETON;
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum Enum : quint8 {
|
|
||||||
Unknown = 0,
|
|
||||||
Connecting = 1,
|
|
||||||
Connected = 2,
|
|
||||||
Disconnecting = 3,
|
|
||||||
Disconnected = 4,
|
|
||||||
};
|
|
||||||
Q_ENUM(Enum);
|
|
||||||
Q_INVOKABLE static QString toString(NetworkState::Enum state);
|
|
||||||
};
|
|
||||||
|
|
||||||
///! The backend supplying the Network service.
|
|
||||||
class NetworkBackendType: public QObject {
|
|
||||||
Q_OBJECT;
|
|
||||||
QML_ELEMENT;
|
|
||||||
QML_SINGLETON;
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum Enum : quint8 {
|
|
||||||
None = 0,
|
|
||||||
NetworkManager = 1,
|
|
||||||
};
|
|
||||||
Q_ENUM(Enum);
|
|
||||||
};
|
|
||||||
|
|
||||||
class NetworkBackend: public QObject {
|
class NetworkBackend: public QObject {
|
||||||
Q_OBJECT;
|
Q_OBJECT;
|
||||||
|
|
||||||
|
|
@ -53,15 +24,65 @@ protected:
|
||||||
explicit NetworkBackend(QObject* parent = nullptr): QObject(parent) {};
|
explicit NetworkBackend(QObject* parent = nullptr): QObject(parent) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Networking: public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static Networking* instance();
|
||||||
|
|
||||||
|
void checkConnectivity();
|
||||||
|
|
||||||
|
[[nodiscard]] ObjectModel<NetworkDevice>* devices() { return &this->mDevices; }
|
||||||
|
[[nodiscard]] NetworkBackendType::Enum backend() const { return this->mBackendType; }
|
||||||
|
QBindable<bool> bindableWifiEnabled() { return &this->bWifiEnabled; }
|
||||||
|
[[nodiscard]] bool wifiEnabled() const { return this->bWifiEnabled; }
|
||||||
|
void setWifiEnabled(bool enabled);
|
||||||
|
QBindable<bool> bindableWifiHardwareEnabled() { return &this->bWifiHardwareEnabled; }
|
||||||
|
QBindable<bool> bindableCanCheckConnectivity() { return &this->bCanCheckConnectivity; }
|
||||||
|
QBindable<bool> bindableConnectivityCheckEnabled() { return &this->bConnectivityCheckEnabled; }
|
||||||
|
[[nodiscard]] bool connectivityCheckEnabled() const { return this->bConnectivityCheckEnabled; }
|
||||||
|
void setConnectivityCheckEnabled(bool enabled);
|
||||||
|
QBindable<NetworkConnectivity::Enum> bindableConnectivity() { return &this->bConnectivity; }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void requestSetWifiEnabled(bool enabled);
|
||||||
|
void requestSetConnectivityCheckEnabled(bool enabled);
|
||||||
|
void requestCheckConnectivity();
|
||||||
|
|
||||||
|
void wifiEnabledChanged();
|
||||||
|
void wifiHardwareEnabledChanged();
|
||||||
|
void canCheckConnectivityChanged();
|
||||||
|
void connectivityCheckEnabledChanged();
|
||||||
|
void connectivityChanged();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void deviceAdded(NetworkDevice* dev);
|
||||||
|
void deviceRemoved(NetworkDevice* dev);
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit Networking(QObject* parent = nullptr);
|
||||||
|
|
||||||
|
ObjectModel<NetworkDevice> mDevices {this};
|
||||||
|
NetworkBackend* mBackend = nullptr;
|
||||||
|
NetworkBackendType::Enum mBackendType = NetworkBackendType::None;
|
||||||
|
// clang-format off
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(Networking, bool, bWifiEnabled, &Networking::wifiEnabledChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(Networking, bool, bWifiHardwareEnabled, &Networking::wifiHardwareEnabledChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(Networking, bool, bCanCheckConnectivity, &Networking::canCheckConnectivityChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(Networking, bool, bConnectivityCheckEnabled, &Networking::connectivityCheckEnabledChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(Networking, NetworkConnectivity::Enum, bConnectivity, &Networking::connectivityChanged);
|
||||||
|
// clang-format on
|
||||||
|
};
|
||||||
|
|
||||||
///! The Network service.
|
///! The Network service.
|
||||||
/// An interface to a network backend (currently only NetworkManager),
|
/// An interface to a network backend (currently only NetworkManager),
|
||||||
/// which can be used to view, configure, and connect to various networks.
|
/// which can be used to view, configure, and connect to various networks.
|
||||||
class Networking: public QObject {
|
class NetworkingQml: public QObject {
|
||||||
Q_OBJECT;
|
Q_OBJECT;
|
||||||
|
QML_NAMED_ELEMENT(Networking);
|
||||||
QML_SINGLETON;
|
QML_SINGLETON;
|
||||||
QML_ELEMENT;
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
/// A list of all network devices.
|
/// A list of all network devices. Networks are exposed through their respective devices.
|
||||||
QSDOC_TYPE_OVERRIDE(ObjectModel<qs::network::NetworkDevice>*);
|
QSDOC_TYPE_OVERRIDE(ObjectModel<qs::network::NetworkDevice>*);
|
||||||
Q_PROPERTY(UntypedObjectModel* devices READ devices CONSTANT);
|
Q_PROPERTY(UntypedObjectModel* devices READ devices CONSTANT);
|
||||||
/// The backend being used to power the Network service.
|
/// The backend being used to power the Network service.
|
||||||
|
|
@ -70,73 +91,143 @@ class Networking: public QObject {
|
||||||
Q_PROPERTY(bool wifiEnabled READ wifiEnabled WRITE setWifiEnabled NOTIFY wifiEnabledChanged);
|
Q_PROPERTY(bool wifiEnabled READ wifiEnabled WRITE setWifiEnabled NOTIFY wifiEnabledChanged);
|
||||||
/// State of the rfkill hardware block of all wireless devices.
|
/// State of the rfkill hardware block of all wireless devices.
|
||||||
Q_PROPERTY(bool wifiHardwareEnabled READ default NOTIFY wifiHardwareEnabledChanged BINDABLE bindableWifiHardwareEnabled);
|
Q_PROPERTY(bool wifiHardwareEnabled READ default NOTIFY wifiHardwareEnabledChanged BINDABLE bindableWifiHardwareEnabled);
|
||||||
|
/// True if the @@backend supports connectivity checks.
|
||||||
|
Q_PROPERTY(bool canCheckConnectivity READ default NOTIFY canCheckConnectivityChanged BINDABLE bindableCanCheckConnectivity);
|
||||||
|
/// True if connectivity checking is enabled.
|
||||||
|
Q_PROPERTY(bool connectivityCheckEnabled READ connectivityCheckEnabled WRITE setConnectivityCheckEnabled NOTIFY connectivityCheckEnabledChanged);
|
||||||
|
/// The result of the last connectivity check.
|
||||||
|
///
|
||||||
|
/// Connectivity checks may require additional configuration depending on your distro.
|
||||||
|
///
|
||||||
|
/// > [!NOTE] This property can be used to determine if network access is restricted
|
||||||
|
/// > or gated behind a captive portal.
|
||||||
|
/// >
|
||||||
|
/// > If checking for captive portals, @@checkConnectivity() should be called after
|
||||||
|
/// > the portal is dismissed to update this property.
|
||||||
|
Q_PROPERTY(qs::network::NetworkConnectivity::Enum connectivity READ default NOTIFY connectivityChanged BINDABLE bindableConnectivity);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Networking(QObject* parent = nullptr);
|
explicit NetworkingQml(QObject* parent = nullptr);
|
||||||
|
|
||||||
[[nodiscard]] ObjectModel<NetworkDevice>* devices() { return &this->mDevices; };
|
/// Re-check the network connectivity state immediately.
|
||||||
[[nodiscard]] NetworkBackendType::Enum backend() const { return this->mBackendType; };
|
/// > [!NOTE] This should be invoked after a user dismisses a web browser that was opened to authenticate via a captive portal.
|
||||||
QBindable<bool> bindableWifiEnabled() { return &this->bWifiEnabled; };
|
Q_INVOKABLE static void checkConnectivity();
|
||||||
[[nodiscard]] bool wifiEnabled() const { return this->bWifiEnabled; };
|
|
||||||
void setWifiEnabled(bool enabled);
|
[[nodiscard]] static ObjectModel<NetworkDevice>* devices() {
|
||||||
QBindable<bool> bindableWifiHardwareEnabled() { return &this->bWifiHardwareEnabled; };
|
return Networking::instance()->devices();
|
||||||
|
}
|
||||||
|
[[nodiscard]] static NetworkBackendType::Enum backend() {
|
||||||
|
return Networking::instance()->backend();
|
||||||
|
}
|
||||||
|
[[nodiscard]] static bool wifiEnabled() { return Networking::instance()->wifiEnabled(); }
|
||||||
|
static void setWifiEnabled(bool enabled) { Networking::instance()->setWifiEnabled(enabled); }
|
||||||
|
[[nodiscard]] static QBindable<bool> bindableWifiHardwareEnabled() {
|
||||||
|
return Networking::instance()->bindableWifiHardwareEnabled();
|
||||||
|
}
|
||||||
|
[[nodiscard]] static QBindable<bool> bindableWifiEnabled() {
|
||||||
|
return Networking::instance()->bindableWifiEnabled();
|
||||||
|
}
|
||||||
|
[[nodiscard]] static QBindable<bool> bindableCanCheckConnectivity() {
|
||||||
|
return Networking::instance()->bindableCanCheckConnectivity();
|
||||||
|
}
|
||||||
|
[[nodiscard]] static bool connectivityCheckEnabled() {
|
||||||
|
return Networking::instance()->connectivityCheckEnabled();
|
||||||
|
}
|
||||||
|
static void setConnectivityCheckEnabled(bool enabled) {
|
||||||
|
Networking::instance()->setConnectivityCheckEnabled(enabled);
|
||||||
|
}
|
||||||
|
[[nodiscard]] static QBindable<NetworkConnectivity::Enum> bindableConnectivity() {
|
||||||
|
return Networking::instance()->bindableConnectivity();
|
||||||
|
}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void requestSetWifiEnabled(bool enabled);
|
|
||||||
void wifiEnabledChanged();
|
void wifiEnabledChanged();
|
||||||
void wifiHardwareEnabledChanged();
|
void wifiHardwareEnabledChanged();
|
||||||
|
void canCheckConnectivityChanged();
|
||||||
private slots:
|
void connectivityCheckEnabledChanged();
|
||||||
void deviceAdded(NetworkDevice* dev);
|
void connectivityChanged();
|
||||||
void deviceRemoved(NetworkDevice* dev);
|
|
||||||
|
|
||||||
private:
|
|
||||||
ObjectModel<NetworkDevice> mDevices {this};
|
|
||||||
NetworkBackend* mBackend = nullptr;
|
|
||||||
NetworkBackendType::Enum mBackendType = NetworkBackendType::None;
|
|
||||||
// clang-format off
|
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(Networking, bool, bWifiEnabled, &Networking::wifiEnabledChanged);
|
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(Networking, bool, bWifiHardwareEnabled, &Networking::wifiHardwareEnabledChanged);
|
|
||||||
// clang-format on
|
|
||||||
};
|
};
|
||||||
|
|
||||||
///! A network.
|
///! A network.
|
||||||
|
/// A network. Networks derived from a @@WifiDevice are @@WifiNetwork instances.
|
||||||
class Network: public QObject {
|
class Network: public QObject {
|
||||||
Q_OBJECT;
|
Q_OBJECT;
|
||||||
QML_ELEMENT;
|
QML_ELEMENT;
|
||||||
QML_UNCREATABLE("BaseNetwork can only be aqcuired through network devices");
|
QML_UNCREATABLE("Network can only be aqcuired through networking devices");
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
/// The name of the network.
|
/// The name of the network.
|
||||||
Q_PROPERTY(QString name READ name CONSTANT);
|
Q_PROPERTY(QString name READ name CONSTANT);
|
||||||
|
/// A list of NetworkManager connnection settings profiles for this network.
|
||||||
|
///
|
||||||
|
/// > [!WARNING] Only valid for the NetworkManager backend.
|
||||||
|
Q_PROPERTY(QList<NMSettings*> nmSettings READ nmSettings NOTIFY nmSettingsChanged BINDABLE bindableNmSettings);
|
||||||
/// True if the network is connected.
|
/// True if the network is connected.
|
||||||
Q_PROPERTY(bool connected READ default NOTIFY connectedChanged BINDABLE bindableConnected);
|
Q_PROPERTY(bool connected READ default NOTIFY connectedChanged BINDABLE bindableConnected);
|
||||||
|
/// True if the wifi network has known connection settings saved.
|
||||||
|
Q_PROPERTY(bool known READ default NOTIFY knownChanged BINDABLE bindableKnown);
|
||||||
/// The connectivity state of the network.
|
/// The connectivity state of the network.
|
||||||
Q_PROPERTY(NetworkState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState);
|
Q_PROPERTY(ConnectionState::Enum state READ default NOTIFY stateChanged BINDABLE bindableState);
|
||||||
/// If the network is currently connecting or disconnecting. Shorthand for checking @@state.
|
/// If the network is currently connecting or disconnecting. Shorthand for checking @@state.
|
||||||
Q_PROPERTY(bool stateChanging READ default NOTIFY stateChangingChanged BINDABLE bindableStateChanging);
|
Q_PROPERTY(bool stateChanging READ default NOTIFY stateChangingChanged BINDABLE bindableStateChanging);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Network(QString name, QObject* parent = nullptr);
|
explicit Network(QString name, QObject* parent = nullptr);
|
||||||
|
/// Attempt to connect to the network.
|
||||||
|
///
|
||||||
|
/// > [!NOTE] If the network is a @@WifiNetwork and requires secrets, a @@connectionFailed(s)
|
||||||
|
/// > signal will be emitted with `NoSecrets`.
|
||||||
|
/// > @@WifiNetwork.connectWithPsk() can be used to provide secrets.
|
||||||
|
Q_INVOKABLE void connect();
|
||||||
|
/// Attempt to connect to the network with a specific @@nmSettings entry.
|
||||||
|
///
|
||||||
|
/// > [!WARNING] Only valid for the NetworkManager backend.
|
||||||
|
Q_INVOKABLE void connectWithSettings(NMSettings* settings);
|
||||||
|
/// Disconnect from the network.
|
||||||
|
Q_INVOKABLE void disconnect();
|
||||||
|
/// Forget all connection settings for this network.
|
||||||
|
Q_INVOKABLE void forget();
|
||||||
|
|
||||||
[[nodiscard]] QString name() const { return this->mName; };
|
void settingsAdded(NMSettings* settings);
|
||||||
|
void settingsRemoved(NMSettings* settings);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
[[nodiscard]] QString name() const { return this->mName; }
|
||||||
|
[[nodiscard]] const QList<NMSettings*>& nmSettings() const { return this->bNmSettings; }
|
||||||
|
QBindable<QList<NMSettings*>> bindableNmSettings() const { return &this->bNmSettings; }
|
||||||
QBindable<bool> bindableConnected() { return &this->bConnected; }
|
QBindable<bool> bindableConnected() { return &this->bConnected; }
|
||||||
QBindable<NetworkState::Enum> bindableState() { return &this->bState; }
|
QBindable<bool> bindableKnown() { return &this->bKnown; }
|
||||||
|
[[nodiscard]] ConnectionState::Enum state() const { return this->bState; }
|
||||||
|
QBindable<ConnectionState::Enum> bindableState() { return &this->bState; }
|
||||||
QBindable<bool> bindableStateChanging() { return &this->bStateChanging; }
|
QBindable<bool> bindableStateChanging() { return &this->bStateChanging; }
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
/// Signals that a connection to the network has failed because of the given @@ConnectionFailReason.
|
||||||
|
void connectionFailed(ConnectionFailReason::Enum reason);
|
||||||
|
|
||||||
void connectedChanged();
|
void connectedChanged();
|
||||||
|
void knownChanged();
|
||||||
void stateChanged();
|
void stateChanged();
|
||||||
void stateChangingChanged();
|
void stateChangingChanged();
|
||||||
|
void nmSettingsChanged();
|
||||||
|
QSDOC_HIDE void requestConnect();
|
||||||
|
QSDOC_HIDE void requestConnectWithSettings(NMSettings* settings);
|
||||||
|
QSDOC_HIDE void requestDisconnect();
|
||||||
|
QSDOC_HIDE void requestForget();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QString mName;
|
QString mName;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(Network, bool, bConnected, &Network::connectedChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(Network, bool, bConnected, &Network::connectedChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(Network, NetworkState::Enum, bState, &Network::stateChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(Network, bool, bKnown, &Network::knownChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(Network, ConnectionState::Enum, bState, &Network::stateChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(Network, bool, bStateChanging, &Network::stateChangingChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(Network, bool, bStateChanging, &Network::stateChangingChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(Network, QList<NMSettings*>, bNmSettings, &Network::nmSettingsChanged);
|
||||||
|
// clang-format on
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace qs::network
|
} // namespace qs::network
|
||||||
|
|
|
||||||
|
|
@ -63,10 +63,12 @@ qt_add_dbus_interface(NM_DBUS_INTERFACES
|
||||||
qt_add_library(quickshell-network-nm STATIC
|
qt_add_library(quickshell-network-nm STATIC
|
||||||
backend.cpp
|
backend.cpp
|
||||||
device.cpp
|
device.cpp
|
||||||
connection.cpp
|
active_connection.cpp
|
||||||
|
settings.cpp
|
||||||
accesspoint.cpp
|
accesspoint.cpp
|
||||||
wireless.cpp
|
wireless.cpp
|
||||||
utils.cpp
|
utils.cpp
|
||||||
|
dbus_types.cpp
|
||||||
enums.hpp
|
enums.hpp
|
||||||
${NM_DBUS_INTERFACES}
|
${NM_DBUS_INTERFACES}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -48,14 +48,14 @@ public:
|
||||||
[[nodiscard]] bool isValid() const;
|
[[nodiscard]] bool isValid() const;
|
||||||
[[nodiscard]] QString path() const;
|
[[nodiscard]] QString path() const;
|
||||||
[[nodiscard]] QString address() const;
|
[[nodiscard]] QString address() const;
|
||||||
[[nodiscard]] QByteArray ssid() const { return this->bSsid; };
|
[[nodiscard]] QByteArray ssid() const { return this->bSsid; }
|
||||||
[[nodiscard]] quint8 signalStrength() const { return this->bSignalStrength; };
|
[[nodiscard]] quint8 signalStrength() const { return this->bSignalStrength; }
|
||||||
[[nodiscard]] NM80211ApFlags::Enum flags() const { return this->bFlags; };
|
[[nodiscard]] NM80211ApFlags::Enum flags() const { return this->bFlags; }
|
||||||
[[nodiscard]] NM80211ApSecurityFlags::Enum wpaFlags() const { return this->bWpaFlags; };
|
[[nodiscard]] NM80211ApSecurityFlags::Enum wpaFlags() const { return this->bWpaFlags; }
|
||||||
[[nodiscard]] NM80211ApSecurityFlags::Enum rsnFlags() const { return this->bRsnFlags; };
|
[[nodiscard]] NM80211ApSecurityFlags::Enum rsnFlags() const { return this->bRsnFlags; }
|
||||||
[[nodiscard]] NM80211Mode::Enum mode() const { return this->bMode; };
|
[[nodiscard]] NM80211Mode::Enum mode() const { return this->bMode; }
|
||||||
[[nodiscard]] QBindable<WifiSecurityType::Enum> bindableSecurity() { return &this->bSecurity; };
|
[[nodiscard]] QBindable<WifiSecurityType::Enum> bindableSecurity() { return &this->bSecurity; }
|
||||||
[[nodiscard]] WifiSecurityType::Enum security() const { return this->bSecurity; };
|
[[nodiscard]] WifiSecurityType::Enum security() const { return this->bSecurity; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void loaded();
|
void loaded();
|
||||||
|
|
|
||||||
68
src/network/nm/active_connection.cpp
Normal file
68
src/network/nm/active_connection.cpp
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
#include "active_connection.hpp"
|
||||||
|
|
||||||
|
#include <qcontainerfwd.h>
|
||||||
|
#include <qdbusconnection.h>
|
||||||
|
#include <qdbuspendingcall.h>
|
||||||
|
#include <qlogging.h>
|
||||||
|
#include <qloggingcategory.h>
|
||||||
|
#include <qnamespace.h>
|
||||||
|
#include <qobject.h>
|
||||||
|
#include <qstring.h>
|
||||||
|
#include <qtypes.h>
|
||||||
|
|
||||||
|
#include "../../core/logcat.hpp"
|
||||||
|
#include "../../dbus/properties.hpp"
|
||||||
|
#include "dbus_nm_active_connection.h"
|
||||||
|
#include "enums.hpp"
|
||||||
|
|
||||||
|
namespace qs::network {
|
||||||
|
using namespace qs::dbus;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
QS_LOGGING_CATEGORY(logNetworkManager, "quickshell.network.networkmanager", QtWarningMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
NMActiveConnection::NMActiveConnection(const QString& path, QObject* parent): QObject(parent) {
|
||||||
|
this->proxy = new DBusNMActiveConnectionProxy(
|
||||||
|
"org.freedesktop.NetworkManager",
|
||||||
|
path,
|
||||||
|
QDBusConnection::systemBus(),
|
||||||
|
this
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!this->proxy->isValid()) {
|
||||||
|
qCWarning(logNetworkManager) << "Cannot create DBus interface for connection at" << path;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
QObject::connect(&this->activeConnectionProperties, &DBusPropertyGroup::getAllFinished, this, &NMActiveConnection::loaded, Qt::SingleShotConnection);
|
||||||
|
QObject::connect(this->proxy, &DBusNMActiveConnectionProxy::StateChanged, this, &NMActiveConnection::onStateChanged);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
this->activeConnectionProperties.setInterface(this->proxy);
|
||||||
|
this->activeConnectionProperties.updateAllViaGetAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NMActiveConnection::onStateChanged(quint32 /*state*/, quint32 reason) {
|
||||||
|
auto enumReason = static_cast<NMConnectionStateReason::Enum>(reason);
|
||||||
|
if (this->bStateReason == enumReason) return;
|
||||||
|
this->bStateReason = enumReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NMActiveConnection::isValid() const { return this->proxy && this->proxy->isValid(); }
|
||||||
|
QString NMActiveConnection::address() const {
|
||||||
|
return this->proxy ? this->proxy->service() : QString();
|
||||||
|
}
|
||||||
|
QString NMActiveConnection::path() const { return this->proxy ? this->proxy->path() : QString(); }
|
||||||
|
|
||||||
|
} // namespace qs::network
|
||||||
|
|
||||||
|
namespace qs::dbus {
|
||||||
|
|
||||||
|
DBusResult<qs::network::NMConnectionState::Enum>
|
||||||
|
DBusDataTransform<qs::network::NMConnectionState::Enum>::fromWire(quint32 wire) {
|
||||||
|
return DBusResult(static_cast<qs::network::NMConnectionState::Enum>(wire));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace qs::dbus
|
||||||
|
|
@ -1,18 +1,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <qbytearray.h>
|
||||||
#include <qdbusextratypes.h>
|
#include <qdbusextratypes.h>
|
||||||
#include <qdbuspendingcall.h>
|
#include <qdbuspendingcall.h>
|
||||||
#include <qdbuspendingreply.h>
|
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qproperty.h>
|
#include <qproperty.h>
|
||||||
#include <qtmetamacros.h>
|
#include <qqmlintegration.h>
|
||||||
|
#include <qstringlist.h>
|
||||||
#include <qtypes.h>
|
#include <qtypes.h>
|
||||||
|
|
||||||
#include "../../dbus/properties.hpp"
|
#include "../../dbus/properties.hpp"
|
||||||
#include "../wifi.hpp"
|
|
||||||
#include "dbus_nm_active_connection.h"
|
#include "dbus_nm_active_connection.h"
|
||||||
#include "dbus_nm_connection_settings.h"
|
|
||||||
#include "dbus_types.hpp"
|
|
||||||
#include "enums.hpp"
|
#include "enums.hpp"
|
||||||
|
|
||||||
namespace qs::dbus {
|
namespace qs::dbus {
|
||||||
|
|
@ -28,40 +26,6 @@ struct DBusDataTransform<qs::network::NMConnectionState::Enum> {
|
||||||
|
|
||||||
namespace qs::network {
|
namespace qs::network {
|
||||||
|
|
||||||
// Proxy of a /org/freedesktop/NetworkManager/Settings/Connection/* object.
|
|
||||||
class NMConnectionSettings: public QObject {
|
|
||||||
Q_OBJECT;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit NMConnectionSettings(const QString& path, QObject* parent = nullptr);
|
|
||||||
|
|
||||||
void forget();
|
|
||||||
|
|
||||||
[[nodiscard]] bool isValid() const;
|
|
||||||
[[nodiscard]] QString path() const;
|
|
||||||
[[nodiscard]] QString address() const;
|
|
||||||
[[nodiscard]] ConnectionSettingsMap settings() const { return this->bSettings; };
|
|
||||||
[[nodiscard]] WifiSecurityType::Enum security() const { return this->bSecurity; };
|
|
||||||
[[nodiscard]] QBindable<WifiSecurityType::Enum> bindableSecurity() { return &this->bSecurity; };
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void loaded();
|
|
||||||
void settingsChanged(ConnectionSettingsMap settings);
|
|
||||||
void securityChanged(WifiSecurityType::Enum security);
|
|
||||||
void ssidChanged(QString ssid);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool mLoaded = false;
|
|
||||||
void updateSettings();
|
|
||||||
// clang-format off
|
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NMConnectionSettings, ConnectionSettingsMap, bSettings, &NMConnectionSettings::settingsChanged);
|
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NMConnectionSettings, WifiSecurityType::Enum, bSecurity, &NMConnectionSettings::securityChanged);
|
|
||||||
QS_DBUS_BINDABLE_PROPERTY_GROUP(NMConnectionSettings, connectionSettingsProperties);
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
DBusNMConnectionSettingsProxy* proxy = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Proxy of a /org/freedesktop/NetworkManager/ActiveConnection/* object.
|
// Proxy of a /org/freedesktop/NetworkManager/ActiveConnection/* object.
|
||||||
class NMActiveConnection: public QObject {
|
class NMActiveConnection: public QObject {
|
||||||
Q_OBJECT;
|
Q_OBJECT;
|
||||||
|
|
@ -72,31 +36,27 @@ public:
|
||||||
[[nodiscard]] bool isValid() const;
|
[[nodiscard]] bool isValid() const;
|
||||||
[[nodiscard]] QString path() const;
|
[[nodiscard]] QString path() const;
|
||||||
[[nodiscard]] QString address() const;
|
[[nodiscard]] QString address() const;
|
||||||
[[nodiscard]] QDBusObjectPath connection() const { return this->bConnection; };
|
[[nodiscard]] QDBusObjectPath connection() const { return this->bConnection; }
|
||||||
[[nodiscard]] NMConnectionState::Enum state() const { return this->bState; };
|
[[nodiscard]] NMConnectionState::Enum state() const { return this->bState; }
|
||||||
[[nodiscard]] NMConnectionStateReason::Enum stateReason() const { return this->mStateReason; };
|
[[nodiscard]] NMConnectionStateReason::Enum stateReason() const { return this->bStateReason; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void loaded();
|
void loaded();
|
||||||
void connectionChanged(QDBusObjectPath path);
|
void connectionChanged(QDBusObjectPath path);
|
||||||
void stateChanged(NMConnectionState::Enum state);
|
void stateChanged(NMConnectionState::Enum state);
|
||||||
void stateReasonChanged(NMConnectionStateReason::Enum reason);
|
void stateReasonChanged(NMConnectionStateReason::Enum reason);
|
||||||
void uuidChanged(const QString& uuid);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onStateChanged(quint32 state, quint32 reason);
|
void onStateChanged(quint32 state, quint32 reason);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NMConnectionStateReason::Enum mStateReason = NMConnectionStateReason::Unknown;
|
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NMActiveConnection, QDBusObjectPath, bConnection, &NMActiveConnection::connectionChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NMActiveConnection, QDBusObjectPath, bConnection, &NMActiveConnection::connectionChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NMActiveConnection, QString, bUuid, &NMActiveConnection::uuidChanged);
|
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NMActiveConnection, NMConnectionState::Enum, bState, &NMActiveConnection::stateChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NMActiveConnection, NMConnectionState::Enum, bState, &NMActiveConnection::stateChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(NMActiveConnection, NMConnectionStateReason::Enum, bStateReason, &NMActiveConnection::stateReasonChanged);
|
||||||
|
|
||||||
QS_DBUS_BINDABLE_PROPERTY_GROUP(NMActiveConnection, activeConnectionProperties);
|
QS_DBUS_BINDABLE_PROPERTY_GROUP(NMActiveConnection, activeConnectionProperties);
|
||||||
QS_DBUS_PROPERTY_BINDING(NMActiveConnection, pConnection, bConnection, activeConnectionProperties, "Connection");
|
QS_DBUS_PROPERTY_BINDING(NMActiveConnection, pConnection, bConnection, activeConnectionProperties, "Connection");
|
||||||
QS_DBUS_PROPERTY_BINDING(NMActiveConnection, pUuid, bUuid, activeConnectionProperties, "Uuid");
|
|
||||||
QS_DBUS_PROPERTY_BINDING(NMActiveConnection, pState, bState, activeConnectionProperties, "State");
|
QS_DBUS_PROPERTY_BINDING(NMActiveConnection, pState, bState, activeConnectionProperties, "State");
|
||||||
// clang-format on
|
// clang-format on
|
||||||
DBusNMActiveConnectionProxy* proxy = nullptr;
|
DBusNMActiveConnectionProxy* proxy = nullptr;
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#include "backend.hpp"
|
#include "backend.hpp"
|
||||||
|
|
||||||
|
#include <qbytearray.h>
|
||||||
#include <qdbusconnection.h>
|
#include <qdbusconnection.h>
|
||||||
#include <qdbusextratypes.h>
|
#include <qdbusextratypes.h>
|
||||||
#include <qdbusmetatype.h>
|
#include <qdbusmetatype.h>
|
||||||
|
|
@ -15,6 +16,7 @@
|
||||||
#include "../../core/logcat.hpp"
|
#include "../../core/logcat.hpp"
|
||||||
#include "../../dbus/properties.hpp"
|
#include "../../dbus/properties.hpp"
|
||||||
#include "../device.hpp"
|
#include "../device.hpp"
|
||||||
|
#include "../enums.hpp"
|
||||||
#include "../network.hpp"
|
#include "../network.hpp"
|
||||||
#include "../wifi.hpp"
|
#include "../wifi.hpp"
|
||||||
#include "dbus_nm_backend.h"
|
#include "dbus_nm_backend.h"
|
||||||
|
|
@ -31,7 +33,8 @@ QS_LOGGING_CATEGORY(logNetworkManager, "quickshell.network.networkmanager", QtWa
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkManager::NetworkManager(QObject* parent): NetworkBackend(parent) {
|
NetworkManager::NetworkManager(QObject* parent): NetworkBackend(parent) {
|
||||||
qDBusRegisterMetaType<ConnectionSettingsMap>();
|
qCDebug(logNetworkManager) << "Connecting to NetworkManager";
|
||||||
|
qDBusRegisterMetaType<NMSettingsMap>();
|
||||||
|
|
||||||
auto bus = QDBusConnection::systemBus();
|
auto bus = QDBusConnection::systemBus();
|
||||||
if (!bus.isConnected()) {
|
if (!bus.isConnected()) {
|
||||||
|
|
@ -69,6 +72,23 @@ void NetworkManager::init() {
|
||||||
this->registerDevices();
|
this->registerDevices();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkManager::checkConnectivity() {
|
||||||
|
auto pending = this->proxy->CheckConnectivity();
|
||||||
|
auto* call = new QDBusPendingCallWatcher(pending, this);
|
||||||
|
|
||||||
|
auto responseCallback = [](QDBusPendingCallWatcher* call) {
|
||||||
|
const QDBusPendingReply<quint32> reply = *call;
|
||||||
|
|
||||||
|
if (reply.isError()) {
|
||||||
|
qCInfo(logNetworkManager) << "Failed to check connectivity: " << reply.error().message();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete call;
|
||||||
|
};
|
||||||
|
|
||||||
|
QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback);
|
||||||
|
}
|
||||||
|
|
||||||
void NetworkManager::registerDevices() {
|
void NetworkManager::registerDevices() {
|
||||||
auto pending = this->proxy->GetAllDevices();
|
auto pending = this->proxy->GetAllDevices();
|
||||||
auto* call = new QDBusPendingCallWatcher(pending, this);
|
auto* call = new QDBusPendingCallWatcher(pending, this);
|
||||||
|
|
@ -117,23 +137,21 @@ void NetworkManager::registerDevice(const QString& path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev) {
|
if (dev) {
|
||||||
|
qCDebug(logNetworkManager) << "Device added:" << path;
|
||||||
if (!dev->isValid()) {
|
if (!dev->isValid()) {
|
||||||
qCWarning(logNetworkManager) << "Ignoring invalid registration of" << path;
|
qCWarning(logNetworkManager) << "Ignoring invalid registration of" << path;
|
||||||
delete dev;
|
delete dev;
|
||||||
} else {
|
} else {
|
||||||
this->mDevices[path] = dev;
|
this->mDevices[path] = dev;
|
||||||
// Only register a frontend device while it's managed by NM.
|
|
||||||
auto onManagedChanged = [this, dev, type](bool managed) {
|
|
||||||
managed ? this->registerFrontendDevice(type, dev) : this->removeFrontendDevice(dev);
|
|
||||||
};
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
QObject::connect(dev, &NMDevice::addAndActivateConnection, this, &NetworkManager::addAndActivateConnection);
|
QObject::connect(dev, &NMDevice::addAndActivateConnection, this, &NetworkManager::addAndActivateConnection);
|
||||||
QObject::connect(dev, &NMDevice::activateConnection, this, &NetworkManager::activateConnection);
|
QObject::connect(dev, &NMDevice::activateConnection, this, &NetworkManager::activateConnection);
|
||||||
QObject::connect(dev, &NMDevice::managedChanged, this, onManagedChanged);
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
if (dev->managed()) this->registerFrontendDevice(type, dev);
|
this->registerFrontendDevice(type, dev);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
qCDebug(logNetworkManager) << "Ignoring registration of unsupported device:" << path;
|
||||||
}
|
}
|
||||||
temp->deleteLater();
|
temp->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
@ -173,21 +191,22 @@ void NetworkManager::registerFrontendDevice(NMDeviceType::Enum type, NMDevice* d
|
||||||
// Bind generic NetworkDevice properties
|
// Bind generic NetworkDevice properties
|
||||||
auto translateState = [dev]() {
|
auto translateState = [dev]() {
|
||||||
switch (dev->state()) {
|
switch (dev->state()) {
|
||||||
case 0 ... 20: return DeviceConnectionState::Unknown;
|
case 0 ... 20: return ConnectionState::Unknown;
|
||||||
case 30: return DeviceConnectionState::Disconnected;
|
case 30: return ConnectionState::Disconnected;
|
||||||
case 40 ... 90: return DeviceConnectionState::Connecting;
|
case 40 ... 90: return ConnectionState::Connecting;
|
||||||
case 100: return DeviceConnectionState::Connected;
|
case 100: return ConnectionState::Connected;
|
||||||
case 110 ... 120: return DeviceConnectionState::Disconnecting;
|
case 110 ... 120: return ConnectionState::Disconnecting;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// clang-format off
|
// clang-format off
|
||||||
frontendDev->bindableName().setBinding([dev]() { return dev->interface(); });
|
frontendDev->bindableName().setBinding([dev]() { return dev->interface(); });
|
||||||
frontendDev->bindableAddress().setBinding([dev]() { return dev->hwAddress(); });
|
frontendDev->bindableAddress().setBinding([dev]() { return dev->hwAddress(); });
|
||||||
frontendDev->bindableNmState().setBinding([dev]() { return dev->state(); });
|
|
||||||
frontendDev->bindableState().setBinding(translateState);
|
frontendDev->bindableState().setBinding(translateState);
|
||||||
frontendDev->bindableAutoconnect().setBinding([dev]() { return dev->autoconnect(); });
|
frontendDev->bindableAutoconnect().setBinding([dev]() { return dev->autoconnect(); });
|
||||||
|
frontendDev->bindableNmManaged().setBinding([dev]() { return dev->managed(); });
|
||||||
QObject::connect(frontendDev, &WifiDevice::requestDisconnect, dev, &NMDevice::disconnect);
|
QObject::connect(frontendDev, &WifiDevice::requestDisconnect, dev, &NMDevice::disconnect);
|
||||||
QObject::connect(frontendDev, &NetworkDevice::requestSetAutoconnect, dev, &NMDevice::setAutoconnect);
|
QObject::connect(frontendDev, &NetworkDevice::requestSetAutoconnect, dev, &NMDevice::setAutoconnect);
|
||||||
|
QObject::connect(frontendDev, &NetworkDevice::requestSetNmManaged, dev, &NMDevice::setManaged);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
this->mFrontendDevices.insert(dev->path(), frontendDev);
|
this->mFrontendDevices.insert(dev->path(), frontendDev);
|
||||||
|
|
@ -215,6 +234,7 @@ void NetworkManager::onDevicePathRemoved(const QDBusObjectPath& path) {
|
||||||
auto* dev = iter.value();
|
auto* dev = iter.value();
|
||||||
this->mDevices.erase(iter);
|
this->mDevices.erase(iter);
|
||||||
if (dev) {
|
if (dev) {
|
||||||
|
qCDebug(logNetworkManager) << "Device removed:" << path.path();
|
||||||
this->removeFrontendDevice(dev);
|
this->removeFrontendDevice(dev);
|
||||||
delete dev;
|
delete dev;
|
||||||
}
|
}
|
||||||
|
|
@ -240,7 +260,7 @@ void NetworkManager::activateConnection(
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkManager::addAndActivateConnection(
|
void NetworkManager::addAndActivateConnection(
|
||||||
const ConnectionSettingsMap& settings,
|
const NMSettingsMap& settings,
|
||||||
const QDBusObjectPath& devPath,
|
const QDBusObjectPath& devPath,
|
||||||
const QDBusObjectPath& specificObjectPath
|
const QDBusObjectPath& specificObjectPath
|
||||||
) {
|
) {
|
||||||
|
|
@ -259,6 +279,12 @@ void NetworkManager::addAndActivateConnection(
|
||||||
QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback);
|
QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkManager::setConnectivityCheckEnabled(bool enabled) {
|
||||||
|
if (enabled == this->bConnectivityCheckEnabled) return;
|
||||||
|
this->bConnectivityCheckEnabled = enabled;
|
||||||
|
this->pConnectivityCheckEnabled.write();
|
||||||
|
}
|
||||||
|
|
||||||
void NetworkManager::setWifiEnabled(bool enabled) {
|
void NetworkManager::setWifiEnabled(bool enabled) {
|
||||||
if (enabled == this->bWifiEnabled) return;
|
if (enabled == this->bWifiEnabled) return;
|
||||||
this->bWifiEnabled = enabled;
|
this->bWifiEnabled = enabled;
|
||||||
|
|
@ -268,3 +294,12 @@ void NetworkManager::setWifiEnabled(bool enabled) {
|
||||||
bool NetworkManager::isAvailable() const { return this->proxy && this->proxy->isValid(); };
|
bool NetworkManager::isAvailable() const { return this->proxy && this->proxy->isValid(); };
|
||||||
|
|
||||||
} // namespace qs::network
|
} // namespace qs::network
|
||||||
|
|
||||||
|
namespace qs::dbus {
|
||||||
|
|
||||||
|
DBusResult<qs::network::NMConnectivityState::Enum>
|
||||||
|
DBusDataTransform<qs::network::NMConnectivityState::Enum>::fromWire(quint32 wire) {
|
||||||
|
return DBusResult(static_cast<qs::network::NMConnectivityState::Enum>(wire));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace qs::dbus
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,20 @@
|
||||||
#include "../../dbus/properties.hpp"
|
#include "../../dbus/properties.hpp"
|
||||||
#include "../network.hpp"
|
#include "../network.hpp"
|
||||||
#include "dbus_nm_backend.h"
|
#include "dbus_nm_backend.h"
|
||||||
|
#include "dbus_types.hpp"
|
||||||
#include "device.hpp"
|
#include "device.hpp"
|
||||||
|
#include "enums.hpp"
|
||||||
|
|
||||||
|
namespace qs::dbus {
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct DBusDataTransform<qs::network::NMConnectivityState::Enum> {
|
||||||
|
using Wire = quint32;
|
||||||
|
using Data = qs::network::NMConnectivityState::Enum;
|
||||||
|
static DBusResult<Data> fromWire(Wire wire);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace qs::dbus
|
||||||
|
|
||||||
namespace qs::network {
|
namespace qs::network {
|
||||||
|
|
||||||
|
|
@ -21,24 +34,34 @@ public:
|
||||||
explicit NetworkManager(QObject* parent = nullptr);
|
explicit NetworkManager(QObject* parent = nullptr);
|
||||||
|
|
||||||
[[nodiscard]] bool isAvailable() const override;
|
[[nodiscard]] bool isAvailable() const override;
|
||||||
[[nodiscard]] bool wifiEnabled() const { return this->bWifiEnabled; };
|
[[nodiscard]] bool wifiEnabled() const { return this->bWifiEnabled; }
|
||||||
[[nodiscard]] bool wifiHardwareEnabled() const { return this->bWifiHardwareEnabled; };
|
[[nodiscard]] bool wifiHardwareEnabled() const { return this->bWifiHardwareEnabled; }
|
||||||
|
[[nodiscard]] bool connectivityCheckAvailable() const {
|
||||||
|
return this->bConnectivityCheckAvailable;
|
||||||
|
};
|
||||||
|
[[nodiscard]] bool connectivityCheckEnabled() const { return this->bConnectivityCheckEnabled; }
|
||||||
|
[[nodiscard]] NMConnectivityState::Enum connectivity() const { return this->bConnectivity; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void deviceAdded(NetworkDevice* device);
|
void deviceAdded(NetworkDevice* device);
|
||||||
void deviceRemoved(NetworkDevice* device);
|
void deviceRemoved(NetworkDevice* device);
|
||||||
void wifiEnabledChanged(bool enabled);
|
void wifiEnabledChanged(bool enabled);
|
||||||
void wifiHardwareEnabledChanged(bool enabled);
|
void wifiHardwareEnabledChanged(bool enabled);
|
||||||
|
void connectivityStateChanged(NMConnectivityState::Enum state);
|
||||||
|
void connectivityCheckAvailableChanged(bool available);
|
||||||
|
void connectivityCheckEnabledChanged(bool enabled);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setWifiEnabled(bool enabled);
|
void setWifiEnabled(bool enabled);
|
||||||
|
void setConnectivityCheckEnabled(bool enabled);
|
||||||
|
void checkConnectivity();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onDevicePathAdded(const QDBusObjectPath& path);
|
void onDevicePathAdded(const QDBusObjectPath& path);
|
||||||
void onDevicePathRemoved(const QDBusObjectPath& path);
|
void onDevicePathRemoved(const QDBusObjectPath& path);
|
||||||
void activateConnection(const QDBusObjectPath& connPath, const QDBusObjectPath& devPath);
|
void activateConnection(const QDBusObjectPath& connPath, const QDBusObjectPath& devPath);
|
||||||
void addAndActivateConnection(
|
void addAndActivateConnection(
|
||||||
const ConnectionSettingsMap& settings,
|
const NMSettingsMap& settings,
|
||||||
const QDBusObjectPath& devPath,
|
const QDBusObjectPath& devPath,
|
||||||
const QDBusObjectPath& specificObjectPath
|
const QDBusObjectPath& specificObjectPath
|
||||||
);
|
);
|
||||||
|
|
@ -56,10 +79,16 @@ private:
|
||||||
// clang-format off
|
// clang-format off
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NetworkManager, bool, bWifiEnabled, &NetworkManager::wifiEnabledChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NetworkManager, bool, bWifiEnabled, &NetworkManager::wifiEnabledChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NetworkManager, bool, bWifiHardwareEnabled, &NetworkManager::wifiHardwareEnabledChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NetworkManager, bool, bWifiHardwareEnabled, &NetworkManager::wifiHardwareEnabledChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(NetworkManager, NMConnectivityState::Enum, bConnectivity, &NetworkManager::connectivityStateChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(NetworkManager, bool, bConnectivityCheckAvailable, &NetworkManager::connectivityCheckAvailableChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(NetworkManager, bool, bConnectivityCheckEnabled, &NetworkManager::connectivityCheckEnabledChanged);
|
||||||
|
|
||||||
QS_DBUS_BINDABLE_PROPERTY_GROUP(NetworkManager, dbusProperties);
|
QS_DBUS_BINDABLE_PROPERTY_GROUP(NetworkManager, dbusProperties);
|
||||||
QS_DBUS_PROPERTY_BINDING(NetworkManager, pWifiEnabled, bWifiEnabled, dbusProperties, "WirelessEnabled");
|
QS_DBUS_PROPERTY_BINDING(NetworkManager, pWifiEnabled, bWifiEnabled, dbusProperties, "WirelessEnabled");
|
||||||
QS_DBUS_PROPERTY_BINDING(NetworkManager, pWifiHardwareEnabled, bWifiHardwareEnabled, dbusProperties, "WirelessHardwareEnabled");
|
QS_DBUS_PROPERTY_BINDING(NetworkManager, pWifiHardwareEnabled, bWifiHardwareEnabled, dbusProperties, "WirelessHardwareEnabled");
|
||||||
|
QS_DBUS_PROPERTY_BINDING(NetworkManager, pConnectivity, bConnectivity, dbusProperties, "Connectivity");
|
||||||
|
QS_DBUS_PROPERTY_BINDING(NetworkManager, pConnectivityCheckAvailable, bConnectivityCheckAvailable, dbusProperties, "ConnectivityCheckAvailable");
|
||||||
|
QS_DBUS_PROPERTY_BINDING(NetworkManager, pConnectivityCheckEnabled, bConnectivityCheckEnabled, dbusProperties, "ConnectivityCheckEnabled");
|
||||||
// clang-format on
|
// clang-format on
|
||||||
DBusNetworkManagerProxy* proxy = nullptr;
|
DBusNetworkManagerProxy* proxy = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,151 +0,0 @@
|
||||||
#include "connection.hpp"
|
|
||||||
|
|
||||||
#include <qdbusconnection.h>
|
|
||||||
#include <qdbusmetatype.h>
|
|
||||||
#include <qdbuspendingcall.h>
|
|
||||||
#include <qdbuspendingreply.h>
|
|
||||||
#include <qlogging.h>
|
|
||||||
#include <qloggingcategory.h>
|
|
||||||
#include <qnamespace.h>
|
|
||||||
#include <qobject.h>
|
|
||||||
#include <qstring.h>
|
|
||||||
#include <qtmetamacros.h>
|
|
||||||
#include <qtypes.h>
|
|
||||||
|
|
||||||
#include "../../core/logcat.hpp"
|
|
||||||
#include "../../dbus/properties.hpp"
|
|
||||||
#include "../wifi.hpp"
|
|
||||||
#include "dbus_nm_active_connection.h"
|
|
||||||
#include "dbus_nm_connection_settings.h"
|
|
||||||
#include "dbus_types.hpp"
|
|
||||||
#include "enums.hpp"
|
|
||||||
#include "utils.hpp"
|
|
||||||
|
|
||||||
namespace qs::network {
|
|
||||||
using namespace qs::dbus;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
QS_LOGGING_CATEGORY(logNetworkManager, "quickshell.network.networkmanager", QtWarningMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
NMConnectionSettings::NMConnectionSettings(const QString& path, QObject* parent): QObject(parent) {
|
|
||||||
qDBusRegisterMetaType<ConnectionSettingsMap>();
|
|
||||||
|
|
||||||
this->proxy = new DBusNMConnectionSettingsProxy(
|
|
||||||
"org.freedesktop.NetworkManager",
|
|
||||||
path,
|
|
||||||
QDBusConnection::systemBus(),
|
|
||||||
this
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!this->proxy->isValid()) {
|
|
||||||
qCWarning(logNetworkManager) << "Cannot create DBus interface for connection at" << path;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QObject::connect(
|
|
||||||
this->proxy,
|
|
||||||
&DBusNMConnectionSettingsProxy::Updated,
|
|
||||||
this,
|
|
||||||
&NMConnectionSettings::updateSettings
|
|
||||||
);
|
|
||||||
this->bSecurity.setBinding([this]() { return securityFromConnectionSettings(this->bSettings); });
|
|
||||||
|
|
||||||
this->connectionSettingsProperties.setInterface(this->proxy);
|
|
||||||
this->connectionSettingsProperties.updateAllViaGetAll();
|
|
||||||
|
|
||||||
this->updateSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NMConnectionSettings::updateSettings() {
|
|
||||||
auto pending = this->proxy->GetSettings();
|
|
||||||
auto* call = new QDBusPendingCallWatcher(pending, this);
|
|
||||||
|
|
||||||
auto responseCallback = [this](QDBusPendingCallWatcher* call) {
|
|
||||||
const QDBusPendingReply<ConnectionSettingsMap> reply = *call;
|
|
||||||
|
|
||||||
if (reply.isError()) {
|
|
||||||
qCWarning(logNetworkManager)
|
|
||||||
<< "Failed to get" << this->path() << "settings:" << reply.error().message();
|
|
||||||
} else {
|
|
||||||
this->bSettings = reply.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this->mLoaded) {
|
|
||||||
emit this->loaded();
|
|
||||||
this->mLoaded = true;
|
|
||||||
}
|
|
||||||
delete call;
|
|
||||||
};
|
|
||||||
|
|
||||||
QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NMConnectionSettings::forget() {
|
|
||||||
auto pending = this->proxy->Delete();
|
|
||||||
auto* call = new QDBusPendingCallWatcher(pending, this);
|
|
||||||
|
|
||||||
auto responseCallback = [this](QDBusPendingCallWatcher* call) {
|
|
||||||
const QDBusPendingReply<> reply = *call;
|
|
||||||
|
|
||||||
if (reply.isError()) {
|
|
||||||
qCWarning(logNetworkManager)
|
|
||||||
<< "Failed to forget" << this->path() << ":" << reply.error().message();
|
|
||||||
}
|
|
||||||
delete call;
|
|
||||||
};
|
|
||||||
|
|
||||||
QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NMConnectionSettings::isValid() const { return this->proxy && this->proxy->isValid(); }
|
|
||||||
QString NMConnectionSettings::address() const {
|
|
||||||
return this->proxy ? this->proxy->service() : QString();
|
|
||||||
}
|
|
||||||
QString NMConnectionSettings::path() const { return this->proxy ? this->proxy->path() : QString(); }
|
|
||||||
|
|
||||||
NMActiveConnection::NMActiveConnection(const QString& path, QObject* parent): QObject(parent) {
|
|
||||||
this->proxy = new DBusNMActiveConnectionProxy(
|
|
||||||
"org.freedesktop.NetworkManager",
|
|
||||||
path,
|
|
||||||
QDBusConnection::systemBus(),
|
|
||||||
this
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!this->proxy->isValid()) {
|
|
||||||
qCWarning(logNetworkManager) << "Cannot create DBus interface for connection at" << path;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
QObject::connect(&this->activeConnectionProperties, &DBusPropertyGroup::getAllFinished, this, &NMActiveConnection::loaded, Qt::SingleShotConnection);
|
|
||||||
QObject::connect(this->proxy, &DBusNMActiveConnectionProxy::StateChanged, this, &NMActiveConnection::onStateChanged);
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
this->activeConnectionProperties.setInterface(this->proxy);
|
|
||||||
this->activeConnectionProperties.updateAllViaGetAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NMActiveConnection::onStateChanged(quint32 /*state*/, quint32 reason) {
|
|
||||||
auto enumReason = static_cast<NMConnectionStateReason::Enum>(reason);
|
|
||||||
if (this->mStateReason == enumReason) return;
|
|
||||||
this->mStateReason = enumReason;
|
|
||||||
emit this->stateReasonChanged(enumReason);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NMActiveConnection::isValid() const { return this->proxy && this->proxy->isValid(); }
|
|
||||||
QString NMActiveConnection::address() const {
|
|
||||||
return this->proxy ? this->proxy->service() : QString();
|
|
||||||
}
|
|
||||||
QString NMActiveConnection::path() const { return this->proxy ? this->proxy->path() : QString(); }
|
|
||||||
|
|
||||||
} // namespace qs::network
|
|
||||||
|
|
||||||
namespace qs::dbus {
|
|
||||||
|
|
||||||
DBusResult<qs::network::NMConnectionState::Enum>
|
|
||||||
DBusDataTransform<qs::network::NMConnectionState::Enum>::fromWire(quint32 wire) {
|
|
||||||
return DBusResult(static_cast<qs::network::NMConnectionState::Enum>(wire));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace qs::dbus
|
|
||||||
69
src/network/nm/dbus_types.cpp
Normal file
69
src/network/nm/dbus_types.cpp
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
#include "dbus_types.hpp"
|
||||||
|
|
||||||
|
#include <qbytearray.h>
|
||||||
|
#include <qcontainerfwd.h>
|
||||||
|
#include <qdbusargument.h>
|
||||||
|
#include <qmap.h>
|
||||||
|
#include <qmetatype.h>
|
||||||
|
#include <qstring.h>
|
||||||
|
|
||||||
|
namespace qs::network {
|
||||||
|
|
||||||
|
const QDBusArgument& operator>>(const QDBusArgument& argument, NMSettingsMap& map) {
|
||||||
|
argument.beginMap();
|
||||||
|
while (!argument.atEnd()) {
|
||||||
|
argument.beginMapEntry();
|
||||||
|
QString groupName;
|
||||||
|
argument >> groupName;
|
||||||
|
|
||||||
|
QVariantMap group;
|
||||||
|
argument >> group;
|
||||||
|
|
||||||
|
map.insert(groupName, group);
|
||||||
|
argument.endMapEntry();
|
||||||
|
}
|
||||||
|
argument.endMap();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDBusArgument& operator<<(QDBusArgument& argument, const NMSettingsMap& map) {
|
||||||
|
argument.beginMap(qMetaTypeId<QString>(), qMetaTypeId<QVariantMap>());
|
||||||
|
for (auto it = map.constBegin(); it != map.constEnd(); ++it) {
|
||||||
|
argument.beginMapEntry();
|
||||||
|
argument << it.key();
|
||||||
|
argument << it.value();
|
||||||
|
argument.endMapEntry();
|
||||||
|
}
|
||||||
|
argument.endMap();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDBusArgument& operator>>(const QDBusArgument& argument, NMIPv6Address& addr) {
|
||||||
|
argument.beginStructure();
|
||||||
|
argument >> addr.address >> addr.prefix >> addr.gateway;
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDBusArgument& operator<<(QDBusArgument& argument, const NMIPv6Address& addr) {
|
||||||
|
argument.beginStructure();
|
||||||
|
argument << addr.address << addr.prefix << addr.gateway;
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDBusArgument& operator>>(const QDBusArgument& argument, NMIPv6Route& route) {
|
||||||
|
argument.beginStructure();
|
||||||
|
argument >> route.destination >> route.prefix >> route.nexthop >> route.metric;
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDBusArgument& operator<<(QDBusArgument& argument, const NMIPv6Route& route) {
|
||||||
|
argument.beginStructure();
|
||||||
|
argument << route.destination << route.prefix << route.nexthop << route.metric;
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace qs::network
|
||||||
|
|
@ -1,9 +1,40 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <qdbusextratypes.h>
|
#include <qbytearray.h>
|
||||||
|
#include <qdbusargument.h>
|
||||||
#include <qmap.h>
|
#include <qmap.h>
|
||||||
#include <qstring.h>
|
#include <qstring.h>
|
||||||
|
#include <qtypes.h>
|
||||||
#include <qvariant.h>
|
#include <qvariant.h>
|
||||||
|
|
||||||
using ConnectionSettingsMap = QMap<QString, QVariantMap>;
|
namespace qs::network {
|
||||||
Q_DECLARE_METATYPE(ConnectionSettingsMap);
|
|
||||||
|
using NMSettingsMap = QMap<QString, QVariantMap>;
|
||||||
|
|
||||||
|
const QDBusArgument& operator>>(const QDBusArgument& argument, NMSettingsMap& map);
|
||||||
|
const QDBusArgument& operator<<(QDBusArgument& argument, const NMSettingsMap& map);
|
||||||
|
|
||||||
|
struct NMIPv6Address {
|
||||||
|
QByteArray address;
|
||||||
|
quint32 prefix = 0;
|
||||||
|
QByteArray gateway;
|
||||||
|
};
|
||||||
|
|
||||||
|
const QDBusArgument& operator>>(const QDBusArgument& argument, qs::network::NMIPv6Address& addr);
|
||||||
|
const QDBusArgument& operator<<(QDBusArgument& argument, const qs::network::NMIPv6Address& addr);
|
||||||
|
|
||||||
|
struct NMIPv6Route {
|
||||||
|
QByteArray destination;
|
||||||
|
quint32 prefix = 0;
|
||||||
|
QByteArray nexthop;
|
||||||
|
quint32 metric = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const QDBusArgument& operator>>(const QDBusArgument& argument, qs::network::NMIPv6Route& route);
|
||||||
|
const QDBusArgument& operator<<(QDBusArgument& argument, const qs::network::NMIPv6Route& route);
|
||||||
|
|
||||||
|
} // namespace qs::network
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(qs::network::NMSettingsMap);
|
||||||
|
Q_DECLARE_METATYPE(qs::network::NMIPv6Address);
|
||||||
|
Q_DECLARE_METATYPE(qs::network::NMIPv6Route);
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,10 @@
|
||||||
|
|
||||||
#include "../../core/logcat.hpp"
|
#include "../../core/logcat.hpp"
|
||||||
#include "../../dbus/properties.hpp"
|
#include "../../dbus/properties.hpp"
|
||||||
#include "../device.hpp"
|
#include "active_connection.hpp"
|
||||||
#include "connection.hpp"
|
|
||||||
#include "dbus_nm_device.h"
|
#include "dbus_nm_device.h"
|
||||||
|
#include "enums.hpp"
|
||||||
|
#include "settings.hpp"
|
||||||
|
|
||||||
namespace qs::network {
|
namespace qs::network {
|
||||||
using namespace qs::dbus;
|
using namespace qs::dbus;
|
||||||
|
|
@ -39,19 +40,29 @@ NMDevice::NMDevice(const QString& path, QObject* parent): QObject(parent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
QObject::connect(this, &NMDevice::availableConnectionPathsChanged, this, &NMDevice::onAvailableConnectionPathsChanged);
|
QObject::connect(this, &NMDevice::availableSettingsPathsChanged, this, &NMDevice::onAvailableSettingsPathsChanged);
|
||||||
QObject::connect(this, &NMDevice::activeConnectionPathChanged, this, &NMDevice::onActiveConnectionPathChanged);
|
QObject::connect(this, &NMDevice::activeConnectionPathChanged, this, &NMDevice::onActiveConnectionPathChanged);
|
||||||
|
QObject::connect(this->deviceProxy, &DBusNMDeviceProxy::StateChanged, this, &NMDevice::onStateChanged);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
this->deviceProperties.setInterface(this->deviceProxy);
|
this->deviceProperties.setInterface(this->deviceProxy);
|
||||||
this->deviceProperties.updateAllViaGetAll();
|
this->deviceProperties.updateAllViaGetAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NMDevice::onStateChanged(quint32 newState, quint32 /*oldState*/, quint32 reason) {
|
||||||
|
auto enumReason = static_cast<NMDeviceStateReason::Enum>(reason);
|
||||||
|
auto enumNewState = static_cast<NMDeviceState::Enum>(newState);
|
||||||
|
if (enumNewState == NMDeviceState::Failed) this->bLastFailReason = enumReason;
|
||||||
|
if (this->bStateReason == enumReason) return;
|
||||||
|
this->bStateReason = enumReason;
|
||||||
|
}
|
||||||
|
|
||||||
void NMDevice::onActiveConnectionPathChanged(const QDBusObjectPath& path) {
|
void NMDevice::onActiveConnectionPathChanged(const QDBusObjectPath& path) {
|
||||||
const QString stringPath = path.path();
|
const QString stringPath = path.path();
|
||||||
|
|
||||||
// Remove old active connection
|
// Remove old active connection
|
||||||
if (this->mActiveConnection) {
|
if (this->mActiveConnection) {
|
||||||
|
qCDebug(logNetworkManager) << "Active connection removed:" << this->mActiveConnection->path();
|
||||||
QObject::disconnect(this->mActiveConnection, nullptr, this, nullptr);
|
QObject::disconnect(this->mActiveConnection, nullptr, this, nullptr);
|
||||||
delete this->mActiveConnection;
|
delete this->mActiveConnection;
|
||||||
this->mActiveConnection = nullptr;
|
this->mActiveConnection = nullptr;
|
||||||
|
|
@ -64,6 +75,7 @@ void NMDevice::onActiveConnectionPathChanged(const QDBusObjectPath& path) {
|
||||||
qCWarning(logNetworkManager) << "Ignoring invalid registration of" << stringPath;
|
qCWarning(logNetworkManager) << "Ignoring invalid registration of" << stringPath;
|
||||||
delete active;
|
delete active;
|
||||||
} else {
|
} else {
|
||||||
|
qCDebug(logNetworkManager) << "Active connection added:" << stringPath;
|
||||||
this->mActiveConnection = active;
|
this->mActiveConnection = active;
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
active,
|
active,
|
||||||
|
|
@ -76,42 +88,44 @@ void NMDevice::onActiveConnectionPathChanged(const QDBusObjectPath& path) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NMDevice::onAvailableConnectionPathsChanged(const QList<QDBusObjectPath>& paths) {
|
void NMDevice::onAvailableSettingsPathsChanged(const QList<QDBusObjectPath>& paths) {
|
||||||
QSet<QString> newPathSet;
|
QSet<QString> newPathSet;
|
||||||
for (const QDBusObjectPath& path: paths) {
|
for (const QDBusObjectPath& path: paths) {
|
||||||
newPathSet.insert(path.path());
|
newPathSet.insert(path.path());
|
||||||
}
|
}
|
||||||
const auto existingPaths = this->mConnections.keys();
|
const auto existingPaths = this->mSettings.keys();
|
||||||
const QSet<QString> existingPathSet(existingPaths.begin(), existingPaths.end());
|
const QSet<QString> existingPathSet(existingPaths.begin(), existingPaths.end());
|
||||||
|
|
||||||
const auto addedConnections = newPathSet - existingPathSet;
|
const auto addedSettings = newPathSet - existingPathSet;
|
||||||
const auto removedConnections = existingPathSet - newPathSet;
|
const auto removedSettings = existingPathSet - newPathSet;
|
||||||
|
|
||||||
for (const QString& path: addedConnections) {
|
for (const QString& path: addedSettings) {
|
||||||
this->registerConnection(path);
|
this->registerSettings(path);
|
||||||
}
|
}
|
||||||
for (const QString& path: removedConnections) {
|
for (const QString& path: removedSettings) {
|
||||||
auto* connection = this->mConnections.take(path);
|
auto* connection = this->mSettings.take(path);
|
||||||
if (!connection) {
|
if (!connection) {
|
||||||
qCDebug(logNetworkManager) << "Sent removal signal for" << path << "which is not registered.";
|
qCDebug(logNetworkManager) << "Sent removal signal for" << path << "which is not registered.";
|
||||||
} else {
|
} else {
|
||||||
|
qCDebug(logNetworkManager) << "Connection settings removed:" << path;
|
||||||
delete connection;
|
delete connection;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void NMDevice::registerConnection(const QString& path) {
|
void NMDevice::registerSettings(const QString& path) {
|
||||||
auto* connection = new NMConnectionSettings(path, this);
|
auto* settings = new NMSettings(path, this);
|
||||||
if (!connection->isValid()) {
|
if (!settings->isValid()) {
|
||||||
qCWarning(logNetworkManager) << "Ignoring invalid registration of" << path;
|
qCWarning(logNetworkManager) << "Ignoring invalid registration of" << path;
|
||||||
delete connection;
|
delete settings;
|
||||||
} else {
|
} else {
|
||||||
this->mConnections.insert(path, connection);
|
qCDebug(logNetworkManager) << "Connection settings added:" << path;
|
||||||
|
this->mSettings.insert(path, settings);
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
connection,
|
settings,
|
||||||
&NMConnectionSettings::loaded,
|
&NMSettings::loaded,
|
||||||
this,
|
this,
|
||||||
[this, connection]() { emit this->connectionLoaded(connection); },
|
[this, settings]() { emit this->settingsLoaded(settings); },
|
||||||
Qt::SingleShotConnection
|
Qt::SingleShotConnection
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -125,6 +139,12 @@ void NMDevice::setAutoconnect(bool autoconnect) {
|
||||||
this->pAutoconnect.write();
|
this->pAutoconnect.write();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NMDevice::setManaged(bool managed) {
|
||||||
|
if (managed == this->bManaged) return;
|
||||||
|
this->bManaged = managed;
|
||||||
|
this->pManaged.write();
|
||||||
|
}
|
||||||
|
|
||||||
bool NMDevice::isValid() const { return this->deviceProxy && this->deviceProxy->isValid(); }
|
bool NMDevice::isValid() const { return this->deviceProxy && this->deviceProxy->isValid(); }
|
||||||
QString NMDevice::address() const {
|
QString NMDevice::address() const {
|
||||||
return this->deviceProxy ? this->deviceProxy->service() : QString();
|
return this->deviceProxy ? this->deviceProxy->service() : QString();
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,10 @@
|
||||||
#include <qtypes.h>
|
#include <qtypes.h>
|
||||||
|
|
||||||
#include "../../dbus/properties.hpp"
|
#include "../../dbus/properties.hpp"
|
||||||
#include "connection.hpp"
|
#include "../enums.hpp"
|
||||||
|
#include "active_connection.hpp"
|
||||||
#include "dbus_nm_device.h"
|
#include "dbus_nm_device.h"
|
||||||
|
#include "settings.hpp"
|
||||||
|
|
||||||
namespace qs::dbus {
|
namespace qs::dbus {
|
||||||
|
|
||||||
|
|
@ -36,43 +38,49 @@ public:
|
||||||
[[nodiscard]] virtual bool isValid() const;
|
[[nodiscard]] virtual bool isValid() const;
|
||||||
[[nodiscard]] QString path() const;
|
[[nodiscard]] QString path() const;
|
||||||
[[nodiscard]] QString address() const;
|
[[nodiscard]] QString address() const;
|
||||||
[[nodiscard]] QString interface() const { return this->bInterface; };
|
[[nodiscard]] QString interface() const { return this->bInterface; }
|
||||||
[[nodiscard]] QString hwAddress() const { return this->bHwAddress; };
|
[[nodiscard]] QString hwAddress() const { return this->bHwAddress; }
|
||||||
[[nodiscard]] bool managed() const { return this->bManaged; };
|
[[nodiscard]] bool managed() const { return this->bManaged; }
|
||||||
[[nodiscard]] NMDeviceState::Enum state() const { return this->bState; };
|
[[nodiscard]] NMDeviceState::Enum state() const { return this->bState; }
|
||||||
[[nodiscard]] bool autoconnect() const { return this->bAutoconnect; };
|
[[nodiscard]] NMDeviceStateReason::Enum stateReason() const { return this->bStateReason; }
|
||||||
[[nodiscard]] NMActiveConnection* activeConnection() const { return this->mActiveConnection; };
|
[[nodiscard]] NMDeviceStateReason::Enum lastFailReason() const { return this->bLastFailReason; }
|
||||||
|
[[nodiscard]] bool autoconnect() const { return this->bAutoconnect; }
|
||||||
|
[[nodiscard]] NMActiveConnection* activeConnection() const { return this->mActiveConnection; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void activateConnection(const QDBusObjectPath& connPath, const QDBusObjectPath& devPath);
|
void activateConnection(const QDBusObjectPath& connPath, const QDBusObjectPath& devPath);
|
||||||
void addAndActivateConnection(
|
void addAndActivateConnection(
|
||||||
const ConnectionSettingsMap& settings,
|
const NMSettingsMap& settings,
|
||||||
const QDBusObjectPath& devPath,
|
const QDBusObjectPath& devPath,
|
||||||
const QDBusObjectPath& apPath
|
const QDBusObjectPath& apPath
|
||||||
);
|
);
|
||||||
void connectionLoaded(NMConnectionSettings* connection);
|
void settingsLoaded(NMSettings* settings);
|
||||||
void connectionRemoved(NMConnectionSettings* connection);
|
void settingsRemoved(NMSettings* settings);
|
||||||
void availableConnectionPathsChanged(QList<QDBusObjectPath> paths);
|
void availableSettingsPathsChanged(QList<QDBusObjectPath> paths);
|
||||||
void activeConnectionPathChanged(const QDBusObjectPath& connection);
|
void activeConnectionPathChanged(const QDBusObjectPath& connection);
|
||||||
void activeConnectionLoaded(NMActiveConnection* active);
|
void activeConnectionLoaded(NMActiveConnection* active);
|
||||||
void interfaceChanged(const QString& interface);
|
void interfaceChanged(const QString& interface);
|
||||||
void hwAddressChanged(const QString& hwAddress);
|
void hwAddressChanged(const QString& hwAddress);
|
||||||
void managedChanged(bool managed);
|
void managedChanged(bool managed);
|
||||||
void stateChanged(NMDeviceState::Enum state);
|
void stateChanged(NMDeviceState::Enum state);
|
||||||
|
void stateReasonChanged(NMDeviceStateReason::Enum reason);
|
||||||
|
void lastFailReasonChanged(NMDeviceStateReason::Enum reason);
|
||||||
void autoconnectChanged(bool autoconnect);
|
void autoconnectChanged(bool autoconnect);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void disconnect();
|
void disconnect();
|
||||||
void setAutoconnect(bool autoconnect);
|
void setAutoconnect(bool autoconnect);
|
||||||
|
void setManaged(bool managed);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onAvailableConnectionPathsChanged(const QList<QDBusObjectPath>& paths);
|
void onStateChanged(quint32 newState, quint32 oldState, quint32 reason);
|
||||||
|
void onAvailableSettingsPathsChanged(const QList<QDBusObjectPath>& paths);
|
||||||
void onActiveConnectionPathChanged(const QDBusObjectPath& path);
|
void onActiveConnectionPathChanged(const QDBusObjectPath& path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void registerConnection(const QString& path);
|
void registerSettings(const QString& path);
|
||||||
|
|
||||||
QHash<QString, NMConnectionSettings*> mConnections;
|
QHash<QString, NMSettings*> mSettings;
|
||||||
NMActiveConnection* mActiveConnection = nullptr;
|
NMActiveConnection* mActiveConnection = nullptr;
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
@ -80,8 +88,10 @@ private:
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NMDevice, QString, bHwAddress, &NMDevice::hwAddressChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NMDevice, QString, bHwAddress, &NMDevice::hwAddressChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NMDevice, bool, bManaged, &NMDevice::managedChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NMDevice, bool, bManaged, &NMDevice::managedChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NMDevice, NMDeviceState::Enum, bState, &NMDevice::stateChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NMDevice, NMDeviceState::Enum, bState, &NMDevice::stateChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(NMDevice, NMDeviceStateReason::Enum, bStateReason, &NMDevice::stateReasonChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(NMDevice, NMDeviceStateReason::Enum, bLastFailReason, &NMDevice::lastFailReasonChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NMDevice, bool, bAutoconnect, &NMDevice::autoconnectChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NMDevice, bool, bAutoconnect, &NMDevice::autoconnectChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NMDevice, QList<QDBusObjectPath>, bAvailableConnections, &NMDevice::availableConnectionPathsChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NMDevice, QList<QDBusObjectPath>, bAvailableConnections, &NMDevice::availableSettingsPathsChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NMDevice, QDBusObjectPath, bActiveConnection, &NMDevice::activeConnectionPathChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NMDevice, QDBusObjectPath, bActiveConnection, &NMDevice::activeConnectionPathChanged);
|
||||||
|
|
||||||
QS_DBUS_BINDABLE_PROPERTY_GROUP(NMDeviceAdapter, deviceProperties);
|
QS_DBUS_BINDABLE_PROPERTY_GROUP(NMDeviceAdapter, deviceProperties);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,20 @@
|
||||||
|
|
||||||
namespace qs::network {
|
namespace qs::network {
|
||||||
|
|
||||||
|
// In sync with https://networkmanager.dev/docs/api/latest/nm-dbus-types.html#NMConnectivityState
|
||||||
|
class NMConnectivityState: public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Enum : quint8 {
|
||||||
|
Unknown = 0,
|
||||||
|
None = 1,
|
||||||
|
Portal = 2,
|
||||||
|
Limited = 3,
|
||||||
|
Full = 4,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// Indicates the type of hardware represented by a device object.
|
// Indicates the type of hardware represented by a device object.
|
||||||
class NMDeviceType: public QObject {
|
class NMDeviceType: public QObject {
|
||||||
Q_OBJECT;
|
Q_OBJECT;
|
||||||
|
|
@ -52,6 +66,123 @@ public:
|
||||||
Q_ENUM(Enum);
|
Q_ENUM(Enum);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// In sync with https://networkmanager.dev/docs/api/latest/nm-dbus-types.html#NMDeviceState.
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Device state change reason codes.
|
||||||
|
// In sync with https://networkmanager.dev/docs/api/latest/nm-dbus-types.html#NMDeviceStateReason.
|
||||||
|
class NMDeviceStateReason: public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
QML_ELEMENT;
|
||||||
|
QML_SINGLETON;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Enum : quint8 {
|
||||||
|
None = 0,
|
||||||
|
Unknown = 1,
|
||||||
|
NowManaged = 2,
|
||||||
|
NowUnmanaged = 3,
|
||||||
|
ConfigFailed = 4,
|
||||||
|
IpConfigUnavailable = 5,
|
||||||
|
IpConfigExpired = 6,
|
||||||
|
NoSecrets = 7,
|
||||||
|
SupplicantDisconnect = 8,
|
||||||
|
SupplicantConfigFailed = 9,
|
||||||
|
SupplicantFailed = 10,
|
||||||
|
SupplicantTimeout = 11,
|
||||||
|
PppStartFailed = 12,
|
||||||
|
PppDisconnect = 13,
|
||||||
|
PppFailed = 14,
|
||||||
|
DhcpStartFailed = 15,
|
||||||
|
DhcpError = 16,
|
||||||
|
DhcpFailed = 17,
|
||||||
|
SharedStartFailed = 18,
|
||||||
|
SharedFailed = 19,
|
||||||
|
AutoIpStartFailed = 20,
|
||||||
|
AutoIpError = 21,
|
||||||
|
AutoIpFailed = 22,
|
||||||
|
ModemBusy = 23,
|
||||||
|
ModemNoDialTone = 24,
|
||||||
|
ModemNoCarrier = 25,
|
||||||
|
ModemDialTimeout = 26,
|
||||||
|
ModemDialFailed = 27,
|
||||||
|
ModemInitFailed = 28,
|
||||||
|
GsmApnFailed = 29,
|
||||||
|
GsmRegistrationNotSearching = 30,
|
||||||
|
GsmRegistrationDenied = 31,
|
||||||
|
GsmRegistrationTimeout = 32,
|
||||||
|
GsmRegistrationFailed = 33,
|
||||||
|
GsmPinCheckFailed = 34,
|
||||||
|
FirmwareMissing = 35,
|
||||||
|
Removed = 36,
|
||||||
|
Sleeping = 37,
|
||||||
|
ConnectionRemoved = 38,
|
||||||
|
UserRequested = 39,
|
||||||
|
Carrier = 40,
|
||||||
|
ConnectionAssumed = 41,
|
||||||
|
SupplicantAvailable = 42,
|
||||||
|
ModemNotFound = 43,
|
||||||
|
BtFailed = 44,
|
||||||
|
GsmSimNotInserted = 45,
|
||||||
|
GsmSimPinRequired = 46,
|
||||||
|
GsmSimPukRequired = 47,
|
||||||
|
GsmSimWrong = 48,
|
||||||
|
InfinibandMode = 49,
|
||||||
|
DependencyFailed = 50,
|
||||||
|
Br2684Failed = 51,
|
||||||
|
ModemManagerUnavailable = 52,
|
||||||
|
SsidNotFound = 53,
|
||||||
|
SecondaryConnectionFailed = 54,
|
||||||
|
DcbFcoeFailed = 55,
|
||||||
|
TeamdControlFailed = 56,
|
||||||
|
ModemFailed = 57,
|
||||||
|
ModemAvailable = 58,
|
||||||
|
SimPinIncorrect = 59,
|
||||||
|
NewActivation = 60,
|
||||||
|
ParentChanged = 61,
|
||||||
|
ParentManagedChanged = 62,
|
||||||
|
OvsdbFailed = 63,
|
||||||
|
IpAddressDuplicate = 64,
|
||||||
|
IpMethodUnsupported = 65,
|
||||||
|
SriovConfigurationFailed = 66,
|
||||||
|
PeerNotFound = 67,
|
||||||
|
DeviceHandlerFailed = 68,
|
||||||
|
UnmanagedByDefault = 69,
|
||||||
|
UnmanagedExternalDown = 70,
|
||||||
|
UnmanagedLinkNotInit = 71,
|
||||||
|
UnmanagedQuitting = 72,
|
||||||
|
UnmanagedManagerDisabled = 73,
|
||||||
|
UnmanagedUserConf = 74,
|
||||||
|
UnmanagedUserExplicit = 75,
|
||||||
|
UnmanagedUserSettings = 76,
|
||||||
|
UnmanagedUserUdev = 77,
|
||||||
|
NetworkingOff = 78,
|
||||||
|
};
|
||||||
|
Q_ENUM(Enum);
|
||||||
|
};
|
||||||
|
|
||||||
// 802.11 specific device encryption and authentication capabilities.
|
// 802.11 specific device encryption and authentication capabilities.
|
||||||
// In sync with https://networkmanager.dev/docs/api/latest/nm-dbus-types.html#NMDeviceWifiCapabilities.
|
// In sync with https://networkmanager.dev/docs/api/latest/nm-dbus-types.html#NMDeviceWifiCapabilities.
|
||||||
class NMWirelessCapabilities: public QObject {
|
class NMWirelessCapabilities: public QObject {
|
||||||
|
|
@ -153,4 +284,31 @@ public:
|
||||||
Q_ENUM(Enum);
|
Q_ENUM(Enum);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// In sync with https://networkmanager.dev/docs/api/latest/nm-dbus-types.html#NMActiveConnectionStateReason.
|
||||||
|
class NMConnectionStateReason: public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
QML_ELEMENT;
|
||||||
|
QML_SINGLETON;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Enum : quint8 {
|
||||||
|
Unknown = 0,
|
||||||
|
None = 1,
|
||||||
|
UserDisconnected = 2,
|
||||||
|
DeviceDisconnected = 3,
|
||||||
|
ServiceStopped = 4,
|
||||||
|
IpConfigInvalid = 5,
|
||||||
|
ConnectTimeout = 6,
|
||||||
|
ServiceStartTimeout = 7,
|
||||||
|
ServiceStartFailed = 8,
|
||||||
|
NoSecrets = 9,
|
||||||
|
LoginFailed = 10,
|
||||||
|
ConnectionRemoved = 11,
|
||||||
|
DependencyFailed = 12,
|
||||||
|
DeviceRealizeFailed = 13,
|
||||||
|
DeviceRemoved = 14
|
||||||
|
};
|
||||||
|
Q_ENUM(Enum);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace qs::network
|
} // namespace qs::network
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
<node>
|
<node>
|
||||||
<interface name="org.freedesktop.NetworkManager.Device">
|
<interface name="org.freedesktop.NetworkManager.Device">
|
||||||
<method name="Disconnect"/>
|
<method name="Disconnect"/>
|
||||||
|
<signal name="StateChanged">
|
||||||
|
<arg name="new_state" type="u"/>
|
||||||
|
<arg name="old_state" type="u"/>
|
||||||
|
<arg name="reason" type="u"/>
|
||||||
|
</signal>
|
||||||
</interface>
|
</interface>
|
||||||
</node>
|
</node>
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,18 @@
|
||||||
<interface name="org.freedesktop.NetworkManager.Settings.Connection">
|
<interface name="org.freedesktop.NetworkManager.Settings.Connection">
|
||||||
<method name="GetSettings">
|
<method name="GetSettings">
|
||||||
<arg name="settings" type="a{sa{sv}}" direction="out"/>
|
<arg name="settings" type="a{sa{sv}}" direction="out"/>
|
||||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="ConnectionSettingsMap"/>
|
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="qs::network::NMSettingsMap"/>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="GetSecrets">
|
||||||
|
<arg name="setting_name" type="s" direction="in"/>
|
||||||
|
<arg name="secrets" type="a{sa{sv}}" direction="out"/>
|
||||||
|
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="qs::network::NMSettingsMap"/>
|
||||||
|
</method>
|
||||||
|
<method name="Update">
|
||||||
|
<arg name="properties" type="a{sa{sv}}" direction="in"/>
|
||||||
|
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="qs::network::NMSettingsMap"/>
|
||||||
|
</method>
|
||||||
|
<method name="ClearSecrets"/>
|
||||||
<method name="Delete"/>
|
<method name="Delete"/>
|
||||||
<signal name="Updated"/>
|
<signal name="Updated"/>
|
||||||
<signal name="Removed"/>
|
<signal name="Removed"/>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
<node>
|
<node>
|
||||||
<interface name="org.freedesktop.NetworkManager">
|
<interface name="org.freedesktop.NetworkManager">
|
||||||
|
<method name="CheckConnectivity">
|
||||||
|
<arg direction="out" type="u" name="connectivity"/>
|
||||||
|
</method>
|
||||||
<method name="GetAllDevices">
|
<method name="GetAllDevices">
|
||||||
<arg direction="out" type="ao" name="devices"/>
|
<arg direction="out" type="ao" name="devices"/>
|
||||||
</method>
|
</method>
|
||||||
|
|
@ -11,7 +14,7 @@
|
||||||
</method>
|
</method>
|
||||||
<method name="AddAndActivateConnection">
|
<method name="AddAndActivateConnection">
|
||||||
<arg direction="in" type="a{sa{sv}}" name="connection"/>
|
<arg direction="in" type="a{sa{sv}}" name="connection"/>
|
||||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="ConnectionSettingsMap"/>
|
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="qs::network::NMSettingsMap"/>
|
||||||
<arg direction="in" type="o" name="device"/>
|
<arg direction="in" type="o" name="device"/>
|
||||||
<arg direction="in" type="o" name="specific_object"/>
|
<arg direction="in" type="o" name="specific_object"/>
|
||||||
<arg direction="out" type="o" name="path"/>
|
<arg direction="out" type="o" name="path"/>
|
||||||
|
|
|
||||||
227
src/network/nm/settings.cpp
Normal file
227
src/network/nm/settings.cpp
Normal file
|
|
@ -0,0 +1,227 @@
|
||||||
|
#include "settings.hpp"
|
||||||
|
|
||||||
|
#include <qcontainerfwd.h>
|
||||||
|
#include <qdbusconnection.h>
|
||||||
|
#include <qdbusmetatype.h>
|
||||||
|
#include <qdbuspendingcall.h>
|
||||||
|
#include <qdbuspendingreply.h>
|
||||||
|
#include <qdebug.h>
|
||||||
|
#include <qlogging.h>
|
||||||
|
#include <qloggingcategory.h>
|
||||||
|
#include <qmetatype.h>
|
||||||
|
#include <qobject.h>
|
||||||
|
#include <qstring.h>
|
||||||
|
#include <qtmetamacros.h>
|
||||||
|
#include <qtypes.h>
|
||||||
|
|
||||||
|
#include "../../core/logcat.hpp"
|
||||||
|
#include "../../dbus/properties.hpp"
|
||||||
|
#include "dbus_nm_connection_settings.h"
|
||||||
|
#include "dbus_types.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
|
namespace qs::network {
|
||||||
|
using namespace qs::dbus;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
QS_LOGGING_CATEGORY(logNetworkManager, "quickshell.network", QtWarningMsg);
|
||||||
|
QS_LOGGING_CATEGORY(logNMSettings, "quickshell.network.nm_settings", QtWarningMsg);
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
NMSettings::NMSettings(const QString& path, QObject* parent): QObject(parent) {
|
||||||
|
qDBusRegisterMetaType<QList<QVariantMap>>();
|
||||||
|
qDBusRegisterMetaType<QList<quint32>>();
|
||||||
|
qDBusRegisterMetaType<QList<QList<quint32>>>();
|
||||||
|
qDBusRegisterMetaType<QList<QByteArray>>();
|
||||||
|
qDBusRegisterMetaType<NMIPv6Address>();
|
||||||
|
qDBusRegisterMetaType<QList<NMIPv6Address>>();
|
||||||
|
qDBusRegisterMetaType<NMIPv6Route>();
|
||||||
|
qDBusRegisterMetaType<QList<NMIPv6Route>>();
|
||||||
|
|
||||||
|
this->proxy = new DBusNMConnectionSettingsProxy(
|
||||||
|
"org.freedesktop.NetworkManager",
|
||||||
|
path,
|
||||||
|
QDBusConnection::systemBus(),
|
||||||
|
this
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!this->proxy->isValid()) {
|
||||||
|
qCWarning(logNetworkManager) << "Cannot create DBus interface for connection settings at"
|
||||||
|
<< path;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
this->proxy,
|
||||||
|
&DBusNMConnectionSettingsProxy::Updated,
|
||||||
|
this,
|
||||||
|
&NMSettings::getSettings
|
||||||
|
);
|
||||||
|
|
||||||
|
this->bId.setBinding([this]() { return this->bSettings.value()["connection"]["id"].toString(); });
|
||||||
|
this->bUuid.setBinding([this]() {
|
||||||
|
return this->bSettings.value()["connection"]["uuid"].toString();
|
||||||
|
});
|
||||||
|
|
||||||
|
this->settingsProperties.setInterface(this->proxy);
|
||||||
|
this->settingsProperties.updateAllViaGetAll();
|
||||||
|
|
||||||
|
this->getSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NMSettings::getSettings() {
|
||||||
|
auto pending = this->proxy->GetSettings();
|
||||||
|
auto* call = new QDBusPendingCallWatcher(pending, this);
|
||||||
|
|
||||||
|
auto responseCallback = [this](QDBusPendingCallWatcher* call) {
|
||||||
|
const QDBusPendingReply<NMSettingsMap> reply = *call;
|
||||||
|
|
||||||
|
if (reply.isError()) {
|
||||||
|
qCWarning(logNetworkManager)
|
||||||
|
<< "Failed to get settings for" << this->path() << ":" << reply.error().message();
|
||||||
|
} else {
|
||||||
|
auto settings = reply.value();
|
||||||
|
manualSettingDemarshall(settings);
|
||||||
|
this->bSettings = settings;
|
||||||
|
qCDebug(logNetworkManager) << "Settings map updated for" << this->path();
|
||||||
|
|
||||||
|
if (!this->mLoaded) {
|
||||||
|
emit this->loaded();
|
||||||
|
this->mLoaded = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
delete call;
|
||||||
|
};
|
||||||
|
|
||||||
|
QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
QDBusPendingCallWatcher* NMSettings::updateSettings(
|
||||||
|
const NMSettingsMap& settingsToChange,
|
||||||
|
const NMSettingsMap& settingsToRemove
|
||||||
|
) {
|
||||||
|
auto settings = removeSettingsInMap(this->bSettings, settingsToRemove);
|
||||||
|
settings = mergeSettingsMaps(settings, settingsToChange);
|
||||||
|
auto pending = this->proxy->Update(settings);
|
||||||
|
auto* call = new QDBusPendingCallWatcher(pending, this);
|
||||||
|
|
||||||
|
return call;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NMSettings::clearSecrets() {
|
||||||
|
auto pending = this->proxy->ClearSecrets();
|
||||||
|
auto* call = new QDBusPendingCallWatcher(pending, this);
|
||||||
|
|
||||||
|
auto responseCallback = [this](QDBusPendingCallWatcher* call) {
|
||||||
|
const QDBusPendingReply<> reply = *call;
|
||||||
|
|
||||||
|
if (reply.isError()) {
|
||||||
|
qCWarning(logNetworkManager)
|
||||||
|
<< "Failed to clear secrets for" << this->path() << ":" << reply.error().message();
|
||||||
|
} else {
|
||||||
|
qCDebug(logNetworkManager) << "Cleared secrets for" << this->path();
|
||||||
|
}
|
||||||
|
delete call;
|
||||||
|
};
|
||||||
|
|
||||||
|
QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NMSettings::forget() {
|
||||||
|
auto pending = this->proxy->Delete();
|
||||||
|
auto* call = new QDBusPendingCallWatcher(pending, this);
|
||||||
|
|
||||||
|
auto responseCallback = [this](QDBusPendingCallWatcher* call) {
|
||||||
|
const QDBusPendingReply<> reply = *call;
|
||||||
|
|
||||||
|
if (reply.isError()) {
|
||||||
|
qCWarning(logNetworkManager)
|
||||||
|
<< "Failed to forget" << this->path() << ":" << reply.error().message();
|
||||||
|
} else {
|
||||||
|
qCDebug(logNetworkManager) << "Successfully deletion of" << this->path();
|
||||||
|
}
|
||||||
|
delete call;
|
||||||
|
};
|
||||||
|
|
||||||
|
QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap NMSettings::read() {
|
||||||
|
QVariantMap result;
|
||||||
|
const auto& settings = this->bSettings.value();
|
||||||
|
for (auto it = settings.constBegin(); it != settings.constEnd(); ++it) {
|
||||||
|
QVariantMap group;
|
||||||
|
for (auto jt = it.value().constBegin(); jt != it.value().constEnd(); ++jt) {
|
||||||
|
group.insert(jt.key(), settingTypeToQml(jt.value()));
|
||||||
|
}
|
||||||
|
result.insert(it.key(), group);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NMSettings::write(const QVariantMap& settings) {
|
||||||
|
NMSettingsMap changedSettings;
|
||||||
|
NMSettingsMap removedSettings;
|
||||||
|
QStringList failedSettings;
|
||||||
|
|
||||||
|
for (auto it = settings.constBegin(); it != settings.constEnd(); ++it) {
|
||||||
|
if (!it.value().canConvert<QVariantMap>()) continue;
|
||||||
|
|
||||||
|
auto group = it.value().toMap();
|
||||||
|
QVariantMap toChange;
|
||||||
|
QVariantMap toRemove;
|
||||||
|
for (auto jt = group.constBegin(); jt != group.constEnd(); ++jt) {
|
||||||
|
if (jt.value().isNull()) {
|
||||||
|
toRemove.insert(jt.key(), QVariant());
|
||||||
|
} else {
|
||||||
|
auto converted = settingTypeFromQml(it.key(), jt.key(), jt.value());
|
||||||
|
if (!converted.isValid()) failedSettings.append(it.key() + "." + jt.key());
|
||||||
|
else toChange.insert(jt.key(), converted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!toChange.isEmpty()) changedSettings.insert(it.key(), toChange);
|
||||||
|
if (!toRemove.isEmpty()) removedSettings.insert(it.key(), toRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!failedSettings.isEmpty()) {
|
||||||
|
qCWarning(logNMSettings) << "A write to" << this
|
||||||
|
<< "has received bad types for the following settings:"
|
||||||
|
<< failedSettings.join(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* call = this->updateSettings(changedSettings, removedSettings);
|
||||||
|
|
||||||
|
auto responseCallback = [this](QDBusPendingCallWatcher* call) {
|
||||||
|
const QDBusPendingReply<> reply = *call;
|
||||||
|
|
||||||
|
if (reply.isError()) {
|
||||||
|
qCWarning(logNetworkManager)
|
||||||
|
<< "Failed to update settings for" << this->path() << ":" << reply.error().message();
|
||||||
|
} else {
|
||||||
|
qCDebug(logNMSettings) << "Successful write to" << this;
|
||||||
|
}
|
||||||
|
delete call;
|
||||||
|
};
|
||||||
|
|
||||||
|
QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NMSettings::isValid() const { return this->proxy && this->proxy->isValid(); }
|
||||||
|
QString NMSettings::address() const { return this->proxy ? this->proxy->service() : QString(); }
|
||||||
|
QString NMSettings::path() const { return this->proxy ? this->proxy->path() : QString(); }
|
||||||
|
|
||||||
|
} // namespace qs::network
|
||||||
|
|
||||||
|
QDebug operator<<(QDebug debug, const qs::network::NMSettings* settings) {
|
||||||
|
auto saver = QDebugStateSaver(debug);
|
||||||
|
|
||||||
|
if (settings) {
|
||||||
|
debug.nospace() << "NMSettings(" << static_cast<const void*>(settings)
|
||||||
|
<< ", uuid=" << settings->uuid() << ")";
|
||||||
|
} else {
|
||||||
|
debug << "WifiNetwork(nullptr)";
|
||||||
|
}
|
||||||
|
|
||||||
|
return debug;
|
||||||
|
}
|
||||||
82
src/network/nm/settings.hpp
Normal file
82
src/network/nm/settings.hpp
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qbytearray.h>
|
||||||
|
#include <qdbusextratypes.h>
|
||||||
|
#include <qdbuspendingcall.h>
|
||||||
|
#include <qdbuspendingreply.h>
|
||||||
|
#include <qobject.h>
|
||||||
|
#include <qproperty.h>
|
||||||
|
#include <qqmlintegration.h>
|
||||||
|
#include <qstringlist.h>
|
||||||
|
#include <qtmetamacros.h>
|
||||||
|
#include <qtypes.h>
|
||||||
|
|
||||||
|
#include "../../dbus/properties.hpp"
|
||||||
|
#include "dbus_nm_connection_settings.h"
|
||||||
|
#include "dbus_types.hpp"
|
||||||
|
|
||||||
|
namespace qs::network {
|
||||||
|
|
||||||
|
// Proxy of a /org/freedesktop/NetworkManager/Settings/Connection/* object.
|
||||||
|
///! A NetworkManager connection settings profile.
|
||||||
|
class NMSettings: public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
QML_ELEMENT;
|
||||||
|
QML_UNCREATABLE("");
|
||||||
|
|
||||||
|
/// The human-readable unique identifier for the connection.
|
||||||
|
Q_PROPERTY(QString id READ default NOTIFY idChanged BINDABLE bindableId);
|
||||||
|
/// A universally unique identifier for the connection.
|
||||||
|
Q_PROPERTY(QString uuid READ uuid NOTIFY uuidChanged BINDABLE bindableUuid);
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit NMSettings(const QString& path, QObject* parent = nullptr);
|
||||||
|
|
||||||
|
/// Clear all of the secrets belonging to the settings.
|
||||||
|
Q_INVOKABLE void clearSecrets();
|
||||||
|
/// Delete the settings.
|
||||||
|
Q_INVOKABLE void forget();
|
||||||
|
/// Update the connection with new settings and save the connection to disk.
|
||||||
|
/// Only changed fields need to be included.
|
||||||
|
/// Writing a setting to `null` will remove the setting or reset it to its default.
|
||||||
|
///
|
||||||
|
/// > [!NOTE] Secrets may be part of the update request,
|
||||||
|
/// > and will be either stored in persistent storage or sent to a Secret Agent for storage,
|
||||||
|
/// > depending on the flags associated with each secret.
|
||||||
|
Q_INVOKABLE void write(const QVariantMap& settings);
|
||||||
|
/// Get the settings map describing this network configuration.
|
||||||
|
///
|
||||||
|
/// > [!NOTE] This will never include any secrets required for connection to the network, as those are often protected.
|
||||||
|
Q_INVOKABLE QVariantMap read();
|
||||||
|
|
||||||
|
[[nodiscard]] bool isValid() const;
|
||||||
|
[[nodiscard]] QString path() const;
|
||||||
|
[[nodiscard]] QString address() const;
|
||||||
|
[[nodiscard]] NMSettingsMap map() { return this->bSettings; }
|
||||||
|
QDBusPendingCallWatcher*
|
||||||
|
updateSettings(const NMSettingsMap& settingsToChange, const NMSettingsMap& settingsToRemove = {});
|
||||||
|
QBindable<QString> bindableId() { return &this->bId; }
|
||||||
|
[[nodiscard]] QString uuid() const { return this->bUuid; }
|
||||||
|
QBindable<QString> bindableUuid() { return &this->bUuid; }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void loaded();
|
||||||
|
void settingsChanged(NMSettingsMap settings);
|
||||||
|
void idChanged(QString id);
|
||||||
|
void uuidChanged(QString uuid);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool mLoaded = false;
|
||||||
|
|
||||||
|
void getSettings();
|
||||||
|
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(NMSettings, NMSettingsMap, bSettings, &NMSettings::settingsChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(NMSettings, QString, bId, &NMSettings::idChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(NMSettings, QString, bUuid, &NMSettings::uuidChanged);
|
||||||
|
QS_DBUS_BINDABLE_PROPERTY_GROUP(NMSettings, settingsProperties);
|
||||||
|
DBusNMConnectionSettingsProxy* proxy = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace qs::network
|
||||||
|
|
||||||
|
QDebug operator<<(QDebug debug, const qs::network::NMSettings* settings);
|
||||||
|
|
@ -1,27 +1,28 @@
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
|
#include <cmath>
|
||||||
// We depend on non-std Linux extensions that ctime doesn't put in the global namespace
|
// We depend on non-std Linux extensions that ctime doesn't put in the global namespace
|
||||||
// NOLINTNEXTLINE(modernize-deprecated-headers)
|
// NOLINTNEXTLINE(modernize-deprecated-headers)
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include <qcontainerfwd.h>
|
#include <qcontainerfwd.h>
|
||||||
#include <qdatetime.h>
|
#include <qdatetime.h>
|
||||||
|
#include <qdbusargument.h>
|
||||||
#include <qdbusservicewatcher.h>
|
#include <qdbusservicewatcher.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qqmlintegration.h>
|
#include <qqmlintegration.h>
|
||||||
#include <qtypes.h>
|
#include <qtypes.h>
|
||||||
|
|
||||||
#include "../wifi.hpp"
|
#include "../enums.hpp"
|
||||||
#include "dbus_types.hpp"
|
#include "dbus_types.hpp"
|
||||||
#include "enums.hpp"
|
#include "enums.hpp"
|
||||||
|
|
||||||
namespace qs::network {
|
namespace qs::network {
|
||||||
|
|
||||||
WifiSecurityType::Enum securityFromConnectionSettings(const ConnectionSettingsMap& settings) {
|
WifiSecurityType::Enum securityFromSettingsMap(const NMSettingsMap& settings) {
|
||||||
const QVariantMap& security = settings.value("802-11-wireless-security");
|
const QString mapName = "802-11-wireless-security";
|
||||||
if (security.isEmpty()) {
|
if (!settings.contains(mapName)) return WifiSecurityType::Unknown;
|
||||||
return WifiSecurityType::Open;
|
const QVariantMap& security = settings.value(mapName);
|
||||||
};
|
if (security.isEmpty()) return WifiSecurityType::Open;
|
||||||
|
|
||||||
const QString keyMgmt = security["key-mgmt"].toString();
|
const QString keyMgmt = security["key-mgmt"].toString();
|
||||||
const QString authAlg = security["auth-alg"].toString();
|
const QString authAlg = security["auth-alg"].toString();
|
||||||
|
|
@ -45,6 +46,8 @@ WifiSecurityType::Enum securityFromConnectionSettings(const ConnectionSettingsMa
|
||||||
return WifiSecurityType::Sae;
|
return WifiSecurityType::Sae;
|
||||||
} else if (keyMgmt == "wpa-eap-suite-b-192") {
|
} else if (keyMgmt == "wpa-eap-suite-b-192") {
|
||||||
return WifiSecurityType::Wpa3SuiteB192;
|
return WifiSecurityType::Wpa3SuiteB192;
|
||||||
|
} else if (keyMgmt == "owe") {
|
||||||
|
return WifiSecurityType::Owe;
|
||||||
}
|
}
|
||||||
return WifiSecurityType::Open;
|
return WifiSecurityType::Open;
|
||||||
}
|
}
|
||||||
|
|
@ -224,6 +227,280 @@ WifiSecurityType::Enum findBestWirelessSecurity(
|
||||||
return WifiSecurityType::Unknown;
|
return WifiSecurityType::Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NMSettingsMap mergeSettingsMaps(const NMSettingsMap& target, const NMSettingsMap& source) {
|
||||||
|
NMSettingsMap result = target;
|
||||||
|
for (auto iter = source.constBegin(); iter != source.constEnd(); ++iter) {
|
||||||
|
result[iter.key()].insert(iter.value());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
NMSettingsMap removeSettingsInMap(const NMSettingsMap& target, const NMSettingsMap& toRemove) {
|
||||||
|
NMSettingsMap result = target;
|
||||||
|
for (auto iter = toRemove.constBegin(); iter != toRemove.constEnd(); ++iter) {
|
||||||
|
const QString& group = iter.key();
|
||||||
|
const QVariantMap& keysToRemove = iter.value();
|
||||||
|
|
||||||
|
if (!result.contains(group)) continue;
|
||||||
|
|
||||||
|
for (auto jt = keysToRemove.constBegin(); jt != keysToRemove.constEnd(); ++jt) {
|
||||||
|
result[group].remove(jt.key());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the group entirely if it's now empty
|
||||||
|
if (result[group].isEmpty()) {
|
||||||
|
result.remove(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some NMSettingsMap settings remain QDBusArguments after autodemarshalling.
|
||||||
|
// Manually demarshall these for any complex signature we have registered.
|
||||||
|
void manualSettingDemarshall(NMSettingsMap& map) {
|
||||||
|
auto demarshallValue = [](const QVariant& value) -> QVariant {
|
||||||
|
if (value.userType() != qMetaTypeId<QDBusArgument>()) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto arg = value.value<QDBusArgument>();
|
||||||
|
auto signature = arg.currentSignature();
|
||||||
|
|
||||||
|
if (signature == "ay") return QVariant::fromValue(qdbus_cast<QByteArray>(arg));
|
||||||
|
if (signature == "aay") return QVariant::fromValue(qdbus_cast<QList<QByteArray>>(arg));
|
||||||
|
if (signature == "au") return QVariant::fromValue(qdbus_cast<QList<quint32>>(arg));
|
||||||
|
if (signature == "aau") return QVariant::fromValue(qdbus_cast<QList<QList<quint32>>>(arg));
|
||||||
|
if (signature == "aa{sv}") return QVariant::fromValue(qdbus_cast<QList<QVariantMap>>(arg));
|
||||||
|
if (signature == "a(ayuay)") return QVariant::fromValue(qdbus_cast<QList<NMIPv6Address>>(arg));
|
||||||
|
if (signature == "a(ayuayu)") return QVariant::fromValue(qdbus_cast<QList<NMIPv6Route>>(arg));
|
||||||
|
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto it = map.begin(); it != map.end(); ++it)
|
||||||
|
for (auto jt = it.value().begin(); jt != it.value().end(); ++jt)
|
||||||
|
jt.value() = demarshallValue(jt.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some NMSettingsMap setting types can't be expressed in QML.
|
||||||
|
// Convert these settings to their correct type or return an invalid QVariant.
|
||||||
|
QVariant settingTypeFromQml(const QString& group, const QString& key, const QVariant& value) {
|
||||||
|
auto s = group + "." + key;
|
||||||
|
|
||||||
|
// QString -> QByteArray
|
||||||
|
if (s == "802-1x.ca-cert" || s == "802-1x.client-cert" || s == "802-1x.private-key"
|
||||||
|
|| s == "802-1x.password-raw" || s == "802-1x.phase2-ca-cert"
|
||||||
|
|| s == "802-1x.phase2-client-cert" || s == "802-1x.phase2-private-key"
|
||||||
|
|| s == "802-11-wireless.ssid")
|
||||||
|
{
|
||||||
|
if (value.typeId() == QMetaType::QString) {
|
||||||
|
return value.toString().toUtf8();
|
||||||
|
}
|
||||||
|
if (value.typeId() == QMetaType::QByteArray) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
// QVariantList -> QList<QByteArray>
|
||||||
|
if (s == "ipv6.dns") {
|
||||||
|
if (value.typeId() == QMetaType::QVariantList) {
|
||||||
|
QList<QByteArray> r;
|
||||||
|
for (const auto& v: value.toList()) {
|
||||||
|
if (v.typeId() == QMetaType::QString) {
|
||||||
|
r.append(v.toString().toUtf8());
|
||||||
|
} else {
|
||||||
|
r.append(v.toByteArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant::fromValue(r);
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
// QVariantList -> QList<quint32>
|
||||||
|
if (s == "ipv4.dns") {
|
||||||
|
if (value.typeId() == QMetaType::QVariantList) {
|
||||||
|
QList<quint32> r;
|
||||||
|
for (const auto& v: value.toList()) {
|
||||||
|
r.append(v.value<quint32>());
|
||||||
|
}
|
||||||
|
return QVariant::fromValue(r);
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
// QVariantList -> QList<QList<quint32>>
|
||||||
|
if (s == "ipv4.addresses" || s == "ipv4.routes") {
|
||||||
|
if (value.typeId() == QMetaType::QVariantList) {
|
||||||
|
QList<QList<quint32>> r;
|
||||||
|
for (const auto& v: value.toList()) {
|
||||||
|
if (v.typeId() != QMetaType::QVariantList) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
QList<quint32> inner;
|
||||||
|
for (const auto& u: v.toList()) {
|
||||||
|
inner.append(u.value<quint32>());
|
||||||
|
}
|
||||||
|
r.append(inner);
|
||||||
|
}
|
||||||
|
return QVariant::fromValue(r);
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
// QVariantList -> QList<QVariantMap>
|
||||||
|
if (s == "ipv4.address-data" || s == "ipv4.route-data" || s == "ipv4.routing-rules"
|
||||||
|
|| s == "ipv6.address-data" || s == "ipv6.route-data" || s == "ipv6.routing-rules")
|
||||||
|
{
|
||||||
|
if (value.typeId() == QMetaType::QVariantList) {
|
||||||
|
QList<QVariantMap> r;
|
||||||
|
for (const auto& v: value.toList()) {
|
||||||
|
if (!v.canConvert<QVariantMap>()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
r.append(v.toMap());
|
||||||
|
}
|
||||||
|
return QVariant::fromValue(r);
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
// QVariantList -> QList<NMIPv6Address>
|
||||||
|
if (s == "ipv6.addresses") {
|
||||||
|
if (value.typeId() == QMetaType::QVariantList) {
|
||||||
|
QList<NMIPv6Address> r;
|
||||||
|
for (const auto& v: value.toList()) {
|
||||||
|
if (v.typeId() != QMetaType::QVariantList) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto fields = v.toList();
|
||||||
|
if (fields.size() != 3) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const QByteArray address = fields[0].typeId() == QMetaType::QString
|
||||||
|
? fields[0].toString().toUtf8()
|
||||||
|
: fields[0].toByteArray();
|
||||||
|
const QByteArray gateway = fields[2].typeId() == QMetaType::QString
|
||||||
|
? fields[2].toString().toUtf8()
|
||||||
|
: fields[2].toByteArray();
|
||||||
|
r.append({.address = address, .prefix = fields[1].value<quint32>(), .gateway = gateway});
|
||||||
|
}
|
||||||
|
return QVariant::fromValue(r);
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
// QVariantList -> QList<NMIPv6Route>
|
||||||
|
if (s == "ipv6.routes") {
|
||||||
|
if (value.typeId() == QMetaType::QVariantList) {
|
||||||
|
QList<NMIPv6Route> r;
|
||||||
|
for (const auto& v: value.toList()) {
|
||||||
|
if (v.typeId() != QMetaType::QVariantList) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto fields = v.toList();
|
||||||
|
if (fields.size() != 4) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const QByteArray destination = fields[0].typeId() == QMetaType::QString
|
||||||
|
? fields[0].toString().toUtf8()
|
||||||
|
: fields[0].toByteArray();
|
||||||
|
const QByteArray nexthop = fields[2].typeId() == QMetaType::QString
|
||||||
|
? fields[2].toString().toUtf8()
|
||||||
|
: fields[2].toByteArray();
|
||||||
|
r.append(
|
||||||
|
{.destination = destination,
|
||||||
|
.prefix = fields[1].value<quint32>(),
|
||||||
|
.nexthop = nexthop,
|
||||||
|
.metric = fields[3].value<quint32>()}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return QVariant::fromValue(r);
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
// QVariantList -> QStringList
|
||||||
|
if (s == "connection.permissions" || s == "ipv4.dns-search" || s == "ipv6.dns-search"
|
||||||
|
|| s == "802-11-wireless.seen-bssids")
|
||||||
|
{
|
||||||
|
if (value.typeId() == QMetaType::QVariantList) {
|
||||||
|
QStringList stringList;
|
||||||
|
for (const auto& item: value.toList()) {
|
||||||
|
stringList.append(item.toString());
|
||||||
|
}
|
||||||
|
return stringList;
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
// double (whole number) -> qint32
|
||||||
|
if (value.typeId() == QMetaType::Double) {
|
||||||
|
auto num = value.toDouble();
|
||||||
|
if (std::isfinite(num) && num == std::trunc(num)) {
|
||||||
|
return QVariant::fromValue(static_cast<qint32>(num));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some NMSettingsMap setting types must be converted to a type that is supported by QML.
|
||||||
|
// Although QByteArrays can be represented in QML, we convert them to strings for convenience.
|
||||||
|
QVariant settingTypeToQml(const QVariant& value) {
|
||||||
|
// QByteArray -> QString
|
||||||
|
if (value.typeId() == QMetaType::QByteArray) {
|
||||||
|
return QString::fromUtf8(value.toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
// QList<QByteArray> -> QVariantList
|
||||||
|
if (value.userType() == qMetaTypeId<QList<QByteArray>>()) {
|
||||||
|
QVariantList out;
|
||||||
|
for (const auto& ba: value.value<QList<QByteArray>>()) {
|
||||||
|
out.append(QString::fromUtf8(ba));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// QList<NMIPv6Address> -> QVariantList
|
||||||
|
if (value.userType() == qMetaTypeId<QList<NMIPv6Address>>()) {
|
||||||
|
QVariantList out;
|
||||||
|
for (const auto& addr: value.value<QList<NMIPv6Address>>()) {
|
||||||
|
out.append(
|
||||||
|
QVariant::fromValue(
|
||||||
|
QVariantList {
|
||||||
|
QString::fromUtf8(addr.address),
|
||||||
|
addr.prefix,
|
||||||
|
QString::fromUtf8(addr.gateway),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// QList<NMIPv6Route> -> QVariantList
|
||||||
|
if (value.userType() == qMetaTypeId<QList<NMIPv6Route>>()) {
|
||||||
|
QVariantList out;
|
||||||
|
for (const auto& route: value.value<QList<NMIPv6Route>>()) {
|
||||||
|
out.append(
|
||||||
|
QVariant::fromValue(
|
||||||
|
QVariantList {
|
||||||
|
QString::fromUtf8(route.destination),
|
||||||
|
route.prefix,
|
||||||
|
QString::fromUtf8(route.nexthop),
|
||||||
|
route.metric,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
// NOLINTBEGIN
|
// NOLINTBEGIN
|
||||||
QDateTime clockBootTimeToDateTime(qint64 clockBootTime) {
|
QDateTime clockBootTimeToDateTime(qint64 clockBootTime) {
|
||||||
clockid_t clkId = CLOCK_BOOTTIME;
|
clockid_t clkId = CLOCK_BOOTTIME;
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,14 @@
|
||||||
#include <qcontainerfwd.h>
|
#include <qcontainerfwd.h>
|
||||||
#include <qdbusservicewatcher.h>
|
#include <qdbusservicewatcher.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qqmlintegration.h>
|
|
||||||
|
|
||||||
#include "../wifi.hpp"
|
#include "../enums.hpp"
|
||||||
#include "dbus_types.hpp"
|
#include "dbus_types.hpp"
|
||||||
#include "enums.hpp"
|
#include "enums.hpp"
|
||||||
|
|
||||||
namespace qs::network {
|
namespace qs::network {
|
||||||
|
|
||||||
WifiSecurityType::Enum securityFromConnectionSettings(const ConnectionSettingsMap& settings);
|
WifiSecurityType::Enum securityFromSettingsMap(const NMSettingsMap& settings);
|
||||||
|
|
||||||
bool deviceSupportsApCiphers(
|
bool deviceSupportsApCiphers(
|
||||||
NMWirelessCapabilities::Enum caps,
|
NMWirelessCapabilities::Enum caps,
|
||||||
|
|
@ -40,6 +39,16 @@ WifiSecurityType::Enum findBestWirelessSecurity(
|
||||||
NM80211ApSecurityFlags::Enum apRsn
|
NM80211ApSecurityFlags::Enum apRsn
|
||||||
);
|
);
|
||||||
|
|
||||||
|
NMSettingsMap mergeSettingsMaps(const NMSettingsMap& target, const NMSettingsMap& source);
|
||||||
|
|
||||||
|
NMSettingsMap removeSettingsInMap(const NMSettingsMap& target, const NMSettingsMap& toRemove);
|
||||||
|
|
||||||
|
void manualSettingDemarshall(NMSettingsMap& map);
|
||||||
|
|
||||||
|
QVariant settingTypeFromQml(const QString& group, const QString& key, const QVariant& value);
|
||||||
|
|
||||||
|
QVariant settingTypeToQml(const QVariant& value);
|
||||||
|
|
||||||
QDateTime clockBootTimeToDateTime(qint64 clockBootTime);
|
QDateTime clockBootTimeToDateTime(qint64 clockBootTime);
|
||||||
|
|
||||||
} // namespace qs::network
|
} // namespace qs::network
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "wireless.hpp"
|
#include "wireless.hpp"
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include <qcontainerfwd.h>
|
||||||
#include <qdatetime.h>
|
#include <qdatetime.h>
|
||||||
#include <qdbusconnection.h>
|
#include <qdbusconnection.h>
|
||||||
#include <qdbusextratypes.h>
|
#include <qdbusextratypes.h>
|
||||||
|
|
@ -11,20 +12,23 @@
|
||||||
#include <qloggingcategory.h>
|
#include <qloggingcategory.h>
|
||||||
#include <qnamespace.h>
|
#include <qnamespace.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
|
#include <qpointer.h>
|
||||||
#include <qstring.h>
|
#include <qstring.h>
|
||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
#include <qtypes.h>
|
#include <qtypes.h>
|
||||||
|
#include <qvariant.h>
|
||||||
|
|
||||||
#include "../../core/logcat.hpp"
|
#include "../../core/logcat.hpp"
|
||||||
#include "../../dbus/properties.hpp"
|
#include "../../dbus/properties.hpp"
|
||||||
#include "../network.hpp"
|
#include "../enums.hpp"
|
||||||
#include "../wifi.hpp"
|
#include "../wifi.hpp"
|
||||||
#include "accesspoint.hpp"
|
#include "accesspoint.hpp"
|
||||||
#include "connection.hpp"
|
#include "active_connection.hpp"
|
||||||
#include "dbus_nm_wireless.h"
|
#include "dbus_nm_wireless.h"
|
||||||
#include "dbus_types.hpp"
|
#include "dbus_types.hpp"
|
||||||
#include "device.hpp"
|
#include "device.hpp"
|
||||||
#include "enums.hpp"
|
#include "enums.hpp"
|
||||||
|
#include "settings.hpp"
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
|
|
||||||
namespace qs::network {
|
namespace qs::network {
|
||||||
|
|
@ -42,38 +46,43 @@ NMWirelessNetwork::NMWirelessNetwork(QString ssid, QObject* parent)
|
||||||
, bReason(NMConnectionStateReason::None)
|
, bReason(NMConnectionStateReason::None)
|
||||||
, bState(NMConnectionState::Deactivated) {}
|
, bState(NMConnectionState::Deactivated) {}
|
||||||
|
|
||||||
void NMWirelessNetwork::updateReferenceConnection() {
|
void NMWirelessNetwork::updateReferenceSettings() {
|
||||||
// If the network has no connections, the reference is nullptr.
|
// If the network has no connections, the reference is nullptr.
|
||||||
if (this->mConnections.isEmpty()) {
|
if (this->mSettings.isEmpty()) {
|
||||||
this->mReferenceConn = nullptr;
|
this->mReferenceSettings = nullptr;
|
||||||
this->bSecurity = WifiSecurityType::Unknown;
|
this->bSecurity = WifiSecurityType::Unknown;
|
||||||
// Set security back to reference AP.
|
|
||||||
if (this->mReferenceAp) {
|
if (this->mReferenceAp) {
|
||||||
this->bSecurity.setBinding([this]() { return this->mReferenceAp->security(); });
|
this->bSecurity.setBinding([this]() { return this->mReferenceAp->security(); });
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// If the network has an active connection, use it as the reference.
|
// If the network has an active connection, use its settings as the reference.
|
||||||
if (this->mActiveConnection) {
|
if (this->mActiveConnection) {
|
||||||
auto* conn = this->mConnections.value(this->mActiveConnection->connection().path());
|
auto* settings = this->mSettings.value(this->mActiveConnection->connection().path());
|
||||||
if (conn && conn != this->mReferenceConn) {
|
if (settings && settings != this->mReferenceSettings) {
|
||||||
this->mReferenceConn = conn;
|
this->mReferenceSettings = settings;
|
||||||
this->bSecurity.setBinding([conn]() { return conn->security(); });
|
this->bSecurity.setBinding([settings]() { return securityFromSettingsMap(settings->map()); });
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, choose the connection with the strongest security settings.
|
// Otherwise, choose the settings responsible for the last successful connection.
|
||||||
NMConnectionSettings* selectedConn = nullptr;
|
NMSettings* selectedSettings = nullptr;
|
||||||
for (auto* conn: this->mConnections.values()) {
|
quint64 selectedTimestamp = 0;
|
||||||
if (!selectedConn || conn->security() > selectedConn->security()) {
|
for (auto* settings: this->mSettings.values()) {
|
||||||
selectedConn = conn;
|
const quint64 timestamp = settings->map()["connection"]["timestamp"].toULongLong();
|
||||||
|
if (!selectedSettings || timestamp > selectedTimestamp) {
|
||||||
|
selectedSettings = settings;
|
||||||
|
selectedTimestamp = timestamp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this->mReferenceConn != selectedConn) {
|
|
||||||
this->mReferenceConn = selectedConn;
|
if (this->mReferenceSettings != selectedSettings) {
|
||||||
this->bSecurity.setBinding([selectedConn]() { return selectedConn->security(); });
|
this->mReferenceSettings = selectedSettings;
|
||||||
|
this->bSecurity.setBinding([selectedSettings]() {
|
||||||
|
return securityFromSettingsMap(selectedSettings->map());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,7 +110,7 @@ void NMWirelessNetwork::updateReferenceAp() {
|
||||||
this->mReferenceAp = selectedAp;
|
this->mReferenceAp = selectedAp;
|
||||||
this->bSignalStrength.setBinding([selectedAp]() { return selectedAp->signalStrength(); });
|
this->bSignalStrength.setBinding([selectedAp]() { return selectedAp->signalStrength(); });
|
||||||
// Reference AP is used for security when there's no connection settings.
|
// Reference AP is used for security when there's no connection settings.
|
||||||
if (!this->mReferenceConn) {
|
if (!this->mReferenceSettings) {
|
||||||
this->bSecurity.setBinding([selectedAp]() { return selectedAp->security(); });
|
this->bSecurity.setBinding([selectedAp]() { return selectedAp->security(); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -113,7 +122,7 @@ void NMWirelessNetwork::addAccessPoint(NMAccessPoint* ap) {
|
||||||
auto onDestroyed = [this, ap]() {
|
auto onDestroyed = [this, ap]() {
|
||||||
if (this->mAccessPoints.take(ap->path())) {
|
if (this->mAccessPoints.take(ap->path())) {
|
||||||
this->updateReferenceAp();
|
this->updateReferenceAp();
|
||||||
if (this->mAccessPoints.isEmpty() && this->mConnections.isEmpty()) emit this->disappeared();
|
if (this->mAccessPoints.isEmpty() && this->mSettings.isEmpty()) emit this->disappeared();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
@ -123,44 +132,45 @@ void NMWirelessNetwork::addAccessPoint(NMAccessPoint* ap) {
|
||||||
this->updateReferenceAp();
|
this->updateReferenceAp();
|
||||||
};
|
};
|
||||||
|
|
||||||
void NMWirelessNetwork::addConnection(NMConnectionSettings* conn) {
|
void NMWirelessNetwork::addSettings(NMSettings* settings) {
|
||||||
if (this->mConnections.contains(conn->path())) return;
|
if (this->mSettings.contains(settings->path())) return;
|
||||||
this->mConnections.insert(conn->path(), conn);
|
this->mSettings.insert(settings->path(), settings);
|
||||||
auto onDestroyed = [this, conn]() {
|
|
||||||
if (this->mConnections.take(conn->path())) {
|
auto onDestroyed = [this, settings]() {
|
||||||
this->updateReferenceConnection();
|
if (this->mSettings.take(settings->path())) {
|
||||||
if (this->mConnections.isEmpty()) this->bKnown = false;
|
emit this->settingsRemoved(settings);
|
||||||
if (this->mAccessPoints.isEmpty() && this->mConnections.isEmpty()) emit this->disappeared();
|
this->updateReferenceSettings();
|
||||||
|
if (this->mSettings.isEmpty()) this->bKnown = false;
|
||||||
|
if (this->mAccessPoints.isEmpty() && this->mSettings.isEmpty()) emit this->disappeared();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// clang-format off
|
QObject::connect(settings, &NMSettings::destroyed, this, onDestroyed);
|
||||||
QObject::connect(conn, &NMConnectionSettings::securityChanged, this, &NMWirelessNetwork::updateReferenceConnection);
|
|
||||||
QObject::connect(conn, &NMConnectionSettings::destroyed, this, onDestroyed);
|
|
||||||
// clang-format on
|
|
||||||
this->bKnown = true;
|
this->bKnown = true;
|
||||||
this->updateReferenceConnection();
|
this->updateReferenceSettings();
|
||||||
|
emit this->settingsAdded(settings);
|
||||||
};
|
};
|
||||||
|
|
||||||
void NMWirelessNetwork::addActiveConnection(NMActiveConnection* active) {
|
void NMWirelessNetwork::addActiveConnection(NMActiveConnection* active) {
|
||||||
if (this->mActiveConnection) return;
|
if (this->mActiveConnection) return;
|
||||||
this->mActiveConnection = active;
|
this->mActiveConnection = active;
|
||||||
|
|
||||||
this->bState.setBinding([active]() { return active->state(); });
|
this->bState.setBinding([active]() { return active->state(); });
|
||||||
this->bReason.setBinding([active]() { return active->stateReason(); });
|
this->bReason.setBinding([active]() { return active->stateReason(); });
|
||||||
auto onDestroyed = [this, active]() {
|
auto onDestroyed = [this, active]() {
|
||||||
if (this->mActiveConnection && this->mActiveConnection == active) {
|
if (this->mActiveConnection && this->mActiveConnection == active) {
|
||||||
this->mActiveConnection = nullptr;
|
this->mActiveConnection = nullptr;
|
||||||
this->updateReferenceConnection();
|
this->updateReferenceSettings();
|
||||||
this->bState = NMConnectionState::Deactivated;
|
this->bState = NMConnectionState::Deactivated;
|
||||||
this->bReason = NMConnectionStateReason::None;
|
this->bReason = NMConnectionStateReason::None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
QObject::connect(active, &NMActiveConnection::destroyed, this, onDestroyed);
|
QObject::connect(active, &NMActiveConnection::destroyed, this, onDestroyed);
|
||||||
this->updateReferenceConnection();
|
this->updateReferenceSettings();
|
||||||
};
|
};
|
||||||
|
|
||||||
void NMWirelessNetwork::forget() {
|
void NMWirelessNetwork::forget() {
|
||||||
if (this->mConnections.isEmpty()) return;
|
if (this->mSettings.isEmpty()) return;
|
||||||
for (auto* conn: this->mConnections.values()) {
|
for (auto* conn: this->mSettings.values()) {
|
||||||
conn->forget();
|
conn->forget();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -200,7 +210,7 @@ void NMWirelessDevice::initWireless() {
|
||||||
QObject::connect(this->wirelessProxy, &DBusNMWirelessProxy::AccessPointAdded, this, &NMWirelessDevice::onAccessPointAdded);
|
QObject::connect(this->wirelessProxy, &DBusNMWirelessProxy::AccessPointAdded, this, &NMWirelessDevice::onAccessPointAdded);
|
||||||
QObject::connect(this->wirelessProxy, &DBusNMWirelessProxy::AccessPointRemoved, this, &NMWirelessDevice::onAccessPointRemoved);
|
QObject::connect(this->wirelessProxy, &DBusNMWirelessProxy::AccessPointRemoved, this, &NMWirelessDevice::onAccessPointRemoved);
|
||||||
QObject::connect(this, &NMWirelessDevice::accessPointLoaded, this, &NMWirelessDevice::onAccessPointLoaded);
|
QObject::connect(this, &NMWirelessDevice::accessPointLoaded, this, &NMWirelessDevice::onAccessPointLoaded);
|
||||||
QObject::connect(this, &NMWirelessDevice::connectionLoaded, this, &NMWirelessDevice::onConnectionLoaded);
|
QObject::connect(this, &NMWirelessDevice::settingsLoaded, this, &NMWirelessDevice::onSettingsLoaded);
|
||||||
QObject::connect(this, &NMWirelessDevice::activeConnectionLoaded, this, &NMWirelessDevice::onActiveConnectionLoaded);
|
QObject::connect(this, &NMWirelessDevice::activeConnectionLoaded, this, &NMWirelessDevice::onActiveConnectionLoaded);
|
||||||
QObject::connect(this, &NMWirelessDevice::scanningChanged, this, &NMWirelessDevice::onScanningChanged);
|
QObject::connect(this, &NMWirelessDevice::scanningChanged, this, &NMWirelessDevice::onScanningChanged);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
@ -218,6 +228,7 @@ void NMWirelessDevice::onAccessPointRemoved(const QDBusObjectPath& path) {
|
||||||
<< "which is not registered.";
|
<< "which is not registered.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
qCDebug(logNetworkManager) << "Access point removed:" << path.path();
|
||||||
delete ap;
|
delete ap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,28 +244,26 @@ void NMWirelessDevice::onAccessPointLoaded(NMAccessPoint* ap) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NMWirelessDevice::onConnectionLoaded(NMConnectionSettings* conn) {
|
void NMWirelessDevice::onSettingsLoaded(NMSettings* settings) {
|
||||||
const ConnectionSettingsMap& settings = conn->settings();
|
const NMSettingsMap& map = settings->map();
|
||||||
// Filter connections that aren't wireless or have missing settings
|
// Filter connections that aren't wireless or have missing settings
|
||||||
if (settings["connection"]["id"].toString().isEmpty()
|
if (map["connection"]["id"].toString().isEmpty() || map["connection"]["uuid"].toString().isEmpty()
|
||||||
|| settings["connection"]["uuid"].toString().isEmpty()
|
|| !map.contains("802-11-wireless") || map["802-11-wireless"]["ssid"].toString().isEmpty())
|
||||||
|| !settings.contains("802-11-wireless")
|
|
||||||
|| settings["802-11-wireless"]["ssid"].toString().isEmpty())
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto ssid = settings["802-11-wireless"]["ssid"].toString();
|
const auto ssid = map["802-11-wireless"]["ssid"].toString();
|
||||||
const auto mode = settings["802-11-wireless"]["mode"].toString();
|
const auto mode = map["802-11-wireless"]["mode"].toString();
|
||||||
|
|
||||||
if (mode == "infrastructure") {
|
if (mode == "infrastructure") {
|
||||||
auto* net = this->mNetworks.value(ssid);
|
auto* net = this->mNetworks.value(ssid);
|
||||||
if (!net) net = this->registerNetwork(ssid);
|
if (!net) net = this->registerNetwork(ssid);
|
||||||
net->addConnection(conn);
|
net->addSettings(settings);
|
||||||
|
|
||||||
// Check for active connections that loaded before their respective connection settings
|
// Check for active connections that loaded before their respective connection settings
|
||||||
auto* active = this->activeConnection();
|
auto* active = this->activeConnection();
|
||||||
if (active && conn->path() == active->connection().path()) {
|
if (active && settings->path() == active->connection().path()) {
|
||||||
net->addActiveConnection(active);
|
net->addActiveConnection(active);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -265,8 +274,8 @@ void NMWirelessDevice::onActiveConnectionLoaded(NMActiveConnection* active) {
|
||||||
// Find an exisiting network with connection settings that matches the active
|
// Find an exisiting network with connection settings that matches the active
|
||||||
const QString activeConnPath = active->connection().path();
|
const QString activeConnPath = active->connection().path();
|
||||||
for (const auto& net: this->mNetworks.values()) {
|
for (const auto& net: this->mNetworks.values()) {
|
||||||
for (auto* conn: net->connections()) {
|
for (auto* settings: net->settings()) {
|
||||||
if (activeConnPath == conn->path()) {
|
if (activeConnPath == settings->path()) {
|
||||||
net->addActiveConnection(active);
|
net->addActiveConnection(active);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -334,6 +343,7 @@ void NMWirelessDevice::registerAccessPoint(const QString& path) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qCDebug(logNetworkManager) << "Access point added:" << path;
|
||||||
this->mAccessPoints.insert(path, ap);
|
this->mAccessPoints.insert(path, ap);
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
ap,
|
ap,
|
||||||
|
|
@ -356,22 +366,18 @@ void NMWirelessDevice::registerAccessPoint(const QString& path) {
|
||||||
NMWirelessNetwork* NMWirelessDevice::registerNetwork(const QString& ssid) {
|
NMWirelessNetwork* NMWirelessDevice::registerNetwork(const QString& ssid) {
|
||||||
auto* net = new NMWirelessNetwork(ssid, this);
|
auto* net = new NMWirelessNetwork(ssid, this);
|
||||||
|
|
||||||
// To avoid exposing outdated state to the frontend, filter the backend networks to only show
|
|
||||||
// the known or currently connected networks when the scanner is off.
|
|
||||||
auto visible = [this, net]() {
|
auto visible = [this, net]() {
|
||||||
return this->bScanning || net->state() == NMConnectionState::Activated || net->known();
|
return this->bScanning || net->state() == NMConnectionState::Activated || net->known();
|
||||||
};
|
};
|
||||||
auto onVisibilityChanged = [this, net](bool visible) {
|
|
||||||
visible ? this->registerFrontendNetwork(net) : this->removeFrontendNetwork(net);
|
|
||||||
};
|
|
||||||
|
|
||||||
net->bindableVisible().setBinding(visible);
|
net->bindableVisible().setBinding(visible);
|
||||||
net->bindableActiveApPath().setBinding([this]() { return this->activeApPath().path(); });
|
net->bindableActiveApPath().setBinding([this]() { return this->activeApPath().path(); });
|
||||||
|
net->bindableDeviceFailReason().setBinding([this]() { return this->lastFailReason(); });
|
||||||
QObject::connect(net, &NMWirelessNetwork::disappeared, this, &NMWirelessDevice::removeNetwork);
|
QObject::connect(net, &NMWirelessNetwork::disappeared, this, &NMWirelessDevice::removeNetwork);
|
||||||
QObject::connect(net, &NMWirelessNetwork::visibilityChanged, this, onVisibilityChanged);
|
|
||||||
|
|
||||||
|
qCDebug(logNetworkManager) << "Registered network for SSID" << ssid;
|
||||||
this->mNetworks.insert(ssid, net);
|
this->mNetworks.insert(ssid, net);
|
||||||
if (net->visible()) this->registerFrontendNetwork(net);
|
this->registerFrontendNetwork(net);
|
||||||
return net;
|
return net;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -385,46 +391,137 @@ void NMWirelessDevice::registerFrontendNetwork(NMWirelessNetwork* net) {
|
||||||
frontendNet->bindableSignalStrength().setBinding(translateSignal);
|
frontendNet->bindableSignalStrength().setBinding(translateSignal);
|
||||||
frontendNet->bindableConnected().setBinding(translateState);
|
frontendNet->bindableConnected().setBinding(translateState);
|
||||||
frontendNet->bindableKnown().setBinding([net]() { return net->known(); });
|
frontendNet->bindableKnown().setBinding([net]() { return net->known(); });
|
||||||
frontendNet->bindableNmReason().setBinding([net]() { return net->reason(); });
|
|
||||||
frontendNet->bindableSecurity().setBinding([net]() { return net->security(); });
|
frontendNet->bindableSecurity().setBinding([net]() { return net->security(); });
|
||||||
frontendNet->bindableState().setBinding([net]() {
|
frontendNet->bindableState().setBinding([net]() {
|
||||||
return static_cast<NetworkState::Enum>(net->state());
|
return static_cast<ConnectionState::Enum>(net->state());
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(net, &NMWirelessNetwork::reasonChanged, this, [net, frontendNet]() {
|
||||||
|
if (net->reason() == NMConnectionStateReason::DeviceDisconnected) {
|
||||||
|
auto deviceReason = net->deviceFailReason();
|
||||||
|
if (deviceReason == NMDeviceStateReason::NoSecrets)
|
||||||
|
emit frontendNet->connectionFailed(ConnectionFailReason::NoSecrets);
|
||||||
|
if (deviceReason == NMDeviceStateReason::SupplicantDisconnect)
|
||||||
|
emit frontendNet->connectionFailed(ConnectionFailReason::WifiClientDisconnected);
|
||||||
|
if (deviceReason == NMDeviceStateReason::SupplicantFailed)
|
||||||
|
emit frontendNet->connectionFailed(ConnectionFailReason::WifiClientFailed);
|
||||||
|
if (deviceReason == NMDeviceStateReason::SupplicantTimeout)
|
||||||
|
emit frontendNet->connectionFailed(ConnectionFailReason::WifiAuthTimeout);
|
||||||
|
if (deviceReason == NMDeviceStateReason::SsidNotFound)
|
||||||
|
emit frontendNet->connectionFailed(ConnectionFailReason::WifiNetworkLost);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(frontendNet, &WifiNetwork::requestConnect, this, [this, net]() {
|
QObject::connect(frontendNet, &WifiNetwork::requestConnect, this, [this, net]() {
|
||||||
if (net->referenceConnection()) {
|
if (net->referenceSettings()) {
|
||||||
emit this->activateConnection(
|
emit this->activateConnection(
|
||||||
QDBusObjectPath(net->referenceConnection()->path()),
|
QDBusObjectPath(net->referenceSettings()->path()),
|
||||||
QDBusObjectPath(this->path())
|
QDBusObjectPath(this->path())
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (net->referenceAp()) {
|
if (net->referenceAp()) {
|
||||||
emit this->addAndActivateConnection(
|
emit this->addAndActivateConnection(
|
||||||
ConnectionSettingsMap(),
|
NMSettingsMap(),
|
||||||
QDBusObjectPath(this->path()),
|
QDBusObjectPath(this->path()),
|
||||||
QDBusObjectPath(net->referenceAp()->path())
|
QDBusObjectPath(net->referenceAp()->path())
|
||||||
);
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
qCInfo(logNetworkManager) << "Failed to connect to"
|
||||||
|
<< this->path() + ": The network disappeared.";
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
frontendNet,
|
frontendNet,
|
||||||
&WifiNetwork::requestDisconnect,
|
&WifiNetwork::requestConnectWithPsk,
|
||||||
this,
|
this,
|
||||||
&NMWirelessDevice::disconnect
|
[this, net](const QString& psk) {
|
||||||
|
NMSettingsMap settings;
|
||||||
|
settings["802-11-wireless-security"]["psk"] = psk;
|
||||||
|
if (const QPointer<NMSettings> ref = net->referenceSettings()) {
|
||||||
|
auto* call = ref->updateSettings(settings);
|
||||||
|
QObject::connect(
|
||||||
|
call,
|
||||||
|
&QDBusPendingCallWatcher::finished,
|
||||||
|
this,
|
||||||
|
[this, ref](QDBusPendingCallWatcher* call) {
|
||||||
|
const QDBusPendingReply<> reply = *call;
|
||||||
|
|
||||||
|
if (reply.isError()) {
|
||||||
|
qCInfo(logNetworkManager)
|
||||||
|
<< "Failed to write PSK for" << this->path() + ":" << reply.error().message();
|
||||||
|
} else {
|
||||||
|
if (!ref) {
|
||||||
|
qCInfo(logNetworkManager) << "Failed to connectWithPsk to"
|
||||||
|
<< this->path() + ": The settings disappeared.";
|
||||||
|
} else {
|
||||||
|
emit this->activateConnection(
|
||||||
|
QDBusObjectPath(ref->path()),
|
||||||
|
QDBusObjectPath(this->path())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete call;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (net->referenceAp()) {
|
||||||
|
emit this->addAndActivateConnection(
|
||||||
|
settings,
|
||||||
|
QDBusObjectPath(this->path()),
|
||||||
|
QDBusObjectPath(net->referenceAp()->path())
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qCInfo(logNetworkManager) << "Failed to connectWithPsk to"
|
||||||
|
<< this->path() + ": The network disappeared.";
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
frontendNet,
|
||||||
|
&WifiNetwork::requestConnectWithSettings,
|
||||||
|
this,
|
||||||
|
[this](NMSettings* settings) {
|
||||||
|
if (settings) {
|
||||||
|
emit this->activateConnection(
|
||||||
|
QDBusObjectPath(settings->path()),
|
||||||
|
QDBusObjectPath(this->path())
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qCInfo(logNetworkManager) << "Failed to connectWithSettings to"
|
||||||
|
<< this->path() + ": The provided settings no longer exist.";
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
net,
|
||||||
|
&NMWirelessNetwork::visibilityChanged,
|
||||||
|
this,
|
||||||
|
[this, frontendNet](bool visible) {
|
||||||
|
if (visible) this->networkAdded(frontendNet);
|
||||||
|
else this->networkRemoved(frontendNet);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
QObject::connect(frontendNet, &WifiNetwork::requestDisconnect, this, &NMWirelessDevice::disconnect);
|
||||||
QObject::connect(frontendNet, &WifiNetwork::requestForget, net, &NMWirelessNetwork::forget);
|
QObject::connect(frontendNet, &WifiNetwork::requestForget, net, &NMWirelessNetwork::forget);
|
||||||
|
QObject::connect(net, &NMWirelessNetwork::settingsAdded, frontendNet, &WifiNetwork::settingsAdded);
|
||||||
|
QObject::connect(net, &NMWirelessNetwork::settingsRemoved, frontendNet, &WifiNetwork::settingsRemoved);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
this->mFrontendNetworks.insert(ssid, frontendNet);
|
this->mFrontendNetworks.insert(ssid, frontendNet);
|
||||||
emit this->networkAdded(frontendNet);
|
if (net->visible()) emit this->networkAdded(frontendNet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NMWirelessDevice::removeFrontendNetwork(NMWirelessNetwork* net) {
|
void NMWirelessDevice::removeFrontendNetwork(NMWirelessNetwork* net) {
|
||||||
auto* frontendNet = this->mFrontendNetworks.take(net->ssid());
|
auto* frontendNet = this->mFrontendNetworks.take(net->ssid());
|
||||||
if (frontendNet) {
|
if (frontendNet) {
|
||||||
emit this->networkRemoved(frontendNet);
|
if (net->visible()) emit this->networkRemoved(frontendNet);
|
||||||
frontendNet->deleteLater();
|
frontendNet->deleteLater();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,11 @@
|
||||||
|
|
||||||
#include "../wifi.hpp"
|
#include "../wifi.hpp"
|
||||||
#include "accesspoint.hpp"
|
#include "accesspoint.hpp"
|
||||||
#include "connection.hpp"
|
#include "active_connection.hpp"
|
||||||
#include "dbus_nm_wireless.h"
|
#include "dbus_nm_wireless.h"
|
||||||
#include "device.hpp"
|
#include "device.hpp"
|
||||||
#include "enums.hpp"
|
#include "enums.hpp"
|
||||||
|
#include "settings.hpp"
|
||||||
|
|
||||||
namespace qs::dbus {
|
namespace qs::dbus {
|
||||||
template <>
|
template <>
|
||||||
|
|
@ -32,7 +33,7 @@ struct DBusDataTransform<QDateTime> {
|
||||||
} // namespace qs::dbus
|
} // namespace qs::dbus
|
||||||
namespace qs::network {
|
namespace qs::network {
|
||||||
|
|
||||||
// NMWirelessNetwork aggregates all related NMActiveConnection, NMAccessPoint, and NMConnectionSetting objects.
|
// NMWirelessNetwork aggregates all related NMActiveConnection, NMAccessPoint, and NMSettings objects.
|
||||||
class NMWirelessNetwork: public QObject {
|
class NMWirelessNetwork: public QObject {
|
||||||
Q_OBJECT;
|
Q_OBJECT;
|
||||||
|
|
||||||
|
|
@ -40,46 +41,51 @@ public:
|
||||||
explicit NMWirelessNetwork(QString ssid, QObject* parent = nullptr);
|
explicit NMWirelessNetwork(QString ssid, QObject* parent = nullptr);
|
||||||
|
|
||||||
void addAccessPoint(NMAccessPoint* ap);
|
void addAccessPoint(NMAccessPoint* ap);
|
||||||
void addConnection(NMConnectionSettings* conn);
|
void addSettings(NMSettings* settings);
|
||||||
void addActiveConnection(NMActiveConnection* active);
|
void addActiveConnection(NMActiveConnection* active);
|
||||||
void forget();
|
void forget();
|
||||||
|
|
||||||
[[nodiscard]] QString ssid() const { return this->mSsid; };
|
// clang-format off
|
||||||
[[nodiscard]] quint8 signalStrength() const { return this->bSignalStrength; };
|
[[nodiscard]] QString ssid() const { return this->mSsid; }
|
||||||
[[nodiscard]] WifiSecurityType::Enum security() const { return this->bSecurity; };
|
[[nodiscard]] quint8 signalStrength() const { return this->bSignalStrength; }
|
||||||
[[nodiscard]] NMConnectionState::Enum state() const { return this->bState; };
|
[[nodiscard]] WifiSecurityType::Enum security() const { return this->bSecurity; }
|
||||||
[[nodiscard]] bool known() const { return this->bKnown; };
|
[[nodiscard]] NMConnectionState::Enum state() const { return this->bState; }
|
||||||
[[nodiscard]] NMConnectionStateReason::Enum reason() const { return this->bReason; };
|
[[nodiscard]] bool known() const { return this->bKnown; }
|
||||||
[[nodiscard]] NMAccessPoint* referenceAp() const { return this->mReferenceAp; };
|
[[nodiscard]] NMConnectionStateReason::Enum reason() const { return this->bReason; }
|
||||||
[[nodiscard]] NMConnectionSettings* referenceConnection() const { return this->mReferenceConn; };
|
QBindable<NMDeviceStateReason::Enum> bindableDeviceFailReason() { return &this->bDeviceFailReason; }
|
||||||
[[nodiscard]] QList<NMAccessPoint*> accessPoints() const { return this->mAccessPoints.values(); };
|
[[nodiscard]] NMDeviceStateReason::Enum deviceFailReason() const { return this->bDeviceFailReason; }
|
||||||
[[nodiscard]] QList<NMConnectionSettings*> connections() const {
|
[[nodiscard]] NMAccessPoint* referenceAp() const { return this->mReferenceAp; }
|
||||||
return this->mConnections.values();
|
[[nodiscard]] QList<NMAccessPoint*> accessPoints() const { return this->mAccessPoints.values(); }
|
||||||
}
|
[[nodiscard]] QList<NMSettings*> settings() const { return this->mSettings.values(); }
|
||||||
[[nodiscard]] QBindable<QString> bindableActiveApPath() { return &this->bActiveApPath; };
|
[[nodiscard]] NMSettings* referenceSettings() const { return this->mReferenceSettings; }
|
||||||
[[nodiscard]] QBindable<bool> bindableVisible() { return &this->bVisible; };
|
QBindable<QString> bindableActiveApPath() { return &this->bActiveApPath; }
|
||||||
[[nodiscard]] bool visible() const { return this->bVisible; };
|
QBindable<bool> bindableVisible() { return &this->bVisible; }
|
||||||
|
bool visible() const { return this->bVisible; }
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void disappeared();
|
void disappeared();
|
||||||
|
void settingsAdded(NMSettings* settings);
|
||||||
|
void settingsRemoved(NMSettings* settings);
|
||||||
void visibilityChanged(bool visible);
|
void visibilityChanged(bool visible);
|
||||||
void signalStrengthChanged(quint8 signal);
|
void signalStrengthChanged(quint8 signal);
|
||||||
void stateChanged(NMConnectionState::Enum state);
|
void stateChanged(NMConnectionState::Enum state);
|
||||||
void knownChanged(bool known);
|
void knownChanged(bool known);
|
||||||
void securityChanged(WifiSecurityType::Enum security);
|
void securityChanged(WifiSecurityType::Enum security);
|
||||||
void reasonChanged(NMConnectionStateReason::Enum reason);
|
void reasonChanged(NMConnectionStateReason::Enum reason);
|
||||||
|
void deviceFailReasonChanged(NMDeviceStateReason::Enum reason);
|
||||||
void capabilitiesChanged(NMWirelessCapabilities::Enum caps);
|
void capabilitiesChanged(NMWirelessCapabilities::Enum caps);
|
||||||
void activeApPathChanged(QString path);
|
void activeApPathChanged(QString path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateReferenceAp();
|
void updateReferenceAp();
|
||||||
void updateReferenceConnection();
|
void updateReferenceSettings();
|
||||||
|
|
||||||
QString mSsid;
|
QString mSsid;
|
||||||
QHash<QString, NMAccessPoint*> mAccessPoints;
|
QHash<QString, NMAccessPoint*> mAccessPoints;
|
||||||
QHash<QString, NMConnectionSettings*> mConnections;
|
QHash<QString, NMSettings*> mSettings;
|
||||||
NMAccessPoint* mReferenceAp = nullptr;
|
NMAccessPoint* mReferenceAp = nullptr;
|
||||||
NMConnectionSettings* mReferenceConn = nullptr;
|
NMSettings* mReferenceSettings = nullptr;
|
||||||
NMActiveConnection* mActiveConnection = nullptr;
|
NMActiveConnection* mActiveConnection = nullptr;
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
@ -88,6 +94,7 @@ private:
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NMWirelessNetwork, WifiSecurityType::Enum, bSecurity, &NMWirelessNetwork::securityChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NMWirelessNetwork, WifiSecurityType::Enum, bSecurity, &NMWirelessNetwork::securityChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NMWirelessNetwork, NMConnectionStateReason::Enum, bReason, &NMWirelessNetwork::reasonChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NMWirelessNetwork, NMConnectionStateReason::Enum, bReason, &NMWirelessNetwork::reasonChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NMWirelessNetwork, NMConnectionState::Enum, bState, &NMWirelessNetwork::stateChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NMWirelessNetwork, NMConnectionState::Enum, bState, &NMWirelessNetwork::stateChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(NMWirelessNetwork, NMDeviceStateReason::Enum, bDeviceFailReason, &NMWirelessNetwork::deviceFailReasonChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NMWirelessNetwork, quint8, bSignalStrength, &NMWirelessNetwork::signalStrengthChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NMWirelessNetwork, quint8, bSignalStrength, &NMWirelessNetwork::signalStrengthChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(NMWirelessNetwork, QString, bActiveApPath, &NMWirelessNetwork::activeApPathChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(NMWirelessNetwork, QString, bActiveApPath, &NMWirelessNetwork::activeApPathChanged);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
@ -103,10 +110,10 @@ public:
|
||||||
explicit NMWirelessDevice(const QString& path, QObject* parent = nullptr);
|
explicit NMWirelessDevice(const QString& path, QObject* parent = nullptr);
|
||||||
|
|
||||||
[[nodiscard]] bool isValid() const override;
|
[[nodiscard]] bool isValid() const override;
|
||||||
[[nodiscard]] NMWirelessCapabilities::Enum capabilities() { return this->bCapabilities; };
|
[[nodiscard]] NMWirelessCapabilities::Enum capabilities() { return this->bCapabilities; }
|
||||||
[[nodiscard]] const QDBusObjectPath& activeApPath() { return this->bActiveAccessPoint; };
|
[[nodiscard]] const QDBusObjectPath& activeApPath() { return this->bActiveAccessPoint; }
|
||||||
[[nodiscard]] NM80211Mode::Enum mode() { return this->bMode; };
|
[[nodiscard]] NM80211Mode::Enum mode() { return this->bMode; }
|
||||||
[[nodiscard]] QBindable<bool> bindableScanning() { return &this->bScanning; };
|
[[nodiscard]] QBindable<bool> bindableScanning() { return &this->bScanning; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void accessPointLoaded(NMAccessPoint* ap);
|
void accessPointLoaded(NMAccessPoint* ap);
|
||||||
|
|
@ -123,7 +130,7 @@ private slots:
|
||||||
void onAccessPointAdded(const QDBusObjectPath& path);
|
void onAccessPointAdded(const QDBusObjectPath& path);
|
||||||
void onAccessPointRemoved(const QDBusObjectPath& path);
|
void onAccessPointRemoved(const QDBusObjectPath& path);
|
||||||
void onAccessPointLoaded(NMAccessPoint* ap);
|
void onAccessPointLoaded(NMAccessPoint* ap);
|
||||||
void onConnectionLoaded(NMConnectionSettings* conn);
|
void onSettingsLoaded(NMSettings* settings);
|
||||||
void onActiveConnectionLoaded(NMActiveConnection* active);
|
void onActiveConnectionLoaded(NMActiveConnection* active);
|
||||||
void onScanTimeout();
|
void onScanTimeout();
|
||||||
void onScanningChanged(bool scanning);
|
void onScanningChanged(bool scanning);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,74 @@ import Quickshell
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import Quickshell.Networking
|
import Quickshell.Networking
|
||||||
|
|
||||||
|
Scope {
|
||||||
|
Component {
|
||||||
|
id: editorComponent
|
||||||
|
FloatingWindow {
|
||||||
|
id: editorWindow
|
||||||
|
required property var nmSettings
|
||||||
|
color: contentItem.palette.window
|
||||||
|
|
||||||
|
Component.onCompleted: editorArea.text = JSON.stringify(nmSettings.read(), null, 2)
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 10
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: "Editing " + nmSettings?.id + " (" + nmSettings?.uuid + ")"
|
||||||
|
font.bold: true
|
||||||
|
font.pointSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
TextArea {
|
||||||
|
id: editorArea
|
||||||
|
wrapMode: TextEdit.Wrap
|
||||||
|
selectByMouse: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Label {
|
||||||
|
id: statusLabel
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: palette.placeholderText
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: "Reload"
|
||||||
|
onClicked: {
|
||||||
|
editorArea.text = JSON.stringify(editorWindow.nmSettings.read(), null, 2);
|
||||||
|
statusLabel.text = "Reloaded";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: "Save"
|
||||||
|
onClicked: {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(editorArea.text);
|
||||||
|
nmSettings.write(parsed);
|
||||||
|
statusLabel.text = "Saved";
|
||||||
|
} catch (e) {
|
||||||
|
statusLabel.text = "Parse error: " + e.message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: "Close"
|
||||||
|
onClicked: {
|
||||||
|
editorArea.focus = false;
|
||||||
|
editorWindow.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FloatingWindow {
|
FloatingWindow {
|
||||||
color: contentItem.palette.window
|
color: contentItem.palette.window
|
||||||
|
|
||||||
|
|
@ -12,13 +80,46 @@ FloatingWindow {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: 5
|
anchors.margins: 5
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Label {
|
||||||
|
text: `Networking (${NetworkBackendType.toString(Networking.backend)} backend)`
|
||||||
|
font.bold: true
|
||||||
|
font.pointSize: 12
|
||||||
|
}
|
||||||
|
RowLayout {
|
||||||
|
Label {
|
||||||
|
text: `Connectivity`
|
||||||
|
font.bold: true
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
text: `${NetworkConnectivity.toString(Networking.connectivity)}`
|
||||||
|
visible: Networking.canCheckConnectivity
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: "Re-check"
|
||||||
|
visible: Networking.canCheckConnectivity && Networking.connectivityCheckEnabled
|
||||||
|
onClicked: Networking.checkConnectivity()
|
||||||
|
}
|
||||||
|
CheckBox {
|
||||||
|
text: "Checking enabled"
|
||||||
|
checked: Networking.connectivityCheckEnabled
|
||||||
|
onClicked: Networking.connectivityCheckEnabled = !Networking.connectivityCheckEnabled
|
||||||
|
visible: Networking.canCheckConnectivity
|
||||||
|
}
|
||||||
|
CheckBox {
|
||||||
|
enabled: false
|
||||||
|
text: "Supported"
|
||||||
|
checked: Networking.canCheckConnectivity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Label {
|
Label {
|
||||||
text: "WiFi"
|
text: "WiFi"
|
||||||
font.bold: true
|
font.bold: true
|
||||||
font.pointSize: 12
|
|
||||||
}
|
}
|
||||||
CheckBox {
|
CheckBox {
|
||||||
text: "Software"
|
text: "Software"
|
||||||
|
|
@ -48,21 +149,29 @@ FloatingWindow {
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Label { text: modelData.name; font.bold: true }
|
Label {
|
||||||
Label { text: modelData.address }
|
text: modelData.name
|
||||||
Label { text: `(Type: ${DeviceType.toString(modelData.type)})` }
|
font.bold: true
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
text: modelData.address
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
text: `(Type: ${DeviceType.toString(modelData.type)})`
|
||||||
|
}
|
||||||
|
CheckBox {
|
||||||
|
text: `Managed`
|
||||||
|
checked: modelData.nmManaged
|
||||||
|
onClicked: modelData.nmManaged = !modelData.nmManaged
|
||||||
|
}
|
||||||
}
|
}
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Label {
|
Label {
|
||||||
text: DeviceConnectionState.toString(modelData.state)
|
text: ConnectionState.toString(modelData.state)
|
||||||
color: modelData.connected ? palette.link : palette.placeholderText
|
color: modelData.connected ? palette.link : palette.placeholderText
|
||||||
}
|
}
|
||||||
Label {
|
|
||||||
visible: Networking.backend == NetworkBackendType.NetworkManager && (modelData.state == DeviceConnectionState.Connecting || modelData.state == DeviceConnectionState.Disconnecting)
|
|
||||||
text: `(${NMDeviceState.toString(modelData.nmState)})`
|
|
||||||
}
|
|
||||||
Button {
|
Button {
|
||||||
visible: modelData.state == DeviceConnectionState.Connected
|
visible: modelData.state == ConnectionState.Connected
|
||||||
text: "Disconnect"
|
text: "Disconnect"
|
||||||
onClicked: modelData.disconnect()
|
onClicked: modelData.disconnect()
|
||||||
}
|
}
|
||||||
|
|
@ -85,17 +194,69 @@ FloatingWindow {
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
model: {
|
model: ScriptModel {
|
||||||
if (modelData.type !== DeviceType.Wifi) return []
|
values: [...modelData.networks.values].sort((a, b) => {
|
||||||
return [...modelData.networks.values].sort((a, b) => {
|
|
||||||
if (a.connected !== b.connected) {
|
if (a.connected !== b.connected) {
|
||||||
return b.connected - a.connected
|
return b.connected - a.connected;
|
||||||
}
|
}
|
||||||
return b.signalStrength - a.signalStrength
|
return b.signalStrength - a.signalStrength;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
WrapperRectangle {
|
WrapperRectangle {
|
||||||
|
property var chosenSettings: {
|
||||||
|
const settings = modelData.nmSettings;
|
||||||
|
if (!settings || settings.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (settings.length === 1) {
|
||||||
|
return settings[0];
|
||||||
|
}
|
||||||
|
return settings[settingsComboBox.currentIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: modelData
|
||||||
|
function onConnectionFailed(reason) {
|
||||||
|
failLoader.sourceComponent = failComponent;
|
||||||
|
failLoader.item.failReason = reason;
|
||||||
|
}
|
||||||
|
function onStateChanged() {
|
||||||
|
if (modelData.state == ConnectionState.Connecting) {
|
||||||
|
failLoader.sourceComponent = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: failComponent
|
||||||
|
RowLayout {
|
||||||
|
property var failReason
|
||||||
|
Label {
|
||||||
|
text: ConnectionFailReason.toString(failReason)
|
||||||
|
}
|
||||||
|
RowLayout {
|
||||||
|
TextField {
|
||||||
|
id: pskField
|
||||||
|
placeholderText: "PSK"
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: "Set"
|
||||||
|
visible: pskField.visible
|
||||||
|
onClicked: {
|
||||||
|
modelData.connectWithPsk(pskField.text);
|
||||||
|
failLoader.sourceComponent = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visible: modelData.security === WifiSecurityType.WpaPsk || modelData.security === WifiSecurityType.Wpa2Psk || modelData.security === WifiSecurityType.Sae
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: "Close"
|
||||||
|
onClicked: failLoader.sourceComponent = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
color: modelData.connected ? palette.highlight : palette.button
|
color: modelData.connected ? palette.highlight : palette.button
|
||||||
border.color: palette.mid
|
border.color: palette.mid
|
||||||
|
|
@ -106,7 +267,10 @@ FloatingWindow {
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Label { text: modelData.name; font.bold: true }
|
Label {
|
||||||
|
text: modelData.name
|
||||||
|
font.bold: true
|
||||||
|
}
|
||||||
Label {
|
Label {
|
||||||
text: modelData.known ? "Known" : ""
|
text: modelData.known ? "Known" : ""
|
||||||
color: palette.placeholderText
|
color: palette.placeholderText
|
||||||
|
|
@ -122,16 +286,40 @@ FloatingWindow {
|
||||||
color: palette.placeholderText
|
color: palette.placeholderText
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Label {
|
|
||||||
visible: Networking.backend == NetworkBackendType.NetworkManager && (modelData.nmReason != NMConnectionStateReason.Unknown && modelData.nmReason != NMConnectionStateReason.None)
|
|
||||||
text: `Connection change reason: ${NMConnectionStateReason.toString(modelData.nmReason)}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
|
BusyIndicator {
|
||||||
|
implicitHeight: 30
|
||||||
|
implicitWidth: 30
|
||||||
|
running: modelData.stateChanging
|
||||||
|
visible: modelData.stateChanging
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
text: ConnectionState.toString(modelData.state)
|
||||||
|
color: modelData.connected ? palette.link : palette.placeholderText
|
||||||
|
}
|
||||||
|
RowLayout {
|
||||||
|
Label {
|
||||||
|
text: "Choose settings:"
|
||||||
|
}
|
||||||
|
ComboBox {
|
||||||
|
id: settingsComboBox
|
||||||
|
model: modelData.nmSettings.map(s => s?.read()?.connection?.id)
|
||||||
|
currentIndex: 0
|
||||||
|
}
|
||||||
|
visible: modelData.nmSettings.length > 1
|
||||||
|
}
|
||||||
Button {
|
Button {
|
||||||
text: "Connect"
|
text: "Connect"
|
||||||
onClicked: modelData.connect()
|
onClicked: {
|
||||||
|
if (chosenSettings)
|
||||||
|
modelData.connectWithSettings(chosenSettings);
|
||||||
|
else
|
||||||
|
modelData.connect();
|
||||||
|
}
|
||||||
visible: !modelData.connected
|
visible: !modelData.connected
|
||||||
}
|
}
|
||||||
Button {
|
Button {
|
||||||
|
|
@ -144,6 +332,23 @@ FloatingWindow {
|
||||||
onClicked: modelData.forget()
|
onClicked: modelData.forget()
|
||||||
visible: modelData.known
|
visible: modelData.known
|
||||||
}
|
}
|
||||||
|
Button {
|
||||||
|
text: "Edit"
|
||||||
|
visible: modelData.known
|
||||||
|
onClicked: {
|
||||||
|
if (chosenSettings)
|
||||||
|
editorComponent.createObject(null, {
|
||||||
|
nmSettings: chosenSettings
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loader {
|
||||||
|
id: failLoader
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
visible: sourceComponent !== null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,99 +6,35 @@
|
||||||
#include <qloggingcategory.h>
|
#include <qloggingcategory.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qstring.h>
|
#include <qstring.h>
|
||||||
|
#include <qtmetamacros.h>
|
||||||
|
|
||||||
#include "../core/logcat.hpp"
|
#include "../core/logcat.hpp"
|
||||||
#include "device.hpp"
|
#include "device.hpp"
|
||||||
|
#include "enums.hpp"
|
||||||
#include "network.hpp"
|
#include "network.hpp"
|
||||||
|
|
||||||
namespace qs::network {
|
namespace qs::network {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
QS_LOGGING_CATEGORY(logWifi, "quickshell.network.wifi", QtWarningMsg);
|
QS_LOGGING_CATEGORY(logWifiNetwork, "quickshell.wifinetwork", QtWarningMsg);
|
||||||
} // namespace
|
|
||||||
|
|
||||||
QString WifiSecurityType::toString(WifiSecurityType::Enum type) {
|
|
||||||
switch (type) {
|
|
||||||
case Unknown: return QStringLiteral("Unknown");
|
|
||||||
case Wpa3SuiteB192: return QStringLiteral("WPA3 Suite B 192-bit");
|
|
||||||
case Sae: return QStringLiteral("WPA3");
|
|
||||||
case Wpa2Eap: return QStringLiteral("WPA2 Enterprise");
|
|
||||||
case Wpa2Psk: return QStringLiteral("WPA2");
|
|
||||||
case WpaEap: return QStringLiteral("WPA Enterprise");
|
|
||||||
case WpaPsk: return QStringLiteral("WPA");
|
|
||||||
case StaticWep: return QStringLiteral("WEP");
|
|
||||||
case DynamicWep: return QStringLiteral("Dynamic WEP");
|
|
||||||
case Leap: return QStringLiteral("LEAP");
|
|
||||||
case Owe: return QStringLiteral("OWE");
|
|
||||||
case Open: return QStringLiteral("Open");
|
|
||||||
default: return QStringLiteral("Unknown");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
QString WifiDeviceMode::toString(WifiDeviceMode::Enum mode) {
|
|
||||||
switch (mode) {
|
|
||||||
case Unknown: return QStringLiteral("Unknown");
|
|
||||||
case AdHoc: return QStringLiteral("Ad-Hoc");
|
|
||||||
case Station: return QStringLiteral("Station");
|
|
||||||
case AccessPoint: return QStringLiteral("Access Point");
|
|
||||||
case Mesh: return QStringLiteral("Mesh");
|
|
||||||
default: return QStringLiteral("Unknown");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
QString NMConnectionStateReason::toString(NMConnectionStateReason::Enum reason) {
|
|
||||||
switch (reason) {
|
|
||||||
case Unknown: return QStringLiteral("Unknown");
|
|
||||||
case None: return QStringLiteral("No reason");
|
|
||||||
case UserDisconnected: return QStringLiteral("User disconnection");
|
|
||||||
case DeviceDisconnected:
|
|
||||||
return QStringLiteral("The device the connection was using was disconnected.");
|
|
||||||
case ServiceStopped:
|
|
||||||
return QStringLiteral("The service providing the VPN connection was stopped.");
|
|
||||||
case IpConfigInvalid:
|
|
||||||
return QStringLiteral("The IP config of the active connection was invalid.");
|
|
||||||
case ConnectTimeout:
|
|
||||||
return QStringLiteral("The connection attempt to the VPN service timed out.");
|
|
||||||
case ServiceStartTimeout:
|
|
||||||
return QStringLiteral(
|
|
||||||
"A timeout occurred while starting the service providing the VPN connection."
|
|
||||||
);
|
|
||||||
case ServiceStartFailed:
|
|
||||||
return QStringLiteral("Starting the service providing the VPN connection failed.");
|
|
||||||
case NoSecrets: return QStringLiteral("Necessary secrets for the connection were not provided.");
|
|
||||||
case LoginFailed: return QStringLiteral("Authentication to the server failed.");
|
|
||||||
case ConnectionRemoved:
|
|
||||||
return QStringLiteral("Necessary secrets for the connection were not provided.");
|
|
||||||
case DependencyFailed:
|
|
||||||
return QStringLiteral("Master connection of this connection failed to activate.");
|
|
||||||
case DeviceRealizeFailed: return QStringLiteral("Could not create the software device link.");
|
|
||||||
case DeviceRemoved: return QStringLiteral("The device this connection depended on disappeared.");
|
|
||||||
default: return QStringLiteral("Unknown");
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
WifiNetwork::WifiNetwork(QString ssid, QObject* parent): Network(std::move(ssid), parent) {};
|
WifiNetwork::WifiNetwork(QString ssid, QObject* parent): Network(std::move(ssid), parent) {};
|
||||||
|
|
||||||
void WifiNetwork::connect() {
|
void WifiNetwork::connectWithPsk(const QString& psk) {
|
||||||
if (this->bConnected) {
|
if (this->bConnected) {
|
||||||
qCCritical(logWifi) << this << "is already connected.";
|
qCCritical(logWifiNetwork) << this << "is already connected.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (this->bSecurity != WifiSecurityType::WpaPsk && this->bSecurity != WifiSecurityType::Wpa2Psk
|
||||||
this->requestConnect();
|
&& this->bSecurity != WifiSecurityType::Sae)
|
||||||
}
|
{
|
||||||
|
qCCritical(logWifiNetwork) << this << "has the wrong security type for a PSK.";
|
||||||
void WifiNetwork::disconnect() {
|
|
||||||
if (!this->bConnected) {
|
|
||||||
qCCritical(logWifi) << this << "is not currently connected";
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
emit this->requestConnectWithPsk(psk);
|
||||||
this->requestDisconnect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WifiNetwork::forget() { this->requestForget(); }
|
|
||||||
|
|
||||||
WifiDevice::WifiDevice(QObject* parent): NetworkDevice(DeviceType::Wifi, parent) {};
|
WifiDevice::WifiDevice(QObject* parent): NetworkDevice(DeviceType::Wifi, parent) {};
|
||||||
|
|
||||||
void WifiDevice::setScannerEnabled(bool enabled) {
|
void WifiDevice::setScannerEnabled(bool enabled) {
|
||||||
|
|
|
||||||
|
|
@ -6,90 +6,15 @@
|
||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
#include <qtypes.h>
|
#include <qtypes.h>
|
||||||
|
|
||||||
|
#include "../core/doc.hpp"
|
||||||
#include "../core/model.hpp"
|
#include "../core/model.hpp"
|
||||||
#include "device.hpp"
|
#include "device.hpp"
|
||||||
|
#include "enums.hpp"
|
||||||
#include "network.hpp"
|
#include "network.hpp"
|
||||||
|
|
||||||
namespace qs::network {
|
namespace qs::network {
|
||||||
|
|
||||||
///! The security type of a wifi network.
|
///! WiFi subtype of @@Network.
|
||||||
class WifiSecurityType: public QObject {
|
|
||||||
Q_OBJECT;
|
|
||||||
QML_ELEMENT;
|
|
||||||
QML_SINGLETON;
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum Enum : quint8 {
|
|
||||||
Wpa3SuiteB192 = 0,
|
|
||||||
Sae = 1,
|
|
||||||
Wpa2Eap = 2,
|
|
||||||
Wpa2Psk = 3,
|
|
||||||
WpaEap = 4,
|
|
||||||
WpaPsk = 5,
|
|
||||||
StaticWep = 6,
|
|
||||||
DynamicWep = 7,
|
|
||||||
Leap = 8,
|
|
||||||
Owe = 9,
|
|
||||||
Open = 10,
|
|
||||||
Unknown = 11,
|
|
||||||
};
|
|
||||||
Q_ENUM(Enum);
|
|
||||||
Q_INVOKABLE static QString toString(WifiSecurityType::Enum type);
|
|
||||||
};
|
|
||||||
|
|
||||||
///! The 802.11 mode of a wifi device.
|
|
||||||
class WifiDeviceMode: public QObject {
|
|
||||||
Q_OBJECT;
|
|
||||||
QML_ELEMENT;
|
|
||||||
QML_SINGLETON;
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum Enum : quint8 {
|
|
||||||
/// The device is part of an Ad-Hoc network without a central access point.
|
|
||||||
AdHoc = 0,
|
|
||||||
/// The device is a station that can connect to networks.
|
|
||||||
Station = 1,
|
|
||||||
/// The device is a local hotspot/access point.
|
|
||||||
AccessPoint = 2,
|
|
||||||
/// The device is an 802.11s mesh point.
|
|
||||||
Mesh = 3,
|
|
||||||
/// The device mode is unknown.
|
|
||||||
Unknown = 4,
|
|
||||||
};
|
|
||||||
Q_ENUM(Enum);
|
|
||||||
Q_INVOKABLE static QString toString(WifiDeviceMode::Enum mode);
|
|
||||||
};
|
|
||||||
|
|
||||||
///! NetworkManager-specific reason for a WifiNetworks connection state.
|
|
||||||
/// In sync with https://networkmanager.dev/docs/api/latest/nm-dbus-types.html#NMActiveConnectionStateReason.
|
|
||||||
class NMConnectionStateReason: public QObject {
|
|
||||||
Q_OBJECT;
|
|
||||||
QML_ELEMENT;
|
|
||||||
QML_SINGLETON;
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum Enum : quint8 {
|
|
||||||
Unknown = 0,
|
|
||||||
None = 1,
|
|
||||||
UserDisconnected = 2,
|
|
||||||
DeviceDisconnected = 3,
|
|
||||||
ServiceStopped = 4,
|
|
||||||
IpConfigInvalid = 5,
|
|
||||||
ConnectTimeout = 6,
|
|
||||||
ServiceStartTimeout = 7,
|
|
||||||
ServiceStartFailed = 8,
|
|
||||||
NoSecrets = 9,
|
|
||||||
LoginFailed = 10,
|
|
||||||
ConnectionRemoved = 11,
|
|
||||||
DependencyFailed = 12,
|
|
||||||
DeviceRealizeFailed = 13,
|
|
||||||
DeviceRemoved = 14
|
|
||||||
};
|
|
||||||
Q_ENUM(Enum);
|
|
||||||
Q_INVOKABLE static QString toString(NMConnectionStateReason::Enum reason);
|
|
||||||
};
|
|
||||||
|
|
||||||
///! An available wifi network.
|
|
||||||
class WifiNetwork: public Network {
|
class WifiNetwork: public Network {
|
||||||
Q_OBJECT;
|
Q_OBJECT;
|
||||||
QML_ELEMENT;
|
QML_ELEMENT;
|
||||||
|
|
@ -97,58 +22,46 @@ class WifiNetwork: public Network {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
/// The current signal strength of the network, from 0.0 to 1.0.
|
/// The current signal strength of the network, from 0.0 to 1.0.
|
||||||
Q_PROPERTY(qreal signalStrength READ default NOTIFY signalStrengthChanged BINDABLE bindableSignalStrength);
|
Q_PROPERTY(qreal signalStrength READ default NOTIFY signalStrengthChanged BINDABLE bindableSignalStrength);
|
||||||
/// True if the wifi network has known connection settings saved.
|
|
||||||
Q_PROPERTY(bool known READ default NOTIFY knownChanged BINDABLE bindableKnown);
|
|
||||||
/// The security type of the wifi network.
|
/// The security type of the wifi network.
|
||||||
Q_PROPERTY(WifiSecurityType::Enum security READ default NOTIFY securityChanged BINDABLE bindableSecurity);
|
Q_PROPERTY(WifiSecurityType::Enum security READ default NOTIFY securityChanged BINDABLE bindableSecurity);
|
||||||
/// A specific reason for the connection state when the backend is NetworkManager.
|
|
||||||
Q_PROPERTY(NMConnectionStateReason::Enum nmReason READ default NOTIFY nmReasonChanged BINDABLE bindableNmReason);
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit WifiNetwork(QString ssid, QObject* parent = nullptr);
|
explicit WifiNetwork(QString ssid, QObject* parent = nullptr);
|
||||||
|
/// Attempt to connect to the network with the given PSK. If the PSK is wrong,
|
||||||
/// Attempt to connect to the wifi network.
|
/// a @@Network.connectionFailed(s) signal will be emitted with `NoSecrets`.
|
||||||
///
|
///
|
||||||
/// > [!WARNING] Quickshell does not yet provide a NetworkManager authentication agent,
|
/// The networking backend may store the PSK for future use with @@Network.connect().
|
||||||
/// > meaning another agent will need to be active to enter passwords for unsaved networks.
|
/// As such, calling that function first is recommended to avoid having to show a
|
||||||
Q_INVOKABLE void connect();
|
/// prompt if not required.
|
||||||
/// Disconnect from the wifi network.
|
///
|
||||||
Q_INVOKABLE void disconnect();
|
/// > [!NOTE] PSKs should only be provided when the @@security is one of
|
||||||
/// Forget all connection settings for this wifi network.
|
/// > `WpaPsk`, `Wpa2Psk`, or `Sae`.
|
||||||
Q_INVOKABLE void forget();
|
Q_INVOKABLE void connectWithPsk(const QString& psk);
|
||||||
|
|
||||||
QBindable<qreal> bindableSignalStrength() { return &this->bSignalStrength; }
|
QBindable<qreal> bindableSignalStrength() { return &this->bSignalStrength; }
|
||||||
QBindable<bool> bindableKnown() { return &this->bKnown; }
|
|
||||||
QBindable<NMConnectionStateReason::Enum> bindableNmReason() { return &this->bNmReason; }
|
|
||||||
QBindable<WifiSecurityType::Enum> bindableSecurity() { return &this->bSecurity; }
|
QBindable<WifiSecurityType::Enum> bindableSecurity() { return &this->bSecurity; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void requestConnect();
|
QSDOC_HIDE void requestConnectWithPsk(QString psk);
|
||||||
void requestDisconnect();
|
|
||||||
void requestForget();
|
|
||||||
void signalStrengthChanged();
|
void signalStrengthChanged();
|
||||||
void knownChanged();
|
|
||||||
void securityChanged();
|
void securityChanged();
|
||||||
void nmReasonChanged();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// clang-format off
|
// clang-format off
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(WifiNetwork, qreal, bSignalStrength, &WifiNetwork::signalStrengthChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(WifiNetwork, qreal, bSignalStrength, &WifiNetwork::signalStrengthChanged);
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(WifiNetwork, bool, bKnown, &WifiNetwork::knownChanged);
|
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(WifiNetwork, NMConnectionStateReason::Enum, bNmReason, &WifiNetwork::nmReasonChanged);
|
|
||||||
Q_OBJECT_BINDABLE_PROPERTY(WifiNetwork, WifiSecurityType::Enum, bSecurity, &WifiNetwork::securityChanged);
|
Q_OBJECT_BINDABLE_PROPERTY(WifiNetwork, WifiSecurityType::Enum, bSecurity, &WifiNetwork::securityChanged);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
};
|
};
|
||||||
|
|
||||||
///! Wireless variant of a NetworkDevice.
|
///! WiFi variant of a @@NetworkDevice.
|
||||||
class WifiDevice: public NetworkDevice {
|
class WifiDevice: public NetworkDevice {
|
||||||
Q_OBJECT;
|
Q_OBJECT;
|
||||||
QML_ELEMENT;
|
QML_ELEMENT;
|
||||||
QML_UNCREATABLE("");
|
QML_UNCREATABLE("");
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
/// A list of this available and connected wifi networks.
|
/// A list of this available or connected wifi networks.
|
||||||
QSDOC_TYPE_OVERRIDE(ObjectModel<WifiNetwork>*);
|
QSDOC_TYPE_OVERRIDE(ObjectModel<WifiNetwork>*);
|
||||||
Q_PROPERTY(UntypedObjectModel* networks READ networks CONSTANT);
|
Q_PROPERTY(UntypedObjectModel* networks READ networks CONSTANT);
|
||||||
/// True when currently scanning for networks.
|
/// True when currently scanning for networks.
|
||||||
|
|
@ -164,9 +77,9 @@ public:
|
||||||
void networkAdded(WifiNetwork* net);
|
void networkAdded(WifiNetwork* net);
|
||||||
void networkRemoved(WifiNetwork* net);
|
void networkRemoved(WifiNetwork* net);
|
||||||
|
|
||||||
[[nodiscard]] ObjectModel<WifiNetwork>* networks() { return &this->mNetworks; };
|
[[nodiscard]] ObjectModel<WifiNetwork>* networks() { return &this->mNetworks; }
|
||||||
QBindable<bool> bindableScannerEnabled() { return &this->bScannerEnabled; };
|
QBindable<bool> bindableScannerEnabled() { return &this->bScannerEnabled; }
|
||||||
[[nodiscard]] bool scannerEnabled() const { return this->bScannerEnabled; };
|
[[nodiscard]] bool scannerEnabled() const { return this->bScannerEnabled; }
|
||||||
void setScannerEnabled(bool enabled);
|
void setScannerEnabled(bool enabled);
|
||||||
QBindable<WifiDeviceMode::Enum> bindableMode() { return &this->bMode; }
|
QBindable<WifiDeviceMode::Enum> bindableMode() { return &this->bMode; }
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue