Workspace menu in i3
I really love the i3 window manager, my only compliant was about the standard workspace handling.
Before
By default you can use at most 10 workspaces binding each of them to a number, optionally you can give them a name.
With a basic configuration you have something like:
1:web 2:mail ...
Pressing Mod+1
you go to web
and pressing Mod+Shift+1
you move a container
to it.
Tools
Luckily i3 is very customizable, through its configuration file, the i3-msg
command and various external programs, in this case we are going to use the
mighty dmenu.
i3-msg
The i3-msg command permits to do useful stuffs like:
i3-msg workspace my_workspace
to change workspace, and the self-explanatory:
i3-msg move container to workspace my_workspace
[Note: if we pass a not existing workspace a new one will be created]
We also need:
i3-msg -t get_workspaces
that prints information about workspaces in json form.
dmenu
You probably know it as something magical called by the dmenu_run
script, the
one that permits you to run any program just pressing Mod+d
.
dmenu
itself does something really simple:
- take a list of options (new-line separated) from the standard input
- display them allowing the user to chose one
- print the user choice on standard output
[Note: if we digit something that is not a given option it will be printed as it is]
(So dmenu_run
is something like: print all the commands in user $PATH |
dmenu | exec stuff from sdtin
)
Put pieces together
So, what we want is define two bindings, one does:
list workspaces | dmenu | go to that workspace
and the other:
list workspaces | dmenu | move container to that workspace
Layer of abstraction
To avoid a messy configuration files Always, in life, you need to
hide complexity, it can be done for example creating some bash scripts to wrap commands.
I keep mine in a bin
folder in my home (many of them are generated by
a python script, the same that generates
the i3 configuration files, but I’m not writing about that), and I added
~/bin
to $PATH
.
menu
dmenu
takes a lot of arguments, about position, font, color, prompt and so on…
Let’s create a menu
command that takes only the prompt character:
#!/bin/bash
dmenu -b -p "$1" -fn Monaco-9 \
-nb "#000000" -nf "#999999" \
-sb "#000000" -sf "#4984bb"
lsws
Now we need a lsws
command to list workspaces, i3-msg -t get_workspaces
prints
a json with many informations, like screen, focus and position, but we want just
names.
My roommate suggested me tu use jq, but I have already here a cryptic implementation in the good old “pure” bash:
#!/bin/bash
i3-msg -t get_workspaces | tr ',' '\n' | grep "name" | cut -d '"' -f 4
Finally, write the conf
Now you can put this lines in your config file:
bindsym $mod+space exec i3-msg workspace $(lsws | menu "→")
bindsym $mod+Shift+space exec i3-msg move container to workspace \
$(lsws | menu "|→")
reload and press:
Mod+space
to go to an existing workspace or create a new oneMod+shift+space
to move a container (eventually creating a new workspace)
Conclusion
I wrote this configuration one night, in less than half hour, just before starting to sleep and without being sure of what I was doing.
I needed some some days to be used to the different workflow, especially the
longer fingers movements to switch focus (from coding
to mail
, than to
music
and than back to coding
).
Before I was used to keep Mod
pressed and than hit random numbers, until the
apparition of the right workspace, now I have to slow down and think of
which keys compose the name of the place where I want to go.