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
|
{-# LANGUAGE DeriveDataTypeable, TypeSynonymInstances, MultiParamTypeClasses, PatternGuards #-}
module ProcessWorkspaces ( setProcessWorkspace
, getProcessWorkspace
, doAutoShift
, doIgnoreProcessWorkspace
, ignoreProcessWorkspace
, ignoreWinProcessWorkspace
, regroupProcess
, regroupWinProcess
, shiftIgnoreGroup
, shiftWinIgnoreGroup
, shiftGroup
, shiftWinGroup
, handleForgetEmptyWindowGroups
, processWorkspaceManager
, spawnOn
, spawnOnCurrent
) where
import XMonad hiding (moveWindow)
import qualified XMonad.StackSet as W
import XMonad.Layout.LayoutModifier (LayoutModifier(..), ModifiedLayout(..))
import XMonad.Hooks.ManageHelpers (pid)
import Graphics.X11.Types (Window)
import Graphics.X11.Xlib.Extras (Event)
import System.Posix.Process (getProcessPriority)
import System.Posix.Types (ProcessID)
import Control.Monad
import Data.Maybe
import Data.Monoid
import qualified Data.Map as M
import Storage
doAutoShift :: ManageHook
doAutoShift = do
mp <- pid
case mp of
Just p -> do
mws <- liftX $ getProcessWorkspace p
case mws of
Just ws ->
doShift ws
_ -> do
idHook
_ ->
idHook
doIgnoreProcessWorkspace :: ManageHook
doIgnoreProcessWorkspace = do
mp <- pid
when (isJust mp) $
liftX $ setProcessWorkspace (fromJust mp) Nothing
idHook
ignoreProcessWorkspace :: X ()
ignoreProcessWorkspace = withFocused ignoreWinProcessWorkspace
ignoreWinProcessWorkspace :: Window -> X ()
ignoreWinProcessWorkspace w = runQuery doIgnoreProcessWorkspace w >> return ()
regroupProcess :: WorkspaceId -> X ()
regroupProcess ws = withFocused $ regroupWinProcess ws
regroupWinProcess :: WorkspaceId -> Window -> X ()
regroupWinProcess ws w = do
mp <- runQuery pid w
when (isJust mp) $ setProcessWorkspace (fromJust mp) (Just ws)
shiftWinGroup ws w
shiftIgnoreGroup :: WorkspaceId -> X ()
shiftIgnoreGroup ws = withFocused $ shiftWinIgnoreGroup ws
shiftWinIgnoreGroup :: WorkspaceId -> Window -> X ()
shiftWinIgnoreGroup ws w = do
ignoreWinProcessWorkspace w
windows $ W.shiftWin ws w
shiftGroup :: WorkspaceId -> X ()
shiftGroup ws = withFocused $ shiftWinGroup ws
shiftWinGroup :: WorkspaceId -> Window -> X ()
shiftWinGroup ws w = do
mp <- runQuery pid w
case mp of
Just p -> do
mws <- getProcessWorkspace p
case mws of
Just pws -> do
setProcessWorkspace p (Just ws)
wins <- withWindowSet $ return . W.allWindows
windows =<< foldM (\f w' -> runQuery pid w' >>= \mp' -> return $ if (mp' == Just p) then W.shiftWin ws w' . f else f) id wins
_ ->
windows $ W.shiftWin ws w
_ ->
windows $ W.shiftWin ws w
handleForgetEmptyWindowGroups :: Event -> X All
handleForgetEmptyWindowGroups (UnmapEvent {ev_window = w}) = do
mp <- runQuery pid w
when (isJust mp) $ do
wins <- withWindowSet $ return . W.allWindows
hasWindows <- foldM (\b w' -> liftM ((|| b) . (&& (w /= w')) . (== mp)) . runQuery pid $ w') False wins
unless hasWindows $ updateStoreData ((\(ProcessWorkspaceStoreData map) -> ProcessWorkspaceStoreData $ M.delete (fromJust mp) map))
return $ All True
handleForgetEmptyWindowGroups _ = return $ All True
data ProcessWorkspaceStoreData = ProcessWorkspaceStoreData (M.Map ProcessID (Maybe WorkspaceId))
deriving (Typeable, Show, Read)
instance StoreData ProcessWorkspaceStoreData
processWorkspaceManager :: (LayoutClass l a) => l a -> ModifiedLayout (Storage ProcessWorkspaceStoreData) l a
processWorkspaceManager = storage (ProcessWorkspaceStoreData M.empty)
setProcessWorkspace :: ProcessID -> Maybe WorkspaceId -> X ()
setProcessWorkspace pid ws = do
ProcessWorkspaceStoreData map <- liftM (fromMaybe $ ProcessWorkspaceStoreData M.empty) $ getStoreData
map' <- filterPIDMap $ M.insert pid ws map
setStoreData $ ProcessWorkspaceStoreData map'
getProcessWorkspace :: ProcessID -> X (Maybe WorkspaceId)
getProcessWorkspace pid = do
ws <- getStoreData >>= return . join . fmap (\(ProcessWorkspaceStoreData map) -> M.lookup pid $ map)
case ws of
Nothing -> do
wsc <- gets (W.currentTag . windowset)
setProcessWorkspace pid (Just wsc)
return $ Just wsc
Just Nothing ->
return Nothing
Just (Just ws') ->
return $ Just ws'
spawnOn :: Maybe WorkspaceId -> String -> X ()
spawnOn ws x = do
pid <- spawnPID x
setProcessWorkspace pid ws
spawnOnCurrent :: String -> X ()
spawnOnCurrent x = gets (W.currentTag . windowset) >>= \ws -> spawnOn (Just ws) x
filterPIDMap :: M.Map ProcessID a -> X (M.Map ProcessID a)
filterPIDMap = liftM M.fromAscList . filterM (pidExists . fst) . M.toAscList
where
pidExists :: ProcessID -> X Bool
pidExists pid = io $ ((getProcessPriority pid) >> return True) `catch` (\_ -> return False)
|