Pimp Your XMonad #4: Urgency Hooks

March 14, 2009

In a traditional desktop environment such as Gnome or KDE, one has a Windows-style taskbar and tray, with small icons for various apps. When an app wants your attention, it generally changes its tray icon, and might highlight or flash the taskbar entry. In a pure xmonad setup, one typically has neither a taskbar nor a tray, so how do you know when someone addresses you on IRC, or sends a Pidgin message?

Xmonad offers a solution, the XMonad.Hooks.UrgencyHook module. This module offers a variety of ways for xmonad to notify you that an app is requesting your attention, and some ways for you to respond.

XMonad Setup
When an app sets the X WM_URGENT option (see below on how to configure this in some common apps), UrgencyHook will notify you. Precisely how it does so is up to you. One uncommon choice is popping up a temporary dzen2 window, which I won’t be covering here (see the XMonad.Hooks.UrgencyHook docs). By far the most common technique is highlighting the workspace in your dzen or xmobar workspace list.

To start, import XMonad.Hooks.UrgencyHook. Then your xmonad defaultConfig { ... } line changes to: xmonad $ withUrgencyHook NoUrgencyHook defaultConfig { ... }. If you run the darcs version of xmonad and use the dzen function or dzenPP for your logHook you’re all set! Both of those functions set up dzen to show urgency by highlighting the workspace with the urgent window.

If you use the xmobar or xmobarPP functions, or want custom colours for your dzen, a little more work is required. You probably have a logHook defined, and it probably uses xmobarPP or dzenPP. If not, see the documentation for XMonad.Hooks.DynamicLog, that’s outside of the scope of this article.

You’ll have to add the field ppUrgent = xmobarColor "yellow" "red" . xmobarStrip to your xmobarPP for xmobar, or ppUrgent = dzenColor "yellow" "red" . dzenStrip for dzen. Of course, you can choose whatever colours you like.

N.B. The dzenStrip and xmobarStrip functions only exist in darcs. If you don’t run darcs xmonad, you can get the code from here and paste it into your xmonad.hs.

A Handy Keybinding: focusUrgent
XMonad.Hooks.UrgencyHook contains a useful keybinding function, focusUrgent, which takes no arguments and focuses the most recently urgent window.

Configuring Pidgin
The second part of setting up UrgencyHook is configuring apps to set WM_URGENT. To do this for Pidgin, you need to enable the Message Notificaton plugin (included with Pidgin), and in the plugin configuration tick the “Set window manager ‘URGENT’ hint” option.

Configuring urxvt
Another common thing to want highlighting for is when someone uses your name in IRC. To make urxvt set urgent on a bell, add the line URxvt.urgentOnBell: true to your ~/.Xdefaults.

Of course, you’ll also have to set your IRC client to trigger a bell on highlight (in irssi: /set bell_beeps ON and /set beep_msg_level MSGS NOTICES DCC DCCMSGS HILIGHT). If you run it in screen, make sure screen isn’t set to use visual bell either.

The XMonad.Hooks.UrgencyHook docs also have information on setting up these apps and others. If you use a different terminal or IRC client, Google knows how to set it up for urgency hints.

UrgencyHook in Action
Here’s a screenshot of me hard at work on xmonad, with UrgencyHook notifying me that I’ve received a Pidgin message on workspace 2: IM.

P.S. Twitter
I’m now on Twitter as bradenshep.


Pimp Your XMonad #3: Prompt

November 29, 2008

This is a big post that I’ve been putting off for a long time. There are a lot of awesome modules in the XMonad.Prompt.* family, and so there’s a lot to cover here.

XMonad.Prompt itself defines a library for displaying prompts to the user, with autocompletion and customizable look and feel. This module is a back-end library, not intended for use in configurations. What follows is a description and use cases for what I consider the most important modules in the Prompt family, a breakdown of how to customize the look and feel, and a quick rundown of the remaining Prompt modules as of 0.8.

Binding a Prompt action to a key
Nearly all Prompt actions are performed using key bindings. You can bind them to whichever keys you wish, and they all take the same basic form. First, you need to import the relevant module, for example

import XMonad.Prompt.Shell

Second, you need to create a keybinding to call a function from it

( modMask conf .|. xK_s, shellPrompt myXPConfig )

or using XMonad.Util.EZConfig (which will be the subject of a future PYXM)

("M-s", shellPrompt myXPConfig)

The myXPConfig argument is how you customize the look and feel of the prompts. See the section called “Look and Feel Customization” below on how to do this.

Running Commands and Launching Applications: Shell, RunOrRaise, DirExec
One obvious application of Prompt is using it to run shell commands and launch applications. XMonad.Prompt.Shell.shellPrompt works similarly to dmenu, though it allows command-line arguments to be provided as well, and more complete look-and-feel customization.

XMonad.Prompt.RunOrRaise.runOrRaisePrompt uses the XMonad.Actions.RunOrRaise functionality to prompt for an application, launch it if it isn’t running, and summon it if it is.

XMonad.Prompt.DirExec.dirExecPrompt can be used when you want to run programs from a directory not necessarily in your path.

Navigating by Window Titles: Window
XMonad.Prompt.Window‘s windowPromptGoto and windowPromptBring functions present an autocompleting list of window titles for all the windows in your session, and either take you to the window you name, or bring it to your location. This can be very helpful both for tracking down windows you’ve misplaced, and for bringing remote windows here without going to find them.

Minimally Disruptive Note-Taking: AppendFile
XMonad.Prompt.AppendFile is my personal favourite find from my research for this article. That might not be fair to Shell and Window, I knew they were there so they weren’t “finds”. What AppendFile does is prompt you for one line of text, which it then appends to a file named in your xmonad.hs. The intended purpose (there are probably others) is to be able to jot down quick notes by hitting a key binding and typing one line, without disrupting whatever other task you were doing.

Arbitrary XMonad Actions: XMonad
XMonad.Prompt.XMonad can be viewed as an extension of your key bindings. It displays an autocompleting list of actions, each action bound to an arbitrary X (), like a key binding. You can use the provided default bindings using xmonadPrompt (which seem to correspond to roughly the same actions as the default key bindings) or create your own list of (name,action) pairs with xmonadPromptC.

Look and Feel Customization: XPConfig
The XPConfig data type is defined in XMonad.Prompt, and it defines the various colours and other parameters that determine the appearance, position, font, size and behaviour of the Prompt box. Following is a rundown of the parameters and what they control.

  • font — a String naming a font in the X format, eg. "-*-terminus-*-*-*-*-16-*-*-*-*-*-*-*" (default: "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*")
  • fgColor,bgColorStrings in "#rrggbb" format, defining the fore- and background colours. (defaults: "#333333" and "#FFFFFF")
  • fgHLight,bgHLightStrings as above, defining the highlight colour for a completion entry. (defaults: "#000000" and "#BBBBBB")
  • borderColor — a String as above, defining the border colour. (default: "#FFFFFF")
  • promptBorderWidth — the border width in pixels. (default: 1)
  • position — either Top or Bottom, the constructors of the XPPosition data type. (default: Bottom)
  • height — the height of the Prompt bar in pixels (make sure it’s large enough for your font!) (default: 18)
  • historySize — the number of history entries to save. (default: 256)
  • defaultText — a String defining the text initially in the Prompt box when it opens. (default: "")
  • autoComplete — a Maybe Int that controls the autocompletion behaviour. If Nothing, you must press Enter to select the entry. If Just x, it will select a unique entry after x microseconds. For example, Just 1000000 would wait 1 full second. (default: Nothing)

Remaining modules
These modules are well worth mentioning but are straightforward enough to just list quickly:

  • Workspace — takes a String -> X () function and gives it the name of the workspace you specify in the prompt. Could be used to focus the named workspace, bring all the windows on it to the current workspace, or any other action.
  • Ssh — given a host name in the prompt, creates an SSH session in a terminal.
  • Man — displays the man page for the subject you provide in the prompt.
  • AppLauncher — functionality similar to dmenu.

The XMonad.Prompt.* family is a prime example of the awesome functionality just waiting to be discovered. Depending on how they use XMonad, I have seen Ssh, Window and RunOrRaise all make an xmonad user’s day.

Pimp Your XMonad #2: SmartBorders

November 15, 2008

This is a quick one. The focused window border is sometimes unnecessary, particularly when using Full or Tabbed layouts, since only one window is visible. XMonad.Layout.NoBorders was built to fix this.

The simplest option is the noBorders modifier, which will simply never show the border on the layouts it is applied to. It is typically applied thus:

layoutHook = ... ||| noBorders Full ||| ... ||| noBorders Tabbed ||| ...

Using it on a layout that shows multiple windows, such as Tall, would be a bad idea. But what about Tall with only one window? There is also the smartBorders modifier that will hide the borders under either of two conditions:

  • There is only one screen and only one window. (Note that on a Xinerama setup, this will never be true.)
  • A floating window covers the entire screen (great for mplayer, probably the largest use case)

Since smartBorders handles all layouts, even those that can have multiple windows, it is best applied to your whole layoutHook:

layoutHook = avoidStruts $ ... $ smartBorders $ ... ||| tiled ||| ...

Adding to core
It has been argued that SmartBorders should be in core, and even be the default behaviour. The main argument against this is that it could be confusing, and that it is rather straightforward to set up. For now, setting up smartBorders is easy, and improves the fullscreen video experience.

Pimp Your XMonad #1: Status bars

November 2, 2008

I’ve been hanging around in #xmonad for a long time, and two things have become clear. First, we answer a certain subset of questions many times. Most of the answers are in the FAQ, but the reality is that #xmonad tends to be more efficient, and it gives the answerers a means of procrastination more useful to society than reading whatever has hit reddit this minute.

Second, some relatively new user whose config is as he wants it will be hanging around in the channel when another new user asks if some feature exists. The first user says “I never even thought of something like this!” So I conceived the idea which eventually turned into this series of posts, a place for new users to discover features they never knew they were lacking.

Status bars

This arguably doesn’t belong, since it’s unlikely any user is going to reel in their jaw and say “I can get it to show me a list of workspaces?!” Don’t get me wrong, it’s an awesome feature, and I would get lost all the time without it, especially on a dual-head setup. But it might not belong since it’s a relatively easy-to-conceive feature.

Why should you use a status bar? Well, it will list all your currently populated workspaces (meaning those with at least one window on it, as well as those currently visible whether or not they have windows on), which can help with the “Oh, I forgot I sent this to workspace 8 six hours ago” problem. Using one of the pretty-printers (available for xmobar and dzen, with customizable behaviour) It highlights the currently focused workspace, as well as the other visible workspaces under a Xinerama setup. Also shown are the current layout, handy to avoid the “I forgot about these other windows because I was in Full” problem; and the window title, handy for the subtle jokes of some web comics, and… well I actually turned that one off.

Which status bar app?

xmonad users generally pick one of two: dzen2 and xmobar. The former is a general-purpose Do-It-Yourself status bar program, with sophisticated color and formatting directives that can be inlined in the input. It also supports XFT fonts and XPM icons. However, it is only an engine for displaying the input; you must write a program to generate the necessary input yourself. If that program is xmonad, the logHook in xmonad.hs, and XMonad.Log.DynamicLog‘s dynamicLogWithPP and dzenPP functions make that easy. If you want time, CPU usage, memory usage, etc., you’ll need to write your own script, with help from the dzen wiki.

xmobar, as the name hints, was designed for use with xmonad. Since xmonad doesn’t have any parts that run periodically, it can’t output a reliable time, or fresh CPU/memory/disk/network data to any status bar app. xmobar handles this itself, allowing the user to specify in a config file what information they want, and in what format it should appear.

Setting it up

With future articles, I intend to describe in more detail how to set up and get full use out of the features I’m discussing. In this case, though, the question is so frequently asked and answered in #xmonad that I’m going to punt. Either see John Goerzen’s excellent guide to setting up xmonad for its xmobar sections, or see that and replace xmobarPP with dzenPP, and remove the sTitle line from the example xmonad.hs seen there.