2020-03-28 18:38:38 -04:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | General commands
|
|
|
|
|
2020-04-01 20:17:47 -04:00
|
|
|
module XMonad.Internal.Command.Desktop
|
|
|
|
( myTerm
|
|
|
|
, runTerm
|
2021-06-17 01:17:59 -04:00
|
|
|
, runTMux
|
2020-04-01 20:17:47 -04:00
|
|
|
, runCalc
|
|
|
|
, runBrowser
|
|
|
|
, runEditor
|
|
|
|
, runFileManager
|
|
|
|
, runTogglePlay
|
|
|
|
, runPrevTrack
|
|
|
|
, runNextTrack
|
|
|
|
, runStopPlay
|
|
|
|
, runVolumeDown
|
|
|
|
, runVolumeUp
|
|
|
|
, runVolumeMute
|
|
|
|
, runToggleBluetooth
|
2020-05-28 23:17:17 -04:00
|
|
|
, runToggleEthernet
|
2020-04-01 20:17:47 -04:00
|
|
|
, runRestart
|
|
|
|
, runRecompile
|
|
|
|
, runAreaCapture
|
|
|
|
, runScreenCapture
|
|
|
|
, runDesktopCapture
|
2020-05-03 00:04:35 -04:00
|
|
|
, runCaptureBrowser
|
2021-02-04 21:46:04 -05:00
|
|
|
, runStartISyncTimer
|
|
|
|
, runStartISyncService
|
2021-10-24 13:30:30 -04:00
|
|
|
, runNotificationClose
|
|
|
|
, runNotificationCloseAll
|
|
|
|
, runNotificationHistory
|
|
|
|
, runNotificationContext
|
2021-11-20 01:15:04 -05:00
|
|
|
, playSound
|
2020-04-01 20:17:47 -04:00
|
|
|
) where
|
|
|
|
|
2021-11-11 00:11:15 -05:00
|
|
|
import Control.Monad (void)
|
2021-11-20 01:15:04 -05:00
|
|
|
import Control.Monad.IO.Class
|
2020-04-01 20:17:47 -04:00
|
|
|
|
2020-05-03 00:04:35 -04:00
|
|
|
import System.Directory
|
|
|
|
( createDirectoryIfMissing
|
|
|
|
, getHomeDirectory
|
|
|
|
)
|
|
|
|
import System.Environment
|
|
|
|
import System.FilePath
|
2020-03-28 18:38:38 -04:00
|
|
|
|
|
|
|
import XMonad.Actions.Volume
|
2021-11-11 00:11:15 -05:00
|
|
|
import XMonad.Core hiding (spawn)
|
2021-11-07 13:35:08 -05:00
|
|
|
import XMonad.Internal.Dependency
|
2020-04-01 20:17:47 -04:00
|
|
|
import XMonad.Internal.Notify
|
2020-04-06 00:14:56 -04:00
|
|
|
import XMonad.Internal.Process
|
2021-11-20 01:15:04 -05:00
|
|
|
import XMonad.Internal.Shell
|
2020-03-28 18:38:38 -04:00
|
|
|
import XMonad.Operations
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
2021-06-19 00:17:47 -04:00
|
|
|
-- | My Executables
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2020-04-01 20:17:47 -04:00
|
|
|
myTerm :: String
|
|
|
|
myTerm = "urxvt"
|
|
|
|
|
2021-06-19 00:17:47 -04:00
|
|
|
myBrowser :: String
|
|
|
|
myBrowser = "brave-accel"
|
|
|
|
|
|
|
|
myEditor :: String
|
|
|
|
myEditor = "emacsclient"
|
|
|
|
|
|
|
|
myMultimediaCtl :: String
|
|
|
|
myMultimediaCtl = "playerctl"
|
|
|
|
|
|
|
|
myBluetooth :: String
|
|
|
|
myBluetooth = "bluetoothctl"
|
|
|
|
|
|
|
|
myCapture :: String
|
|
|
|
myCapture = "flameshot"
|
|
|
|
|
|
|
|
myImageBrowser :: String
|
|
|
|
myImageBrowser = "feh"
|
|
|
|
|
2021-10-24 13:30:30 -04:00
|
|
|
myNotificationCtrl :: String
|
|
|
|
myNotificationCtrl = "dunstctl"
|
|
|
|
|
2021-06-19 00:17:47 -04:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | Misc constants
|
|
|
|
|
|
|
|
volumeChangeSound :: FilePath
|
|
|
|
volumeChangeSound = "smb_fireball.wav"
|
|
|
|
|
|
|
|
ethernetIface :: String
|
|
|
|
ethernetIface = "enp7s0f1"
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2021-06-19 00:17:47 -04:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | Some nice apps
|
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runTerm :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runTerm = featureSpawn "terminal" myTerm
|
2021-06-19 00:17:47 -04:00
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runTMux :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runTMux = featureRun "terminal multiplexer" deps cmd
|
2021-06-17 01:17:59 -04:00
|
|
|
where
|
2021-11-20 19:35:24 -05:00
|
|
|
deps = [Executable myTerm, Executable "tmux", Executable "bash"]
|
2021-06-19 00:17:47 -04:00
|
|
|
cmd = spawn
|
|
|
|
$ "tmux has-session"
|
|
|
|
#!&& fmtCmd myTerm ["-e", "bash", "-c", singleQuote c]
|
|
|
|
#!|| fmtNotifyCmd defNoteError { body = Just $ Text msg }
|
2021-06-17 01:17:59 -04:00
|
|
|
c = "exec tmux attach-session -d"
|
|
|
|
msg = "could not connect to tmux session"
|
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runCalc :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runCalc = featureRun "calculator" [Executable myTerm, Executable "R"]
|
|
|
|
$ spawnCmd myTerm ["-e", "R"]
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runBrowser :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runBrowser = featureSpawn "web browser" myBrowser
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runEditor :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runEditor = featureSpawnCmd "text editor" myEditor
|
2021-06-17 01:17:59 -04:00
|
|
|
["-c", "-e", doubleQuote "(select-frame-set-input-focus (selected-frame))"]
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runFileManager :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runFileManager = featureSpawn "file browser" "pcmanfm"
|
2020-03-28 18:38:38 -04:00
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | Multimedia Commands
|
|
|
|
|
2021-11-20 19:35:24 -05:00
|
|
|
runMultimediaIfInstalled :: String -> String -> FeatureX
|
|
|
|
runMultimediaIfInstalled n cmd =
|
|
|
|
featureSpawnCmd (n ++ " multimedia control") myMultimediaCtl [cmd]
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runTogglePlay :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runTogglePlay = runMultimediaIfInstalled "play/pause" "play-pause"
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runPrevTrack :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runPrevTrack = runMultimediaIfInstalled "previous track" "previous"
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runNextTrack :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runNextTrack = runMultimediaIfInstalled "next track" "next"
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runStopPlay :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runStopPlay = runMultimediaIfInstalled "stop playback" "stop"
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | Volume Commands
|
|
|
|
|
|
|
|
soundDir :: FilePath
|
|
|
|
soundDir = "sound"
|
|
|
|
|
|
|
|
playSound :: MonadIO m => FilePath -> m ()
|
|
|
|
playSound file = do
|
|
|
|
p <- (</> soundDir </> file) <$> getXMonadDir
|
|
|
|
-- paplay seems to have less latency than aplay
|
|
|
|
spawnCmd "paplay" [p]
|
2020-05-31 20:56:57 -04:00
|
|
|
|
2021-11-20 19:35:24 -05:00
|
|
|
featureSound :: String -> FilePath -> X () -> X () -> FeatureX
|
|
|
|
featureSound n file pre post =
|
|
|
|
featureRun ("volume " ++ n ++ " control") [Executable "paplay"]
|
2021-11-20 01:15:04 -05:00
|
|
|
$ pre >> playSound file >> post
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runVolumeDown :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runVolumeDown = featureSound "up" volumeChangeSound (return ()) $ void (lowerVolume 2)
|
2021-11-20 01:15:04 -05:00
|
|
|
|
|
|
|
runVolumeUp :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runVolumeUp = featureSound "down" volumeChangeSound (return ()) $ void (raiseVolume 2)
|
2021-11-20 01:15:04 -05:00
|
|
|
|
|
|
|
runVolumeMute :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runVolumeMute = featureSound "mute" volumeChangeSound (void toggleMute) $ return ()
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2021-10-24 13:30:30 -04:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | Notification control
|
|
|
|
|
2021-11-20 19:35:24 -05:00
|
|
|
runNotificationCmd :: String -> String -> FeatureX
|
|
|
|
runNotificationCmd n cmd =
|
|
|
|
featureSpawnCmd (n ++ " control") myNotificationCtrl [cmd]
|
2021-10-24 13:30:30 -04:00
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runNotificationClose :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runNotificationClose = runNotificationCmd "close notification" "close"
|
2021-10-24 13:30:30 -04:00
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runNotificationCloseAll :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runNotificationCloseAll =
|
|
|
|
runNotificationCmd "close all notifications" "close-all"
|
2021-10-24 13:30:30 -04:00
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runNotificationHistory :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runNotificationHistory =
|
|
|
|
runNotificationCmd "see notification history" "history-pop"
|
2021-10-24 13:30:30 -04:00
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runNotificationContext :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runNotificationContext =
|
|
|
|
runNotificationCmd "open notification context" "context"
|
2021-10-24 13:30:30 -04:00
|
|
|
|
2020-03-28 18:38:38 -04:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | System commands
|
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runToggleBluetooth :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runToggleBluetooth =
|
|
|
|
featureRun "bluetooth toggle" [Executable myBluetooth]
|
|
|
|
$ spawn
|
2021-06-19 00:17:47 -04:00
|
|
|
$ myBluetooth ++ " show | grep -q \"Powered: no\""
|
2020-03-28 18:38:38 -04:00
|
|
|
#!&& "a=on"
|
|
|
|
#!|| "a=off"
|
2021-06-19 00:17:47 -04:00
|
|
|
#!>> fmtCmd myBluetooth ["power", "$a", ">", "/dev/null"]
|
2020-03-28 18:38:38 -04:00
|
|
|
#!&& fmtNotifyCmd defNoteInfo { body = Just $ Text "bluetooth powered $a" }
|
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runToggleEthernet :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runToggleEthernet = featureRun "ethernet toggle" [Executable "nmcli"]
|
|
|
|
$ spawn
|
2020-05-28 23:17:17 -04:00
|
|
|
$ "nmcli -g GENERAL.STATE device show " ++ ethernetIface ++ " | grep -q disconnected"
|
|
|
|
#!&& "a=connect"
|
|
|
|
#!|| "a=disconnect"
|
|
|
|
#!>> fmtCmd "nmcli" ["device", "$a", ethernetIface]
|
|
|
|
#!&& fmtNotifyCmd defNoteInfo { body = Just $ Text "ethernet \"$a\"ed" }
|
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runStartISyncTimer :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runStartISyncTimer = featureRun "isync timer" [userUnit "mbsync.timer"]
|
2021-06-20 17:17:30 -04:00
|
|
|
$ spawn
|
2021-02-04 21:46:04 -05:00
|
|
|
$ "systemctl --user start mbsync.timer"
|
|
|
|
#!&& fmtNotifyCmd defNoteInfo { body = Just $ Text "Isync timer started" }
|
2021-06-20 17:17:30 -04:00
|
|
|
#!|| fmtNotifyCmd defNoteError { body = Just $ Text "Isync timer failed to start" }
|
2021-02-04 21:46:04 -05:00
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runStartISyncService :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runStartISyncService = featureRun "isync" [userUnit "mbsync.service"]
|
2021-06-20 17:17:30 -04:00
|
|
|
$ spawn
|
2021-02-04 21:46:04 -05:00
|
|
|
$ "systemctl --user start mbsync.service"
|
2021-06-20 17:17:30 -04:00
|
|
|
#!&& fmtNotifyCmd defNoteInfo { body = Just $ Text "Isync completed" }
|
|
|
|
#!|| fmtNotifyCmd defNoteError { body = Just $ Text "Isync failed" }
|
2021-02-04 21:46:04 -05:00
|
|
|
|
2020-03-28 18:38:38 -04:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | Configuration commands
|
|
|
|
|
|
|
|
runRestart :: X ()
|
|
|
|
runRestart = restart "xmonad" True
|
|
|
|
|
|
|
|
runRecompile :: X ()
|
|
|
|
runRecompile = do
|
|
|
|
-- assume that the conf directory contains a valid stack project
|
|
|
|
confDir <- getXMonadDir
|
2020-04-06 00:14:56 -04:00
|
|
|
spawnAt confDir $ fmtCmd "stack" ["install"]
|
|
|
|
#!&& fmtNotifyCmd defNoteInfo { body = Just $ Text "compilation succeeded" }
|
|
|
|
#!|| fmtNotifyCmd defNoteError { body = Just $ Text "compilation failed" }
|
|
|
|
|
|
|
|
-- runRecompile :: X ()
|
|
|
|
-- runRecompile = do
|
|
|
|
-- -- assume that the conf directory contains a valid stack project
|
|
|
|
-- -- TODO this is hacky AF
|
|
|
|
-- confDir <- getXMonadDir
|
|
|
|
-- spawnCmdAt confDir "stack" ["install"]
|
2020-04-01 20:17:47 -04:00
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | Screen capture commands
|
|
|
|
|
2020-05-03 00:04:35 -04:00
|
|
|
getCaptureDir :: IO FilePath
|
|
|
|
getCaptureDir = do
|
|
|
|
e <- lookupEnv "XDG_DATA_HOME"
|
|
|
|
parent <- case e of
|
|
|
|
Nothing -> fallback
|
|
|
|
Just path
|
|
|
|
| isRelative path -> fallback
|
|
|
|
| otherwise -> return path
|
|
|
|
let fullpath = parent </> "screenshots"
|
|
|
|
createDirectoryIfMissing True fullpath
|
|
|
|
return fullpath
|
|
|
|
where
|
|
|
|
fallback = (</> ".local/share") <$> getHomeDirectory
|
2020-04-01 20:17:47 -04:00
|
|
|
|
2021-11-20 19:35:24 -05:00
|
|
|
runFlameshot :: String -> String -> FeatureX
|
|
|
|
runFlameshot n mode = featureRun n [Executable myCapture] $ do
|
2020-05-03 00:04:35 -04:00
|
|
|
ssDir <- io getCaptureDir
|
2021-06-19 00:17:47 -04:00
|
|
|
spawnCmd myCapture $ mode : ["-p", ssDir]
|
2020-04-01 20:17:47 -04:00
|
|
|
|
|
|
|
-- TODO this will steal focus from the current window (and puts it
|
|
|
|
-- in the root window?) ...need to fix
|
2021-11-20 01:15:04 -05:00
|
|
|
runAreaCapture :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runAreaCapture = runFlameshot "screen area capture" "gui"
|
2020-04-01 20:17:47 -04:00
|
|
|
|
|
|
|
-- myWindowCap = "screencap -w" --external script
|
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runDesktopCapture :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runDesktopCapture = runFlameshot "fullscreen capture" "full"
|
2020-05-03 00:04:35 -04:00
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runScreenCapture :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runScreenCapture = runFlameshot "screen capture" "screen"
|
2021-06-19 00:54:01 -04:00
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
runCaptureBrowser :: FeatureX
|
2021-11-20 19:35:24 -05:00
|
|
|
runCaptureBrowser =
|
|
|
|
featureRun "screen capture browser" [Executable myImageBrowser] $ do
|
2020-05-03 00:04:35 -04:00
|
|
|
dir <- io getCaptureDir
|
2021-06-19 00:17:47 -04:00
|
|
|
spawnCmd myImageBrowser [dir]
|