Desktop tools

2025-06-16

Window manager

  • bspwm - tiling window manager based on binary space partitioning
  • bspc - a program that writes messages on bspwm’s socket, used to setup and control bspwm

.config/bspwm/bspwmrc:

#! /bin/sh
SECONDARY_SCREEN=$(xrandr --query | awk '/ connected/ && !/ primary/ {print $1; exit}')

bspc config border_width         1
bspc config window_gap           0

bspc config split_ratio          0.5
bspc config borderless_monocle   true
bspc config gapless_monocle      true
bspc config focus_by_distance    true
bspc config history_aware_focus  true
bspc config focus_follows_pointer  true
bspc config remove_unplugged_monitors  true

bspc config normal_border_color \#0d0d0d
bspc config focused_border_color \#35322d
bspc config urgent_border_color \#cd9641
bspc config automatic_scheme alternate
bspc config initial_polarity second_child
bspc config directional_focus_tightness low
bspc config single_monocle true

# define tags for monitor
bspc monitor $PRIMARY_SCREEN -d Q W E A S D

# windows with special treatment
bspc rule -a mplayer state=floating
bspc rule -a Onboard state=floating
bspc rule -a Peek state=floating
bspc rule -a stalonetray state=floating manage=off
bspc rule -a Screenkey manage=off

bspc config pointer_mod         mod4
bspc config pointer_action1     move
bspc config pointer_action2 resize_corner

bspc config top_padding  $PANEL_HEIGHT
bspc config bottom_padding  0

# launch the bar script
exec bar.sh

Bspwm does not listen for any keybindings, another program is needed to capture key press and use bspc to control bspwm.

Hotkeys

  • sxhkd Simple X HotKey Daemon When sxhkd detects a keypress it runs command defined for it in the configuration file.

You can discover key names using xev.
For actions that should also work outside X (such as changing brightness and volume), consider using acpi.

.config/sxhkd/sxhkdrc:

Print
    scrot ~/dat/scrot/%Y-%m-%d-%T.png

super + r
    urxvt
super + shift + r
    bspc node -f @parent && bspc node -R 90

super + v
    dmenu_run -nb '#000000' -sb '#333' -fn 'Terminus-12'
super + shift + v
     bspc node @/ -R 90

super + x
    clipmenu -nb '#000000' -sb '#333' -fn 'Terminus-12'
super + shift + x
    dmenu-calc.sh


super + t
    bspc desktop -l next
super + p
    bspc wm -r
super + shift + p
    xrandrToggleScreens.sh
super + Return
    bspc node -s biggest.local
super + shift + Return
    bspc monitor -f next

super + c
    bspc node -c
super + shift + c
    bspc node -k

super + space
    bspc node -t floating
super + shift + space
    bspc node -t tiled

super + f
	bspc node @/ -F horizontal
super + shift + f
	bspc node @/ -F vertical

super + g
	bspc node @/ -E
super + shift + g
	bspc node @/ -B

## hide window
super + y
	bspc node -g hidden=on
## unhide window
super + shift + y
    bspc node "$(bspc query -N -n .hidden | tail -n1)" -g hidden=off

super + {q,w,e,a,s,d,plus,ecaron,scaron,ccaron}
	bspc desktop -f {Q,W,E,A,S,D,+,ě,š,č}
super + shift + {q,w,e,a,s,d,plus,ecaron,scaron,ccaron}
	bspc node -d {Q,W,E,A,S,D,+,ě,š,č}

super + {Left,Down,Up,Right}
	bspc node -f {west,south,north,east}
super + shift + {Left,Down,Up,Right}
	bspc node -s {west,south,north,east}

    
super + shift + h
	bspc node @east -r -50; bspc node @west -r -50 
super + shift + l
	bspc node @east -r +50; bspc node @west -r +50 
super + shift + j
	bspc node @north -r -50; bspc node @south -r -50 
super + shift + k
	bspc node @north -r +50; bspc node @south -r +50 

super + h
	bspc node -f prev.local 
super + l
	bspc node -f next.local
super + j
	bspc node @/ -C backward
super + k
	bspc node @/ -C forward


super + {n,m}
         bspc node -p {south, east}
super + shift + {n,m}
         bspc node -p {north, west}
## set the node flags
super + ctrl + {y,x,c,v}
	bspc node -g {marked,locked,sticky,private}

super + shift + F10
    bspc quit

super + comma
    rotateXdisplayAndPointers.sh normal
super + shift + comma
    rotateXdisplayAndPointers.sh inverted
super + period
    rotateXdisplayAndPointers.sh left
super + shift + period
    rotateXdisplayAndPointers.sh right

Things run here:

Status bar

See bar.sh for the status bar setup.

Application launcher

  • dmenu - a dynamic menu for X, originally designed for dwm. It manages large numbers of user-defined menu items efficiently In .config/sxhkd/sxhkdrc:
super + v
    dmenu_run.sh -nb '#000000' -sb '#333' -fn 'Terminus-12'

Calculator

Using menu-calc.

In .config/sxhkd/sxhkdrc:

super + shift + x
    dmenu-calc.sh

Screenshots

  • scrot - command line screen capture utility. In .config/sxhkd/sxhkdrc:
Print
    scrot ~/dat/scrot/%Y-%m-%d-%T.png

Redshift

  • redshift - adjust color temperature of your screen (make it warmer in the evening)
  • redshift-gtk - displays tray icon to toggle color temperature off and on, useful when doing color sensitive work

Configure in ~/.config/redshift/redshift.conf:

[redshift]
temp-day=5700
temp-night=3500
fade=0
dawn-time=7:00-8:30
dusk-time=19:30-21:00
adjustment-method=randr

Run in ~/.xinitrc:

redshift-gtk &

Notifications

Dunst

  • dunst - highly configurable and lightweight notification daemon

configuration in ~/.config/dunst/dunstrc

usage:

dunstify -u critical -h string:x-dunst-stack-tag:notification-tag -h int:value:10 message
  • -u: urgency (low, normal, critical)
  • -h: hint of type string, int, double, byte or variant
  • hint notification-tag: this notification will replace another of the same tag
  • hint value: will visualize the value in progress bar

Herbe

  • herbe - daemon-less notifications without D-Bus, minimal and lightweight
  • monitor patch - display notifications on your selected position on primary monitor (otherwise whole screen will be used)
  • xresources patch - load settings from ~/.Xresources (otherwise you need to edit them in source code)
  • all patches

Patching

Clone the void-packages git repository and install the bootstrap packages:

$ git clone https://github.com/void-linux/void-packages.git
$ cd void-packages/
$ ./xbps-src binary-bootstrap

Add the patches:

$ mkdir srcpkgs/herbe/patches
$ wget -O srcpkgs/herbe/patches/xresources.diff https://patch-diff.githubusercontent.com/raw/dudik/herbe/pull/11.diff
$ wget -O srcpkgs/herbe/patches/monitor.diff https://patch-diff.githubusercontent.com/raw/dudik/herbe/pull/21.diff

Build and install the herbe package:

$ ./xbps-src pkg herbe
$ sudo xbps-install --repository hostdir/binpkgs herbe

Settings

~/.Xresources:

herbe.background_color: #111111
herbe.border_color: #555555
herbe.font_color: #aaaaaa
herbe.font_pattern: Terminus:size=8
herbe.line_spacing: 2
herbe.padding: 5
herbe.width: 200
herbe.border_size: 1
herbe.pos_x: 1
herbe.pos_y: 1
!corners: 0 = TOP_LEFT, 1 = TOP_RIGHT, 2 = BOTTOM_LEFT, 3 = BOTTOM_RIGHT
herbe.corner: 3
herbe.duration: 5

After saving the file, load it and test herbe:

$ xrdb ~/.Xresources 
$ herbe "test"

Using

Herbe runs in the foreground for the duration of displaying the notification and then exits. If you use it for action that generates several notifications in quick succession and only the last one is relevant (like changing the volume), terminate the earlier ones, so only the last remains:

pkill -SIGUSR1 herbe; herbe "Volume UP $(amixer get Master|tail -n1|sed 's/.*\[\(.*%\)\].*/\1/')"

Terminal emulator

  • rxvt-unicode - terminal emulator supporting Xft fonts and Unicode

Settings in ~/.Xresources:

URxvt.font:xft:Firacode:size=10
!URxvt.font: xft:terminus:size=12
!URxvt.boldFont: xft:terminus:size=12,style=medium
URxvt.letterSpace: 0
URxvt.lineSpace: 0
URxvt.imLocale: cs_CZ.UTF-8
URxvt.urgentOnBell: true
URxvt.cursorBlink: 1
URxvt.clipboard.autocopy: true
URxvt*termName:rxvt-unicode
URxvt.perl-ext-common: default,matcher,remote-clipboard
URxvt.url-launcher: /usr/bin/firefox
URxvt.matcher.button: 1
URxvt.matcher.pattern.1:   \\bwww\\.[\\w-]+\\.[\\w./?&@#-]*[\\w/-]
URxvt.scrollStyle:xterm
URxvt.scrollTtyKeypress:true
URxvt.jumpScroll:false
URxvt.scrollBar: false
URxvt.scrollTtyOutput: false
URxvt.scrollWithBuffer: true
URxvt.scrollstyle: plain
URxvt.saveLines: 100000
URxvt.background:   #000

There is a bug/feature that makes the prompt appear several empty lines bellow the top of the terminal. There are several workarounds, but none of them were worth it for me.

If in shell on remote host pressing arrows does not move the cursor/browse history or work as expected, but instead adds more text to current line, check what your $TERM variable contains.

$ echo $TERM
rxvt-unicode-256color

If it is something uncommon, maybe the host does not have it in /usr/share/terminfo/ and thus does not know its capabilities. Set it to something more common in ~/.Xresources, like:

URxvt*termName:rxvt-256color

Notice the *. Using URxvt.termName did not work for me.

File manager

  • ranger - console file manager with VI key bindings
  • spacefm - customizable Multi-panel tabbed file manager

Ranger setup

Copy configuration files to ~/.config/ranger:

ranger --copy-config=all

Set a variable in ~/.profile to tell ranger not to load global configuration :

export RANGER_LOAD_DEFAULT_RC=FALSE

Archives

To preview and extract archives in ranger, you need:

  • atool - script for managing file archives of various types

Depending on the type you want to extract:

You probably already have:

Preview images

Ranger supports several methods of previewing images:

From the methods I tried (which was urxvt and w3mimgdisplay), ueberzug works by far the best for me.
Install the thing and set it to be used in ~/.config/ranger/rc.conf:

# Use one of the supported image preview protocols
set preview_images true
# Set the preview image method
set preview_images_method ueberzug

Preview video

Install ffmpegthumbnailer

uncomment in ~/.config/ranger/scope.sh these lines:

video/*)
    # Thumbnail
    ffmpegthumbnailer -i "${FILE_PATH}" -o "${IMAGE_CACHE_PATH}" -s 0 && exit 6
    exit 1;;

Make sure ~/.config/ranger/rc.conf contains:

# Use the external preview script or display simple plain text or image previews?
set use_preview_script true

Preview PDF

Install mutool, it is in package mupdf-tools

Syntax highlighting in text previews

Install highlight

Preview EXIF information of media

Install exiftool

Launching

Rifle tries to guess in which application you want to open a file.
Edit ~/.config/ranger/rifle.conf, if your preferred applications are not used, put them higher in the file; if they are missing, add them.
For example:

mime ^image, has nsxiv-ranger.sh,   X, flag f = nsxiv-ranger.sh -- "$@"
ext ora,                            X, flag f = mypaint -- "$@"

Desktop background

Feh

  • feh - a lightweight, configurable and versatile image viewer. Can compile text and thumbnail listings, show (un)loadable files, set X11 backgrounds, and more Run:
feh --bg-center /path/to/image.png

which will create a file ~/.fehbg that you can use in ~/.xinitrc:

~/.fehbg &

Pscircle

  • pscircle - visualize running processes in a radial tree and set them as desktop wallpaper (print to X11 root window)

I run in ~/.xinitrc a script pscirclecustom.sh that launches pscircle with my custom options:

pscirclecustom.sh &

But to refresh the background with currently running processes, it needs to be run again. You can do this by:

  1. pscircle options:
pscircle --daemonize=true --loop-delay=3600
  1. supertinycron:
supertinycron '@hourly' pscirclecustom.sh;
  1. cron:
$ crontab -e
0 * * * *  pscirclecustom.sh

You can also pipe processes to pscircle:

ps -N --ppid 2 -p 2 -o pid,ppid,pcpu,rss,comm --no-headers | pscircle --stdin=1