My i3 window manager setup

almost 5 years ago

I have been a long time i3 window manager user. But not really.

My old Windows 10 based setup involved doing all my console work in an Ubuntu VM running i3. However, the lion’s share of the non console work was still done in Windows, including browsing and more.

For multiple years now I only partially experienced i3, it showed. My i3 setup was almost vanilla.

My move to Arch Linux changed everything.

This move completely shifted the way I think about my relationship with my desktop environment. Previously, my relationship with Windows was very simplistic. Windows works the way it works, I simply adapted to that. Sometimes I learned a new shortcut, but the majority of my Windows day-to-day involved dragging windows around, reaching Firefox window and tab saturation, closing windows with the mouse and so on.

I am not a great example of a Windows ninja some users go down a far more custom path. I do feel I am pretty typical though of a developer using Windows or Mac. I was given a menu, I learned a tiny bit of it, then I simply threw away the menu and reached for the mouse.

In this blog post I would like to talk about what my 3.5 week adventure has looked like and where I am today!

Opening moves

When I moved to Linux I did not know much of the current state of Linux on the desktop but I did know 2 things:

  1. I would be using Arch Linux
  2. I would be using the i3 tiling window manager

I opted for Arch cause I love not having to worry about upgrading my system every 6-12 months to another major release, I think pacman and the package library on Arch is amazing, if I ever am missing tiny bits from the official library it is trivial for me to just grab a package from the very comprehensive AUR. I also think the documentation in the Arch wiki is fantastic and it helped me enormously.

I opted for i3 cause I wanted to fully experience the window manager, not treat it as a glorified tmux like I was for years.

A day or so into my move I was uncomfortable with the way my stock install looked and acted, I quickly learned about the r/unixporn reddit and this movement called “Ricing”.

During the first few days I watched a fair bit of youtube to see what others are doing.

I can recommend:

My basic ricing

I totally get that lots of people love dmenu people get it to do all sorts of amazing things like mount drives, select monitors and pick files. It is a very powerful and in true suckless fashion minimal tool.

I opted to swap out my dmenu with rofi which I seem to like a bit more. It looks like this:

I prefer the positioning and really like the combi menu that allows me to also navigate through my open windows. rofi works in a dmenu mode as well so I can just use it interchangeably.

I also used LXApperance for some very rudimentary themeing in particular I do like the Apple San Fransico font that I use for my window titles:

image

I also set up a basic gruvbox theme for my urxvt terminal and was careful to grab the fork with 24 bit color support so everything looks just right. Initially I tried out terminator but find urxvt a bit “lighter” that said, I may try out st next.

Finally I swapped out i3status with i3status-rust. It shows me weather, volume, network and cpu speed and pending update count. I really enjoy it.

My ricing is very basic, I don’t like wallpapers, I don’t like transparency and am unsure if I would even like to try gaps or not.

A tiny note on mod keys

A large amount of i3 configuration relies on using a mod key. The mod key is mapped by end users to an appropriate key that does not get in the way with other keyboard bindings other programs use.

In my case I map mod to both the Windows key and the right Menu key. I do the menu key mapping by running exec_always --no-startup-id xmodmap -e "keysym Menu = Super_R" in my config file.

The tool I used for displaying keys on this blog post (the amazing screenkey) calls the Windows key Super which is the Linuxey name. I can rename it to mod, but I am already multiple screenshots in.

For the purpose of this blog post. Mod == Super == Windows Keyboard key. I will be calling this key Super from here downwards.

Easy editing of Discourse

When I moved to i3 proper I set myself the goal to eliminate trivialities. I observed things that I kept on doing inefficiently and optimized my setup.

I found that in the past every time I wanted to hack on Discourse I would

  • Open a terminal
  • cd Source/discourse
  • open nvim
  • split the window
  • open nerdtree

This flow involved lots of steps which can easily be automated:

I now hit Super + Shift + D and tada Discourse opens.

This is done by adding this to my i3 config:

bindsym $mod+Shift+d exec "i3-sensible-terminal -e '/home/sam/.i3/edit_discourse'"

And this tiny shell script

sam@arch .i3 % cat edit_discourse 
#!/bin/zsh

cd /home/sam/Source/discourse
exec nvim -c ':NERDTree|:wincmd w|:vsplit'

Smart window centering

Even though i3 is a “tiled” window manager. Some windows… I prefer in floating mode. In particular I like having Firefox in floating mode.

I like having Firefox in the middle of my center monitor at very particular dimensions. I do sometimes drag it around but it is nice to “reset” the position.

Sometimes I like it a bit wider, so I hit Super + c again.

And sometimes I like it a tiny bit wider, so I hit Super+c again.

If I hit Super + c yet again it is back to square one and window is small centered.

I achieve this by having this in my i3 file.

bindsym $mod+c exec "/home/sam/.i3/i3-plus smart_center 1830x2100,2030x2100,2230x2100"

The little i3-plus utility is a work-in-progress Ruby utility I have that interacts with the i3 IPC so it can make smart decisions about what to do. You can find the source for it in my dotfiles.

The basic logic being:

This config also allows me to quickly zoom a tiled panel to the middle of the screen, size it right and once I am done with focused work I can ship it back to the tile with Super+Shift+Enter

Easy terminal arrangement

One issue I had with i3 for quite a while was needing to remember to flip the way I split windows in tiling mode. I would hit Super+Enter to open a terminal, then hit it again and open a terminal to the right.

And then I hit a problem.

My brain simply did not consistently remember if I had to hit Super+v for a vertical split or Super + h for a horizontal split. Is splitting vertically splitting the vertical window in half or is splitting horizontally splitting tall window at the horizon.

Clearly, I could work around my brain glitch by using a different shortcut that was easier for me to associate. Or just tough it up and train myself properly. But what I observed here is that I was just repeating a pointless task.

I like my tiled windows arranged “just so” and in a specific order. i3 by design is not a “just so” tiler, all tiling is manual not automatic like xmonad and dwm. This is an explicit design goal of the project.

Michael Stapelberg explains:

Actually, now that I think of it, what you describe is how automatic tiling WMs work (like DWM, awesome, etc.). If you really need that, you might be better off using one of these. i3 is (and will stay) a manual tiling WM.

That said… this is my Window Manager, and I can make it do what I want. Unlike my life in Windows and Mac, when I dislike a behavior I can amend it. I am encouraged to amend it. i3 will not merge in dynamic tiling which is a way they manage bloat and complexity, but I can have a bodged up dynamic tiling system that works for my workflows with i3.

So, I have this standard behavior:

Followed by this … non standard behavior. (notice how I never had to hit Super+v

What more it gets better cause then next Super+enter switches panels, no matter what terminal I am on.

My system is somewhat glitchy, I have only been doing this for a few weeks, but it scratches my itch big time.

As an added bonus I made it so when I am on my right most monitor I start tiling vertically in the left column instead of right.

My work in progress code to make this happen is at my i3-plus file in my dotfiles.

At the moment layout is hardcoded and I simply run:

bindsym $mod+Return exec /home/sam/.i3/i3-plus layout_exec i3-sensible-terminal

Tweaks to multi monitor focus

I tend to keep a floating window around on my left monitor for chat. I found that I tended to get trapped on my left monitor after hitting Super + Left. i3 has a behavior where it cycles between floating windows on a monitor. This got in the way of my workflows.

After raising raising this at GitHub airblader fairly concluded that this is a minor annoyance with a clear workaround but was worried about adding any more complexity to focus behavior. This is fair.

But… this is my Window Manager and I get to call the shots on my computer.

So now my focus never gets trapped on a monitor. My Super + Right key works the way I want it to.

Tweaks to move

Out-of-the-box i3s example file binds Super + Shift + Right/Left to the i3 command move.

What this does is:

  • In tiled mode moves the tile to left or right
  • In floating mode moves the window a few pixels to the left or right.

The behavior in tiled mode worked for me, but I found that I am not really into positioning floating windows using arrows and instead find it far more useful to “throw” a floated window to the right or left monitor.

From what I can tell (and I may be wrong) I could not find a way to tell i3 to run a certain command in floating mode and another in tiled mode. However using the ipc interface this was trivial:

  def move(dir)
    if is_floating?
      @i3.command("mark _last")
      @i3.command("move to output #{dir}")
      @i3.command('[con_mark="_last"] focus')
    else
      @i3.command("move #{dir}")
    end
  end

A keyboard friendly exit

The i3 sample config spins up a nagbar prior to attempting to exit the windows manager. I found the position of this nagbar not ideal and did not like that I needed to reach for the mouse. I am not alone here but this is really only a common problem when you are heavily tweaking stuff.

That said I came across this wonderful idea somewhere, which I would love to share:

mode "exit: [l]ogout, [r]eboot, [s]hutdown" {
  bindsym l exec i3-msg exit
  bindsym r exec systemctl reboot
  bindsym s exec systemctl shutdown
  bindsym Escape mode "default"
  bindsym Return mode "default"
}

bindsym $mod+x mode "exit: [l]ogout, [r]eboot, [s]hutdown"

I now use Super + x to enter my “exit i3 mode”, which gives me all the goodies I need with a nice UX.

image

I love screenshots

During my day I tend to take a lot of screenshots. I always struggled with this for a degree. I never had the “right” tool for the job in my Windows days. Now I do.

I set up my screenshot hotkeys as:

  1. PrtScn : take a screenshot of a selection

  2. Super + PrtScn : take a 3 second delayed screenshot of a selection

  3. Super + Shift + PrtScn: take a screenshot of the current desktop + pass it through pngquant and add to clipboard.

(1) in the list here was really easy. I used the flameshot tool and simply bound prtscn to it:

exec --no-startup-id flameshot
bindsym Print exec "flameshot gui"

It works a treat. Highly recommend.

Delayed screenshots (2) is where stuff got tricky.

Flameshot has a delay option, even if it did not it is trivial to exec sleep 2 && flameshot gui. However, I like having a visible reminder on the screen that this thing will happen:

To implement this I adapted the countdown script from Jacob Vlijm

My adaptation is here..

In i3 I have:

bindsym $mod+Print exec "/bin/bash -c '/home/sam/.i3/countdown 3 && sleep 0.2 && flameshot gui'"

Full screen screenshots (3), like the ones further up this blog post was a bit tricky.

Xwindows screenshot tools like treating all my 3 4k screens as one big panel, not too many tools out there can figure out current focused monitor let alone split up the enormous image.

To achieve this I rolled my own script that uses the i3 IPC to figure out what display has focus and then tells ImageMagick to capture and crop correctly and finally passes throw pngquant and back on to the clipboard in a web past friendly format using CopyQ.

This simple binding then takes care of it for me.

bindsym $mod+Shift+Print exec "/home/sam/.i3/i3-plus screenshot"

Scratchpad

i3 has a special desktop that is not visible called “the scratchpad”. If you want to get rid of a window temporarily you can always just ship it there and recall it from there. I like to use it for a couple of things.

  1. I bind Super + b to toggle my browser in and out of the scratchpad. No matter which monitor I am on I can summon my browser with this hotkey (and make it go away)

  2. I bind Super + p to toggle a dedicated terminal. I like to use this dedicated terminal to run stuff like pacman -Syu that can take a bit, look at a calendar, run a quick calculation and so on.

  3. Similar to both above I like Super + y to bring up my yubico authenticator. (I highly recommend a Yubikey for devs it is a big time saver)

# terminal that pops up on demand
exec urxvt -name scratch-term
for_window [instance="scratch-term"] floating enable, move to scratchpad
bindsym $mod+p [instance="scratch-term"] scratchpad show

exec firefox
for_window [class="Firefox"] floating enable, move to scratchpad, scratchpad show
bindsym $mod+b [class="Firefox"] scratchpad show

exec yubioath-desktop
for_window [class="Yubico Authenticator"] floating enable, move to scratchpad
bindsym $mod+y [class="Yubico Authenticator"] scratchpad show

Other bits and pieces

My current .xinitrc looks like this:

eval $(dbus-launch -sh-syntax --exit-with-session)
dbus-update-activation-environment --systemd DISPLAY

xrdb -merge ~/.Xresources

xrandr --output DVI-D-0 --off --output HDMI-1 --off --output HDMI-0 --mode 3840x2160 --pos 0x0 --rotate normal --output DP-3 --off --output DP-2 --primary --mode 3840x2160 --pos 3840x0 --rotate normal --output DP-1 --off --output DP-0 --mode 3840x2160 --pos 7680x0 --rotate normal

eval $(/usr/bin/gnome-keyring-daemon --start --components=gpg,pkcs11,secrets,ssh)
export GNOME_KEYRING_CONTROL GNOME_KEYRING_PID GPG_AGENT_INFO SSH_AUTH_SOCK

exec i3

I am not a fan of using Gnome Display Manager as I feel it introduces more complexity into my setup. Instead, I just run startx after logging in.

The two trips here is that I needed a dbus session so gnome type apps work (like skype for example) and needed to spin up my keyring (which skype needed as well)

Do I actually get any work done?

The i3 sample config file has a wonderful comment at the top.

# This file has been auto-generated by i3-config-wizard(1).
# It will not be overwritten, so edit it as you like.

My i3 setup is my setup. It is tailored for my use cases.

I love that i3 has a single config file, it is very easy to reason about my current desktop environment. If I don’t ever use a shortcut I can remove it. If I need a new shortcut I can add it. If I forget what is “on the menu” I can read the reasonably small file to figure out!

All of this tweaking does sound like it could be a full time job for multiple weeks but it really was not at all. I hit barriers in my workflow, unblocked them and then moved on. Each barrier I removed made me more efficient.

The end result has been that I can now jump on a problem and solve it with significantly more focus. My window manager is working for me, I am no longer its slave.

In my previous blog post I talked about leaving Windows. The catalyst was performance. What I did not know was what a wonderful experience I would have in my new Linux home.

Sure, I have the usual niggles of needing to run a compositor fight with Nvidia drivers and deal with finding Linux alternatives for Windows tools I was used to using. However, on a fundamental level I am just so much happier now. I feel like I relinquished control over my computer for too long.

What you can do?

If you wish to do a Linux experiment you can choose the hard mode or the easy mode, there are plenty of alternatives out there. If you want to try out tiling, you can even just pick up Manjaro which has an i3 distribution or Regolith Linux.

As a programmer in any terminal dominated technology stack (like Ruby/Rust/Golang and so on) I strongly recommend trying out a tiling window manager.

From all my research i3 is the perfect first choice for trying out a tiling window manager, it comes with very sane and complete defaults, the config file is very easy to reason about and it works great!

If you have any questions or would like any tips feel free to post here and I will reply, but be warned, I am no expert I am just learning.

Big thank you to Michael Stapelberg for creating i3, and the very active community (Airblader, Orestis and others) for maintaining i3. Big thank you to all you people putting excellent content out there and making my ride into the Linux world easy.

Comments

Kelly Stannard over 4 years ago
Kelly Stannard

For anyone stuck on Macos for work reasons, skhd + chunkwm can replicate a lot of i3 functionality with some effort.

i3 is truly the best possible wm for serious developers though.

Sam Saffron over 4 years ago
Sam Saffron

Nice … wondering how GitHub - koekeishiya/yabai: A tiling window manager for macOS based on binary space partitioning fits into this picture now that chunkwm has been archived, does it work any better?

HenriP about 4 years ago
HenriP

Hi Sam
Thanks for sharing your toughts and instructions.
One thing popped up when reading your way of working. You said you don’t like GDM but rather run startx (from console)? Are you running i3lock or xscreensaver to lock your workspace?
Have you tried not typing your password to get back but press CTRL-ALT-F1 (or whatever text terminal you used) and then pressing CTRL-z to suspend your startx session? Do you get your prompt without knowing your password?
Earlier when not using any Display Manager it was dangerous to hack into somebody’s console. I hope it’s fixed nowdays (with systemd or so).
Regards, HenriP

Sam Saffron about 4 years ago
Sam Saffron

Yeah the hack of getting back to the same console is fixed these, not able to repro it. I use xfce screensaver.

Thanks heaps though for letting me know about this.


comments powered by Discourse