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_workspaceto 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_workspacesthat 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 workspaceand the other:
list workspaces | dmenu | move container to that workspaceLayer 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 4Finally, 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+spaceto go to an existing workspace or create a new oneMod+shift+spaceto 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.