summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--accounts/gkleen@sif/niri/default.nix58
-rw-r--r--accounts/gkleen@sif/niri/swayosd.nix66
-rw-r--r--accounts/gkleen@sif/shell/quickshell-plugins/Systemd.cpp14
-rw-r--r--accounts/gkleen@sif/shell/quickshell-plugins/Systemd.hpp1
-rw-r--r--accounts/gkleen@sif/shell/quickshell/Bar.qml23
-rw-r--r--accounts/gkleen@sif/shell/quickshell/BatteryWidget.qml61
-rw-r--r--accounts/gkleen@sif/shell/quickshell/BrightnessOSD.qml117
-rw-r--r--accounts/gkleen@sif/shell/quickshell/BrightnessWidget.qml33
-rw-r--r--accounts/gkleen@sif/shell/quickshell/MaterialDesignIcon.qml17
-rw-r--r--accounts/gkleen@sif/shell/quickshell/PipewireWidget.qml3
-rw-r--r--accounts/gkleen@sif/shell/quickshell/PrivacyWidget.qml49
-rw-r--r--accounts/gkleen@sif/shell/quickshell/Services/Brightness.qml68
-rw-r--r--accounts/gkleen@sif/shell/quickshell/Services/Privacy.qml63
-rw-r--r--accounts/gkleen@sif/shell/quickshell/SystemTray.qml34
-rw-r--r--accounts/gkleen@sif/shell/quickshell/UnixIPC.qml59
-rw-r--r--accounts/gkleen@sif/shell/quickshell/VolumeOSD.qml55
-rw-r--r--accounts/gkleen@sif/shell/quickshell/shell.qml3
-rw-r--r--flake.lock45
-rw-r--r--flake.nix7
-rw-r--r--overlays/niri.nix1
-rw-r--r--overlays/quickshell/default.nix1
-rw-r--r--overlays/quickshell/io.patch13
-rw-r--r--overlays/quickshell/pipewire.patch28
-rw-r--r--overlays/swayosd/default.nix13
-rw-r--r--overlays/swayosd/exponential.patch57
25 files changed, 666 insertions, 223 deletions
diff --git a/accounts/gkleen@sif/niri/default.nix b/accounts/gkleen@sif/niri/default.nix
index e1eca4c4..10b85169 100644
--- a/accounts/gkleen@sif/niri/default.nix
+++ b/accounts/gkleen@sif/niri/default.nix
@@ -10,7 +10,6 @@ let
10 makoctl = lib.getExe' config.services.mako.package "makoctl"; 10 makoctl = lib.getExe' config.services.mako.package "makoctl";
11 loginctl = lib.getExe' hostConfig.systemd.package "loginctl"; 11 loginctl = lib.getExe' hostConfig.systemd.package "loginctl";
12 systemctl = lib.getExe' hostConfig.systemd.package "systemctl"; 12 systemctl = lib.getExe' hostConfig.systemd.package "systemctl";
13 swayosd-client = lib.getExe' config.services.swayosd.package "swayosd-client";
14 13
15 focus_or_spawn = pkgs.writeShellApplication { 14 focus_or_spawn = pkgs.writeShellApplication {
16 name = "focus-or-spawn"; 15 name = "focus-or-spawn";
@@ -168,7 +167,6 @@ in {
168 imports = [ 167 imports = [
169 ./waybar.nix 168 ./waybar.nix
170 ./mako.nix 169 ./mako.nix
171 ./swayosd.nix
172 ]; 170 ];
173 171
174 options = { 172 options = {
@@ -939,31 +937,6 @@ in {
939 allow-when-locked = true; 937 allow-when-locked = true;
940 }; 938 };
941 939
942 "XF86MonBrightnessUp" = {
943 action = spawn swayosd-client "--brightness" "raise";
944 allow-when-locked = true;
945 };
946 "XF86MonBrightnessDown" = {
947 action = spawn swayosd-client "--brightness" "lower";
948 allow-when-locked = true;
949 };
950 "XF86AudioRaiseVolume" = {
951 action = spawn swayosd-client "--output-volume" "raise";
952 allow-when-locked = true;
953 };
954 "XF86AudioLowerVolume" = {
955 action = spawn swayosd-client "--output-volume" "lower";
956 allow-when-locked = true;
957 };
958 "XF86AudioMute" = {
959 action = spawn swayosd-client "--output-volume" "mute-toggle";
960 allow-when-locked = true;
961 };
962 "XF86AudioMicMute" = {
963 action = spawn swayosd-client "--input-volume" "mute-toggle";
964 allow-when-locked = true;
965 };
966
967 "Mod+Semicolon".action = spawn makoctl "dismiss" "--group"; 940 "Mod+Semicolon".action = spawn makoctl "dismiss" "--group";
968 "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all"; 941 "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all";
969 "Mod+Period".action = spawn makoctl "menu" "--" (lib.getExe config.programs.fuzzel.package) "--dmenu"; 942 "Mod+Period".action = spawn makoctl "menu" "--" (lib.getExe config.programs.fuzzel.package) "--dmenu";
@@ -982,6 +955,37 @@ in {
982 "Mod+K".action = spawn (lib.getExe' pkgs.worktime "worktime-ui"); 955 "Mod+K".action = spawn (lib.getExe' pkgs.worktime "worktime-ui");
983 "Mod+Shift+K".action = spawn (lib.getExe' pkgs.worktime "worktime-stop"); 956 "Mod+Shift+K".action = spawn (lib.getExe' pkgs.worktime "worktime-stop");
984 })) 957 }))
958 (lib.mapAttrsToList (name: cfg: node name [(lib.removeAttrs cfg ["action"])] [cfg.action]) (let
959 shell = obj: leaf "send-unix" [
960 { path = ''''${XDG_RUNTIME_DIR}/shell.sock''; }
961 (builtins.toJSON obj + "\n")
962 ];
963 in {
964 "XF86AudioRaiseVolume" = {
965 allow-when-locked = true;
966 action = shell { Volume.volume = "up"; };
967 };
968 "XF86AudioLowerVolume" = {
969 allow-when-locked = true;
970 action = shell { Volume.volume = "down"; };
971 };
972 "XF86AudioMute" = {
973 allow-when-locked = true;
974 action = shell { Volume.muted = "toggle"; };
975 };
976 "XF86AudioMicMute" = {
977 allow-when-locked = true;
978 action = shell { Volume."mic-muted" = "toggle"; };
979 };
980 "XF86MonBrightnessUp" = {
981 action = shell { Brightness = "up"; };
982 allow-when-locked = true;
983 };
984 "XF86MonBrightnessDown" = {
985 action = shell { Brightness = "down"; };
986 allow-when-locked = true;
987 };
988 }))
985 (map ({ name, selector, spawn, key, ...}: if key != null && selector != null && spawn != null then bind key { action = focus-or-spawn-action selector name spawn; } else null) cfg.scratchspaces) 989 (map ({ name, selector, spawn, key, ...}: if key != null && selector != null && spawn != null then bind key { action = focus-or-spawn-action selector name spawn; } else null) cfg.scratchspaces)
986 (map ({ name, moveKey, ...}: if moveKey != null then bind moveKey { action = kdl.magic-leaf "move-column-to-workspace" name; } else null) cfg.scratchspaces) 990 (map ({ name, moveKey, ...}: if moveKey != null then bind moveKey { action = kdl.magic-leaf "move-column-to-workspace" name; } else null) cfg.scratchspaces)
987 ] 991 ]
diff --git a/accounts/gkleen@sif/niri/swayosd.nix b/accounts/gkleen@sif/niri/swayosd.nix
deleted file mode 100644
index 54ebb302..00000000
--- a/accounts/gkleen@sif/niri/swayosd.nix
+++ /dev/null
@@ -1,66 +0,0 @@
1{ pkgs, ... }:
2{
3 config = {
4 services.swayosd = {
5 enable = true;
6 topMargin = 0.4769706078;
7 stylePath = pkgs.runCommand "style.css" {
8 passAsFile = [ "src" ];
9 src = ''
10 window#osd {
11 padding: 12px 20px;
12 border-radius: 999px;
13 border: none;
14 background: rgba(0, 0, 0, 0.87);
15
16 #container {
17 margin: 16px;
18 }
19
20 image,
21 label {
22 color: rgb(255, 255, 255);
23
24 &:disabled {
25 opacity: 1;
26 color: rgb(84, 84, 84);
27 }
28 }
29
30 progressbar {
31 min-height: 6px;
32 border-radius: 999px;
33 background: transparent;
34 border: none;
35
36 trough, progress {
37 min-height: inherit;
38 border-radius: inherit;
39 border: none;
40 }
41
42 trough {
43 background: rgb(127, 127, 127);
44 }
45 progress {
46 background: rgb(255, 255, 255);
47 }
48
49 &:disabled {
50 opacity: 1;
51
52 trough {
53 background: rgb(19, 19, 19);
54 }
55 progress {
56 background: rgb(38, 38, 38);
57 }
58 }
59 }
60 }
61 '';
62 buildInputs = with pkgs; [sass];
63 } "scss -C --sourcemap=none --style=compact $srcPath $out";
64 };
65 };
66}
diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.cpp b/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.cpp
index 9ccd8ba0..5e607709 100644
--- a/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.cpp
+++ b/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.cpp
@@ -9,8 +9,16 @@ void Systemd::stopUserUnit(const QString& unit, const QString& mode) {
9 "/org/freedesktop/systemd1", 9 "/org/freedesktop/systemd1",
10 "org.freedesktop.systemd1.Manager", 10 "org.freedesktop.systemd1.Manager",
11 "StopUnit" 11 "StopUnit"
12 ); 12 ) << unit << mode;
13 m << unit;
14 m << mode;
15 QDBusConnection::sessionBus().send(m); 13 QDBusConnection::sessionBus().send(m);
16} 14}
15
16void Systemd::setBrightness(const QString& subsystem, const QString& name, quint32 brightness) {
17 QDBusMessage m = QDBusMessage::createMethodCall(
18 "org.freedesktop.login1",
19 "/org/freedesktop/login1/session/auto",
20 "org.freedesktop.login1.Session",
21 "SetBrightness"
22 ) << subsystem << name << brightness;
23 QDBusConnection::systemBus().send(m);
24}
diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.hpp b/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.hpp
index 883a96f3..f8841518 100644
--- a/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.hpp
+++ b/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.hpp
@@ -10,4 +10,5 @@ class Systemd : public QObject {
10 10
11public: 11public:
12 Q_INVOKABLE void stopUserUnit(const QString& unit, const QString& mode); 12 Q_INVOKABLE void stopUserUnit(const QString& unit, const QString& mode);
13 Q_INVOKABLE void setBrightness(const QString& subsystem, const QString& name, quint32 brightness);
13}; 14};
diff --git a/accounts/gkleen@sif/shell/quickshell/Bar.qml b/accounts/gkleen@sif/shell/quickshell/Bar.qml
index 3652af54..d52740b2 100644
--- a/accounts/gkleen@sif/shell/quickshell/Bar.qml
+++ b/accounts/gkleen@sif/shell/quickshell/Bar.qml
@@ -1,7 +1,6 @@
1import Quickshell 1import Quickshell
2import QtQuick 2import QtQuick
3 3
4
5PanelWindow { 4PanelWindow {
6 id: bar 5 id: bar
7 6
@@ -64,25 +63,39 @@ PanelWindow {
64 anchors.verticalCenter: parent.verticalCenter 63 anchors.verticalCenter: parent.verticalCenter
65 spacing: 0 64 spacing: 0
66 65
67 PipewireWidget {} 66 PrivacyWidget {
67 id: privacy
68 }
68 69
69 Item { 70 Item {
71 enabled: privacy.active
70 height: parent.height 72 height: parent.height
71 width: 4 73 width: 8
72 } 74 }
73 75
74 SystemTray {} 76 BatteryWidget {}
77
78 Item {
79 height: parent.height
80 width: 8
81 }
82
83 BrightnessWidget {}
75 84
76 Item { 85 Item {
77 height: parent.height 86 height: parent.height
78 width: 4 87 width: 4
79 } 88 }
80 89
90 PipewireWidget {}
91
92 SystemTray {}
93
81 KeyboardLayout {} 94 KeyboardLayout {}
82 95
83 Item { 96 Item {
84 height: parent.height 97 height: parent.height
85 width: 4 98 width: 8 - 4
86 } 99 }
87 100
88 Clock {} 101 Clock {}
diff --git a/accounts/gkleen@sif/shell/quickshell/BatteryWidget.qml b/accounts/gkleen@sif/shell/quickshell/BatteryWidget.qml
new file mode 100644
index 00000000..896440f1
--- /dev/null
+++ b/accounts/gkleen@sif/shell/quickshell/BatteryWidget.qml
@@ -0,0 +1,61 @@
1import QtQuick
2import Quickshell
3import Quickshell.Widgets
4import Quickshell.Services.UPower
5
6Item {
7 id: root
8
9 height: parent.height
10 width: batteryIcon.width
11 anchors.verticalCenter: parent.verticalCenter
12
13 property var batteryDevice: Array.from(UPower.devices.values).find(dev => dev.isLaptopBattery)
14
15 WrapperMouseArea {
16 id: widgetMouseArea
17
18 anchors.fill: parent
19
20 hoverEnabled: true
21
22 Item {
23 anchors.fill: parent
24
25 MaterialDesignIcon {
26 id: batteryIcon
27
28 implicitSize: 14
29 anchors.centerIn: parent
30
31 icon: {
32 if (!root.batteryDevice?.ready)
33 return "battery-unknown";
34
35 if (root.batteryDevice.state == UPowerDeviceState.FullyCharged)
36 return "power-plug-battery";
37
38 const perdec = 10 * Math.max(1, Math.ceil(root.batteryDevice.percentage * 10));
39 if (root.batteryDevice.state == UPowerDeviceState.Charging)
40 return `battery-charging-${perdec}`;
41 if (perdec == 100)
42 return "battery";
43 return `battery-${perdec}`;
44 }
45 color: {
46 if (!root.batteryDevice?.ready)
47 return "#555";
48
49 if (root.batteryDevice.state != UPowerDeviceState.FullyCharged && root.batteryDevice.state != UPowerDeviceState.Charging && root.batteryDevice.timeToEmpty < 20 * 60)
50 return "#f2201f";
51 if (root.batteryDevice.state != UPowerDeviceState.FullyCharged && root.batteryDevice.state != UPowerDeviceState.Charging && root.batteryDevice.timeToEmpty < 40 * 60)
52 return "#f28a21";
53 if (root.batteryDevice.state != UPowerDeviceState.FullyCharged)
54 return "#fff";
55 return "#555";
56 }
57 }
58
59 }
60 }
61}
diff --git a/accounts/gkleen@sif/shell/quickshell/BrightnessOSD.qml b/accounts/gkleen@sif/shell/quickshell/BrightnessOSD.qml
new file mode 100644
index 00000000..a432179e
--- /dev/null
+++ b/accounts/gkleen@sif/shell/quickshell/BrightnessOSD.qml
@@ -0,0 +1,117 @@
1import QtQuick
2import QtQuick.Layouts
3import Quickshell
4import Quickshell.Widgets
5import qs.Services
6
7Scope {
8 id: root
9
10 property bool show: false
11 property bool inhibited: true
12
13 Connections {
14 target: Brightness
15
16 function onCurrBrightnessChanged() {
17 root.show = true;
18 hideTimer.restart();
19 }
20 }
21
22 onShowChanged: {
23 if (show)
24 hideTimer.restart();
25 }
26
27 Timer {
28 id: hideTimer
29 interval: 1000
30 onTriggered: root.show = false
31 }
32
33 Timer {
34 id: startInhibit
35 interval: 100
36 running: true
37 onTriggered: {
38 root.show = false;
39 root.inhibited = false;
40 }
41 }
42
43 LazyLoader {
44 active: root.show && !root.inhibited
45
46 Variants {
47 model: Quickshell.screens
48
49 delegate: Scope {
50 id: screenScope
51
52 required property var modelData
53
54 PanelWindow {
55 id: window
56
57 screen: screenScope.modelData
58
59 anchors.top: true
60 margins.top: screen.height / 2 - 50 + 3.5
61 exclusiveZone: 0
62 exclusionMode: ExclusionMode.Ignore
63
64 implicitWidth: 400
65 implicitHeight: 50
66
67 mask: Region {}
68
69 color: "transparent"
70
71 Rectangle {
72 anchors.fill: parent
73 color: Qt.rgba(0, 0, 0, 0.75)
74 }
75
76 RowLayout {
77 id: layout
78
79 anchors.centerIn: parent
80
81 height: 50 - 8*2
82 width: 400 - 8*2
83
84 MaterialDesignIcon {
85 id: volumeIcon
86
87 implicitWidth: parent.height
88 implicitHeight: parent.height
89
90 icon: `brightness-${Math.min(7, Math.floor(Brightness.currBrightness * 7) + 1)}`
91 }
92
93 Rectangle {
94 Layout.fillWidth: true
95
96 implicitHeight: 10
97
98 color: "#50ffffff"
99
100 Rectangle {
101 anchors {
102 left: parent.left
103 top: parent.top
104 bottom: parent.bottom
105 }
106
107 color: "white"
108
109 implicitWidth: parent.width * Brightness.currBrightness
110 }
111 }
112 }
113 }
114 }
115 }
116 }
117}
diff --git a/accounts/gkleen@sif/shell/quickshell/BrightnessWidget.qml b/accounts/gkleen@sif/shell/quickshell/BrightnessWidget.qml
new file mode 100644
index 00000000..664b28e2
--- /dev/null
+++ b/accounts/gkleen@sif/shell/quickshell/BrightnessWidget.qml
@@ -0,0 +1,33 @@
1import QtQuick
2import Quickshell
3import Quickshell.Widgets
4import qs.Services
5
6Item {
7 height: parent.height
8 width: brightnessIcon.width
9 anchors.verticalCenter: parent.verticalCenter
10
11 WrapperMouseArea {
12 id: widgetMouseArea
13
14 anchors.fill: parent
15
16 property real sensitivity: (1 / 50) / 120
17 onWheel: event => Brightness.currBrightness += event.angleDelta.y * sensitivity
18
19 Item {
20 anchors.fill: parent
21
22 MaterialDesignIcon {
23 id: brightnessIcon
24
25 implicitSize: 14
26 anchors.centerIn: parent
27
28 icon: `brightness-${Math.min(7, Math.floor(Brightness.currBrightness * 7) + 1)}`
29 color: "#555"
30 }
31 }
32 }
33}
diff --git a/accounts/gkleen@sif/shell/quickshell/MaterialDesignIcon.qml b/accounts/gkleen@sif/shell/quickshell/MaterialDesignIcon.qml
index 387dcc8b..155a009e 100644
--- a/accounts/gkleen@sif/shell/quickshell/MaterialDesignIcon.qml
+++ b/accounts/gkleen@sif/shell/quickshell/MaterialDesignIcon.qml
@@ -2,15 +2,26 @@ import QtQuick
2import QtQuick.Effects 2import QtQuick.Effects
3 3
4Item { 4Item {
5 id: icon 5 id: root
6 6
7 required property string icon 7 required property string icon
8 property color color: "white" 8 property color color: "white"
9 9
10 property real implicitSize: 0
11
12 readonly property real actualSize: Math.min(root.width, root.height)
13
14 implicitWidth: root.implicitSize
15 implicitHeight: root.implicitSize
16
10 Image { 17 Image {
11 id: sourceImage 18 id: sourceImage
12 source: "file://" + @mdi@ + "/svg/" + icon.icon + ".svg" 19 source: "file://" + @mdi@ + "/svg/" + root.icon + ".svg"
13 anchors.fill: parent 20 anchors.fill: parent
21 fillMode: Image.PreserveAspectFit
22
23 sourceSize.width: root.actualSize
24 sourceSize.height: root.actualSize
14 25
15 layer.enabled: true 26 layer.enabled: true
16 layer.effect: MultiEffect { 27 layer.effect: MultiEffect {
@@ -18,7 +29,7 @@ Item {
18 29
19 brightness: 1 30 brightness: 1
20 colorization: 1 31 colorization: 1
21 colorizationColor: icon.color 32 colorizationColor: root.color
22 } 33 }
23 } 34 }
24} 35}
diff --git a/accounts/gkleen@sif/shell/quickshell/PipewireWidget.qml b/accounts/gkleen@sif/shell/quickshell/PipewireWidget.qml
index 7fdb5006..007ce100 100644
--- a/accounts/gkleen@sif/shell/quickshell/PipewireWidget.qml
+++ b/accounts/gkleen@sif/shell/quickshell/PipewireWidget.qml
@@ -50,8 +50,7 @@ Item {
50 MaterialDesignIcon { 50 MaterialDesignIcon {
51 id: volumeIcon 51 id: volumeIcon
52 52
53 width: 16 53 implicitSize: 14
54 height: 16
55 anchors.centerIn: parent 54 anchors.centerIn: parent
56 55
57 icon: { 56 icon: {
diff --git a/accounts/gkleen@sif/shell/quickshell/PrivacyWidget.qml b/accounts/gkleen@sif/shell/quickshell/PrivacyWidget.qml
new file mode 100644
index 00000000..bb02528b
--- /dev/null
+++ b/accounts/gkleen@sif/shell/quickshell/PrivacyWidget.qml
@@ -0,0 +1,49 @@
1import QtQuick
2import QtQuick.Layouts
3import Quickshell
4import Quickshell.Widgets
5import qs.Services
6
7Item {
8 height: parent.height
9 width: layout.childrenRect.width
10 anchors.verticalCenter: parent.verticalCenter
11
12 readonly property bool active: Boolean(Privacy.activeItems)
13
14 RowLayout {
15 id: layout
16
17 anchors.fill: parent
18
19 spacing: 8
20
21 Repeater {
22 model: Privacy.activeItems
23
24 Item {
25 id: privacyItem
26
27 required property var modelData;
28
29 height: parent.height
30 width: icon.width
31
32 MaterialDesignIcon {
33 id: icon
34
35 implicitSize: 14
36 anchors.centerIn: parent
37
38 icon: {
39 if (privacyItem.modelData == Privacy.Item.Microphone)
40 return "microphone";
41 if (privacyItem.modelData == Privacy.Item.Screensharing)
42 return "monitor-share";
43 }
44 color: "#f2201f"
45 }
46 }
47 }
48 }
49}
diff --git a/accounts/gkleen@sif/shell/quickshell/Services/Brightness.qml b/accounts/gkleen@sif/shell/quickshell/Services/Brightness.qml
new file mode 100644
index 00000000..87c7c05b
--- /dev/null
+++ b/accounts/gkleen@sif/shell/quickshell/Services/Brightness.qml
@@ -0,0 +1,68 @@
1pragma Singleton
2
3import QtQml
4import Quickshell
5import Quickshell.Io
6import Custom as Custom
7
8Singleton {
9 id: root
10
11 property string subsystem: "backlight"
12 property string device: "intel_backlight"
13
14 property real currBrightness
15 property real exponent: 4
16
17 function calcCurrBrightness() {
18 if (!currFile.loaded || !maxFile.loaded)
19 return undefined;
20 const curr = Number(currFile.text());
21 const max = Number(maxFile.text());
22 const val = Math.pow(curr / max, 1 / root.exponent);
23 return val;
24 }
25
26 Component.onCompleted: root.currBrightness = root.calcCurrBrightness()
27 Connections {
28 target: currFile
29 function onLoaded() { root.currBrightness = root.calcCurrBrightness(); }
30 }
31 Connections {
32 target: maxFile
33 function onLoaded() { root.currBrightness = root.calcCurrBrightness(); }
34 }
35
36 onCurrBrightnessChanged: {
37 root.currBrightness = Math.max(0, Math.min(1, root.currBrightness));
38
39 const prev = root.calcCurrBrightness();
40 if (typeof prev === 'undefined' || Math.abs(root.currBrightness - prev) < 0.01)
41 return;
42
43 const max = Number(maxFile.text());
44 const actual = Number(currFile.text());
45 let curr = Math.max(0, Math.min(max, Math.pow(root.currBrightness, root.exponent) * max));
46 if (Math.round(curr) == actual && curr < actual)
47 curr = Math.max(0, actual - 1);
48 else if (Math.round(curr) == actual && curr > actual)
49 curr = Math.min(max, actual + 1);
50 // root.currBrightness = Math.pow(curr / max, 1 / root.exponent);
51 Custom.Systemd.setBrightness(root.subsystem, root.device, Math.round(curr));
52 }
53
54 FileView {
55 id: currFile
56 path: `/sys/class/${root.subsystem}/${root.device}/brightness`
57 blockAllReads: true
58 watchChanges: true
59 onFileChanged: reload()
60 }
61 FileView {
62 id: maxFile
63 path: `/sys/class/${root.subsystem}/${root.device}/max_brightness`
64 blockAllReads: true
65 watchChanges: true
66 onFileChanged: reload()
67 }
68}
diff --git a/accounts/gkleen@sif/shell/quickshell/Services/Privacy.qml b/accounts/gkleen@sif/shell/quickshell/Services/Privacy.qml
new file mode 100644
index 00000000..9c813e49
--- /dev/null
+++ b/accounts/gkleen@sif/shell/quickshell/Services/Privacy.qml
@@ -0,0 +1,63 @@
1pragma Singleton
2
3import QtQml
4import Quickshell
5import Quickshell.Services.Pipewire
6
7Singleton {
8 id: root
9
10 PwObjectTracker {
11 objects: Pipewire.nodes.values
12 }
13
14 enum Item {
15 Microphone,
16 Screensharing
17 }
18
19 readonly property list<var> activeItems: {
20 var items = [];
21 if (microphoneActive)
22 items.push(Privacy.Item.Microphone);
23 if (screensharingActive)
24 items.push(Privacy.Item.Screensharing);
25 return items;
26 }
27
28 readonly property bool microphoneActive: {
29 if (!Pipewire.ready || !Pipewire.nodes?.values) {
30 return false
31 }
32
33 for (const node of Pipewire.nodes.values) {
34 if (!node || (node.type & PwNodeType.AudioInStream) != PwNodeType.AudioInStream)
35 continue;
36
37 if (node.properties?.["stream.monitor"] === "true")
38 continue;
39
40 if (node.audio?.muted)
41 continue;
42
43 return true;
44 }
45
46 return false;
47 }
48
49 readonly property bool screensharingActive: {
50 if (!Pipewire.ready || !Pipewire.nodes?.values) {
51 return false
52 }
53
54 for (const node of Pipewire.nodes.values) {
55 if (!node || (node.type & PwNodeType.VideoInStream) != PwNodeType.VideoInStream)
56 continue;
57
58 return true;
59 }
60
61 return false;
62 }
63}
diff --git a/accounts/gkleen@sif/shell/quickshell/SystemTray.qml b/accounts/gkleen@sif/shell/quickshell/SystemTray.qml
index 55b1690e..6f70be29 100644
--- a/accounts/gkleen@sif/shell/quickshell/SystemTray.qml
+++ b/accounts/gkleen@sif/shell/quickshell/SystemTray.qml
@@ -47,7 +47,7 @@ Item {
47 return "" 47 return ""
48 } 48 }
49 49
50 width: 16 50 width: icon.width + 6
51 height: parent.height 51 height: parent.height
52 anchors.verticalCenter: parent.verticalCenter 52 anchors.verticalCenter: parent.verticalCenter
53 53
@@ -83,14 +83,24 @@ Item {
83 } 83 }
84 } 84 }
85 85
86 IconImage { 86 Rectangle {
87 anchors.centerIn: parent 87 anchors.fill: parent
88 width: parent.width 88 color: {
89 height: parent.width 89 if (trayItemArea.containsMouse)
90 source: trayItemWrapper.iconSource 90 return "#33808080";
91 asynchronous: true 91 return "transparent";
92 smooth: true 92 }
93 mipmap: true 93
94 IconImage {
95 id: icon
96
97 anchors.centerIn: parent
98 implicitSize: 16
99 source: trayItemWrapper.iconSource
100 asynchronous: true
101 smooth: true
102 mipmap: true
103 }
94 } 104 }
95 } 105 }
96 106
@@ -116,7 +126,7 @@ Item {
116 color: "black" 126 color: "black"
117 127
118 implicitWidth: Math.max(tooltipTitle.contentWidth, tooltipDescription.contentWidth) + 16 128 implicitWidth: Math.max(tooltipTitle.contentWidth, tooltipDescription.contentWidth) + 16
119 implicitHeight: tooltipTitle.contentHeight + tooltipDescription.contentHeight + 16 129 implicitHeight: (trayItem.tooltipTitle ? tooltipTitle.contentHeight : 0) + (trayItem.tooltipDescription ? tooltipDescription.contentHeight : 0) + 16
120 130
121 WrapperMouseArea { 131 WrapperMouseArea {
122 id: tooltipMouseArea 132 id: tooltipMouseArea
@@ -130,6 +140,8 @@ Item {
130 Text { 140 Text {
131 id: tooltipTitle 141 id: tooltipTitle
132 142
143 enabled: trayItem.tooltipTitle
144
133 font.pointSize: 10 145 font.pointSize: 10
134 font.family: "Fira Sans" 146 font.family: "Fira Sans"
135 font.bold: true 147 font.bold: true
@@ -141,6 +153,8 @@ Item {
141 Text { 153 Text {
142 id: tooltipDescription 154 id: tooltipDescription
143 155
156 enabled: trayItem.tooltipDescription
157
144 font.pointSize: 10 158 font.pointSize: 10
145 font.family: "Fira Sans" 159 font.family: "Fira Sans"
146 color: "white" 160 color: "white"
diff --git a/accounts/gkleen@sif/shell/quickshell/UnixIPC.qml b/accounts/gkleen@sif/shell/quickshell/UnixIPC.qml
new file mode 100644
index 00000000..742ef4f5
--- /dev/null
+++ b/accounts/gkleen@sif/shell/quickshell/UnixIPC.qml
@@ -0,0 +1,59 @@
1import Quickshell
2import Quickshell.Io
3import Quickshell.Services.Pipewire
4import qs.Services
5
6Scope {
7 id: root
8
9 SocketServer {
10 active: true
11 path: `${Quickshell.env("XDG_RUNTIME_DIR")}/shell.sock`
12 handler: Socket {
13 parser: SplitParser {
14 onRead: line => {
15 try {
16 const command = JSON.parse(line);
17
18 if (command.Volume)
19 root.onCommandVolume(command.Volume);
20 else if (command.Brightness)
21 root.onCommandBrightness(command.Brightness);
22 else
23 console.warn("UnixIPC: Command not handled:", JSON.stringify(command));
24 } catch (e) {
25 console.warn("UnixIPC: Failed to parse command:", line, e);
26 }
27 }
28 }
29
30 onError: e => {
31 if (e == 1)
32 return;
33 console.warn("QLocalSocket::LocalSocketError", e);
34 }
35 }
36 }
37
38 PwObjectTracker {
39 objects: [ Pipewire.defaultAudioSink, Pipewire.defaultAudioSource ]
40 }
41 function onCommandVolume(command) {
42 if (command.muted === "toggle")
43 Pipewire.defaultAudioSink.audio.muted = !Pipewire.defaultAudioSink.audio.muted;
44 if (command.volume === "up")
45 Pipewire.defaultAudioSink.audio.volume += 0.02;
46 if (command.volume === "down")
47 Pipewire.defaultAudioSink.audio.volume -= 0.02;
48
49 if (command["mic-muted"] === "toggle")
50 Pipewire.defaultAudioSource.audio.muted = !Pipewire.defaultAudioSource.audio.muted;
51 }
52
53 function onCommandBrightness(command) {
54 if (command === "up")
55 Brightness.currBrightness += 0.02
56 if (command === "down")
57 Brightness.currBrightness -= 0.02
58 }
59}
diff --git a/accounts/gkleen@sif/shell/quickshell/VolumeOSD.qml b/accounts/gkleen@sif/shell/quickshell/VolumeOSD.qml
index 02dcf227..16fb5dea 100644
--- a/accounts/gkleen@sif/shell/quickshell/VolumeOSD.qml
+++ b/accounts/gkleen@sif/shell/quickshell/VolumeOSD.qml
@@ -7,11 +7,11 @@ import Quickshell.Widgets
7Scope { 7Scope {
8 id: root 8 id: root
9 9
10 property bool show: false 10 property string show: ""
11 property bool inhibited: true 11 property bool inhibited: true
12 12
13 PwObjectTracker { 13 PwObjectTracker {
14 objects: [ Pipewire.defaultAudioSink ] 14 objects: [ Pipewire.defaultAudioSink, Pipewire.defaultAudioSource ]
15 } 15 }
16 16
17 Connections { 17 Connections {
@@ -19,11 +19,25 @@ Scope {
19 target: Pipewire.defaultAudioSink?.audio 19 target: Pipewire.defaultAudioSink?.audio
20 20
21 function onVolumeChanged() { 21 function onVolumeChanged() {
22 root.show = true; 22 root.show = "sink";
23 hideTimer.restart(); 23 hideTimer.restart();
24 } 24 }
25 function onMutedChanged() { 25 function onMutedChanged() {
26 root.show = true; 26 root.show = "sink";
27 hideTimer.restart();
28 }
29 }
30
31 Connections {
32 enabled: Pipewire.defaultAudioSource
33 target: Pipewire.defaultAudioSource?.audio
34
35 function onVolumeChanged() {
36 root.show = "source";
37 hideTimer.restart();
38 }
39 function onMutedChanged() {
40 root.show = "source";
27 hideTimer.restart(); 41 hideTimer.restart();
28 } 42 }
29 } 43 }
@@ -36,7 +50,7 @@ Scope {
36 Timer { 50 Timer {
37 id: hideTimer 51 id: hideTimer
38 interval: 1000 52 interval: 1000
39 onTriggered: root.show = false 53 onTriggered: root.show = ""
40 } 54 }
41 55
42 Timer { 56 Timer {
@@ -44,7 +58,7 @@ Scope {
44 interval: 100 58 interval: 100
45 running: true 59 running: true
46 onTriggered: { 60 onTriggered: {
47 root.show = false; 61 root.show = "";
48 root.inhibited = false; 62 root.inhibited = false;
49 } 63 }
50 } 64 }
@@ -97,13 +111,20 @@ Scope {
97 implicitHeight: parent.height 111 implicitHeight: parent.height
98 112
99 icon: { 113 icon: {
100 if (!Pipewire.defaultAudioSink || Pipewire.defaultAudioSink.audio.muted) 114 if (root.show == "sink") {
101 return "volume-off"; 115 if (!Pipewire.defaultAudioSink || Pipewire.defaultAudioSink.audio.muted)
102 if (Pipewire.defaultAudioSink.audio.volume <= 0.33) 116 return "volume-off";
103 return "volume-low"; 117 if (Pipewire.defaultAudioSink.audio.volume <= 0.33)
104 if (Pipewire.defaultAudioSink.audio.volume <= 0.67) 118 return "volume-low";
105 return "volume-medium"; 119 if (Pipewire.defaultAudioSink.audio.volume <= 0.67)
106 return "volume-high"; 120 return "volume-medium";
121 return "volume-high";
122 } else if (root.show == "source") {
123 if (!Pipewire.defaultAudioSource || Pipewire.defaultAudioSource.audio.muted)
124 return "microphone-off";
125 return "microphone";
126 }
127 return "volume-high";
107 } 128 }
108 } 129 }
109 130
@@ -123,7 +144,13 @@ Scope {
123 144
124 color: Pipewire.defaultAudioSink?.audio.muted ? "#70ffffff" : "white" 145 color: Pipewire.defaultAudioSink?.audio.muted ? "#70ffffff" : "white"
125 146
126 implicitWidth: parent.width * (Pipewire.defaultAudioSink?.audio.volume ?? 0) 147 implicitWidth: {
148 if (root.show == "sink")
149 return parent.width * (Pipewire.defaultAudioSink?.audio.volume ?? 0);
150 else if (root.show == "source")
151 return parent.width * (Pipewire.defaultAudioSource?.audio.volume ?? 0);
152 return 0;
153 }
127 } 154 }
128 } 155 }
129 } 156 }
diff --git a/accounts/gkleen@sif/shell/quickshell/shell.qml b/accounts/gkleen@sif/shell/quickshell/shell.qml
index 3657f77f..0fa45f79 100644
--- a/accounts/gkleen@sif/shell/quickshell/shell.qml
+++ b/accounts/gkleen@sif/shell/quickshell/shell.qml
@@ -43,4 +43,7 @@ ShellRoot {
43 Lockscreen {} 43 Lockscreen {}
44 44
45 VolumeOSD {} 45 VolumeOSD {}
46 BrightnessOSD {}
47
48 UnixIPC {}
46} 49}
diff --git a/flake.lock b/flake.lock
index 6046d92f..05385ecd 100644
--- a/flake.lock
+++ b/flake.lock
@@ -507,11 +507,11 @@
507 "xwayland-satellite-unstable": "xwayland-satellite-unstable" 507 "xwayland-satellite-unstable": "xwayland-satellite-unstable"
508 }, 508 },
509 "locked": { 509 "locked": {
510 "lastModified": 1755424351, 510 "lastModified": 1757437545,
511 "narHash": "sha256-xcorYLNdtLpb0wH5CPlUcpmYQUxeK95j1X855xQw+DY=", 511 "narHash": "sha256-7ssbrFnmSrqtCtOySiu5ncyOBxPrR6p2nhNHrg6D+fo=",
512 "owner": "sodiboo", 512 "owner": "sodiboo",
513 "repo": "niri-flake", 513 "repo": "niri-flake",
514 "rev": "9aa137af01f05386e5bb5050e983750017007a66", 514 "rev": "ef694b996daeeb8684c0adfaa9b7067a6e709054",
515 "type": "github" 515 "type": "github"
516 }, 516 },
517 "original": { 517 "original": {
@@ -524,16 +524,16 @@
524 "niri-stable": { 524 "niri-stable": {
525 "flake": false, 525 "flake": false,
526 "locked": { 526 "locked": {
527 "lastModified": 1748151941, 527 "lastModified": 1756556321,
528 "narHash": "sha256-z4viQZLgC2bIJ3VrzQnR+q2F3gAOEQpU1H5xHtX/2fs=", 528 "narHash": "sha256-RLD89dfjN0RVO86C/Mot0T7aduCygPGaYbog566F0Qo=",
529 "owner": "YaLTeR", 529 "owner": "YaLTeR",
530 "repo": "niri", 530 "repo": "niri",
531 "rev": "8ba57fcf25d2fc9565131684a839d58703f1dae7", 531 "rev": "01be0e65f4eb91a9cd624ac0b76aaeab765c7294",
532 "type": "github" 532 "type": "github"
533 }, 533 },
534 "original": { 534 "original": {
535 "owner": "YaLTeR", 535 "owner": "YaLTeR",
536 "ref": "v25.05.1", 536 "ref": "v25.08",
537 "repo": "niri", 537 "repo": "niri",
538 "type": "github" 538 "type": "github"
539 } 539 }
@@ -541,15 +541,16 @@
541 "niri-unstable": { 541 "niri-unstable": {
542 "flake": false, 542 "flake": false,
543 "locked": { 543 "locked": {
544 "lastModified": 1755419373, 544 "lastModified": 1757438446,
545 "narHash": "sha256-EFH3zbpyLYjEboNV2Lmkxf9joEuFCmeYX+MMLRPStpg=", 545 "narHash": "sha256-4NN+weI4isQCFB+A36J+CU8tb251maVlBO9usuzgMQ8=",
546 "owner": "YaLTeR", 546 "owner": "gkleen",
547 "repo": "niri", 547 "repo": "niri",
548 "rev": "a6febb86aa5af0df7bf2792ca027ef95a503d599", 548 "rev": "2c7f7053ce360279160a9e2366d54980def848ad",
549 "type": "github" 549 "type": "github"
550 }, 550 },
551 "original": { 551 "original": {
552 "owner": "YaLTeR", 552 "owner": "gkleen",
553 "ref": "feat/unix-sockets",
553 "repo": "niri", 554 "repo": "niri",
554 "type": "github" 555 "type": "github"
555 } 556 }
@@ -780,11 +781,11 @@
780 }, 781 },
781 "nixpkgs-stable_3": { 782 "nixpkgs-stable_3": {
782 "locked": { 783 "locked": {
783 "lastModified": 1755274400, 784 "lastModified": 1757408970,
784 "narHash": "sha256-rTInmnp/xYrfcMZyFMH3kc8oko5zYfxsowaLv1LVobY=", 785 "narHash": "sha256-aSgK4BLNFFGvDTNKPeB28lVXYqVn8RdyXDNAvgGq+k0=",
785 "owner": "NixOS", 786 "owner": "NixOS",
786 "repo": "nixpkgs", 787 "repo": "nixpkgs",
787 "rev": "ad7196ae55c295f53a7d1ec39e4a06d922f3b899", 788 "rev": "d179d77c139e0a3f5c416477f7747e9d6b7ec315",
788 "type": "github" 789 "type": "github"
789 }, 790 },
790 "original": { 791 "original": {
@@ -1280,16 +1281,16 @@
1280 "xwayland-satellite-stable": { 1281 "xwayland-satellite-stable": {
1281 "flake": false, 1282 "flake": false,
1282 "locked": { 1283 "locked": {
1283 "lastModified": 1748488455, 1284 "lastModified": 1755491097,
1284 "narHash": "sha256-IiLr1alzKFIy5tGGpDlabQbe6LV1c9ABvkH6T5WmyRI=", 1285 "narHash": "sha256-m+9tUfsmBeF2Gn4HWa6vSITZ4Gz1eA1F5Kh62B0N4oE=",
1285 "owner": "Supreeeme", 1286 "owner": "Supreeeme",
1286 "repo": "xwayland-satellite", 1287 "repo": "xwayland-satellite",
1287 "rev": "3ba30b149f9eb2bbf42cf4758d2158ca8cceef73", 1288 "rev": "388d291e82ffbc73be18169d39470f340707edaa",
1288 "type": "github" 1289 "type": "github"
1289 }, 1290 },
1290 "original": { 1291 "original": {
1291 "owner": "Supreeeme", 1292 "owner": "Supreeeme",
1292 "ref": "v0.6", 1293 "ref": "v0.7",
1293 "repo": "xwayland-satellite", 1294 "repo": "xwayland-satellite",
1294 "type": "github" 1295 "type": "github"
1295 } 1296 }
@@ -1297,11 +1298,11 @@
1297 "xwayland-satellite-unstable": { 1298 "xwayland-satellite-unstable": {
1298 "flake": false, 1299 "flake": false,
1299 "locked": { 1300 "locked": {
1300 "lastModified": 1755219541, 1301 "lastModified": 1757179758,
1301 "narHash": "sha256-yKV6xHaPbEbh5RPxAJnb9yTs1wypr7do86hFFGQm1w8=", 1302 "narHash": "sha256-TIvyWzRt1miQj6Cf5Wy8Qz43XIZX7c4vTVwRLAT5S4Y=",
1302 "owner": "Supreeeme", 1303 "owner": "Supreeeme",
1303 "repo": "xwayland-satellite", 1304 "repo": "xwayland-satellite",
1304 "rev": "5a184d435927c3423f0ad189ea2b490578450fb7", 1305 "rev": "970728d0d9d1eada342bb8860af214b601139e58",
1305 "type": "github" 1306 "type": "github"
1306 }, 1307 },
1307 "original": { 1308 "original": {
diff --git a/flake.nix b/flake.nix
index b9382c6f..0b2ce0a8 100644
--- a/flake.nix
+++ b/flake.nix
@@ -209,7 +209,12 @@
209 ref = "main"; 209 ref = "main";
210 inputs = { 210 inputs = {
211 nixpkgs.follows = "nixpkgs"; 211 nixpkgs.follows = "nixpkgs";
212 # niri-unstable.url = "github:gkleen/niri"; 212 niri-unstable = {
213 type = "github";
214 owner = "gkleen";
215 repo = "niri";
216 ref = "feat/unix-sockets";
217 };
213 }; 218 };
214 }; 219 };
215 nix-monitored = { 220 nix-monitored = {
diff --git a/overlays/niri.nix b/overlays/niri.nix
index 9188ed7d..95a918b0 100644
--- a/overlays/niri.nix
+++ b/overlays/niri.nix
@@ -3,6 +3,7 @@
3 (final: prev: { 3 (final: prev: {
4 niri-unstable = prev.niri-unstable.overrideAttrs (oldAttrs: { 4 niri-unstable = prev.niri-unstable.overrideAttrs (oldAttrs: {
5 buildInputs = (oldAttrs.buildInputs or []) ++ [ final.libgbm ]; 5 buildInputs = (oldAttrs.buildInputs or []) ++ [ final.libgbm ];
6 doCheck = false;
6 }); 7 });
7 }) 8 })
8 final prev 9 final prev
diff --git a/overlays/quickshell/default.nix b/overlays/quickshell/default.nix
index 622d69a3..d806753f 100644
--- a/overlays/quickshell/default.nix
+++ b/overlays/quickshell/default.nix
@@ -5,6 +5,7 @@
5 ./greetd-response.patch 5 ./greetd-response.patch
6 ./lock-state-changed.patch 6 ./lock-state-changed.patch
7 ./pipewire.patch 7 ./pipewire.patch
8 ./io.patch
8 ]; 9 ];
9 }); 10 });
10} 11}
diff --git a/overlays/quickshell/io.patch b/overlays/quickshell/io.patch
new file mode 100644
index 00000000..961bdcaf
--- /dev/null
+++ b/overlays/quickshell/io.patch
@@ -0,0 +1,13 @@
1diff --git i/src/io/socket.cpp w/src/io/socket.cpp
2index 371f687..d12eaeb 100644
3--- i/src/io/socket.cpp
4+++ w/src/io/socket.cpp
5@@ -66,7 +66,7 @@ void Socket::onSocketDisconnected() {
6 }
7
8 void Socket::onSocketError(QLocalSocket::LocalSocketError error) {
9- qCWarning(logSocket) << "Socket error for" << this << error;
10+ // qCWarning(logSocket) << "Socket error for" << this << error;
11 emit this->error(error);
12 }
13
diff --git a/overlays/quickshell/pipewire.patch b/overlays/quickshell/pipewire.patch
index 33025d8b..2d98eefc 100644
--- a/overlays/quickshell/pipewire.patch
+++ b/overlays/quickshell/pipewire.patch
@@ -211,6 +211,34 @@ index 1a1f705..ee64858 100644
211 bool 211 bool
212 setRouteProps(qint32 routeDevice, const std::function<void*(spa_pod_builder*)>& propsCallback); 212 setRouteProps(qint32 routeDevice, const std::function<void*(spa_pod_builder*)>& propsCallback);
213 213
214diff --git i/src/services/pipewire/node.cpp w/src/services/pipewire/node.cpp
215index 3e68149..4721a58 100644
216--- i/src/services/pipewire/node.cpp
217+++ w/src/services/pipewire/node.cpp
218@@ -145,6 +145,10 @@ void PwNode::initProps(const spa_dict* props) {
219 this->type = PwNodeType::VideoSink;
220 } else if (strcmp(mediaClass, "Video/Source") == 0) {
221 this->type = PwNodeType::VideoSource;
222+ } else if (strcmp(mediaClass, "Stream/Output/Video") == 0) {
223+ this->type = PwNodeType::VideoOutStream;
224+ } else if (strcmp(mediaClass, "Stream/Input/Video") == 0) {
225+ this->type = PwNodeType::VideoInStream;
226 }
227 }
228
229diff --git i/src/services/pipewire/node.hpp w/src/services/pipewire/node.hpp
230index 0d4c92e..ee6f223 100644
231--- i/src/services/pipewire/node.hpp
232+++ w/src/services/pipewire/node.hpp
233@@ -144,6 +144,8 @@ public:
234 // This is equivalent to the media class `Video/Sink` and is composed of the
235 // @@PwNodeType.Video and @@PwNodeType.Sink flags.
236 VideoSink = Video | Sink,
237+ VideoOutStream = Video | Sink | Stream,
238+ VideoInStream = Video | Source | Stream,
239 };
240 Q_ENUM(Flag);
241 Q_DECLARE_FLAGS(Flags, Flag);
214diff --git i/src/services/pipewire/qml.cpp w/src/services/pipewire/qml.cpp 242diff --git i/src/services/pipewire/qml.cpp w/src/services/pipewire/qml.cpp
215index 9efb17e..921d12a 100644 243index 9efb17e..921d12a 100644
216--- i/src/services/pipewire/qml.cpp 244--- i/src/services/pipewire/qml.cpp
diff --git a/overlays/swayosd/default.nix b/overlays/swayosd/default.nix
deleted file mode 100644
index 5e715dae..00000000
--- a/overlays/swayosd/default.nix
+++ /dev/null
@@ -1,13 +0,0 @@
1{ final, prev, sources, ... }: {
2 swayosd = prev.swayosd.overrideAttrs (oldAttrs: rec {
3 inherit (sources.swayosd) version src;
4 cargoDeps = prev.rustPlatform.fetchCargoVendor {
5 inherit (oldAttrs) pname;
6 inherit version src;
7 hash = "sha256-J2sl6/4+bRWlkvaTJtFsMqvvOxYtWLRjJcYWcu0loRE=";
8 };
9 patches = (oldAttrs.patches or []) ++ [
10 ./exponential.patch
11 ];
12 });
13}
diff --git a/overlays/swayosd/exponential.patch b/overlays/swayosd/exponential.patch
deleted file mode 100644
index eb90d739..00000000
--- a/overlays/swayosd/exponential.patch
+++ /dev/null
@@ -1,57 +0,0 @@
1diff --git a/src/brightness_backend/brightnessctl.rs b/src/brightness_backend/brightnessctl.rs
2index ccb0e11..740fdb6 100644
3--- a/src/brightness_backend/brightnessctl.rs
4+++ b/src/brightness_backend/brightnessctl.rs
5@@ -107,10 +107,21 @@ impl VirtualDevice {
6 }
7 }
8
9- fn set_percent(&mut self, mut val: u32) -> anyhow::Result<()> {
10- val = val.clamp(0, 100);
11- self.current = self.max.map(|max| val * max / 100);
12- let _: String = self.run(("set", &*format!("{val}%")))?;
13+ fn val_to_percent(&mut self, val: u32) -> u32 {
14+ return ((val as f64 / self.get_max() as f64).powf(0.25) * 100_f64).round() as u32;
15+ }
16+ fn percent_to_val(&mut self, perc: u32) -> u32 {
17+ return ((perc as f64 / 100_f64).powf(4_f64) * self.get_max() as f64).round() as u32;
18+ }
19+
20+ fn set_percent(&mut self, val: u32) -> anyhow::Result<()> {
21+ let new = self.percent_to_val(val);
22+ self.set_val(new)
23+ }
24+ fn set_val(&mut self, val: u32) -> anyhow::Result<()> {
25+ let curr = val.clamp(0, self.get_max());
26+ self.current = Some(curr);
27+ let _: String = self.run(("set", &*format!("{curr}")))?;
28 Ok(())
29 }
30 }
31@@ -134,20 +145,18 @@ impl BrightnessBackend for BrightnessCtl {
32
33 fn lower(&mut self, by: u32) -> anyhow::Result<()> {
34 let curr = self.get_current();
35- let max = self.get_max();
36-
37- let curr = curr * 100 / max;
38+ let mut new = self.device.val_to_percent(curr).saturating_sub(by);
39+ new = self.device.percent_to_val(new).min(curr.saturating_sub(1));
40
41- self.device.set_percent(curr.saturating_sub(by))
42+ self.device.set_val(new)
43 }
44
45 fn raise(&mut self, by: u32) -> anyhow::Result<()> {
46 let curr = self.get_current();
47- let max = self.get_max();
48-
49- let curr = curr * 100 / max;
50+ let mut new = self.device.val_to_percent(curr) + by;
51+ new = self.device.percent_to_val(new).max(curr + 1);
52
53- self.device.set_percent(curr + by)
54+ self.device.set_val(new)
55 }
56
57 fn set(&mut self, val: u32) -> anyhow::Result<()> {