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:
@@ -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;
|
||||
}
|
||||
@@ -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 $
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user