1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
|
module Rahm.Desktop.Common
( focusLocation,
masterWindow,
windowsInWorkspace,
getString,
askWindowId,
windowJump,
withBorderColor,
withBorderWidth,
gotoWorkspace,
moveLocationToWorkspace,
getCurrentWorkspace,
getCurrentLocation,
runMaybeT_,
Location (..),
)
where
import Control.Monad (forM_, void, when)
import Control.Monad.Trans.Maybe (MaybeT (..))
import Data.Char (toLower)
import Data.List (concatMap, head, isInfixOf, map, (++))
import qualified Data.Map as Map (fromListWith)
import Data.Maybe (Maybe (..))
import Rahm.Desktop.DMenu (runDMenuPromptWithMap)
import qualified Rahm.Desktop.StackSet as S
( Screen (Screen, workspace),
StackSet (StackSet, current),
Workspace (Workspace, stack, tag),
allWindows,
focusWindow,
greedyView,
integrate',
peek,
shiftWin,
workspaces,
)
import Text.Printf (printf)
import XMonad
( Window,
WorkspaceId,
X,
XConf (config, display),
XConfig (focusedBorderColor, normalBorderColor),
appName,
asks,
focus,
io,
refresh,
runQuery,
setWindowBorderWidth,
setWindowBorderWithFallback,
title,
windows,
withFocused,
withWindowSet,
)
import XMonad.Prompt (XPrompt (commandToComplete, showXPrompt))
import XMonad.Util.XUtils (pixelToString, stringToPixel)
-- A location is a workspace and maybe a window with that workspace.
data Location = Location
{ locationWorkspace :: WorkspaceId,
locationWindow :: Maybe Window
}
deriving (Read, Show, Eq, Ord)
focusLocation :: Location -> X ()
focusLocation (Location ws Nothing) = windows $ S.greedyView ws
focusLocation (Location _ (Just win)) = windows $ S.focusWindow win
masterWindow :: MaybeT X Window
masterWindow = MaybeT $
withWindowSet $ \ss ->
let windows = (S.integrate' . S.stack . S.workspace . S.current) ss
in case windows of
(a : _) -> return $ Just a
_ -> return Nothing
windowsInWorkspace :: WorkspaceId -> X [Location]
windowsInWorkspace wid =
withWindowSet $
return
. concatMap
( \ws ->
if S.tag ws == wid
then map (Location wid . Just) $ S.integrate' (S.stack ws)
else []
)
. S.workspaces
data WinPrompt = WinPrompt
instance XPrompt WinPrompt where
showXPrompt _ = "[Window] "
commandToComplete _ = id
getString :: Window -> X String
getString = runQuery $ do
t <- title
a <- appName
return $
if map toLower a `isInfixOf` map toLower t
then t
else printf "%s - %s" t a
askWindowId :: X (Maybe [Window])
askWindowId = do
windowTitlesToWinId <- withWindowSet $ \ss ->
Map.fromListWith (++) <$> mapM (\wid -> (,) <$> getString wid <*> return [wid]) (S.allWindows ss)
runDMenuPromptWithMap "Window" (Just "#f542f5") windowTitlesToWinId
windowJump :: X ()
windowJump = mapM_ (focus . head) =<< askWindowId
-- Temporarily set the border color of the given windows.
withBorderColor :: String -> [Window] -> X a -> X a
withBorderColor color wins fn = do
d <- asks display
px <- stringToPixel d color
oPx <- stringToPixel d =<< asks (normalBorderColor . config)
fPx <- stringToPixel d =<< asks (focusedBorderColor . config)
colorName <- io (pixelToString d px)
oColorName <- io (pixelToString d oPx)
fColorName <- io (pixelToString d fPx)
forM_ wins $ \w ->
setWindowBorderWithFallback d w colorName px
ret <- fn
withFocused $ \fw -> do
forM_ wins $ \w ->
when (w /= fw) $
setWindowBorderWithFallback d w oColorName oPx
setWindowBorderWithFallback d fw fColorName fPx
return ret
withBorderWidth :: Int -> [Window] -> X a -> X a
withBorderWidth width ws fn = do
d <- asks display
forM_ ws $ \window ->
io $ setWindowBorderWidth d window $ fromIntegral width
ret <- fn
forM_ ws $ \window ->
io $ setWindowBorderWidth d window 2
refresh
return ret
gotoWorkspace :: WorkspaceId -> X ()
gotoWorkspace wid = windows $ S.greedyView wid
moveLocationToWorkspace :: Location -> WorkspaceId -> X ()
moveLocationToWorkspace (Location _ (Just win)) wid =
windows $ S.shiftWin wid win
moveLocationToWorkspace _ _ = return ()
getCurrentWorkspace :: X WorkspaceId
getCurrentWorkspace = withWindowSet $
\(S.StackSet (S.Screen (S.Workspace t _ _) _ _) _ _ _) -> do
return t
getCurrentLocation :: X Location
getCurrentLocation = do
ws <- getCurrentWorkspace
win <- withWindowSet (return . S.peek)
return (Location ws win)
runMaybeT_ :: (Monad m) => MaybeT m a -> m ()
runMaybeT_ = void . runMaybeT
|