kwm
macOS’s default window manager leaves much to be
desired. kwm
is a highly configurable
tiling window manager. This is a beginner’s guide to installing and configuring
kwm
and khd
, which provides a keybinding interface.
Architecture
kwm
runs a daemon (i.e. background process) that detects windows and performs
actions on them. Actions include things such as focusing, moving, resizing, and
swapping. Since it is continuously running, kwm
maintains an internal
representation of your window positioning based off a set of rules.
This differs from other styles of window management, in that if you manually
modify a window (e.g. by dragging a corner or side), kwm
will resist your
change and resize it to what it thinks is its correct position. In most cases,
kwm
will tile the windows on each workspace to fill the screen.
Another thing that kwm
does differently is keybindings. Unlike other macOS
window managers, it doesn’t come with a set of keybindings. kwm
reads from a
set of rules and tiles windows automatically. You do not have to tell it to
split a screen between two windows, or maximize a certain window. It just goes
ahead and does it on its own.
Once the workspace is managed, however, you would probably like to perform
actions such as moving focus, swapping windows, and switching spaces. That is
the purpose of khd
. Like kwm
, khd
is also a daemon, but instead of working
with windows, it manages keybindings and communicates with kwm
.
Installing kwm
Though kwm
used to have a more involved installation process, the authors have
now provided Homebrew port which greatly simplifies the process.
$ brew install koekeishiya/kwm/kwm
Note that kwm
requires ‘Displays have separate spaces’ enabled.
To activate the daemon, and have it run automatically at login,
$ brew services start kwm
Note that sudo
should not be necessary. After kwm
starts up, your workspace
should be tiled automatically. A restart may be necessary in some cases.
kwm
configuration
To get started, copy the example configuration into your home directory. You can
see where the example file is located by running brew info kwm
.
$ brew info kwm
...
Copy the example config from /usr/local/Cellar/kwm/4.0.2/kwmrc into your home directory.
mkdir -p ~/.kwm
cp /usr/local/Cellar/kwm/4.0.2/kwmrc ~/.kwm/kwmrc
Open the kwmrc
file and take a look. Each configuration begins with the kwmc
prefix followed by a number of arguments. A detailed description of every
possible option can be found on
the wiki.
I’ve found that the defaults are generally pretty sane. Out of personal
preference, I’ve chosen to disable focus-follows-mouse
and blacklisted a few
applications that I did not want to be tiled (e.g. Photoshop, Archive Utility,
Finder, and System Preferences). Additionally, I’ve set the default focus color
to transparent (0x00000000
), which I’ll describe soon. Note that the colors
are in 0xAARRBBGG
format.
Adding keybindings
To add keybindings to kwm
operations, you’ll need to install and configure
khd
.
$ brew install koekeishiya/khd/khd
$ brew services start khd
Similar to kwm
, we use brew services
to manage the khd
daemon. I needed
to restart until khd
was working, but your results may vary. One way to check
if the desired processes are running is to run
$ ps -ax | grep khd
45031 ?? 0:01.23 /usr/local/Cellar/khd/1.1.0/bin/khd
...
If khd
is up, you should see an executable in /usr/local/Cellar/khd
show up.
Introduction to modal keybindings
khd
is a modal-hotkey daemon. Modal means that at any time, you may be in any
one of several modes, and the actions of each keybinding is dependent on the
current mode. If you use vim
, you may already be familiar with modal
keybindings. Otherwise, the concept may be fairly new.
First, we’ll lay out the general idea of what we want our keybindings to
accomplish, then we’ll walk through how to implement our system in khd
.
Our ‘modes’
We will begin with three modes: default, switcher, and swap.
default
The default
mode is meant to be the resting state of our system. In default
mode, pressing keys shouldn’t interfere with the applications we’re using. If
you are a vim
user, we are aiming for something akin to normal mode (no
editing capability).
default
mode should have a single keybinding to enter a different mode with
more functionality. We’ll call it switcher
.
switcher
We’ll use switcher
mode to do a lot of things. First, we want to be able to
switch focus between windows. We’ll also switch focus between spaces
(i.e. virtual desktops) and throw windows from one space to another. At the end,
we’ll add a few extra functionalities such as opening new terminal windows.
Finally, from switcher
mode, we will have the option to enter swap
mode.
swap
In swap
mode, we can make ‘edits’ to our window layout by swapping the
positions of windows and rotating the entire workspace. This is like vim
’s
insert mode.
Define our modes
So, inside of a file named .khdrc
, which should be located in your home
directory, we first define our three modes, and assign them colors. The colors
will be displayed by the border around focused windows.
Choose a prefix key
To switch from default into our other modes, we’ll need a prefix. Ideally, a
prefix should be quick to type. I’ve remapped the caps key to trigger
f19, which I’ll be using as my prefix. This can be done easily using
Karabiner Elements which is
available for macOS Sierra (f19 is keycode 80
, or 0x50
).
Define mode switching
Now, we’ll define a way to switch between modes. There is a lot of freedom in how to do this, so definitely use what you feel is the most natural.
Starting from default
mode, we will switch into switcher
mode by hitting
the prefix key (keycode 0x50
in my case).
In switcher
mode, we will define a single press of s
to get us to swap
mode.
Finally, if we are either in swap
or switcher
, a single press of the prefix
should take us back to default
. To make this work, the configuration looks
like
We can see that the syntax of a keybind is <keysym> : <command>
where
<keysym>
is composed of the mode name, followed by a -
, and then a literal
(s
), or a keycode (0x50
).
To test out our mode configuration, we need to reload .khdrc
. The easiest
way to do this is
$ brew services restart khd
So we can walk through how this configuration captures the behavior we desire.
Assuming we start in default
mode, a single press of caps (which
triggers 0x50
) brings us to switcher
mode. If we want to leave, another
press of caps takes us back to default
mode (this logic is captured
on the second line).
In switcher
mode, pressing s gets us to swap
mode (line 4). In
swap
mode, pressing caps gets us back to default
mode (line 3).
switcher
functionality
Now, we are ready to actually add some functional keybindings. The commands
triggered by these keybindings are all prefixed with kwmc
, which is a program
that can interact with kwm
, the actual window manager. You can type these
commands individually into a terminal, and observe the expected behavior.
So in switcher
mode, pressing h will switch focus to the left
neighbor of the current window. Pressing 3 switches to the third
space, and shift + left throws the currently focused
window left one space.
swap
functionality
In swap
mode, pressing h swaps the currently focused window with
its neighbor to the left. Pressing r performs a rotation of all
windows on the workspace. The name of the command, tree rotate
comes from the
way kwm
represents window tilings internally–as a binary-space-paritioning
tree.
New Finder/iTerm windows
A common action that you may want to perform is opening a new Finder or iTerm window. First, consider the following two scripts:
We can bind these scripts to quick keybindings in switcher
mode using
Hyper key (untested)
As of the writing of this article, the typical way of using the caps key to trigger cmd + alt + ctrl + shift is not yet possible because Seil and Karabiner are not released for macOS Sierra.
As mentioned
before, Karabiner Elements can
still be used on macOS Sierra to rebind caps to f19. Then,
the following configuration in .khdrc
may be a possible way to trigger our
hyper key
which uses khd -p
to simulate our desired keypress. Note that I have not yet
tested this method, but it seems plausible.
Wrap up
Hopefully this article was a helpful introduction to the world of macOS window
managers. Using a window manager may not be for everyone, but the ones who do
rarely look back. My full configuration of kwm
can be found in my
dotfiles.
kwm
is just one of many solutions, and I encourage you to find whatever system
works for you. It still has a few kinks (such as occaisional window
oscillations) but mostly feels stable. It’s greatest strength, configuration,
may be its greatest weakness, especially for users who don’t need or don’t
want the level of customization it provides.
But for the right person, kwm
is a refreshing blend of functionality,
configurability, power, and elegance.