Skip to main content

i3wm scratchpad with terminator and screen

I use i3wm, of course without any stupid gaps, and I find it annoying to have more than a few active workspaces open at the same time but I want be able to quickly access some of my more frequently used applications and I think it's a waste of valuable display real estate to dedicate one or more workspaces to for example an email client and a RSS reader.

I want my workspaces to be work-spaces. Containers where I at least in theory do stuff. So how do we hide windows while making them easily accessible at the same time? I3wm offers a wonderful feature for solving this exact problem; scratchpads!

Here is a cluttered screenshot as an example.

scratchpad
A scratchpad in i3 is basically a "hidden workspace" to which we can "minimize" stuff. Besides from the scratchpad in this post I've found it convenient to have the Signal desktop client in the scratchpad.

Multiple command line programs in one scratchpad window

It would be even more annoying to have every frequently used application in a separate terminal window in the scratchpad. The solution is to use a terminal multiplexer like GNU screen or Tmux. I myself prefer screen because I'm too lazy to try out tmux.

The idea

At i3 startup we want to automatically open a terminal window and send it to the scratchpad. In this hidden terminal we start a screen session and then open screen windows with some applications and it should preferably all look nice and tidy as well.

Setup

It sounds like an easy task but it actually took me some time and effort to make this work the way I wanted. It's still not 100% perfect.

I use terminator but I'm not very pleased with it since it's so slow and bulky. I prefer urxvt or even xterm but terminator is so easy to configure and its native support for URL management is a killer feature for me and that was something I never could get working properly in urxvt.

Apparently there is no way of manually setting the WM_CLASS variable for a terminator windows. This is a known bug and it looks like the --classname=SomeClassName option is now removed. But we need to set a custom VM_CLASS variable for i3 to be able to grab the terminator window and send it to the scratchpad.

So I did an ugly hack around this. We open a terminator window with a non-standard title, search for that window based on the title and manually set the class name with the help of a short bash script. It works but the downside is that i3 doesn't immediately grab the window and hide it. You will probably see a terminator window flash open and then quickly disappear. A workaround would perhaps be to do this even before i3wm is started.

Since my system is slow, it takes maybe 10 seconds for i3 to start all of my stuff and get settled so I've added a delay in my open-stuff-in-scratchpad-screen-session helper script which is executed after everything else.

The relevant entries in my ~/config/i3/config is as follows:

...
for_window [instance="scratchpad"] floating enable;
for_window [instance="scratchpad"] border pixel 2;
for_window [instance="scratchpad"] move scratchpad; [instance="scratchpad"] scratchpad show; move position 80px 50px; move scratchpad
bindsym $mod+F1 [instance="scratchpad"] scratchpad show, resize set 816 572 
...
exec --no-startup-id ~/scripts/setClass
exec --no-startup-id terminator -T havohej -p scratchpad -x screen -S scratchy -T vim -m vim -n ~/docs/vimwiki/index.wiki +Goyo122x40
...
exec --no-startup-id ~/scripts/scratchStart

Some explanation might be in necessary. For any window with VM_CLASS = 'scratchpad':

  • Make it floating with a narrow border.
  • Move it to the scratchpad.
  • Always show it at position (80,50).
  • When pressing Win+F1 show the window with size 816x572, in case it has been resized.
  • If scratchpad is visible Win+F1 will hide it.

Start the setClass script. It will start searching for the window we will start in the next step.

Open a terminator window.

  • With the weird title "havohej",
  • profile "scratchpad",
  • start a screen session with the name "scratchy" in which we start vim (with no swapfile),
  • with the title "vim" and in vim we open the index of a vimwiki.

Finally, we run the scratchStart script which opens some more programs in the screen session.

That's quite a mouthful!

setClass

The script setClass looks likes this:

#!/bin/bash

var=$(xdotool search -name havohej)

while [ -z "$var" ] # while var is empty search for it
    do 
        var=$(xdotool search -name havohej)
    done

xdotool set_window --classname scratchpad $var
xdotool set_window --name scratchpad $var

We search for a window with the title "havohej" until we find it. Perhaps it's not such a good idea to have an infinite loop here in case something goes wrong.

When we find it, set the classname and title of that window to "scratchpad".

scratchStart

scratchStart looks like this:

#!/bin/bash

sleep 12

screen -S scratchy -X screen -t mutt 1
screen -S scratchy -p mutt -X stuff '~/scripts/khardMutt && mutt'`echo -ne '\015'`

screen -S scratchy -X screen -t rss 2
screen -S scratchy -p rss -X stuff 'newsboat'`echo -ne '\015'`

screen -S scratchy -X select 0 #select the 1st win ie vimwiki
screen -S scratchy -p vim -X stuff `echo -ne '\015'` #press enter
screen -S scratchy -p vim -X stuff ':e'`echo -ne '\015'` #reload index

The choice of applications vary depending on which computer I'm using and what kind of period I'm in. Some handy applications that works well in this setup are irssi, profanity, ssh, htop, khal in interactive mode, buku, todoman, vimpc/ncmpcpp, rtv, toot/tootstream, bluetoothctl, w3m etc. Whatever you use often can be put there but it's a balancing act on a thin line since putting to many programs in the screen session makes it cluttered and bulky and defeats the whole purpose of this exercise.

Vimwiki in goyo

To make vimwiki look nice and minimalistic I always run it in goyo.vim. Unfortunately this is not completely unproblematic. If we are in "godzilla.wiki" and want to close it via :bd, vim will spit out an error message and we have to reload the page. I would expect the buffer to be closed and be thrown back to the index page or the last page we visited. There is some configuration that can make your life a bit easier but it's not a perfect solution.

For some reason the feature of going back to index page by pressing the backspace key doesn't always work.

Lastly, on startup we get a black window and after pressing some key to render the wiki visible vim doesn't get the goyo margins right. I think this might be a bug(?). The ugly hack around this issue are the very last two lines above in the scratchStart script. We let screen press enter for us and reload the vimwiki index page.

Conclusion?

This is a extremely convoluted setup to a achieve something very simple. I would really prefer a simpler and cleaner solution but it kind of works. If I had a faster computer and managed to break my addiction to terminator and used a reasonable terminal emulator instead this would probably almost be a one-liner.

For completeness here is my ~/.screenrc:

startup_message off
backtick 1 5 5 true
termcapinfo rxvt* 'hs:ts=\E]2;:fs=\007:ds=\E]2;\007'
hardstatus string "screen (%n: %t)"
caption always
term screen-256color
caption always "%{= dW} %{G}%H%{-} %?%-Lw%?%{G}[%{W}%n%f %{-}%{W}%t%{-}]%{-}%?%+Lw%?%="

and my ~/.config/terminator/config:

[global_config]
  tab_position = hidden
  use_custom_url_handler = True
  custom_url_handler = ~/scripts/tab
  title_hide_sizetext = True
  inactive_color_offset = 0.5138888888888888
  always_split_with_profile = True
  title_use_system_font = False
  title_font = Iosevka Heavy 8
[keybindings]
  go_down = <Primary><Shift>onehalf
  full_screen = section
  help = <Primary>Forward
[profiles]
  [[default]]
    icon_bell = False
    background_darkness = 0.7
    cursor_color = "#73d216"
    cursor_color_fg = False
    font = Iosevka 8
    show_titlebar = False
    scrollbar_position = hidden
    scrollback_lines = 5000
    login_shell = True
    use_system_font = False
    bold_is_bright = True
    copy_on_selection = True<span style="color: #009900;">
  [[scratchpad]]
    visible_bell = True
    cursor_color = "#73d216"
    cursor_color_fg = False
    font = Iosevka 8
    show_titlebar = False
    scrollbar_position = hidden
    use_system_font = False
    copy_on_selection = True</span>
[layouts]
  [[default]]
    [[[window0]]]
      type = Window
      parent = ""
    [[[child1]]]
      type = Terminal
      parent = window0
[plugins]

As Lewis Caroll put it in The Hunting Of The Snark:

"The method employed I would gladly explain, while I have it so clear in my head. If I had but the time and you had but the brain - but much yet remains to be said."