Skip to content

Commit 8910bda

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

3 files changed

Lines changed: 87 additions & 1 deletion

File tree

driver/XMonad.hs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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 <- readProcess "xprop" ["-id", wid, "_NET_WM_PID"] ""
41+
42+
case listToMaybe (filter (all (`elem` "0123456789")) (words wmPidOutput)) of
43+
Just wmPid | wmPid == pid -> return (Just $ XWindowId wid)
44+
_ -> findWindow rest
45+
46+
-- Recursively find the first ancestor PID that is an X window
47+
findAncestorWindowId :: PID -> IO (Maybe XWindowId)
48+
findAncestorWindowId pid = do
49+
windowId <- getWindowIdForPid pid
50+
case windowId of
51+
Just wid -> return (Just wid)
52+
Nothing -> do
53+
parentPid <- getParentPid pid
54+
case parentPid of
55+
Just ppid -> findAncestorWindowId ppid
56+
Nothing -> return Nothing
57+
58+
addTag :: Tag -> XWindowId -> IO ()
59+
addTag (Tag name) (XWindowId wid) = do
60+
result <- readProcess "xprop" ["-id", wid, "_XMONAD_TAGS"] ""
61+
62+
let
63+
tags :: String
64+
tags = if "not found" `elem` words result then "" else extractTags result
65+
66+
newTags :: String
67+
newTags = if null tags then name else tags <> " " <> name
68+
69+
callProcess "xprop" ["-id", wid, "-f", "_XMONAD_TAGS", "8s", "-set", "_XMONAD_TAGS", newTags]
70+
where
71+
extractTags :: String -> String
72+
extractTags = unwords . drop 1 . words . last . lines
73+
74+
tagSelfWith :: Tag -> IO ()
75+
tagSelfWith name = do
76+
pid <- PID . show <$> getProcessID
77+
result <- findAncestorWindowId pid
78+
case result of
79+
Just wid -> addTag name wid
80+
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)