AmethystでmacOS作業を快適に: 新たなウィンドウ管理の可能性

## 背景

macOSでタイル型ウィンドウマネージャーを使っていました。自動でウィンドウを整列してくれるので、手動でウィンドウを整理する手間が省けます。

以前はyabai+skhdを使用していました。その中で標準的なキーバインドをマスターしておこうと考え、i3-wmキーバインドに寄せてカスタマイズを行っていました。

- [macOSのタイル型ウィンドウマネジャーyabaiを、なるべくi3-wmに近くなるよう設定 - Qiita](https://qiita.com/hann-solo/items/0d8dbda76ee9f22c3ae4)

macOS VenturaでOS自体のウィンドウマネージャーの変更が大きく、各所で不具合が出ていたので、macOSのステージマネジャーをしばらく使っていました。効率化をふたたび求めて、またVentura対応も進んでいるので、タイル型ウィンドウマネジャーに戻ることにしました。

![SS 2023-07-22 8.19.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/78ba4b4e-4549-3ec0-898f-5eb38f5d549f.png)

<span style="color: #999999">【画像：たとえば4枚のウィンドウを開くと、自動的に並びます】</span>

## Amethystとは

今回、ウィンドウマネージャーとして選んだのはAmethystというソフトウェアです。AmethystはmacOS向けに特化した自動タイル型ウィンドウマネージャーで、ユーザーが手動でウィンドウを配置、管理する必要を大幅に削減します。

ウィンドウの配置とサイズ調整は自動的に行われ、複数のウィンドウを同時に開いて作業する際の効率性と整理整頓を大幅に向上させます。手動でウィンドウを管理する時間と労力を大幅に減り、本来の作業に集中できます。

また、Amethystの特徴としては、一部の機能を使うためにmacOSのSystem Integrity Protection (SIP)を無効化する必要がない点が挙げられます。これにより、SIPを無効化することによるセキュリティリスクを避けることができます。これらの理由から、前回使用していたyabai+skhdからAmethystに切り替えることにしました。

Amethystの設定は、`.amethyst.yml`という設定ファイルでも行えます。しかし、一部の設定が反映されなかったため、今回はGUIを利用して設定を行いました。

## キーバインドの設定

以下に、yabaiとAmethystでのキーバインドを比較した表を示します。

|  | i3-wm | yabai | Amethyst |
| --- | --- | --- | --- |
| フォーカスの移動 | $mod + jkl; | alt + hjkl | alt + hl |
| メインウィンドウにフォーカス | -- | -- | alt + k |
| ウィンドウをワープ | $mod + shift + jkl; | shift + alt + hjkl | shift + alt + hl |
| スペースにワープ | $mod + shift + num | shift + alt + 12345 | shift + alt + 1-8 |
| スペースにワープ (prev/next) | -- | shift + alt + 9/0 | shift + alt + 9/0 |
| スペースに切り替え | $mod + num | alt + 12345<br>要SIP対応 | --  |
| スクリーンにフォーカスを移動 | -- | alt + 12345<br>要SIP対応 | alt + w/e <br> (prev/next) |
| スクリーンにワープ | -- | alt + 12345<br>要SIP対応 | shift + alt + w/e <br> (prev/next) |
| フルスクリーン (native) | $mod + f | shift + alt + f | -- |
| tallレイアウト | たぶん存在しない | -- | shift + alt + a |
| tall-Rightレイアウト | たぶん存在しない | -- | shift + alt + s |
| wideレイアウト | たぶん存在しない | -- | shift + alt + d |
| fullscreenレイアウト | たぶん存在しない | alt + f | shift + alt + f |
| toggle floting | $mod + shift + space | shift + alt + space | shift + alt + space |
| splith/splitv (toggle) | $mod + e | alt + e | -- |
| splith, splitv | $mod + h v | たぶん存在しない | -- |
| rotate 90 | -- | alt + r | -- |
| mirror x or y | -- | alt + x y | -- |
| タイリングON/OFFトグル | -- | -- | shift + alt + t |

## 補足

Amethystはyamlでも設定できますが、全てのキーバインドの設定ができないようです。バグだと思うんですが、追求しきれませんでした。やむなくGUIで設定しました。

:::note
ちなみに、ymlでは
スペースにワープ (prev/next) mod2 + 9/0
toggle floting	mod2 + space
の設定がうまくできませんでした。
:::

yamlで設定する場合、修飾キーは2パターンに固定しないといけない（GUIの場合は制限がない）ようです。ほんとうはyamlで設定したいので、GUIでもmod1: alt、mod2: shift + altに統一しておきました。


## おわりに

yabaiからAmethystへの切り替えと、それに伴うi3-wmキーバインドのカスタマイズについての紹介でした。タイル型ウィンドウマネージャーの利点は、手動でウィンドウを配置、管理することから解放されることです。これにより、作業の効率化と整理整頓が実現され、作業により集中できるようになります。

Amethystはその点において非常に有効で、macOSのSystem Integrity Protection (SIP)を無効化することなく使用できるという点でも優れています。

さまざまなタイル型ウィンドウマネージャーを体験することで、その特性や使い勝手を理解し、自分の作業スタイルに最適なツールを選ぶことが可能になります。今回の経験は、新たなウィンドウ管理の視点を得る機会となり、非常に有益でした。

### リンク

- Amethyst
    - [GitHub - ianyh/Amethyst: Automatic tiling window manager for macOS à la xmonad.](https://github.com/ianyh/Amethyst)
    - [Boost your MacOS PRODUCTIVITY with Amethyst | Tiling Window Manager](https://www.youtube.com/watch?v=7Z9-Ry4yGNc)
- yabai
  - [GitHub - koekeishiya/yabai: A tiling window manager for macOS based on binary space partitioning](https://github.com/koekeishiya/yabai)
  - [macOSのタイル型ウィンドウマネジャーyabaiを、なるべくi3-wmに近くなるよう設定 - Qiita](https://qiita.com/hann-solo/items/0d8dbda76ee9f22c3ae4)


### 環境

- Amethyst 0.19.0 (103)
- macOS Ventura 13.4.1
- MacBook Pro (14-inch, 2021)


## .amethyst.yml

今回は使えませんでしたが、ymlはこちら。

```.amethyst.yml
# layouts - Ordered list of layouts to use by layout key (default tall, wide, fullscreen, and column).
layouts:
  - tall
  - fullscreen
  # - tall-right
  - wide
  # - two-pane
  # - middle-wide
  # - 3column-left
  # - 3column-middle
  # - 3column-right
  # - 4column-left
  # - 4column-right
  # - column
  # - row
  # - floating
  # - widescreen-tall
  # - widescreen-tall-right
  # - bsp

# First mod (default option + shift).
mod1:
  - option
  # - shift
  # - control
  # - command

# Second mod (default option + shift + control).
mod2:
  - option
  - shift
  # - control
  # - command

# Commands:
# special key values
# space
# enter
# up
# right
# down
# left

# special characters require quotes
# '.'
# ','

# Move to the next layout in the list.
cycle-layout:
#   mod: mod1
#   key: space

# Move to the previous layout in the list.
cycle-layout-backward:
#   mod: mod2
#   key: space

# Shrink the main pane by a percentage of the screen dimension as defined by window-resize-step. Note that not all layouts respond to this command.
shrink-main:
  mod: mod2
  key: left

# Expand the main pane by a percentage of the screen dimension as defined by window-resize-step. Note that not all layouts respond to this command.
expand-main:
  mod: mod2
  key: right

# Increase the number of windows in the main pane. Note that not all layouts respond to this command.
increase-main:
#   mod: mod1
#   key: ','

# Decrease the number of windows in the main pane. Note that not all layouts respond to this command.
decrease-main:
#   mod: mod1
#   key: '.'

# General purpose command for custom layouts. Functionality is layout-dependent.
# command1:
#   mod: <NONE>
#   key: <NONE>
# General purpose command for custom layouts. Functionality is layout-dependent.
# command2:
#   mod: <NONE>
#   key: <NONE>
# General purpose command for custom layouts. Functionality is layout-dependent.
# command3:
#   mod: <NONE>
#   key: <NONE>
# General purpose command for custom layouts. Functionality is layout-dependent.
# command4:
#   mod: <NONE>
#   key: <NONE>

# Focus the next window in the list going counter-clockwise.
focus-ccw:
  mod: mod1
  key: h

# Focus the next window in the list going clockwise.
focus-cw:
  mod: mod1
  key: l

# Focus the main window in the list.
focus-main:
  mod: mod1
  key: k

# Focus the next screen in the list going counter-clockwise.
focus-screen-ccw:
  mod: mod1
  key: w

# Focus the next screen in the list going clockwise.
focus-screen-cw:
  mod: mod1
  key: e

# Move the currently focused window onto the next screen in the list going counter-clockwise.
swap-screen-ccw:
  mod: mod2
  key: w

# Move the currently focused window onto the next screen in the list going clockwise.
swap-screen-cw:
  mod: mod2
  key: e

# Swap the position of the currently focused window with the next window in the list going counter-clockwise.
swap-ccw:
  mod: mod2
  key: h

# Swap the position of the currently focused window with the next window in the list going clockwise.
swap-cw:
  mod: mod2
  key: l

# Swap the position of the currently focused window with the main window in the list.
swap-main:
  mod: mod2
  key: k

# Move focus to the n-th screen in the list; e.g., focus-screen-3 will move mouse focus to the 3rd screen. Note that the main window in the given screen will be focused.
#focus-screen-n:
# focus-screen-<screen-number>:
#   mod: mod1
#   key: y
# Move the currently focused window to the n-th screen; e.g., throw-screen-3 will move the window to the 3rd screen.
# throw-screen-n:
# throw-screen-<screen-number>:
#   mod: mod1
#   key: u
# Move the curr
# Move the currently focused window to the n-th space; e.g., throw-space-3 will move the window to the 3rd space.
throw-space-1:
  mod: mod2
  key: 1
throw-space-2:
  mod: mod2
  key: 2
throw-space-3:
  mod: mod2
  key: 3
throw-space-4:
  mod: mod2
  key: 4
throw-space-5:
  mod: mod2
  key: 5
throw-space-6:
  mod: mod2
  key: 6
throw-space-7:
  mod: mod2
  key: 7
throw-space-8:
  mod: mod2
  key: 8
throw-space-9:
  mod: mod2
  key: 9

# Select tall layout
select-tall-layout:
  mod: mod2
  key: a

# Select wide layout
select-wide-layout:
  mod: mod2
  key: s

# Select fullscreen layout
select-fullscreen-layout:
  mod: mod2
  key: f

# Select column layout
select-column-layout:
#   mod: mod1
#   key: f

# Move the currently focused window to the space to the left.
throw-space-left:
  mod: mod2
  key: '-'

# Move currently the focused window to the space to the right.
throw-space-right:
  mod: mod2
  key: '='

# Toggle the floating state of the currently focused window; i.e., if it was floating make it tiled and if it was tiled make it floating.
toggle-float:
  mod: mod2
  key: space

# Display the layout HUD with the current layout on each screen.
display-current-layout:
#   mod: mod1
#   key: i

# Turn on or off tiling entirely.
toggle-tiling:
#   mod: mod1
#   key: t

# Rerun the current layout's algorithm.
reevaluate-windows:
  mod: mod1
  key: z

# Turn on or off focus-follows-mouse.
toggle-focus-follows-mouse:
#   mod: mod2
#   key: x

# Automatically quit and reopen Amethyst.
relaunch-amethyst:
  mod: mod2
  key: z

# disable screen padding on in-built display
disable-screen-padding-on-inbuilt: false

# Boolean flag for whether or not to add margins betwen windows (default false).
window-margins: true

# Boolean flag for whether or not to set window margins if there is only one window on the screen, assuming window margins are enabled (default false).
smart-window-margins: false

# # Add 10px margin between windows
# window-margins: true
# window-margin-size: 5
# The size of the margins between windows (in px, default 0).
window-margin-size: 2

# The max number of windows that may be visible on a screen at one time before
# additional windows are minimized. A value of 0 disables the feature.
window-max-count: 4

# The smallest height that a window can be sized to regardless of its layout frame (in px, default 0).
window-minimum-height: 0

# The smallest width that a window can be sized to regardless of its layout frame (in px, default 0)
window-minimum-width: 0

# List of bundle identifiers for applications to either be automatically floating or automatically tiled based on floating-is-blacklist (default []).
floating: []

# Boolean flag determining behavior of the floating list. true if the applications should be floating and all others tiled. false if the applications should be tiled and all others floating (default true).
floating-is-blacklist: true

# true if screen frames should exclude the status bar. false if the screen frames should include the status bar (default false).
ignore-menu-bar: false

# true if windows smaller than a 500px square should be floating by default (default true)
float-small-windows: true

# true if the mouse should move position to the center of a window when it becomes focused (default false). Note that this is largely incompatible with focus-follows-mouse.
mouse-follows-focus: false

# true if the windows underneath the mouse should become focused as the mouse moves (default false). Note that this is largely incompatible with mouse-follows-focus
focus-follows-mouse: false

# true if dragging and dropping windows on to each other should swap their positions (default false).
mouse-swaps-windows: true

# true if changing the frame of a window with the mouse should update the layout to accommodate the change (default false). Note that not all layouts will be able to respond to the change.
mouse-resizes-windows: true

# true to display the name of the layout when a new layout is selected (default true).
enables-layout-hud: true

# true to display the name of the layout when moving to a new space (default true).
enables-layout-hud-on-space-change: true

# true to get updates to beta versions of the software (default false).
use-canary-build: false

# true to insert new windows into the first position and false to insert new windows into the last position (default false).
new-windows-to-main: false

# true to automatically move to a space when throwing a window to it (default true).
follow-space-thrown-windows: true

# The integer percentage of the screen dimension to increment and decrement main pane ratios by (default 5).
window-resize-step: 5

# Padding to apply between windows and the left edge of the screen (in px, default 0).
screen-padding-left: 0

# Padding to apply between windows and the right edge of the screen (in px, default 0).
screen-padding-right: 0

# Padding to apply between windows and the top edge of the screen (in px, default 0).
screen-padding-top: 0

# Padding to apply between windows and the bottom edge of the screen (in px, default 0).
screen-padding-bottom: 0

# true to maintain layout state across application executions (default true).
restore-layouts-on-launch: true

# true to display some optional debug information in the layout HUD (default false).
debug-layout-info: false

```