Skip to Content »

Tech Life of Recht » archive for 'xmonad'

 Gnome Do in XMonad

  • December 2nd, 2009
  • 10:15 pm

I recently started using Gnome Do as a launcher in xmonad - not to replace the good old XMonad.Prompt, but because it integrates quite nicely into some other OS features. For example, suspending is a matter of pressing Ctrl-Alt-space and entering susp. There are a lot of other nice features like that. I still use the regular XMonad.Prompt to start programs, as it works just fine for that.

To use Gnome Do with xmonad, I changed two things: I made sure that the Gnome Do window is ignored by xmonad, and I bound the popup key to Ctrl-Alt-space instead of the default mod4-space, which I use to switch layouts in xmonad.

Ignoring the window is simply a matter of adding a condition to the manageHook:

CODE:
  1. main = do din <- spawnPipe statusBarCmd
  2.   xmonad $ defaultConfig
  3.     {
  4.       manageHook = composeAll . concat $ [
  5.         [ className =? "Do" --> doIgnore ]
  6.       ]
  7.     }

To assign a new shortcut for the popup, simply press mod4-space to bring it up, and then click on the small arrow in the top right corner. Under Preferences->Keyboard, a new shortcut can be assigned.

 Karmic Koala

  • October 29th, 2009
  • 9:50 pm

Ubuntu 9.10 (Karmic Koala) is out, so I decided to upgrade. The upgrade process itself went fine, but it seems there were some other changes to the system, which affected me.

I'm running on a MacBook Pro Santa Rosa with 4 GB mem, which means that if I use the standard 32 bit kernel, I cannot use all of the memory. That's not really a problem, I just recompile the kernel to support PAE.
However, I also use XMonad (because it's the best window manager available), and previously I launched it from ~/.xsession. However, the new version of GDM doesn't support that anymore, so now you have to drop a file in /usr/share/xsessions/xmonad.desktop - mine contains this:

CODE:
  1. [Desktop Entry]
  2. Encoding=UTF-8
  3. Name=xmonad
  4. Comment=xmonad
  5. Exec=/pack/haskell/bin/runxmonad.sh
  6. Type=Application

Other than that, simply follow this little guide to make the keyboard and touchpad work properly.

 xmonad upgrade

  • May 1st, 2009
  • 9:10 am

Yesterday, I decided to upgrade my xmonad installation to the latest from the Darcs repository. There were no problems compiling the new version, but when I restarted X, xmonad wouldn't start. After digging in the log files, I found this error:

xmonad-i386-linux: getProcessStatus: does not exist

Very strange, and not much help on Google either. After fiddling around a little, I remembered that xmonad compiles the ~/.xmonad/xmonad.hs config file into a new executable, which is called xmonad-i386-linux, and is placed in ~/.xmonad. Remove the file and everything will work again.

The problem seems to be that a new patch in the repository changes the way xmonad launches child processes, but xmonad does not automatically detect that the configuration should also be recompiled.

 2008 wishes

  • December 29th, 2007
  • 3:02 pm

The coming of a new year usually attracts a number of predictions, some more accurate than others. I'm no good at predicting, so I'll give my wishes for the new year instead:

  • Get my Macbook Pro to work with the DVI-VGA adapter (done)
  • I'd like to be convinced that the dynamic languages are really the way forward. I see that they can do smart stuff, but I sorely miss some kind of help using whatever APIs are developed, besides the source code, and I can't get used to working without a proper editor. I can probably live without the editor, but having methods like def initialize (options = {}) just hurts my eyes. I haven't used Ruby/Rails that much, but I've already dug around more source code than I care to in order to find out what the legal options were.
  • Release Java 7 with proper closures. This probably won't happen, and even when it does, it will take a couple of years before it's adopted.
  • Already, I know that I'm going to spend a good part of my time fiddling around with huge WSDLs and schemas. Could somebody find a way to stop the black hole that is Web Services?
  • As for Linux on the desktop, that will still not happen, even though it should, especially when you look at the new distributions such as Ubuntu. However, I'm pretty satisfied, now I just need xmonad to support dynamic twinview, so I can add a monitor without restarting X
  • And to Apple: please take corporate customers seriously and make a docking station for the Macbook (Pro). I'm getting tired of plugging and unplugging 5 different cables every time I have to move my laptop.
  • Less focus on creating big monolithic systems, more on distributing across autonomous nodes.
  • Finally, it would be great with a proper vi-mode for Eclipse - like vimperator for Firefox.

 xmonad 0.5

  • December 16th, 2007
  • 12:57 am

xmonad 0.5 is out, and I haven't upgraded my installation in a while. It's pretty nice that configuration is now done in /.xmonad/xmonad.hs, then there's no need to recompile xmonad all the time. The configuration change did require a reorganisation of my old Config.hs, so I took a look at some of the samples to see what other people did.
I ended up with something which looks like this:

xmonad

This is my xmonad.hs:

CODE:
  1. -- XMonad Core
  2. import XMonad
  3. import XMonad.Layout
  4. import XMonad.Operations
  5. import qualified XMonad.StackSet as W
  6.  
  7. -- GHC hierarchical libraries
  8. import Data.Bits ((.|.))
  9. import qualified Data.Map as M
  10. import Graphics.X11
  11. import Graphics.X11.Xlib
  12. import Graphics.X11.Xlib.Extras
  13. import System.IO
  14.  
  15. -- Contribs
  16. import XMonad.Actions.CycleWS
  17. import XMonad.Actions.SwapWorkspaces
  18. import XMonad.Actions.Submap
  19. import XMonad.Actions.WindowBringer
  20. import XMonad.Actions.FloatKeys
  21.  
  22. import XMonad.Hooks.UrgencyHook
  23. import XMonad.Layout.NoBorders
  24. import XMonad.Layout.Tabbed
  25. import XMonad.Layout.WindowNavigation
  26. import XMonad.Layout.Grid
  27. import XMonad.Layout.LayoutHints
  28. import XMonad.Layout.Dishes
  29. import XMonad.Util.EZConfig
  30. import XMonad.Util.Run
  31.  
  32. import XMonad.Prompt.Shell
  33. import XMonad.Prompt
  34.  
  35. import XMonad.Hooks.DynamicLog   ( PP(..), dynamicLogWithPP, dzenColor, wrap, defaultPP )
  36.  
  37. myfont = "\"-xos4-terminus-medium-r-normal--12-120-72-72-c-60-iso8859-1\""
  38. fgcolor = "black"
  39. bgcolor = "white"
  40.  
  41. statusBarCmd= "dzen2 -e '' -w 660 -h 15 -ta l -xs 1 -fg " ++ fgcolor ++ " -bg " ++ bgcolor ++ " -fn " ++ myfont
  42.  
  43. -- Get ready!
  44. main = do din <- spawnPipe statusBarCmd
  45.           xmonad $ withUrgencyHook dzenUrgencyHook { args = ["-bg", "darkgreen", "-xs", "1"] }
  46.               $ defaultConfig
  47.                 { workspaces     = workspaces'
  48.                 , modMask        = modMask'
  49.                 , numlockMask    = 0
  50.                 , layoutHook     = layoutHook'
  51.                 , terminal       = "urxvtc || urxvt"
  52.     , normalBorderColor = "#dddddd"
  53.     , focusedBorderColor = "#3499dd"
  54.     , defaultGaps = [(15,0,0,0)]
  55.     , logHook = dynamicLogWithPP $ myPP din
  56.                 }
  57.                 `additionalKeys` keys'
  58.  
  59. modMask'    = mod4Mask
  60. workspaces' = map show [1] ++ ["web", "mail", "chat", "code"] ++ map show [6 .. 9 :: Int]
  61.  
  62. layoutHook' =
  63.     configurableNavigation noNavigateBorders $
  64.     layouts
  65. layouts =
  66.         Mirror tiled
  67.     ||| tiled
  68.     ||| Grid
  69.     ||| layoutHints Full
  70.     ||| Dishes 2 (1/5)
  71.     ||| noBorders (tabbed shrinkText
  72.                           defaultTConf { fontName = myfont })
  73.   where
  74.      tiled   = Tall nmaster delta ratio
  75.      nmaster = 2     -- The default number of windows in the master pane
  76.      ratio   = 1/2   -- Default proportion of screen occupied by master pane
  77.      delta   = 3/100 -- Percent of screen to increment by when resizing panes
  78. noFollow CrossingEvent {} = return False
  79. noFollow _                = return True
  80. keys' =
  81.     [ ((modMask' .|. shiftMask, xK_d        ), spawn "date | dzen2 -p 2 -xs 1") -- %! Print current date
  82.      , ((modMask', xK_p), shellPrompt defaultXPConfig)
  83.     ]
  84.     ++
  85.     -- modMask'-[1..0] %! Switch to workspace N
  86.     -- modMask'-shift-[1..0] %! Move client to workspace N
  87.     [((m .|. modMask', k), windows $ f i)
  88.         | (i, k) <- zip workspaces' $ [xK_1 .. xK_9] ++ [xK_0]
  89.         , (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]]
  90.     ++
  91.     -- modMask'-{e,r} %! Switch to physical/Xinerama screens 1 or 2
  92.     -- modMask'-shift-{e,r} %! Move client to screen 1 or 2
  93.     [((m .|. modMask', key), screenWorkspace sc>>= flip whenJust (windows . f))
  94.         | (key, sc) <- zip [xK_e, xK_w] [0..]
  95.         , (f, m) <- [(W.view, 0), (W.shift, shiftMask)]]
  96.     ++
  97.     [((modMask' .|. mod1Mask, k), windows $ swapWithCurrent i)
  98.         | (i, k) <- zip workspaces' $ [xK_1 .. xK_9] ++ [xK_0]]
  99.     -- float keys
  100.     ++
  101.     [
  102.       ((modMask',               xK_d     ), withFocused (keysResizeWindow (-10,-10) (1,1)))
  103.     , ((modMask',               xK_s     ), withFocused (keysResizeWindow (10,10) (1,1)))
  104.     , ((modMask',               xK_a     ), withFocused (keysMoveWindowTo (512,384) (1, 0)))
  105.     ]
  106.  
  107.  
  108. myPP h = defaultPP
  109.          { ppCurrent  = dzenColor "white" "#cd8b00" . pad
  110.          , ppVisible  = dzenColor "white" "#666666" . pad
  111.          , ppHidden   = dzenColor "black" "#cccccc" . pad
  112.          , ppHiddenNoWindows = dzenColor "#999999" "#cccccc" . pad
  113.          , ppWsSep    = dzenColor "#bbbbbb" "#cccccc" "^r(1x18)"
  114.          , ppSep      = dzenColor "#bbbbbb" "#cccccc" "^r(1x18)"
  115.          , ppLayout   = dzenColor "black" "#cccccc" .
  116.                         (\ x -> case x of
  117.                                   "TilePrime Horizontal" ->
  118.                                     " ^i(/home/emertens/images/tile_horz.xpm) "
  119.                                   "TilePrime Vertical"   ->
  120.                                     " ^i(/home/emertens/images/tile_vert.xpm) "
  121.                                   "Hinted Full"          ->
  122.                                     " ^i(/home/emertens/images/fullscreen.xpm) "
  123.                                   _                      -> pad x
  124.                         )
  125.          , ppTitle    = (' ':) . escape
  126.          , ppOutput   = hPutStrLn h
  127.          }
  128.   where
  129.   escape = concatMap (\x -> if x == '^' then "^^" else [x])
  130.   pad = wrap " " " "

I use a simple shell script for starting xmonad:

CODE:
  1. ssh-add ~/.ssh/id_dsa </dev/null>/dev/null
  2. Esetroot /usr/share/backgrounds/warty-final-ubuntu.png
  3. unclutter -idle 2 &
  4. urxvtd -f -o
  5. irxevent -d
  6.  
  7. gnome-settings-daemon &
  8. gnome-volume-manager &
  9.  
  10. export PATH=$PATH:`dirname $0`
  11. `dirname $0`/status &
  12.  
  13. xmonad

Finally, the dzen2 status bar is run using this script:

CODE:
  1. #!/bin/sh
  2.  
  3. BG=white
  4. FG=black
  5. FONT="-xos4-terminus-medium-r-normal--12-120-72-72-c-60-iso8859-1"
  6.  
  7. BFG="#444"
  8.  
  9. gcpubar -i 2 -fg '#444' -w 30 -h 10 | dzen2 -e '' -x 1360 -fg $FG \
  10.    -bg $BG -fn $FONT -h 15 -xs 1 &
  11.  
  12. while :; do
  13. MEM=`memstatus.awk /proc/meminfo`
  14. CPU=`cpustatus.awk`
  15. DATE=`date +"%d-%m %k:%M"`
  16.  
  17. REM=`awk '/remaining capacity/ { print $3 }' /proc/acpi/battery/BAT0/state`
  18. LAST=`awk '/last full/ { print $4}' /proc/acpi/battery/BAT0/info`
  19. STATE=`awk '{print $2}' /proc/acpi/ac_adapter/ADP1/state`
  20. if [ "$STATE" = "on-line" ]; then
  21.   BAT=$(echo $REM $LAST | awk '{printf "Bat: %.1f%%, AC", ($1/$2)*100'})
  22. else
  23.   PRESENT=`awk '/present rate/ { print $3}' /proc/acpi/battery/BAT0/state`
  24.   BAT=$(echo $REM $LAST $PRESENT | \
  25.     awk '{printf "Bat: %.1f%%, %d min", ($1/$2)*100, ($1/$3)*60}')
  26. fi
  27.  
  28. LOAD=`awk '{print $1 " " $2 " " $3}' /proc/loadavg`
  29.  
  30. echo "$CPU $MEM | $DATE | $BAT | $LOAD"
  31. sleep 5
  32. done | dzen2 -e '' -x 660 -w 700 -fg $FG -bg $BG -fn $FONT -h 15 -xs 1

Two awk scripts are used - one for the memory usage and one for CPU frequencies. Why awk? No idea, it just seemed like a good choice at the time.

memstatus.awk:

CODE:
  1. #!/usr/bin/awk -f
  2. BEGIN {
  3.   BG="darkgrey";
  4.   FG="#444";
  5.   WIDTH=30;
  6.   HEIGHT=10;
  7. }
  8.  
  9. /MemTotal/ {t=$2};
  10. /MemFree/ {f=$2};
  11. /SwapTotal/ {st=$2};
  12. /SwapFree/ {sf=$2};
  13.  
  14. END {
  15.   mw=int(WIDTH*(t-f)/t);
  16.   fw=WIDTH-mw;
  17.   sw=int(WIDTH*(st-sf)/st);
  18.  
  19.   printf("Mem: ^ib(1)^fg(%s)^r(%dx%d)^fg(%s)^r(%dx%d)" \
  20.     "^fg(%s)^r(2x%d)^fg(%s)^r(%dx%d)^fg(%s)^r(%dx%d)^ib(0)^fg()\n",
  21.     FG, mw, HEIGHT,
  22.     BG, fw, HEIGHT,
  23.     "black",
  24.     HEIGHT, BG, WIDTH-sw,
  25.     HEIGHT, FG, sw, HEIGHT);
  26. }

CODE:
  1. #!/usr/bin/awk -f
  2. BEGIN {
  3.   BG="darkgrey"
  4.   FG="#444"
  5.   WIDTH=30
  6.   HEIGHT=10
  7.   CPUS=0
  8.  
  9.   cmd = "ls /sys/devices/system/cpu"
  10.   while ((cmd | getline)> 0) {
  11.     if ($1 ~ /cpu/) {
  12.       CPUS++
  13.     }
  14.   }
  15.   close(cmd)
  16.  
  17.   printf "CPU: "
  18.   for (i=0; i <CPUS; i++) {
  19.     cfn="/sys/devices/system/cpu/cpu" i "/cpufreq/scaling_cur_freq"
  20.     mfn="/sys/devices/system/cpu/cpu" i "/cpufreq/scaling_max_freq"
  21.     getline cf <cfn
  22.     getline mf <mfn
  23.     cw=int(WIDTH*(mf-cf)/mf)
  24.  
  25.     printf("^ib(1)^fg(%s)^r(%dx%d)^fg(%s)^r(%dx%d)^ib(0)^fg()",
  26.       FG, cw, HEIGHT, BG, WIDTH-cw, HEIGHT)
  27.  
  28.     close(cfn)
  29.     close(mfn)
  30.  
  31.     if (i <CPUS - 1) {
  32.       printf("^ib(0)^fg()^r(5x0)^ib(1)")
  33.     }
  34.  
  35.   }
  36.   printf("\n");
  37. }

 My xmonad start script

  • October 25th, 2007
  • 10:54 pm

After reinstalling xmonad on my laptop using Ubuntu as the base distribution, I've finally got a setup I like, so I thought I'd share it. So, here is my script which starts xmonad:

CODE:
  1. ssh-add ~/.ssh/id_dsa </dev/null>/dev/null
  2.  
  3. Esetroot /usr/share/backgrounds/warty-final-ubuntu.png
  4. unclutter -idle 2 &
  5.  
  6. urxvtd -f -o
  7.  
  8. gnome-settings-daemon &
  9. gnome-power-manager
  10. gnome-volume-manager &
  11.  
  12. BG=white
  13. FG=black
  14. FONT="-xos4-terminus-medium-r-normal--12-120-72-72-c-60-iso8859-1"
  15.  
  16. export PATH=$PATH:`dirname $0`
  17.  
  18. # create a pipe for xmonad to talk to
  19. PIPE=$HOME/.xmonad-status
  20. rm -f $PIPE
  21. mkfifo -m 600 $PIPE
  22. [ -p $PIPE ] || exit
  23.  
  24. # and a workspace status bar, reading's xmonad's stdout
  25. dzen2 -e '' -w 680 -ta l -fg $FG -bg $BG -fn $FONT -h 15 <$PIPE &
  26.  
  27. `dirname $0`/status &
  28.  
  29. xmonad> $PIPE &
  30. wait $!
  31.  
  32. pkill -HUP dzen2
  33.  
  34. wait

This script is launched from ~/.xsession. It uses dzen and some of the dzen gadgets (which must be compiled separately from dzen/gadgets). It also starts some of the Gnome daemons which normally run under Ubuntu. This means that power management and sound volume goes through Gnome, and devices are mounted automatically when they are added to the system.

Two dzens are launched: One for displaying workspaces and one for general status. The general status script looks like this:

CODE:
  1. #!/bin/sh
  2.  
  3. BG=white
  4. FG=black
  5. FONT="-xos4-terminus-medium-r-normal--12-120-72-72-c-60-iso8859-1"
  6.  
  7. while :; do
  8. MEM=`awk '/MemTotal/ {t=$2}; /MemFree/ {f=$2}; END {print t-f " " t}' \
  9.   /proc/meminfo | dbar -s ':' -l 'Mem:' -w 10`
  10. CF0=$(echo `cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq` \
  11.   `cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq` | dbar -w 7 -l 'CPU0:')
  12. CF1=$(echo `cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq` \
  13.   `cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq` | dbar -w 7 -l 'CPU1:')
  14. DATE=`date +"%d-%m %k:%M"`
  15.  
  16. REM=`grep 'remaining capacity' /proc/acpi/battery/BAT0/state | awk '{print $3}'`
  17. LAST=`grep 'last full' /proc/acpi/battery/BAT0/info |awk '{print $4}'`
  18. STATE=`awk '{print $2}' /proc/acpi/ac_adapter/ADP1/state`
  19. if [ "$STATE" = "on-line" ]; then
  20.   BAT=$(echo $REM $LAST | awk '{printf "Bat: %.1f%%, AC", ($1/$2)*100'})
  21. else
  22.   PRESENT=`grep 'present rate' /proc/acpi/battery/BAT0/state | awk '{print $3}'`
  23.   BAT=$(echo $REM $LAST $PRESENT | awk '{printf "Bat: %.1f%%, %d min", ($1/$2)*100, ($1/$3)*60}')
  24. fi
  25.  
  26. LOAD=`awk '{print $1 " " $2 " " $3}' /proc/loadavg`
  27.  
  28. echo "$CF0 $CF1 $MEM | $DATE | $BAT | $LOAD"
  29. sleep 5
  30. done | dzen2 -e '' -x 440 -w 1000 -fg $FG -bg $BG -fn $FONT -h 15

The script is made for a MacBook Pro with a two core processor and acpi. It displays the CPU frequencies in a dbar, memory usage, battery status, and load. I would like to display network status too, but I can't figure out how to dig around in dbus efficiently, so that's still missing.

 MacBook Pro

  • October 24th, 2007
  • 11:04 pm

Last week, we had some of the local drugheads come into the office at night, and they ran off with my laptop, and 6 other laptops. I had a trusty Lenovo Thinkpad z61m with Ubuntu (and xmonad, of course), which is now gone, together with whatever I had on it. Naturally, I didn't have backup of everything, but at least all of my code was checked into Subversion, so the most critical I'm missing now are some course material.
Luckily, it didn't take long before we got permission to go out and buy some new laptops (this is one of the great things when you're working for a small company: no company procedures which have to be followed). We were told that we should probably go for a IBM, HP or Apple laptop. Now, I don't know about you, but when I buy new hardware, I can't just decide. It takes a couple of days (or even weeks), so deciding what to buy and live with for the next couple of years in half an hour certainly wasn't easy. In the end, I got a MacBook Pro with a 15" display - but only after confirming that it could run Linux, in case OS X got on my nerves too much.
Having lived with xmonad for a couple of months, it didn't take long before I decided that OS X might be pretty nice, but there's just too much focus on the looks, so I installed rEFIt, downloaded the new Ubuntu 7.10 and installed it.

I had anticipated some problems installing, as some of the experience reports on the net indicated that some things might go wrong, but that didn't really happen. Everything just installed (tm) - almost: The wireless driver had to be compiled from Subversion. Other than that, everything works: X, accellerated graphics, Xinerama/TwinView, sound, webcam, temp. sensors, keyboard lights, and touchpad with different zones. Only two things aren't working: The remote control and suspend to ram.
I can live without the remote control (actually, I can't really imagine what I should use it for if it worked), but the missing software suspend is not exactly optimal. It doesn't help that it's not consistent: Sometimes it can actually suspend and resume correctly. Using 'pm-suspend --quirk-post-vbe' seems to increase the number of times it works.
At other times, it doesn't suspend. Sometimes, it just blanks the screen, and nothing else happend. It can also switch to console with a blinking cursor, and then nothing else happend. Sometimes bliking the cursor is so hard it has to turn on the fans. No matter what, a cold boot is the only way forward.
If it manages to suspend, resume often fails. When this happens, the disk turns on, but the screen doesn't, and there's no response to any keypresses. Again, cold boot is the way forward.
I haven't managed to identify why software suspend doesn't work. The only hint I have is that if the network cable is unplugged when I suspend, it seems to suspend successfully more often than else. Acpid should unload the network drivers before suspend, so I can't see why this has anything to do with it. I'm hoping a kernel upgrade will fix it at some point.

 The xmonad experience

  • October 1st, 2007
  • 6:28 pm

I've been running xmonad on both my desktop computer at home and my laptop at work, and overall I'm pretty happy about it. However, I've had to work around some stuff:

  • There's no fancy graphical tools like the default Ubuntu desktop. This means no network-manager, no battery monitor, and so on. For the network manager (nm-applet), I've used knetworkmanager - almost the same, but it works a little better. I usually just run knetworkmanager, connects to the right network, and closes it again.
  • Battery is monitored through dzen
  • For mounting and unmounting devices, something that Ubuntu did automatically, I use pmount directly.
  • I use mplayer through kplayer, a KDE mplayer wrapper, which makes it possible to run movies in a large window with the ratio preserved, something I've not been able to with the command line directly.

Other than that, there's not much to it. It does attract some interest, though. Today, I held a course on Java and Web services, and someone asked me what type of Linux I ran. Not regarding the wrongness of the question, I answered "xmonad" - and there was 5 seconds silence, followed by a vague "ah...".