# SwBr config — ~/.config/swbr/config # One key=value per line. '#' starts a comment. Blank lines are ignored. # Every key here also works on the command line (key=value or --key=value); # command-line values win over the file. See `swbr --help` for the list. # # Inline comments after a value are stripped, but a '#' inside quotes is not, # so foreground="#19cb00" inside a command is safe. # # All sizes are LOGICAL pixels: swbr multiplies them by the output scale, # so the bar keeps its size on a HiDPI screen. ui_scale scales the text on # top of that, and height=0 derives the height from the font. # --- placement --- layer=top # background | bottom | top | overlay # top floats above tiled windows but below fullscreen ones; # overlay stays above fullscreen too position=top # top | bottom height=0 # 0 = derive from the font size exclusive=0 # 0 = float above the windows, they keep the whole screen # 1 = reserve the space, windows tile below the bar margin=0 # gap to the screen edge side_margin=0 # gap left and right min_width=800 # 0 = span the whole output. Otherwise the bar floats and # sizes itself to its content: never narrower than this, # never wider than the screen. Cells appearing (charging, # docker) grow it instead of being cut off shrink_px=24 # it grows at once but ignores getting narrower by less than # this, so 99% -> 100% or a temperature losing a digit does # not move the whole (centred) bar shrink_s=30 # a bigger narrowing has to hold this long first align_x=center # where the floating bar sits: center | left | right radius=10 # corner radius. The two corners that touch the screen edge # stay square, so the bar sits flush against it outputs= # comma separated output names, empty = one bar per output # --- workspaces --- ws_names=0 # 0 = number only ("3" out of "3:web"), 1 = the full name ws_pad=11 ws_gap=4 ws_min_w=0 ws_inset=0 # gap above and below the buttons. 0 = the button spans # the full bar height, top to bottom ws_radius=0 # 0 = square corners. -1 = follow radius, or a full pill # when ws_inset > 0 ws_border=0 # outline thickness in px around every button. 0 = none, # which is the plain look: the gap between buttons is the # only division ws_slots=10 # always show the numbers 1..10, open or not. A free number # is the same button in the same place, just faint, and # clicking one opens that workspace. It also means the bar # is the same width folded and open. 0 = only what is open ws_empty_alpha=35 # how visible a free number is, percent ws_click=1 scroll_workspace=0 mode_show=1 # show the binding mode (resize, ..) # --- text --- # By default swbr uses the desktop's monospace font (via fontconfig). # font=DejaVu Sans Mono # font_alt=Noto Sans Symbols 2 # for glyphs the main font lacks ui_scale=1.0 # master text size. 1.3 = bigger, 0.85 = smaller text_px=19 # status text ws_px=19 # workspace labels text_y=-2 # nudge every baseline, logical px, negative = up pad_x=12 # padding at the left end pad_right=20 # padding at the right end, so the last cell can breathe scroll_speed=45 # text cells: logical px per second while hovered scroll_pause=900 # ms held at each end before scrolling # --------------------------------------------------------------------------- # CELLS — the right hand side # # cell=NAME declares a cell. The order of these lines is the order # the cells appear in, left to right. # NAME.cmd=... shell command; whatever it prints is the cell text. # Print nothing and the cell disappears, separator too. # NAME.interval=2 seconds between runs. 0 = run once at start, # -1 = keep the command running and take every line. # NAME.fmt=%s C %s is replaced by the output. No printf escaping: # a % in here is just a %. # NAME.color= text colour NAME.bg= cell background # NAME.warn=>70:cecb00 NAME.crit=<12:ff2222 # recolour when the first number in the output is at or # above (>) / at or below (<) the threshold # NAME.min_w=280 keep this width even when the text is shorter # NAME.max_w=0 clip beyond this width # NAME.align=right left | center | right, inside min_w # NAME.sep=0 do not draw a separator after this cell — that is how # two cells are combined into one group # NAME.empty=TEXT drawn instead of hiding when the command prints # nothing — keeps the cell's area clickable # NAME.gap= space after this cell, overrides cell_gap. 0 glues it # to the next one: equal bg colours merge into one box # NAME.pad=0 padding inside the cell, left and right # NAME.slim=auto folded strip: auto | tick | bar | clock | presence | # off. presence = a plain block in the running colour, # present only while the program is # NAME.slim_color= override this cell's colour on the strip. Without it # the strip reuses the colour the cell's own text has, # so a cyan clock stays cyan when folded # NAME.slim_color2= second colour: the minutes of a clock cell # NAME.slim_min=0 the value range a gauge maps, so a temperature or a # NAME.slim_max=100 load average can be a gauge as well as a percent # NAME.markup=1 the output may use .. # NAME.button2=CMD click the cell (1 left, 2 middle, 3 right, 4/5 wheel) # --------------------------------------------------------------------------- cell_gap=14 cell_inset=3 # gap above and below a cell background cell_radius=5 # corner radius of a cell background separator=│ separator_color=3a4654ff # --- messages --------------------------------------------------------------- # Anything can shout at the bar: # swbr --msg "warn: backup running" # swbr --msg "error: disk full" # swbr --msg clear # echo "info: hello" > $XDG_RUNTIME_DIR/swbr.fifo # While a message is up it takes over the cmus cell, so the title turns into # the warning and turns back into the title afterwards. Click it to dismiss. msg_target=cmus redraw_ms=250 # or refresh=0.25, the same thing in seconds. Try 1000 if # you would rather the bar redrew once a second. # Cell updates are held this long and merged into one # frame. Every frame is a round trip through the # compositor, and ten cells on their own timers otherwise # wake the bar three times a second. Anything from sway -- # a workspace switch, urgency -- skips the hold and is # drawn on the next frame msg_timeout=8 # seconds; 0 = stays until cleared msg_flash=1 # folded bar turns fully into the message colour msg_info=89afc4 msg_warn=cb9b00 msg_error=e0533c # --- cmus: two cells glued into one box ------------------------------------- # The title is a text cell: cut with ".." and scrolls while hovered. The # controls are their OWN cell so a long title can never truncate them away, # and they keep a fixed clickable area when nothing plays (empty=). # Both share one background: same bg + gap=0 merges them into a single box. # Note: the U+23Fx media glyphs (pause, stop) are missing from most mono # fonts, so the icon is derived here from glyphs that actually exist. cell=cmus cmus.source=cmus # swbr runs cmus-remote itself: no script, and playing vs # paused is read from cmus rather than guessed cmus.cmus_fmt=%n # just Artist — Title; %i is the icon, %a %t %s also work cmus.interval=2 cmus.scroll=1 # text cell: cut with ".." and scroll it while hovered cmus.min_w=210 # fixed slot, so nothing else on the bar ever shifts cmus.align=left cmus.pad=10 # breathing room inside the background box cmus.bg=ffffff14 # a faint lighter panel, not a solid block cmus.gap=0 # glued to the controls: one continuous background cmus.sep=0 cmus.slim=off # the title says nothing at five pixels cmus.button1=pgrep -x cmus >/dev/null && cmus_control toggle || foot -e cmus cmus.button2=cmus_control toggle cmus.button4=cmus_control prev cmus.button5=cmus_control next cell=cmusui cmusui.source=cmus # the same source, laid out as just the icon cmusui.cmus_fmt=%i # ▶ while playing, ⏸ while paused, following the real state cmusui.interval=2 cmusui.empty=♪ # cmus not running: still a button, click it to start cmusui.min_w=38 # never shrinks, never truncates cmusui.align=center cmusui.pad=4 cmusui.bg=ffffff14 cmusui.color=e8b81a cmusui.slim=media # folded: a full block while playing, a short dim one when # paused, nothing at all when cmus is stopped. # source=cmus knows which, so slim_on is not needed. cmusui.slim_w=26 # wider than the other ticks, so it is easy to find and hit cmusui.button1=pgrep -x cmus >/dev/null && cmus_control toggle || foot -e cmus cmusui.button2=cmus_control toggle cmusui.button4=cmus_control prev cmusui.button5=cmus_control next # --- volume ---------------------------------------------------------------- cell=volume volume.cmd=alsa_control volume get volume.interval=2 volume.button2=alsa_control mute toggle volume.slim=bar volume.slim_w=56 # folded: a gauge needs room for its ten blocks, and this # cell is only two characters wide. Wins over slim_align, # growing about the middle so it stays where the text was volume.slim_color=a9d8f5 # light baby blue, its own thing on the strip # --- docker and mpv share one group: docker.sep=0 joins them --------------- cell=docker docker.cmd=pgrep -x dockerd >/dev/null || exit 0; docker ps --format '{{.Image}}' | sed 's/:.*//' | xargs docker.interval=10 docker.color=19cb00 docker.sep=0 docker.slim=presence # folded: a block in the running colour, there only # while dockerd is, so a glance says it is up cell=mpv mpv.source=window # asks sway which workspaces have an mpv window, no jq and # no swaymsg. %n the name, %w the workspaces, %c how many mpv.program=mpv # matched against app_id, the X11 class, then the title mpv.src_fmt=%n [%w] mpv.interval=3 mpv.slim=presence # same for mpv: started something in the background? mpv.slim_color=3ea6ff # its own colour, so you can tell the two apart # --- clock ----------------------------------------------------------------- cell=clock clock.cmd=date '+%H:%M %a %d.%m' clock.interval=5 clock.hover_click=1 # the calendar opens on a click and stays until you # click again, rather than following the pointer clock.hover_cal=1 # the panel: this month, with today in the hl colour. # Built in, so the columns line up whatever the font and # nothing is spawned. hover_cmd=cal would work too # clock.hover_cmd=cal # the panel: this month, from cal(1). Run once when # the hover starts, not on a timer clock.slim=clock # twelve dots for the hour, in the same cyan the clock # uses in the full bar (taken from its own markup) clock.slim_color2=2f7f9f # the minutes bar, and the morning hours. Every dot # up to the hour is lit, so you count bars: 2 at 02:00 and # still 2 at 02:55. Main colour after noon, this one # before, so 13:00 and 1:00 differ # --- cpu load and temperature, joined -------------------------------------- cell=cpu cpu.cmd=cpu_in_percent cpu.fmt=%s% cpu.interval=2 cpu.color=e1eeff cpu.warn=>70:cecb00 cpu.crit=>80:cc0403 cpu.min_w=52 cpu.slim=bar # a gauge in the folded strip, 0..100% cpu.sep=0 cell=temp temp.cmd=t=$(cpu_temp); [ "${t%%.*}" -ge 70 ] 2>/dev/null && printf '%s°C' "$t" temp.interval=5 temp.warn=>70:cecb00 temp.crit=>85:cc0403 temp.slim=bar # a gauge too, but degrees are not percent: temp.slim_min=40 # so map 40..100 C onto the gauge temp.slim_max=100 # --- battery --------------------------------------------------------------- # The draw and the time left live in the hover panel now, so they are there # when you want them and not taking width when you do not. Uncomment this if # you would rather have them in the bar all the time. # cell=power # power.source=battery # power.src_fmt=%w %h # power.color=b3c0cd # power.slim=off # power.sep=0 # The marker at the end tells the folded strip which way it is going: # + charging, - discharging, = full. In the full bar it reads as ⚡ or nothing. cell=battery battery.source=battery # reads /sys itself: 83+ filling, 83- draining, no # sign when full # battery.bat_path=/sys/class/power_supply/BAT1 # if yours is not BAT0, or # you have two. Left out, swbr takes the first thing with a # capacity file, preferring one called BAT* # battery.src_fmt=%c%i %w %h # %c capacity, %i sign, %w watts now, %h hours # left, %s the word. This one reads "83- 21.5W 1.7h" # battery.cmd=... # setting a command switches the cell back to your own # script; source= and cmd= are the two ways, never both battery.hover=%w %h %e # the panel: 21.5W 1.7h left, or "0.3h to full" on # the cable. %e says which way the clock runs; with # nothing to report it falls back to the word Full # or Discharging battery.hover_click=1 # opens on a click and stays until you click again, # rather than following the pointer battery.hover_slim=0 # 1 = folded, resting on it opens the bar so the # panel has somewhere to go. 0 = no hover when folded battery.interval=10 battery.color=e1eeff battery.warn=<30:cecb00 battery.crit=<12:ff2222 battery.slim=bar battery.slim_w=56 # same again: wide enough to count the blocks # --- shouting when it is going flat ----------------------------------------- battery.alert=30,20,10,5,1 # percentages. Each fires once on the way down and # rearms when the charge comes back above it, or when the # cable goes in — no counter file, no repeats at 19% battery.alert_msg=BATTERY %c%% # taken over the bar like any other message; # the last level is sent as an error, the rest as warnings battery.alert_tone=250 # Hz. A sine with soft edges, written straight to battery.alert_ms=1050 # the player — no click, unlike a test tone. battery.alert_beeps=2 # 0 Hz for silence battery.alert_gain=35 # how loud the tone itself is, percent of full # scale. Costs nothing and touches no mixer, so try this # before alert_vol_min below. 80 is loud but still clean battery.alert_play=aplay -q -f cd - # on pipewire/pulse instead: # paplay --raw --rate=44100 --format=s16le --channels=2 # An alert nobody hears is not an alert. If the mixer is below this, swbr # raises it for the tone and puts it straight back — even if the alert is # killed half way through. ALSA has no per-stream level, so this is the master # control: music gets louder too, for the second or two the tone lasts. # 0 = never touch the mixer. battery.alert_vol_min=50 battery.alert_vol_get=amixer -M get Master | grep -o '[0-9]*%' | head -1 battery.alert_vol_set=amixer -M -q set Master %v% # any pair of commands works: the first prints a number, # the second takes %v. Your own alsa_control, pactl, # wpctl -- whatever you already use # A muted output stays muted: swbr cannot tell deliberate # silence from an accident. Append `unmute` to the set # command if you would rather it spoke anyway battery.alert_cmd=[ %c -le 1 ] && poweroff # run at every level, and ONLY at a level: the guard can # only ever be true if 1 is in the list above, which is why # it is. %c is the percentage. Check it works without # waiting for a flat battery: swbr --alert-test # poweroff needs root — give your user a sudo rule for it, # or the command silently does nothing # --- folding --------------------------------------------------------------- # Put the pointer over the bar and press the key: the bar rolls up into a thin # strip. Press it again to roll it back out. hide_key=space # matched by physical key, not by layout hover_keys=1 # grab the keyboard while the pointer is over the bar. # That is what makes hide_key work without clicking first. collapsed_px=5 anim_ms=120 slim_align=1 # folded: each mark takes its cell's whole place, same # left edge and same width, so toggling changes the height # of the bar and nothing else. # 0 = pack them against the right edge instead signals=1 # the folded strip still says something: every workspace # keeps a fixed slot on the left (slot 3 is always # workspace 3), the clock becomes twelve dots, and cells # with a percentage become little gauges slim_ws_slots=10 # only for slim_align=0, the packed strip: this many # slots. Lined up, the strip is exactly the open bar's own # buttons — same set, same place, same width — so set # ws_slots above to choose how many slim_bar_segs=10 # folded gauges are split into this many blocks, so four # lit blocks reads as forty percent without measuring it. # 0 = one solid bar. Halves itself in a cell too narrow to # show the dividers — give that cell a slim_w instead slim_bar_gap=2 # px between those blocks slim_bar_pad=3 # px either side of a folded gauge. A gauge takes its # whole cell, so without this it runs edge to edge slim_ws_w=0 # folded slot width in px. 0 = each slot copies its own # button in the open bar, so nothing moves or resizes start_collapsed=0 # 1 = start folded. Command line: swbr --slim # Without the mouse. Bind either one to a key in your sway config: # bindsym $mod+b exec swbr --toggle (also --fold / --unfold) # bindsym $mod+b exec pkill -USR1 swbr # --- mouse: anywhere on the bar, folded or not ------------------------------ # Cell bindings win where a cell is; these catch everywhere else, which is the # reliable way to control music while the bar is folded down to a few pixels. # Same buttons your old sway bar block used. button2=cmus_control toggle button6=cmus_control prev button7=cmus_control next # --------------------------------------------------------------------------- # LAYOUT — one line that places everything. Keep it last: it assigns group, # order and separators, overriding pos= and sep= above. # # || splits groups. One part = left only, two = left and right, # three = left, center, right. # , separates items. # (..) glues items together with no separator between them. # names are cell names plus the built-ins "workspaces" and "mode". # --------------------------------------------------------------------------- bar={workspaces,mode||(cmus,cmusui),volume,(docker,mpv),clock,(cpu,temp),battery} # --- colors: #rrggbb or #rrggbbaa ------------------------------------------ bg=26313fe6 # the bar itself text=e1eeffff # default cell colour alias: statusline dim=5a6b7aff accent=89afc4ff # visible-but-not-focused workspace tick hl=cb9b00ff # focused workspace tick in the folded strip urgent=e0533cff ws_sort=1 # order them by number. sway lists them grouped by output, # so two monitors otherwise give 1 2 5 8 3 10 ws_other=1 # 1 = also show the workspaces of your other monitors, as # short pills on the baseline so they are clearly not this # screen's ws_cpu=1 # a dot on each workspace button showing how much # processor time the windows on it are using. Folded, the # workspace slot fills from the bottom instead ws_cpu_interval=3 # seconds between samples # tree_min_s=5 # the load dots and source=window cells need sway's tree. # It is fetched only when sway reports a change, and never # more often than this. no_tree=1 stops asking entirely ws_cpu_idle=0.01 # in cores. Under this a workspace counts as doing # nothing and stays blank. Above it, but under ws_cpu_min, # one faint dot: a player, a polling script, something # small but alive ws_cpu_min=0.25 # where the real scale starts, in cores: 1.0 is one core # kept busy ws_cpu_full=4 # four cores fills the column. A share of the whole # machine was the wrong unit: on sixteen threads two busy # cores are twelve percent, which rounds to nothing running=3ddc84ff # folded strip: this program is up, and where a charging # gauge's pips ramp to slim_warm=e8963cff # where the direction pips start: orange into red while # draining, orange into green while charging ws_bg=00000000 # inactive button: nothing, the bar shows through ws_fg=b3c0cdff ws_focused_bg=cb9b00ff # the appwheel orange ws_focused_fg=141414ff ws_visible_bg=3c4a5cff ws_visible_fg=e1eeffff ws_urgent_bg=e0533cff ws_urgent_fg=141414ff mode_bg=cb9b00ff mode_fg=141414ff