summaryrefslogtreecommitdiff
path: root/overlays
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@yggdrasil.li>2026-10-21 15:05:50 +0200
committerGregor Kleen <gkleen@yggdrasil.li>2026-10-21 15:05:50 +0200
commitebccb33b4eb60a07e667332665181ba9ad352615 (patch)
tree14947c3add7677919250265616f9ab4f5f6b071b /overlays
parentf2c90589d4d4d6c1f101c969d1363729171b3115 (diff)
downloadnixos-ebccb33b4eb60a07e667332665181ba9ad352615.tar
nixos-ebccb33b4eb60a07e667332665181ba9ad352615.tar.gz
nixos-ebccb33b4eb60a07e667332665181ba9ad352615.tar.bz2
nixos-ebccb33b4eb60a07e667332665181ba9ad352615.tar.xz
nixos-ebccb33b4eb60a07e667332665181ba9ad352615.zip
...
Diffstat (limited to 'overlays')
-rw-r--r--overlays/etesync-dav.nix54
-rw-r--r--overlays/etesync.nix14
-rw-r--r--overlays/keepassxc/database-open-dialog.patch129
-rw-r--r--overlays/keepassxc/default.nix113
-rw-r--r--overlays/quickshell/default.nix2
-rw-r--r--overlays/quickshell/pipewire.patch127
6 files changed, 96 insertions, 343 deletions
diff --git a/overlays/etesync-dav.nix b/overlays/etesync-dav.nix
index dbb7c7b6..64f30071 100644
--- a/overlays/etesync-dav.nix
+++ b/overlays/etesync-dav.nix
@@ -1,5 +1,5 @@
1{ final, prev, ... }: { 1{ flakeInputs, final, prev, ... }: {
2 etesync-dav = final.python312Packages.buildPythonApplication rec { 2 etesync-dav = final.python312Packages.buildPythonApplication (finalAttrs: rec {
3 pname = "etesync-dav"; 3 pname = "etesync-dav";
4 version = "0.35.1"; 4 version = "0.35.1";
5 pyproject = true; 5 pyproject = true;
@@ -7,12 +7,23 @@
7 src = prev.fetchFromGitHub { 7 src = prev.fetchFromGitHub {
8 owner = "etesync"; 8 owner = "etesync";
9 repo = "etesync-dav"; 9 repo = "etesync-dav";
10 tag = "v${version}"; 10 tag = "v${finalAttrs.version}";
11 hash = "sha256-y4BhU2kSn+RWqc5+pJQFhbwfat9cMWD0ED0EXJp25cY="; 11 hash = "sha256-y4BhU2kSn+RWqc5+pJQFhbwfat9cMWD0ED0EXJp25cY=";
12 }; 12 };
13 13
14 patches = [
15 (flakeInputs.nixpkgs + "/pkgs/by-name/et/etesync-dav/radicale-3-6-compat.patch")
16 (prev.fetchpatch {
17 url = "https://github.com/etesync/etesync-dav/pull/366.patch";
18 hash = "sha256-WR+D6ZLMsvFzSFSGaensNxrs4VZAc9EoIwCfF6OPOSQ=";
19 })
20 ];
21 pythonRelaxDeps = [ "radicale" ];
22
14 build-system = with final.python312Packages; [ setuptools ]; 23 build-system = with final.python312Packages; [ setuptools ];
15 24
25 PYTHONPATH = final.python312Packages.makePythonPath dependencies;
26
16 dependencies = with final.python312Packages; [ 27 dependencies = with final.python312Packages; [
17 appdirs 28 appdirs
18 etebase 29 etebase
@@ -21,40 +32,9 @@
21 flask-wtf 32 flask-wtf
22 msgpack 33 msgpack
23 requests 34 requests
24 requests.optional-dependencies.socks 35 (toPythonModule (final.radicale.override { python3 = python; }))
25 (buildPythonApplication rec { 36 ] ++ requests.optional-dependencies.socks;
26 pname = "radicale";
27 version = "3.2.0";
28 pyproject = true;
29
30 src = prev.fetchFromGitHub {
31 owner = "Kozea";
32 repo = "Radicale";
33 rev = "refs/tags/v${version}";
34 hash = "sha256-RxC8VOfdTXJZiAroDHTKjJqGWu65Z5uyb4WK1LOqubQ=";
35 };
36
37 postPatch = ''
38 sed -i '/addopts/d' setup.cfg
39 '';
40
41 build-system = [
42 setuptools
43 ];
44
45 dependencies = [
46 defusedxml
47 passlib
48 vobject
49 pika
50 python-dateutil
51 pytz # https://github.com/Kozea/Radicale/issues/816
52 ] ++ passlib.optional-dependencies.bcrypt;
53
54 doCheck = false;
55 })
56 ];
57 37
58 doCheck = false; 38 doCheck = false;
59 }; 39 });
60} 40}
diff --git a/overlays/etesync.nix b/overlays/etesync.nix
new file mode 100644
index 00000000..7311016e
--- /dev/null
+++ b/overlays/etesync.nix
@@ -0,0 +1,14 @@
1{ final, prev, ... }: {
2 python312 = prev.python312.override {
3 packageOverrides = self: super: {
4 etesync = super.etesync.overridePythonAttrs (oldAttrs: {
5 patches = (oldAttrs.patches or []) ++ [
6 (prev.fetchpatch {
7 url = "https://github.com/etesync/etebase-py/pull/59.patch";
8 hash = "sha256-vCueuk4gYskBZkzwJB2B8d7N6XXNDgNBA7rsZ2gpZXs=";
9 })
10 ];
11 });
12 };
13 };
14}
diff --git a/overlays/keepassxc/database-open-dialog.patch b/overlays/keepassxc/database-open-dialog.patch
deleted file mode 100644
index dff84846..00000000
--- a/overlays/keepassxc/database-open-dialog.patch
+++ /dev/null
@@ -1,129 +0,0 @@
1diff --git a/src/browser/BrowserService.cpp b/src/browser/BrowserService.cpp
2index 60412b5a..c0497d91 100644
3--- a/src/browser/BrowserService.cpp
4+++ b/src/browser/BrowserService.cpp
5@@ -249,7 +249,7 @@ QJsonObject BrowserService::createNewGroup(const QString& groupName)
6 return result;
7 }
8
9- auto dialogResult = MessageBox::warning(m_currentDatabaseWidget,
10+ auto dialogResult = MessageBox::warning(nullptr,
11 tr("KeePassXC - Create a new group"),
12 tr("A request for creating a new group \"%1\" has been received.\n"
13 "Do you want to create this group?\n")
14@@ -422,7 +422,7 @@ QList<Entry*> BrowserService::confirmEntries(QList<Entry*>& entriesToConfirm,
15
16 m_dialogActive = true;
17 updateWindowState();
18- BrowserAccessControlDialog accessControlDialog(m_currentDatabaseWidget);
19+ BrowserAccessControlDialog accessControlDialog{};
20
21 connect(m_currentDatabaseWidget, SIGNAL(databaseLockRequested()), &accessControlDialog, SLOT(reject()));
22
23@@ -512,7 +512,7 @@ QString BrowserService::storeKey(const QString& key)
24 QString id;
25
26 do {
27- QInputDialog keyDialog(m_currentDatabaseWidget);
28+ QInputDialog keyDialog{};
29 connect(m_currentDatabaseWidget, SIGNAL(databaseLockRequested()), &keyDialog, SLOT(reject()));
30 keyDialog.setWindowTitle(tr("KeePassXC - New key association request"));
31 keyDialog.setLabelText(tr("You have received an association request for the following database:\n%1\n\n"
32@@ -535,7 +535,7 @@ QString BrowserService::storeKey(const QString& key)
33
34 contains = db->metadata()->customData()->contains(CustomData::BrowserKeyPrefix + id);
35 if (contains) {
36- dialogResult = MessageBox::warning(m_currentDatabaseWidget,
37+ dialogResult = MessageBox::warning(nullptr,
38 tr("KeePassXC - Overwrite existing key?"),
39 tr("A shared encryption key with the name \"%1\" "
40 "already exists.\nDo you want to overwrite it?")
41@@ -595,7 +595,7 @@ QJsonObject BrowserService::showPasskeysRegisterPrompt(const QJsonObject& public
42 const auto existingEntries = getPasskeyEntriesWithUserHandle(rpId, userId, keyList);
43
44 raiseWindow();
45- BrowserPasskeysConfirmationDialog confirmDialog(m_currentDatabaseWidget);
46+ BrowserPasskeysConfirmationDialog confirmDialog{};
47 confirmDialog.registerCredential(username, rpId, existingEntries, timeout);
48
49 auto dialogResult = confirmDialog.exec();
50@@ -612,7 +612,7 @@ QJsonObject BrowserService::showPasskeysRegisterPrompt(const QJsonObject& public
51 // If no entry is selected, show the import dialog for manual entry selection
52 auto selectedEntry = confirmDialog.getSelectedEntry();
53 if (!selectedEntry) {
54- PasskeyImporter passkeyImporter(m_currentDatabaseWidget);
55+ PasskeyImporter passkeyImporter{};
56 const auto result = passkeyImporter.showImportDialog(db,
57 nullptr,
58 origin,
59@@ -683,7 +683,7 @@ QJsonObject BrowserService::showPasskeysAuthenticationPrompt(const QJsonObject&
60 const auto timeout = publicKeyOptions["timeout"].toInt();
61
62 raiseWindow();
63- BrowserPasskeysConfirmationDialog confirmDialog(m_currentDatabaseWidget);
64+ BrowserPasskeysConfirmationDialog confirmDialog{};
65 confirmDialog.authenticateCredential(entries, rpId, timeout);
66 auto dialogResult = confirmDialog.exec();
67 if (dialogResult == QDialog::Accepted) {
68@@ -760,7 +760,7 @@ void BrowserService::addPasskeyToEntry(Entry* entry,
69
70 // Ask confirmation if entry already contains a Passkey
71 if (entry->hasPasskey()) {
72- if (MessageBox::question(m_currentDatabaseWidget,
73+ if (MessageBox::question(nullptr,
74 tr("KeePassXC - Update passkey"),
75 tr("Entry already has a passkey.\nDo you want to overwrite the passkey in %1 - %2?")
76 .arg(entry->title(), passkeyUtils()->getUsernameFromEntry(entry)),
77@@ -873,7 +873,7 @@ bool BrowserService::updateEntry(const EntryParameters& entryParameters, const Q
78 MessageBox::Button dialogResult = MessageBox::No;
79 if (!browserSettings()->alwaysAllowUpdate()) {
80 raiseWindow();
81- dialogResult = MessageBox::question(m_currentDatabaseWidget,
82+ dialogResult = MessageBox::question(nullptr,
83 tr("KeePassXC - Update Entry"),
84 tr("Do you want to update the information in %1 - %2?")
85 .arg(QUrl(entryParameters.siteUrl).host(), username),
86@@ -909,7 +909,7 @@ bool BrowserService::deleteEntry(const QString& uuid)
87 return false;
88 }
89
90- auto dialogResult = MessageBox::warning(m_currentDatabaseWidget,
91+ auto dialogResult = MessageBox::warning(nullptr,
92 tr("KeePassXC - Delete entry"),
93 tr("A request for deleting entry \"%1\" has been received.\n"
94 "Do you want to delete the entry?\n")
95@@ -1536,7 +1536,7 @@ QSharedPointer<Database> BrowserService::selectedDatabase()
96 }
97 }
98
99- BrowserEntrySaveDialog browserEntrySaveDialog(m_currentDatabaseWidget);
100+ BrowserEntrySaveDialog browserEntrySaveDialog{};
101 int openDatabaseCount = browserEntrySaveDialog.setItems(databaseWidgets, m_currentDatabaseWidget);
102 if (openDatabaseCount > 1) {
103 int res = browserEntrySaveDialog.exec();
104diff --git a/src/fdosecrets/objects/Prompt.cpp b/src/fdosecrets/objects/Prompt.cpp
105index e89cd499..347c98b8 100644
106--- a/src/fdosecrets/objects/Prompt.cpp
107+++ b/src/fdosecrets/objects/Prompt.cpp
108@@ -313,7 +313,7 @@ namespace FdoSecrets
109 if (!entries.isEmpty()) {
110 QString app = tr("%1 (PID: %2)").arg(client->name()).arg(client->pid());
111 auto ac = new AccessControlDialog(
112- findWindow(m_windowId), entries, app, client->processInfo(), AuthOption::Remember);
113+ nullptr, entries, app, client->processInfo(), AuthOption::Remember);
114 connect(ac, &AccessControlDialog::finished, this, &UnlockPrompt::itemUnlockFinished);
115 connect(ac, &AccessControlDialog::finished, ac, &AccessControlDialog::deleteLater);
116 ac->open();
117diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp
118index 805d4eab..4836199e 100644
119--- a/src/gui/DatabaseTabWidget.cpp
120+++ b/src/gui/DatabaseTabWidget.cpp
121@@ -41,7 +41,7 @@ DatabaseTabWidget::DatabaseTabWidget(QWidget* parent)
122 : QTabWidget(parent)
123 , m_dbWidgetStateSync(new DatabaseWidgetStateSync(this))
124 , m_dbWidgetPendingLock(nullptr)
125- , m_databaseOpenDialog(new DatabaseOpenDialog(this))
126+ , m_databaseOpenDialog(new DatabaseOpenDialog())
127 , m_databaseOpenInProgress(false)
128 {
129 auto* tabBar = new QTabBar(this);
diff --git a/overlays/keepassxc/default.nix b/overlays/keepassxc/default.nix
deleted file mode 100644
index 325f1aa4..00000000
--- a/overlays/keepassxc/default.nix
+++ /dev/null
@@ -1,113 +0,0 @@
1{ final, prev, flakeInputs, ... }:
2{
3 keepassxc = final.stdenv.mkDerivation (finalAttrs: {
4 pname = "keepassxc";
5 version = "2.8.0-beta1";
6
7 src = final.fetchFromGitHub {
8 owner = "keepassxreboot";
9 repo = "keepassxc";
10 tag = finalAttrs.version;
11 hash = "sha256-fksThYmGZed66zxGDxlS2SHQzJYRf+T9AuZPbaNZV5Y=";
12 };
13
14 env =
15 final.lib.optionalAttrs final.stdenv.cc.isClang {
16 NIX_CFLAGS_COMPILE = toString [
17 "-Wno-old-style-cast"
18 "-Wno-error"
19 "-D__BIG_ENDIAN__=${if final.stdenv.hostPlatform.isBigEndian then "1" else "0"}"
20 ];
21 };
22
23 # Upstream develops against a build of PCSC from Xcode.
24 # The types are incompatible with nixpkgs pcsclite.
25 # https://github.com/NixOS/nixpkgs/issues/520227
26 postPatch = ''
27 substituteInPlace src/keys/drivers/YubiKeyInterfacePCSC.cpp \
28 --replace-fail "typedef uint32_t RETVAL;" "typedef int32_t RETVAL;"
29 '';
30
31 cmakeFlags = [
32 (final.lib.cmakeFeature "KEEPASSXC_BUILD_TYPE" "Release")
33 (final.lib.cmakeBool "WITH_GUI_TESTS" true)
34 (final.lib.cmakeBool "WITH_XC_UPDATECHECK" false)
35 (final.lib.cmakeBool "WITH_XC_X11" false)
36 (final.lib.cmakeBool "WITH_XC_BROWSER" true)
37 (final.lib.cmakeBool "WITH_XC_BROWSER_PASSKEYS" true)
38 (final.lib.cmakeBool "WITH_XC_KEESHARE" true)
39 (final.lib.cmakeBool "WITH_XC_NETWORKING" true)
40 (final.lib.cmakeBool "WITH_XC_SSHAGENT" true)
41 (final.lib.cmakeBool "WITH_XC_FDOSECRETS" true)
42 (final.lib.cmakeBool "WITH_XC_YUBIKEY" true)
43 ];
44
45 doCheck = true;
46 checkPhase =
47 let
48 disabledTests = final.lib.concatStringsSep "|" (
49 [
50 # flaky
51 "testcli"
52 "testgui"
53 ]
54 );
55 in
56 ''
57 runHook preCheck
58
59 export LC_ALL="en_US.UTF-8"
60 export QT_QPA_PLATFORM=offscreen
61 export QT_PLUGIN_PATH="${final.qt6.qtbase}/${final.qt6.qtbase.qtPluginPrefix}"
62
63 make test ARGS+="-E '${disabledTests}' --output-on-failure"
64
65 runHook postCheck
66 '';
67
68 nativeBuildInputs = with final; [
69 asciidoctor
70 cmake
71 qt6.wrapQtAppsHook
72 qt6.qttools
73 pkg-config
74 wrapGAppsHook3
75 ];
76
77 dontWrapGApps = true;
78 preFixup = ''
79 qtWrapperArgs+=("''${gappsWrapperArgs[@]}")
80 '';
81
82 postInstall = final.lib.concatLines [
83 # See https://github.com/keepassxreboot/keepassxc/blob/cd7a53abbbb81e468efb33eb56eefc12739969b8/src/browser/NativeMessageInstaller.cpp#L317
84 # See https://github.com/keepassxreboot/keepassxc/blob/cd7a53abbbb81e468efb33eb56eefc12739969b8/utils/keepassxc-snap-helper.sh#L48-L58
85 ''
86 mkdir -p "$out/lib/mozilla/native-messaging-hosts"
87 substituteAll "${toString (flakeInputs.nixpkgs) + "/pkgs/by-name/ke/keepassxc/firefox-native-messaging-host.json"}" "$out/lib/mozilla/native-messaging-hosts/org.keepassxc.keepassxc_browser.json"
88
89 mkdir -p "$out/etc/chromium/native-messaging-hosts"
90 substituteAll "${toString (flakeInputs.nixpkgs) + "/pkgs/by-name/ke/keepassxc/chromium-native-messaging-host.json"}" "$out/etc/chromium/native-messaging-hosts/org.keepassxc.keepassxc_browser.json"
91 ''
92 ];
93
94 buildInputs = with final; [
95 botan3
96 curl
97 libxi
98 libxtst
99 libargon2
100 qt6.qtbase
101 qt6.qtsvg
102 minizip
103 pcsclite
104 qrencode
105 readline
106 zlib
107 libusb1
108 keyutils
109 ];
110
111 meta.mainProgram = "keepassxc";
112 });
113}
diff --git a/overlays/quickshell/default.nix b/overlays/quickshell/default.nix
index 47aee5ac..38c78883 100644
--- a/overlays/quickshell/default.nix
+++ b/overlays/quickshell/default.nix
@@ -17,7 +17,7 @@
17 17
18 patches = (oldAttrs.patches or []) ++ [ 18 patches = (oldAttrs.patches or []) ++ [
19 # ./lock-state-changed.patch 19 # ./lock-state-changed.patch
20 ./notify-session-unlock.patch 20 # ./notify-session-unlock.patch
21 ./pipewire.patch 21 ./pipewire.patch
22 ./io.patch 22 ./io.patch
23 ./close-stdin.patch 23 ./close-stdin.patch
diff --git a/overlays/quickshell/pipewire.patch b/overlays/quickshell/pipewire.patch
index b94a2691..8c5a4c1e 100644
--- a/overlays/quickshell/pipewire.patch
+++ b/overlays/quickshell/pipewire.patch
@@ -1,7 +1,7 @@
1diff --git i/src/services/pipewire/device.cpp w/src/services/pipewire/device.cpp 1diff --git c/src/services/pipewire/device.cpp i/src/services/pipewire/device.cpp
2index 616e7d0..0c55008 100644 2index 61079a1..7246a67 100644
3--- i/src/services/pipewire/device.cpp 3--- c/src/services/pipewire/device.cpp
4+++ w/src/services/pipewire/device.cpp 4+++ i/src/services/pipewire/device.cpp
5@@ -3,6 +3,7 @@ 5@@ -3,6 +3,7 @@
6 #include <cstdint> 6 #include <cstdint>
7 #include <functional> 7 #include <functional>
@@ -21,7 +21,7 @@ index 616e7d0..0c55008 100644
21 21
22 #include "../../core/logcat.hpp" 22 #include "../../core/logcat.hpp"
23 #include "core.hpp" 23 #include "core.hpp"
24@@ -46,6 +49,25 @@ void PwDevice::unbindHooks() { 24@@ -46,6 +51,25 @@ void PwDevice::unbindHooks() {
25 this->mWaitingForDevice = false; 25 this->mWaitingForDevice = false;
26 } 26 }
27 27
@@ -47,7 +47,7 @@ index 616e7d0..0c55008 100644
47 const pw_device_events PwDevice::EVENTS = { 47 const pw_device_events PwDevice::EVENTS = {
48 .version = PW_VERSION_DEVICE_EVENTS, 48 .version = PW_VERSION_DEVICE_EVENTS,
49 .info = &PwDevice::onInfo, 49 .info = &PwDevice::onInfo,
50@@ -71,6 +93,11 @@ void PwDevice::onInfo(void* data, const pw_device_info* info) { 50@@ -71,6 +95,11 @@ void PwDevice::onInfo(void* data, const pw_device_info* info) {
51 } 51 }
52 52
53 break; 53 break;
@@ -59,7 +59,7 @@ index 616e7d0..0c55008 100644
59 } 59 }
60 } 60 }
61 } 61 }
62@@ -97,6 +124,15 @@ void PwDevice::onParam( 62@@ -97,6 +126,15 @@ void PwDevice::onParam(
63 } 63 }
64 64
65 self->addDeviceIndexPairs(param); 65 self->addDeviceIndexPairs(param);
@@ -75,7 +75,7 @@ index 616e7d0..0c55008 100644
75 } 75 }
76 } 76 }
77 77
78@@ -145,6 +181,21 @@ void PwDevice::polled() { 78@@ -159,6 +197,21 @@ void PwDevice::polled() {
79 return false; 79 return false;
80 }); 80 });
81 } 81 }
@@ -97,7 +97,7 @@ index 616e7d0..0c55008 100644
97 } 97 }
98 98
99 bool PwDevice::setVolumes(qint32 routeDevice, const QVector<float>& volumes) { 99 bool PwDevice::setVolumes(qint32 routeDevice, const QVector<float>& volumes) {
100@@ -182,6 +233,15 @@ bool PwDevice::setMuted(qint32 routeDevice, bool muted) { 100@@ -196,6 +249,15 @@ bool PwDevice::setMuted(qint32 routeDevice, bool muted) {
101 }); 101 });
102 } 102 }
103 103
@@ -113,7 +113,7 @@ index 616e7d0..0c55008 100644
113 void PwDevice::waitForDevice() { this->mWaitingForDevice = true; } 113 void PwDevice::waitForDevice() { this->mWaitingForDevice = true; }
114 bool PwDevice::waitingForDevice() const { return this->mWaitingForDevice; } 114 bool PwDevice::waitingForDevice() const { return this->mWaitingForDevice; }
115 115
116@@ -222,4 +282,24 @@ bool PwDevice::setRouteProps( 116@@ -236,4 +298,24 @@ bool PwDevice::setRouteProps(
117 return true; 117 return true;
118 } 118 }
119 119
@@ -138,10 +138,10 @@ index 616e7d0..0c55008 100644
138+} 138+}
139+ 139+
140 } // namespace qs::service::pipewire 140 } // namespace qs::service::pipewire
141diff --git i/src/services/pipewire/device.hpp w/src/services/pipewire/device.hpp 141diff --git c/src/services/pipewire/device.hpp i/src/services/pipewire/device.hpp
142index 1a1f705..ee64858 100644 142index f973b18..7cff16f 100644
143--- i/src/services/pipewire/device.hpp 143--- c/src/services/pipewire/device.hpp
144+++ w/src/services/pipewire/device.hpp 144+++ i/src/services/pipewire/device.hpp
145@@ -1,6 +1,7 @@ 145@@ -1,6 +1,7 @@
146 #pragma once 146 #pragma once
147 147
@@ -150,7 +150,7 @@ index 1a1f705..ee64858 100644
150 150
151 #include <pipewire/core.h> 151 #include <pipewire/core.h>
152 #include <pipewire/device.h> 152 #include <pipewire/device.h>
153@@ -17,6 +18,20 @@ 153@@ -16,6 +17,20 @@
154 154
155 namespace qs::service::pipewire { 155 namespace qs::service::pipewire {
156 156
@@ -170,8 +170,8 @@ index 1a1f705..ee64858 100644
170+ 170+
171 class PwDevice; 171 class PwDevice;
172 172
173 class PwDevice: public PwBindable<pw_device, PW_TYPE_INTERFACE_Device, PW_VERSION_DEVICE> { 173 // Forward declare to avoid circular dependency with node.hpp
174@@ -25,6 +40,12 @@ class PwDevice: public PwBindable<pw_device, PW_TYPE_INTERFACE_Device, PW_VERSIO 174@@ -27,6 +42,12 @@ class PwDevice: public PwBindable<pw_device, PW_TYPE_INTERFACE_Device, PW_VERSIO
175 public: 175 public:
176 void bindHooks() override; 176 void bindHooks() override;
177 void unbindHooks() override; 177 void unbindHooks() override;
@@ -184,9 +184,9 @@ index 1a1f705..ee64858 100644
184 184
185 bool setVolumes(qint32 routeDevice, const QVector<float>& volumes); 185 bool setVolumes(qint32 routeDevice, const QVector<float>& volumes);
186 bool setMuted(qint32 routeDevice, bool muted); 186 bool setMuted(qint32 routeDevice, bool muted);
187@@ -32,9 +53,16 @@ public: 187@@ -37,10 +58,17 @@ public:
188 void waitForDevice(); 188 [[nodiscard]] bool tryLoadVolumeProps(qint32 routeDevice, PwVolumeProps& volumeProps);
189 [[nodiscard]] bool waitingForDevice() const; 189 [[nodiscard]] bool hasRouteDevice(qint32 routeDevice) const;
190 190
191+ void setProfile(qint32 profileIndex); 191+ void setProfile(qint32 profileIndex);
192+ 192+
@@ -195,13 +195,14 @@ index 1a1f705..ee64858 100644
195+ 195+
196 signals: 196 signals:
197 void deviceReady(); 197 void deviceReady();
198 void routeVolumesChanged(qint32 routeDevice, const PwVolumeProps& volumeProps); 198 void
199 routeVolumesChanged(qint32 routeDevice, const qs::service::pipewire::PwVolumeProps& volumeProps);
199+ void profilesChanged(QList<PwProfile> profiles); 200+ void profilesChanged(QList<PwProfile> profiles);
200+ void currentProfileChanged(PwProfile profile); 201+ void currentProfileChanged(PwProfile profile);
201 202
202 private slots: 203 private slots:
203 void polled(); 204 void polled();
204@@ -49,6 +77,11 @@ private: 205@@ -56,6 +84,11 @@ private:
205 QList<qint32> stagingIndexes; 206 QList<qint32> stagingIndexes;
206 void addDeviceIndexPairs(const spa_pod* param); 207 void addDeviceIndexPairs(const spa_pod* param);
207 208
@@ -213,11 +214,11 @@ index 1a1f705..ee64858 100644
213 bool 214 bool
214 setRouteProps(qint32 routeDevice, const std::function<void*(spa_pod_builder*)>& propsCallback); 215 setRouteProps(qint32 routeDevice, const std::function<void*(spa_pod_builder*)>& propsCallback);
215 216
216diff --git i/src/services/pipewire/node.cpp w/src/services/pipewire/node.cpp 217diff --git c/src/services/pipewire/node.cpp i/src/services/pipewire/node.cpp
217index 3e68149..4721a58 100644 218index 2811833..25e1f8d 100644
218--- i/src/services/pipewire/node.cpp 219--- c/src/services/pipewire/node.cpp
219+++ w/src/services/pipewire/node.cpp 220+++ i/src/services/pipewire/node.cpp
220@@ -145,6 +145,10 @@ void PwNode::initProps(const spa_dict* props) { 221@@ -146,6 +146,10 @@ void PwNode::initProps(const spa_dict* props) {
221 this->type = PwNodeType::VideoSink; 222 this->type = PwNodeType::VideoSink;
222 } else if (strcmp(mediaClass, "Video/Source") == 0) { 223 } else if (strcmp(mediaClass, "Video/Source") == 0) {
223 this->type = PwNodeType::VideoSource; 224 this->type = PwNodeType::VideoSource;
@@ -228,11 +229,11 @@ index 3e68149..4721a58 100644
228 } 229 }
229 } 230 }
230 231
231diff --git i/src/services/pipewire/node.hpp w/src/services/pipewire/node.hpp 232diff --git c/src/services/pipewire/node.hpp i/src/services/pipewire/node.hpp
232index 0d4c92e..ee6f223 100644 233index d96525a..4f44c8d 100644
233--- i/src/services/pipewire/node.hpp 234--- c/src/services/pipewire/node.hpp
234+++ w/src/services/pipewire/node.hpp 235+++ i/src/services/pipewire/node.hpp
235@@ -144,6 +144,8 @@ public: 236@@ -145,6 +145,8 @@ public:
236 // This is equivalent to the media class `Video/Sink` and is composed of the 237 // This is equivalent to the media class `Video/Sink` and is composed of the
237 // @@PwNodeType.Video and @@PwNodeType.Sink flags. 238 // @@PwNodeType.Video and @@PwNodeType.Sink flags.
238 VideoSink = Video | Sink, 239 VideoSink = Video | Sink,
@@ -241,11 +242,11 @@ index 0d4c92e..ee6f223 100644
241 }; 242 };
242 Q_ENUM(Flag); 243 Q_ENUM(Flag);
243 Q_DECLARE_FLAGS(Flags, Flag); 244 Q_DECLARE_FLAGS(Flags, Flag);
244diff --git i/src/services/pipewire/qml.cpp w/src/services/pipewire/qml.cpp 245diff --git c/src/services/pipewire/qml.cpp i/src/services/pipewire/qml.cpp
245index 9efb17e..921d12a 100644 246index e4424c1..407096b 100644
246--- i/src/services/pipewire/qml.cpp 247--- c/src/services/pipewire/qml.cpp
247+++ w/src/services/pipewire/qml.cpp 248+++ i/src/services/pipewire/qml.cpp
248@@ -9,6 +9,9 @@ 249@@ -8,6 +8,9 @@
249 #include <qtypes.h> 250 #include <qtypes.h>
250 #include <qvariant.h> 251 #include <qvariant.h>
251 252
@@ -255,7 +256,7 @@ index 9efb17e..921d12a 100644
255 #include "../../core/model.hpp" 256 #include "../../core/model.hpp"
256 #include "connection.hpp" 257 #include "connection.hpp"
257 #include "defaults.hpp" 258 #include "defaults.hpp"
258@@ -54,6 +57,12 @@ Pipewire::Pipewire(QObject* parent): QObject(parent) { 259@@ -53,6 +56,12 @@ Pipewire::Pipewire(QObject* parent): QObject(parent) {
259 260
260 QObject::connect(&connection->registry, &PwRegistry::nodeAdded, this, &Pipewire::onNodeAdded); 261 QObject::connect(&connection->registry, &PwRegistry::nodeAdded, this, &Pipewire::onNodeAdded);
261 262
@@ -268,7 +269,7 @@ index 9efb17e..921d12a 100644
268 for (auto* link: connection->registry.links.values()) { 269 for (auto* link: connection->registry.links.values()) {
269 this->onLinkAdded(link); 270 this->onLinkAdded(link);
270 } 271 }
271@@ -123,6 +132,19 @@ void Pipewire::onNodeRemoved(QObject* object) { 272@@ -115,6 +124,19 @@ void Pipewire::onNodeRemoved(QObject* object) {
272 this->mNodes.removeObject(iface); 273 this->mNodes.removeObject(iface);
273 } 274 }
274 275
@@ -288,7 +289,7 @@ index 9efb17e..921d12a 100644
288 ObjectModel<PwLinkIface>* Pipewire::links() { return &this->mLinks; } 289 ObjectModel<PwLinkIface>* Pipewire::links() { return &this->mLinks; }
289 290
290 void Pipewire::onLinkAdded(PwLink* link) { 291 void Pipewire::onLinkAdded(PwLink* link) {
291@@ -357,6 +379,8 @@ QVariantMap PwNodeIface::properties() const { 292@@ -352,6 +374,8 @@ QVariantMap PwNodeIface::properties() const {
292 293
293 PwNodeAudioIface* PwNodeIface::audio() const { return this->audioIface; } 294 PwNodeAudioIface* PwNodeIface::audio() const { return this->audioIface; }
294 295
@@ -297,7 +298,7 @@ index 9efb17e..921d12a 100644
297 PwNodeIface* PwNodeIface::instance(PwNode* node) { 298 PwNodeIface* PwNodeIface::instance(PwNode* node) {
298 if (node == nullptr) return nullptr; 299 if (node == nullptr) return nullptr;
299 300
300@@ -481,4 +505,42 @@ void PwObjectTracker::objectDestroyed(QObject* object) { 301@@ -476,4 +500,42 @@ void PwObjectTracker::objectDestroyed(QObject* object) {
301 emit this->objectsChanged(); 302 emit this->objectsChanged();
302 } 303 }
303 304
@@ -340,10 +341,10 @@ index 9efb17e..921d12a 100644
340+} 341+}
341+ 342+
342 } // namespace qs::service::pipewire 343 } // namespace qs::service::pipewire
343diff --git i/src/services/pipewire/qml.hpp w/src/services/pipewire/qml.hpp 344diff --git c/src/services/pipewire/qml.hpp i/src/services/pipewire/qml.hpp
344index e3489a1..e5e1891 100644 345index 93c4844..87cbcb3 100644
345--- i/src/services/pipewire/qml.hpp 346--- c/src/services/pipewire/qml.hpp
346+++ w/src/services/pipewire/qml.hpp 347+++ i/src/services/pipewire/qml.hpp
347@@ -12,11 +12,13 @@ 348@@ -12,11 +12,13 @@
348 #include "../../core/model.hpp" 349 #include "../../core/model.hpp"
349 #include "link.hpp" 350 #include "link.hpp"
@@ -378,13 +379,13 @@ index e3489a1..e5e1891 100644
378@@ -159,7 +164,9 @@ signals: 379@@ -159,7 +164,9 @@ signals:
379 380
380 private slots: 381 private slots:
381 void onNodeAdded(PwNode* node); 382 void onNodeAdded(qs::service::pipewire::PwNode* node);
382+ void onDeviceAdded(PwDevice* node); 383+ void onDeviceAdded(PwDevice* node);
383 void onNodeRemoved(QObject* object); 384 void onNodeRemoved(QObject* object);
384+ void onDeviceRemoved(QObject* object); 385+ void onDeviceRemoved(QObject* object);
385 void onLinkAdded(PwLink* link); 386 void onLinkAdded(qs::service::pipewire::PwLink* link);
386 void onLinkRemoved(QObject* object); 387 void onLinkRemoved(QObject* object);
387 void onLinkGroupAdded(PwLinkGroup* group); 388 void onLinkGroupAdded(qs::service::pipewire::PwLinkGroup* group);
388@@ -167,6 +174,7 @@ private slots: 389@@ -167,6 +174,7 @@ private slots:
389 390
390 private: 391 private:
@@ -454,11 +455,11 @@ index e3489a1..e5e1891 100644
454 ///! A connection between pipewire nodes. 455 ///! A connection between pipewire nodes.
455 /// Note that there is one link per *channel* of a connection between nodes. 456 /// Note that there is one link per *channel* of a connection between nodes.
456 /// You usually want @@PwLinkGroup. 457 /// You usually want @@PwLinkGroup.
457diff --git i/src/services/pipewire/registry.cpp w/src/services/pipewire/registry.cpp 458diff --git c/src/services/pipewire/registry.cpp i/src/services/pipewire/registry.cpp
458index c08fc1d..50c6d7a 100644 459index 4b670b1..4295874 100644
459--- i/src/services/pipewire/registry.cpp 460--- c/src/services/pipewire/registry.cpp
460+++ w/src/services/pipewire/registry.cpp 461+++ i/src/services/pipewire/registry.cpp
461@@ -196,6 +196,7 @@ void PwRegistry::onGlobal( 462@@ -236,6 +236,7 @@ void PwRegistry::onGlobal(
462 device->initProps(props); 463 device->initProps(props);
463 464
464 self->devices.emplace(id, device); 465 self->devices.emplace(id, device);
@@ -466,7 +467,7 @@ index c08fc1d..50c6d7a 100644
466 } 467 }
467 } 468 }
468 469
469@@ -211,6 +212,9 @@ void PwRegistry::onGlobalRemoved(void* data, quint32 id) { 470@@ -251,6 +252,9 @@ void PwRegistry::onGlobalRemoved(void* data, quint32 id) {
470 } else if (auto* node = self->nodes.value(id)) { 471 } else if (auto* node = self->nodes.value(id)) {
471 self->nodes.remove(id); 472 self->nodes.remove(id);
472 node->safeDestroy(); 473 node->safeDestroy();
@@ -476,15 +477,15 @@ index c08fc1d..50c6d7a 100644
476 } 477 }
477 } 478 }
478 479
479diff --git i/src/services/pipewire/registry.hpp w/src/services/pipewire/registry.hpp 480diff --git c/src/services/pipewire/registry.hpp i/src/services/pipewire/registry.hpp
480index 8473f04..87e0766 100644 481index ec0a9ea..c9be65a 100644
481--- i/src/services/pipewire/registry.hpp 482--- c/src/services/pipewire/registry.hpp
482+++ w/src/services/pipewire/registry.hpp 483+++ i/src/services/pipewire/registry.hpp
483@@ -132,6 +132,7 @@ public: 484@@ -133,6 +133,7 @@ public:
484 485
485 signals: 486 signals:
486 void nodeAdded(PwNode* node); 487 void nodeAdded(qs::service::pipewire::PwNode* node);
487+ void deviceAdded(PwDevice* node); 488+ void deviceAdded(PwDevice* node);
488 void linkAdded(PwLink* link); 489 void linkAdded(qs::service::pipewire::PwLink* link);
489 void linkGroupAdded(PwLinkGroup* group); 490 void linkGroupAdded(qs::service::pipewire::PwLinkGroup* group);
490 void metadataAdded(PwMetadata* metadata); 491 void metadataAdded(qs::service::pipewire::PwMetadata* metadata);