Open11

yabai + skhd での快適Mac生活

NanamiiiiiNanamiiiii

3ヶ月くらい熟成したconfig

条件

  • macOS Ventura Sonoma
  • M1 MacBook Pro (2021)
  • SIP一部無効化済み(scripting additionのため)
  • Status Bar Widgetとして,Übersichtのsimple-barを使用(若干カスタム済み) Sketchybarに移行
yabairc
#!/usr/bin/env sh
# loading sa
yabai -m signal --add event=dock_did_restart action="sudo yabai --load-sa"
sudo yabai --load-sa

# global settings
yabai -m config mouse_follows_focus          off
yabai -m config focus_follows_mouse          on
yabai -m config window_origin_display        default
yabai -m config window_placement             second_child
yabai -m config window_topmost               off
yabai -m config window_shadow                on
yabai -m config window_opacity               off
yabai -m config window_opacity_duration      0.0
yabai -m config active_window_opacity        1.0
yabai -m config normal_window_opacity        0.90
yabai -m config window_border                off
yabai -m config window_border_width          6
yabai -m config active_window_border_color   0xff775759
yabai -m config normal_window_border_color   0xff555555
yabai -m config insert_feedback_color        0xffd75f5f
yabai -m config split_ratio                  0.50
yabai -m config auto_balance                 off
yabai -m config mouse_modifier               fn
yabai -m config mouse_action1                move
yabai -m config mouse_action2                resize
yabai -m config mouse_drop_action            swap

# general space settings
yabai -m config layout                       bsp
yabai -m config top_padding                  12
yabai -m config bottom_padding               12
yabai -m config left_padding                 12
yabai -m config right_padding                12
yabai -m config window_gap                   06

# in external display, top padding is different
# on M1 or later macbook, the notch space working as padding
DISPLAY_UUID=37D8832A-2D66-02CA-B9F7-8F30A301B230 # UUID of built-in display
BAR_PADDING=50
SPACES_ON_SUB=$(yabai -m query --displays | jq ".[] | select(.uuid != \"${DISPLAY_UUID}\") | .spaces[]")
for idx in ${SPACES_ON_SUB}
do
    yabai -m config --space "$idx" top_padding "$BAR_PADDING"
done

# Rules
yabai -m rule --add app="^System Settings$" manage=off
yabai -m rule --add app="^Termius$" manage=off
yabai -m rule --add app="^zoom\.us$" manage=off
yabai -m rule --add app="^Docker Desktop$" manage=off
yabai -m rule --add app="^Calculator$" manage=off
yabai -m rule --add app="^Finder$" title="^Connect to Server$" manage=off
yabai -m rule --add app="^Finder$" title="^Connecting to Server$" manage=off
yabai -m rule --add app="^Finder$" title="^.* Info$" manage=off
yabai -m rule --add app="^Finder$" title="^Copy$" manage=off
yabai -m rule --add app="^Inkdrop$" title="^Preferences$" manage=off
yabai -m rule --add app="^Weather$" manage=off
yabai -m rule --add app="^Clock$" manage=off
yabai -m rule --add app="^1Password$" manage=off
yabai -m rule --add app="^Discord$" title="^Discord Updater$" manage=off
yabai -m rule --add app="^Archive Utility$" manage=off
yabai -m rule --add app="^Microsoft To Do$" manage=off
yabai -m rule --add app="^UTM$" manage=off
yabai -m rule --add app="^GitKraken$" manage=off
yabai -m rule --add app="^Parallels Desktop$" manage=off
yabai -m rule --add app="^Plexamp$" sticky=on

echo "yabai configuration loaded.."
skhdrc
# focus window
alt - x : yabai -m window --focus recent
alt - h : yabai -m window --focus west
alt - j : yabai -m window --focus south
alt - k : yabai -m window --focus north
alt - l : yabai -m window --focus east
alt - n : ~/.scripts/yabai_next_window.sh
alt - p : ~/.scripts/yabai_prev_window.sh

# swap window
shift + alt - x : yabai -m window --swap recent
shift + alt - h : yabai -m window --swap west
shift + alt - j : yabai -m window --swap south
shift + alt - k : yabai -m window --swap north
shift + alt - l : yabai -m window --swap east

# move window
shift + cmd - h : yabai -m window --warp west
shift + cmd - j : yabai -m window --warp south
shift + cmd - k : yabai -m window --warp north
shift + cmd - l : yabai -m window --warp east

# move window
shift + ctrl - a : yabai -m window --move rel:-20:0
shift + ctrl - s : yabai -m window --move rel:0:20
shift + ctrl - w : yabai -m window --move rel:0:-20
shift + ctrl - d : yabai -m window --move rel:20:0

# increase window size
shift + alt - a : yabai -m window --resize left:-20:0
shift + alt - s : yabai -m window --resize bottom:0:20
shift + alt - w : yabai -m window --resize top:0:-20
shift + alt - d : yabai -m window --resize right:20:0

# decrease window size
shift + cmd - a : yabai -m window --resize left:20:0
shift + cmd - s : yabai -m window --resize bottom:0:-20
shift + cmd - w : yabai -m window --resize top:0:20
shift + cmd - d : yabai -m window --resize right:-20:0

# rotate tree
alt - r : yabai -m space --rotate 90

# mirror tree y-axis
alt - y : yabai -m space --mirror y-axis

# mirror tree x-axis
alt - x : yabai -m space --mirror x-axis

# toggle desktop offset
alt - a : yabai -m space --toggle padding && yabai -m space --toggle gap

# toggle window fullscreen zoom
alt - f : yabai -m window --toggle zoom-fullscreen

# toggle window native fullscreen
shift + alt - f : yabai -m window --toggle native-fullscreen

# toggle window split type
alt - e : yabai -m window --toggle split

# float / unfloat window and restore position
# alt - t : yabai -m window --toggle float && /tmp/yabai-restore/$(yabai -m query --windows --window | jq -re '.id').restore 2>/dev/null || true
alt - t : yabai -m window --toggle float && yabai -m window --grid 4:4:1:1:2:2

# toggle sticky window
alt - s : yabai -m window --toggle sticky

# restart yabai
shift + alt - r : yabai --restart-service && osascript -e 'tell application id "tracesOf.Uebersicht" to reload widget id "simple-bar-index-jsx"'

# restart skhd
shift + ctrl - r : skhd --restart-service

# Close app
alt - q : yabai -m window --close

# Focus spaces (require sa)
alt - 1 : yabai -m space --focus 1
alt - 2 : yabai -m space --focus 2
alt - 3 : yabai -m space --focus 3
alt - 4 : yabai -m space --focus 4
alt - 5 : yabai -m space --focus 5
alt - 6 : yabai -m space --focus 6
alt - 7 : yabai -m space --focus 7
alt - 8 : yabai -m space --focus 8
alt - 9 : yabai -m space --focus 9
alt - 0 : yabai -m space --focus 10

# Move spaces (require sa)
shift + alt - 1 : yabai -m window --space 1
shift + alt - 2 : yabai -m window --space 2
shift + alt - 3 : yabai -m window --space 3
shift + alt - 4 : yabai -m window --space 4
shift + alt - 5 : yabai -m window --space 5
shift + alt - 6 : yabai -m window --space 6
shift + alt - 7 : yabai -m window --space 7
shift + alt - 8 : yabai -m window --space 8
shift + alt - 9 : yabai -m window --space 9
shift + alt - 0 : yabai -m window --space 10

# Move display
shift + alt - p : yabai -m space --move prev
shift + alt - n : yabai -m space --move next

# Launch Apps
## WezTerm
alt - return : open -a "WezTerm"
## memos
alt - m : open "https://memos.myuu.dev"
## FireFox
alt - b : open -a "Firefox Developer Edition"
## Vivaldi
shift + alt - b : open -a "Firefox"
## Finder
alt - g : osascript ~/.config/skhd/finder.scpt
## Inkdrop
cmd + alt - m : open -a "Inkdrop"
## Code
cmd + alt - o : open -a "Visual Studio Code"
## 1Password
cmd + alt - k : open -a "1Password"

https://raw.githubusercontent.com/Nanamiiiii/dotfiles/main/yabai/yabairc

https://raw.githubusercontent.com/Nanamiiiii/dotfiles/main/skhd/skhdrc

NanamiiiiiNanamiiiii

Built-inディスプレイと外部ディスプレイのpaddingをよしなにする

yabairc
# in external display, top padding is different
# on M1 or later macbook, the notch space working as padding
DISPLAY_UUID=37D8832A-2D66-02CA-B9F7-8F30A301B230 # UUID of built-in display
BAR_PADDING=50
SPACES_ON_SUB=$(yabai -m query --displays | jq ".[] | select(.uuid != \"${DISPLAY_UUID}\") | .spaces[]")
for idx in ${SPACES_ON_SUB}
do
    yabai -m config --space "$idx" top_padding "$BAR_PADDING"
done

Why

M1搭載以降のMBPは,ノッチを避けるためにデフォルトでパディングが存在する.
そのため,Built-inディスプレイではパディングなしで独自のステータスバー領域を確保できる.
しかし,外部ディスプレイにはノッチのためのパディングが確保されない(当然)ので,外部ディスプレイにのみyabai側でパディングを設定する.

How

各ディスプレイに振られるuuidを利用する.Built-inのuuidは基本変化しないとしてベタ書きし,これに該当しないディスプレイ上のspace対してのみパディングを与える.

  • 外部ディスプレイ上のspaceの取得
    yabai -m query --displays | jq ".[] | select(.uuid != \"${DISPLAY_UUID}\") | .spaces[]"
  • spaceごとにパディングを設定
    yabai -m config --space SPACE_ID top_padding PADDING
NanamiiiiiNanamiiiii

Space内でcyclicにwindowを切り替える

What

アクティブなspace内にあるwindowを巡回したかったが,yabai側でそれができる機能がなかったっぽい?
shellscriptでゴリゴリとやった

Why

floatingなwindowがあるとき,これにfocusする手段がなかった

Keybind

skhdrc
alt - n : ~/.scripts/yabai_next_window.sh
alt - p : ~/.scripts/yabai_prev_window.sh

nextprev はwindow idの前後

Script

yabai_next_window.sh
#!/bin/bash

# focusされてるwindowの情報
FOCUSED=$(yabai -m query --windows --window 2> /dev/null)
# focusされてるwindow id
FOCUSED_ID=$(echo "$FOCUSED" | jq ".id")

# focusされてるwindowが存在するとき
if [ -n "$FOCUSED_ID" ]; then
    UNFOCUSED=$(yabai -m query --windows --space | jq "[ .[] | if .id != $FOCUSED_ID then . else empty end]")
    UPPER_ID=$(echo "$UNFOCUSED" | jq "[ .[] | if .id > $FOCUSED_ID then . else empty end]")
    if [ "$(echo "$UPPER_ID" | jq ". | length")" -gt 0 ]; then
        NEXT=$(echo "$UPPER_ID" | jq "[ .[].id ] | min")
        yabai -m window --focus "$NEXT"
    else
        NEXT=$(echo "$UNFOCUSED" | jq "[ .[].id ] | min")
        yabai -m window --focus "$NEXT"
    fi
else # なにもfocusされてないとき
    UNFOCUSED=$(yabai -m query --windows --space)
    NEXT=$(echo "$UNFOCUSED" | jq "[ .[].id ] | min")
    yabai -m window --focus "$NEXT"
fi
  • window idに基づいて,直後・直前のwindowにfocusする
  • なにもfocusされていない場合,idが先頭・末尾のwindowへfocus
  • prevはidの大小比較を真逆にしたもの

https://raw.githubusercontent.com/Nanamiiiii/dotfiles/main/scripts/yabai_next_window.sh

NanamiiiiiNanamiiiii

SIPの無効化について

しないと実際どうなのか

個人的には不快.マウス操作したほうがマシだった.

なにができないのか

  • スムーズなspace (仮想デスクトップ) の移動
    • scripting-additionはアニメーションとかその他いらない視覚効果を無効化できる
  • windowのspace間移動
  • yabai側からのspace追加・削除
  • sticky windowが使えない
  • などなど…

指示通り設定するとシステム保護機能はこうなる

最低限の保護は効いてるはずなので,まあ個人使用マシンならそこまで問題はないだろう…
今のところその他アプリケーションへの影響もない.

NanamiiiiiNanamiiiii

Übersicht

React / jsx (tsx) で記述したウィジェットを画面上にレンダリングできる.
任意のコマンド実行結果を取得して,それを表示するなど.

https://github.com/felixhageloh/uebersicht

Install

Homebrew or Website

brew install ubersicht

simple-bar

yabaiへのメッセージパッシングを実装しているÜbersichtのウィジェット.
yabai以外にSpotifyなどの表示にも対応している.

https://github.com/Jean-Tinland/simple-bar

作者はApple Silicon非所持で動作保証はしないよ!と言っているが,今のところ支障はない.
(むしろAppleSilicon以降のノッチが丁度余白になってて良き)

Install

Übersichtのウィジェットディレクトリに直接cloneすればよい

  • ~/Library/Application Support/Übersicht/widgets

カスタマイズ

Reactが分かれば容易.画面サイズとかに合わせてPadding/Marginはカスタムした方がよさそうな所感.

完全に自分用にカスタムしただけのやつ
https://github.com/Nanamiiiii/simple-bar

Refresh / Reload

yabaiをrestartするとメッセージパッシングが効かなくなる(多分古いsocketを参照したままだから?)
skhdでyabaiのrestartにあわせてwidgetをreloadする設定にするといい.
CLIからのÜbersichtの制御はAppleScriptで可能.

# restart yabai
shift + alt - r : yabai --restart-service && osascript -e 'tell application id "tracesOf.Uebersicht" to reload widget id "simple-bar-index-jsx"'
NanamiiiiiNanamiiiii

ÜbersichtをやめてSketchybarに移行した

https://github.com/FelixKratz/SketchyBar

理由

  • 最近Übersichtの挙動が怪しかった
    • 起動オーバーヘッドが著しい
    • 一部コンテンツがバグる(たまに読み込まない)
    • しばらく使ってるとyabaiとのやりとりが遅くなる(メッセージパッシングが詰まってるかのような挙動)
    • ぶっちゃけReactである必要がない(そこまでカスタマイズしないので)

Sketchybar,非常に軽くて良い.見た目も思ったよりカスタムできるし,何よりも✝️黒魔術️✝️(ShellScript)で項目を作れるのがいい.

NanamiiiiiNanamiiiii

SIP無効化をやめた

あれだけSIP無効化をした方がいいと言っていたが…結局無効化なしでの運用にした

Reason

  • 起動時とかわりかし不安定になる
  • Update降ってきたときにsudoersのハッシュ値更新するのが面倒
  • masOSのアプデのときにCompatibleか気にするのがダルくなってきた
  • (セキュリティの研究してんのにこういうことやってんのはどうなん?とか思っちゃったりした.あんま関係ないが)

使えなくなった機能の代替

Space切り替え

  • Mission Controlの標準ショートカットで代用可能
  • アニメーションは入るが,そこまで不快に感じなくなった

Space移動

  • ここはキーボードOnlyで対応するのは厳しい
  • マウスでウィンドウを保持しつつ,Space切り替えをすると移動できるとかいう裏技?のようなやり方でなんとかしている

Sticky

  • ぶっちゃけあんまり使ってないので困らなかった
  • Stickyにまでしなくても,標準機能でSpaceに固定割り当てすれば自分のニーズでは特に困らなかった