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.
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."