about summary refs log blame commit diff
path: root/dotfiles/xmonad.hs
blob: 1a823fb6bed99ea66c74f8f7991dc34a941da5a8 (plain) (tree)
1
2
3
4
5
6
7
8
9


                  
                          
                               
                               

             
 

                                     
                               



                                
                               

                         
                              


                                          
                                   
 
                             
                               
 

                                      





















                                                                        
                          

                         

     









                                                                        




                                                      
 

                                             
 
                          
                   












                                                                                  

                      
 






                                                 
                                      


                                             



                                                                        
                          
                 
 
                             
                               
 




                           
 


                       





                                                                                                                                          



                                                                  
                                                                                                   
                          

                                                                              



                                                                                  
                        







                                                                                                                                                  



                                                                                      
 
                                                                        
                    
 











                                                                                           
                                                                                           
                                                                                           
                                                                                           
                                                                                           







                                                                                           
                                       
                                                                    


                                                                              












                                                                                                    
 


                           
                                                                        





                                                                        
                                              
                          
                                        








                                                                               



                                                  
 



                                                                                  
                              

                                                                                  
                                                      
                                                                                 

                                                                                                                                                                                
                                                                
                                                                  
                                                                
                                                                         
                                                                                                                                                                                            
                                                                                                                                     
                                                                                                                                                               

                                           
                                           
                                                                                                              
                                                                                                                                                                                                                          
 










                                                                        

             




                             
                                                                                                                                                  




                                                         
                                                     



                                                     

                                                           
                
import System.IO
import System.Exit

import Data.Semigroup(All)
import qualified Data.List as L
import qualified Data.Map  as M

import XMonad

import qualified XMonad.StackSet as W

import XMonad.Hooks.ManageDocks
import XMonad.Hooks.ServerMode
import XMonad.Hooks.StatusBar
import XMonad.Hooks.StatusBar.PP
import XMonad.Hooks.EwmhDesktops
import XMonad.Hooks.UrgencyHook

import XMonad.Layout.Gaps
import XMonad.Layout.NoBorders
import XMonad.Layout.Spacing
import XMonad.Layout.MultiToggle
import XMonad.Layout.MultiToggle.Instances
import XMonad.Layout.LayoutModifier

import XMonad.Actions.CycleWS
import XMonad.Actions.NoBorders

import XMonad.Util.ClickableWorkspaces

------------------------------------------------------------------------
-- Workspaces
-- The default number of workspaces (virtual screens) and their names.
--
myWorkspaces :: [String]
myWorkspaces = map show [1..9]


------------------------------------------------------------------------
-- Window rules
-- Execute arbitrary actions and WindowSet manipulations when managing
-- a new window. You can use this to, for example, always float a
-- particular program, or have a client always appear on a particular
-- workspace.
--
-- To find the property name associated with a program, use
-- > xprop | grep WM_CLASS
-- and click on the client you're interested in.
--
-- To match on the WM_NAME, you can use 'title' in the same way that
-- 'className' and 'resource' are used below.
--
myManageHook :: ManageHook
myManageHook = composeAll
    [
    ]

------------------------------------------------------------------------
-- Layouts
-- You can specify and transform your layouts by modifying these values.
-- If you change layout bindings be sure to use 'mod-shift-space' after
-- restarting (with 'mod-q') to reset your layout state to the new
-- defaults, as xmonad preserves your old layout settings by default.
--
-- The available layouts.  Note that each layout is separated by |||,
-- which denotes layout choice.

gap :: Int
gap = 7

myGaps :: l a -> ModifiedLayout Gaps l a
myGaps = gaps [(U, gap), (R, gap), (L, gap), (D, gap)]

addSpace :: l a -> ModifiedLayout Spacing l a
addSpace = spacing gap

tiledLayout :: Tall Window
tiledLayout = tiled
                where
                  -- default tiling algorithm partitions the screen into two panes
                  tiled   = Tall nmaster delta ratio

                  -- The default number of windows in the master pane
                  nmaster = 1

                  -- Default proportion of screen occupied by master pane
                  ratio   = 1/2

                  -- Percent of screen to increment by when resizing panes
                  delta   = 3/100

layouts :: Tall Window
layouts =  tiledLayout

{-
  Set up layouts.

  1. Remove borders on floating windows.
  2. Create NBFULL (No borders fullscreen toggle)
  3. Configure layouts to avoid struts
-}
myLayout = lessBorders OnlyLayoutFloat
            $ mkToggle (NBFULL ?? EOT)
            $ avoidStruts $ myGaps $ addSpace
            $ layouts

------------------------------------------------------------------------
-- Colors and borders

myBorderWidth :: Dimension
myBorderWidth = 2

myNormalBorderColor :: String
myNormalBorderColor = "#444444"

backgroundColor :: String
backgroundColor = "#005577"

foregroundColor :: String
foregroundColor = "#bbbbbb"

urgentColor :: String
urgentColor = "#ff0000"

------------------------------------------------------------------------

{-
  This sets the "_NET_WM_STATE_FULLSCREEN" window property, helping some programs such as firefox to adjust acoordingly to fullscreen mode
  In a perfect world we shouldnt need to do this manually but it seems like ewmhFullscreen/others dont implement this functionality
-}
setFullscreenProp :: Bool -> Window -> X ()
setFullscreenProp b win = withDisplay $ \dpy -> do
                      state  <- getAtom "_NET_WM_STATE"
                      fullsc <- getAtom "_NET_WM_STATE_FULLSCREEN"
                      let replaceWMStateProperty = changeProperty32 dpy win state 4 propModeReplace
                      if b
                        then io $ replaceWMStateProperty [fromIntegral fullsc]
                        else io $ replaceWMStateProperty []
{- 
  Fullscreen: Hide xmobar -> Hide borders -> Set fullscreen -> Set fullscreenprops
  Unfullscreen: ^^ but reverse
-}
toggleFullScreen :: X ()
toggleFullScreen = do
                    mIsFullScreen <- withWindowSet (isToggleActive NBFULL . W.workspace . W.current)
                    case mIsFullScreen of
                      Just isFullScreen -> if isFullScreen
                                            then withFocused (setFullscreenProp False) >> sendMessage (Toggle NBFULL) >> sendMessage ToggleStruts 
                                            else sendMessage ToggleStruts >> sendMessage (Toggle NBFULL)  >> withFocused (setFullscreenProp True)
                      Nothing -> return ()

toggleFloat :: Window -> X ()
toggleFloat w = windows (\s -> if M.member w (W.floating s)
                            then W.sink w s
                            else (W.float w (W.RationalRect 0.125 0.125 0.75 0.75) s))

------------------------------------------------------------------------
-- External commands

myCommands :: [(String, X ())]
myCommands =
        [ ("decrease-master-size"      , sendMessage Shrink                               )
        , ("increase-master-size"      , sendMessage Expand                               )
        , ("decrease-master-count"     , sendMessage $ IncMasterN (-1)                    )
        , ("increase-master-count"     , sendMessage $ IncMasterN ( 1)                    )
        , ("focus-prev"                , windows W.focusUp                                )
        , ("focus-next"                , windows W.focusDown                              )
        , ("focus-master"              , windows W.focusMaster                            )
        , ("swap-with-prev"            , windows W.swapUp                                 )
        , ("swap-with-next"            , windows W.swapDown                               )
        , ("swap-with-master"          , windows W.swapMaster                             )
        , ("togglefullscreen"          , toggleFullScreen                                 )
        , ("togglefloating"            , withFocused toggleFloat                          )
        , ("next-layout"               , sendMessage NextLayout                           )
        , ("cycle-workspace"           , toggleWS                                         )
        , ("kill-window"               , kill                                             )
        , ("quit"                      , io $ exitWith ExitSuccess                        )
        , ("restart"                   , spawn "xmonad --recompile; xmonad --restart"     )
        ]

-----------------------------------------------------------------------
-- Custom server mode

myServerModeEventHook :: Event -> X All
myServerModeEventHook = serverModeEventHookCmd' $ return myCommands'

myCommands' :: [(String, X ())]
myCommands' = ("list-commands", listMyServerCmds) : myCommands ++ wscs ++ sccs
    where
        wscs = [((m ++ s), windows $f s) | s <- myWorkspaces
               , (f, m) <- [(W.view, "focus-workspace-"), (W.shift, "send-to-workspace-")] ]

        sccs = [((m ++ show sc), screenWorkspace (fromIntegral sc) >>= flip whenJust (windows . f))
               | sc <- [0..10], (f, m) <- [(W.view, "focus-screen-"), (W.shift, "send-to-screen-")]]

listMyServerCmds :: X ()
listMyServerCmds = spawn ("echo '" ++ asmc ++ "' | xmessage -file -")
    where asmc = concat $ "Available commands:" : map (\(x, _)-> "    " ++ x) myCommands'

------------------------------------------------------------------------
-- Mouse bindings

myFocusFollowsMouse :: Bool
myFocusFollowsMouse = False

myMouseBindings :: XConfig l -> M.Map (KeyMask, Button) (Window -> X ())
myMouseBindings (XConfig {XMonad.modMask = modMask}) = M.fromList $
  [
    -- mod-button1, Set the window to floating mode and move by dragging
    ((modMask, button1),
     (\w -> focus w >> mouseMoveWindow w))

    -- mod-button2, Toggle float on the window
    , ((modMask, button2),
       (\w -> focus w >> toggleFloat w))

    -- mod-button3, Set the window to floating mode and resize by dragging
    , ((modMask, button3),
       (\w -> focus w >> mouseResizeWindow w))

    -- you may also bind events to the mouse scroll wheel (button4 and button5)
  ]

------------------------------------------------------------------------
-- Status bar

{-
  Configure xmobar in a dwm style with statusBarPP

  1. Get the active, inactive, urgent and full rectangles above workspace numbers.
  2. Make workspaces clickable.
  3. Set a 2 space separation between workspaces.
-}
myStatusBar :: StatusBarConfig
myStatusBar = statusBarProp "xmobar" (do 
                                        numWindows <- getNumberOfWindowsInWorkpace
                                        return $ def {
                                                    ppCurrent = if numWindows > 0
                                                                        then xmobarBorder "Top" foregroundColor 4 . xmobarColor foregroundColor backgroundColor . wrap "  " "  "
                                                                        else xmobarColor foregroundColor backgroundColor . wrap "  " "  "
                                                  , ppTitle = id
                                                  , ppSep = " |  "
                                                  , ppWsSep = ""
                                                  , ppLayout = (\_ -> "")
                                                  , ppHidden = (\s -> clickableWrap ((read s::Int) - 1) (createDwmBox foregroundColor ("  " ++ s ++ "  "))) --better way to clickablewrap . 
                                                  , ppHiddenNoWindows = (\s -> clickableWrap ((read s::Int) - 1) ("  " ++ s ++ "  "))
                                                  , ppUrgent = (\s -> clickableWrap ((read s::Int) - 1) (xmobarBorder "Top" urgentColor 4 ("  " ++ s ++ "  ")))
                                          }
                                      )
                                      where
                                        getNumberOfWindowsInWorkpace = withWindowSet (pure . length . W.index)
                                        createDwmBox color prefix = "<box type=HBoth offset=L20 color="++color++"><box type=Top mt=3 color="++color++"><box type=Top color="++color++">" ++ prefix ++ "</box></box></box>"

------------------------------------------------------------------------
-- Launch xmonad with the aforementioned settings

{-
  Main function (Launch xmonad)

  1. Setup statusbar (with docks).
  2. Enable fullscreen hook.
  3. Enable urgency hook.
  4. Setup xmonad defaults.
-}
main :: IO ()
main = do
         xmonad
         . withSB myStatusBar
         . docks
         . ewmhFullscreen
         . ewmh
         $ withUrgencyHookC BorderUrgencyHook { urgencyBorderColor = urgentColor } urgencyConfig { suppressWhen = XMonad.Hooks.UrgencyHook.Never }
         $ def {
                focusFollowsMouse  = myFocusFollowsMouse,
                borderWidth        = myBorderWidth,
                workspaces         = myWorkspaces,
                normalBorderColor  = myNormalBorderColor,
                focusedBorderColor = backgroundColor,

                mouseBindings      = myMouseBindings,

                layoutHook         = myLayout,
                handleEventHook    = myServerModeEventHook,
                manageHook         = myManageHook
                }