Life With XMonad
Summary
Details on my XMonad setup, and on living with a tiling window manger, full-time, for many years. (I am old)
Why XMonad?
Long ago, at a job far far away, I became aware that I was spending a huge amount of my day moving windows around the screen so that I could find the thing I was looking for. It was at that point I decided there had to be a better way, and I started looking for it. I happened to come across XMonad, and a cheat sheet of it’s key bindings, and for some reason it really resonated with me, and the key bindings just stuck. I did not know Haskell (I’m still no expert), I had no idea what a Monad was.
But from that grew my love and appreciation for XMonad, and just how great of a window manager it is. I read lots of things about the other tiling window managers that are out there, but frankly, I don’t think people fully appreciate how much better XMonad is than those alternatives. So one of my goals with this series is to try to explain that. (I have tried every tiling window manager at some point, believe me)
One other thing I think it is important to note right away, is that XMonad does NOT work on Wayland.. which makes me sad. There is one tiling WM that does, named Sway, but one look at it’s github issues page, makes me feel like it is not really ready for prime time, and that it has the same problems as other non-monad inspired window managers. Namely that it can crash at runtime, which XMonad has never done for me.
If you want to get right to the actual config, and are not interested in my theme etc. Then you can either checkout my XMonad-Config github repo, or jump down to the XMonad Config section.
Screenshots
Pictures or it didn’t happen. Here are some quick screenshots of what my current setup looks like. There is more than just XMonad in these screenshots, and I will try to document everything I run from the ground up in what I hope will be a series of posts on the subject.
Wallpaper / Icons
Let’s start simple, with the wallpaper. It’s a little crazy, but so am I. I happened to find it attached to an article about ransomware form comodo, and I thought it was hilarious that day, so I made it my wallpaper. That’s all there is to that.
For icons I use the beautiful and free Paper Icon Theme which is by far my favorite icon set.
My cursor is actually the Breeze Light theme from KDE, which is equally beautiful.
I am also using the amazing Proggy Vector font. I used swear by the Terminus font, but after having lots and lots of issues over time getting it to render clearly, I finally gave up on it. (Sorry) The TTF version has just never quite compared to the super clear text the bitmap version provides.
Terminal
The terminal I am currently using is xfce4-terminal. I already use Thunar as my file manager (also from xfce) and had finally gotten tired of the constant font rendering issues I had with urxvt. So it was time for a change. I have not regretted it at all, it has been a joy to use, has modern features and to date has not had any font rendering issues. Yay!
Shell
I am currently using fish as my shell. I have in the past used bash, and zsh (with Oh My ZSH!), but have found fish to be super reliable and a pleasure to actually use every day. The prompt is a custom setup that I put together myself (mostly). I often would walk away and wish I knew when something finished, or how long it took. This prompt always provides that information.
My current dotfiles repo on GitHub contains my .dircolors and my fish config. Have a look if you are interested.
Top Bar
I use the excellent xmobar as my top status bar. It supports tons of plugins and can be customized to do anything you want. My current config is included in my XMonad-Config github repo.
A quick rundown from left to right, trayer system tray, containing blueman-applet, and nm-applet, followed by the list of desktops with windows on them, and the current desktops layout.
Following that is the current window name.
Aligned to the right, is the currently connected network and it’s signal strength (from my wireless.sh script).
After that is the current battery charging status and battery percentage. If charging, the time is how long until charged. If discharging, the time is an estimate of remaining battery life.
Following that is the current Rx and Tx speeds from the network, and then the current usage and temperature of the CPU, and memory usage.
And finally the current date and time, followed by the current relative humidity and temperature from the xmobar weather plugin.
A truly amazing amount of information in a small space.
Additional Apps
I use a ton of other apps that make my environment whole, this is just a helpful list for others. My configs for all these apps with eventually be on my github.
- blueman-applet - Handy applet for managing BT connections
- bpytop - The best status monitor
- dmenu - Excellent run dialog for launching apps NOT from a terminal
- Dunst - Super awesome and configurable notification windows
- feh - Set my wallpapaer
- gsd-xsettings - Used so that Gnome apps have proper themes etc.
- hsetroot - if you do NOT want a wallpaper image, but colors or gradients
- Lightdm - Great and configurable login manager
- nm-applet - Handy system tray applet for managing networking
- Picom (formerly compton) - Compositing (fancy transparent windows)
- rumno - Excellent GUI for showing pretty volume / brightness control status
- touchegg - used to glue some touchscreen gestures into my XMonad setup
- trayer - Still the best minimal system tray IMO
XMonad Config
Last but certainly not least, is the star of the show, XMonad.
My current config (and the helpers I am using to build it) are available in my XMonad-Config github repo.
For this first post, I just want to cover some small details about my config, which are a little less common (I think).
Also, I should probably add a disclaimer that I import a lot of stuff and I probably don’t use everything. I have been using this config for what, I think, is 15+ years? (I really am getting old) So undoubtedly there have been some changes during that time, and likely some things I neglected.
With that out of the way, let’s get into some details. I typically use the Tall or Mirror Tall layouts, but have some desktops defaulted to Full. I find this far more convenient that having to switch layouts around on every reboot. This is accomplished by the following section of xmonad.hs
Additional comments added below for clarity
fullFirstLayouts = noBorders Full ||| tiled ||| mirrored
-- this section defines the layouts which are defaulted to full screen..
-- I am using noBorders to skip putting any border on full screen windows (not really useful as there is only one active thing anyway)
-- all the CurWordsLeft gook is just to keep the Layout Names the same in xmobar
-- I use noFrillsDeco to get the nice titlebars, and have border spacing enabled to get a nice gap between windows..
-- I just think it looks prettier, and after staring at a screen for 20 years, I want it to look nice.
where
mirrored = renamed [CutWordsLeft 1] $ noFrillsDeco shrinkText myTitleTheme (Mirror otiled)
--
tiled = renamed [CutWordsLeft 1] $ noFrillsDeco shrinkText myTitleTheme otiled
-- default tiling algorithm partitions the screen into two panes
otiled = renamed [CutWordsLeft 1] $ spacingRaw True (Border 8 8 8 8) True (Border 8 8 8 8) True $ Tall nmaster delta ratio
-- The default number of windows in the master pane
nmaster = 1
-- Default proportion of screen occupied by master pane
ratio = 1/2
-- Percent of screen to increment by when resizing panes
delta = 3/100
defaultLayouts = tiled ||| mirrored ||| noBorders Full
-- this section defines the layouts which are just tiled normally..
-- I am using noBorders to skip putting any border on full screen windows (not really useful as there is only one active thing anyway)
-- all the CurWordsLeft gook is just to keep the Layout Names the same in xmobar
-- I use noFrillsDeco to get the nice titlebars, and have border spacing enabled to get a nice gap between windows..
-- I just think it looks prettier, and after staring at a screen for 20 years, I want it to look nice.
where
mirrored = renamed [CutWordsLeft 1] $ noFrillsDeco shrinkText myTitleTheme (Mirror otiled)
--
tiled = renamed [CutWordsLeft 1] $ noFrillsDeco shrinkText myTitleTheme otiled
-- default tiling algorithm partitions the screen into two panes
otiled = renamed [CutWordsLeft 1] $ spacingRaw True (Border 8 8 8 8) True (Border 8 8 8 8) True $ Tall nmaster delta ratio
-- The default number of windows in the master pane
nmaster = 1
-- Default proportion of screen occupied by master pane
ratio = 1/2
-- Percent of screen to increment by when resizing panes
delta = 3/100
-- here we pull everything together, we use onWorkspaces to set desktops 2, 3, 5, and 9 to use the full layouts, and the rest to default.
myLayout = onWorkspaces ["2", "3", "5", "9"] fullFirstLayouts $ defaultLayouts
Another section of my config which is a little less common, I think, is controlling the transparency of windows. That is accomplished by the following section. (The window manager just sets hints, Picom is what actually does the magic along with the X11 composite extension)
-- setup the fade hook, which tests if we should set a transparency, and then sets it.
myFadeHook toggleFadeSet = fadeOutLogHook $ fadeIf (testCondition toggleFadeSet) 0.82
-- here we define a list of window properties that we want to exclude from fading (this keeps things like the web browser on my second monitor from going transparent)
-- this is obviously not as much of a concern on my laptop (one screen), but things like Mplayer or vlc, you probably want to see all the time.
-- also we check if the window is fullscreen, as again you probably don't want that to be translucent.
doNotFadeOutWindows = title =? "Call with " <||> className =? "xine" <||> className =? "MPlayer" <||> className =? "Firefox" <||> className =? "firefox" <||> className =? "vlc" <||> isFullscreen
-- here is the actual magic that does the testing..
testCondition :: IORef (S.Set Window) -> Query Bool
testCondition floats =
liftM not doNotFadeOutWindows <&&> isUnfocused
<&&> (join . asks $ \w -> liftX . io $ S.notMember w `fmap` readIORef floats)
At the moment the rest of my config is pretty standard I think, and even the above sections are at least known among the XMonad community, so I won’t go into to much detail in this first post about the rest.
What’s Next
Next in this series I plan to dive deeper into how to actually build / install XMonad, why I am using stack to do so, and providing some useful information for anyone who would like to give XMonad a try for themselves.
In the meantime, if someone is actually reading this and wants more direction on building and setting everything up with stack, I followed this guide from Brian Buccola originally. (Thank You Sir!)
The Meta
- Added additional screenshot
- Added link to my dotfiles repo
- Initial post