diff options
| -rwxr-xr-x | extras/HOME/.local/bin/set-app-volume.sh | 101 | ||||
| -rwxr-xr-x | install.sh | 2 | ||||
| -rw-r--r-- | src/Main.hs | 1 | ||||
| -rw-r--r-- | src/Rahm/Desktop/Dragging.hs | 14 | ||||
| -rw-r--r-- | src/Rahm/Desktop/Keys.hs | 21 |
5 files changed, 110 insertions, 29 deletions
diff --git a/extras/HOME/.local/bin/set-app-volume.sh b/extras/HOME/.local/bin/set-app-volume.sh index 8080cca..cc16185 100755 --- a/extras/HOME/.local/bin/set-app-volume.sh +++ b/extras/HOME/.local/bin/set-app-volume.sh @@ -4,39 +4,97 @@ set -e # Best-effort script to control volume of the focused application, # falling back to the default sink. +# +# MODIFIED: Now checks for Spotify and uses 'playerctl' if found. +# MODIFIED: Pactl branch now matches on process binary name, not PID. -USAGE="Usage: $(basename "$0") WINDOW_ID [--up | --down]" +USAGE="Usage: $(basename "$0") WINDOW_ID [--up | --down | --set <0-100>]" +CHANGE_PCT="5" # Percent to change # Get the focused window ID FOCUSED_WIN_ID="$1" - shift; +ACTION=$1 +ARGUMENT=$2 + +# --- Check if the window is Spotify --- +IS_SPOTIFY=0 +if [ -n "$FOCUSED_WIN_ID" ] && [ "$FOCUSED_WIN_ID" != "0" ]; then + # xprop output is: WM_CLASS(STRING) = "spotify", "Spotify" + # We check for "spotify" case-insensitive + if xprop -id "$FOCUSED_WIN_ID" WM_CLASS | grep -q -i "spotify"; then + IS_SPOTIFY=1 + fi +fi + + +# --- BRANCH 1: SPOTIFY LOGIC (use playerctl) --- +if [ "$IS_SPOTIFY" -eq 1 ]; then + echo "Spotify window detected. Using playerctl." >&2 + + # playerctl volume is a float from 0.0 to 1.0 + # We use awk to convert our 5% to 0.05 + CHANGE_FLOAT=$(awk "BEGIN {print $CHANGE_PCT / 100}") + + case $ACTION in + --up) + playerctl --player=spotify volume "${CHANGE_FLOAT}+" + ;; + --down) + playerctl --player=spotify volume "${CHANGE_FLOAT}-" + ;; + --set) + # Convert 0-100 input to 0.0-1.0 float + TARGET_VOL=$(awk "BEGIN {print $ARGUMENT / 100}") + playerctl --player=spotify volume "$TARGET_VOL" + ;; + *) + echo "$USAGE" >&2 + exit 1 + ;; + esac + + # We are done. Exit successfully. + exit 0 +fi + + +# --- BRANCH 2: DEFAULT PACTL LOGIC (if not Spotify) --- +echo "Non-Spotify window. Using pactl." >&2 + SINK_INPUT_INDEX="" if [ -n "$FOCUSED_WIN_ID" ] && [ "$FOCUSED_WIN_ID" != "0" ]; then # Get the PID of the focused window PID=$(xprop -id "$FOCUSED_WIN_ID" _NET_WM_PID | awk '{print $NF}') if [ -n "$PID" ]; then - # Find PulseAudio sink input index for this PID - SINK_INPUT_INDEX=$(pactl list sink-inputs | perl -ne ' - BEGIN { - our $sink_id = -1; - our $maybe_sink_id = -1; - } - if (/Sink Input #(\d+)/) { - $maybe_sink_id = $1; - } - if (/application\.process\.id = "'"$PID"'"/) { - $sink_id = $maybe_sink_id; - } - END { print "$sink_id\n"; } -') + # NEW: Get the binary name from the PID + BINARY_NAME=$(ps -p "$PID" -o comm= | tr -d '[:space:]') + echo "Looking for binary $BINARY_NAME" + + if [ -n "$BINARY_NAME" ]; then + # Find PulseAudio sink input index for this BINARY_NAME + # This is more robust than PID for apps like browsers + SINK_INPUT_INDEX=$(pactl list sink-inputs | perl -ne ' + BEGIN { + our $sink_id = -1; + our $maybe_sink_id = -1; + } + if (/Sink Input #(\d+)/) { + $maybe_sink_id = $1; + } + # Match the binary name, e.g., application.process.binary = "firefox" + if (/application\.process\.binary = "'"$BINARY_NAME"'"/) { + $sink_id = $maybe_sink_id; + } + END { print "$sink_id\n"; } + ') + fi fi fi -ACTION=$1 -CHANGE="5%" +CHANGE="${CHANGE_PCT}%" set_volume() { local target=$1 @@ -51,7 +109,7 @@ set_volume() { } TARGET="@DEFAULT_SINK@" -if [ -n "$SINK_INPUT_INDEX" -a "$SINK_INPUT_INDEX" -ne -1 ]; then +if [ -n "$SINK_INPUT_INDEX" ] && [ "$SINK_INPUT_INDEX" -ne -1 ]; then TARGET="SINK INPUT #$SINK_INPUT_INDEX" fi @@ -62,9 +120,14 @@ case $ACTION in --down) set_volume "$TARGET" "-$CHANGE" ;; + --set) + # pactl can take a percentage directly + set_volume "$TARGET" "${ARGUMENT}%" + ;; *) echo "$USAGE" >&2 exit 1 ;; esac + @@ -19,7 +19,7 @@ cc -o \ build/extras/HOME/.xmonad/automonitor \ extras/util/automonitor/automonitor.c \ -ludev - + ln -sf "$(stack path --local-install-root)/bin/xmobar-weather" build/extras/HOME/.xmonad/xmobar-weather ln -sf "$(stack path --local-install-root)/bin/xmobar-weather" extras/HOME/.xmonad/xmobar-weather diff --git a/src/Main.hs b/src/Main.hs index 09810e2..1c67732 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -123,6 +123,7 @@ main = do className =? "yakuake" --> doFloat, className =? "MPlayer" --> doFloat, className =? "zenity" --> doCenterFloat, + className =? "gnuplot_qt" --> doCenterFloat, className =? "Yad" --> doCenterFloat, className =? "Xfce4-notifyd" --> doIgnore, className =? "popup-terminal" --> doShift "*" <> updatePopupTerminalHook, diff --git a/src/Rahm/Desktop/Dragging.hs b/src/Rahm/Desktop/Dragging.hs index c95deff..1f19290 100644 --- a/src/Rahm/Desktop/Dragging.hs +++ b/src/Rahm/Desktop/Dragging.hs @@ -11,7 +11,7 @@ import Data.Maybe (fromMaybe, isJust, mapMaybe) import qualified Data.Set as Set import Graphics.X11.Xlib.Extras import Rahm.Desktop.BorderColors (BorderColor (BorderColor), setBorderColor) -import Rahm.Desktop.Common (pointerLocation, pointerWindow, runMaybeT_, floatAll) +import Rahm.Desktop.Common (floatAll, pointerLocation, pointerWindow, runMaybeT_) import Rahm.Desktop.Layout.Hole (addHoleForWindow, removeHoleForWindow, resetHole) import Rahm.Desktop.Layout.PinWindow (isWindowPinned, pinWindow, unpinWindow) import Rahm.Desktop.Logger @@ -20,6 +20,7 @@ import qualified Rahm.Desktop.StackSet as W import XMonad (X, io) import qualified XMonad as X import XMonad.Util.WindowProperties (getProp32s) +import Rahm.Desktop.Workspaces (accompanyingWorkspace) -- Action which happens after a dragging event. -- @@ -217,6 +218,17 @@ dragWorkspace = do lift $ X.windows $ W.switchWorkspaces ws1 ws2 +dragAlternateWorkspace :: X () +dragAlternateWorkspace = do + (ox, oy) <- pointerLocation + X.mouseDrag (\_ _ -> return ()) $ do + (nx, ny) <- pointerLocation + runMaybeT_ $ do + (W.Screen (W.tag -> ws1) _ _) <- MaybeT $ X.pointScreen ox oy + (W.Screen (W.tag -> ws2) _ _) <- MaybeT $ X.pointScreen nx ny + + lift $ X.windows $ W.switchWorkspaces (accompanyingWorkspace ws1) ws2 + dragWindow :: X () dragWindow = do w <- pointerWindow diff --git a/src/Rahm/Desktop/Keys.hs b/src/Rahm/Desktop/Keys.hs index 1985caf..4a2a426 100644 --- a/src/Rahm/Desktop/Keys.hs +++ b/src/Rahm/Desktop/Keys.hs @@ -150,6 +150,8 @@ import XMonad.Layout.Spacing import XMonad.Util.Run (hPutStrLn, safeSpawn, spawnPipe) import XMonad.Util.WindowProperties import Prelude hiding ((!!)) +import Rahm.Desktop.Dragging (windowsUnderCursor) +import Control.Applicative type KeyMap l = XConfig l -> Map (KeyMask, KeySym) (X ()) @@ -163,9 +165,13 @@ safeSpawnX = safeSpawn selectedWindowsColor = BorderColor "#00ffff" "#00ffff" -decreaseVolume = spawnX "set-app-volume.sh --down" +decreaseVolume = do + wins <- (<|>[0]) <$> windowsUnderCursor + spawnX $ printf "set-app-volume.sh %d --down" (head wins) -increaseVolume = spawnX "set-app-volume.sh --up" +increaseVolume = do + wins <- (<|>[0]) <$> windowsUnderCursor + spawnX $ printf "set-app-volume.sh %d --up" (head wins) playPause = spawnX "media-control play" @@ -1058,6 +1064,11 @@ bindings = do doc "Drag a workspace to a different screen" $ noWindow D.dragWorkspace + bind button15 $ + noMod $ + doc "Drag a workspace to a different screen" $ + noWindow D.dragAlternateWorkspace + bind button1 $ noMod $ doc "Swap a window with another window by dragging." $ @@ -1069,12 +1080,6 @@ bindings = do noWindow $ click >> sendMessage togglePop - bind button15 $ do - noMod $ - doc "Spawn 'pavucontrol'" $ - noWindow $ - spawnX "pavucontrol" - let mediaButtons = [ (button4, "Increase volume", noWindow increaseVolume), (button5, "Decrease volume", noWindow decreaseVolume), |