Skip to content

Instantly share code, notes, and snippets.

@fffe
Created December 31, 2018 13:16
Show Gist options
  • Save fffe/48e2c05c856a3f9c0b70e31e9254a79b to your computer and use it in GitHub Desktop.
Save fffe/48e2c05c856a3f9c0b70e31e9254a79b to your computer and use it in GitHub Desktop.
xmonad.hs for xinerama with per-screen status bars
import XMonad
import qualified XMonad.StackSet as S
import XMonad.Config.Desktop
import XMonad.Layout.WindowNavigation
import XMonad.Layout.Minimize
import XMonad.Layout.Reflect
import XMonad.Actions.GroupNavigation
import XMonad.Actions.CycleWS
import XMonad.Actions.CycleRecentWS
import XMonad.Actions.WindowBringer
import XMonad.Actions.PhysicalScreens
import XMonad.Actions.NoBorders
import XMonad.Layout.IM
import XMonad.Layout.Grid
import XMonad.Layout.NoBorders
import XMonad.Layout.PerWorkspace (onWorkspace)
import XMonad.Layout.ToggleLayouts
import XMonad.Layout.NoFrillsDecoration
import XMonad.Hooks.SetWMName (setWMName)
import XMonad.Hooks.DynamicLog hiding (xmobar)
import XMonad.Hooks.ManageDocks (avoidStruts, manageDocks)
import XMonad.Hooks.UrgencyHook
import XMonad.Hooks.EwmhDesktops (ewmh, fullscreenEventHook)
import XMonad.Hooks.ManageHelpers
import XMonad.Util.Run (spawnPipe, hPutStrLn)
import XMonad.Util.EZConfig
import XMonad.Util.NamedWindows (getName)
import Data.Ord (comparing)
import Data.List (intercalate, sortBy, isInfixOf)
import Data.Maybe (isJust, catMaybes)
import Data.Ratio ((%))
import Data.Monoid (All(All), mappend)
import Codec.Binary.UTF8.String (encodeString)
import Control.Monad (when, zipWithM_, liftM2)
import System.Exit (ExitCode(ExitSuccess), exitWith)
myTerminal = "urxvt"
myActiveColor = "GoldenRod"
myInactiveColor = "DimGrey"
myTextColor = "Black"
myFont = "xft:DejaVu Sans-10:bold"
myScreenShotPath = "~/Screenshots/`date +%s%3N`.png"
myDmenu = "dmenu -i -nf " ++ myActiveColor ++ " -nb " ++ myTextColor ++ " -sf " ++ myTextColor ++ " -sb " ++ myActiveColor ++ " -fn '" ++ myFont ++ "' -p '>'"
main = do
xmobar0 <- xmobar 0 "%StdinReader%}{%date%"
"[Run StdinReader, Run Date \"%a %b %_d, %r\" \"date\" 10]"
xmobar1 <- xmobar 1 "%StdinReader%}{"
"[Run StdinReader]"
xmonad $ withUrgencyHook NoUrgencyHook desktopConfig {
focusFollowsMouse = False
, borderWidth = 1
, focusedBorderColor = myActiveColor
, normalBorderColor = myInactiveColor
, terminal = myTerminal
, modMask = mod1Mask
, logHook = myLogHook [ pp { ppOutput = hPutStrLn xmobar0 }
, pp { ppOutput = hPutStrLn xmobar1 }
]
, workspaces = myWorkspaces
, layoutHook = myLayoutHook
, manageHook = myManageHook
, startupHook = startupHook desktopConfig >> setWMName "LG3D" -- makes (old?) java applets actually work.
, handleEventHook = fullscreenEventHook `mappend` handleEventHook def
}
`additionalKeysP`
[
("M-x c", spawn "google-chrome"),
("M-x x", spawn $ "j4-dmenu-desktop --term=" ++ myTerminal ++ " --dmenu=\"" ++ myDmenu ++ "\""),
("C-M-l", spawn "xscreensaver-command -lock"),
("C-M-k", spawn "keepassx"),
("<Print>", spawn $ "scrot -u " ++ myScreenShotPath),
("<F12>", spawn $ "scrot -u " ++ myScreenShotPath),
("M-<Print>", spawn $ "scrot -s " ++ myScreenShotPath),
("M-<F12>", spawn $ "scrot " ++ myScreenShotPath),
("M-x <Space>", spawn myTerminal),
("C-M-w", gotoMenu),
("C-M-s", bringMenu),
("M-`", nextMatchWithThis Forward className),
("M-S-`", nextMatchWithThis Backward className),
("<XF86AudioMute>", spawn "pactl set-sink-mute 1 toggle"),
("<XF86AudioLowerVolume>", spawn "pactl -- set-sink-volume 1 -5%"),
("<XF86AudioRaiseVolume>", spawn "pactl -- set-sink-volume 1 +5%"),
("C-M-<Right>", sendMessage $ Swap R),
("C-M-<Left>", sendMessage $ Swap L),
("C-M-<Up>", sendMessage $ Swap U),
("C-M-<Down>", sendMessage $ Swap D),
("C-M-<Pause>", io (exitWith ExitSuccess))
]
`additionalKeys`
[
((mod1Mask .|. mask, key), f sc)
| (key, sc) <- zip [xK_w, xK_e] [0..] -- map M-w to screen 1, M-e to screen 2, ...
, (f, mask) <- [(viewScreen, 0), (sendToScreen, shiftMask)] -- M-S-w = move to screen 1, ...
]
`removeKeys`
[
((mod1Mask .|. shiftMask, xK_q))
]
-- if you use 'windowNavigation' instead of 'configurableNavigation noNavigateBorders',
-- you'll get weird coloring/shading of inactive window borders.
myLayoutHook =
configurableNavigation noNavigateBorders
-- No borders around single-window-on-screen, with Xinerama (smartBorders doesn't work in that case)
$ lessBorders (Combine Difference Screen OnlyFloat)
$ defaultLayout
where
defaultLayout
= avoidStruts
$ noFrillsDeco shrinkText myTheme
$ onWorkspace "4:im" chatLayout
$ minimize
$ layoutHook def
chatLayout = reflectHoriz $ noBorders $ withIM (1%6) pidginRoster Grid
pidginRoster = And (ClassName "Pidgin") (Role "buddy_list")
-- Theme for window decorations
myTheme = def {
activeColor = myActiveColor
, activeTextColor = myTextColor
, activeBorderColor = myActiveColor
, inactiveColor = myInactiveColor
, inactiveBorderColor = myInactiveColor
, fontName = myFont
}
-- Set up a mix of 9 named/unnamed workspaces
myWorkspaces = ["1:term", "2:web", "3:local", "4:im", "5:vm", "6:files", "7:gimp"] ++ map show [8..9]
myManageHook = manageDocks <+> manageFloats <+> manageApps
where manageFloats = composeOne [ isFullscreen -?> doFullFloat
, isDialog -?> doFloat
]
manageApps = composeAll [
className =? "URxvt" --> moveTo "1:term",
className =? "Google-chrome" --> moveTo "2:web",
className =? "Psi-plus" --> moveTo "4:im",
className =? "Pidgin" --> moveTo "4:im",
className =? "Virt-manager" --> moveTo "5:vm",
className =? "Remote-viewer" --> moveTo "5:vm",
className =? "Thunar" --> moveTo "6:files",
className =? "Gimp" --> moveTo "7:gimp",
className =? "Keepassx" --> doFloat
]
moveTo = doF . liftM2 (.) S.view S.shift
xmobar screen template commands = spawnPipe . unwords $ options
where options = [ "xmobar"
, "-x"
, show screen
, "-t"
, wrap "'" "'" template
, "-c"
, wrap "'" "'" commands
]
-- Tweak pretty printer for xmobar output
pp = def {
ppHiddenNoWindows = xmobarColor myInactiveColor "" . pad
, ppCurrent = xmobarColor "White" myInactiveColor . pad
, ppVisible = pad
, ppHidden = pad
, ppUrgent = xmobarColor "Black" myActiveColor . xmobarStrip
, ppLayout = xmobarColor "LightSkyBlue" "" . pad . iconify
, ppTitle = xmobarColor "White" "" . pad . xmobarStrip . shorten 200
, ppWsSep = ""
, ppSep = ""
}
where
iconify l | "Mirror" `isInfixOf` l = "[-]" -- text icon for each layout
| "Grid" `isInfixOf` l = "[+]"
| "Tall" `isInfixOf` l = "[|]"
| "Full" `isInfixOf` l = "[ ]"
| otherwise = l
-- A whole lot of hateful magicke for per-screen active window titles in the taskbar.
myLogHook pps = do
screens <- (sortBy (comparing S.screen) . S.screens) `fmap` gets windowset
zipWithM_ dynamicLogWithPP' screens pps
-- Extract the focused window from the stack of windows on the given screen.
-- Return Just that window, or Nothing for an empty stack.
focusedWindow = maybe Nothing (return . S.focus) . S.stack . S.workspace
-- The functions dynamicLogWithPP', dynamicLogString', and pprWindowSet' below
-- are similar to their undashed versions, with the difference being that the
-- latter operate on the current screen, whereas the former take the screen to
-- operate on as the first argument.
dynamicLogWithPP' screen pp = dynamicLogString' screen pp >>= io . ppOutput pp
dynamicLogString' screen pp = do
winset <- gets windowset
urgents <- readUrgents
sort' <- ppSort pp
-- layout description
let ld = description . S.layout . S.workspace $ screen
-- workspace list
let ws = pprWindowSet' screen sort' urgents pp winset
-- window title
wt <- maybe (return "") (fmap show . getName) $ focusedWindow screen
-- run extra loggers, ignoring any that generate errors.
extras <- mapM (`catchX` return Nothing) $ ppExtras pp
return $ encodeString $ sepBy (ppSep pp) . ppOrder pp $
[ ws
, ppLayout pp ld
, ppTitle pp wt
]
++ catMaybes extras
pprWindowSet' screen sort' urgents pp s = sepBy (ppWsSep pp) . map fmt . sort' $ S.workspaces s
where this = S.tag . S.workspace $ screen
visibles = map (S.tag . S.workspace) (S.current s : S.visible s)
fmt w = printer pp (S.tag w)
where printer | S.tag w == this = ppCurrent
| S.tag w `elem` visibles = ppVisible
| any (\x -> maybe False (== S.tag w) (S.findTag x s)) urgents = \ppC -> ppUrgent ppC . ppHidden ppC
| isJust (S.stack w) = ppHidden
| otherwise = ppHiddenNoWindows
sepBy :: String -> [String] -> String
sepBy sep = intercalate sep . filter (not . null)
#!/bin/bash
export SSH_ASKPASS=/usr/bin/ssh-askpass
# fuck. middle. mouse. paste.
xmodmap -e "pointer = 1 25 3 4 5 6 7 8 9 10 11 12 13 14 15 16"
# load prefs
xrdb -merge $HOME/.Xresources
# black background
xsetroot -solid black
# sound
pulseaudio --start
# color calibration
xcalib $HOME/.monitor/monitor.icm
# compositing
compton -bCG
# xscreensaver
/usr/share/xscreensaver/xscreensaver-wrapper.sh -nosplash &
# background
feh --bg-fill --no-fehbg $HOME/Wallpapers/bg.jpg
# systray
stalonetray -i 16 --icon-gravity E --geometry 8x1-1920+1060 --sticky --skip-taskbar --background black &
# sound applet for systray
pasystray &
exec xmonad
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment