Propagate taffybar redraw fix

This commit is contained in:
2026-05-04 08:13:17 -07:00
parent 07fb87ddbb
commit df36fe2d12
5 changed files with 146 additions and 46 deletions

View File

@@ -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

View File

@@ -37,6 +37,7 @@ executable taffybar
, time
, taffybar>=3.2.0
, transformers
, unix
, xdg-basedir
default-language: Haskell2010

View File

@@ -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 $

4
nixos/flake.lock generated
View File

@@ -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"
},