diff --git a/home.nix b/home.nix index 8583317..e0e9045 100644 --- a/home.nix +++ b/home.nix @@ -269,5 +269,11 @@ in { config = ./xmonad.hs; enableContribAndExtras = true; }; + + programs.xmobar = { + enable = true; + extraConfig = builtins.readFile ./xmobarrc; + }; + programs.rofi.enable = true; } diff --git a/xmobarrc b/xmobarrc new file mode 100644 index 0000000..53555e2 --- /dev/null +++ b/xmobarrc @@ -0,0 +1,63 @@ +Config { overrideRedirect = False + , font = "xft:Victor Mono NerdFont-8" + , bgColor = "#07080d" + , fgColor = "#e0e2ea" + , position = TopW L 100 + , commands = [ Run MultiCoreTemp + [ "-t", "Temp:°C" + , "-L", "50" + , "-H", "80" + , "--low" , "#b6f0ff" + , "--normal", "#b3f6c0" + , "--high" , "#fcbeb7" + ] 50 + , Run Cpu + [ "-L", "3" + , "-H", "50" + , "--ppad", "3" + , "--low" , "#b6f0ff" + , "--normal", "#b3f6c0" + , "--high" , "#fcbeb7" + ] 10 + , Run Battery + [ "-L", "15" + , "-H", "80" + , "--ppad", "3" + , "--low", "#fcbeb7" + , "--normal", "#b6f0ff" + , "--high", "#b3f6c0" + ] 10 + , Run Alsa "default" "Master" + [ "--template", "" + , "--suffix" , "True" + , "--" + , "--on", "" + ] + , Run Memory + [ "--template", "Mem: %" + , "-L", "20" + , "-H", "50" + , "--ppad", "3" + , "--low" , "#b6f0ff" + , "--normal", "#b3f6c0" + , "--high" , "#fcbeb7" + ] 10 + , Run DateZone "%a %d %b %Y-%m-%d %H:%M:%S" + "fr_FR.UTF-8" + "Europe/Paris" + "date" 10 + , Run DiskIO [ ("/", "r: w:") ] + [ "-L", "300" + , "-H", "1000" + , "--ppad", "3" + , "--low" , "#b6f0ff" + , "--normal", "#b3f6c0" + , "--high" , "#fcbeb7" + ] 10 + , Run Mpris2 "cmus" [] 10 + , Run XMonadLog + ] + , sepChar = "%" + , alignSep = "}{" + , template = "%XMonadLog%}%mpris2%{%diskio% • %alsa:default:Master% • %battery% • %cpu% • %memory% • %multicoretemp% • %date%" + } diff --git a/xmonad.hs b/xmonad.hs index 4849a01..3c632ef 100644 --- a/xmonad.hs +++ b/xmonad.hs @@ -1,24 +1,199 @@ import XMonad import XMonad.Util.EZConfig +import XMonad.Layout.ThreeColumns +import XMonad.Layout.WindowNavigation +import XMonad.Layout.MultiToggle.Instances +import XMonad.Layout.MultiToggle +import XMonad.Layout.NoBorders +import XMonad.Layout.IndependentScreens +import XMonad.Actions.CopyWindow +import XMonad.Actions.CycleWS +import XMonad.Actions.EasyMotion (selectWindow) +import XMonad.Hooks.EwmhDesktops +import XMonad.Hooks.DynamicLog +import XMonad.Hooks.StatusBar +import XMonad.Hooks.StatusBar.PP +import qualified XMonad.Layout.Magnifier as Mag +import qualified Data.Map as M +import qualified XMonad.StackSet as W import System.Exit +import XMonad.Util.Loggers -main :: IO () -main = xmonad $ myConfig -myConfig = def - `additionalKeysP` - [ - -- Screen lock & suspend - ("C-M-l" , spawn "swaylock" ) - , ("C-M-L" , spawn "swaylock" *> spawn "systemctl suspend") - -- Terminal - , ("S-", spawn "kitty" ) - -- Frequent programs - , ("S-q", spawn "firefox" ) - , ("S-a", spawn "emacs" ) - , ("S-d", spawn "discord" ) - , ("S-g", spawn "dolphin" ) - -- Program launcher - , ("S-r", spawn "rofi -show drun -theme Paper" ) - -- Exit - , ("S-M-C-q", io (exitWith ExitSuccess) ) - ] +-- TODO: xmobar + +myWorkspaceNames = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] +myScreens = 2 +conf = def { layoutHook = myLayout + , workspaces = withScreens myScreens myWorkspaceNames + , modMask = mod4Mask + } + `additionalKeysP` + myKeys + +-- main :: IO () +main = + xmonad $ ewmh $ withEasySB (statusBarProp "xmobar" (pure myXmobarPP)) defToggleStrutsKey conf + +-- Define the status bars for each screen +-- myStatusBars :: [StatusBarConfig] +-- myStatusBars = [ statusBarProp ("xmobar -x " ++ show sc) (pure myXmobarPP) | sc <- [0..myScreens - 1] ] + +-- main :: IO () +-- main = xmonad . ewmh $ dynamicSBs myStatusBars conf + +myXmobarPP :: PP +myXmobarPP = def + { ppSep = magenta " • " + , ppTitleSanitize = xmobarStrip + , ppCurrent = xmobarBorder "Top" borderColor 2 . xmobarBorder "Bottom" borderColor 2 + , ppUrgent = red . wrap (yellow "!") (yellow "!") + , ppOrder = \[ws, l, _, wins] -> [ws, l, wins] + , ppExtras = [logTitles formatFocused formatUnfocused] + } + where + formatFocused = wrap (white "[") (white "]") . magenta . ppWindow + formatUnfocused = wrap (lowWhite "[") (lowWhite "]") . blue . ppWindow + + -- | Windows should have *some* title, which should not not exceed a + -- sane length. + ppWindow :: String -> String + ppWindow = xmobarRaw . (\w -> if null w then "untitled" else w) . shorten 30 + + blue, lowWhite, magenta, red, white, yellow :: String -> String + magenta = xmobarColor "#ff79c6" "" + blue = xmobarColor "#bd93f9" "" + white = xmobarColor "#f8f8f2" "" + yellow = xmobarColor "#f1fa8c" "" + red = xmobarColor "#ff5555" "" + lowWhite = xmobarColor "#bbbbbb" "" + borderColor = "#8be9fd" + +myKeys :: [(String, X ())] +myKeys = [ + -- Screen lock & suspend + ("C-M1-l" , spawn "i3lock" ) + , ("C-M1-S-l" , spawn "i3lock" *> spawn "systemctl suspend") + -- Terminal + , ("M4-", spawn "kitty -1") + -- Frequent programs + , ("M4-q", spawn "firefox" ) + , ("M4-a", runOrCopy "emacs" (className =? "Emacs")) + , ("M4-d", spawn "discord" ) + , ("M4-g", spawn "dolphin" ) + -- Program launcher + , ("M4-r", spawn "rofi -show drun -theme Paper" ) + -- Exit + , ("M4-M1-C-q", io (exitWith ExitSuccess) ) + -- Manipulate current client + , ("M4-w", kill1 ) + , ("M4-s", toggleFloat ) + -- focus client + , ("M4-h", sendMessage (Go L) ) + , ("M4-j", sendMessage (Go D) ) + , ("M4-k", sendMessage (Go U) ) + , ("M4-l", sendMessage (Go R) ) + -- focus client (easymotion) + , ("M4-;", selectWindow def >>= (`whenJust` windows . W.focusWindow)) + -- Swap client + , ("M4-S-h", sendMessage $ Swap L) + , ("M4-S-j", sendMessage $ Swap D) + , ("M4-S-k", sendMessage $ Swap U) + , ("M4-S-l", sendMessage $ Swap R) + , ("M4-S-", windows $ W.swapMaster) + -- Move client + , ("M4-M1-S-h", sendMessage (Move L) ) + , ("M4-M1-S-j", sendMessage (Move D) ) + , ("M4-M1-S-k", sendMessage (Move U) ) + , ("M4-M1-S-l", sendMessage (Move R) ) + -- Fullscreen + , ("M4-f", sendMessage (Toggle FULL) ) + -- Magnification + , ("M4-m", sendMessage (Mag.Toggle) ) + , ("M4-[", sendMessage (Mag.MagnifyLess) ) + , ("M4-]", sendMessage (Mag.MagnifyMore) ) + -- Modify number of master windows + , ("M4-M1-j", sendMessage (IncMasterN (-1))) + , ("M4-M1-k", sendMessage (IncMasterN 1 )) + -- Resize master area + , ("M4-C-h", sendMessage Shrink) + , ("M4-C-l", sendMessage Expand) + -- Cycle through workspaces + , ("M4-", moveTo Prev spacesOnCurrentScreen ) + , ("M4-", moveTo Next spacesOnCurrentScreen ) + -- Cycle through empty workspaces + , ("M4-M1-", moveTo Prev emptySpacesOnCurrentScreen) + , ("M4-M1-", moveTo Next emptySpacesOnCurrentScreen) + -- Send window through workspaces + , ("M4-S-", shiftTo Prev spacesOnCurrentScreen ) + , ("M4-S-", shiftTo Next spacesOnCurrentScreen ) + -- Music player control (void) + , ("", spawn "playerctl play-pause" ) + , ("", spawn "playerctl previous" ) + , ("", spawn "playerctl next" ) + , ("", spawn "cmus-remote -C player-next-album") + -- Music player control (t470) + , ("", spawn "playerctl play-pause") + , ("", spawn "playerctl previous") + , ("", spawn "playerctl next") -- Potentially broken key + , ("", spawn "cmus-remote -C player-next-album") + -- Audio control + , ("", spawn "wpctl set-mute @DEFAULT_SINK@ toggle") + , ("", spawn "wpctl set-volume @DEFAULT_SINK@ 1%-") + , ("", spawn "wpctl set-volume @DEFAULT_SINK@ 1%+") + -- Mic control + , ("", spawn "wpctl set-mute @DEFAULT_SOURCE@ toggle") + , ("M1-", spawn "wpctl set-volume @DEFAULT_SOURCE@ 1%-") + , ("M1-", spawn "wpctl set-volume @DEFAULT_SOURCE@ 1%+") + -- backlight control (t470) + , ("", spawn "brightnessctl set 1%-") + , ("", spawn "brightnessctl set 1%+") + -- backlight control (void) + , ("M4-", spawn "ddcutil setvcp 10 + 10") + , ("M4-", spawn "ddcutil setvcp 10 - 10") + -- Reload configuration + , ("M4-", spawn "xmonad --recompile; xmonad --restart") + ] ++ concat [ + -- Workspace switching + [ ("M4-" ++ i, windows $ onCurrentScreen W.view $ i) + -- Move window to workspace + , ("M4-S-" ++ i, windows $ onCurrentScreen W.shift $ i) + -- Copy window to workspace + , ("M4-M1-S-" ++ i, windows $ onCurrentScreen copy $ i) ] + | i <- myWorkspaceNames + ] + +-- https://stackoverflow.com/questions/33547168/xmonad-combine-dwm-style-workspaces-per-physical-screen-with-cycling-function +isOnScreen :: ScreenId -> WindowSpace -> Bool +isOnScreen s ws = s == unmarshallS (W.tag ws) + +currentScreen :: X ScreenId +currentScreen = gets (W.screen . W.current . windowset) + +spacesOnCurrentScreen :: WSType +spacesOnCurrentScreen = WSIs (isOnScreen <$> currentScreen) + +emptySpacesOnCurrentScreen :: WSType +emptySpacesOnCurrentScreen = spacesOnCurrentScreen :&: emptyWS + +myLayout = smartBorders + $ windowNavigation + $ mkToggle (single FULL) + $ (Mag.magnifiercz' 1.3 $ ThreeColMid 1 (3/100) (2/3)) + ||| Tall 1 (3/100) (2/3) + +-- https://www.reddit.com/r/xmonad/comments/hm2tg0/how_to_toggle_floating_state_on_a_window/ +-- Centre and float a window (retain size) +centreFloat win = do + (_, W.RationalRect x y w h) <- floatLocation win + windows $ W.float win (W.RationalRect ((1 - w) / 2) ((1 - h) / 2) w h) + return () + +-- If the window is floating then (f), if tiled then (n) +floatOrNot f n = withFocused $ \windowId -> do + floats <- gets (W.floating . windowset) + if windowId `M.member` floats -- if the current window is floating... + then f + else n + +-- Float and centre a tiled window, sink a floating window +toggleFloat = floatOrNot (withFocused $ windows . W.sink) (withFocused float)