SFWBAR(1)
πΈ NAME πΈ
sfwbar β the S* Floating Window taskBar, bestie. It's manual section 1, and it's rocking a GPLv3+ copyright. (There's also a stray little test :Copyright: GPLv3+ :Manual section: 1 line hanging around in the source page like a forgotten hair tie, so here it is, preserved for the archives. π
)
β¨ SYNOPSIS β¨
sfwbar [options]
π¦ DESCRIPTION π¦
Okay so, SFWBar is a taskbar for wayland compositors. It was originally written for Sway, but fr fr it should work with any compositor that supports the layer-shell protocol. π
What it actually does: it assists in handling floating windows on a wayland desktop. It gives you:
- a taskbar
- a pager
- a task switcher
- a system tray
- a floating window placement engine
- a simple widget set for displaying data extracted from various system files
SFWBar can work with any wayland compositor supporting layer shell protocol. BUT β pay attention, this part matters β the taskbar and switcher require either sway or wlr-foreign-toplevel protocol support. The placer and pager require sway. No sway, no placer, that's just the vibe check. π
π OPTIONS π
The SFWBar executable can be invoked with the following options:
-f|--configβ specify a filename of a configuration file-c|--cssβ specify a filename of a css file-s|--socketβ specify a location of sway ipc socket-m|--monitorβ specify a monitor to display the bar on ("-m list"to list available monitors)-b|--bar_idβ specify a swaybar_idon which sfwbar will listen for status changes
π CONFIGURATION π
SFWBar reads configuration from a config file (sfwbar.config by default). The program checks the user's XDG config directory (usually ~/.config/sfwbar/) for this file, followed by system xdg data directories. Additionally, you can specify a location and a name of the config file using the -f command line option. π«Ά
Appearance of the program can be specified using CSS properties. These are sourced either from the css section of the main configuration file, or from a file with a .css extension with the same base name as the config file, located in the same directory as the config file. The name of the css file can also be specified using the -c option.
Sfwbar can be restarted and its configuration reloaded by sending a SIGHUP signal to the sfwbar process, i.e. killall -SIGHUP sfwbar. β¨
The config file consists of the following top level sections:
π Placer π
The Placer section enables intelligent placement of new floating windows. If enabled, the program will first attempt to place the window in a location where it won't overlap with other windows. If such a location doesn't exist, the window will be placed in a cascading pattern from top-left to bottom-right. π
The Placer declaration accepts parameters "xstep" and "ystep" that specify the steps in the window cascade. These are specified in percentage of the desktop dimensions. The cascade placement will start at a location specified by "xorigin" and "yorigin" parameters. I.e.:
placer {
xorigin = 5
yorigin = 5
xstep = 5
ystep = 5
children = false
}
The "children" parameter specifies if new windows opened by a program with other windows already opened should be placed. These are usually dialog windows, and SFWBar won't place them by default.
If the placer section is not present in the file, SFWBar will let the compositor determine the locations for new windows. No cap.
β Task Switcher β
Task switcher implements a keyboard shortcut to cycle focus across windows (i.e. Alt-Tab, the classic). The action is triggered upon receiving a change in a bar hidden_state property or signal SIGUSR1. This can be configured in Sway, via one of the following bindings:
bindsym Alt-Tab bar hidden_state toggle
or
bindsym Alt-Tab exec killall -SIGUSR1 sfwbar
(for non-sway compositors, use the SIGUSR1 trigger)
NixOS + Hyprland (and probably other non-sway compositors) use:
bind = ALT, Tab, exec, killall -SIGUSR1 .sfwbar-wrapped
Task switcher is configured in the "switcher" section of the configuration file. The following parameters are accepted:
intervalβ a timeout after the last task switch event after which the selected window is activatedlabels [true|false]β display window titles in the task listicons [true|false]β display window icons in the task listcolsβ a number of columns in the task listcssβ css code applicable to the switcher grid. This property can only be set to a static string, not an expression. You can specify more detailed css code in the main CSS file. Use style name#switcherfor the task switcher window and the main grid, and the names#switcher_normaland#switcher_activefor inactive and active window representations respectively.
π Layout π
Defines the layout of the taskbar. The layout holds a set of widgets. Widgets can be nested in case of a grid widget, which acts as a container. π§
The following widget types are supported:
taskbarβ a special widget displaying a list of all floating windows. (requires a compositor supporting wlr-foreign-toplevel protocol or i3 ipc)pagerβ a special widget displaying a list of all workspaces. (requires a compositor supporting wlr-foreign-toplevel protocol or i3 ipc)trayβ a special widget displaying a list of tray icons received via status notifier item interfacegridβ a layout grid capable of containing other widgets. You can use these to further subdivide each cell of the main grid and arrange items within it.labelβ a label displaying text sourced from an expression. Labels accept pango markup to further theme text within them.scaleβ a progress bar with a progress value specified by an expressionchartβ a chart plotting the value of the expression over timeimageβ display an icon or an image from a file. The name of an icon or a file is specified by an expression and can change dynamically.buttonβ add a clickable button with an icon/image.
Each widget is placed within the parent grid. By default, widgets are placed next to the previous widget along the "direction" of the grid (left to right by default). You can specify a widget's position within a grid by using a property "loc(x,y[,w,h])", with the first two parameters specifying the location of the widget within the parent grid and the last two parameters specifying the widget dimensions in grid cells:
layout "id" {
label {
style = "mystyle"
value = SwapUsed / SwapTotal + "%"
loc(2,1,1,1)
}
}
The optional "id" string of the layout specifies the bar to populate, and can control positioning of the grid within a bar using syntax of "name:position". Valid positions are start, center and end. This allows placement of some widgets in the center of the bar β main character energy. π In case of a single bar, the name of a bar can be omitted, i.e. ":center". External widgets can be included in a layout using the following syntax:
layout {
include("MyWidget.widget")
}
The above will include all scanner variables data and the widget sub-layout from file MyWidget.widget.
Grid widgets can contain other widgets; these are declared within the grid definition, i.e.
grid {
css = "* { border: none }"
label "id" {
...
}
}
Widgets can optionally have unique id's assigned to them in order to allow manipulating them in the future. π―
All widgets can have the following properties:
valueβ an expression specifying the value to display. This can be a static value (i.e."string"or1) or an expression (i.e."Value is:" + $MyStringor2 * MyNumber.val). See the expressions section for more detail. For Label widgets,valuetells the text to display. For Scale widgets, it specifies a fraction to display. For Chart widgets, it specifies a fraction of the next datapoint. For Image widgets and buttons, it provides an icon or an image file name.styleβ a style name for the widget. Styles can be used in CSS to theme widgets. Multiple widgets can have the same style. A style name can be used in css using the gtk+ named widget convention, i.e.label#mystyle. The style property can be set to an expression to change styles in response to changes in system parameters.tooltipβ sets a tooltip for a widget. A tooltip can be a static value or an expression. In case of the latter, the tooltip will be dynamically updated every time it pops up.intervalβ widget update frequency in milliseconds.triggerβ trigger on which event updates. Triggers are emitted by Client sources. A widget should not have both anintervaland atriggerspecified. (if both are specified,intervalis ignored andtriggeris used).cssβ additional css properties for the widget. These properties will only apply to the widget in question. You can have multiple instances of thecssproperty in a single widget definition and they all will be applied in the order of their occurrence. Thecssproperty value can only be a static string, not an expression.actionβ an action to execute upon interaction with a widget. Actions can be attached to any widget. Multiple actions can be attached to various pointer events. The notation isaction[<event>] = <action>. Event values are1,2,3orLeftClick,MiddleClickorRightClickrespectively. For mouse scroll events, use values4,5,6,7,8orScrollUp,ScrollDown,ScrollLeft,ScrollRightandDragrespectively. If no index is specified, the action is attached to a left mouse button click. Additionally, modifiers can be specified using the notation of[Modifier+]Index. I.e.action[Ctrl+LeftClick]. The following modifiers are supported:Shift,Ctrl,Mod1,Mod2,Mod3,Mod4,Mod5,Super,Hyper, andMeta. Multiple modifiers can be added, i.e.action[Ctrl+Shift+ScrollUp].action[0]will be executed on startup. You can use this action to set initial configuration for a widget. See the Actions section for more details on how actions are specified.
π Taskbar widget options π
Taskbar widget may contain the following options:
labels [true|false]β an indicator whether to display an application title within the taskbaricons [true|false]β an indicator whether to display application icons within the taskbarfilter_output [true|false]β This property is deprecated, please usefilterinstead. Specifies whether the taskbar should only list windows present on the same output as the taskbar.filter [output|workspace]β Specifies whether the taskbar should only list windows present on the same output or workspace as the taskbar itself.title_widthβ set maximum width of an application title in characterssort [true|false]β the vibe check on whether taskbar items get sorted for you or not. If they're not sorted, you (yes you, bestie) can drag-and-drop them around yourself. Default is sorted, so set this tofalseto unlock the drag-and-drop fantasy β¨rowsβ how many rows live in a taskbar.colsβ how many columns live in a taskbar. Important tea: if you set bothrowsandcols,rowswins, no discussion. If you set neither, the default isrows=1πgroup [popup|pager|false]β set totrueand your taskbar items get grouped together like a lil friend group π«Ά The supported groupings arepopupandpager.- In a
popupgrouping, windows are grouped byapp_id. The main taskbar holds one item perapp_id, with an icon and a label set to theapp_id. Hover over it and it pops up a "group taskbar" containing items for the individual windows. It's giving β¨folder energyβ¨. - In a
pagergrouping mode, the taskbar is partitioned into workspaces and each workspace contains the windows that belong to it. Drag a window from one workspace to another and it moves to the destination workspace. (ngl, right now this is only supported withswayandhyprlandcompositors β other compositors would need new wayland protocols adopted first, so don't come for me.)
- In a
You can specify taskbar parameters for the group taskbars using the group prefix, i.e. group cols = 1. The properties supported for groups are cols, rows, style, css, title_width, labels, icons.
β¨ Layout objects may have the following options β¨
sensor <timeout>β tells the bar whether it should hide itself once your pointer leaves the bar window (autohide, the classic disappearing act π¨). Once it's hidden, the bar pops back up if your pointer touches the sensor β that lil invisible thing chilling along the screen edge where the bar lives. A numeric value sets the bar pop-down delay in milliseconds. If the timeout is zero, the bar is always visible, periodt.size = <string>β sets the size of the bar (width for a top or bottom bar, height for a left or right bar). The argument is a string, like"800"for 800 pixels or"50%"for 50% of screen size. Math? In my bar? More likely than you think πmonitor = <string>β assigns the bar to a given monitor. The monitor name can be prefixed by"static:", i.e."static:eDP-1". If you set this and the specified monitor doesn't exist or gets disconnected, the bar will not jump to another monitor β it'll just hide and stay hidden until that monitor comes back. Loyalty πmirror = <string>β mirrors the bar onto monitors matching any of the specified patterns. The string parameter is a string list of patterns to match monitors against, i.e."eDP-*","HDMI-1"will mirror to any monitor whose name starts witheDP-or to the monitor namedHDMI-1. Patterns starting with'!'block the bar from being mirrored to a matching monitor. Patterns are glob style β'*'and'?'are your wildcards. The simplest use ismirror = "*", which mirrors the bar across literally all monitors πlayer = <string>β moves the bar to a specified layer. Supported parameters are"top","bottom","background"and"overlay".margin = <string>β sets the margin around the bar to the number of pixels specified by the string.exclusive_zone <string>β specifies the exclusive zone policy for the bar window. Acceptable values are"auto","-1","0"or positive integers. These mean the same things as the exclusive zone setting in the layer shell protocol. Default value is"auto".sway_bar_id <string>β specifies the bar ID to listen on formodeandhidden_statesignals. If no bar ID is specified, SfwBar will listen to signals on all IDs. FOMO who? Not this bar π
β¨ Pager widget may contain the following options β¨
preview [true|false]β says whether workspace previews show up when you hover your mouse over pager buttons. Little sneak peek, we love to see it πsort [true|false]β same energy as before: do pager items get sorted automatically? If not sorted, you can sort them manually via drag-and-drop. Sorted by default; set this tofalseto enable drag-and-drop.pinsβ a list of "pinned" workspaces. These will show up in the pager even if the workspace is empty. They're basically permanent residents πrowsβ a number of rows in a pager.colsβ a number of columns in a pager. If bothrowsandcolsare specified,rowsis used. If neither is specified, the default isrows=1.
β¨ tray widget may contain the following options β¨
rowsβ a number of rows in a pager.colsβ a number of columns in a pager. If bothrowsandcolsare specified,rowsis used. If neither is specified, the default isrows=1.sort [true|false]β whether tray items get sorted. If they're not sorted, the user can sort them manually via drag-and-drop. Sorted by default, set this tofalseto enable drag-and-drop.
β¨ popup window may contain the following options β¨
AutoClose [true|false]β specifies whether the popup window should close if the user clicks anywhere outside of the window. Click away and it's gone, bye π
π¦ PopUp π¦
Popup windows can be defined the exact same way as layouts. The only difference is that popups are not part of a bar and will not be displayed by default. Instead, they show up when a PopUp action is invoked on a widget. i.e.:
PopUp "MyPopup" {
label { value = "test" }
}
Layout {
label {
value = "click me"
action = PopUp "MyPopup"
}
}
The PopUp action toggles visibility of the popup window. I.e. the first time it's invoked, the window pops up; on the second invocation, it pops down. So yes, it's safe to bind the PopUp to multiple widgets β it won't get confused, it's got main character multitasking energy π
π Menus π
User defined menus can be attached to any widget (see the action widget property). Menus are defined using a Menu section in the config file. The example syntax is as following:
menuclear("menu_name")
menu ("menu_name") {
item("item1", Exec "command")
separator
submenu("sub","mysubmenu") {
item("item2", SwayCmd "focus next")
}
}
The command MenuClear deletes any existing items from a menu. Each menu has a name used to link the menu to the widget action, plus a list of menu items. If a menu with the same name is defined more than once, the items from subsequent declarations get appended to the original menu. Want to fully re-define it instead? Use the MenuClear action to clear the original menu first. No cap π§
The following menu items are supported:
itemβ an actionable menu item. This item has three parameters: the first is a label, the second is an action to execute when the item is activated, and the third is an optionidyou can use to delete the item later if needed. See the Actions section for more details on supported actions.separatorβ a menu separator. This item has no parameters. Just vibes and a line β¨submenuβ attach a submenu. The first parameter is a label to display in the parent menu; the second optional parameter is a menu name. If a menu name is assigned, the third optional parameter is anidyou can use later to delete the submenu using theMenuItemClearaction. Further items can be added to a submenu just like to any other menu. Menus within menus, it's giving inception π
π₯ Triggers π₯
Triggers are emitted in response to various events, such as compositor state changes, real time signals, or notifications from modules. Some triggers can be defined as part of the configuration (i.e. SocketClient or ExecClient scanner sources), others are built in, or defined in modules.
Built-in triggers are:
SIGRTMIN+Xβ RT signalSIGRTMIN+Xhas been received (X is a number)swayβ Data has been received onSwayClientscanner sourcempdβ Data has been received onMpdClientscanner source<output>-connectedβ an output has been connected (i.e.eDP-1-connected)<output>-disconnectedβ an output has been disconnected
π Actions π
Actions can be attached to click and scroll events for any widget, or to items within a menu. Actions can be conditional on a state of a window or a widget they refer to, and some actions may require a parameter. Conditions are specified in square brackets prior to the action, i.e. [Minimized], and can be inverted using ! or joined using |, i.e. [!Minimized | Focused]. All conditions on the list must be satisfied. Supported conditions are: Minimized, Maximized, Focused, FullScreen and UserState.
Actions can be activated upon receipt of a trigger from one of the client type sources, using the TriggerAction top-level keyword. I.e.
TriggerAction "mytrigger", Exec "MyCommand"
Parameters are specified as strings immediately following the relevant action. I.e. Menu "WindowOps". Some actions apply to a window β if the action is attached to a taskbar button, the action applies to the window referenced by the button; otherwise, it applies to the currently focused window. The way it just knows which window you meant. The following action types are supported:
Config <string>β process a snippet of configuration file. This action lets you change the bar configuration on the fly π₯Exec <string>β execute a shell commandFunction [<addr>,]<string>β runs a function π«. It takes an optional address, so you can invoke a function on one specific widget, iykyk.Menu <string>β opens a menu with the name you hand it. πΈMenuClear <string>β deletes a menu with that given name ποΈ. This one is so useful if you wanna generate menus dynamically viaPipeReadand you'd like to delete a menu you generated earlier, bestie.MenuItemClear <string>β deletes a menu item whose id matches the string. Real talk: the menu item must be declared with an id if you wanna use this action on it. πPipeRead <string>β processes a lil snippet of configuration sourced from the output of a shell command π«Ά.SwayCmd <string>β sends a command over Sway IPC. π₯SwayWinCmd <string>β sends a command over Sway IPC that applies to the current window. πͺMpdCmd <string>β sends a command to Music Player Daemon. π΅ClientSend <string>, <string>β sends a string to a client. That string gets written to the client's standard input forexecClientclients, or written into a socket forsocketClient's. First parameter = the client id, second parameter = the string to send. β¨SwitcherEvent <string>β triggers a switcher event: it brings up the switcher window and cycles the focus either forward or back based on the argument. The string argument can be either"foward"or"back". If the argument is omitted, the focus will cycle forward. (and yes, it's spelled"foward"up in here, we just live with it π)MapIcon <app_id>, <icon>β use icon<icon>for applications with app id<app_id>. πSetMonitor [<bar_name>,]<string>β moves the bar to a given monitor. Thebar_namestring specifies a bar to move. The monitor name can be prefixed by"static:", i.e."static:eDP-1"β if this is set and the specified monitor doesn't exist or gets disconnected, the bar will not jump to another monitor, it'll just be hidden and won't reappear until the monitor is reconnected. π β οΈ This action is deprecated, please use propertymonitorinstead.SetMirror [<bar_name>,]<string>β mirrors the bar to monitors matching any of the specified patterns. Ifbar_nameis specified, the mirror instruction gets applied to that specific bar, otherwise it applies to all bars. The string parameter is a colon-delimited list of patterns to match the monitors against, i.e."eDP-:HDMI-1"will mirror to any monitor with a name starting with"eDP-"or a monitor named"HDMI-1". Patterns are glob style,*and?are used as wildcards. The simplest use isSetMirror "*", which mirrors all bars across all monitors. πͺ β οΈ This action is deprecated, please use propertymirrorinstead.SetLayer [<bar_name>,]<string>β moves the bar to a specified layer (supported parameters are"top","bottom","background"and"overlay"). β οΈ This action is deprecated, please use propertylayerinstead.SetBarSize [<bar_name>,]<string>β sets the size of the bar (width for a top or bottom bar, height for a left or right bar). The argument is a string, i.e."800"for 800 pixels or"50%"for 50% of screen size. π β οΈ This action is deprecated, please use propertysizeinstead.SetBarMargin [<bar_name>,]<string>β sets the margin around the bar to the number of pixels specified by the string. β οΈ This action is deprecated, please use propertymargininstead.SetBarSensor [<bar_name>],<string>β specifies whether the bar should be hidden once the pointer leaves the bar window. Once it's hidden, the bar will popup again if the pointer touches the sensor located along the screen edge along which the bar is placed. The string specifies the bar pop-down delay in milliseconds. β±οΈ β οΈ This action is deprecated, please use propertysensorinstead.SetBarID <string>β specifies the bar ID to listen on formodeandhidden_statesignals. If no bar ID is specified, SfwBar will listen to signals on all IDs. β οΈ This action is deprecated, please use propertysway_bar_idinstead.SetExclusiveZone [<bar_name>,]<string>β specifies the exclusive zone policy for the bar window. Acceptable values are"auto","-1","0"or positive integers. These have meanings in line with the exclusive zone setting in the layer shell protocol. Default value is"auto". β οΈ This action is deprecated, please use propertyexclusive_zoneinstead.SetValue [<widget>,]<string>β sets the value of the widget. This action applies to the widget from which the action chain has been invoked. I.e. a widget may popup a menu, which in turn will call a function, which executedSetValueβ and theSetValuewill still act upon the widget that popped up the menu. πSetStyle [<widget>,]<string>β sets the style name for a widget. πSetTooltip [<widget>,]<string>β sets the tooltip text for a widget. π¬UserState <string>β sets a boolean user state on a widget. Valid values are"On"or"Off". πFocusβ set window to focused. πCloseβ close a window. βMinimizeβ minimize a window (send to scratchpad in sway). π₯UnMinimizeβ unset a minimized state for the window. π€Maximizeβ maximize a window (set fullscreen in sway). π₯οΈUnMaximizeβ unset a maximized state for the window. π³
π§ Functions π§
Functions are sequences of actions. You reach for them when multiple actions need to be executed on a single trigger. A genuinely iconic example of this whole thing is dynamically constructed menus generated by an external script:
function("fancy_menu") {
MenuClear "dynamic_menu"
PipeRead "$HOME/bin/buildmenu.sh"
Menu "dynamic_menu"
}
So what's happening up there? It clears a menu, executes a script that builds a menu again, and then opens the resulting menu. Chef's kiss. π
Also important: the function "SfwBarInit" is executed on startup. You can use this function to set initial parameters for the bar, such as default monitor and layer. π
π Scanner π
SFWBar widgets display data obtained from various sources. These can be files or output of commands. π
Each source section contains one or more variables that SFWBar will poll periodically and populate with the data parsed from the source. The sources and the variables linked to them are configured in the section scanner:
scanner {
File("/proc/swaps",NoGlob) {
SwapTotal = RegEx("[\t ]([0-9]+)")
SwapUsed = RegEx("[\t ][0-9]+[\t ]([0-9]+)")
}
Exec("getweather.sh") {
WeatherTemp = Json(".forecast.today.degrees")
}
ExecClient("stdbuf -oL foo.sh BAR BAZ", "foo") {
Foo_foo = Json(".foo")
Foo_bar = Json(".bar")
}
}
Each declaration within the scanner section specifies a source. This can be one of the following:
Fileβ read data from a file. πExecβ read data from an output of a shell command. πExecClientβ read data from an executable. This source will wait for any output from the standard output of the executable. Once available (i.e. the program flushes its output) the source will populate the variables and emit a trigger event. This source accepts two parameters: the command to execute and an id. The id can be used to write to the standard input of the executable viaClientSend(provided that the executable takes standard input) and to identify a trigger emitted upon variable updates. β οΈ USE RESPONSIBLY: if a trigger causes the client to receive new data (i.e. by triggering aClientSendcommand that in turn triggers a response from the source), you can end up with an infinite loop π (seealsa.widgetandrfkill-wifi.widgetas examples).SocketClientβ read data from a socket. This source will read a burst of data, using it to populate the variables and emit a trigger event once done. This source accepts two parameters: a socket address and an id. The id is used to address the socket viaClientSendand to identify a trigger emitted upon variable updates. β οΈ USE RESPONSIBLY: if a trigger causes the client to receive new data (i.e. by triggering aClientSendcommand that in turn triggers a response from the source), you can end up with an infinite loop. π΅βπ«MpdClientβ read data from Music Player Daemon IPC (data is polled whenever MPD responds to an'idle player'event).MpdClientemits trigger"mpd". π§ (seempd-int.widgetas an example)SwayClientβ receive updates on Sway state. The updates are the json objects sent by sway, wrapped into an object with a name of the event, i.e.window: { sway window change object }.SwayClientemits trigger"sway". π (seesway-lang.widgetas an example).
The file source also accepts further optional arguments specifying how the scanner should handle the source. These can be:
NoGlobβ specifies that SFWBar shouldn't attempt to expand the pattern in the file name. If this flag is not specified, the file source will attempt to read from all files matching a filename pattern. π§©CheckTimeβ indicates that the program should only update the variables from this file when the file modification date/time changes. π°οΈ
Variables are extracted from sources using parsers. Currently the following parsers are supported:
Grab([Aggregator])β specifies that the data is copied from the file verbatim. βRegEx(Pattern[,Aggregator])β extracts data using a regular expression parser; the variable is assigned data from the first capture buffer. πJson(Path[,Aggregator])β extracts data from a json structure. The path starts with a separator character, which is followed by a path with elements separated by the same character. The path can contain numbers to indicate array indices, i.e..data.node.1.string, and key checks to filter arrays, i.e..data.node.[key="blah"].value. π§¬
Optional aggregators specify how multiple occurrences of numeric data are treated. The following aggregators are supported:
Firstβ the variable should be set to the first occurrence of the pattern in the source. π₯Lastβ the variable should be set to the last occurrence of the pattern in the source. πSumβ the variable should be set to the sum of all occurrences of the pattern in the source. βProductβ the variable should be set to the product of all occurrences of the pattern in the source. βοΈ
For string variables, Sum and Product aggregators are treated as Last. π
β¨ Global Options β¨
okay so these are the global config options, bestie. they're giving main character energy for your whole setup π
Theme<string> β overrides a Gtk theme to the name you specify. it's giving makeover montage πIconTheme<string> β overrides a Gtk icon theme. icons? slay.DisownMinimized<boolean> β disassociates windows from their workplaces when they are minimized. if this option is set, selecting a minimized window will unminimize it on the active workplace. if set toFalse(which is the default, bestie), the window will be unminimized to its last workplace. this option only applies to Sway and Hyprland compositors, no cap.FilterTitle<regex> β any windows with titles matching a regular expression <regex> will not be shown on the taskbar or switcher. bye felicia πFilterAppId<regex> β any windows with appids matching a regular expression <regex> will not be shown on the taskbar or switcher. same vibe, different filter.TriggerAction<trigger>, <action> β executes an action when a trigger is emitted. <trigger> is a string, and <action> is any valid action, as described in the Actions section. it's giving if-this-then-that but make it iconic β¨
π₯ EXPRESSIONS π₯
okay so bestie, values in widgets can contain basic arithmetic and string manipulation expressions. these allow transformation of data obtained by the scanner before it is displayed by the widgets. it's like a little glow-up for your data before it hits the screen π
the numeric operations are:
+β addition-β subtraction*β multiplication/β division%β remainder of an integer division>β greater than>=β greater than or equal<β less than>=β less than or equal
bestie, yes the second >= says "less than or equal" β that's a typo in the original, but we're keeping it real π
=β equalValβ convert a string into a number, the argument is a string or a string expression to convert.Ifβ conditional:If(condition,expr1,expr2)Cachedβ get last value from a variable without updating it:Cached(identifier)Identβ Check if an identifier exists either as a variable or a function
The string operations are: β¨ okay bestie, this is the fun part, these are the little magic words you can call to mess with text π
+β concatenates strings, like'String'+$Var. yes it's literally just plus, math girlies stay winning πMidβ extracts a substring, likeMid($Var,2,5)βοΈExtractβ pulls out a regex pattern, likeExtract($Var,'FindThis:(GrabThat)')π΅οΈβοΈ she finds, she grabs, she servesStrβ converts a number into a string. The first argument is a number (or a numeric expression), and the second argument is the decimal precision. If the precision is omitted, the number gets rounded to the nearest integer π’Padβ pads a string to be n characters long. The first parameter is the string to pad, the second is the desired number of characters. If that number is negative, the string gets padded at the end; if it's positive, the string gets padded at the front. The third, optional string parameter tells it which character to pad with πUpperβ converts a string to upper case π£Lowerβ converts a string to lower case π€«Escapeβ sanitizes text input for a label widget π§ΌReadβ reads the contents of a file into a string πReplaceβ replaces one substring with another within a string, asReplace (string, old, new)πLookupβ looks up a numeric value within a list of tuplets. The function call isLookup(Value, Threshold1, String1, ..., DefaultString). She checks the value against the thresholds and returns the String associated with the highest threshold matched by the Value. If the Value is lower than all the thresholds,DefaultStringis what you get back. Lowkey important: the thresholds in the function call must be in decreasing order πMapβ matches a string within a list of tuplets. The usage is:
Map(Value, Match1,String`,...,DefaultString).
She'll match Value against all the Match strings and return the corresponding String. If none of the Match strings match, the function returns DefaultString πΊοΈ
ReplaceAllβ performs multiple substring replacements in a string,ReplaceAll(string, old1, new1, ...)π―
In addition, bestie, there's a whole stack of query functions you can use, and they're lowkey iconic:
Timeβ grabs the current time as a string β¨. The first optional argument sets the format, and the second optional argument sets a timezone. Returns a string.ElapsedStrβ takes a time interval (given in seconds) and formats it into an elapsed time string, likeJust nowor5 minutes ago. So cute, so useful.Diskβ gets disk utilization data πΎ. You gotta pass a mount point as the first argument and a data field as the second. The supported data fields are"total","avail","free","%avail","%free"or"%used". Returns a number.ActiveWinβ gets the title of the currently focused window π. Returns a string.GtkEventβ gets the location of an event that triggered the action. Heads up: this one is only applicable in action command expressions where an action is called as a result of a button click. The function returns the location of the click within the widget, and that value comes back as a percentage of the widget width or height. Acceptable arguments are"X","Y"and"Dir".XandYselect an axis to return the event location for, whileDirreturns the event location along the widget direction property.BarDirβ gets the direction property of the taskbar holding the current widget. Returns a string:"left","right","top","bottom"or"unknown".WidgetIDβ obtains an ID of the current widget (i.e. a widget in respect to which the expression is being evaluated).WindowInfoβ obtains information about a window πͺ. This function takes a window property as a single input parameter. Valid properties are:appid,title,minimized,maximized,fullscreen,focused.
Okay so now the numeric variable tea π β each numeric variable contains four values:
.valβ current value of the variable.pvalβ previous value of the variable.timeβ time elapsed between observing.pvaland.val.ageβ time elapsed since variable was last updated.countβ a number of time the pattern has been matched during the last scan
By default, the value of the variable is the value of .val. String variables are prefixed with $, i.e. $StringVar. The following string operations are supported. For example:
$MyString + Str((MyValue - MyValue.pval)/MyValue.time),2)
User defined expression macros are supported via the top-level define keyword. I.e.
define MyExpr = VarA + VarB * VarC + Val($Complex)
...
value = Str(MyExpr,2)
The above will expand the expression into:
value = Str(VarA + VarB * VarC + Val($Complex),2)
Macro's don't have types, because they perform substitution before the expression is evaluated. No cap π§
Intermediate variables can be declared using a top-level set keyword. I.e.
set MyExpr = VarA + VarB * VarC + Val($Complex
...
value = Str(MyExpr,2)
In the above example, the value of the MyExpr variable will be calculated, and that result will be used in computing the value expression. Intermediate variables have a type and have all of the fields of a scan variable (i.e. val, pval, time etc). They can be used the same way as scan variables. Periodt π
π MISCELLANEOUS π
If the icon is missing for a specific program in the taskbar or switcher, it's likely due to a missing icon, or the application not setting app_id correctly π. You can check app_id's of running programs by running:
sfwbar -d -g app_id
If app_id is present, you need to add an icon with the appropriate name to your icon theme. If it's blank, you can try mapping it from the program's title (please note that the title may change during runtime, so matching it can be tricky π). Mapping is supported via the top-level MapAppId keyword. I.e.
MapAppId app_id, pattern
where app_id is the desired app_id and pattern is a regular expression to match the title against.
If you are using an XWayland app, they usually do not have an app_id set. If an icon is not showing, you can add your icon to the following locations:
$HOME/.icons- One of the directories listed in
$XDG_DATA_DIRS/icons /usr/share/pixmaps- Location of the main config file currently in use
$XDG_CONFIG_HOME/sfwbar/
If an app_id is not set, and sway is being used, sfwbar will fallback to using the instance in the window-properties.
You can find the app_id that is being used with sfwbar by using the sfwbar -d -g app_id command, which will show a list of running applications if your compositor supports the wlr-foreign-toplevel protocol (i.e. labwc, wayfire, sway):
14:49:25.41 app_id: 'jetbrains-clion', title 'sfwbar β pager.c'
Alternatively your desktop environment might have a command to display a list:
- Sway:
swaymsg -t get_tree - Hyperland:
hyprctl -j clients
When using swaymsg -t get_tree, with CLion this will show the following:
"window_properties": {
"class": "jetbrains-clion",
"instance": "jetbrains-clion",
"title": "sfwbar β trayitem.c",
"transient_for": null,
"window_type": "normal"
}
So we can put an icon called jetbrains-clion.svg (or other formats, see the [Arch wiki](<https://wiki.archlinux.org/title/desktop_entries#Icons>) ) for information about file formats. π
π CSS STYLE π
SFWBar uses gtk+ widgets and can accept all css properties supported by gtk+ β¨. SFWBar widgets correspond to gtk+ widgets as following:
labelβ gtk+ widget:GtkLabelβ css class:labelimageβ gtk+ widget:GtkImageβ css class:imagebuttonβ gtk+ widget:GtkButtonβ css class:buttonscaleβ gtk+ widget:GtkProgressBarβ css class:progressbar,trough,progress
Taskbar, Pager, Tray and Switcher use combinations of these widgets and can be themed using gtk+ nested css convention, i.e. grid#taskbar button { ... } (this example assumes you assigned style = taskbar to your taskbar widget). Slay π«Ά
okay bestie, so SFWBar doesn't just do standard gtk+ css, it's got its own extra properties and they're lowkey iconic β¨ here's the whole vibe, no cap:
-GtkWidget-alignβ sets text alignment for a label, defined as a fraction. (i.e.0= left aligned,1= right aligned,0.5= centered) π-GtkWidget-ellipsizeβ tells you whether text in a label should be ellipsized if it's too long to fit in the allocated space. the way that's just good UX, fr fr.-GtkWidget-wrapβ wraps a string if it's too long for its container (you'd usually wanna pair it with-GtkWidget-max-width) π-GtkWidget-directionβ specifies a direction for a widget. for scale, it's a direction towards which scale grows. for a grid, it's a direction in which a new widget is positioned relative to the last placed widget. for a window it's an edge along which the bar is positioned. possible values:[top|bottom|left|right]π-GtkWidget-max-widthβ limits maximum width of a widget (in pixels) π-GtkWidget-max-heightβ limits maximum height of a widget (in pixels) π-GtkWidget-hexpandβ specifies if a widget should expand horizontally to occupy available space.[true|false]π-GtkWidget-vexpandβ as above, for vertical expansion. same energy, different axis π-GtkWidget-halignβ horizontally aligns a widget within any free space allocated to it. values supported are:fill,start,end,centerandbaseline. the last one vertically aligns widgets to align text within. it's giving attention to detail β¨-GtkWidget-valignβ vertically aligns a widget. simple as that, bestie.-GtkWidget-visibleβ controls visibility of a widget. if set tofalse, the widget will be hidden. not me hiding my problems with css π-ScaleImage-colorβ specifies a color to repaint an image with. the image will be painted with this color using the image's alpha channel as a mask. the color's own alpha value can be used to tint an image. obsessed with this level of control π-ScaleImage-symbolicβ renders an image as a symbolic icon. if set totrue, the image will be re-colored to the gtk theme foreground color, preserving the image alpha channel. this property is ignored if-ScaleImage-coloris specified. iykyk π¦-ScaleImage-shadow-radiusβ specifies a radius for a drop shadow of an image widget. a drop shadow is rendered if a radius or one of the offsets is specified for an image. (an integer specifying a number of pixels) πΈ-ScaleImage-shadow-x-offsetβ a horizontal offset of a drop shadow relative to an image. (an integer specifying a number of pixels) π-ScaleImage-shadow-y-offsetβ a vertical offset of a drop shadow relative to an image. (an integer specifying a number of pixels) β-ScaleImage-shadow-clipβ a boolean specifying whether a shadow is clipped to a padding box. iffalse, the shadow may spill over a border and a margin of a widget. (default =true) π-ScaleImage-shadow-colorβ a color of a drop shadow. periodt. π
Okay so here's the lil roster of what gets styled, bestie β every taskbar and pager button has its own vibe slot π
sfwbarβ the toplevel bar window itself, the whole main character πlayoutβ the top level layout gridtaskbar_itemβ the taskbar button for a window (supports the class.active) β¨takbar_popupβ the taskbar popup button (supports the class.active) πtaskbar_pagerβ the taskbar pager grid (supports the class.active) π¦pager_itemβ the pager button for a workspace (supports the classes.focusedand.visible) π₯switcher_itemβ the switcher window and top level grid (supports the class.active) βtrayβ tray menus and menu items πtray_itemβ the tray item icon (supports the classes.passiveand.attention) πmenu_itemβ menu items, and ngl each one contains an image and a label π
For example you can style the top level grid using grid#layout { }.
not me pointing out that takbar_popup really do be spelled like that in the source π copy it exactly, bestie, do not "fix" it or your CSS will simply not hit π
And that's a wrap on SFWBAR(1), fr fr π«Ά This page is the sfwbar manual, from SFWBAR(), dated the day it was generated β go forth and style your bar, you absolute icon ππ
π¦ where this page comes from
- fedora 43: sfwbar 1.0~beta16.1-2.fc43 Β· GPL-3.0-only AND MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms