aboutsummaryrefslogtreecommitdiff
path: root/src/Rahm/Desktop/Common.hs
blob: e012a8f1af132d98588231fc051f674c8ff10d6b (plain) (blame)
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
module Rahm.Desktop.Common where

import Control.Monad (forM_, void, when)
import Control.Monad.Trans.Maybe
import Data.Char
import Data.List hiding ((!!))
import Data.List.Safe ((!!))
import qualified Data.Map as Map
import Data.Maybe
import Data.Ord (comparing)
import Rahm.Desktop.DMenu
import Rahm.Desktop.PromptConfig
import qualified Rahm.Desktop.StackSet as S
import Text.Printf
import XMonad hiding (Screen, workspaces)
import XMonad.Prompt
import XMonad.Prompt.Input
import XMonad.Prompt.Shell
import XMonad.Util.Run
import XMonad.Util.XUtils
import Prelude hiding ((!!))

-- 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