Difference between revisions of "Xmonad/Config archive/John Goerzen's Configuration"

From HaskellWiki
Jump to navigation Jump to search
(→‎Configuring xmobar: clarify lowerOnStart version deps)
m (→‎Configuring xmonad to use xmobar: reformat comment so main is not broken up)
Line 121: Line 121:
   
 
<haskell>
 
<haskell>
 
-- make sure to edit paths to xmobar and .xmobarrc to match your system.
 
-- If xmobar is in your $PATH, and its config is in ~/.xmobarrc you don't
 
-- need the xmobar path or config file, use: xmproc <- spawnPipe "xmobar"
  +
 
main = do
 
main = do
 
xmproc <- spawnPipe "/path/to/xmobarbinary /home/jgoerzen/.xmobarrc"
 
xmproc <- spawnPipe "/path/to/xmobarbinary /home/jgoerzen/.xmobarrc"
-- make sure to edit paths to xmobar and .xmobarrc to match your system.
 
-- If xmobar is in your $PATH, and its config in ~/.xmobarrc you don't need
 
-- the xmobar path or config file, use: xmproc <- spawnPipe "xmobar"
 
 
xmonad $ defaultConfig
 
xmonad $ defaultConfig
 
{ manageHook = manageDocks <+> manageHook defaultConfig
 
{ manageHook = manageDocks <+> manageHook defaultConfig

Revision as of 01:45, 30 July 2009

I'm going to take you step-by-step through the process of configuring Xmonad, setting up a status bar with xmobar, setting up a tray with trayer, and making it all play nicely together. I use this exact configuration on everything from a 1024x600 Eee PC to a 1920x1200 24" workstation, and it works well on all of them.

I assume that you have read the About xmonad page as well as the xmonad guided tour already.

Before you begin, here is a screenshot of my desktop:

John-goerzen-xmonad-screenshot.png

And here is a screenshot that points out what I'm talking about when I talk about the status bar and the tray:

John-goerzen-xmonad-screenshot-annotated.png


Preliminaries

First you'll want to install xmonad. You can find instructions for that on xmonad.org. I'm going to assume xmonad 0.8 here.

This guide will work for any operating system. I happen to use Debian, so when I talk about installing software, I can give you Debian commands. But you can run xmonad all over the place; just substitute the appropriate commands for your system.

To install xmonad on Debian sid, you can just run:

apt-get install xmonad libghc6-xmonad-contrib-dev libghc6-xmonad-dev dwm-tools

This installs xmonad itself, everything you need to configure it, and dwm-tools, which provides the Mod-P launching feature. If you're not on sid, consult the xmonad download site -- note that there are etch binaries there, too. If you're downloading the etch binaries, you'll need the etch ghc6 and libghc6-*-dev*.deb binaries as well.

Set up xmonad in your .xsession as directed in the xmonad guided tour. You should have xmonad up and running before continuing.

Customizing xmonad

So the first thing you will want to do is customize xmonad. Make a directory called ~/.xmonad, and in there, create a file named xmonad.hs. We'll start off with importing some of the utility modules we will use:

import XMonad
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageDocks
import XMonad.Util.Run(spawnPipe)
import XMonad.Util.EZConfig(additionalKeys)
import System.IO

Next, a basic configuration -- which is the same as the default -- is this:

main = do
    xmonad $ defaultConfig

Over at the how to write a config file page -- which you should go read right now -- there are instructions for testing your config file. You should be able to save the above file, with the import lines plus the other two, and validate it with ghci, then press Mod-q to load it up. Another way to validate your xmonad.hs is to simply run `xmonad --recompile' in a terminal. You'll see errors if it's bad, and nothing if it's good.

Now how about something real? Replace the lines starting with main with:

main = do
    xmonad $ defaultConfig
        { manageHook = manageDocks <+> manageHook defaultConfig
        , layoutHook = avoidStruts  $  layoutHook defaultConfig
        }

(Disclaimer: The author in reality does not use this 'comma first' style. However, since it is the style used in xmonad, xmonad-contrib and most all xmonad.hs files, he has kindly consented to allow your friendly wiki gardeners to convert the original Haskell from 'comma last' style. This should make copying pieces from other configs a bit easier.)

Also, ghc sees all tabs as eight spaces, so to prevent confusion ensure your editor produces eight space tabs or expands tabs to spaces when editing haskell files. XMonad convention is to always expand tabs and (mostly) indent by four space increments.

-- real Goerzen config style
main = do
  xmonad $ defaultConfig {
         manageHook = manageDocks <+> manageHook defaultConfig,
         layoutHook = avoidStruts  $  layoutHook defaultConfig
         }

What this does is take the default configuration (defaultConfig) and modify two aspects of it -- the manageHook and layoutHook. This particular recipe comes from the Xmonad FAQ and adds the support we need for a status bar and dock.

I'll show my completed file at the end of this page, but for now let's add a few additional things in. By default, the Mod key is Alt, which is also used in Emacs. Sometimes Emacs and xmonad want to use the same key for different actions. Rather than remap every common key, I just change Mod to be the Windows key that's between Ctrl and Alt. So I add this line after layoutHook:

        , modMask = mod4Mask     -- Rebind Mod to the Windows key

The two dashes are a comment to the end of the line.

I also want to bind Mod-Shift-z to lock my screen with the screensaver, control-PrintScreen to take a snapshot of one window, and Printscreen to take a snapshot of the entire screen. My config file, starting with main, now looks like:

main = do
    xmonad $ defaultConfig
        { manageHook = manageDocks <+> manageHook defaultConfig
        , layoutHook = avoidStruts  $  layoutHook defaultConfig
        , modMask = mod4Mask     -- Rebind Mod to the Windows key
        } `additionalKeys`
        [ ((mod4Mask .|. shiftMask, xK_z), spawn "xscreensaver-command -lock")
        , ((controlMask, xK_Print), spawn "sleep 0.2; scrot -s")
        , ((0, xK_Print), spawn "scrot")
        ]

You can find the names for keys in the haskell-X11 source package in the files Graphics/X11/Types.hsc and Graphics.X11.ExtraTypes.hsc.

To support screen capture, run apt-get install scrot. I will cover setting up the screensaver later in this tutorial.

Did you notice the 0 in the xK_Print line? The first part of the (0, xK_Print) tuple states what modifier keys (ctrl, alt, etc.) have to be held down for a pattern to match. For the PrintScreen key, we don't need anything to be held down, and the zero indicates that. The 'sleep' before running the 'scrot -s' command is to leave time for keys to be released before scrot -s tries to grab the keyboard.

Installing xmobar

Next, it's time to get started with xmobar, the status bar. You can use xmobar or dzen2. dzen2 probably has a few more features, but xmobar has lower resource utilization and is considerably easier and more reliable to set up. I found it does more than everything I need, and recommend it.

You can download xmobar from its homepage, linked to above. That page also has compilation and installation instructions. As of Sept. 17, 2008, I also maintain a Darcs tree with some enhancements that you may wish. You can download my tree from:

darcs get http://darcs.complete.org/xmobar

If you darcs, apt-get install darcs or get it from your distribution or darcs.net. We will use my xmobar tree only for the part of the tutorial that shows the status of your keyboard LEDs (caps lock, num lock, etc.). You can safely use the default xmobar if you don't need that.

Configuring xmonad to use xmobar

So, let's talk a little bit about how xmonad and xmobar fit together. You can piece them together in several different ways.

xmobar accepts input on its stdin, which it can display at an arbitrary position on the screen. It can also easily display other information. We want xmonad to send xmobar the stuff that I have at the upper left of my screenshot: information about available workspaces, current layout, and window manager.

We could, then, have xmonad write this stuff to its stdout, and write xmonad | xmobar in ~/.xsession. But it's more elegant and useful, in my opinion, to have xmonad fire up xmobar itself. This is pretty simple. Our main part of xmonad.hs will now look like:

    -- make sure to edit paths to xmobar and .xmobarrc to match your system.
    -- If xmobar is in your $PATH, and its config is in ~/.xmobarrc you don't
    -- need the xmobar path or config file, use: xmproc <- spawnPipe "xmobar"

main = do
    xmproc <- spawnPipe "/path/to/xmobarbinary /home/jgoerzen/.xmobarrc"
    xmonad $ defaultConfig
        { manageHook = manageDocks <+> manageHook defaultConfig
        , layoutHook = avoidStruts  $  layoutHook defaultConfig
        , logHook = dynamicLogWithPP $ xmobarPP
                        { ppOutput = hPutStrLn xmproc
                        , ppTitle = xmobarColor "green" "" . shorten 50
                        }
        , modMask = mod4Mask     -- Rebind Mod to the Windows key
        } `additionalKeys`
        [ ((mod4Mask .|. shiftMask, xK_z), spawn "xscreensaver-command -lock")
        , ((controlMask, xK_Print), spawn "sleep 0.2; scrot -s")
        , ((0, xK_Print), spawn "scrot")
        ]

We've added a line right after "main". We fire up xmobar, and pass to it a command-line argument giving the path to its config file -- we will create this file in a minute. Then we also define a logHook. We tell xmonad that the way we get output to xmobar is with the command hPutStrLn xmproc -- this transmits the data via a pipe to xmobar. We also tell it that we want to put the first 50 characters of the window title in the title area.

When using hPutStrLn in your logHook make sure to add StdinReader to your xmobarrc as described below or xmonad may freeze when the unread pipe fills up.

Save this and test it with ghci.

Configuring xmobar

Now, before this will work, we have to configure xmobar. Here's a slightly simplified version of what I use, which is mostly similar to the sample you can find in the xmobar source package.

For xmobar-0.9 or earlier

Config { font = "-*-Fixed-Bold-R-Normal-*-13-*-*-*-*-*-*-*"
       , bgColor = "black"
       , fgColor = "grey"
       , position = TopW L 90
       , commands = [ Run Weather "EGPF" ["-t"," <tempF>F","-L","64","-H","77","--normal","green","--high","red","--low","lightblue"] 36000
                    , Run Cpu ["-L","3","-H","50","--normal","green","--high","red"] 10
                    , Run Memory ["-t","Mem: <usedratio>%"] 10
                    , Run Swap [] 10
                    , Run Date "%a %b %_d %l:%M" "date" 10
                    , Run StdinReader
                    ]
       , sepChar = "%"
       , alignSep = "}{"
       , template = "%StdinReader% }{ %cpu% | %memory% * %swap%    <fc=#ee9a00>%date%</fc> | %EGPF%"
       }

Note With > xmobar-0.9, i.e. xmobar from darcs, xmobar home page or hackage (cabal install), you will need to add a lowerOnStart line just below position:

Config { font = "-*-Fixed-Bold-R-Normal-*-13-*-*-*-*-*-*-*"
       , bgColor = "black"
       , fgColor = "grey"
       , position = TopW L 90
       , lowerOnStart = True
       ....<snip>

First, I set the font to use for my bar, as well as the colors. The position is documented well on the xmobar home page. This says to put my bar in the upper left of the screen, and make it consume 90% of the width of the screen. Note that although this looks similar to Haskell, it isn't, and doesn't accept comments or allow you to change the field order. In the commands list you, well, define commands. The commands are the pieces that generate the content that is available to display, which will later be combined together in the template. I define a weather widget, a CPU widget, memory and swap widgets, a clock, and of course the data from xmonad via the StdinReader.

The template then combines them together. Stuff to be left-justified goes before the } character, things to be centered after it, and things to be right justified after {. I have nothing centered so there is nothing in between them.

Save that to ~/.xmobarrc. Now you should be able to press Mod-q and have xmonad load up xmobar, and have it work.

Replace both occurrences of EGPF with your choice of ICAO weather stations. There is a list of ICAO station codes maintained at ucar.edu. You can of course monitor more than one if you like, see the xmobar home page for more details.

Adding Keyboard LED Indication

My 9.1" Eee doesn't have capslock or numlock lights. Before xmonad, I had an applet to do that, but that's not very efficient now. If you want this, read this section, otherwise skip it.

You'll need two pieces of software for this to work:

1) My darcs branch of xmobar

2) My ledmon tool, which you can obtain with:

git clone git://git.complete.org/ledmon

Or download from its gitweb page.

My darcs branch added a CommandReader option, which will cause xmobar to fork off ledmon. I compiled ledmon and put the binary in ~/.xmonad/ledmon, then modified my ~/.xmobarrc to look like this:

Config { font = "-*-Fixed-Bold-R-Normal-*-13-*-*-*-*-*-*-*"
       , bgColor = "black"
       , fgColor = "grey"
       , position = TopW L 90
       , commands = [ Run Weather "EGPF" ["-t"," <tempF>F","-L","64","-H","77","--normal","green","--high","red","--low","lightblue"] 36000
                    , Run Cpu ["-L","3","-H","50","--normal","green","--high","red"] 10
                    , Run Memory ["-t","Mem: <usedratio>%"] 10
                    , Run Swap [] 10
                    , Run Date "%a %b %_d %l:%M" "date" 10
                    , Run StdinReader
                    , Run CommandReader "/home/jgoerzen/.xmonad/ledmon" "LED"
                    ]
       , sepChar = "%"
       , alignSep = "}{"
       , template = "%StdinReader% }{ <fc=#ffff00>%LED%</fc> %cpu% | %memory% * %swap%    <fc=#ee9a00>%date%</fc> | %EGPF%"
       }

That's all there is to it.

(for >xmobar-0.9, i.e. darcs xmobar, add lowerOnStart)

Configuring Related Utilities

So now you've got a status bar and xmonad. We still need a few more things: a screensaver, a tray for your apps that have tray icons, a way to set your desktop background, and the like.

For this, we will need a few pieces of software.

apt-get install trayer xscreensaver

If you want the Gajim instant messenger client, a battery meter, and a network applet, also:

apt-get install gajim nm-applet gnome-power-manager

First, configure xscreensaver how you like it with the xscreensaver-demo command. Now, we will set these things up in ~/.xsession. Your .xsession may wind up looking like this:

<nowiki>#!/bin/bash</nowiki>

<nowiki># Load resources</nowiki>

xrdb -merge .Xresources

<nowiki># Set up an icon tray</nowiki>

trayer --edge top --align right --SetDockType true --SetPartialStrut true \
 --expand true --width 10 --transparent true --tint 0x191970 --height 12 &

<nowiki># Set the background color</nowiki>

xsetroot -solid midnightblue

# Fire up apps

gajim &

xscreensaver -no-splash &

if [ -x /usr/bin/nm-applet ] ; then
   nm-applet --sm-disable &
fi

if [ -x /usr/bin/gnome-power-manager ] ; then
   sleep 3
   gnome-power-manager
fi

exec xmonad

This uses xsetroot to set my background color. It can also use images; see its manpage for more.

Then we fire up trayer, the icon tray. The options tell it to go on the top right, with a default width of 10% of the screen (to nicely match up with the status bar, which we set to a width of 90% of the screen). We give it a color and a height.

Then we fire up gajim, the screensaver daemon, and if installed, the network manager applet and the power manager.

Finally, we start xmonad.

Mission accomplished!

Final Touches

There may be some programs that you don't want xmonad to tile. The classic example is Gimp. It pops up all sorts of new windows all the time, and they work best at defined sizes. It makes sense for xmonad to ignore them. Over at the general tips page, there are suggestions on how to accomplish this. The xmonad FAQ has instructions on using xprop to find the class (or other properties) of your window.

We are going to compose a list like so:

myManageHook = composeAll
    [ className =? "Gimp"      --> doFloat]

I also don't want xmonad to tile the VNC viewer, because I want to manage its size myself. Very well; I can add it:

myManageHook = composeAll
    [ className =? "Gimp"      --> doFloat
    , className =? "Vncviewer" --> doFloat
    ]

Now, we tie that in with what we're already doing for the manageHook, so our manageHook bit of main looks like:

    xmonad $ defaultConfig
        { manageHook = manageDocks <+> myManageHook
                        <+> manageHook defaultConfig

The full ~/.xmonad/xmonad.hs now looks like this:

import XMonad
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageDocks
import XMonad.Util.Run(spawnPipe)
import XMonad.Util.EZConfig(additionalKeys)
import System.IO

myManageHook = composeAll
    [ className =? "Gimp"      --> doFloat
    , className =? "Vncviewer" --> doFloat
    ]

main = do
    xmproc <- spawnPipe "/path/to/xmobarbinary /home/jgoerzen/.xmobarrc"
    xmonad $ defaultConfig
        { manageHook = manageDocks <+> myManageHook -- make sure to include myManageHook definition from above
                        <+> manageHook defaultConfig
        , layoutHook = avoidStruts  $  layoutHook defaultConfig
        , logHook = dynamicLogWithPP $ xmobarPP
                        { ppOutput = hPutStrLn xmproc
                        , ppTitle = xmobarColor "green" "" . shorten 50
                        }
        , modMask = mod4Mask     -- Rebind Mod to the Windows key
        } `additionalKeys`
        [ ((mod4Mask .|. shiftMask, xK_z), spawn "xscreensaver-command -lock")
        , ((controlMask, xK_Print), spawn "sleep 0.2; scrot -s")
        , ((0, xK_Print), spawn "scrot")
        ]

Tips on daily use

Here are a few things that occurred to me as I was learning xmonad.

Minimizing Windows

xmonad doesn't have a "minimize" feature. So I've designated workspace 9 for this purpose. When I want to hide a window, I Mod-Shift-9 it. That makes it go away. When I want it back, it's Mod-9, the Mod-j or Mod-k to select it, then Mod-Shift-1 Mod-1 or whatnot to zip it back and go back. It works surprisingly well.

Use of workspaces

I used to use KDE, and I used workspaces there too. But with the ability to so easily zip windows around to different workspaces, and to instantaneously change between them using only the keyboard, it's a lot easier to use.

Also, I find myself not wanting to have quite as many windows open on a given desktop at once. I generally have desktop 1 be for shells, 2 for email/IM, 3 for web, and 9 for music/minimized stuff. But I'm just learning this so far, and may find a better way. Don't hesitate to try different ways of organizing and use what works for you.

Trouble?

Check ~/.xsession-errors first.