- もちろん Gentoo
- ghc-7.8.4
- xmonad-0.11-r1
- xmonad-contrib-0.11.2
1. startupHook
startupHook
を利用して,従来 .xinitrc に書いていたものを少し xmonad のほうに持ってきた.とはいえ .xinitrc との棲み分けをちゃんとできているわけではなく,適当.import XMonad.Util.Cursor -- setDefaultCursor
import XMonad.Util.Run -- unsafeSpawn, spawnPipe, hPutStrLn
main = do
myStatusBar <- spawnPipe "xmobar"
xmonad $ ewmh
$ defaultConfig {
layoutHook = myLayoutHook
, manageHook = myManageHook
, handleEventHook = myHandleEventHook
, modMask = myModMask
, logHook = myLogHook myStatusBar
, startupHook = myStartupHook
}
`additionalKeysP` myAdditionalKeysP
myStartupHook = do
setDefaultCursor xC_left_ptr
unsafeSpawn "thunderbird"
unsafeSpawn "pidgin"
startupHook
は X ()
の型として定義されている.ghci> :m +XMonad
ghci> :i startupHook
data XConfig (l :: * -> *)
= XConfig {..., startupHook :: !X (), ...}
-- Defined in ‘XMonad.Core’
xmonad における 「アクション」 はこれを満たす関数 (モナド) になっているので,スタートアップ時に実行したいアクションを (do
でつなげて) 列挙してやれば良い.上記の setDefaultCursor
はその名のとおりポインタを設定するもの.従来 xsetroot
コマンドで行っていたけれど,たまたま見つけたので使ってみたというレベルのもの.なお参考までに,.xinitrc は以下のようになっている.# ~/.xinitrc
xrdb -merge $HOME/.Xresources
xmodmap $HOME/.Xmodmap
autocutsel &
autocutsel -selection PRIMARY &
dispad
export GTK_IM_MODULE="uim"
export QT_IM_MODULE="uim"
uim-xim &
export XMODIFIERS="@im=uim"
exec xmonad
他のものも xmonad のほうに移せるだろうけれど,とりあえず残している.特に明確な基準はない.それから,
startupHook
を使用せずとも,xmonad
関数を呼び出す前の xmobar を spawn
しているところにアクションを列挙していけば同様のことができると想像している (試していないけれど).ただ,せっかく startupHook
という機構を用意してくれているので,戻り値が必要な特殊なケースを除けば,別のところにまとめておいたほうが見通しが良くなるのだと思う.2. additionalKeysP
前回はキーバインドの追加にadditionalKeys
を使用していたが,同様に XMonad.Util.EZConfig に用意されている additionalKeysP
を使用することにした.従来は xbindkeys で割り当てていたものを xmonad に持ってこようとしたときに,additionalKeysP
のほうが手軽に利用できるキーが多いようだったため.import XMonad.Util.Run -- unsafeSpawn
import XMonad.Util.EZConfig -- additionalKeysP
myAdditionalKeysP = [
--snip --
-- volume control
, ("<XF86AudioRaiseVolume>", unsafeSpawn "amixer set Master playback 10+")
, ("<XF86AudioLowerVolume>", unsafeSpawn "amixer set Master playback 10-")
, ("<XF86AudioMute>", unsafeSpawn "amixer set Master toggle")
]
利用できるキーは XMonad.Util.EZConfig で参照可能.3. xmonad と相性の悪いアプリケーションへの対応
3.1. mpv (MPlayer)
MPlayer の時からそうだったけれど,mpv でフルスクリーン表示にならないという問題があった.これはmanageHook
で mpv のウィンドウを float させてやることで解決する.import XMonad.Hooks.ManageHelpers -- isFullscreen, doFullFloat
myManageHook = manageDocks
<+> composeAll [
isFullscreen --> doFullFloat
, className =? "mpv" --> doFloat
-- snip --
]
3.2. Java Swing アプリケーション
JabRef など,Swing を利用した Java アプリケーションはうまく表示が行えないという問題があった.まさかウィンドウマネージャとの相性の問題だとは…….と思ったら FAQ にあった.4. その他
4.1. XMonad.Prompt.Shell
dmenu の代わりに XMonad.Prompt.Shell. 外部プログラムへの依存が減る,カスタマイズ性が高いといったところがメリット.import XMonad.Prompt -- XPConfig
import XMonad.Prompt.Shell -- shellPrompt
myAdditionalKeysP = [
("M-p", shellPrompt myXPConfig)
-- snip --
]
myXPConfig = defaultXPConfig {
font = "xft:sans-serif:size=6"
, bgColor = "black"
, fgColor = "grey"
, promptBorderWidth = 0
, position = Top
, alwaysHighlight = True
, height = 30
}
4.2. XMonad.Layout.HintedTile/XMonad.Layout.Renamed
Tall の代わりに XMonad.Layout.HintedTile. ターミナルのようなアプリケーションで 1 行以下の 「余り」 が出ないように,ウィンドウサイズのほうを調整 (縮小) する.場合によっては並んだウィンドウの高さや幅ががたがたになるので,Tall とどっちが良いかは好みによりそう.XMonad.Layout.Spacing も併用すると綺麗になることを期待したのだけれど,どうやら HintedTile とは相性が悪そう (ヒンティングしたあとにスペースを入れることになり,結果として全てのウィンドウでヒンティングが合わなくなる).それから,レイアウトに機能を足していくと名前が長くなってくるので,それをリネームするための XMonad.Layout.Remaned.
import XMonad hiding (Tall)
import XMonad.Layout.HintedTile
import XMonad.Layout.Renamed
myLayoutHook = renamed [CutWordsLeft 2]
$ smartBorders $ avoidStruts $ maximize $ minimize
$ (hintedTile Tall ||| hintedTile Wide)
||| (avoidStruts $ noBorders Full)
where
hintedTile = HintedTile nmaster delta ratio TopLeft
nmaster = 1
ratio = 1/2
delta = 3/100
4.3. XMonad.Layout.LayoutScreens
スクリーンのなかで workspace を切るという機能.最近 31.5 インチのディスプレイを買ったので,便利に使えるかどうかを試してみている.import XMonad.Layout.LayoutScreens -- layoutSplitScreen
import XMonad.Layout.TwoPane
myAdditionalKeysP = [
-- snip --
-- split screen
, ("M-M1-<Space>", layoutSplitScreen 2 (TwoPane (3/100) 0.7))
, ("M-M1-S-<Space>", rescreen)
]
4.4. XMonad.Hooks.InsertPosition
insertPosition
を使用して,新しいウィンドウがアクティブなウィンドウの次に来る,すなわち新しいウィンドウにマスタを取られないようにした.import XMonad.Hooks.InsertPosition
myManageHook = insertPosition Below Newer
<+> manageDocks
<+> composeAll [ -- snip -- ]
5. スクリーンショット
高解像度っぷりのアピールを含め.6. 現在の xmonad.hs
-- ~/.xmonad/xmonad.hs
import XMonad hiding (Tall)
import XMonad.Hooks.DynamicLog -- logHook-related
import XMonad.Hooks.EwmhDesktops -- ewmh, fullscreenEventHook
import XMonad.Hooks.InsertPosition
import XMonad.Hooks.ManageDocks -- manageDocks, avoidStruts, docksEventHook
import XMonad.Hooks.ManageHelpers -- isFullscreen, doFullFloat
import XMonad.Layout.HintedTile
import XMonad.Layout.LayoutScreens -- layoutSplitScreen
import XMonad.Layout.Maximize
import XMonad.Layout.Minimize
import XMonad.Layout.NoBorders -- smartBorders, noBorders
import XMonad.Layout.Renamed
import XMonad.Layout.TwoPane
import XMonad.Prompt -- XPConfig
import XMonad.Prompt.Shell -- shellPrompt
import XMonad.Util.Cursor -- setDefaultCursor
import XMonad.Util.EZConfig -- additionalKeysP
import XMonad.Util.Run -- unsafeSpawn, spawnPipe, hPutStrLn
import XMonad.Util.WorkspaceCompare -- getSortByXineramaRule
main = do
myStatusBar <- spawnPipe "xmobar"
xmonad $ ewmh
$ defaultConfig {
layoutHook = myLayoutHook
, manageHook = myManageHook
, handleEventHook = myHandleEventHook
, modMask = myModMask
, logHook = myLogHook myStatusBar
, startupHook = myStartupHook
}
`additionalKeysP` myAdditionalKeysP
myModMask = mod4Mask
myLayoutHook = renamed [CutWordsLeft 2]
$ smartBorders $ avoidStruts $ maximize $ minimize
$ (hintedTile Tall ||| hintedTile Wide)
||| (avoidStruts $ noBorders Full)
where
hintedTile = HintedTile nmaster delta ratio TopLeft
nmaster = 1
ratio = 1/2
delta = 3/100
myManageHook = insertPosition Below Newer
<+> manageDocks
<+> composeAll [
isFullscreen --> doFullFloat
, className =? "mpv" --> doFloat
, className =? "Gimp" --> doFloat
, className =? "Pidgin" --> doShift "9"
, className =? "Thunderbird" --> doShift "9"
]
myHandleEventHook = docksEventHook
<+> fullscreenEventHook
myLogHook h = dynamicLogWithPP xmobarPP {
ppSep = " | "
, ppTitle = xmobarColor "green" "" . shorten 80
, ppOutput = hPutStrLn h
, ppSort = getSortByXineramaRule
}
myStartupHook = do
setDefaultCursor xC_left_ptr
unsafeSpawn "thunderbird"
unsafeSpawn "pidgin"
myAdditionalKeysP = [
("M-p", shellPrompt myXPConfig)
, ("M-m", withFocused (sendMessage . maximizeRestore))
, ("M-n", withFocused minimizeWindow)
, ("M-S-n", sendMessage RestoreNextMinimizedWin)
-- toggle dock visibility
, ("M-b", sendMessage ToggleStruts)
-- split screen
, ("M-M1-<Space>", layoutSplitScreen 2 (TwoPane (3/100) 0.7))
, ("M-M1-S-<Space>", rescreen)
-- volume control
, ("<XF86AudioRaiseVolume>", unsafeSpawn "amixer set Master playback 10+")
, ("<XF86AudioLowerVolume>", unsafeSpawn "amixer set Master playback 10-")
, ("<XF86AudioMute>", unsafeSpawn "amixer set Master toggle")
-- other commands
, ("M-S-l", unsafeSpawn "alock -auth pam -bg blank")
, ("M-c", unsafeSpawn "chromium --incognito --force-device-scale-factor=1.6")
]
myXPConfig = defaultXPConfig {
font = "xft:sans-serif:size=6"
, bgColor = "black"
, fgColor = "grey"
, promptBorderWidth = 0
, position = Top
, alwaysHighlight = True
, height = 30
}