import Xmobar import Data.Function ((&)) import Data.List (intercalate) import Data.Map qualified as M import System.Process parseXRDB :: String -> M.Map String String parseXRDB = M.fromList . parseXRDBLines . lines parseXRDBLines :: [String] -> [(String, String)] parseXRDBLines = map parseXRDBLine parseXRDBLine :: String -> (String, String) parseXRDBLine s = case break (== ':') s of (k, ':' : v) -> (k, dropWhile (== '\t') v) _ -> error $ "Failed to parse " <> s -- | Hack to adapt the bar height, fontsize, etc, with the chosen dpi in XRDB withDynamicDPI :: Config -> IO Config withDynamicDPI cfg = do xrdbConfig <- parseXRDB <$> readCreateProcess (shell "xrdb -query") mempty case xrdbConfig M.!? "Xft.dpi" of Nothing -> pure cfg Just dpiStr -> let dpi = read dpiStr -- In case of low DPI: -- * reduce height -- * increase font size isLowDPI = dpi < 120 updatePosition (BottomH x) = BottomH $ if isLowDPI then 15 else x updatePosition x = x updateFontSize x = k <> " " <> v' where (k, ' ' : v) = break (== ' ') x v' = if isLowDPI then "9" else v in pure $ cfg { dpi = dpi , position = updatePosition (position cfg) , font = updateFontSize (font cfg) } config :: Config config = defaultConfig { -- as docked overrideRedirect = False -- For framework 13 , dpi = 150 , font = "Iosevka 8" , fgColor = "#FFFFFF" , bgColor = "#000000" , position = BottomH 24 , textOffset = 2 , commands = [ Run $ DateZone "%a %d %H:%M:%S" "" "" "hereClock" (1 &second) , Run $ DateZone "%H:%M" "" "Europe/Dublin" "dublinClock" (10 &second) , Run $ DateZone "%H:%M" "" "Europe/Paris" "parisClock" (10 &second) , Run $ DateZone "%H:%M" "" "Asia/Taipei" "tstClock" (10 &second) , Run $ Com "tomorrow" [ "--target", "2025-08-14" , "--target", "2025-08-21" , "--target", "2025-08-22" , "--target", "2025-09-16=snip snip" , "--target", "2025-10-13=no teef" , "--target", "2025-10-31=dragon book" , "--target", "2025-11-19=scalpel" , "--target", "2025-11-29=à deux" , "--target", "2025-12-16=dragon book" , "--target", "2025-12-30=seule" ] "" (60 &minute) , Run $ Battery [ "-t", " (" , "-H", "70" , "-L", "20" , "-h", "green" , "-n", "orange" , "-l", "red" , "--" , "-O", "Charging" , "-i", "Idle" , "-o", "Battery" , "-P" , "-A", "10" -- TODO: File a bug upstream about notify-send -- https://codeberg.org/xmobar/xmobar/issues/746 , "-a", "notify-send -u critical \"Battery Low\" \"Please charge your battery\"" ] (6 &second) , Run $ Com "powerprofilesctl" ["get"] "" (6 &second) , Run XMonadLog , Run $ Weather "RCSS" [ "-t", ": °C" , "-L", "10" , "-H", "25" , "--normal", "white" , "--high", "orange" , "--low", "blue" ] (15 &minute) ] , template = let greyFg x = "" <> x <> "" in " %XMonadLog% " <> alignSep config <> intercalate "|" [ (unwords . map greyFg) [ "[DUB: %dublinClock%]" , "[CDG: %parisClock%]" , "[TPE: %tstClock%]" ] <> " " , " %RCSS% " , " %battery%, %powerprofilesctl%) " , " %hereClock% (%tomorrow%) " ] } second :: Int -> Int second = (* 10) minute :: Int -> Int minute = (* 60) . second main :: IO () main = withDynamicDPI config >>= xmobar