Skip to content

Commit a59ffd7

Browse files
committed
Add driver/XMonad.hs
1 parent 8b7a6fd commit a59ffd7

3 files changed

Lines changed: 85 additions & 1 deletion

File tree

driver/XMonad.hs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
{-# LANGUAGE BlockArguments #-}
2+
{-# LANGUAGE NoOverloadedStrings #-}
3+
{-# LANGUAGE LambdaCase #-}
4+
{-# LANGUAGE ViewPatterns #-}
5+
module XMonad where
6+
7+
-- import Control.Exception (IOException, try)
8+
import System.Process
9+
import System.Posix.Process (getProcessID)
10+
-- import Data.Maybe (listToMaybe)
11+
import Data.Functor
12+
import System.Exit
13+
import Data.List
14+
15+
import Imports
16+
17+
newtype PID = PID String
18+
newtype XWindowId = XWindowId String
19+
newtype Tag = Tag String
20+
21+
instance IsString Tag where
22+
fromString = Tag
23+
24+
-- Get the parent PID of a process
25+
getParentPid :: PID -> IO (Maybe PID)
26+
getParentPid (PID pid) = readProcessWithExitCode "ps" ["-o", "ppid=", "-p", pid] "" <&> \ case
27+
(_, result, _) -> case strip result of
28+
"" -> Nothing
29+
ppid -> Just (PID ppid)
30+
31+
getWindowIdForPid :: PID -> IO (Maybe XWindowId)
32+
getWindowIdForPid (PID pid) = do
33+
windowIds <- filter (isPrefixOf "0x") . words <$> readProcess "xprop" ["-root", "_NET_CLIENT_LIST"] ""
34+
findWindow windowIds
35+
where
36+
findWindow :: [String] -> IO (Maybe XWindowId)
37+
findWindow = \ case
38+
[] -> return Nothing
39+
wid : rest -> do
40+
(_, wmPidOutput, _) <- readProcessWithExitCode "xprop" ["-id", wid, "_NET_WM_PID"] ""
41+
case reverse (words wmPidOutput) of
42+
wmPid : _ | wmPid == pid -> return (Just $ XWindowId wid)
43+
_ -> findWindow rest
44+
45+
findAncestorWindowId :: PID -> IO (Maybe XWindowId)
46+
findAncestorWindowId pid = do
47+
windowId <- getWindowIdForPid pid
48+
case windowId of
49+
Just wid -> return (Just wid)
50+
Nothing -> do
51+
parentPid <- getParentPid pid
52+
case parentPid of
53+
Just ppid -> findAncestorWindowId ppid
54+
Nothing -> return Nothing
55+
56+
addTag :: Tag -> XWindowId -> IO ()
57+
addTag (Tag name) (XWindowId wid) = do
58+
result <- readProcess "xprop" ["-id", wid, "_XMONAD_TAGS"] ""
59+
60+
let
61+
tags :: String
62+
tags = if "not found" `elem` words result then "" else extractTags result
63+
64+
newTags :: String
65+
newTags = if null tags then name else tags <> " " <> name
66+
67+
callProcess "xprop" ["-id", wid, "-f", "_XMONAD_TAGS", "8s", "-set", "_XMONAD_TAGS", newTags]
68+
where
69+
extractTags :: String -> String
70+
extractTags = unwords . drop 1 . words . last . lines
71+
72+
tagSelfWith :: Tag -> IO ()
73+
tagSelfWith name = do
74+
pid <- PID . show <$> getProcessID
75+
result <- findAncestorWindowId pid
76+
case result of
77+
Just wid -> addTag name wid
78+
Nothing -> exitFailure

driver/sensei.hs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ module Main (main) where
22

33
import System.Environment
44

5+
import qualified XMonad
56
import Run
67

78
main :: IO ()
8-
main = getArgs >>= run
9+
main = do
10+
XMonad.tagSelfWith "sensei"
11+
getArgs >>= run

sensei.cabal

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)