From d20393e077b8d97b18f4a224ddcb20caf6dac23b Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Wed, 10 Sep 2025 15:57:26 +0200 Subject: ... --- accounts/gkleen@sif/niri/default.nix | 19 ++-- accounts/gkleen@sif/niri/swayosd.nix | 66 ------------ .../shell/quickshell-plugins/Systemd.cpp | 14 ++- .../shell/quickshell-plugins/Systemd.hpp | 1 + accounts/gkleen@sif/shell/quickshell/Bar.qml | 31 +++++- .../gkleen@sif/shell/quickshell/BatteryWidget.qml | 61 +++++++++++ .../gkleen@sif/shell/quickshell/BrightnessOSD.qml | 117 +++++++++++++++++++++ .../shell/quickshell/BrightnessWidget.qml | 33 ++++++ .../shell/quickshell/MaterialDesignIcon.qml | 17 ++- .../gkleen@sif/shell/quickshell/PipewireWidget.qml | 3 +- .../gkleen@sif/shell/quickshell/PrivacyWidget.qml | 49 +++++++++ .../shell/quickshell/Services/Brightness.qml | 68 ++++++++++++ .../shell/quickshell/Services/Privacy.qml | 63 +++++++++++ .../gkleen@sif/shell/quickshell/SystemTray.qml | 6 +- accounts/gkleen@sif/shell/quickshell/UnixIPC.qml | 10 ++ accounts/gkleen@sif/shell/quickshell/shell.qml | 1 + overlays/quickshell/pipewire.patch | 28 +++++ overlays/swayosd/default.nix | 13 --- overlays/swayosd/exponential.patch | 57 ---------- 19 files changed, 497 insertions(+), 160 deletions(-) delete mode 100644 accounts/gkleen@sif/niri/swayosd.nix create mode 100644 accounts/gkleen@sif/shell/quickshell/BatteryWidget.qml create mode 100644 accounts/gkleen@sif/shell/quickshell/BrightnessOSD.qml create mode 100644 accounts/gkleen@sif/shell/quickshell/BrightnessWidget.qml create mode 100644 accounts/gkleen@sif/shell/quickshell/PrivacyWidget.qml create mode 100644 accounts/gkleen@sif/shell/quickshell/Services/Brightness.qml create mode 100644 accounts/gkleen@sif/shell/quickshell/Services/Privacy.qml delete mode 100644 overlays/swayosd/default.nix delete mode 100644 overlays/swayosd/exponential.patch diff --git a/accounts/gkleen@sif/niri/default.nix b/accounts/gkleen@sif/niri/default.nix index 1ff149bc..10b85169 100644 --- a/accounts/gkleen@sif/niri/default.nix +++ b/accounts/gkleen@sif/niri/default.nix @@ -10,7 +10,6 @@ let makoctl = lib.getExe' config.services.mako.package "makoctl"; loginctl = lib.getExe' hostConfig.systemd.package "loginctl"; systemctl = lib.getExe' hostConfig.systemd.package "systemctl"; - swayosd-client = lib.getExe' config.services.swayosd.package "swayosd-client"; focus_or_spawn = pkgs.writeShellApplication { name = "focus-or-spawn"; @@ -168,7 +167,6 @@ in { imports = [ ./waybar.nix ./mako.nix - ./swayosd.nix ]; options = { @@ -939,15 +937,6 @@ in { allow-when-locked = true; }; - "XF86MonBrightnessUp" = { - action = spawn swayosd-client "--brightness" "raise"; - allow-when-locked = true; - }; - "XF86MonBrightnessDown" = { - action = spawn swayosd-client "--brightness" "lower"; - allow-when-locked = true; - }; - "Mod+Semicolon".action = spawn makoctl "dismiss" "--group"; "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all"; "Mod+Period".action = spawn makoctl "menu" "--" (lib.getExe config.programs.fuzzel.package) "--dmenu"; @@ -988,6 +977,14 @@ in { allow-when-locked = true; action = shell { Volume."mic-muted" = "toggle"; }; }; + "XF86MonBrightnessUp" = { + action = shell { Brightness = "up"; }; + allow-when-locked = true; + }; + "XF86MonBrightnessDown" = { + action = shell { Brightness = "down"; }; + allow-when-locked = true; + }; })) (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) (map ({ name, moveKey, ...}: if moveKey != null then bind moveKey { action = kdl.magic-leaf "move-column-to-workspace" name; } else null) cfg.scratchspaces) 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 @@ -{ pkgs, ... }: -{ - config = { - services.swayosd = { - enable = true; - topMargin = 0.4769706078; - stylePath = pkgs.runCommand "style.css" { - passAsFile = [ "src" ]; - src = '' - window#osd { - padding: 12px 20px; - border-radius: 999px; - border: none; - background: rgba(0, 0, 0, 0.87); - - #container { - margin: 16px; - } - - image, - label { - color: rgb(255, 255, 255); - - &:disabled { - opacity: 1; - color: rgb(84, 84, 84); - } - } - - progressbar { - min-height: 6px; - border-radius: 999px; - background: transparent; - border: none; - - trough, progress { - min-height: inherit; - border-radius: inherit; - border: none; - } - - trough { - background: rgb(127, 127, 127); - } - progress { - background: rgb(255, 255, 255); - } - - &:disabled { - opacity: 1; - - trough { - background: rgb(19, 19, 19); - } - progress { - background: rgb(38, 38, 38); - } - } - } - } - ''; - buildInputs = with pkgs; [sass]; - } "scss -C --sourcemap=none --style=compact $srcPath $out"; - }; - }; -} 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) { "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StopUnit" - ); - m << unit; - m << mode; + ) << unit << mode; QDBusConnection::sessionBus().send(m); } + +void Systemd::setBrightness(const QString& subsystem, const QString& name, quint32 brightness) { + QDBusMessage m = QDBusMessage::createMethodCall( + "org.freedesktop.login1", + "/org/freedesktop/login1/session/auto", + "org.freedesktop.login1.Session", + "SetBrightness" + ) << subsystem << name << brightness; + QDBusConnection::systemBus().send(m); +} 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 { public: Q_INVOKABLE void stopUserUnit(const QString& unit, const QString& mode); + Q_INVOKABLE void setBrightness(const QString& subsystem, const QString& name, quint32 brightness); }; diff --git a/accounts/gkleen@sif/shell/quickshell/Bar.qml b/accounts/gkleen@sif/shell/quickshell/Bar.qml index 3652af54..399b566f 100644 --- a/accounts/gkleen@sif/shell/quickshell/Bar.qml +++ b/accounts/gkleen@sif/shell/quickshell/Bar.qml @@ -1,7 +1,6 @@ import Quickshell import QtQuick - PanelWindow { id: bar @@ -64,25 +63,49 @@ PanelWindow { anchors.verticalCenter: parent.verticalCenter spacing: 0 - PipewireWidget {} + PrivacyWidget { + id: privacy + } + + Item { + enabled: privacy.active + height: parent.height + width: 8 + } + + BatteryWidget {} + + Item { + height: parent.height + width: 8 + } + + BrightnessWidget {} Item { height: parent.height width: 4 } + PipewireWidget {} + + Item { + height: parent.height + width: 2 + } + SystemTray {} Item { height: parent.height - width: 4 + width: 2 } KeyboardLayout {} Item { height: parent.height - width: 4 + width: 8 - 4 } 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 @@ +import QtQuick +import Quickshell +import Quickshell.Widgets +import Quickshell.Services.UPower + +Item { + id: root + + height: parent.height + width: batteryIcon.width + anchors.verticalCenter: parent.verticalCenter + + property var batteryDevice: Array.from(UPower.devices.values).find(dev => dev.isLaptopBattery) + + WrapperMouseArea { + id: widgetMouseArea + + anchors.fill: parent + + hoverEnabled: true + + Item { + anchors.fill: parent + + MaterialDesignIcon { + id: batteryIcon + + implicitSize: 14 + anchors.centerIn: parent + + icon: { + if (!root.batteryDevice?.ready) + return "battery-unknown"; + + if (root.batteryDevice.state == UPowerDeviceState.FullyCharged) + return "power-plug-battery"; + + const perdec = 10 * Math.max(1, Math.ceil(root.batteryDevice.percentage * 10)); + if (root.batteryDevice.state == UPowerDeviceState.Charging) + return `battery-charging-${perdec}`; + if (perdec == 100) + return "battery"; + return `battery-${perdec}`; + } + color: { + if (!root.batteryDevice?.ready) + return "#555"; + + if (root.batteryDevice.state != UPowerDeviceState.FullyCharged && root.batteryDevice.state != UPowerDeviceState.Charging && root.batteryDevice.timeToEmpty < 20 * 60) + return "#f2201f"; + if (root.batteryDevice.state != UPowerDeviceState.FullyCharged && root.batteryDevice.state != UPowerDeviceState.Charging && root.batteryDevice.timeToEmpty < 40 * 60) + return "#f28a21"; + if (root.batteryDevice.state != UPowerDeviceState.FullyCharged) + return "#fff"; + return "#555"; + } + } + + } + } +} 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 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Widgets +import qs.Services + +Scope { + id: root + + property bool show: false + property bool inhibited: true + + Connections { + target: Brightness + + function onCurrBrightnessChanged() { + root.show = true; + hideTimer.restart(); + } + } + + onShowChanged: { + if (show) + hideTimer.restart(); + } + + Timer { + id: hideTimer + interval: 1000 + onTriggered: root.show = false + } + + Timer { + id: startInhibit + interval: 100 + running: true + onTriggered: { + root.show = false; + root.inhibited = false; + } + } + + LazyLoader { + active: root.show && !root.inhibited + + Variants { + model: Quickshell.screens + + delegate: Scope { + id: screenScope + + required property var modelData + + PanelWindow { + id: window + + screen: screenScope.modelData + + anchors.top: true + margins.top: screen.height / 2 - 50 + 3.5 + exclusiveZone: 0 + exclusionMode: ExclusionMode.Ignore + + implicitWidth: 400 + implicitHeight: 50 + + mask: Region {} + + color: "transparent" + + Rectangle { + anchors.fill: parent + color: Qt.rgba(0, 0, 0, 0.75) + } + + RowLayout { + id: layout + + anchors.centerIn: parent + + height: 50 - 8*2 + width: 400 - 8*2 + + MaterialDesignIcon { + id: volumeIcon + + implicitWidth: parent.height + implicitHeight: parent.height + + icon: `brightness-${Math.min(7, Math.floor(Brightness.currBrightness * 7) + 1)}` + } + + Rectangle { + Layout.fillWidth: true + + implicitHeight: 10 + + color: "#50ffffff" + + Rectangle { + anchors { + left: parent.left + top: parent.top + bottom: parent.bottom + } + + color: "white" + + implicitWidth: parent.width * Brightness.currBrightness + } + } + } + } + } + } + } +} 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 @@ +import QtQuick +import Quickshell +import Quickshell.Widgets +import qs.Services + +Item { + height: parent.height + width: brightnessIcon.width + anchors.verticalCenter: parent.verticalCenter + + WrapperMouseArea { + id: widgetMouseArea + + anchors.fill: parent + + property real sensitivity: (1 / 50) / 120 + onWheel: event => Brightness.currBrightness += event.angleDelta.y * sensitivity + + Item { + anchors.fill: parent + + MaterialDesignIcon { + id: brightnessIcon + + implicitSize: 14 + anchors.centerIn: parent + + icon: `brightness-${Math.min(7, Math.floor(Brightness.currBrightness * 7) + 1)}` + color: "#555" + } + } + } +} 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 import QtQuick.Effects Item { - id: icon + id: root required property string icon property color color: "white" + property real implicitSize: 0 + + readonly property real actualSize: Math.min(root.width, root.height) + + implicitWidth: root.implicitSize + implicitHeight: root.implicitSize + Image { id: sourceImage - source: "file://" + @mdi@ + "/svg/" + icon.icon + ".svg" + source: "file://" + @mdi@ + "/svg/" + root.icon + ".svg" anchors.fill: parent + fillMode: Image.PreserveAspectFit + + sourceSize.width: root.actualSize + sourceSize.height: root.actualSize layer.enabled: true layer.effect: MultiEffect { @@ -18,7 +29,7 @@ Item { brightness: 1 colorization: 1 - colorizationColor: icon.color + colorizationColor: root.color } } } 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 { MaterialDesignIcon { id: volumeIcon - width: 16 - height: 16 + implicitSize: 14 anchors.centerIn: parent 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 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Widgets +import qs.Services + +Item { + height: parent.height + width: layout.childrenRect.width + anchors.verticalCenter: parent.verticalCenter + + readonly property bool active: Boolean(Privacy.activeItems) + + RowLayout { + id: layout + + anchors.fill: parent + + spacing: 8 + + Repeater { + model: Privacy.activeItems + + Item { + id: privacyItem + + required property var modelData; + + height: parent.height + width: icon.width + + MaterialDesignIcon { + id: icon + + implicitSize: 14 + anchors.centerIn: parent + + icon: { + if (privacyItem.modelData == Privacy.Item.Microphone) + return "microphone"; + if (privacyItem.modelData == Privacy.Item.Screensharing) + return "monitor-share"; + } + color: "#f2201f" + } + } + } + } +} 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..545ef24f --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/Services/Brightness.qml @@ -0,0 +1,68 @@ +pragma Singleton + +import QtQml +import Quickshell +import Quickshell.Io +import Custom as Custom + +Singleton { + id: root + + property string subsystem: "backlight" + property string device: "intel_backlight" + + property real currBrightness + property real exponent: 4 + + function calcCurrBrightness() { + if (!currFile.loaded || !maxFile.loaded) + return undefined; + const curr = Number(currFile.text()); + const max = Number(maxFile.text()); + const val = Math.pow(curr / max, 1 / root.exponent); + return val; + } + + Component.onCompleted: root.currBrightness = root.calcCurrBrightness() + Connections { + target: currFile + onLoaded: root.currBrightness = root.calcCurrBrightness() + } + Connections { + target: maxFile + onLoaded: root.currBrightness = root.calcCurrBrightness() + } + + onCurrBrightnessChanged: { + root.currBrightness = Math.max(0, Math.min(1, root.currBrightness)); + + const prev = root.calcCurrBrightness(); + if (typeof prev === 'undefined' || Math.abs(root.currBrightness - prev) < 0.01) + return; + + const max = Number(maxFile.text()); + const actual = Number(currFile.text()); + let curr = Math.max(0, Math.min(max, Math.pow(root.currBrightness, root.exponent) * max)); + if (Math.round(curr) == actual && curr < actual) + curr = Math.max(0, actual - 1); + else if (Math.round(curr) == actual && curr > actual) + curr = Math.min(max, actual + 1); + // root.currBrightness = Math.pow(curr / max, 1 / root.exponent); + Custom.Systemd.setBrightness(root.subsystem, root.device, Math.round(curr)); + } + + FileView { + id: currFile + path: `/sys/class/${root.subsystem}/${root.device}/brightness` + blockAllReads: true + watchChanges: true + onFileChanged: reload() + } + FileView { + id: maxFile + path: `/sys/class/${root.subsystem}/${root.device}/max_brightness` + blockAllReads: true + watchChanges: true + onFileChanged: reload() + } +} 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 @@ +pragma Singleton + +import QtQml +import Quickshell +import Quickshell.Services.Pipewire + +Singleton { + id: root + + PwObjectTracker { + objects: Pipewire.nodes.values + } + + enum Item { + Microphone, + Screensharing + } + + readonly property list activeItems: { + var items = []; + if (microphoneActive) + items.push(Privacy.Item.Microphone); + if (screensharingActive) + items.push(Privacy.Item.Screensharing); + return items; + } + + readonly property bool microphoneActive: { + if (!Pipewire.ready || !Pipewire.nodes?.values) { + return false + } + + for (const node of Pipewire.nodes.values) { + if (!node || (node.type & PwNodeType.AudioInStream) != PwNodeType.AudioInStream) + continue; + + if (node.properties?.["stream.monitor"] === "true") + continue; + + if (node.audio?.muted) + continue; + + return true; + } + + return false; + } + + readonly property bool screensharingActive: { + if (!Pipewire.ready || !Pipewire.nodes?.values) { + return false + } + + for (const node of Pipewire.nodes.values) { + if (!node || (node.type & PwNodeType.VideoInStream) != PwNodeType.VideoInStream) + continue; + + return true; + } + + return false; + } +} diff --git a/accounts/gkleen@sif/shell/quickshell/SystemTray.qml b/accounts/gkleen@sif/shell/quickshell/SystemTray.qml index 55b1690e..956f3995 100644 --- a/accounts/gkleen@sif/shell/quickshell/SystemTray.qml +++ b/accounts/gkleen@sif/shell/quickshell/SystemTray.qml @@ -116,7 +116,7 @@ Item { color: "black" implicitWidth: Math.max(tooltipTitle.contentWidth, tooltipDescription.contentWidth) + 16 - implicitHeight: tooltipTitle.contentHeight + tooltipDescription.contentHeight + 16 + implicitHeight: (trayItem.tooltipTitle ? tooltipTitle.contentHeight : 0) + (trayItem.tooltipDescription ? tooltipDescription.contentHeight : 0) + 16 WrapperMouseArea { id: tooltipMouseArea @@ -130,6 +130,8 @@ Item { Text { id: tooltipTitle + enabled: trayItem.tooltipTitle + font.pointSize: 10 font.family: "Fira Sans" font.bold: true @@ -141,6 +143,8 @@ Item { Text { id: tooltipDescription + enabled: trayItem.tooltipDescription + font.pointSize: 10 font.family: "Fira Sans" color: "white" diff --git a/accounts/gkleen@sif/shell/quickshell/UnixIPC.qml b/accounts/gkleen@sif/shell/quickshell/UnixIPC.qml index 7b308ec0..742ef4f5 100644 --- a/accounts/gkleen@sif/shell/quickshell/UnixIPC.qml +++ b/accounts/gkleen@sif/shell/quickshell/UnixIPC.qml @@ -1,6 +1,7 @@ import Quickshell import Quickshell.Io import Quickshell.Services.Pipewire +import qs.Services Scope { id: root @@ -16,6 +17,8 @@ Scope { if (command.Volume) root.onCommandVolume(command.Volume); + else if (command.Brightness) + root.onCommandBrightness(command.Brightness); else console.warn("UnixIPC: Command not handled:", JSON.stringify(command)); } catch (e) { @@ -46,4 +49,11 @@ Scope { if (command["mic-muted"] === "toggle") Pipewire.defaultAudioSource.audio.muted = !Pipewire.defaultAudioSource.audio.muted; } + + function onCommandBrightness(command) { + if (command === "up") + Brightness.currBrightness += 0.02 + if (command === "down") + Brightness.currBrightness -= 0.02 + } } diff --git a/accounts/gkleen@sif/shell/quickshell/shell.qml b/accounts/gkleen@sif/shell/quickshell/shell.qml index 3bb2ae00..0fa45f79 100644 --- a/accounts/gkleen@sif/shell/quickshell/shell.qml +++ b/accounts/gkleen@sif/shell/quickshell/shell.qml @@ -43,6 +43,7 @@ ShellRoot { Lockscreen {} VolumeOSD {} + BrightnessOSD {} UnixIPC {} } 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 bool setRouteProps(qint32 routeDevice, const std::function& propsCallback); +diff --git i/src/services/pipewire/node.cpp w/src/services/pipewire/node.cpp +index 3e68149..4721a58 100644 +--- i/src/services/pipewire/node.cpp ++++ w/src/services/pipewire/node.cpp +@@ -145,6 +145,10 @@ void PwNode::initProps(const spa_dict* props) { + this->type = PwNodeType::VideoSink; + } else if (strcmp(mediaClass, "Video/Source") == 0) { + this->type = PwNodeType::VideoSource; ++ } else if (strcmp(mediaClass, "Stream/Output/Video") == 0) { ++ this->type = PwNodeType::VideoOutStream; ++ } else if (strcmp(mediaClass, "Stream/Input/Video") == 0) { ++ this->type = PwNodeType::VideoInStream; + } + } + +diff --git i/src/services/pipewire/node.hpp w/src/services/pipewire/node.hpp +index 0d4c92e..ee6f223 100644 +--- i/src/services/pipewire/node.hpp ++++ w/src/services/pipewire/node.hpp +@@ -144,6 +144,8 @@ public: + // This is equivalent to the media class `Video/Sink` and is composed of the + // @@PwNodeType.Video and @@PwNodeType.Sink flags. + VideoSink = Video | Sink, ++ VideoOutStream = Video | Sink | Stream, ++ VideoInStream = Video | Source | Stream, + }; + Q_ENUM(Flag); + Q_DECLARE_FLAGS(Flags, Flag); diff --git i/src/services/pipewire/qml.cpp w/src/services/pipewire/qml.cpp index 9efb17e..921d12a 100644 --- 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 @@ -{ final, prev, sources, ... }: { - swayosd = prev.swayosd.overrideAttrs (oldAttrs: rec { - inherit (sources.swayosd) version src; - cargoDeps = prev.rustPlatform.fetchCargoVendor { - inherit (oldAttrs) pname; - inherit version src; - hash = "sha256-J2sl6/4+bRWlkvaTJtFsMqvvOxYtWLRjJcYWcu0loRE="; - }; - patches = (oldAttrs.patches or []) ++ [ - ./exponential.patch - ]; - }); -} 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 @@ -diff --git a/src/brightness_backend/brightnessctl.rs b/src/brightness_backend/brightnessctl.rs -index ccb0e11..740fdb6 100644 ---- a/src/brightness_backend/brightnessctl.rs -+++ b/src/brightness_backend/brightnessctl.rs -@@ -107,10 +107,21 @@ impl VirtualDevice { - } - } - -- fn set_percent(&mut self, mut val: u32) -> anyhow::Result<()> { -- val = val.clamp(0, 100); -- self.current = self.max.map(|max| val * max / 100); -- let _: String = self.run(("set", &*format!("{val}%")))?; -+ fn val_to_percent(&mut self, val: u32) -> u32 { -+ return ((val as f64 / self.get_max() as f64).powf(0.25) * 100_f64).round() as u32; -+ } -+ fn percent_to_val(&mut self, perc: u32) -> u32 { -+ return ((perc as f64 / 100_f64).powf(4_f64) * self.get_max() as f64).round() as u32; -+ } -+ -+ fn set_percent(&mut self, val: u32) -> anyhow::Result<()> { -+ let new = self.percent_to_val(val); -+ self.set_val(new) -+ } -+ fn set_val(&mut self, val: u32) -> anyhow::Result<()> { -+ let curr = val.clamp(0, self.get_max()); -+ self.current = Some(curr); -+ let _: String = self.run(("set", &*format!("{curr}")))?; - Ok(()) - } - } -@@ -134,20 +145,18 @@ impl BrightnessBackend for BrightnessCtl { - - fn lower(&mut self, by: u32) -> anyhow::Result<()> { - let curr = self.get_current(); -- let max = self.get_max(); -- -- let curr = curr * 100 / max; -+ let mut new = self.device.val_to_percent(curr).saturating_sub(by); -+ new = self.device.percent_to_val(new).min(curr.saturating_sub(1)); - -- self.device.set_percent(curr.saturating_sub(by)) -+ self.device.set_val(new) - } - - fn raise(&mut self, by: u32) -> anyhow::Result<()> { - let curr = self.get_current(); -- let max = self.get_max(); -- -- let curr = curr * 100 / max; -+ let mut new = self.device.val_to_percent(curr) + by; -+ new = self.device.percent_to_val(new).max(curr + 1); - -- self.device.set_percent(curr + by) -+ self.device.set_val(new) - } - - fn set(&mut self, val: u32) -> anyhow::Result<()> { -- cgit v1.2.3