Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
a7ff484
init: NetworkManager service
cpwrs Jul 3, 2025
e92a9ec
fix: CMake typo
cpwrs Jul 4, 2025
66fa5dc
feat: NetworkManager.state
cpwrs Jul 4, 2025
c3e1280
feat: devices, wifiDevice, device properties
cpwrs Jul 6, 2025
6ee3cb5
hotfix: revert unintended change to upower
cpwrs Jul 6, 2025
8679f79
feat(nix): nm buildInput
cpwrs Jul 9, 2025
3c32d88
test: device basics
cpwrs Jul 9, 2025
0391e02
test: nm state
cpwrs Jul 9, 2025
fdbdf1d
fix: devicetype enum matches NMDeviceType in spec
cpwrs Jul 9, 2025
208cfd0
style: shorten to NM
cpwrs Jul 9, 2025
2504210
Revert "feat(nix): nm buildInput"
cpwrs Jul 9, 2025
d323881
feat: AP, Wireless xml
cpwrs Jul 9, 2025
4705796
fix test
cpwrs Jul 9, 2025
a1515c1
feat: begin wireless
cpwrs Jul 9, 2025
19ac6db
Merge branch 'quickshell-mirror:master' into nm
cpwrs Jul 9, 2025
e445c9b
Quickshell.Network
cpwrs Jul 11, 2025
c4d8fc2
clean
cpwrs Jul 11, 2025
28bf2d7
refactor: nm dir
cpwrs Jul 11, 2025
1d02e1c
fix: log names
cpwrs Jul 11, 2025
112eb66
feat: Wireless
cpwrs Jul 11, 2025
87787dc
feat: frontend slots
cpwrs Jul 14, 2025
bdaaa5f
feat: state, working subdevices
cpwrs Jul 14, 2025
c9ece29
disconnect
cpwrs Jul 15, 2025
997f45b
feat: scan, lastScan, NetworkDeviceType
cpwrs Jul 15, 2025
560232c
feat: accessPoints
cpwrs Jul 16, 2025
7090633
fix: annotate RequestScan a{sv} for qdbusxml2cpp
cpwrs Jul 16, 2025
6429991
feat: AccessPoints -> WifiNetworks
cpwrs Jul 21, 2025
61f8c8f
feat: connected
cpwrs Jul 21, 2025
8b21137
feat: remove lastScan
cpwrs Jul 22, 2025
c955811
refactor: move nm_* to nm/ and seperate adapter classes
cpwrs Jul 23, 2025
e5e0544
feat: backend connections
cpwrs Jul 23, 2025
be80d20
feat: ap flags, device connections
cpwrs Jul 24, 2025
840e6ec
feat: merge backend connections + networks -> WifiNetwork.
cpwrs Jul 28, 2025
c936fb9
feat: add NMActiveConnectionAdapter
cpwrs Aug 4, 2025
c49e825
feat: NMWirelessNetwork holds all wifi network objects
cpwrs Aug 18, 2025
6282af4
fix: show signal of active AP
cpwrs Aug 19, 2025
b12ad1b
refactor: active AP is handled by NMWirelessNetwork
cpwrs Aug 28, 2025
c23b068
chore: cleanup and lint
cpwrs Aug 29, 2025
434f9ee
fix: style, includes, best network Security
cpwrs Sep 4, 2025
c9f70e0
feat: move synced properties to bindables
cpwrs Sep 5, 2025
c4656a7
fix: scanning is bindable on backend
cpwrs Sep 5, 2025
fc69097
fix: setEnabled is WRITE
cpwrs Sep 5, 2025
8fee842
style: whitespace
cpwrs Sep 8, 2025
62ab321
network: fmt, lint, style
cpwrs Sep 25, 2025
6e227a7
network: update API
cpwrs Oct 16, 2025
b031b02
network: add WifiScanner
cpwrs Oct 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ boption(SERVICE_GREETD "Greetd" ON)
boption(SERVICE_UPOWER "UPower" ON)
boption(SERVICE_NOTIFICATIONS "Notifications" ON)
boption(BLUETOOTH "Bluetooth" ON)
boption(NETWORK "Network" ON)

include(cmake/install-qml-module.cmake)
include(cmake/util.cmake)
Expand Down Expand Up @@ -117,7 +118,7 @@ if (WAYLAND)
list(APPEND QT_FPDEPS WaylandClient)
endif()

if (SERVICE_STATUS_NOTIFIER OR SERVICE_MPRIS OR SERVICE_UPOWER OR SERVICE_NOTIFICATIONS OR BLUETOOTH)
if (SERVICE_STATUS_NOTIFIER OR SERVICE_MPRIS OR SERVICE_UPOWER OR SERVICE_NOTIFICATIONS OR BLUETOOTH OR NETWORK)
set(DBUS ON)
endif()

Expand Down
4 changes: 4 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@ add_subdirectory(services)
if (BLUETOOTH)
add_subdirectory(bluetooth)
endif()

if (NETWORK)
add_subdirectory(network)
endif()
95 changes: 95 additions & 0 deletions src/network/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
set_source_files_properties(nm/org.freedesktop.NetworkManager.xml PROPERTIES
CLASSNAME DBusNetworkManagerProxy
NO_NAMESPACE TRUE
INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/nm/dbus_types.hpp
)

qt_add_dbus_interface(NM_DBUS_INTERFACES
nm/org.freedesktop.NetworkManager.xml
nm/dbus_nm_backend
)

set_source_files_properties(nm/org.freedesktop.NetworkManager.Device.xml PROPERTIES
CLASSNAME DBusNMDeviceProxy
NO_NAMESPACE TRUE
)

qt_add_dbus_interface(NM_DBUS_INTERFACES
nm/org.freedesktop.NetworkManager.Device.xml
nm/dbus_nm_device
)

set_source_files_properties(nm/org.freedesktop.NetworkManager.Device.Wireless.xml PROPERTIES
CLASSNAME DBusNMWirelessProxy
NO_NAMESPACE TRUE
)

qt_add_dbus_interface(NM_DBUS_INTERFACES
nm/org.freedesktop.NetworkManager.Device.Wireless.xml
nm/dbus_nm_wireless
)

set_source_files_properties(nm/org.freedesktop.NetworkManager.AccessPoint.xml PROPERTIES
CLASSNAME DBusNMAccessPointProxy
NO_NAMESPACE TRUE
)

qt_add_dbus_interface(NM_DBUS_INTERFACES
nm/org.freedesktop.NetworkManager.AccessPoint.xml
nm/dbus_nm_accesspoint
)

set_source_files_properties(nm/org.freedesktop.NetworkManager.Settings.Connection.xml PROPERTIES
CLASSNAME DBusNMConnectionSettingsProxy
NO_NAMESPACE TRUE
INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/nm/dbus_types.hpp
)

qt_add_dbus_interface(NM_DBUS_INTERFACES
nm/org.freedesktop.NetworkManager.Settings.Connection.xml
nm/dbus_nm_connection_settings
)

set_source_files_properties(nm/org.freedesktop.NetworkManager.Connection.Active.xml PROPERTIES
CLASSNAME DBusNMActiveConnectionProxy
NO_NAMESPACE TRUE
)

qt_add_dbus_interface(NM_DBUS_INTERFACES
nm/org.freedesktop.NetworkManager.Connection.Active.xml
nm/dbus_nm_active_connection
)

qt_add_library(quickshell-network STATIC
network.cpp
device.cpp
wifi.cpp
nm/backend.cpp
nm/device.cpp
nm/connection.cpp
nm/accesspoint.cpp
nm/wireless.cpp
nm/utils.cpp
nm/enums.hpp
${NM_DBUS_INTERFACES}
)

# dbus headers
target_include_directories(quickshell-network PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
)

qt_add_qml_module(quickshell-network
URI Quickshell.Network
VERSION 0.1
DEPENDENCIES QtQml
)

qs_add_module_deps_light(quickshell-network Quickshell)
install_qml_module(quickshell-network)

target_link_libraries(quickshell-network PRIVATE Qt::Qml Qt::DBus)
qs_add_link_dependencies(quickshell-network quickshell-dbus)
target_link_libraries(quickshell PRIVATE quickshell-networkplugin)

qs_module_pch(quickshell-network SET dbus)
72 changes: 72 additions & 0 deletions src/network/device.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include "device.hpp"

#include <qdebug.h>
#include <qlogging.h>
#include <qloggingcategory.h>
#include <qobject.h>
#include <qstringliteral.h>

#include "../core/logcat.hpp"

namespace qs::network {

namespace {
QS_LOGGING_CATEGORY(logNetworkDevice, "quickshell.network.device", QtWarningMsg);
} // 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");
}
}

QString DeviceType::toString(DeviceType::Enum type) {
switch (type) {
case None: return QStringLiteral("None");
case Wifi: return QStringLiteral("Wifi");
}
}

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 whether 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");
};
}

NetworkDevice::NetworkDevice(DeviceType::Enum type, QObject* parent)
: QObject(parent)
, mType(type) {};

void NetworkDevice::disconnect() {
if (this->bState == DeviceConnectionState::Disconnected) {
qCCritical(logNetworkDevice) << "Device" << this << "is already disconnected";
return;
}
if (this->bState == DeviceConnectionState::Disconnecting) {
qCCritical(logNetworkDevice) << "Device" << this << "is already disconnecting";
return;
}
qCDebug(logNetworkDevice) << "Disconnecting from device" << this;
this->requestDisconnect();
}

} // namespace qs::network
122 changes: 122 additions & 0 deletions src/network/device.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#pragma once

#include <qobject.h>
#include <qproperty.h>
#include <qqmlintegration.h>
#include <qtmetamacros.h>
#include <qtypes.h>

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.
class NetworkDevice: public QObject {
Q_OBJECT;
QML_ELEMENT;
QML_UNCREATABLE("Devices can only be acquired through Network");
// clang-format off
/// The device type.
Q_PROPERTY(DeviceType::Enum type READ type CONSTANT);
/// The name of the device's control interface.
Q_PROPERTY(QString name READ name NOTIFY nameChanged BINDABLE bindableName);
/// The hardware address of the device in the XX:XX:XX:XX:XX:XX format.
Q_PROPERTY(QString address READ address NOTIFY addressChanged BINDABLE bindableAddress);
/// Connection state of the device.
Q_PROPERTY(qs::network::DeviceConnectionState::Enum state READ state NOTIFY stateChanged BINDABLE bindableState);
/// A more specific device state when the backend is NetworkManager.
Q_PROPERTY(qs::network::NMDeviceState::Enum nmState READ nmState NOTIFY nmStateChanged BINDABLE bindableNmState);
// clang-format on

public:
explicit NetworkDevice(DeviceType::Enum type, QObject* parent = nullptr);

/// Disconnects the device and prevents it from automatically activating further connections.
Q_INVOKABLE void disconnect();

[[nodiscard]] DeviceType::Enum type() const { return this->mType; };
QBindable<QString> bindableName() { return &this->bName; };
[[nodiscard]] QString name() const { return this->bName; };
QBindable<QString> bindableAddress() { return &this->bAddress; };
[[nodiscard]] QString address() const { return this->bAddress; };
QBindable<DeviceConnectionState::Enum> bindableState() { return &this->bState; };
[[nodiscard]] DeviceConnectionState::Enum state() const { return this->bState; };
QBindable<NMDeviceState::Enum> bindableNmState() { return &this->bNmState; };
[[nodiscard]] NMDeviceState::Enum nmState() const { return this->bNmState; };

signals:
void requestDisconnect();
void nameChanged();
void addressChanged();
void stateChanged();
void nmStateChanged();

private:
DeviceType::Enum mType;
// clang-format off
Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, QString, bName, &NetworkDevice::nameChanged);
Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, QString, bAddress, &NetworkDevice::addressChanged);
Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, DeviceConnectionState::Enum, bState, &NetworkDevice::stateChanged);
Q_OBJECT_BINDABLE_PROPERTY(NetworkDevice, NMDeviceState::Enum, bNmState, &NetworkDevice::nmStateChanged);
// clang-format on
};

} // namespace qs::network
52 changes: 52 additions & 0 deletions src/network/network.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include "network.hpp"
#include <utility>

#include <qlogging.h>
#include <qloggingcategory.h>
#include <qobject.h>
#include <qtmetamacros.h>

#include "../core/logcat.hpp"
#include "device.hpp"
#include "nm/backend.hpp"

namespace qs::network {

namespace {
QS_LOGGING_CATEGORY(logNetwork, "quickshell.network", QtWarningMsg);
} // namespace

Network::Network(QObject* parent): QObject(parent) {
// NetworkManager
auto* nm = new NetworkManager(this);
if (nm->isAvailable()) {
QObject::connect(nm, &NetworkManager::deviceAdded, this, &Network::onDeviceAdded);
QObject::connect(nm, &NetworkManager::deviceRemoved, this, &Network::onDeviceRemoved);
this->bindableWifiEnabled().setBinding([nm]() { return nm->wifiEnabled(); });
this->bindableWifiHardwareEnabled().setBinding([nm]() { return nm->wifiHardwareEnabled(); });
QObject::connect(this, &Network::requestSetWifiEnabled, nm, &NetworkManager::setWifiEnabled);
this->mBackend = nm;
this->mBackendType = NetworkBackendType::NetworkManager;
return;
} else {
delete nm;
}

qCCritical(logNetwork) << "Network will not work. Could not find an available backend.";
}

void Network::onDeviceAdded(NetworkDevice* dev) { this->mDevices.insertObject(dev); }
void Network::onDeviceRemoved(NetworkDevice* dev) { this->mDevices.removeObject(dev); }

void Network::setWifiEnabled(bool enabled) {
if (this->bWifiEnabled == enabled) {
const QString state = enabled ? "enabled" : "disabled";
qCCritical(logNetwork) << "Wifi is already software" << state;
} else {
emit this->requestSetWifiEnabled(enabled);
}
}

BaseNetwork::BaseNetwork(QString name, QObject* parent): QObject(parent), mName(std::move(name)) {};

} // namespace qs::network
Loading