Clickable DZen2 Panel for XMonad
2009-09-02: Uploaded the config files package clickable-dzen2.tar.bz2, and the complete XMonad config is available on github.
Xmobar and dzen2 are two poplar status panel for XMonad, because they
can be hooked into the logHook and display the status of XMonad. But
they are not interactively friendly. Although I can use keyboard to
perform all the tasks, in very rare cases, I still want to be able to
use only one hand and the mouse.
Fortunately, latest version 1 of dzen2 supports mouse action on region. But XMonad does not support client command to invoke windows management command. Two tools wmctrl and xdotool can help to resolve this problem. The former can interact with any EWMH/NetWM compatible X Window Manager, and the latter can simulate keyboard input. So my solution is adding mouse action in dzen2, use wmctrl to switch desktop and xdotool to change layout.
Let XMonad use EWMH
XMonad.Hook.EwmhDesktops makes XMonad use the EWMH hints to tell panel applications about its workspaces and the windows therein. It is required by wmctrl, otherwise wmctrl cannot control windows and switch workspaces in XMonad.
Just follow the example in XMonad.Hooks.EwmhDesktops to enable EWMH:
import XMonad import XMonad.Hooks.EwmhDesktops main = do xmonad $ defaultConfig { layoutHook = ewmhDesktopsLayout $ layoutHook defaultConfig , logHook = ewmhDesktopsLogHook }
Format Dynamic Log
XMonad calls the logHook with every internal state update. The state
then is sent to status panel. The function dynamicLogWithPP can
simplify the output formatting. I use it to add ^ca for dzen2, which
is used to add mouse action. Following code let me switch to a
workspace by a left click on its name, and toggle layout by clicking
the layout indicator.
myDzenPP h = defaultPP { ppOutput = hPutStrLn h , ppCurrent = dzenColor "#f8f8f8" "DodgerBlue4" . pad , ppVisible = dzenColor "#f8f8f8" "LightSkyBlue4" . pad . dzenSwitchWs , ppUrgent = dzenColor "#f8f8f8" "red4" . pad . dzenSwitchWs . dzenStrip , ppHidden = pad . dzenSwitchWs , ppLayout = dzenColor "DarkOrange" "" . wrap "^ca(1,xdotool key Super_L+space)[" "]^ca()" , ppTitle = dzenColor "#61ce3c" "" . dzenEscape , ppSep = " " , ppWsSep = "|" } dzenSwitchWs :: String -> String dzenSwitchWs s = "^ca(1,switch-workspace.pl " ++ (show s) ++ ")" ++ s ++ "^ca()"
Layout indicator is formatted using ppLayout, in which I add a mouse
action. When it is clicked, xdotool sends a keyboard input
Super_L+space, which is the default shortcut to cycle layouts.
The function dzenSwitchWs adds a mouse action around the workspace
name. 1 indicates left button and switch-workspace.pl is a script
switching to workspace by name.
Function dzenStrip is required, because the workspace name passed to
ppUrgent has already formatted by ppVisible or ppHiden. The
color markups, white space padding and mouse action must be stripped
first.
dzenStrip :: String -> String dzenStrip = strip [] where strip keep x | null x || " " == x = keep | null keep && ' ' == head x = strip keep (tail x) | "^" `isPrefixOf` x = strip keep (drop 1 . dropWhile (/= ')') $ x) | otherwise = let (good,x') = span (/= '^') x in strip (keep ++ good) x'
Switch Workspace Script
The script should be executable and placed in a directory listed in
PATH.
File: switch-workspace.pl
#!/usr/bin/env perl use strict; die unless @ARGV && -x "/usr/bin/wmctrl"; open DESKLIST, "/usr/bin/wmctrl -d |"; while (<DESKLIST>) { chomp; split ' ', $_, 9; next if $_[-1] ne $ARGV[0]; system("/usr/bin/wmctrl -s $_[0]"); last; } close DESKLIST;
The script uses wmctrl -d to list workspaces, and uses wmctrl -s
switch to the matching workspace.
Complete xmonad.hs
File: xmonad.hs
import XMonad import XMonad.Hooks.DynamicLog import XMonad.Hooks.ManageDocks import XMonad.Hooks.EwmhDesktops import XMonad.Util.EZConfig(additionalKeys) import XMonad.Util.Run(spawnPipe) import System.IO import Data.List(isPrefixOf) dzenStrip :: String -> String dzenStrip = strip [] where strip keep x | null x || " " == x = keep | null keep && ' ' == head x = strip keep (tail x) | "^" `isPrefixOf` x = strip keep (drop 1 . dropWhile (/= ')') $ x) | otherwise = let (good,x') = span (/= '^') x in strip (keep ++ good) x' dzenSwitchWs :: String -> String dzenSwitchWs s = "^ca(1,switch-workspace.pl " ++ (show s) ++ ")" ++ s ++ "^ca()" myDzenPP h = defaultPP { ppOutput = hPutStrLn h , ppCurrent = dzenColor "#f8f8f8" "DodgerBlue4" . pad , ppVisible = dzenColor "#f8f8f8" "LightSkyBlue4" . pad . dzenSwitchWs , ppUrgent = dzenColor "#f8f8f8" "red4" . pad . dzenSwitchWs . dzenStrip , ppHidden = pad . dzenSwitchWs , ppLayout = dzenColor "DarkOrange" "" . wrap "^ca(1,xdotool key Super_L+space)[" "]^ca()" , ppTitle = dzenColor "#61ce3c" "" . dzenEscape , ppSep = " " , ppWsSep = "|" } main = do dzen <- spawnPipe "dzen2 -ta l -fg grey80 -bg grey20 -e 'button3='" xmonad $ defaultConfig { manageHook = manageDocks <+> manageHook defaultConfig , layoutHook = ewmhDesktopsLayout $ avoidStruts $ layoutHook defaultConfig , logHook = ewmhDesktopsLogHook >> (dynamicLogWithPP $ myDzenPP dzen) , modMask = mod4Mask }
No related posts.

能不能以打包的形式共享一下配置:)
@transtone
shared
Good tutorial, but there is an easier way:
http://www.arch-ed.dk/wiki/doku.php?id=clickable_workspaces
@Archer
Thanks for shareing.
My solution uses wmctrl to switch workspace because I use XMonad.Actions.DynamicWorkspaces. It is used to create new workspace dynamically.