remove ivanm-dfinity-razer and uber-loaner host references

Both hosts are long dead. Removes their CSS files, taffybar host
config entries, and synergy aliases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-07 14:41:29 -08:00
committed by Kat Huang
parent 09a57e4076
commit a22e4cfb8b
4 changed files with 271 additions and 657 deletions

View File

@@ -1,211 +0,0 @@
@define-color transparent rgba(0.0, 0.0, 0.0, 0.0);
@define-color white #FFFFFF;
@define-color black #000000;
@define-color taffy-blue #0c7cd5;
@define-color active-window-color @white;
@define-color urgent-window-color @taffy-blue;
@define-color font-color @white;
@define-color menu-background-color @white;
@define-color menu-font-color @black;
/* Top level styling */
.taffy-window * {
font-family: "Noto Sans", sans-serif;
font-size: 10pt;
color: @font-color;
}
.taffy-box {
border-color: @white;
border-style: solid;
border-radius: 0px;
}
.inner-pad {
padding: 3px;
}
.contents {
padding: 1px;
transition: border-color .5s, background-color .5s, border-style 3s;
border-radius: 6px;
/* This transparent border is needed because we will run in to sizing issues
without it because we only check sizing one time. */
border-color: @transparent;
border-width: 2px;
border-style: solid;
}
/* Workspaces styling */
.workspace-label {
padding-right: 3px;
padding-left: 2px;
font-size: 10pt;
}
.active .contents {
background-color: rgba(0.0, 0.0, 0.0, 0.2);
border-color: @font-color;
border-style: solid;
}
.visible .contents {
background-color: rgba(0.0, 0.0, 0.0, 0.2);
border-style: dotted;
border-color: @font-color;
}
.window-icon-container {
transition: opacity .5s, box-shadow .5s, background-color .5s;
opacity: 1;
border-radius: 5px;
}
/* This gives space for the box-shadow (they look like underlines) that follow.
This will actually affect all widgets, (not just the workspace icons), but
that is what we want since we want the icons to look the same. */
.auto-size-image, .sni-tray {
padding: 0px;
}
.window-icon-container.active {
background-color: @font-color;
}
.window-icon-container.urgent {
}
.window-icon-container.inactive .window-icon {
padding: 0px;
}
.window-icon-container.minimized .window-icon {
opacity: .3;
}
.window-icon {
opacity: 1;
transition: opacity .5s;
}
/* Button styling */
.taffy-window button {
all: initial;
background-color: @transparent;
border-width: 0px;
border-radius: 0px;
}
.taffy-window button:checked, .taffy-window button:hover .Contents:hover {
box-shadow: inset 0 -3px @taffy-blue;
}
/* Menu styling */
/* The ".taffy-window" prefixed selectors are needed because if they aren't present,
the top level .Taffybar selector takes precedence */
.taffy-window menuitem *, menuitem * {
color: @menu-font-color;
}
/* Force an opaque background for menus, regardless of the system GTK theme. */
.taffy-window menu, menu,
.taffy-window menu.background, menu.background,
.taffy-window .menu, .menu,
.taffy-window .menu.background, .menu.background,
GtkMenu, GtkMenu.background {
background-color: @menu-background-color;
background-image: none;
border: 1px solid rgba(0, 0, 0, 0.20);
padding: 4px 0px;
}
.taffy-window menu, menu {
background-color: @menu-background-color;
background-image: none;
}
/* Some themes apply transparency to the menu's toplevel popup window. */
window.popup, window.popup.background,
window.menu, window.menu.background,
.menu, .menu.background {
background-color: @menu-background-color;
background-image: none;
}
window.popup *, window.menu * {
background-color: @menu-background-color;
background-image: none;
}
window.popup decoration, window.menu decoration {
background-color: @menu-background-color;
background-image: none;
}
.taffy-window menuitem, menuitem {
background-color: @menu-background-color;
}
menu menuitem, GtkMenu menuitem, .menu menuitem {
background-color: @menu-background-color;
}
.taffy-window menuitem:hover, menuitem:hover {
background-color: @taffy-blue;
}
menu menuitem:hover, GtkMenu menuitem:hover, .menu menuitem:hover {
background-color: @taffy-blue;
}
window.popup menuitem:hover *, window.menu menuitem:hover * {
background-color: @taffy-blue;
}
menu *, GtkMenu *, .menu * {
background-color: @menu-background-color;
background-image: none;
}
menu menuitem:hover *, GtkMenu menuitem:hover *, .menu menuitem:hover * {
background-color: @taffy-blue;
}
.taffy-window menuitem:hover > label, menuitem:hover > label {
color: @menu-font-color;
}
/* Some menus (notably a few StatusNotifierItem menus) are rendered as popovers
containing modelbuttons instead of menuitems. */
popover, popover.background, popover > contents {
background-color: @menu-background-color;
background-image: none;
border: 1px solid rgba(0, 0, 0, 0.20);
}
popover modelbutton, popover modelbutton * {
background-color: @menu-background-color;
color: @menu-font-color;
}
popover modelbutton:hover {
background-color: @taffy-blue;
}
popover modelbutton:hover > label {
color: @menu-font-color;
}
popover * {
background-color: @menu-background-color;
background-image: none;
}
popover modelbutton:hover * {
background-color: @taffy-blue;
}

View File

@@ -1,118 +1,76 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE DataKinds #-}
module Main where
import Control.Exception.Base
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import Control.Monad.Trans.Reader
import qualified Data.ByteString.Char8 as BS
import Data.List
import Data.List.Split
module Main (main) where
import Control.Monad (guard, when)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Int (Int32)
import Data.List (nub)
import qualified Data.Map as M
import Data.Maybe
import qualified Data.Text
import Data.Time
import Data.Maybe (catMaybes, fromMaybe, isJust, mapMaybe)
import Data.Text (Text)
import qualified Data.Text as T
import qualified GI.GdkPixbuf.Objects.Pixbuf as Gdk
import qualified GI.Gtk as Gtk
import qualified GI.Gtk.Objects.Overlay as Gtk
import Network.HostName
import System.Directory
import System.Environment
import System.Environment.XDG.BaseDir
import System.FilePath.Posix
import System.IO
import System.Log.Handler.Simple
import System.Log.Logger
import System.Process
import System.Taffybar
import System.Taffybar.Context (Backend(..), TaffyIO, appendHook, detectBackend)
import Network.HostName (getHostName)
import System.Directory (doesPathExist)
import System.Environment (lookupEnv, setEnv, unsetEnv)
import System.Environment.XDG.BaseDir (getUserConfigFile)
import System.FilePath.Posix ((</>))
import System.Log.Logger (Priority (..), getLogger, logM, saveGlobalLogger, setLevel)
import System.Taffybar (startTaffybar)
import System.Taffybar.Context (Backend (BackendWayland, BackendX11), TaffyIO, detectBackend)
import System.Taffybar.DBus
import System.Taffybar.DBus.Toggle
import System.Taffybar.Hooks
import System.Taffybar.Information.CPU
import System.Taffybar.Information.EWMHDesktopInfo
import System.Taffybar.Information.Memory
import System.Taffybar.Information.EWMHDesktopInfo (WorkspaceId (..))
import System.Taffybar.Information.X11DesktopInfo
import System.Taffybar.SimpleConfig
import System.Taffybar.Util
import System.Taffybar.Util (getPixbufFromFilePath, (<|||>), maybeTCombine)
import System.Taffybar.Widget
import System.Taffybar.Widget.Generic.Icon
import System.Taffybar.Widget.Generic.PollingGraph
import System.Taffybar.Widget.Generic.PollingLabel
import qualified System.Taffybar.Widget.HyprlandWorkspaces as Hyprland
import qualified System.Taffybar.Widget.NetworkManager as NetworkManager
import qualified System.Taffybar.Widget.PulseAudio as PulseAudio
import System.Taffybar.Widget.SNITray
( sniTrayNew
, sniTrayThatStartsWatcherEvenThoughThisIsABadWayToDoIt
)
import System.Taffybar.Widget.Util
import qualified System.Taffybar.Widget.HyprlandWorkspaces as Hyprland
import System.Taffybar.Widget.Util (buildContentsBox, loadPixbufByName, widgetSetClassGI)
import qualified System.Taffybar.Widget.Workspaces as X11Workspaces
import System.Taffybar.WindowIcon (pixBufFromColor)
import Text.Printf
import Text.Read hiding (lift)
import Data.Int (Int32)
setClassAndBoundingBoxes :: MonadIO m => Data.Text.Text -> Gtk.Widget -> m Gtk.Widget
setClassAndBoundingBoxes klass = buildContentsBox >=> flip widgetSetClassGI klass
-- | 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
boxed <- buildContentsBox widget
widgetSetClassGI boxed klass
deocrateWithSetClassAndBoxes :: MonadIO m => Data.Text.Text -> m Gtk.Widget -> m Gtk.Widget
deocrateWithSetClassAndBoxes klass builder = builder >>= setClassAndBoundingBoxes klass
decorateWithClassAndBoxM :: MonadIO m => Text -> m Gtk.Widget -> m Gtk.Widget
decorateWithClassAndBoxM klass builder =
builder >>= decorateWithClassAndBox klass
mkRGBA (r, g, b, a) = (r/256, g/256, b/256, a/256)
blue = mkRGBA (42, 99, 140, 256)
yellow1 = mkRGBA (242, 163, 54, 256)
yellow2 = mkRGBA (254, 204, 83, 256)
yellow3 = mkRGBA (227, 134, 18, 256)
red = mkRGBA (210, 77, 37, 256)
-- ** X11 Workspaces
myGraphConfig =
defaultGraphConfig
{ graphPadding = 0
, graphBorderWidth = 0
, graphWidth = 75
, graphBackgroundColor = (0.0, 0.0, 0.0, 0.0)
}
x11FullWorkspaceNames :: X11Property [(WorkspaceId, String)]
x11FullWorkspaceNames =
go <$> readAsListOfString Nothing "_NET_DESKTOP_FULL_NAMES"
where
go = zip [WorkspaceId i | i <- [0 ..]]
netCfg = myGraphConfig
{ graphDataColors = [yellow1, yellow2]
, graphLabel = Just "net"
}
memCfg = myGraphConfig
{ graphDataColors = [(0.129, 0.588, 0.953, 1)]
, graphLabel = Just "mem"
}
cpuCfg = myGraphConfig
{ graphDataColors = [red, (1, 0, 1, 0.5)]
, graphLabel = Just "cpu"
}
memCallback :: IO [Double]
memCallback = do
mi <- parseMeminfo
return [memoryUsedRatio mi]
cpuCallback = do
(_, systemLoad, totalLoad) <- cpuLoad
return [totalLoad, systemLoad]
getFullWorkspaceNames :: X11Property [(WorkspaceId, String)]
getFullWorkspaceNames = go <$> readAsListOfString Nothing "_NET_DESKTOP_FULL_NAMES"
where go = zip [WorkspaceId i | i <- [0..]]
workspaceNamesLabelSetter workspace =
x11WorkspaceLabelSetter :: X11Workspaces.Workspace -> X11Workspaces.WorkspacesIO String
x11WorkspaceLabelSetter workspace =
remapNSP . fromMaybe "" . lookup (X11Workspaces.workspaceIdx workspace) <$>
liftX11Def [] getFullWorkspaceNames
where remapNSP "NSP" = "S"
remapNSP n = n
liftX11Def [] x11FullWorkspaceNames
where
remapNSP "NSP" = "S"
remapNSP n = n
enableLogger logger level = do
logger <- getLogger logger
-- ** Logging
enableLogger :: String -> Priority -> IO ()
enableLogger loggerName level = do
logger <- getLogger loggerName
saveGlobalLogger $ setLevel level logger
-- Systemd --user's manager environment can be stale across logins (e.g. still
@@ -149,48 +107,34 @@ detectBackendRobust = do
when (isJust mHyprSig) $ unsetEnv "HYPRLAND_INSTANCE_SIGNATURE"
when (mSessionType == Just "wayland") $ setEnv "XDG_SESSION_TYPE" "x11"
case () of
_ | waylandOk -> pure BackendWayland
| maybe False (not . null) mDisplay -> pure BackendX11
| otherwise -> detectBackend
let x11Ok = maybe False (not . null) mDisplay
if waylandOk
then pure BackendWayland
else if x11Ok
then pure BackendX11
else detectBackend
logDebug = do
global <- getLogger ""
saveGlobalLogger $ setLevel DEBUG global
logger3 <- getLogger "System.Taffybar"
saveGlobalLogger $ setLevel DEBUG logger3
logger <- getLogger "System.Taffybar.Widget.Generic.AutoSizeImage"
saveGlobalLogger $ setLevel DEBUG logger
logger2 <- getLogger "StatusNotifier.Tray"
saveGlobalLogger $ setLevel DEBUG logger2
-- workspacesLogger <- getLogger "System.Taffybar.Widget.Workspaces"
-- saveGlobalLogger $ setLevel WARNING workspacesLogger
-- logDebug
-- logM "What" WARNING "Why"
-- enableLogger "System.Taffybar.Widget.Util" DEBUG
-- enableLogger "System.Taffybar.Information.XDG.DesktopEntry" DEBUG
-- enableLogger "System.Taffybar.WindowIcon" DEBUG
-- enableLogger "System.Taffybar.Widget.Generic.PollingLabel" DEBUG
-- ** Hyprland Icon Finding
iconRemap :: [(Data.Text.Text, [Data.Text.Text])]
iconRemap :: [(Text, [Text])]
iconRemap =
[ ("spotify", ["spotify-client", "spotify"])
]
iconRemapMap :: M.Map Data.Text.Text [Data.Text.Text]
iconRemapMap :: M.Map Text [Text]
iconRemapMap =
M.fromList [ (Data.Text.toLower k, v) | (k, v) <- iconRemap ]
M.fromList [ (T.toLower k, v) | (k, v) <- iconRemap ]
lookupIconRemap :: Data.Text.Text -> [Data.Text.Text]
lookupIconRemap name = fromMaybe [] $ M.lookup (Data.Text.toLower name) iconRemapMap
lookupIconRemap :: Text -> [Text]
lookupIconRemap name = fromMaybe [] $ M.lookup (T.toLower name) iconRemapMap
iconNameVariants :: Data.Text.Text -> [Data.Text.Text]
iconNameVariants :: Text -> [Text]
iconNameVariants raw =
let lower = Data.Text.toLower raw
stripped = fromMaybe lower (Data.Text.stripSuffix ".desktop" lower)
let lower = T.toLower raw
stripped = fromMaybe lower (T.stripSuffix ".desktop" lower)
suffixes = ["-gtk", "-client", "-desktop"]
stripSuffixes name =
let variants = mapMaybe (`Data.Text.stripSuffix` name) suffixes
let variants = mapMaybe (`T.stripSuffix` name) suffixes
in nub $ variants ++ [name]
baseNames = stripSuffixes stripped ++ [raw]
toDash c
@@ -201,13 +145,13 @@ iconNameVariants raw =
| otherwise = c
variantsFor name =
let dotted =
case Data.Text.splitOn "." name of
case T.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
dashed = T.map toDash name
dashedDotted = T.map toDash dotted
underscored = T.map toUnderscore name
underscoredDotted = T.map toUnderscore dotted
in [dotted, dashed, dashedDotted, underscored, underscoredDotted, name]
in nub $ concatMap variantsFor baseNames
@@ -215,12 +159,12 @@ iconNameVariants raw =
-- usually not something we want visible in the workspace widget.
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
let name = T.toLower $ T.pack $ Hyprland.workspaceName ws
in T.isPrefixOf "special" name || Hyprland.workspaceIdx ws < 0
hyprlandIconCandidates :: Hyprland.HyprlandWindow -> [Data.Text.Text]
hyprlandIconCandidates :: Hyprland.HyprlandWindow -> [Text]
hyprlandIconCandidates windowData =
let baseNames = map Data.Text.pack $ catMaybes
let baseNames = map T.pack $ catMaybes
[ Hyprland.windowClass windowData
, Hyprland.windowInitialClass windowData
]
@@ -229,17 +173,18 @@ hyprlandIconCandidates windowData =
baseExpanded = concatMap iconNameVariants baseNames
in nub (remappedExpanded ++ baseExpanded)
isPathCandidate :: Data.Text.Text -> Bool
isPathCandidate :: Text -> Bool
isPathCandidate name =
Data.Text.isInfixOf "/" name ||
any (`Data.Text.isSuffixOf` name) [".png", ".svg", ".xpm"]
T.isInfixOf "/" name ||
any (`T.isSuffixOf` name) [".png", ".svg", ".xpm"]
hyprlandIconFromCandidate :: Int32 -> Text -> TaffyIO (Maybe Gdk.Pixbuf)
hyprlandIconFromCandidate size name
| isPathCandidate name =
liftIO $ getPixbufFromFilePath (Data.Text.unpack name)
liftIO $ getPixbufFromFilePath (T.unpack name)
| otherwise =
maybeTCombine
(Hyprland.getWindowIconFromDesktopEntryByAppId size (Data.Text.unpack name))
(Hyprland.getWindowIconFromDesktopEntryByAppId size (T.unpack name))
(liftIO $ loadPixbufByName size name)
hyprlandManualIconGetter :: Hyprland.HyprlandWindowIconPixbufGetter
@@ -274,124 +219,210 @@ hyprlandFallbackIcon :: Hyprland.HyprlandWindowIconPixbufGetter
hyprlandFallbackIcon size _ =
fallbackIconPixbuf size
-- ** Host Overrides
defaultCssFiles :: [FilePath]
defaultCssFiles = ["palette.css", "taffybar.css"]
cssFilesByHostname :: [(String, [FilePath])]
cssFilesByHostname =
[ ("uber-loaner", ["palette.css", "uber-loaner.css"])
, ("imalison-home", ["palette.css", "taffybar.css"])
, ("ivanm-dfinity-razer", ["palette.css", "taffybar.css"])
[ ("imalison-home", ["palette.css", "taffybar.css"])
, ("ryzen-shine", ["palette.css", "taffybar.css"])
, ("stevie-nixos", ["palette.css", "taffybar.css"])
]
laptopHosts :: [String]
laptopHosts =
[ "adell"
, "stevie-nixos"
, "strixi-minaj"
, "jay-lenovo"
]
cssFilesForHost :: String -> [FilePath]
cssFilesForHost hostName =
fromMaybe defaultCssFiles $ lookup hostName cssFilesByHostname
-- ** Widgets
audioWidget :: TaffyIO Gtk.Widget
audioWidget =
decorateWithClassAndBoxM "audio" PulseAudio.pulseAudioLabelNew
networkWidget :: TaffyIO Gtk.Widget
networkWidget =
decorateWithClassAndBoxM "network" NetworkManager.networkManagerWifiLabelNew
layoutWidget :: TaffyIO Gtk.Widget
layoutWidget =
decorateWithClassAndBoxM "layout" (layoutNew defaultLayoutConfig)
windowsWidget :: TaffyIO Gtk.Widget
windowsWidget =
decorateWithClassAndBoxM "windows" (windowsNew defaultWindowsConfig)
x11WorkspacesWidget :: TaffyIO Gtk.Widget
x11WorkspacesWidget =
flip widgetSetClassGI "workspaces" =<<
X11Workspaces.workspacesNew
X11Workspaces.defaultWorkspacesConfig
{ X11Workspaces.minIcons = 1
, X11Workspaces.getWindowIconPixbuf =
X11Workspaces.scaledWindowIconPixbufGetter $
X11Workspaces.getWindowIconPixbufFromChrome <|||>
X11Workspaces.unscaledDefaultGetWindowIconPixbuf <|||>
(\size _ -> fallbackIconPixbuf size)
, X11Workspaces.widgetGap = 0
, X11Workspaces.showWorkspaceFn = X11Workspaces.hideEmpty
, X11Workspaces.updateRateLimitMicroseconds = 100000
, X11Workspaces.labelSetter = x11WorkspaceLabelSetter
, X11Workspaces.widgetBuilder = X11Workspaces.buildLabelOverlayController
}
-- | Like 'buildWorkspaceIconLabelOverlay' but lets you choose the corner.
buildAlignedOverlay ::
Gtk.Align -> Gtk.Align -> Gtk.Widget -> Gtk.Widget -> TaffyIO Gtk.Widget
buildAlignedOverlay halign valign iconsWidget labelWidget = liftIO $ do
base <- buildContentsBox iconsWidget
ebox <- Gtk.eventBoxNew
_ <- widgetSetClassGI ebox "overlay-box"
Gtk.widgetSetHalign ebox halign
Gtk.widgetSetValign ebox valign
Gtk.containerAdd ebox labelWidget
overlayLabel <- Gtk.toWidget ebox
overlay <- Gtk.overlayNew
baseW <- Gtk.toWidget base
Gtk.containerAdd overlay baseW
Gtk.overlayAddOverlay overlay overlayLabel
Gtk.overlaySetOverlayPassThrough overlay overlayLabel True
Gtk.toWidget overlay
hyprlandWorkspacesWidget :: TaffyIO Gtk.Widget
hyprlandWorkspacesWidget =
flip widgetSetClassGI "workspaces" =<<
Hyprland.hyprlandWorkspacesNew
Hyprland.defaultHyprlandWorkspacesConfig
{ Hyprland.widgetGap = 0
, Hyprland.minIcons = 1
, Hyprland.widgetBuilder = buildAlignedOverlay Gtk.AlignStart Gtk.AlignEnd
-- Don't show Hyprland "special:*" workspaces.
, Hyprland.showWorkspaceFn =
\ws ->
Hyprland.workspaceState ws /= X11Workspaces.Empty &&
not (isSpecialHyprWorkspace ws)
, Hyprland.getWindowIconPixbuf =
hyprlandManualIconGetter <|||>
Hyprland.defaultHyprlandGetWindowIconPixbuf <|||>
hyprlandFallbackIcon
}
clockWidget :: TaffyIO Gtk.Widget
clockWidget =
decorateWithClassAndBoxM
"clock"
( textClockNewWith
defaultClockConfig
{ clockUpdateStrategy = RoundedTargetInterval 60 0.0
, clockFormatString = "%a %b %_d, 🕑%I:%M %p"
}
)
mprisWidget :: TaffyIO Gtk.Widget
mprisWidget =
mpris2NewWithConfig
MPRIS2Config
{ mprisWidgetWrapper = decorateWithClassAndBox "mpris"
, updatePlayerWidget =
simplePlayerWidget
defaultPlayerConfig
{ setNowPlayingLabel = playingText 20 20
}
}
batteryIconWidget :: TaffyIO Gtk.Widget
batteryIconWidget =
decorateWithClassAndBoxM "battery-icon" batteryIconNew
batteryTextWidget :: TaffyIO Gtk.Widget
batteryTextWidget =
decorateWithClassAndBoxM "battery-text" (textBatteryNew "$percentage$%")
batteryWidgets :: [TaffyIO Gtk.Widget]
batteryWidgets = [batteryIconWidget, batteryTextWidget]
-- Note: end widgets are packed with Gtk.boxPackEnd; list order is right-to-left.
batteryEndWidgets :: [TaffyIO Gtk.Widget]
batteryEndWidgets = reverse batteryWidgets
backlightWidget :: TaffyIO Gtk.Widget
backlightWidget =
decorateWithClassAndBoxM
"backlight"
( backlightLabelNewChanWith
defaultBacklightWidgetConfig
{ backlightFormat = "☀ $percent$%"
, backlightUnknownFormat = "☀ n/a"
, backlightTooltipFormat =
Just "Device: $device$\nBrightness: $brightness$/$max$ ($percent$%)"
}
)
sniTrayWidget :: TaffyIO Gtk.Widget
sniTrayWidget =
decorateWithClassAndBoxM
"sni-tray"
sniTrayNew
-- ** Layout
startWidgetsForBackend :: Backend -> [TaffyIO Gtk.Widget]
startWidgetsForBackend backend =
case backend of
BackendX11 -> [x11WorkspacesWidget, layoutWidget, windowsWidget]
-- These Wayland widgets are Hyprland-specific.
BackendWayland -> [hyprlandWorkspacesWidget]
endWidgetsForHost :: String -> Backend -> [TaffyIO Gtk.Widget]
endWidgetsForHost hostName backend =
let tray = sniTrayWidget
baseEndWidgets = [tray, audioWidget, networkWidget, mprisWidget]
-- Keep battery widgets visually *after* the tray (i.e. further to the right).
laptopEndWidgets =
batteryEndWidgets ++
[ tray
, audioWidget
, backlightWidget
, networkWidget
, mprisWidget
]
in if hostName `elem` laptopHosts
then laptopEndWidgets
else baseEndWidgets
mkSimpleTaffyConfig :: String -> Backend -> [FilePath] -> SimpleTaffyConfig
mkSimpleTaffyConfig hostName backend cssFiles =
defaultSimpleTaffyConfig
{ startWidgets = startWidgetsForBackend backend
, endWidgets = endWidgetsForHost hostName backend
, barPosition = Top
, widgetSpacing = 0
, barPadding = 4
, barHeight = ScreenRatio $ 1 / 36
, cssPaths = cssFiles
, centerWidgets = [clockWidget]
}
-- ** Entry Point
main :: IO ()
main = do
enableLogger "Graphics.UI.GIGtkStrut" DEBUG
hostName <- getHostName
backend <- detectBackendRobust
let relativeFiles = fromMaybe ["palette.css", "taffybar.css"] $ lookup hostName cssFilesByHostname
cssFiles <- mapM (getUserConfigFile "taffybar") relativeFiles
cssFiles <- mapM (getUserConfigFile "taffybar") (cssFilesForHost hostName)
let myCPU =
( deocrateWithSetClassAndBoxes "cpu" $
pollingGraphNew cpuCfg 5 cpuCallback
) :: TaffyIO Gtk.Widget
myMem =
( deocrateWithSetClassAndBoxes "mem" $
pollingGraphNew memCfg 5 memCallback
) :: TaffyIO Gtk.Widget
myNet =
( deocrateWithSetClassAndBoxes "net" $
networkGraphNew netCfg Nothing
) :: TaffyIO Gtk.Widget
myAudio = deocrateWithSetClassAndBoxes "audio" $
PulseAudio.pulseAudioLabelNew
myNetwork = deocrateWithSetClassAndBoxes "network" $
NetworkManager.networkManagerWifiLabelNew
myLayout = deocrateWithSetClassAndBoxes "layout" $
layoutNew defaultLayoutConfig
myWindows = deocrateWithSetClassAndBoxes "windows" $
windowsNew defaultWindowsConfig
myWorkspaces =
flip widgetSetClassGI "workspaces" =<<
X11Workspaces.workspacesNew X11Workspaces.defaultWorkspacesConfig
{ X11Workspaces.minIcons = 1
, X11Workspaces.getWindowIconPixbuf =
X11Workspaces.scaledWindowIconPixbufGetter $
X11Workspaces.getWindowIconPixbufFromChrome <|||>
X11Workspaces.unscaledDefaultGetWindowIconPixbuf <|||>
(\size _ -> fallbackIconPixbuf size)
, X11Workspaces.widgetGap = 0
, X11Workspaces.showWorkspaceFn = X11Workspaces.hideEmpty
, X11Workspaces.updateRateLimitMicroseconds = 100000
, X11Workspaces.labelSetter = workspaceNamesLabelSetter
, X11Workspaces.widgetBuilder = X11Workspaces.buildLabelOverlayController
}
myHyprWorkspaces =
flip widgetSetClassGI "workspaces" =<<
Hyprland.hyprlandWorkspacesNew Hyprland.defaultHyprlandWorkspacesConfig
{ Hyprland.widgetGap = 0
, Hyprland.minIcons = 1
-- Don't show Hyprland "special:*" workspaces.
, Hyprland.showWorkspaceFn =
(\ws -> Hyprland.workspaceState ws /= X11Workspaces.Empty &&
not (isSpecialHyprWorkspace ws))
, Hyprland.getWindowIconPixbuf =
hyprlandManualIconGetter <|||>
Hyprland.defaultHyprlandGetWindowIconPixbuf <|||>
hyprlandFallbackIcon
}
myClock = deocrateWithSetClassAndBoxes "clock" $
textClockNewWith
defaultClockConfig
{ clockUpdateStrategy = RoundedTargetInterval 60 0.0
, clockFormatString = "%a %b %_d, 🕑%I:%M %p"
}
myMpris =
mpris2NewWithConfig
MPRIS2Config
{ mprisWidgetWrapper = deocrateWithSetClassAndBoxes "mpris" . return
, updatePlayerWidget =
simplePlayerWidget
defaultPlayerConfig
{ setNowPlayingLabel = playingText 20 20
}
}
myBatteryIcon = deocrateWithSetClassAndBoxes "battery-icon" batteryIconNew
myBatteryText =
deocrateWithSetClassAndBoxes "battery-text" $ textBatteryNew "$percentage$%"
batteryWidgets = [ myBatteryIcon, myBatteryText ]
mySNITray = deocrateWithSetClassAndBoxes "sni-tray" $
case backend of
BackendWayland -> sniTrayThatStartsWatcherEvenThoughThisIsABadWayToDoIt
BackendX11 -> sniTrayNew
baseEndWidgets = [ myAudio, myNetwork, myMpris, mySNITray ]
laptopEndWidgets = batteryWidgets ++ baseEndWidgets
x11StartWidgets = [ myWorkspaces, myLayout, myWindows ]
hyprlandStartWidgets = [ myHyprWorkspaces ]
startWidgetsForBackend =
case backend of
BackendX11 -> x11StartWidgets
-- These Wayland widgets are Hyprland-specific.
BackendWayland -> hyprlandStartWidgets
baseConfig =
defaultSimpleTaffyConfig
{ startWidgets = startWidgetsForBackend
, endWidgets = baseEndWidgets
, barPosition = Top
, widgetSpacing = 0
, barPadding = 4
, barHeight = ScreenRatio $ 1 / 36
, cssPaths = cssFiles
, centerWidgets = [ myClock ]
}
hostOverrides =
[ ("uber-loaner", \cfg -> cfg { endWidgets = laptopEndWidgets })
, ("adell", \cfg -> cfg { endWidgets = laptopEndWidgets })
, ("stevie-nixos", \cfg -> cfg { endWidgets = laptopEndWidgets })
, ("strixi-minaj", \cfg -> cfg { endWidgets = laptopEndWidgets })
, ("jay-lenovo", \cfg -> cfg { endWidgets = laptopEndWidgets })
]
simpleTaffyConfig =
fromMaybe baseConfig $ ($ baseConfig) <$> lookup hostName hostOverrides
let simpleTaffyConfig = mkSimpleTaffyConfig hostName backend cssFiles
startTaffybar $
withLogServer $
withToggleServer $

View File

@@ -1,203 +0,0 @@
@define-color transparent rgba(0.0, 0.0, 0.0, 0.0);
@define-color white #FFFFFF;
@define-color black #000000;
@define-color taffy-blue #0c7cd5;
@define-color active-window-color @white;
@define-color urgent-window-color @taffy-blue;
@define-color font-color @white;
@define-color menu-background-color @white;
@define-color menu-font-color @black;
/* Top level styling */
.taffy-window * {
font-family: "Noto Sans", sans-serif;
font-size: 10pt;
color: @font-color;
}
.taffy-box {
border-color: @white;
border-style: solid;
border-radius: 0px;
}
.inner-pad {
padding: 1px;
}
.contents {
padding: 1px;
transition: background-color .5s;
border-radius: 6px;
}
/* Workspaces styling */
.workspace-label {
padding-right: 3px;
padding-left: 2px;
font-size: 10pt;
}
.active .contents {
background-color: rgba(0.0, 0.0, 0.0, 0.2);
}
.visible .contents {
background-color: rgba(0.0, 0.0, 0.0, 0.2);
}
.window-icon-container {
transition: opacity .5s, box-shadow .5s;
opacity: 1;
border-radius: 5px;
transition: background-color 1s;
}
/* This gives space for the box-shadow (they look like underlines) that follow.
This will actually affect all widgets, (not just the workspace icons), but
that is what we want since we want the icons to look the same. */
.auto-size-image, .sni-tray {
padding: 1px;
}
.window-icon-container.active {
background-color: rgba(255.0, 255.0, 255.0, 0.3);
}
.window-icon-container.urgent {
}
.window-icon-container.inactive .window-icon {
padding: 0px;
}
.window-icon-container.minimized .window-icon {
opacity: .3;
}
.window-icon {
opacity: 1;
transition: opacity .5s;
}
/* Button styling */
.taffy-window button {
all: initial;
background-color: @transparent;
border-width: 0px;
border-radius: 0px;
}
.taffy-window button:checked, .taffy-window button:hover .Contents:hover {
box-shadow: inset 0 -3px @taffy-blue;
}
/* Menu styling */
/* The ".taffy-window" prefixed selectors are needed because if they aren't present,
the top level .Taffybar selector takes precedence */
.taffy-window menuitem *, menuitem * {
color: @menu-font-color;
}
/* Force an opaque background for menus, regardless of the system GTK theme. */
.taffy-window menu, menu,
.taffy-window menu.background, menu.background,
.taffy-window .menu, .menu,
.taffy-window .menu.background, .menu.background,
GtkMenu, GtkMenu.background {
background-color: @menu-background-color;
background-image: none;
border: 1px solid rgba(0, 0, 0, 0.20);
padding: 4px 0px;
}
.taffy-window menu, menu {
background-color: @menu-background-color;
background-image: none;
}
/* Some themes apply transparency to the menu's toplevel popup window. */
window.popup, window.popup.background,
window.menu, window.menu.background,
.menu, .menu.background {
background-color: @menu-background-color;
background-image: none;
}
window.popup *, window.menu * {
background-color: @menu-background-color;
background-image: none;
}
window.popup decoration, window.menu decoration {
background-color: @menu-background-color;
background-image: none;
}
.taffy-window menuitem, menuitem {
background-color: @menu-background-color;
}
menu menuitem, GtkMenu menuitem, .menu menuitem {
background-color: @menu-background-color;
}
.taffy-window menuitem:hover, menuitem:hover {
background-color: @taffy-blue;
}
menu menuitem:hover, GtkMenu menuitem:hover, .menu menuitem:hover {
background-color: @taffy-blue;
}
window.popup menuitem:hover *, window.menu menuitem:hover * {
background-color: @taffy-blue;
}
menu *, GtkMenu *, .menu * {
background-color: @menu-background-color;
background-image: none;
}
menu menuitem:hover *, GtkMenu menuitem:hover *, .menu menuitem:hover * {
background-color: @taffy-blue;
}
.taffy-window menuitem:hover > label, menuitem:hover > label {
color: @menu-font-color;
}
/* Some menus (notably a few StatusNotifierItem menus) are rendered as popovers
containing modelbuttons instead of menuitems. */
popover, popover.background, popover > contents {
background-color: @menu-background-color;
background-image: none;
border: 1px solid rgba(0, 0, 0, 0.20);
}
popover modelbutton, popover modelbutton * {
background-color: @menu-background-color;
color: @menu-font-color;
}
popover modelbutton:hover {
background-color: @taffy-blue;
}
popover modelbutton:hover > label {
color: @menu-font-color;
}
popover * {
background-color: @menu-background-color;
background-image: none;
}
popover modelbutton:hover * {
background-color: @taffy-blue;
}