taffybar: use submodule and improve hyprland config

This commit is contained in:
2026-02-05 00:12:51 -08:00
committed by Kat Huang
parent 7005b042f0
commit 9c40ba1013
5 changed files with 224 additions and 65 deletions

View File

@@ -115,11 +115,11 @@
"gtk-sni-tray": { "gtk-sni-tray": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1760550917, "lastModified": 1770069502,
"narHash": "sha256-oELopLiVb7D1fzYHAiw/cbfNPHLQcOJ3Rz/I1gbk8IY=", "narHash": "sha256-jreuryLGfbyNwx5yEtOYGt2PX+uyGRsgmakYfCQ+OdM=",
"owner": "taffybar", "owner": "taffybar",
"repo": "gtk-sni-tray", "repo": "gtk-sni-tray",
"rev": "f6d1bf5dd64ac0f532b03ae01f5e1cc051116f09", "rev": "733a43f187b35bf65b443a7ede70d62f684932ef",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -148,16 +148,16 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1764252443, "lastModified": 1770181073,
"narHash": "sha256-U4G4dUSYWZYKtrF7/ozebD1B96at08SIhY4R9OaK1nw=", "narHash": "sha256-ksTL7P9QC1WfZasNlaAdLOzqD8x5EPyods69YBqxSfk=",
"owner": "colonelpanic8", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "e1fc6c25b91d3d49dd02a156237721f12dbd86b2", "rev": "bf922a59c5c9998a6584645f7d0de689512e444c",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "colonelpanic8", "owner": "NixOS",
"ref": "remove-gi-gtk-hs-patch", "ref": "nixos-unstable",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
@@ -310,18 +310,14 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1760591109, "lastModified": 1770273353,
"narHash": "sha256-O21ayp5v2eccXdcwNjTK5ZB99ruK0Zt9CUaw5Rye42g=", "narHash": "sha256-0VQfT0bxyU+xmEMLDRQq+hbJX35+PWPjSXiAVFGOlzQ=",
"owner": "taffybar", "path": "/home/imalison/dotfiles/dotfiles/config/taffybar/taffybar",
"repo": "taffybar", "type": "path"
"rev": "b256a711416036ca124fc9b3f89e7c957535e465",
"type": "github"
}, },
"original": { "original": {
"owner": "taffybar", "path": "/home/imalison/dotfiles/dotfiles/config/taffybar/taffybar",
"ref": "master", "type": "path"
"repo": "taffybar",
"type": "github"
} }
}, },
"unstable": { "unstable": {
@@ -349,11 +345,11 @@
"pre-commit-hooks": "pre-commit-hooks" "pre-commit-hooks": "pre-commit-hooks"
}, },
"locked": { "locked": {
"lastModified": 1748252779, "lastModified": 1764753633,
"narHash": "sha256-kSyD/VDUX2m9c2vcuLBT2wnpYiVSHHlP9vuDTtsAtD8=", "narHash": "sha256-6552zbHzdNnkREnOluE6xePIib5cc/8Nc5OnPyHORUo=",
"owner": "NorfairKing", "owner": "NorfairKing",
"repo": "weeder-nix", "repo": "weeder-nix",
"rev": "388df7a6f00220d1960118e1ad37cd86150d2c5a", "rev": "2203c43ab9f1c4e52c2cff8e3d01bbb53159b922",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -1,10 +1,10 @@
{ {
inputs = { inputs = {
flake-utils.url = "github:numtide/flake-utils"; flake-utils.url = "github:numtide/flake-utils";
nixpkgs.url = "github:colonelpanic8/nixpkgs/remove-gi-gtk-hs-patch"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
xmonad.url = "github:xmonad/xmonad/master"; xmonad.url = "github:xmonad/xmonad/master";
taffybar = { taffybar = {
url = "github:taffybar/taffybar/master"; url = "path:/home/imalison/dotfiles/dotfiles/config/taffybar/taffybar";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
inputs.xmonad.follows = "xmonad"; inputs.xmonad.follows = "xmonad";
}; };
@@ -16,7 +16,7 @@
taffybar = prev.haskell.lib.overrideCabal hsuper.taffybar (oa: { taffybar = prev.haskell.lib.overrideCabal hsuper.taffybar (oa: {
doHaddock = false; doHaddock = false;
doCheck = false; doCheck = false;
# Fix for GHC 9.4 where liftA2 is not in Prelude # Legacy fix for older GHC (harmless on newer)
postPatch = (oa.postPatch or "") + '' postPatch = (oa.postPatch or "") + ''
substituteInPlace src/System/Taffybar/DBus/Client/Util.hs \ substituteInPlace src/System/Taffybar/DBus/Client/Util.hs \
--replace-fail "import Control.Monad (forM)" \ --replace-fail "import Control.Monad (forM)" \
@@ -47,7 +47,7 @@ import Control.Applicative (liftA2)"
final.xorg.libXtst.out final.xorg.libXtst.out
]; ];
}; };
defComp = { compiler = "ghc94"; }; defComp = { compiler = "ghc98"; };
overlay = xmonad.lib.fromHOL hoverlay defComp; overlay = xmonad.lib.fromHOL hoverlay defComp;
overlayList = [ taffybar.overlays.default overlay ]; overlayList = [ taffybar.overlays.default overlay ];
in flake-utils.lib.eachDefaultSystem (system: in flake-utils.lib.eachDefaultSystem (system:
@@ -57,10 +57,21 @@ import Control.Applicative (liftA2)"
{ {
devShell = hpkgs.shellFor { devShell = hpkgs.shellFor {
packages = p: [ p.imalison-taffybar p.taffybar ]; packages = p: [ p.imalison-taffybar p.taffybar ];
nativeBuildInputs = with hpkgs; [ nativeBuildInputs = (with hpkgs; [
cabal-install cabal-install
# ghcid ormolu implicit-hie haskell-language-server hlint # ghcid ormolu implicit-hie haskell-language-server hlint
]) ++ [
pkgs.gdk-pixbuf
pkgs.librsvg
]; ];
shellHook = ''
if [ -z "''${GDK_PIXBUF_MODULE_FILE:-}" ]; then
export GDK_PIXBUF_MODULE_FILE="${pkgs.gdk-pixbuf}/lib/gdk-pixbuf-2.0/${pkgs.gdk-pixbuf.version}/loaders.cache"
fi
if [ -z "''${GDK_PIXBUF_MODULEDIR:-}" ]; then
export GDK_PIXBUF_MODULEDIR="${pkgs.gdk-pixbuf}/lib/gdk-pixbuf-2.0/${pkgs.gdk-pixbuf.version}/loaders"
fi
'';
}; };
defaultPackage = hpkgs.imalison-taffybar; defaultPackage = hpkgs.imalison-taffybar;
}) // { }) // {

View File

@@ -22,6 +22,7 @@ executable taffybar
, directory , directory
, filepath , filepath
, gi-gtk3 , gi-gtk3
, gi-gdkpixbuf
, gtk-sni-tray , gtk-sni-tray
, gtk-strut , gtk-strut
, haskell-gi-base , haskell-gi-base

View File

@@ -15,6 +15,7 @@ import qualified Data.Map as M
import Data.Maybe import Data.Maybe
import qualified Data.Text import qualified Data.Text
import Data.Time import Data.Time
import qualified GI.GdkPixbuf.Objects.Pixbuf as Gdk
import qualified GI.Gtk as Gtk import qualified GI.Gtk as Gtk
import qualified GI.Gtk.Objects.Overlay as Gtk import qualified GI.Gtk.Objects.Overlay as Gtk
import Network.HostName import Network.HostName
@@ -28,7 +29,7 @@ import System.Log.Handler.Simple
import System.Log.Logger import System.Log.Logger
import System.Process import System.Process
import System.Taffybar import System.Taffybar
import System.Taffybar.Context (appendHook) import System.Taffybar.Context (Backend(..), TaffyIO, appendHook, detectBackend)
import System.Taffybar.DBus import System.Taffybar.DBus
import System.Taffybar.DBus.Toggle import System.Taffybar.DBus.Toggle
import System.Taffybar.Hooks import System.Taffybar.Hooks
@@ -43,9 +44,12 @@ import System.Taffybar.Widget.Generic.Icon
import System.Taffybar.Widget.Generic.PollingGraph import System.Taffybar.Widget.Generic.PollingGraph
import System.Taffybar.Widget.Generic.PollingLabel import System.Taffybar.Widget.Generic.PollingLabel
import System.Taffybar.Widget.Util import System.Taffybar.Widget.Util
import System.Taffybar.Widget.Workspaces import qualified System.Taffybar.Widget.HyprlandWorkspaces as Hyprland
import qualified System.Taffybar.Widget.Workspaces as X11Workspaces
import System.Taffybar.WindowIcon (pixBufFromColor)
import Text.Printf import Text.Printf
import Text.Read hiding (lift) import Text.Read hiding (lift)
import Data.Int (Int32)
setClassAndBoundingBoxes :: MonadIO m => Data.Text.Text -> Gtk.Widget -> m Gtk.Widget setClassAndBoundingBoxes :: MonadIO m => Data.Text.Text -> Gtk.Widget -> m Gtk.Widget
setClassAndBoundingBoxes klass = buildContentsBox >=> flip widgetSetClassGI klass setClassAndBoundingBoxes klass = buildContentsBox >=> flip widgetSetClassGI klass
@@ -97,7 +101,7 @@ getFullWorkspaceNames = go <$> readAsListOfString Nothing "_NET_DESKTOP_FULL_NAM
where go = zip [WorkspaceId i | i <- [0..]] where go = zip [WorkspaceId i | i <- [0..]]
workspaceNamesLabelSetter workspace = workspaceNamesLabelSetter workspace =
remapNSP . fromMaybe "" . lookup (workspaceIdx workspace) <$> remapNSP . fromMaybe "" . lookup (X11Workspaces.workspaceIdx workspace) <$>
liftX11Def [] getFullWorkspaceNames liftX11Def [] getFullWorkspaceNames
where remapNSP "NSP" = "S" where remapNSP "NSP" = "S"
remapNSP n = n remapNSP n = n
@@ -124,6 +128,106 @@ logDebug = do
-- enableLogger "System.Taffybar.WindowIcon" DEBUG -- enableLogger "System.Taffybar.WindowIcon" DEBUG
-- enableLogger "System.Taffybar.Widget.Generic.PollingLabel" DEBUG -- enableLogger "System.Taffybar.Widget.Generic.PollingLabel" DEBUG
iconRemap :: [(Data.Text.Text, [Data.Text.Text])]
iconRemap =
[ ("spotify", ["spotify-client", "spotify"])
]
iconRemapMap :: M.Map Data.Text.Text [Data.Text.Text]
iconRemapMap =
M.fromList [ (Data.Text.toLower k, v) | (k, v) <- iconRemap ]
lookupIconRemap :: Data.Text.Text -> [Data.Text.Text]
lookupIconRemap name = fromMaybe [] $ M.lookup (Data.Text.toLower name) iconRemapMap
iconNameVariants :: Data.Text.Text -> [Data.Text.Text]
iconNameVariants raw =
let lower = Data.Text.toLower raw
stripped = fromMaybe lower (Data.Text.stripSuffix ".desktop" lower)
suffixes = ["-gtk", "-client", "-desktop"]
stripSuffixes name =
let variants = mapMaybe (`Data.Text.stripSuffix` name) suffixes
in nub $ variants ++ [name]
baseNames = stripSuffixes stripped ++ [raw]
toDash c
| c == ' ' || c == '_' || c == '.' || c == '/' = '-'
| otherwise = c
toUnderscore c
| c == ' ' || c == '-' || c == '.' || c == '/' = '_'
| otherwise = c
variantsFor name =
let dotted =
case Data.Text.splitOn "." name of
[] -> name
xs -> last xs
dashed = Data.Text.map toDash name
dashedDotted = Data.Text.map toDash dotted
underscored = Data.Text.map toUnderscore name
underscoredDotted = Data.Text.map toUnderscore dotted
in [dotted, dashed, dashedDotted, underscored, underscoredDotted, name]
in nub $ concatMap variantsFor baseNames
isSpecialHyprWorkspace :: Hyprland.HyprlandWorkspace -> Bool
isSpecialHyprWorkspace ws =
let name = Data.Text.toLower $ Data.Text.pack $ Hyprland.workspaceName ws
in Data.Text.isPrefixOf "special" name || Hyprland.workspaceIdx ws < 0
hyprlandIconCandidates :: Hyprland.HyprlandWindow -> [Data.Text.Text]
hyprlandIconCandidates windowData =
let baseNames = map Data.Text.pack $ catMaybes
[ Hyprland.windowClass windowData
, Hyprland.windowInitialClass windowData
]
remapped = concatMap lookupIconRemap baseNames
remappedExpanded = concatMap iconNameVariants remapped
baseExpanded = concatMap iconNameVariants baseNames
in nub (remappedExpanded ++ baseExpanded)
isPathCandidate :: Data.Text.Text -> Bool
isPathCandidate name =
Data.Text.isInfixOf "/" name ||
any (`Data.Text.isSuffixOf` name) [".png", ".svg", ".xpm"]
hyprlandIconFromCandidate size name
| isPathCandidate name =
liftIO $ getPixbufFromFilePath (Data.Text.unpack name)
| otherwise =
maybeTCombine
(Hyprland.getWindowIconFromDesktopEntryByAppId size (Data.Text.unpack name))
(liftIO $ loadPixbufByName size name)
hyprlandManualIconGetter :: Hyprland.HyprlandWindowIconPixbufGetter
hyprlandManualIconGetter =
Hyprland.handleIconGetterException $ \size windowData ->
foldl maybeTCombine (return Nothing) $
map (hyprlandIconFromCandidate size) (hyprlandIconCandidates windowData)
fallbackIconPixbuf :: Int32 -> TaffyIO (Maybe Gdk.Pixbuf)
fallbackIconPixbuf size = do
let fallbackNames =
[ "application-x-executable"
, "application"
, "image-missing"
, "gtk-missing-image"
, "dialog-question"
, "utilities-terminal"
, "system-run"
, "window"
]
tryNames =
foldl
maybeTCombine
(return Nothing)
(map (liftIO . loadPixbufByName size) fallbackNames)
result <- tryNames
case result of
Just _ -> return result
Nothing -> Just <$> pixBufFromColor size 0x5f5f5fff
hyprlandFallbackIcon :: Hyprland.HyprlandWindowIconPixbufGetter
hyprlandFallbackIcon size _ =
fallbackIconPixbuf size
cssFilesByHostname = cssFilesByHostname =
[ ("uber-loaner", ["uber-loaner.css"]) [ ("uber-loaner", ["uber-loaner.css"])
, ("imalison-home", ["taffybar.css"]) , ("imalison-home", ["taffybar.css"])
@@ -136,7 +240,7 @@ main = do
enableLogger "Graphics.UI.GIGtkStrut" DEBUG enableLogger "Graphics.UI.GIGtkStrut" DEBUG
hostName <- getHostName hostName <- getHostName
homeDirectory <- getHomeDirectory backend <- detectBackend
let relativeFiles = fromMaybe ["taffybar.css"] $ lookup hostName cssFilesByHostname let relativeFiles = fromMaybe ["taffybar.css"] $ lookup hostName cssFilesByHostname
cssFiles <- mapM (getUserConfigFile "taffybar") relativeFiles cssFiles <- mapM (getUserConfigFile "taffybar") relativeFiles
@@ -152,20 +256,32 @@ main = do
windowsNew defaultWindowsConfig windowsNew defaultWindowsConfig
myWorkspaces = myWorkspaces =
flip widgetSetClassGI "workspaces" =<< flip widgetSetClassGI "workspaces" =<<
workspacesNew defaultWorkspacesConfig X11Workspaces.workspacesNew X11Workspaces.defaultWorkspacesConfig
{ minIcons = 1 { minIcons = 1
, getWindowIconPixbuf = , getWindowIconPixbuf =
scaledWindowIconPixbufGetter $ X11Workspaces.scaledWindowIconPixbufGetter $
getWindowIconPixbufFromChrome <|||> X11Workspaces.getWindowIconPixbufFromChrome <|||>
unscaledDefaultGetWindowIconPixbuf <|||> X11Workspaces.unscaledDefaultGetWindowIconPixbuf <|||>
(\size _ -> lift $ loadPixbufByName size (\size _ -> fallbackIconPixbuf size)
"application-default-icon")
, widgetGap = 0 , widgetGap = 0
, showWorkspaceFn = hideEmpty , showWorkspaceFn = X11Workspaces.hideEmpty
, updateRateLimitMicroseconds = 100000 , updateRateLimitMicroseconds = 100000
, labelSetter = workspaceNamesLabelSetter , labelSetter = workspaceNamesLabelSetter
, widgetBuilder = buildLabelOverlayController , widgetBuilder = X11Workspaces.buildLabelOverlayController
} }
myHyprWorkspaces =
flip widgetSetClassGI "workspaces" =<<
Hyprland.hyprlandWorkspacesNew Hyprland.defaultHyprlandWorkspacesConfig
{ Hyprland.widgetGap = 0
, Hyprland.minIcons = 1
, Hyprland.showWorkspaceFn =
(\ws -> Hyprland.workspaceState ws /= Hyprland.Empty &&
not (isSpecialHyprWorkspace ws))
, Hyprland.getWindowIconPixbuf =
hyprlandManualIconGetter <|||>
Hyprland.defaultHyprlandGetWindowIconPixbuf <|||>
hyprlandFallbackIcon
}
myClock = deocrateWithSetClassAndBoxes "clock" $ myClock = deocrateWithSetClassAndBoxes "clock" $
textClockNewWith textClockNewWith
defaultClockConfig defaultClockConfig
@@ -193,7 +309,7 @@ main = do
] ]
fullEndWidgets = baseEndWidgets ++ [ myCPU, myMem, myNet, myMpris ] fullEndWidgets = baseEndWidgets ++ [ myCPU, myMem, myNet, myMpris ]
laptopEndWidgets = batteryWidgets ++ baseEndWidgets laptopEndWidgets = batteryWidgets ++ baseEndWidgets
baseConfig = baseConfigX11 =
defaultSimpleTaffyConfig defaultSimpleTaffyConfig
{ startWidgets = [ myWorkspaces, myLayout, myWindows ] { startWidgets = [ myWorkspaces, myLayout, myWindows ]
, endWidgets = baseEndWidgets , endWidgets = baseEndWidgets
@@ -204,30 +320,65 @@ main = do
, cssPaths = cssFiles , cssPaths = cssFiles
, centerWidgets = [ myClock ] , centerWidgets = [ myClock ]
} }
baseConfigWayland =
defaultSimpleTaffyConfig
{ startWidgets = [ myHyprWorkspaces ]
, endWidgets = baseEndWidgets
, barPosition = Top
, widgetSpacing = 0
, barPadding = 0
, barHeight = ScreenRatio $ 1/27
, cssPaths = cssFiles
, centerWidgets = [ myClock ]
}
x11Overrides =
[ ( "uber-loaner"
, baseConfigX11 { endWidgets = laptopEndWidgets }
)
, ( "adell"
, baseConfigX11 { endWidgets = laptopEndWidgets }
)
, ( "stevie-nixos"
, baseConfigX11 { endWidgets = laptopEndWidgets
, startWidgets = [ myWorkspaces, myLayout ]
}
)
, ( "strixi-minaj"
, baseConfigX11 { endWidgets = laptopEndWidgets }
)
, ( "jay-lenovo"
, baseConfigX11 { endWidgets = laptopEndWidgets }
)
, ( "nixquick"
, baseConfigX11 { endWidgets = [ myTray , myMpris ] }
)
]
waylandOverrides =
[ ( "uber-loaner"
, baseConfigWayland { endWidgets = laptopEndWidgets }
)
, ( "adell"
, baseConfigWayland { endWidgets = laptopEndWidgets }
)
, ( "stevie-nixos"
, baseConfigWayland { endWidgets = laptopEndWidgets }
)
, ( "strixi-minaj"
, baseConfigWayland { endWidgets = laptopEndWidgets }
)
, ( "jay-lenovo"
, baseConfigWayland { endWidgets = laptopEndWidgets }
)
, ( "nixquick"
, baseConfigWayland { endWidgets = [ myTray , myMpris ] }
)
]
selectedConfig = selectedConfig =
fromMaybe baseConfig $ lookup hostName case backend of
[ ( "uber-loaner" BackendX11 ->
, baseConfig { endWidgets = laptopEndWidgets } fromMaybe baseConfigX11 $ lookup hostName x11Overrides
) BackendWayland ->
, ( "adell" fromMaybe baseConfigWayland $ lookup hostName waylandOverrides
, baseConfig { endWidgets = laptopEndWidgets }
)
, ( "stevie-nixos"
, baseConfig { endWidgets = laptopEndWidgets
, startWidgets = [myWorkspaces, myLayout]
}
)
, ( "strixi-minaj"
, baseConfig { endWidgets = laptopEndWidgets }
)
, ( "jay-lenovo"
, baseConfig { endWidgets = laptopEndWidgets }
)
, ( "nixquick"
, baseConfig { endWidgets = [ myTray , myMpris ] }
)
]
simpleTaffyConfig = selectedConfig simpleTaffyConfig = selectedConfig
{ centerWidgets = [ myClock ] { centerWidgets = [ myClock ]
-- , endWidgets = [] -- , endWidgets = []
@@ -237,4 +388,4 @@ main = do
appendHook (void $ getTrayHost False) $ appendHook (void $ getTrayHost False) $
withLogServer $ withLogServer $
withToggleServer $ withToggleServer $
toTaffyConfig simpleTaffyConfig toTaffybarConfig simpleTaffyConfig