jump to navigation

Xmonadの設定 3/3「応用」編

2010-02-20 17:50 Posted by
nase
in : ソフトウェア
flow3.jpg

タイル型ウィンドウマネージャの多くは、設定ファイル次第で自分好みの環境を構築することができます。

特にXmonadの場合、沢山のcontribモジュールが用意されているので、これらを設定ファイルに組み込んでゆくだけで様々な効果が得られます。

私の設定ファイルは導入直後ということもあり大した内容ではありませんが、いくつかの便利な設定について紹介したいと思います。

xmonad.hs

先に紹介したGNOME関連の設定等も含め、私の現在の~/.xmonad/xmonad.hsは以下のようになっています。

import Control.OldException
import Control.Monad
import DBus
import DBus.Connection
import DBus.Message
import XMonad
import XMonad.Config.Gnome
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageHelpers (doCenterFloat)
import XMonad.Util.Run (spawnPipe)
import XMonad.Util.EZConfig
import XMonad.Util.WorkspaceCompare
import System.IO
import Data.List -- isPrefixOf,isSuffixOf,isInfixOfを使用可能に
import Control.Monad (liftM2)
import qualified XMonad.StackSet as W
import XMonad.Actions.CycleWS
import XMonad.Layout.MultiToggle
import XMonad.Layout.MultiToggle.Instances
import XMonad.Config.Desktop (desktopLayoutModifiers)
import XMonad.Layout.Named

getWellKnownName :: Connection -> IO ()
getWellKnownName dbus = tryGetName `catchDyn` (\ (DBus.Error _ _) -> getWellKnownName dbus)
 where
  tryGetName = do
    namereq <- newMethodCall serviceDBus pathDBus interfaceDBus "RequestName"
    addArgs namereq [String "org.xmonad.Log", Word32 5]
    sendWithReplyAndBlock dbus namereq 0
    return ()

-- ウィンドウ作成時のデフォルトワークスペースを指定
myManageHookShift = composeAll
    [ className =? "Firefox"                --> viewShift "1"
    , fmap ("Gimp" `isPrefixOf`) className  --> viewShift "1"
    , className =? "Gvim"                   --> viewShift "2"
    , className =? "Gnome-terminal"         --> viewShift "2"
    ]
    where viewShift = doF . liftM2 (.) W.view W.shift
-- ウィンドウ作成時のフローティングを指定
myManageHookFloat = composeAll
    [ (fmap ("Gimp" `isPrefixOf`) className <&&> fmap (not . ("gimp-image-window" `isInfixOf`)) role) --> doFloat
    , className =? "Smplayer"              --> doCenterFloat
    ]
    where role = stringProperty "WM_WINDOW_ROLE"

myWorkspaces = ["1","2","3","4","5","6","7","8","9"]

myKeys =
    -- screensaver起動
    [ ("C-M-l", spawn "gnome-screensaver-command -a")
    -- CycleWS setup
    , ("M-n", moveTo Next NonEmptyWS)
    , ("M-p", moveTo Prev NonEmptyWS)
    -- カレントウィンドウを最初の未使用ワークスペースへ移動
    , ("M-S-n", do t <- findWorkspace getSortByIndex Next EmptyWS 1
                   (windows . W.shift) t
                   (windows . W.greedyView) t)
    , ("M-S-p", shiftTo Prev EmptyWS)
    -- フルスクリーンをトグル(MultiToggle)
    , ("M-f", sendMessage $ Toggle FULL)
    -- 画面リセット(スクリーン1でワークスペース2を開き、スクリーン0でワークスペース1を開く)
    , ("M-S-r", do
        screenWorkspace 1 >>= flip whenJust (windows.W.view)
        (windows . W.greedyView) "2"
        screenWorkspace 0 >>= flip whenJust (windows.W.view)
        (windows . W.greedyView) "1")
    -- デフォルトキーバインドの退避
    , ("M-r", refresh)
    , ("M-S-,", sendMessage Shrink)
    , ("M-S-.", sendMessage Expand)
    ]
    ++ -- (S-)M-h/lでスクリーン切り替え
    [((m ++ "M-" ++ [key]), screenWorkspace sc >>= flip whenJust (windows . f))
        | (key, sc) <- zip "hl" [0..]
        , (f, m) <- [(W.view, ""), (W.shift, "S-")]]

tall = Tall 1 (3/100) (1/2)

main :: IO ()
main = withConnection Session $ \ dbus -> do
    putStrLn "Getting well-known name."
    getWellKnownName dbus
    putStrLn "Got name, starting XMonad."
    xmonad $ gnomeConfig
        { workspaces = myWorkspaces
        , manageHook = myManageHookShift
                        <+> myManageHookFloat
                        <+> manageHook gnomeConfig
        , layoutHook = mkToggle1 FULL $ desktopLayoutModifiers (named "V" tall ||| (named "H" $ Mirror tall))
        -- xmonad-log-appletの設定
        , logHook    = do
            logHook gnomeConfig
            dynamicLogWithPP $ defaultPP {
                         ppOutput   = \ str -> do
                           let str'  = "<span font=\"UmePlus P Gothic\" weight=\"bold\">" ++ str ++ "</span>"
                           msg <- newSignal "/org/xmonad/Log" "org.xmonad.Log" "Update"
                           addArgs msg [String str']
                           -- If the send fails, ignore it.
                           send dbus msg 0 `catchDyn` (\ (DBus.Error _name _msg) -> return 0)
                           return ()
                       , ppTitle    = pangoColor "#003366" . shorten 60 . escape
                       , ppCurrent  = pangoColor "#003366" . wrap "[" "]"
                       , ppVisible  = pangoColor "#006666" . wrap "_" ""
                       , ppHidden   = wrap "" ""
                       , ppUrgent   = pangoColor "red"
                       }
        -- modキーに無変換キーを設定
        , modMask = mod3Mask
        -- ターミナル設定
        , terminal           = "gnome-terminal"
        -- 外観設定
        , borderWidth        = 2
        , normalBorderColor  = "#333333"
        , focusedBorderColor = "#cd8b00"
        } `additionalKeysP` myKeys

pangoColor :: String -> String -> String
pangoColor fg = wrap left right
 where
  left  = "<span foreground=\"" ++ fg ++ "\">"
  right = "</span>"

escape :: String -> String
escape = concatMap escapeChar
escapeChar :: Char -> String
escapeChar '<' = "&lt;"
escapeChar '>' = "&gt;"
escapeChar '&' = "&amp;"
escapeChar '"' = "&quot;"
escapeChar c = [c]

ワークスペースまわり

XMonad.Actions.CycleWSは、ワークスペースまわりのキーバンドを気の利いた感じにできます。私は次のように使っています。

  • mod-n/pで次/前の空でないワークスペースへ切り替え
  • mod-S-n/pでカレントウィンドウを次/前の空のワークスペースへ送る

設定は以下の部分。

-- import部分
import qualified XMonad.StackSet as W
import XMonad.Util.WorkspaceCompare
import XMonad.Actions.CycleWS
-- キーバインド定義部分
    , ("M-n", moveTo Next NonEmptyWS)
    , ("M-p", moveTo Prev NonEmptyWS)
    , ("M-S-n", do t <- findWorkspace getSortByIndex Next EmptyWS 1
                   (windows . W.shift) t
                   (windows . W.greedyView) t)
    , ("M-S-p", shiftTo Prev EmptyWS)

mod-S-nだけちょっと凝った書き方になっているのは、ウィンドウを送ると同時に表示も移動先ワークスペースに切り替えるためです。

レイアウトまわり

標準ではmod-spaceする度に「縦分割」→「横分割」→「フル」の順でレイアウト表示が変更されますが、個人的にこの挙動は好みではありません。

mod-spaceは「縦分割」→「横分割」の変更のみにして、いつでもmod-fでフルスクリーンをトグルできるようにしました。

-- import部分
import XMonad.Layout.MultiToggle
import XMonad.Layout.MultiToggle.Instances
import XMonad.Config.Desktop (desktopLayoutModifiers)
import XMonad.Layout.Named
-- キーバインド定義部分
    , ("M-f", sendMessage $ Toggle FULL)
-- 変数定義部分
tall = Tall 1 (3/100) (1/2)
-- layoutHook部分
        , layoutHook = mkToggle1 FULL $ desktopLayoutModifiers (named "V" tall ||| (named "H" $ Mirror tall))

見ての通り、加えてレイアウトの表示名をV(ertical)とH(orizontal)に変更しています。

デュアルディスプレイまわり

スクリーンの切り替えキーバインドは標準ではmod-w/eですが、これをmod-h/lに変更しました。

-- キーバインド定義部分
++ -- (S-)M-h/lでスクリーン切り替え
[((m ++ "M-" ++ [key]), screenWorkspace sc >>= flip whenJust (windows . f))
    | (key, sc) <- zip "hl" [0..]
    , (f, m) <- [(W.view, ""), (W.shift, "S-")]]

デュアルディスプレイで使う場合、ワークスペースの表示をリセットするキーバインドを定義しておくと、使用ワークスペースが増えてきてもすぐにメイン環境に戻れて便利です。

-- キーバインド定義部分
-- 画面リセット(スクリーン1でワークスペース2を開き、スクリーン0でワークスペース1を開く)
, ("M-S-r", do
    screenWorkspace 1 >>= flip whenJust (windows.W.view)
    (windows . W.greedyView) "2"
    screenWorkspace 0 >>= flip whenJust (windows.W.view)
    (windows . W.greedyView) "1")

おわりに

これらの設定で、ある程度は使いやすい環境になってきました。ただ、Xmonadの真価はまだまだこの程度のものではないと思います。

調べきれていない部分が多いので、引き続き役立ちそうな情報を見つけたら随意公開してゆきます。

Xmonadは現在のところまだ日本語情報も少ない状況なので、今回の連載をきっかけに興味を持つ人が増えれば幸いです。

連載一覧

Comments»

no comments yet


*Comments and trackbacks will appear after it is approved by the administrator.