Minimal but functional unix desktop with sowm

05 Dec 2019


I've been an i3wm user for a long time now. But everyonce in a while I get annoyed with writing floating rules for programs that look far-fetched in tiling mode.

Like many others, my first fore into plain window manager desktops was with openbox and crunchbang. So I decided to go back to openbox. And I was happy... for a while. The menus and configuring openbox without obconf is a nightmare. Then one fine day, while scrolling through r/unixporn, I saw a post from Dylan Araps, of neofetch fame. It turns out he made a bare-bones floating window manager called sowm and has even started a minimal linux distro called KISS. sowm, like dwm is configured at compile-time and the defaults make sense. Knowing Dylan and the quality of work he does, I had to give this a try!

This post is my personal sowm setup running on top of voidlinux. But the same can be done on any distro.

My workflow

Installing

To build sowm or any wm, we'll need the x11 dev libraries(just xlib for sowm). Do an # xbps-install libX11-devel to have those installed in our machine. It goes without saying that gcc and make should also be present.

$ git clone https://github.com/dylanaraps/sowm
$ cd sowm

All my personal programs are in $HOME/bin. Having the following line in $HOME/.profile

[ -d $HOME/bin ] && export PATH="${HOME}/bin:${PATH}"

will add the programs/scripts in that bin folder to my $PATH. So when I install sowm, I need it to go here. Open up the Makefile and change the PREFIX and BINDIR variables.

PREFIX?= /home/username
BINDIR?= $(PREFIX)/bin

To install, run

$ make
$ make install

This will build the sowm binary and put it in $HOME/bin.

Making changes to sowm

There is a config.h file in the clonned folder. If not, make one by copying over the config.def.h file. This file holds the keybinds, sowm uses.

There are keybinds for starting a terminal, changing brightness and some others. But, I'd like to use a separate program for controlling the keybindings called sxhkd. Voidlinux has it in the default repos. So my config.h looks like

#ifndef CONFIG_H
#define CONFIG_H

#define MOD Mod4Mask

const char* menu[]    = {"wm_run",     0};
const char* term[]    = {"xst",        0};

static struct key keys[] = {
    {MOD,      XK_q,   win_kill,   {0}},
    {MOD,      XK_c,   win_center, {0}},
    {MOD,      XK_f,   win_fs,     {0}},
    {Mod1Mask, XK_Tab, win_next,   {0}},

    {MOD, XK_Return, run, {.com = term}},
    {MOD, XK_d,      run, {.com = menu}},

    {MOD,           XK_1, ws_go,     {.i = 1}},
    {MOD|ShiftMask, XK_1, win_to_ws, {.i = 1}},
    {MOD,           XK_2, ws_go,     {.i = 2}},
    {MOD|ShiftMask, XK_2, win_to_ws, {.i = 2}},
    {MOD,           XK_3, ws_go,     {.i = 3}},
    {MOD|ShiftMask, XK_3, win_to_ws, {.i = 3}},
    {MOD,           XK_4, ws_go,     {.i = 4}},
    {MOD|ShiftMask, XK_4, win_to_ws, {.i = 4}},
    {MOD,           XK_5, ws_go,     {.i = 5}},
    {MOD|ShiftMask, XK_5, win_to_ws, {.i = 5}},
    {MOD,           XK_6, ws_go,     {.i = 6}},
    {MOD|ShiftMask, XK_6, win_to_ws, {.i = 6}},
};

#endif

xst is my terminal and wm_run is simply a wrapper script around dmenu_run. Here's the content of $HOME/bin/wm_run

#!/bin/sh

dmenu_run \
  -p "Run:" -l 10 -fn "Monospace:size=10"

So sowm manages,

Rebuild the binary with,

$ make clean
$ make
$ make install

Starting sowm

I run my X session with startx. So to start sowm, I put it in my $HOME/.xinitrc. Here's a simple .xinitrc file, that I use.

#!/bin/sh

# kill wm session with Ctrl + Alt + Backspace
setxkbmap -option terminate:ctrl_alt_bksp

xrdb -merge $HOME/.Xresources
xset b off
xset r rate 250 25
xsetroot -cursor_name left_ptr

# startup programs, the & means background it
dunst & # notification daemon
sxhkd & # keyboard shortcut daemon
xautolock -time 10 -locker "slock" & 

# start sowm
exec ck-launch-session dbus-launch sowm
# I have pulseaudio installed and dbus is a strict dependency!
# you can replace the above line with just
# exec sowm 

Another way people run X sessions is via a Display Manager like lightdm. In that case, our .xinitrc is pointless. Special thanks to koutsie and Leon-Plicat, for the info. Discussion can be found here. If you use a login manager, then use the following method and not .xinitrc.

Start by making a executable start_sowm.sh in your $HOME/bin. It's an exact copy of our .xinitrc

#!/bin/sh

# kill wm session with Ctrl + Alt + Backspace
setxkbmap -option terminate:ctrl_alt_bksp

xrdb -merge /home/youruser/.Xresources
xset b off
xset r rate 250 25
xsetroot -cursor_name left_ptr

# startup programs, the & means background it
dunst & # notification daemon
sxhkd & # keyboard shortcut daemon
xautolock -time 10 -locker "slock" & 

# start sowm
exec /home/youruser/bin/sowm 

Next make a /usr/share/xsessions/sowm.desktop file. The content is

[Desktop Entry]
Name=sowm
Exec=/home/youruser/bin/start_sowm.sh
Comment=Bootstrap script for sowm
Type=Application

Logout and you should see an entry for sowm.

Launching apps

wm_run will be invoked via Mod4 + d. We can launch apps via that menu. But, having a few nifty keybinds that launch handy tools and operations is a plus. And thats where sxhkd comes in.

Here's my $HOME/.config/sxhkd/sxhkdrc file.

# programs I use
super + shift + e
  code-oss
super + shift + f
  thunar
super + shift + w
  firefox

# a bar replacement ?
super + s
  wm_notify_pop

# lock screen
super + x
  slock

# exit menu
super + shift + x
  wm_session_exit

# make sxhkd reload its configuration files
super + shift + Escape
  pkill -USR1 -x sxhkd; \
  notify-send "reloaded sxhkd"

XF86AudioMute
  pactl set-sink-mute 0 toggle
XF86AudioRaiseVolume
  pactl set-sink-volume 0 +5%
XF86AudioLowerVolume
  pactl set-sink-volume 0 -5%
XF86AudioMicMute
  pactl set-source-mute 1 toggle
XF86MonBrightnessUp
      xbacklight +10
XF86MonBrightnessDown
      xbacklight -10

The config file is in plain english!. The programs starting with wm_* are custom scripts in $HOME/bin, the others are installable via our distro's package manager.

wm_notify_pop is a pop-up replacement for a bar. Technically I'm cheating by using a notification, but it works. Here it is, in all its glory.

#!/bin/sh

BAT="BAT0"
STATUS=$(cat /sys/class/power_supply/$BAT/status)
PERCENT=$(cat /sys/class/power_supply/$BAT/capacity)%
BAT_STATUS=$(echo $STATUS $PERCENT)

DATE=$(date +"%a %b %e %H:%M")

# putting it all together
notify-send "$BAT_STATUS  |  $DATE"

Here's the wm_session_exit, an another wrapper around dmenu

#!/bin/bash

DMENU='dmenu -i -fn Monospace:size=10 -p > '
choice=$(echo -e "poweroff\nreboot" | $DMENU)

case "$choice" in
  poweroff) sudo poweroff;;
  reboot) sudo reboot;;
esac

For the above script to work, I have an entry for my $USER in the sudoers file. Invoke $ sudo visudo and put the following at the end.

username ALL=NOPASSWD: /bin/poweroff, /bin/reboot

Fin

With this, we should have a minimal but functional sowm powered desktop session. Just as a summary, here is the list of keybinds

and the mouse controls are,

As a bonus, here's a not so exciting screenshot of the fruits of our labor.

screenshot of sowm

Note: sowm is still actively being worked on. So keep track of its github issues. If you run into any problems, raise an issue there or feel free to email me.

I hope you'd give this workflow and sowm a try.

Happy hacking and have a great day!