aboutsummaryrefslogtreecommitdiff
path: root/src/Rahm/Desktop/Common.hs
blob: 3e6d54c8ed959db2e69ee0b91e46d0677313841e (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
module Rahm.Desktop.Common where

import Prelude hiding ((!!))

import Control.Monad (void, when, forM_)
import Control.Monad.Trans.Maybe
import XMonad.Util.Run
import XMonad.Prompt
import XMonad.Prompt.Input
import XMonad.Prompt.Shell
import XMonad.Util.XUtils

import Rahm.Desktop.PromptConfig

import Data.Char
import Data.List hiding ((!!))
import Data.List.Safe ((!!))
import Data.Maybe
import Text.Printf
import XMonad hiding (workspaces, Screen)
import qualified Data.Map as Map
import Rahm.Desktop.DMenu
import Data.Ord (comparing)

import qualified Rahm.Desktop.StackSet as S

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