diff --git a/dotfiles/config/taffybar/Justfile b/dotfiles/config/taffybar/Justfile index cb34cd6a..134161fc 100644 --- a/dotfiles/config/taffybar/Justfile +++ b/dotfiles/config/taffybar/Justfile @@ -8,6 +8,28 @@ run: restart: @scripts/taffybar-restart +# Restart with one of the bisect widget profiles: +# minimal, workspaces, workspaces-windows, or full. +restart-widget-profile profile: + @TAFFYBAR_WIDGET_PROFILE='{{profile}}' scripts/taffybar-restart + +# Restart a widget profile with draw and workspace update logging enabled. +# Inspect /tmp/taffybar.log after switching workspaces. +restart-redraw-debug profile="full": + @TAFFYBAR_WIDGET_PROFILE='{{profile}}' TAFFYBAR_DRAW_DEBUG=1 TAFFYBAR_WORKSPACE_DEBUG=1 scripts/taffybar-restart + +# Minimal widget profile with all taffybar CSS disabled. +restart-redraw-minimal: + @TAFFYBAR_WIDGET_PROFILE='minimal' TAFFYBAR_DRAW_DEBUG=1 TAFFYBAR_WORKSPACE_DEBUG=1 TAFFYBAR_DISABLE_VENDOR_CSS=1 TAFFYBAR_DISABLE_USER_CSS=1 scripts/taffybar-restart + +# Workspace-only profile with all taffybar CSS disabled. +restart-redraw-workspaces-empty-css: + @TAFFYBAR_WIDGET_PROFILE='workspaces' TAFFYBAR_DRAW_DEBUG=1 TAFFYBAR_WORKSPACE_DEBUG=1 TAFFYBAR_DISABLE_VENDOR_CSS=1 TAFFYBAR_DISABLE_USER_CSS=1 scripts/taffybar-restart + +# Workspace-only profile with the normal configured CSS. +restart-redraw-workspaces-user-css: + @TAFFYBAR_WIDGET_PROFILE='workspaces' TAFFYBAR_DRAW_DEBUG=1 TAFFYBAR_WORKSPACE_DEBUG=1 scripts/taffybar-restart + # Restart with no vendor CSS (taffybar's built-in stylesheet) loaded. restart-no-vendor-css: @TAFFYBAR_DISABLE_VENDOR_CSS=1 scripts/taffybar-restart diff --git a/dotfiles/config/taffybar/imalison-taffybar.cabal b/dotfiles/config/taffybar/imalison-taffybar.cabal index 9dc465e4..7ce2951e 100644 --- a/dotfiles/config/taffybar/imalison-taffybar.cabal +++ b/dotfiles/config/taffybar/imalison-taffybar.cabal @@ -37,6 +37,7 @@ executable taffybar , time , taffybar>=3.2.0 , transformers + , unix , xdg-basedir default-language: Haskell2010 diff --git a/dotfiles/config/taffybar/taffybar b/dotfiles/config/taffybar/taffybar index db93e622..bd89ce30 160000 --- a/dotfiles/config/taffybar/taffybar +++ b/dotfiles/config/taffybar/taffybar @@ -1 +1 @@ -Subproject commit db93e622b07cea1a766d2edfd0c2a0fe364f65eb +Subproject commit bd89ce305958cce1cdc0ac0b1ec386903feefc00 diff --git a/dotfiles/config/taffybar/taffybar.hs b/dotfiles/config/taffybar/taffybar.hs index bf53bccc..bb6395a5 100644 --- a/dotfiles/config/taffybar/taffybar.hs +++ b/dotfiles/config/taffybar/taffybar.hs @@ -11,6 +11,7 @@ import Control.Monad.Trans.Reader (asks) import Data.Char (toLower) import Data.Foldable (for_) import Data.GI.Base (castTo) +import Data.IORef (newIORef, readIORef, writeIORef) import Data.Int (Int32) import Data.List (nub) import qualified Data.Map as M @@ -26,7 +27,9 @@ import Network.HostName (getHostName) import qualified StatusNotifier.Tray as SNITray import System.Environment (lookupEnv) import System.Environment.XDG.BaseDir (getUserConfigFile) +import System.IO (hFlush, stdout) import System.Log.Logger (Priority (WARNING), rootLoggerName, setLevel, updateGlobalLogger) +import System.Posix.Process (getProcessID) import System.Process (spawnCommand) import System.Taffybar (startTaffybar) import System.Taffybar.Context @@ -83,6 +86,40 @@ import System.Taffybar.WindowIcon (pixBufFromColor) import Text.Printf (printf) import Text.Read (readMaybe) +envFlag :: String -> IO Bool +envFlag name = do + value <- lookupEnv name + pure $ + case fmap (map toLower) value of + Just "1" -> True + Just "true" -> True + Just "yes" -> True + Just "on" -> True + _ -> False + +envTextDefault :: String -> Text -> IO Text +envTextDefault name fallback = + maybe fallback T.pack <$> lookupEnv name + +attachDrawProbe :: Text -> Gtk.Widget -> TaffyIO Gtk.Widget +attachDrawProbe name widget = do + enabled <- liftIO $ envFlag "TAFFYBAR_DRAW_DEBUG" + when enabled $ liftIO $ do + counter <- newIORef (0 :: Int) + pid <- getProcessID + _ <- Gtk.onWidgetDraw widget $ \_ -> do + count <- (+ 1) <$> readIORef counter + writeIORef counter count + printf "taffybar-draw pid=%s widget=%s count=%d\n" (show pid) (T.unpack name) count + hFlush stdout + pure False + pure () + pure widget + +withDrawProbe :: Text -> TaffyIO Gtk.Widget -> TaffyIO Gtk.Widget +withDrawProbe name builder = + builder >>= attachDrawProbe name + -- | Wrap the widget in a "TaffyBox" (via 'buildContentsBox') and add a CSS class. decorateWithClassAndBox :: (MonadIO m) => Text -> Gtk.Widget -> m Gtk.Widget decorateWithClassAndBox klass widget = do @@ -320,13 +357,19 @@ windowsWidget = ) workspacesWidget :: TaffyIO Gtk.Widget -workspacesWidget = Workspaces.workspacesNew cfg +workspacesWidget = do + iconProfile <- liftIO $ envTextDefault "TAFFYBAR_WORKSPACE_ICON_PROFILE" "custom" + Workspaces.workspacesNew (cfg iconProfile) where - cfg = + iconGetter "default" = Workspaces.defaultGetWindowIconPixbuf + iconGetter "fallback" = workspaceFallbackIcon + iconGetter "none" = \_ _ -> return Nothing + iconGetter _ = workspaceWindowIconGetter + cfg iconProfile = Workspaces.defaultWorkspacesConfig { Workspaces.widgetGap = 0, Workspaces.minIcons = 1, - Workspaces.getWindowIconPixbuf = workspaceWindowIconGetter, + Workspaces.getWindowIconPixbuf = iconGetter iconProfile, Workspaces.labelSetter = workspaceLabelSetter, Workspaces.showWorkspaceFn = \workspace -> @@ -700,68 +743,101 @@ sniTrayWidget = do -- ** Layout -startWidgetsForBackend :: Backend -> [TaffyIO Gtk.Widget] -startWidgetsForBackend backend = - case backend of - BackendX11 -> [omniMenuWidget, workspacesWidget, layoutWidget, windowsWidget] - -- These Wayland widgets are Hyprland-specific. - BackendWayland -> [omniMenuWidget, workspacesWidget, windowsWidget] +probeWidgets :: [(Text, TaffyIO Gtk.Widget)] -> [TaffyIO Gtk.Widget] +probeWidgets = + map (uncurry withDrawProbe) -endWidgetsForHost :: String -> [TaffyIO Gtk.Widget] -endWidgetsForHost hostName = +startWidgetsForBackend :: Text -> Backend -> [TaffyIO Gtk.Widget] +startWidgetsForBackend "minimal" _ = + [] +startWidgetsForBackend "workspaces" _ = + probeWidgets [("workspaces", workspacesWidget)] +startWidgetsForBackend "workspaces-windows" _ = + probeWidgets [("workspaces", workspacesWidget), ("windows", windowsWidget)] +startWidgetsForBackend _ backend = + case backend of + BackendX11 -> + probeWidgets + [ ("omni-menu", omniMenuWidget), + ("workspaces", workspacesWidget), + ("layout", layoutWidget), + ("windows", windowsWidget) + ] + -- These Wayland widgets are Hyprland-specific. + BackendWayland -> + probeWidgets + [ ("omni-menu", omniMenuWidget), + ("workspaces", workspacesWidget), + ("windows", windowsWidget) + ] + +centerWidgetsForProfile :: Text -> [TaffyIO Gtk.Widget] +centerWidgetsForProfile "workspaces" = [] +centerWidgetsForProfile _ = probeWidgets [("clock", clockWidget)] + +endWidgetsForHost :: Text -> String -> [TaffyIO Gtk.Widget] +endWidgetsForHost "minimal" _ = + [] +endWidgetsForHost "workspaces" _ = + [] +endWidgetsForHost "workspaces-windows" _ = + [] +endWidgetsForHost _ hostName = -- NOTE: end widgets are packed with Gtk.boxPackEnd, so the list order is -- right-to-left on screen. Make the tray appear at the far right by placing -- it first in the list. (On laptops: the battery/wifi stack is far right, -- tray immediately left of it.) let baseEndWidgets = - [ sniTrayWidget, - audioWidget, - anthropicUsageWidget, - openAIUsageWidget, - cpuWidget, - ramSwapWidget, - diskUsageWidget, - networkWidget, - screensaverWidget, - sunLockWidget, - mprisWidget - ] + probeWidgets + [ ("sni-tray", sniTrayWidget), + ("audio", audioWidget), + ("anthropic-usage", anthropicUsageWidget), + ("openai-usage", openAIUsageWidget), + ("cpu", cpuWidget), + ("ram-swap", ramSwapWidget), + ("disk-usage", diskUsageWidget), + ("network", networkWidget), + ("screensaver", screensaverWidget), + ("sun-lock", sunLockWidget), + ("mpris", mprisWidget) + ] laptopEndWidgets = - [ batteryNetworkWidget, - sniTrayWidget, - asusDiskUsageWidget, - audioBacklightWidget, - anthropicUsageWidget, - openAIUsageWidget, - cpuWidget, - ramSwapWidget, - screensaverWidget, - sunLockWidget, - mprisWidget - ] + probeWidgets + [ ("battery-network", batteryNetworkWidget), + ("sni-tray", sniTrayWidget), + ("asus-disk-usage", asusDiskUsageWidget), + ("audio-backlight", audioBacklightWidget), + ("anthropic-usage", anthropicUsageWidget), + ("openai-usage", openAIUsageWidget), + ("cpu", cpuWidget), + ("ram-swap", ramSwapWidget), + ("screensaver", screensaverWidget), + ("sun-lock", sunLockWidget), + ("mpris", mprisWidget) + ] in if hostName `elem` laptopHosts then laptopEndWidgets else baseEndWidgets -mkSimpleTaffyConfig :: String -> Backend -> [FilePath] -> SimpleTaffyConfig -mkSimpleTaffyConfig hostName backend cssFiles = +mkSimpleTaffyConfig :: String -> Text -> Backend -> [FilePath] -> SimpleTaffyConfig +mkSimpleTaffyConfig hostName widgetProfile backend cssFiles = defaultSimpleTaffyConfig - { startWidgets = startWidgetsForBackend backend, - centerWidgets = [clockWidget], - endWidgets = endWidgetsForHost hostName, + { startWidgets = startWidgetsForBackend widgetProfile backend, + centerWidgets = centerWidgetsForProfile widgetProfile, + endWidgets = endWidgetsForHost widgetProfile hostName, barLevels = Nothing, barPosition = Top, widgetSpacing = 0, barPadding = if hostName `elem` smallBarHosts - then 1 + then 0 else if hostName `elem` compactBarHosts then 2 else 4, barHeight = if hostName `elem` smallBarHosts - then ScreenRatio $ 1 / 48 + then ScreenRatio $ 1 / 64 else if hostName `elem` compactBarHosts then ScreenRatio $ 1 / 40 @@ -777,9 +853,10 @@ main = do hostName <- getHostName backend <- detectBackend + widgetProfile <- envTextDefault "TAFFYBAR_WIDGET_PROFILE" "full" cssFiles <- mapM (getUserConfigFile "taffybar") (cssFilesForHost hostName) - let simpleTaffyConfig = mkSimpleTaffyConfig hostName backend cssFiles + let simpleTaffyConfig = mkSimpleTaffyConfig hostName widgetProfile backend cssFiles startTaffybar $ withLogServer $ withLogLevels $ diff --git a/nixos/flake.lock b/nixos/flake.lock index 42fffffe..546adb27 100644 --- a/nixos/flake.lock +++ b/nixos/flake.lock @@ -1934,8 +1934,8 @@ ] }, "locked": { - "lastModified": 1777790216, - "narHash": "sha256-0rnLX5oPIsxzypq6t1dI6uLkkMhFYqO5N0ql9BgmX6c=", + "lastModified": 1777906173, + "narHash": "sha256-g0mvCQ1erIjaNnNerr8AAjdwY9PTcas6c0iOJukilOY=", "path": "/home/imalison/dotfiles/dotfiles/config/taffybar/taffybar", "type": "path" },