XMonadでカスタマイズ可能なマルチカラムレイアウトを
Table of Contents
はじめに
XMonadで3列以上のレイアウトを提供するモジュールとして、xmonad-contribのThreeColumns
とMultiColumns
が存在する。ThreeColumns
は3列固定のレイアウトで、MultiColumns
は列数が動的に増減するレイアウトだ。しかし、いずれのレイアウトも筆者の要求を満たすものではなく、新しいレイアウトを独自に作成するに至った。
それがStableColumns
というレイアウトで、事前に定義した列のキャパシティに応じてウィンドウを配置する。配置するための列が動的に増減せずStableであるという意味で名付けた。
本稿では、筆者が作成したマルチカラムレイアウトStableColumns
を紹介するとともに、どのような要求の下でこれを作ったのかを述べる。
要求1:列へのウィンドウの配置順をカスタマイズ
まず、3カラムレイアウトを使う時の筆者の代表的な使い方は以下のようなものだ。
- 左列:ターミナルを配置する作業用の領域
- 中央列:Webブラウザを配置する資料閲覧用の領域
- 右列:動画再生用の領域
そのためには、以下のような順序でウィンドウが配置されて欲しい。
しかし、ThreeColumns
ではこのような配置順にはならない。もし、ThreeCol 1 (3/100) (1/2)
のようにレイアウトを定義したなら、最初のウィンドウは一番左のメイン列に配置され、以降のウィンドウは右二つの列に交互に配置される。
そこで、理想の配置順を実現する設計として、列ごとに収納できるウィンドウの数(キャパシティ)を設定できようにすることを考えた。具体的には、多くともN個までのウィンドウを配置するStaticColumn、少なくともN個のウィンドウを配置するDynamicColumnという2つの列の変種を考えた。コード中の列の定義は以下のようになっている。
この時、列には以下のような手順でウィンドウが配置される。
- 定義されたすべての列を左から順に走査して、列のキャパシティが0になるまでウィンドウを配置する。
- 未配置のウィンドウをDynamicColumnの列に対して左から順に1枚ずつ配置する。
- 未配置のウィンドウがなくなるまで手順2を繰り返す。
この手順による実際のウィンドウの配置の流れを示す。まず、レイアウトに以下のような3つの列が設定されているとする。
この時、4つのウィンドウを配置することを考える。まず、手順1によって左列から順にキャパシティが0になるまでウィンドウを配置する。この場合、右列のみキャパシティを1残してすべてのウィンドウは配置される。未配置のウィンドウはないのでここで配置は終了し、配置は以下のようになる。
続いて、同じ設定で6つのウィンドウを配置することを考える。まず、手順1によってキャパシティの空いてる列に5つのウィンドウが配置される。すべてのキャパシティは消費されたので、残る1つのウィンドウは手順2によってDynamicColumnの最初の列(中央列)に配置される。
このアルゴリズムによって、ThreeColumns
相当のレイアウトも、2列や4列以上のレイアウトも実現できる柔軟性を手に入れることができた。なお、列のキャパシティはIncMasterN
メッセージによって、動的に増減させることができる。
要求2:列間の境界線をリサイズ
次は、列のリサイズについて考える。列が二つしかないならリサイズする方法は自明だが、列が三つ以上ある時にはリサイズする方法は二つ考えられる。一つは列そのものをリサイズする方法で、もう一つが列の境界をリサイズ方法だ。その違いを示したのが以下の図で、左列 を半分の幅に縮小した時のリサイズ結果の違いを表している。
図中のResult Aが左列そのものをリサイズした結果で、左列が縮小した分だけ中心と右の列の大きさが拡張されている。Result Bは左の列と中心の列の境界をリサイズした結果で、この場合は中心列の大きさのみが拡張されている。
この点について、ThreeColumns
ではどの列にフォーカスが当たっているかは関係なく、左列(ThreeColMid
なら中心列)しかリサイズできない。リサイズ方法としては前者の「列そのものをリサイズする方法」を取っている。
一方、StableColumns
では現在フォーカスのある列に対して、後者の「列の境界をリサイズする方法」でリサイズを実行する。これによってすべての列がリサイズ可能になるとともに、列をリサイズした時の動作が直感的に感じられるようになる。
StableColumnsを使用する
XMonadの設定ファイルはデフォルトではGHCによって直接コンパイルされる。この時、GHCにはコマンドラインオプションとして-ilib
が与えられるので、設定ディレクトリ内のlib
にHaskellソースを置くことで外部モジュールを読み込むことができる。
したがって、StableColumns
のようなパッケージ管理されていない外部モジュールを使用するには、lib
ディレクトリにソースを直接コピーすればいい。
XMonad.Layout.StableColumns
がimportできるようになったなら、レイアウトは以下ように定義できる。
レイアウトに対してメッセージを送信するキーバインドは以下のように定義できる。ShrinkRow
とExpandRow
はStableColumns
が独自に定義したResizeRow
型のコンストラクターで、他のメッセージはXMonad.Layout
からimportしたものだ。
まとめ
XMonadではxmonad-contribを利用することで様々なレイアウトを利用することができるが、細部で自分の好みに合わない所がある場合もある。XMonadのレイアウト関数はRectangle
とWindow
のペアの一覧を返すだけの単純なものなので、Haskellが書けるなら(それが難しいかもしれないが)レイアウトをフォークして改造することは容易だ。StableColumns
の実装もThreeColumns
をフォークする所から始まった。
今回のStableColumns
についてもあくまで作者の使い方に合うよう作られた実装なので、読者の好みには合わない部分があるかもしれない。それでも、今回の実装が改造のベースとして役立てれば嬉しい。