Linuxを使っていてよかったうちの1つがタイル型ウィンドウマネージャがすごく便利なことでした。
前までは1つのスペース(仮想デスクトップ)でCommand+Tabを酷使してウィンドウ管理をしていたのですが、Linuxでi3wmというタイル型ウィンドウマネージャを使ってみたらすごく便利だったのでぜひmacOSでも使いたいと思ってました。
ただmacOSのタイル型ウィンドウマネージャで有名なAmethystは私的には微妙で他のタイル型ウィンドウマネージャを探したところ、chunkwmがなかなかよかったのでその備忘録です。
注意: chunkwmは2018/1現在Alpha版です。私が使っている限りでは比較的安定していますが、ときどきバグっぽい挙動があったり仕様が変わる可能性があります。
また、設定はGUIではなくCLIからなのである程度Terminalからのコマンド操作になれていることが前提です。
環境
- MacBookPro mid 2015
- macOS High Sierra
- chunkwm 0.2.36
chunkwmとは
作者が同じタイル型ウィンドウマネージャであるkwmの後継でプラグインアーキテクチャを使い拡張性が高い?ウィンドウマネージャです。
bspwmに影響を受けているらしいですが、私はbspwmは使ったことないのでよくわかりません。
ただ使ってみた感じ、ウィンドウ管理においてi3に似た操作感を実現できる気がしました(気がしただけでやっぱり違うけど)
こんな感じでウィンドウが重ならないように分割できます。
(画質が荒いのはffmpeg+gifsicleで圧縮したらやりすぎた)
インストール
brew tapしてinstallができます。
# clone tap
brew tap crisidev/homebrew-chunkwm
# install latest stable version
brew install chunkwm
# install from git repo
brew install --HEAD chunkwm
brewからインストールした場合、brew services
を使って起動時に自動的に実行できます。
ただし最初はAccesibilityの許可が必要なため、
brew services restart chunkwm
でサービスを再起動し表示されるダイアログのOpen System Preferences
を選択し、
Security & Privacy > Privacy > Accesibility > chunkwm
にチェックをする必要があります。
コンフィグ
chunkwmは起動時デフォルトで~/.chunkwmrc
を読み込むのでファイルを作ってやります(コンフィグファイルがない場合は起動に失敗します)
また、.chunkwmrc
は実行権限が必要なのでそれもつけてやります。
touch ~/.chunkwmrc
chmod +x ~/.chunkwmrc
コンフィグファイルは公式にサンプルがありますが、そのまま適用するとMacBookProの15inchでは表示崩れが激しいので変更しています。
#!/bin/bash
#
# NOTE: specify the absolutepath to the directory to use when
# loading a plugin. '~' expansion is supported.
#
# プラグインのディレクトリ
# brewから入れた場合、/usr/local/Cellar/chunkwm/0.2.36/share/chunkwm/pluginsにあるのでそれを直接指定してもいい気がする。
# chunkc core::plugin_dir /usr/local/Cellar/chunkwm/0.2.36/share/chunkwm/plugins/usr/local/Cellar/chunkwm/0.2.36/share/chunkwm/plugins
# 公式通り~/.chunkwm_pluginsを使いたい場合は事前に
# cp /usr/local/Cellar/chunkwm/0.2.36/share/chunkwm/plugins/* .chunkwm_plugins/
# 等で.soファイルをコピーする必要がある。
chunkc core::plugin_dir ~/.chunkwm_plugins
#
# NOTE: if enabled, chunkwm will monitor the specified plugin_dir
# and automatically reload any '.so' file that is changed.
#
# Pluginを開発しない限り多分使わない
chunkc core::hotload 0
# レイアウトモード
# global_desktop_modeでデフォルトの表示モード
# {index}_desktop_modeでSpaceによって表示モードを変更できる
#
# - bsp: ウィンドウが分割されていくやつ
# - monocle: ウィンドウが画面いっぱいに拡大され重なる
# - float: 普段使っているようなウィンドウを自由に移動できるやつ
chunkc set global_desktop_mode bsp
# chunkc set 2_desktop_mode monocle
# chunkc set 5_desktop_mode float
# ウィンドウと画面端の距離を設定
# gapはウィンドウとウィンドウの距離
# {index}_desktop_offset_{position}でそのSpaceの値を決定できる
chunkc set global_desktop_offset_top 12
chunkc set global_desktop_offset_bottom 12
chunkc set global_desktop_offset_left 12
chunkc set global_desktop_offset_right 12
chunkc set global_desktop_offset_gap 16
# chunkc set 1_desktop_offset_top 190
# chunkc set 1_desktop_offset_bottom 190
# chunkc set 1_desktop_offset_left 190
# chunkc set 1_desktop_offset_right 190
# chunkc set 1_desktop_offset_gap 15
chunkc set desktop_padding_step_size 10.0
chunkc set desktop_gap_step_size 5.0
# 新しいウィンドウを開くとき、現在フォーカスしているウィンドウの左に開くかどうか
# true: 1
# false: 0
chunkc set bsp_spawn_left 0
chunkc set bsp_optimal_ratio 1.618
# 分割モード
# - horizontal: 水平分割(-)
# - vertical: 垂直分割(|)
# - optimal: よしなに
chunkc set bsp_split_mode optimal
# 分割されたときの比率
chunkc set bsp_split_ratio 0.5
chunkc set monitor_focus_cycle 1
chunkc set window_focus_cycle monitor
# フォーカスの移動にマウスが追従するかどうか
chunkc set mouse_follows_focus 1
chunkc set window_float_next 0
# windowサイズをマウスで変更できないようにするか
chunkc set window_region_locked 1
#
# NOTE: shell commands require escaped quotes
# to pass value containing a whitespace.
#
# chunkc set mouse_modifier \"cmd shift\"
chunkc set mouse_modifier fn
chunkc set preselect_border_color 0xffd75f5f
chunkc set preselect_border_width 5
chunkc set preselect_border_radius 0
#
# NOTE: these settings require chwm-sa.
# (https://github.com/koekeishiya/chwm-sa)
#
chunkc set window_float_topmost 0
chunkc set window_fade_inactive 0
chunkc set window_fade_alpha 0.85
chunkc set window_fade_duration 0.25
chunkc set window_use_cgs_move 0
#
# NOTE: the following are config variables for the chunkwm-border plugin.
#
chunkc set focused_border_color 0xff0f6288
chunkc set focused_border_width 5
chunkc set focused_border_radius 5
chunkc set focused_border_skip_floating 0
#
# NOTE: specify plugins to load when chunkwm starts.
# if chunkc plugin_dir is not set, the absolutepath is necessary.
#
chunkc core::load border.so
chunkc core::load tiling.so
chunkc core::load ffm.so
# 個別のウィンドウ表示設定
# --ownerがアプリ名で--nameがタイトルバーの名前
chunkc tiling::rule --owner Finder --name Copy --state float
chunkc tiling::rule --owner \"App Store\" --state float
chunkc tiling::rule --owner \"ConfigDialog\" --name \"Google Japanese Input Preferences\" --state float
chunkc tiling::rule --owner \"IntelliJ IDEA\" --name \"Default Preferences\" --state float
コマンド
ウィンドウの操作はすべてコマンド経由で行います。
フォーカスの移動
ウィンドウのフォーカスの移動をします。
現在フォーカスしているウィンドウを中心に東西南北(右左下上)で指定します。
その方向にウィンドウがない場合は何も起こりません。
# 現在フォーカスしているウィンドウの西(左)にあるウィンドウにフォーカスを移動
chunkc tiling::window --focus west
ウィンドウの移動
現在フォーカスしているウィンドウの移動を行います。
だいたいフォーカスの移動と同じ感じです。
# 現在フォーカスしているウィンドウを西(左)に移動する
chunkc tiling::window --warp west
別スペースにウィンドウを飛ばす
現在フォーカスしているウィンドウを別スペースに飛ばします。
# 1つ前のスペースに飛ばす
chunkc tiling::window --send-to-desktop prev
# 1つあとのスペースに飛ばす
chunkc tiling::window --send-to-desktop next
# 番号を指定するとそのスペースに飛ばせる
chunkc tiling::window --send-to-desktop prev
ウィンドウのモード切り替え
現在フォーカスしているウィンドウのモードを切り替えます。
# floatモードに切り替え(floatモードだったら元に戻る)
chunkc tiling::window --toggle float
# フルスクリーン化の切り替え
# 大きさはウィンドウがスペースに1つしかないときと同じ大きさ
chunkc tiling::window --toggle fullscreen
# フルスクリーン化の切り替え
# 大きさはmacOSのウィンドウ左上にある緑色のボタンを押したときと同じ
hunkc tiling::window --toggle native-fullscreen
ウィンドウサイズの変更
現在フォーカスしているウィンドウのサイズを変更します。
東西南北の方向に増やしたり減らしたりできます(なので画面を2分割しているときに左にあるウィンドウを選択した状態でwestを増やしても何も起こらない)。
また、--use-temporary-ratio
に指定する数字は割合で値は-1 < value < 1
です。
# ウィンドウを西(左)へ伸ばす
chunkc tiling::window --use-temporary-ratio 0.01 --adjust-window-edge west
# ウィンドウを西(左)へ縮める
chunkc tiling::window --use-temporary-ratio -0.01 --adjust-window-edge west
分割モードの変更
次に開くウィンドウの分割の仕方を変更します。
# 縦方向に分割
chunkc set bsp_split_mode vertical
# 横方向に分割
chunkc set bsp_split_mode horizontal
# 現在のウィンドウの大きさを元によしなに決める
chunkc set bsp_split_mode optimal
他にも色々あるのでchunkwm-tilingのリファレンスやchunkwm-borderのリファレンスを見たりキーバインディングの設定のサンプルを見ていろいろ試してみてください。
- shkdの設定のサンプル: https://github.com/koekeishiya/chunkwm/tree/master/src/plugins/tiling/examples/skhdrc
- khdの設定のサンプル: https://github.com/koekeishiya/chunkwm/tree/master/src/plugins/tiling/examples/khdrc
キーバインディング
chunkwmはデフォルトでキーバインディングを提供していません。
なので自分で上記のコマンドとキーを紐付ける必要があります。
私はKarabiner-Elementを使っていて、いつの間にかシェルの実行に対応していたので全てKarabiner-Elementで設定しました。
とりあえずシェルを実行できればなんでもいいと思います。
Karabiner-Elementの設定
Karabiner-Elementで独自のキーバインディングをするには~/.config/karabiner/assets/complex_modifications
ディレクトリ内に設定ファイルを用意してあげます。
今回はchunkwmについての設定だったのでそのままchunkwm.json
という名前にしました。
touch ~/.config/karabiner/assets/complex_modifications/chunkwm.json
あとは自分の好みに合わせて作成すれば大丈夫だと思います。
Karabiner-Elementsの設定ファイルの書き方や設定方法などは
を参考にしました。ありがとうございます!
一応私の設定ファイルです。Vim風に移動できるようにしたりしています。
本当はスペースの移動がcontrol+矢印キーなのでcontrolが良かったのですが、IDEとかで使う気がしたのでoptionキーをベースに設定しています。
{
"title": "chunkwm key bindings",
"rules": [
{
"description": "focus window",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "h",
"modifiers":{
"mandatory":[
"option"
]
}
},
"to": [
{
"shell_command":"/usr/local/bin/chunkc tiling::window --focus west"
}
]
},
{
"type": "basic",
"from": {
"key_code": "j",
"modifiers":{
"mandatory":[
"option"
]
}
},
"to": [
{
"shell_command":"/usr/local/bin/chunkc tiling::window --focus south"
}
]
},
{
"type": "basic",
"from": {
"key_code": "k",
"modifiers":{
"mandatory":[
"option"
]
}
},
"to": [
{
"shell_command":"/usr/local/bin/chunkc tiling::window --focus north"
}
]
},
{
"type": "basic",
"from": {
"key_code": "l",
"modifiers":{
"mandatory":[
"option"
]
}
},
"to": [
{
"shell_command":"/usr/local/bin/chunkc tiling::window --focus east"
}
]
}
]
},
{
"description":"move window",
"manipulators":[
{
"type":"basic",
"from":{
"key_code":"h",
"modifiers":{
"mandatory":[
"shift",
"option"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc tiling::window --warp west"
}
]
},
{
"type":"basic",
"from":{
"key_code":"j",
"modifiers":{
"mandatory":[
"shift",
"option"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc tiling::window --warp south"
}
]
},
{
"type":"basic",
"from":{
"key_code":"k",
"modifiers":{
"mandatory":[
"shift",
"option"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc tiling::window --warp north"
}
]
},
{
"type":"basic",
"from":{
"key_code":"l",
"modifiers":{
"mandatory":[
"shift",
"option"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc tiling::window --warp east"
}
]
},
{
"type":"basic",
"from":{
"key_code":"open_bracket",
"modifiers":{
"mandatory":[
"option",
"shift"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc tiling::window --send-to-desktop prev"
}
]
},
{
"type":"basic",
"from":{
"key_code":"close_bracket",
"modifiers":{
"mandatory":[
"option",
"shift"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc tiling::window --send-to-desktop next"
}
]
}
]
},
{
"description":"change window layout",
"manipulators":[
{
"type":"basic",
"from":{
"key_code":"spacebar",
"modifiers":{
"mandatory":[
"option"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc tiling::window --toggle float"
}
]
},
{
"type":"basic",
"from":{
"key_code":"f",
"modifiers":{
"mandatory":[
"option"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc tiling::window --toggle fullscreen"
}
]
},
{
"type":"basic",
"from":{
"key_code":"f",
"modifiers":{
"mandatory":[
"shift",
"option"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc tiling::window --toggle native-fullscreen"
}
]
}
]
},
{
"description":"change window size",
"manipulators":[
{
"type":"basic",
"from":{
"key_code":"e",
"modifiers":{
"mandatory":[
"option"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc tiling::desktop --equalize"
}
]
},
{
"type":"basic",
"from":{
"key_code":"h",
"modifiers":{
"mandatory":[
"option",
"control"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc tiling::window --use-temporary-ratio -0.01 --adjust-window-edge east"
}
]
},
{
"type":"basic",
"from":{
"key_code":"j",
"modifiers":{
"mandatory":[
"option",
"control"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc tiling::window --use-temporary-ratio 0.01 --adjust-window-edge south"
}
]
},
{
"type":"basic",
"from":{
"key_code":"k",
"modifiers":{
"mandatory":[
"option",
"control"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc tiling::window --use-temporary-ratio -0.01 --adjust-window-edge south"
}
]
},
{
"type":"basic",
"from":{
"key_code":"l",
"modifiers":{
"mandatory":[
"option",
"control"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc tiling::window --use-temporary-ratio 0.01 --adjust-window-edge east"
}
]
},
{
"type":"basic",
"from":{
"key_code":"h",
"modifiers":{
"mandatory":[
"option",
"control",
"shift"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc tiling::window --use-temporary-ratio 0.01 --adjust-window-edge west"
}
]
},
{
"type":"basic",
"from":{
"key_code":"j",
"modifiers":{
"mandatory":[
"option",
"control",
"shift"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc tiling::window --use-temporary-ratio -0.01 --adjust-window-edge north"
}
]
},
{
"type":"basic",
"from":{
"key_code":"k",
"modifiers":{
"mandatory":[
"option",
"control",
"shift"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc tiling::window --use-temporary-ratio 0.01 --adjust-window-edge north"
}
]
},
{
"type":"basic",
"from":{
"key_code":"l",
"modifiers":{
"mandatory":[
"option",
"control",
"shift"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc tiling::window --use-temporary-ratio -0.01 --adjust-window-edge west"
}
]
}
]
},
{
"description":"config variable",
"manipulators":[
{
"type":"basic",
"from":{
"key_code":"v",
"modifiers":{
"mandatory":[
"option"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc set bsp_split_mode vertical"
}
]
},
{
"type":"basic",
"from":{
"key_code":"b",
"modifiers":{
"mandatory":[
"option"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc set bsp_split_mode horizontal"
}
]
},
{
"type":"basic",
"from":{
"key_code":"o",
"modifiers":{
"mandatory":[
"option"
]
}
},
"to":[
{
"shell_command":"/usr/local/bin/chunkc set bsp_split_mode optimal"
}
]
}
]
},
{
"description":"new terminal window",
"manipulators":[
{
"type": "basic",
"from": {
"key_code": "n",
"modifiers":{
"mandatory":[
"option"
]
}
},
"to": [
{
"shell_command":"open -na Terminal.app"
}
]
}
]
}
]
}
コマンドはchunkc
だけだとcommand not found
になったのでフルパスで指定しています。
ウィンドウの幅の変更はi3みたいに特定のキーを押すとresizeモードになるみたいな挙動にしてみたいのですが、気力が・・・
あとIDEとかでcontrolをあまり使わなかったらcontrolにしたいと思います。
Tips
設定するとき
設定をするときはbrew services stop chunkwm
で一回chunkwmの自動起動をやめてTerminalでchunkwm
を実行して出力を見ながらいろいろ弄ったほうが楽です。
エラーがあった場合そこに表示されますし、コンフィグファイルでtiling::rule
を設定するときの--owner
と--name
はウィンドウをフォーカスしたときなどに表示される
Google Chrome:New Tab:1172 window title changed
の最初の'Google Chrome'が--owner
で'New Tab'が--name
です(Google Chromeの場合)。
設定が全て終わったらbrew services start chunkwm
でchunkwmの自動起動を有効にすればOKです。
'chunkwm: failed to initialize daemon! abort..'で起動できない
既にchunkwmが起動していた場合、chunkwmの起動に失敗します。
もしどこかでゾンビプロセスになってた場合は
killall -QUIT "chunkwm"
などで成仏させてあげましょう。
まとめ
macOSでタイル型ウィンドウマネージャを実現するchunkwmを使ってみました。
拡張性が高く、全てCLIからなので自分でいろいろカスタマイズできてエンジニア的には嬉しいです。
また、まだAlpha版なのでこれからの発展に期待したいです。