xmonadとxmobarの設定

(追記：2015/03/11 [新たに更新](http://qiita.com/ssh0/items/b92d9ab61eb5c92faa3e)しました。現在はこちらの設定を使用しています。)

以前はウィンドウマネージャーとしてタイル型WMの[awesomeを使用していました](http://qiita.com/ssh0/items/c7ad3470a9852bdae3a7)が、現在は同じくタイル型のWMであるxmonadを使用しています。今回はその設定を晒すことにします。

awesomeからxmonadに移行した理由は2つ。

1. マルチディスプレイ対応の差
2. タイル間のスペース表示

1に関しては、自分の設定が良くなかっただけかもしれませんが、awesomeではどうしてもマルチディスプレイ環境でうまく表示してくれませんでした。その点xmonadは最初からきちんと表示してくれ、クラッシュすることもなかったので、良いです。

2でawesomeからxmonadに移行した人は多いんじゃないかと思います(笑)いや、だってスクリーンショット色々見てたら、タイルの間にスペースあるの、すごくかっこよく見えたんですもん。そりゃ使いたくなりますよ。

xmonadの導入については何人かの方が既に書いていますので、そちらを参考にしてください。一つ重ねて注意すると、インストールしたからと言ってすぐにログアウトして試してみるのはやめましょう。初期状態では壁紙すら表示されず、操作方法もわからないため結局再起動させるはめになったりします（経験談）。逸る気持ちを抑えて、きちんと他の環境で説明を読みながら実行するようにしましょう。もしくは最初から設定ファイルを書いておいてしまいましょう。

以下では、xmonadの設定ファイルである~/.xmonad/xmonad.hsの設定と、ステータスバーxmobarの設定ファイル~/.xmonad/xmobarrcを紹介したいと思います。

#xmonadの設定

```haskell:~/.xmonad/xmonad.hs

import qualified Data.Map as M

import XMonad
import qualified XMonad.StackSet as W  -- myManageHookShift

import Control.Monad (liftM2)          -- myManageHookShift
import System.IO                       -- for xmobar

import XMonad.Actions.WindowGo
import XMonad.Actions.CycleWS
import XMonad.Hooks.DynamicLog         -- for xmobar
import XMonad.Hooks.EwmhDesktops
import XMonad.Hooks.FadeWindows
import XMonad.Hooks.ManageDocks        -- avoid xmobar area
import XMonad.Hooks.Place
import XMonad.Layout
import XMonad.Layout.DragPane          -- see only two window
import XMonad.Layout.Gaps
import XMonad.Layout.IM
import XMonad.Layout.Magnifier         -- this makes window bigger
import XMonad.Layout.MultiToggle
import XMonad.Layout.MultiToggle.Instances
import XMonad.Layout.Named
import XMonad.Layout.NoBorders         -- In Full mode, border is no use
import XMonad.Layout.ResizableTile     -- Resizable Horizontal border
import XMonad.Layout.Spacing           -- this makes smart space around windows
import XMonad.Layout.Tabbed
import XMonad.Layout.ThreeColumns      -- for many windows
import XMonad.Layout.ToggleLayouts     -- Full window at any time
import XMonad.Util.EZConfig            -- removeKeys, additionalKeys
import XMonad.Util.Run(spawnPipe)      -- spawnPipe, hPutStrLn
import XMonad.Util.Run

import Graphics.X11.ExtraTypes.XF86

tall = ResizableTall 1 (3/100) (1/2) []

myWorkspaces = ["  main  ", "  browser  ", "  media  ", "  work  ", "  tray  "]
modm = mod4Mask

colorBlue      = "#857da9"
colorGreen     = "#88b986"
colorGray      = "#676767"
colorWhite     = "#d3d7cf"
colorGrayAlt   = "#313131"
colorNormalbg  = "#1a1e1b"

-- Define keys to remove
keysToRemove x =
    [
        -- Unused gmrun binding
          (modm .|. shiftMask, xK_p)
        -- Unused close window binding
        , (modm .|. shiftMask, xK_c)
        , (modm .|. shiftMask, xK_Return)
    ]
 
-- Delete the keys combinations we want to remove.
strippedKeys x = foldr M.delete (keys defaultConfig x) (keysToRemove x)

main :: IO ()

main = do
    wsbar <- spawnPipe myWsBar
    xmonad $ defaultConfig
       { borderWidth = 2
       , terminal = "urxvt"
       , normalBorderColor = colorGray
       , focusedBorderColor = colorGreen
       , startupHook = myStartupHook
       , manageHook = placeHook myPlacement <+> myManageHookShift <+> myManageHookFloat <+> manageDocks
        -- any time Full mode, avoid xmobar area
       , layoutHook = toggleLayouts (noBorders Full) $ avoidStruts $ myLayout
        -- xmobar setting
       , logHook = myLogHook wsbar
       , handleEventHook = fadeWindowsEventHook
       , workspaces = myWorkspaces
       , modMask = modm }

       `additionalKeys`
       [ ((modm              , xK_f     ), sendMessage ToggleLayout)
       , ((modm              , xK_g     ), sendMessage ToggleGaps)
       , ((modm              , xK_l     ), sendMessage MirrorShrink)
       , ((modm              , xK_h     ), sendMessage MirrorExpand)
       , ((modm              , xK_Right ), nextWS ) -- go to next workspace
       , ((modm              , xK_Left  ), prevWS ) -- go to prev workspace
       , ((modm .|. shiftMask, xK_Right ), shiftToNext)
       , ((modm .|. shiftMask, xK_Left  ), shiftToPrev)
       , ((modm              , xK_comma ), sendMessage MagnifyLess)   -- smaller window
       , ((modm              , xK_period), sendMessage MagnifyMore)  -- bigger window
       , ((modm              , xK_j     ), windows W.focusDown)
       , ((modm              , xK_k     ), windows W.focusUp)
       , ((modm .|. shiftMask, xK_j     ), windows W.swapDown)
       , ((modm .|. shiftMask, xK_k     ), windows W.swapUp)
       , ((modm              , xK_w     ), nextScreen) ]

       `additionalKeys`
       [ ((modm .|. m, k), windows $ f i)
         | (i, k) <- zip myWorkspaces
                     [ xK_exclam, xK_at, xK_numbersign
                     , xK_dollar, xK_percent, xK_asciicircum
                     , xK_ampersand, xK_asterisk, xK_parenleft
                     , xK_parenright
                     ]
       , (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]
       ]

       `additionalKeys`
       [ ((mod1Mask .|. controlMask, xK_l      ), spawn "xscreensaver-command -lock")
       , ((modm                    , xK_Return ), spawn "urxvt")
       , ((modm                    , xK_c      ), kill) -- %! Close the focused window
       , ((modm                    , xK_p      ), spawn "exe=`dmenu_run -nb '#1a1e1b' -nf '#d3d7cf' -sb '#88b986' -sf '#1a1e1b'` && exec $exe")
       , ((mod1Mask .|. controlMask, xK_f      ), spawn "python /home/ssh0/Workspace/python/web_search/websearch.py")
       , ((0                       , 0x1008ff13), spawn "amixer -D pulse set Master 5%+ && paplay /usr/share/sounds/freedesktop/stereo/audio-volume-change.oga")
       , ((0                       , 0x1008ff11), spawn "amixer -D pulse set Master 5%- && paplay /usr/share/sounds/freedesktop/stereo/audio-volume-change.oga")
       , ((0                       , 0x1008ff12), spawn "amixer -D pulse set Master toggle")
        -- Brightness Keys
       , ((0                       , 0x1008FF02), spawn "xbacklight + 10")
       , ((0                       , 0x1008FF03), spawn "xbacklight - 10")

       ]

-- Handle Window behaveior
myLayout = (spacing 18 $ ResizableTall 1 (3/100) (3/5) [])
            |||  (spacing 2 $ (dragPane Horizontal (1/10) (1/2)))
            |||  (dragPane Vertical   (1/10) (1/2))


-- Start up (at xmonad beggining), like "wallpaper" or so on
myStartupHook = do
        spawn "gnome-settings-daemon"
        spawn "nm-applet"
        spawn "gnome-sound-applet"
        spawn "xscreensaver -no-splash"
        spawn "feh --bg-fill /media/ssh0/STOCK/Pictures/wallpapers/Abstract-gauss.jpg"
        spawn "compton --config /home/ssh0/.config/compton/compton.conf -b"
        spawn "/home/ssh0/.dropbox-dist/dropboxd"

-- some window must created there
myManageHookShift = composeAll
            -- if you want to know className, type "$ xprop|grep CLASS" on shell
            [ className =? "Firefox"   --> doShift "  browser  "
            , className =? "Mplayer"   --> doShift "  media  "
            ]
--             where viewShift = doF . liftM2 (.) W.view W.shift

-- new window will created in Float mode
myManageHookFloat = composeAll
            [ className =? "MPlayer"          --> doFloat,
              className =? "Gimp"             --> doFloat,
              className =? "Websearch.py"     --> doFloat,
              className =? "Plugin-container" --> doFloat,
              title     =? "Speedbar"         --> doFloat]


myLogHook h = dynamicLogWithPP $ wsPP { ppOutput = hPutStrLn h }

myWsBar = "xmobar /home/ssh0/.xmonad/xmobarrc"

wsPP = xmobarPP { ppOrder               = \(ws:l:t:_)   -> [ws,t]
                , ppCurrent             = xmobarColor   colorGreen       colorNormalbg
                , ppUrgent              = xmobarColor   colorWhite       colorNormalbg
                , ppVisible             = xmobarColor   colorWhite       colorNormalbg
                , ppHidden              = xmobarColor   colorWhite       colorNormalbg
                , ppHiddenNoWindows     = xmobarColor   colorGray        colorNormalbg
                , ppTitle               = xmobarColor   colorWhite       colorNormalbg
                , ppWsSep               = ""
                , ppSep                 = "  ::: "
                }

myPlacement = fixed (0.5, 0.5)

```


はじめにいろいろなモジュールをインポートしています。いろんなところから持ってきているので、多分いらない奴たくさん入ってます(笑)

デフォルトではAltキー(mod1Mask)に設定されているmodキーをWindowsキー/Superキー(mod4Mask)に変更しています。

設定ファイルに書いているキーバインドは以下

<table class="table table-condensed table-bordered">
  <tr><td><Strong>キー</Strong></td><td><Strong>やっていること</Strong></td></tr>
  <tr><td>Ctrl + Alt + l</td><td>スクリーンをロック</td></tr>
  <tr><td>Super + Return</td><td>端末urxvtを起動</td></tr>
  <tr><td>Super + c</td><td>フォーカスのあるウィンドウを削除</td></tr>
  <tr><td>Super + p</td><td>アプリケーションランチャーdmenuを起動。オプションは色の設定</td></tr>
  <tr><td>Ctrl + Alt + f</td><td> [以前に作成した簡易検索バーwebsearch.py](http://qiita.com/ssh0/items/7e70c8f72a0fa03df4b0)を起動</td></tr>
  <tr><td>音量アップボタン(0x1008ff13)</td><td>音量を上げてunity環境と同じ音でフィードバック</td></tr>
  <tr><td>音量ダウンボタン(0x1008ff11)</td><td>音量を下げてunity環境と同じ音でフィードバック</td></tr>
  <tr><td>ミュートボタン(0x1008ff12)</td><td>音量をミュート</td></tr>
  <tr><td>輝度アップボタン(0x1008FF02)</td><td>xbacklightを使って画面の明るさを上げる</td></tr>
  <tr><td>輝度ダウンボタン(0x1008FF03)</td><td>xbacklightを使って画面の明るさを下げる</td></tr>
  <tr><td>Super + f</td><td>全画面表示にするかの切り替え</td></tr>
  <tr><td>Super + l</td><td>(縦に並んだ)タイルの縦方向を短くする</td></tr>
  <tr><td>Super + h</td><td>(縦に並んだ)タイルの縦方向を長くする</td></tr>
  <tr><td>Super + Right</td><td>次(右)のワークスペースに移動する</td></tr>
  <tr><td>Super + Left</td><td>前(左)のワークスペースに移動する</td></tr>
  <tr><td>Super + Shift + Right</td><td>フォーカスのあるウィンドウを次のワークスペースに移動</td></tr>
  <tr><td>Super + Shift + Left</td><td>フォーカスのあるウィンドウを前にワークスペースに移動</td></tr>
  <tr><td>Super + j</td><td>フォーカスを次のウィンドウに移す</td></tr>
  <tr><td>Super + k</td><td>フォーカスを前のウィンドウに移す</td></tr>
  <tr><td>Super + Shift + j</td><td>フォーカスのあるウィンドウを次のタイル配置に移す</td></tr>
  <tr><td>Super + Shift + k</td><td>フォーカスのあるウィンドウを前のタイル配置に移す</td></tr>
  <tr><td>Super + w</td><td>次のスクリーンにフォーカスを移す</td></tr>
</table>

個人的に好きなレイアウト

```hs
spacing 18 $ ResizableTall 1 (3/100) (3/5) []
```

タイル間のスペース18pt、2個以降のウィンドウは全て右側に。横の比率は3対2

その他にFloat配置にするものを指定したり、表示するワークスペースを指定したりしています。

myStartupHookでログイン後すぐに自動で起動するアプリケーションを指定。xscreensaverとかdropboxとか。壁紙の指定もここで行います。

##スクリーンショット

![browser.jpg](https://qiita-image-store.s3.amazonaws.com/0/54869/b7867343-d8a0-688c-8659-85d7e3722dd8.jpeg)

![media.jpg](https://qiita-image-store.s3.amazonaws.com/0/54869/2ea0f532-ed33-6ba7-00ff-4f9b80ae7c66.jpeg)

![work.jpg](https://qiita-image-store.s3.amazonaws.com/0/54869/972b4727-2c88-7d6c-da75-d5b1fedd387f.jpeg)


#xmobarの設定

~/xmonad/xmonad.hsのmainの定義の中で

```haskell
wsbar <- spawnPipe myWsBar
xmonad $ defaultConfig
       {
       ...
        -- xmobar setting
       , logHook = myLogHook wsbar
       ...
       }
```

としておいて、その中身は

```
myLogHook h = dynamicLogWithPP $ wsPP { ppOutput = hPutStrLn h }

myWsBar = "xmobar /home/ssh0/.xmonad/xmobarrc"

wsPP = xmobarPP { ppOrder               = \(ws:l:t:_)   -> [ws,t]
                , ppCurrent             = xmobarColor   colorGreen       colorNormalbg
                , ppUrgent              = xmobarColor   colorWhite       colorNormalbg
                , ppVisible             = xmobarColor   colorWhite       colorNormalbg
                , ppHidden              = xmobarColor   colorWhite       colorNormalbg
                , ppHiddenNoWindows     = xmobarColor   colorGray        colorNormalbg
                , ppTitle               = xmobarColor   colorWhite       colorNormalbg
                , ppWsSep               = ""
                , ppSep                 = "  ::: "
                }
```

とします。
これでxmobarの色や表示する要素の選択ができます。レイアウトの表示は邪魔なので消しました。
統一感を出すために色にはこだわっています。


~/.xmonad/xmobarrcの中身は以下のようになっています。

フォントは日本語表示しても文字化けしないようにTakaoPGothic。Unicode絵文字があんまり使えないのはしょうがないか。
いいフォントがあったら教えていただきたいです。

```haskell:~/.xmonad/xmobarrc
-- -*- mode:haskell -*-
Config { font = "xft:TakaoPGothic-9:Bold"
       , bgColor = "#1a1e1b"
       , fgColor = "#676767"
       , position = Top
       , lowerOnStart = False
       , commands = [ Run Network "wlan0" [ "-t"       , " ⇩ <rx> : ⇧ <tx>"
                                          , "-L"       , "40"
                                          , "-H"       , "200"
                                          , "--normal" , "#d3d7cf"
                                          , "--high"   , "#88b986"
                                          ] 10

                    , Run MultiCpu        [ "-t"       , "<total0>.<total1>.<total2>.<total3>"
                                          , "-L"       , "40"
                                          , "-H"       , "85"
                                          , "--normal" , "#d3d7cf"
                                          , "--high"   , "#c16666"
                                          ] 50

                    , Run Memory          [ "-t"       , "<usedratio>%"
                                          , "-L"       , "40"
                                          , "-H"       , "90"
                                          , "--normal" , "#d3d7cf"
                                          , "--high"   , "#c16666"
                                          ] 10
                    , Run BatteryP        ["CMB1"]
                                          [ "-t"       , "<acstatus>"
                                          , "-L"       , "20"
                                          , "-H"       , "80"
                                          , "--low"    , "#c16666"
                                          , "--normal" , "#d3d7cf"
                                          , "--"
                                                , "-o" , "<left>% (<timeleft>)"
                                                , "-O" , "Charging <left>%"
                                                , "-i" , "<left>%"
                                          ] 50
                    , Run Date "%a %m/%d %H:%M" "date" 10
                    , Run StdinReader
                    ]
       , sepChar = "%"
       , alignSep = "}{"
       , template = " %StdinReader% }{≫%multicpu%  ≫%memory%  ≫%wlan0%  ≫%battery%  <fc=#c7a273>%date%</fc> "
       }
```

こうすると、左側は
![xmobar_left.jpg](https://qiita-image-store.s3.amazonaws.com/0/54869/a38905b4-0c13-dcbb-2169-581dc89f7bb9.jpeg)

のように、

右側は

![xmobar_right.jpg](https://qiita-image-store.s3.amazonaws.com/0/54869/94c396d6-3a89-e0eb-966d-cee18df69154.jpeg)

のように綺麗に表示してくれます。過不足なく、スッキリ表示できてるんじゃないかと思います。

comptonを使って影をつけたり透過処理を入れれば、すこしリッチな感じになります。

#まとめ

- haskell全然知らないけど、なんとかなった。
- タイル型やっぱり好き
- あうGtkテーマがなかなか見つからない