Window managers -5- 2bwm

So… you want a lighter-than-air window manager, something that takes the least possible amount of system resources. You want no frills but still enough ease to get your stuff done.

Well, look no further: here is 2bwm, floating/stacking window manager that packs all of the above into a tiny space. This WM is named after one of its most notable feature: the double borders of windows, that act as indicators for windows’ status (more on this in the following sections). Being a minimal, power user-oriented WM, all window operations can be primarily executed by keyboard shortcuts; mouse actions such as resize and move are of course possible but are intended to be “alternative” to keybinds.

Such a “niche” window manager requires a little effort to set up the environment, as you might expect. And by “niche” I mean… uh… there are probably five people using it (don’t count me, I am just taking a ride…). Nevertheless, 2bwm is a nice and feature-rich piece of software that might be worth trying. If you’re reading this post it’s because I have come across one of those brave users, b4d_tR1p, and extorted him most of the technical stuff you’ll read. I have striven to install & set up the whole contraption, while he has provided hints based on his daily usage. Thanks man!


I am using a clean Debian testing netinstall as a base (current stable: Jessie), so “YMMV” (not so much, actually) if you’re using something different. Installing 2bwm is of course not a “apt-get” job or the like: head to venam’s Github page, clone the WM repository and finally compile from source (don’t worry, that’s only ~100 kB of code). Size aside, compiling is not as difficult as it seems, I already tried and succeded.

Cloning git repository
Cloning git repository – orange emphasis is mine!

Lucky, lazy Archers can pull the 2bwm or 2bwm-git packages from AUR.

Thanks for the quote, Al!

However, the README on the Github page covers the installation on several distributions. The master branch will fit Linux and *BSD brave users, the devel one is of course for the braver among the braves.

There’s also a 3bwm branch (3, not 2!) that takes a different twist on the borders appearance, enabling transparency on one of the two; 3bwm is not covered here.

Now you’ll have to pull the dependencies onto your system. But… hold your keyboards! Before you make && sudo make install take a look at Makefile, config.h and even definitions.h files, because that’s currently the only way to customize the WM.

Configuration via plain text file is in the works, now in the devel branch. It should also be noted that I can’t code a single line in C but, you know…

First file to look into is the Makefile:

CFLAGS+=-std=c99 -Os -s -I${X11_INCLUDE} \
LDFLAGS+=-L${PREFIX}/${LIB_SUFFIX} -lxcb -lxcb-randr -lxcb-keysyms \
-lxcb-icccm -lxcb-ewmh

Most notably support for Compton compositor can be enabled (replace -DNCOMPTON with -DCOMPTON, see note in config.h file). Also, the LDFLAGS line list the dependencies you’ll have to get. For Debian (here is where your mileage may vary) install:

libxcb-randr0-dev libxcb-ewmh-dev libxcb-icccm4-dev libxcb-keysyms1-dev

I have chosen to give 2bwm a first try in its default configuration (except for the Compton option) and dive into its customization later, to highlight variations. So, now you can make && sudo make install if you wish, for a first look.


The default desktop is absolutely empty, since 2bwm comes with no panel, icons or right-click menus. I have just set a decent wallpaper (all hail hsetroot) and fired up a terminal to collect system’s basic information. To keep the graphical session running at least one active application is required, otherwise X will terminate and bring you back to the command line. A terminal window is enough, even though a panel (I’ve added tint2 to keep things easy) is a better choice because it cannot be accidentally closed.

On a fresh startup 2bwm takes only 1.7MB RAM, the whole system sums up to 80MB RAM usage, including (you do the maths…):

  • some Virtualbox stuff (that wouldn’t run on a physical machine) – 1.5MB
  • lxterminal – 20MB
  • tint2 panel – 11MB
  • volumeicon – 15MB

Also, there’s no DM (lightdm or anything else) running; an interesting comparison on the Github page shows that 2bwm ranks 2nd in resource usage among several light window managers: the first one is mcwm, from which 2bwm is derived. Also mcwm was born as a “personal” window manager, because you just can’t pick a light WM from the bunch and use it: you write your own from scratch, of course!

Default desktop – sort of…

Use .xinitrc file to adjust your session startup. Here is the simple one I am using for my test:

xsetroot -cursor_name left_ptr &
hsetroot -tile ~/Immagini/wallpaper.jpg &
tint2 &
compton -CGb -o 0.7 -m 0.95 -i 0.85 --no-fading-openclose &
volumeicon &
exec /usr/local/bin/2bwm

I am setting the pointer and the wallpaper, starting some nice stuff and, lastly, the window manager: pretty standard usage. The look & feel is driven by .gtkrc-2.0 file.


Default colour scheme

At last, let’s start breaking things! As far as I could see (and understand) all the code is well commented: that helped a lot! I am providing below the explanations of the few changes I made to show the effect on the WM behaviour and appearance.

So, first stop is config.h where we can set border colours and thickness, keybindings and… pretty much anything because it is intended for this very purpose. I am showing the original line commented out (within “/* ... DEFAULT VALUES */“) along with the modified line.

Let’s start with the borders and their colour scheme:

  • inner border: colours (0) or (1) respectively if windows are in or out of focus;
  • fixed windows border: colour (2),  (the sticky i.e. visible on all desktops), this colour will override colour (5) when the window attribute is set;
  • unkillable windows border: colour (3), windows cannot be closed when attribute is set, overrides colour (5) when set;
  • fixed + unkillable windows border: colour (4), a combination of the two attributes above, overrides colour (5) when set;
  • outer border: colour (5), inner and outer border colours can be inverted (you’ve read into config.h, didn’t you?);
  • empty colour: colour (6), fills space when window content doesn’t follow frame resize;
Border colours for different window statuses

I didn’t like the default colours, so these were the right target to start customization, using the Base16 colour palette (Base16 colours by Chris Kempson) that is also on my home Linux box. Open config.h with your favourite editor and look for the “Colors” section:

/*0)focuscol 1)unfocuscol
*2)fixedcol 3)unkilcol
*4)fixedunkilcol 5)outerbordercol
*6)emptycol */
/* static const char *colors[] = {"#35586c","#333333","#7a8c5c","#ff6666","#cc9933","#0d131a","#000000"}; DEFAULT VALUES */
static const char *colors[] = {"#a1b56c","#7cafc2","#7a8c5c","#dc9656","#ab4642","#ba8baf","#181818"};

And you’re done, for a gorgeous new palette.

Customized colour scheme

Next step, change borders width. The first two values are the most important (defaults are {3,5,5,4}): 5 (the second value) is the total width in pixels of window border, while 3 (the first value) is the outer border size. That means that you’ll have 5 – 3 = 2 px width of inner border, used for window status (fixed, unkillable, fixed + unkillable). I exaggerated a little the replacement values to make changes more evident:

/* static const uint8_t borders[] = {3,5,5,4}; DEFAULT VALUES */
static const uint8_t borders[] = {5,8,5,8};

Next change were the offsets from screen borders: here I’ve just set a 30px offset from lower edge to make maximized windows (unless they are made full screen) not cover the panel. Change the values as shown below

/*static const uint8_t offsets[] = {0,0,0,0}; DEFAULT VALUES */
static const uint8_t offsets[] = {0,0,0,30};

the latter value being consistent with tint2 height as set in its tint2rc file: adjust to your needs and liking and don’t forget to experiment a little bit!

Here is the result on overall appearance:

Desktop – custom colours & borders width

Let’s move to keybinds, a vital part of such a keyboard-oriented WM, that cover window actions mainly and an handful of shortcuts for programs. I chose not to change the keybinds for window actions, since (you’ll notice) they are carefully “grouped” to be executed in different parts of your keyboard. Resize and move actions are bound “vim-style” to h, j, k and l keys, teleporting actions to y, u, g, b and n (in the center of keyboard). Windows movement and resizing is also accomplished with Super + left/right click and drag, respectively.

In the examples below, I replaced the default terminal and added another entry to start the filemanager. In the first case just change the executable within the line:

/*static const char *terminal[] = { "urxvtc", NULL }; DEFAULT VALUES */
static const char *terminal[]  = { "lxterminal", NULL };

To add a new entry, first add a constant name and value, i.e. the command line you want to run, in the “///--Menus and Programs---///” section (you’d better keep the code clean!):

static const char *fileman[]     = { "/usr/bin/pcmanfm",NULL};

Here I defined the constant name “fileman” that will start my file manager of choice. Then, within the proper section, define the keybind (for example Super + F1) and refer to the constant name defined before:

static key keys[] = {
    {  MOD ,              XK_F1,          start,             {.com = fileman}},

You might want to use an external tool to manage such keybinds and change them on the fly: I found the oldie-but-goldie keylaunch from the Debian repositories as an example, although a better choice might be sxhkd, from the Github repo of the bspwm author, or anything else you prefer!

Another little, easy tweak I was able to make affected the number of workspaces, as you might have noticed in one of the previous screenshots. The default value (10), however, is in definitions.h file:

#define WORKSPACES 5

I changed the value to 5 because those are usually enough for my typical session. Again, choose what just fits your needs.

Interesting features

Borders aside, shortcuts for “teleporting” and placement of windows are the key features of 2bwm. The GIF on its Github page provides a nice overview of all available actions.


While maximizing vertically or horizontally is a common feature for all stacking WMs, exact placement of windows on the screen (in the corners, centered on x/y axis, etc.) is something more rarely seen and definitely helpful to quickly and neatly arrange flocks of floating windows. Some related code snippets from config.h:

// Teleport the window to an area of the screen.
/* Center: */
{ MOD , XK_g, teleport, {.i=TWOBWM_TELEPORT_CENTER}},
/* Center y: */
/* Center x: */

Moreover, even windows size is accurately controlled by specific functions (see excerpt from the README):

  • Multiply / Divide window’s width or height by 2
  • Grow / Shrink windows keeping aspect ratio
  • Move / Resize windows by two user defined amount

A very smart feature, also rarely seen elsewhere, prevents windows to be moved out of the screen, even partially. That might be very useful, for instance, if you switch between bigger and smaller screens using a laptop or if a program misplaces its own windows, disregarding your screen’s resolution.

Dual monitor setup

Finally, speaking about monitors, there are of course shortcuts to move windows on all active screens. I have set up a dual monitor configuration to test such features, casting a little xrandr spell. Each workspace spans across all available screens, i.e. a workspace cannot be assigned to a specific output (a feature available – and much appreciated – in i3wm, for example).

It’s worth noting that shortcuts to move windows across screens involve using the mouse, as an alternative to “,” and “.” keys for the same action:

{  MOD|ALT,    XCB_BUTTON_INDEX_1,     changescreen,    {.i=1}},
{  MOD|ALT,    XCB_BUTTON_INDEX_3,     changescreen,    {.i=0}}


What I like: of course all the “teleporting” features. I switched to a tiling WM mainly because I was sick of moving windows around the screen, so any assistance for such a boring task is welcome. Other floating WMs/DEs, XFCE for example, allow some “smart placements” of windows (top/bottom half screen, sides) but none of them has the same flexibility and complete set of features. I am not going back to a floating WM, however…

The double borders are also a clever trick that is both aesthetically pleasing and informative, lacking the (useless!) window title bars.

What I do not like: current focus policy “focus follows mouse” (window under mouse pointer takes focus, “sloppy focus“), although consistent with the reduced usage of mouse permitted by the several available shortcuts. It might be annoying to lose focus by accidentally moving the pointer away from the window we are looking at: an option to change that would be nice, although the developer has decided not even to implement the “click to focus” policy. Same for the simpler “click to raise window” behaviour instead of “Super + click to raise window” one: I couldn’t find (despite support from more C-aware fellows!) a way to change that.

These are both minor annoyances, anyway, that would probably be quickly forgotten once you learn the shortcuts (it’s a steep way to the top, sometimes!) and get used to them.

Summing up: For sure 2bwm looks promising: fast, lightweight, designed with a clear “mission” in mind. Like many so-called “minimal” WMs out there in the Linux world, it is targeted to intermediate/advanced users who are willing not to stick with “conventional” graphical environments. Lots of tinkering, adjustments and manual settings will be required on the system in order to make it work and look the way one wants. There are still some interesting options in config.h I did not change and more could be done if only I had some knowledge of coding! This is also, though, an indication that it’s not that hard to modify well-written and thoroughly commented code!

The plain text config file feature, once implemented, might ease adoption of 2bwm. On the other hand, the same “pro” users who are likely to choose it are also likely to be focused on productivity rather than desktop customization. Those users, therefore, will settle on a convenient configuration after few trials and stay with that, forgetting about recompilation. Well, unless there are updates…

On the hardware side, the extremely low resource request makes 2bwm suitable even for low power hardware, be it an old PC found in the basement or a Raspberry Pi and the like.

I’ll keep an eye on this project to see how it grows, although even now it is usable and pretty stable, as far as I could judge in my short tests. Hat off to Venam for his skills and taste!


1 Comment

Ora tocca a te / Your turn now

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:


Stai commentando usando il tuo account Chiudi sessione /  Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...

This site uses Akismet to reduce spam. Learn how your comment data is processed.