{-# OPTIONS_GHC -W -fwarn-unused-imports -fno-warn-missing-signatures -O2 #-} import Control.Monad (liftM2) import Data.Map (fromList, toList, union) import System.Environment (getEnv, setEnv) import System.IO (hPutStrLn) import XMonad import XMonad.Actions.CopyWindow (copy, kill1, killAllOtherCopies) import XMonad.Actions.CycleWS (moveTo, nextWS, emptyWS, WSType(Not) , prevWS, shiftToNext, shiftToPrev, toggleWS) import XMonad.Actions.DynamicWorkspaces (addWorkspacePrompt, removeWorkspace , renameWorkspace, selectWorkspace , withWorkspace) import XMonad.Actions.GridSelect (HasColorizer, GSConfig, buildDefaultGSConfig , defaultColorizer, goToSelected , gridselectWorkspace, gs_navigate, navNSearch) import XMonad.Actions.Submap (submap) import XMonad.Hooks.DynamicLog (dzenColor, dynamicLogWithPP , ppCurrent, ppVisible, ppSep, ppHidden , ppUrgent, ppTitle, ppExtras , ppOrder, ppOutput, trim, wrap) import XMonad.Hooks.ManageDocks (avoidStruts, docks, docksEventHook , ToggleStruts(ToggleStruts)) import XMonad.Hooks.ManageHelpers (isFullscreen, doFullFloat) import XMonad.Hooks.Place (placeHook, fixed) import XMonad.Hooks.UrgencyHook (focusUrgent) import XMonad.Layout.Accordion (Accordion(Accordion)) import XMonad.Layout.Dishes (Dishes(Dishes)) import XMonad.Layout.FixedColumn (FixedColumn(FixedColumn)) import XMonad.Layout.Grid (Grid(Grid)) import XMonad.Layout.LimitWindows (limitWindows) import XMonad.Layout.Magnifier (magnifiercz') import XMonad.Layout.MultiToggle (mkToggle, single, Toggle(Toggle)) import XMonad.Layout.MultiToggle.Instances (StdTransformers(MIRROR)) import XMonad.Layout.NoBorders (smartBorders) import XMonad.Layout.NoFrillsDecoration (activeBorderColor, activeColor , activeTextColor, decoHeight, fontName , inactiveBorderColor, inactiveColor , inactiveTextColor, urgentColor , urgentTextColor) import XMonad.Layout.PerWorkspace (onWorkspace) import XMonad.Layout.ResizableTile (ResizableTall(ResizableTall)) import XMonad.Layout.Tabbed (shrinkText, tabbed) import XMonad.Layout.ThreeColumns (ThreeCol(ThreeColMid)) import XMonad.Layout.ToggleLayouts (toggleLayouts, ToggleLayout(ToggleLayout)) import XMonad.Layout.WindowNavigation (Navigate(Move)) import XMonad.Prompt (fgColor, bgColor, XPPosition(Bottom), height, font , position, promptBorderWidth) import XMonad.Prompt.Shell (shellPrompt) import XMonad.Util.Loggers (date, logCmd) import XMonad.Util.Run (spawnPipe) import XMonad.Util.Themes (theme, themeAuthor, themeDescription, ThemeInfo(TI) , themeName) import XMonad.Util.Types (Direction1D(Next, Prev), Direction2D(L, R, U, D)) import XMonad.StackSet (shiftMaster, greedyView, shift) --------------- -- BINDINGS --------------- myMod = mod4Mask -- windows key myCtrl = controlMask myTerminal = {{ if (eq .chezmoi.os "linux") }}"urxvtc"{{ else }}"xterm"{{ end }} -- Mouse bindings: default actions bound to mouse events myMouseBindings (XConfig {XMonad.modMask = modMask}) = fromList $ -- mod-button1 %! Set the window to floating mode and move by dragging [ ((modMask, button1), (\w -> focus w >> mouseMoveWindow w >> windows shiftMaster)) -- mod-button2 %! Raise the window to the top of the stack , ((modMask, button2), (\w -> focus w >> windows shiftMaster)) -- mod-button3 %! Set the window to floating mode and resize by dragging , ((modMask, button3), (\w -> focus w >> mouseResizeWindow w >> windows shiftMaster)) -- you may also bind events to the mouse scroll wheel (button4 and button5) , ((modMask, button5), (\_ -> moveTo Next (Not emptyWS))) , ((modMask, button4), (\_ -> moveTo Prev (Not emptyWS))) -- scroll wheel click, bottom right corner on trackball , ((modMask, 6), (\w -> focus w >> kill)) , ((modMask, 8), (\w -> focus w >> kill)) ] mykeys _ = [ ((myMod, xK_Left), prevWS) , ((myMod, xK_Right), nextWS) , ((myMod .|. shiftMask, xK_Left), shiftToPrev >> prevWS) , ((myMod .|. shiftMask, xK_Right), shiftToNext >> nextWS) , ((myMod, xK_a), toggleWS) , ((myMod, xK_z), shellPrompt myXPConfig) , ((myMod, xK_g), goToSelected myGSConfig) , ((myMod .|. shiftMask, xK_m), sendMessage $ Toggle MIRROR) , ((myMod .|. shiftMask, xK_g), gridselectWorkspace myGSConfig greedyView) , ((myMod, xK_x), sendMessage ToggleStruts) , ((myMod, xK_F1), spawn "${HOME}/.screenlayout/`hostname`-work.sh") , ((myMod, xK_F2), spawn "${HOME}/.screenlayout/`hostname`-home.sh") , ((myMod, xK_F3), spawn "${HOME}/.screenlayout/`hostname`-solo.sh") , ((myMod, xK_F4), spawn "sleep 0.5 && xset dpms force suspend") , ((myMod, xK_F5), spawn "sleep 0.5 && xset dpms force off") , ((myMod, xK_F6), spawn "sleep 0.5 && ${HOME}/bin/icd && ${HOME}/bin/mice.sh") , ((myMod, xK_Up), spawn "sleep 0.5 && b u") , ((myMod, xK_Down), spawn "sleep 0.5 && b d") , ((myMod, xK_l), spawn {{ if (eq .chezmoi.os "linux") }}"slock xset dpms force off"{{ else }}"xlock -lockdelay 0"{{ end }}) , ((myMod .|. myCtrl .|. shiftMask, xK_Right), sendMessage $ Move R) , ((myMod .|. myCtrl .|. shiftMask, xK_Left), sendMessage $ Move L) , ((myMod .|. myCtrl .|. shiftMask, xK_Up), sendMessage $ Move U) , ((myMod .|. myCtrl .|. shiftMask, xK_Down), sendMessage $ Move D) , ((myMod, xK_BackSpace), focusUrgent) , ((myMod, xK_s), sendMessage $ ToggleLayout) , ((myMod, xK_b), submap . fromList $ [ ((m, k), f) | m <- [0, myMod] , (k, f) <- [ (xK_a, addWorkspacePrompt myXPConfig) , (xK_c, withWorkspace myXPConfig (windows . copy)) , (xK_d, kill1) , (xK_k, removeWorkspace) , (xK_m, withWorkspace myXPConfig (windows . shift)) , (xK_o, killAllOtherCopies) , (xK_r, renameWorkspace myXPConfig) , (xK_s, selectWorkspace myXPConfig) ] ] )] dvorakify kl = fromList $ map (\((m, k), d) -> ((m, dk k), d)) $ toList kl where dk :: KeySym -> KeySym dk k | k == xK_grave = xK_dollar | k == xK_asciitilde = xK_asciitilde | k == xK_1 = xK_ampersand | k == xK_exclam = xK_percent | k == xK_2 = xK_bracketleft | k == xK_at = xK_7 | k == xK_3 = xK_braceleft | k == xK_numbersign = xK_5 | k == xK_4 = xK_braceright | k == xK_dollar = xK_3 | k == xK_5 = xK_parenleft | k == xK_percent = xK_1 | k == xK_6 = xK_equal | k == xK_asciicircum = xK_9 | k == xK_7 = xK_asterisk | k == xK_ampersand = xK_0 | k == xK_8 = xK_parenright | k == xK_asterisk = xK_2 | k == xK_9 = xK_plus | k == xK_parenleft = xK_4 | k == xK_0 = xK_bracketright | k == xK_parenright = xK_6 | k == xK_minus = xK_exclam | k == xK_underscore = xK_8 | k == xK_equal = xK_numbersign | k == xK_plus = xK_grave | k == xK_q = xK_semicolon -- upper row, left side | k == xK_Q = xK_colon | k == xK_w = xK_comma | k == xK_W = xK_less | k == xK_e = xK_period | k == xK_E = xK_greater | k == xK_bracketleft = xK_slash -- upper row, top right | k == xK_braceleft = xK_question | k == xK_bracketright = xK_at | k == xK_braceright = xK_asciicircum | k == xK_R = xK_P | k == xK_T = xK_Y | k == xK_Y = xK_F | k == xK_U = xK_G | k == xK_I = xK_C | k == xK_O = xK_R | k == xK_P = xK_L | k == xK_A = xK_A | k == xK_S = xK_O | k == xK_D = xK_E | k == xK_F = xK_U | k == xK_G = xK_I | k == xK_H = xK_D | k == xK_J = xK_H | k == xK_K = xK_T | k == xK_L = xK_N | k == xK_Z = xK_quotedbl | k == xK_X = xK_Q | k == xK_C = xK_J | k == xK_V = xK_K | k == xK_B = xK_X | k == xK_N = xK_B | k == xK_M = xK_M | k == xK_r = xK_p | k == xK_t = xK_y | k == xK_y = xK_f | k == xK_u = xK_g | k == xK_i = xK_c | k == xK_o = xK_r | k == xK_p = xK_l | k == xK_a = xK_a | k == xK_s = xK_o | k == xK_d = xK_e | k == xK_f = xK_u | k == xK_g = xK_i | k == xK_h = xK_d | k == xK_j = xK_h | k == xK_k = xK_t | k == xK_l = xK_n | k == xK_z = xK_apostrophe | k == xK_x = xK_q | k == xK_c = xK_j | k == xK_v = xK_k | k == xK_b = xK_x | k == xK_n = xK_b | k == xK_m = xK_m | k == xK_comma = xK_w -- bottom right | k == xK_less = xK_W | k == xK_period = xK_v | k == xK_greater = xK_V | k == xK_slash = xK_z | k == xK_question = xK_Z | otherwise = k ------------- -- THEMES ------------- -- Color names are easier to remember: colorBlack = "#000000" colorOrange = "#ff7701" -- colorDarkGray = "#171717" -- colorPink = "#e3008d" colorGreen = "#00aa4a" colorBlue = "#008dd5" colorYellow = "#fee100" colorWhite = "#cfbfad" -- colorBrightGreen = "#00FF00" colorRed = "#FF0000" xftFont = "Inconsolata:size=8" newTheme :: ThemeInfo newTheme = TI "" "" "" def rakTheme :: ThemeInfo rakTheme = newTheme { themeName = "rakTheme" , themeAuthor = "Ryan Kavanagh" , themeDescription = "Small decorations: orange and blue theme" , theme = def { activeColor = colorBlack , inactiveColor = colorBlack , activeBorderColor = colorOrange , inactiveBorderColor = colorBlack , activeTextColor = colorOrange , inactiveTextColor = colorBlue , urgentColor = colorRed , urgentTextColor = colorYellow , decoHeight = 13 , fontName = "Inconsolata" } } myTheme = theme rakTheme myXPConfig = def { fgColor = "white" , bgColor = "black" , promptBorderWidth = 0 , position = Bottom , height = 15 , font = "xft:" ++ xftFont } ----------------- -- LAYOUTS ----------------- -- My workspaces myWorkspaces = ["term", "web", "chatter", "reading", "gnus", "music", "LaTeX", "work", "radio"] ++ (map show [9..20]) ++ ["console"] -- smartBorders removes borders when there's no ambiguity myLayout = mkToggle (single MIRROR) (smartBorders $ toggleLayouts Full $ avoidStruts perWS) where -- Per workspace layout selection. perWS = onWorkspace "term" (myTall ||| customRyan) $ onWorkspace "web" (tabbed shrinkText myTheme ||| mySplit ||| myTCM) $ onWorkspace "LaTeX" latexFirst $ customRyan -- Each of these allows toggling through a set of layouts -- in the same logical order, but from a different starting point. customRyan = myGrid ||| myDish ||| Accordion ||| myCode ||| myFixed ||| myTall latexFirst = myFixed ||| customRyan -- This is a three column mode, with the master in the middle. myTCM = ThreeColMid 1 (3/100) (1/2) -- This is a tall-like layout with magnification. -- The master window is fixed at 80 columns wide, making this good -- for coding. Limited to 3 visible windows at a time to ensure all -- are a good size. myCode = limitWindows 3 $ magnifiercz' 1.4 $ FixedColumn 1 20 80 10 -- Stack with one large master window. -- It's easy to overflow a stack to the point that windows are too -- small, so only show first 5. myDish = limitWindows 5 $ Dishes nmaster ratio where -- The default number of windows in the master pane nmaster = 1 -- Default proportion of screen occupied by other panes ratio = 1/5 -- Split screen, optimized for web browsing. mySplit = magnifiercz' 1.4 $ Tall nmaster delta ratio where -- The default number of windows in the master pane nmaster = 1 -- Percent of screen to increment by when resizing panes delta = 3/100 -- Default proportion of screen occupied by master pane ratio = 60/100 -- Standard grid. myGrid = Grid myFixed = FixedColumn 1 20 80 10 myTall = ResizableTall nmaster delta ratio [50/100] where nmaster = 1 delta = 3/100 ratio = 1/2 ------------------- -- STATUS BAR ------------------- statusBarCmd = "dzen2" ++ " -dock" ++ " -bg '" ++ colorBlack ++ "'" ++ " -fg '" ++ colorBlue ++ "'" ++ " -sa c" ++ " -fn '" ++ xftFont ++ "'" ++ " -w 925 -x 0 -y 0 -ta l -e ''" -- dynamiclog pretty printer for dzen mPP h = def { ppCurrent = dzenColor colorOrange colorBlack , ppVisible = dzenColor colorGreen colorBlack , ppHidden = dzenColor colorBlue colorBlack , ppUrgent = dzenColor colorRed colorBlack . wrap "[" "]" , ppSep = dzenColor "grey60" colorBlack " ^r(1x8) " , ppTitle = dzenColor colorWhite colorBlack . trim , ppOrder = \(ws:l:t:d:b:o) -> [b,d,ws,l,t] ++ o , ppExtras = [date "%H:%M:%S", batteryCheck] , ppOutput = hPutStrLn h } where batteryCheck = logCmd ("${HOME}/.dzen/battery.sh") --------------------- -- GENERAL CONFIG -------------------- myGSConfig :: HasColorizer a => GSConfig a myGSConfig = (buildDefaultGSConfig defaultColorizer) { gs_navigate = navNSearch } myManageHook = composeAll . concat $ [ [ className =? c --> doFloat | c <- floats] , [ className =? c --> viewShift "web" | c <- web] , [ className =? c --> viewShift "chatter" | c <- chatter] , [ className =? c --> viewShift "music" | c <- music] , [ className =? c --> doShift "console" | c <- xconsole] , [ isFullscreen --> doFullFloat ] ] where viewShift = doF . liftM2 (.) greedyView shift doShift = doF . shift floats = ["MPlayer"] web = ["Firefox", "Firefox-esr", "Navigator", "google-chrome", "Google-chrome"] chatter = ["slack", "Slack"] music = ["pavucontrol", "Pavucontrol"] xconsole = ["xconsole", "XConsole"] myConfig dzenPipe = docks $ def { workspaces = myWorkspaces , modMask = myMod , terminal = myTerminal , normalBorderColor = inactiveBorderColor myTheme , focusedBorderColor = activeBorderColor myTheme , borderWidth = 1 , layoutHook = myLayout , manageHook = manageHook def <+> myManageHook , mouseBindings = myMouseBindings , keys = \x -> (fromList $ mykeys x) `union` dvorakify (keys def x) , logHook = dynamicLogWithPP $ mPP dzenPipe } main = do dzenPipe <- spawnPipe statusBarCmd path <- getEnv "PATH" home <- getEnv "HOME" setEnv "PATH" (home ++ "/bin:" ++ path) xmonad $ myConfig dzenPipe