diff --git a/hosts/RyanMac/configuration.nix b/hosts/RyanMac/configuration.nix
index 088b774..19ffeec 100644
--- a/hosts/RyanMac/configuration.nix
+++ b/hosts/RyanMac/configuration.nix
@@ -179,6 +179,7 @@ in {
"tailscale-app"
"netbird-ui"
"ubersicht"
+ "hammerspoon"
];
};
diff --git a/users/ryan/hammerspoon/init.lua b/users/ryan/hammerspoon/init.lua
new file mode 100644
index 0000000..1245a09
--- /dev/null
+++ b/users/ryan/hammerspoon/init.lua
@@ -0,0 +1,35 @@
+-- ~/.hammerspoon/init.lua
+
+local function refreshWidget()
+ hs.http.asyncGet("http://127.0.0.1:7776/widget/sound/refresh", nil, function(status, body, headers)
+ -- optional: log failures
+ if status ~= 200 then
+ print("Widget refresh failed with status: " .. tostring(status))
+ end
+ end)
+end
+
+local function audioWatcherCallback(uid, eventName, scope, element)
+ -- "vmvc" = volume changed, "mute" = mute toggled
+ if eventName == "vmvc" or eventName == "mute" then
+ refreshWidget()
+ end
+end
+
+local function setupAudioWatcher()
+ local device = hs.audiodevice.defaultOutputDevice()
+ if device then
+ device:watcherCallback(audioWatcherCallback)
+ device:watcherStart()
+ end
+end
+
+setupAudioWatcher()
+
+-- Re-attach the watcher if the default output device changes (e.g. plugging in headphones)
+hs.audiodevice.watcher.setCallback(function(event)
+ if event == "dOut " then -- note: the trailing space is intentional, it's part of the event name
+ setupAudioWatcher()
+ end
+end)
+hs.audiodevice.watcher.start()
diff --git a/users/ryan/home.nix b/users/ryan/home.nix
index f1c1b32..2aaacb3 100644
--- a/users/ryan/home.nix
+++ b/users/ryan/home.nix
@@ -106,6 +106,9 @@
'';
};
+ # Add hammerspoon if on mac
+ home.file.".hammerspoon".source = lib.mkIf pkgs.stdenv.isDarwin ./hammerspoon;
+
programs.zsh = {
enable = true;
initContent = let
diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/sound.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/sound.jsx
index a3c5cab..3b39594 100755
--- a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/sound.jsx
+++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/sound.jsx
@@ -56,7 +56,7 @@ export const Widget = React.memo(() => {
if (!visible) return;
const output = await Utils.cachedRun(
`osascript -e 'set v to get volume settings' -e 'output volume of v & output muted of v'`,
- refresh,
+ 500,
);
const parts = Utils.cleanupOutput(output).split(", ");
setState({