コンテンツにスキップ

Window Layouts

Window Layoutsは、あらかじめ定義したレイアウト(どのアプリのウィンドウを、どのディスプレイのどのエリアに置くか)を、ホットキー一発で一括適用する機能です。

いつもの作業で決まった位置に配置する複数のウィンドウを、一瞬で整列できます。

全設定に、Window Layoutsの全項目、デフォルト値、各項目の説明を掲載しています。

レイアウトを定義する

layoutsにレイアウトの一覧を配列で定義します。各レイアウトにはname(必須・重複不可)と、ホットキーや配置対象ウィンドウの一覧を指定します。

"displayAliases": {
  "desk": "37D8832A-2D66-02CA-B9F7-8F30A301B230"
},
"windowLayouts": {
  "layouts": [
    {
      "name": "dev",
      "hotkey": { "modifiers": ["ctrl", "alt"], "key": "1" },
      "unlistedWindows": "close",
      "windows": [
        {
          "bundleID": "com.google.Chrome",
          "screen": "desk",
          "area": "halfLeft"
        },
        { "bundleID": "dev.warp.Warp-Stable", "area": "halfRight" },
        { "bundleID": "md.obsidian", "area": "1200x900Center", "launch": true }
      ]
    },
    {
      "name": "meeting",
      "hotkey": { "modifiers": ["ctrl", "alt"], "key": "2" },
      "windows": [
        { "bundleID": "us.zoom.xos", "area": "twoThirdsLeft" },
        { "bundleID": "com.apple.Notes", "area": "thirdRight" }
      ]
    }
  ]
}

ホットキーを押すと、windowsの各エントリにマッチしたウィンドウが指定エリアへ一括で移動します。

レイアウト個別のhotkeyは任意です。省略したレイアウトは、次のピッカーからのみ呼び出せます(ピッカーへの導線も未設定の場合は設定エラーになります)。

ピッカーで選択する

windowLayouts.hotkeyを設定すると、レイアウトを検索して選択するモーダル(ピッカー)を開けます。 レイアウトごとにホットキーを覚えなくても、1つのホットキーからすべてのレイアウトを呼び出せます。

"windowLayouts": {
  "hotkey": { "modifiers": ["ctrl", "alt"], "key": "l" },
  "layouts": [
    {
      "name": "dev",
      "description": "開発用: ブラウザ + ターミナル",
      "windows": [ /* ... */ ]
    },
    {
      "name": "meeting",
      "description": "会議用: Zoom + メモ",
      "windows": [ /* ... */ ]
    }
  ]
}
  • レイアウトはlayoutsの記載順に表示されます
  • 文字を入力すると、レイアウト名とdescriptionの部分一致(大文字小文字は無視)でインクリメンタルサーチされます
  • Up / Down(または Ctrl+N / Ctrl+P)で選択行を移動し、Enter で選択したレイアウトを適用します
  • Esc、画面クリック、ピッカーのホットキー再押下で閉じます
  • description(任意)はピッカーの一覧に表示され、検索対象にもなります

Window Hintsから開く

windowHints.navigation.windowLayouts.keyを設定すると、Window Hints表示中にレイアウト選択ピッカーへ切り替えられます。 Window Layouts専用のグローバルホットキーを増やさず、Window Hintsを起点にレイアウト適用できます。 jinraiModeを有効にすると、通常のWindow Hints表示からでもJINRAI Modeを開始してピッカーへ移れます。 レイアウト適用後はコンボを進めてWindow Hintsへ戻ります。

"windowHints": {
  "navigation": {
    "windowLayouts": { "key": "l", "jinraiMode": true }
  }
},
"windowLayouts": {
  "layouts": [
    {
      "name": "dev",
      "description": "開発用: ブラウザ + ターミナル",
      "windows": [ /* ... */ ]
    }
  ]
}

ウィンドウのマッチ規則

各エントリは次の規則でウィンドウを特定します。

  • bundleID(必須): アプリのbundle IDと完全一致で照合します。
  • titleGlob(任意): ウィンドウタイトルをglobパターンで絞り込みます。*は任意の文字列、?は任意の1文字にマッチします。省略するとタイトルを問いません。
  • そのウィンドウにマッチしうるエントリがレイアウト内に1つだけの場合、マッチするすべてのウィンドウを同じ位置へ配置します(全取り)。
  • 複数のエントリにマッチしうるウィンドウは、エントリの記述順に最前面に近いものから1枚ずつ配置します。先のエントリで配置したウィンドウは、後のエントリのマッチ対象から除外されます。同一アプリの別ウィンドウをtitleGlobで振り分けたり、同じ条件を2回書いて前面から順に2枚配置したりできます。
"windows": [
  { "bundleID": "com.google.Chrome", "titleGlob": "*GitHub*", "area": "halfLeft" },
  { "bundleID": "com.google.Chrome", "titleGlob": "*Gmail*", "area": "quarterTopRight", "focus": true }
]

マッチしないエントリはスキップされます。レイアウトに含まれないウィンドウには、unlistedWindowsを指定しない限り一切触りません。

配置先の指定

  • area(必須): 利用可能なエリアの名前を指定します(freeAreaは使用不可)。1200x900Centerのような固定サイズ中央配置も指定できます。
  • screen(任意): 配置先ディスプレイのUUIDまたはディスプレイ別名を指定します。省略時、またはそのディスプレイが未接続のときは、そのウィンドウが現在いるディスプレイに配置します(最小化中などで判定できない場合はメインディスプレイ)。UUIDの確認方法はArea Hintsを参照してください。

接続ディスプレイによってレイアウト自体を切り替えたい場合は、プロファイルと組み合わせてください。

ウィンドウが存在しないアプリの起動 (launch)

launchtrueにすると、対象アプリのウィンドウが1枚も存在しないときにアプリを起動し、ウィンドウの出現を待ってから配置します。アプリが未起動の場合はもちろん、起動済みでもウィンドウが1枚もなければ再オープン(Dockアイコンのクリック相当)でウィンドウを開かせます。 false(デフォルト)の場合、ウィンドウが存在しないアプリのエントリはスキップされます。

出現を待つ最大時間はwindowWaitTimeout(デフォルト10秒)で変更できます。

Note

同一アプリに対して複数のエントリでlaunchを指定しても、起動直後に現れるウィンドウは通常1枚のため、2枚目以降はタイムアウトまで待った後スキップされることがあります。また、起動後の出現待ちで配置されるウィンドウは1エントリにつき1枚です(全取りは適用時にすでに表示されているウィンドウが対象)。

Note

ウィンドウが存在するのにtitleGlobに一致するウィンドウが無い場合は、launchは行われずスキップされます。また、再オープンで新規ウィンドウを開かないアプリでは、出現待ちがタイムアウトすることがあります。

URLで新規ウィンドウを開く (launch.newWindow)

launch{ "newWindow": { "url": ... } }を指定すると、エントリにマッチするウィンドウが無いときにアプリの起動(reopen)ではなくURLスキームを開いて、目的のウィンドウを直接作らせます。Obsidianの特定Vaultなど、「アプリは起動済みだが目的のウィンドウが無い」状態でも発火するのがtrueとの違いです。

"windows": [
  {
    "bundleID": "md.obsidian",
    "titleGlob": "*MyVault*",
    "area": "halfRight",
    "launch": { "newWindow": { "url": "obsidian://open?path=/path/to/MyVault" } }
  }
]

発火条件の比較(エントリにマッチするウィンドウが無い前提):

状況 launch: false(デフォルト) launch: true launch: { newWindow: { url } }
アプリ未起動 スキップ 起動 → 出現待ち URLを開く → 出現待ち
起動済み・ウィンドウ0枚 スキップ 再オープン → 出現待ち URLを開く → 出現待ち
同アプリの別ウィンドウあり(titleGlob不一致) スキップ スキップ URLを開く → 出現待ち

出現したウィンドウはtitleGlobで照合するため、URLで開くウィンドウのタイトルにマッチするtitleGlobを指定してください(省略すると同アプリの新規ウィンドウ全般にマッチします)。URLはアプリをアクティブ化せずに送るため、既存ウィンドウが一瞬前面に出ることはありません。

指定ウィンドウを必ず閉じる (closeWindows)

closeWindowsで、レイアウト適用時に必ず閉じるウィンドウを指定できます。「開発モードではSlackを閉じる」のように、特定アプリを狙い撃ちで閉じられます。

"layouts": [
  {
    "name": "dev",
    "hotkey": { "modifiers": ["ctrl", "alt"], "key": "1" },
    "closeWindows": [
      { "bundleID": "com.tinyspeck.slackmacgap" }
    ],
    "windows": [ /* ... */ ]
  }
]
  • bundleID(必須): アプリのbundle IDと完全一致で照合します。
  • titleGlob(任意): ウィンドウタイトルをglobパターンで絞り込みます(windowsと同じ規則)。

マッチしたすべてのウィンドウを閉じます(クローズボタン押下相当。アプリ自体は終了しません)。最小化されたウィンドウも対象です。閉じる処理はwindowsの配置より先に実行されます。

closeWindowsのマッチはwindowsの配置マッチより優先されます。閉じられたウィンドウは配置・フォーカス・unlistedWindowsの対象になりません。同じbundleIDwindowscloseWindowsの両方にtitleGlobなしで指定すると、常に閉じられて配置できず矛盾するため設定エラーになります(少なくとも一方にtitleGlobを指定してください)。

closeWindowsだけのレイアウトも定義できます。

"layouts": [
  {
    "name": "no-chat",
    "hotkey": { "modifiers": ["ctrl", "alt"], "key": "9" },
    "closeWindows": [
      { "bundleID": "com.tinyspeck.slackmacgap" },
      { "bundleID": "com.hnc.Discord" }
    ]
  }
]

Note

closeWindowsで閉じてもlaunch: trueの再オープン判定には影響しません(閉じたのがそのアプリ唯一のウィンドウでも、同レイアウト内のlaunch: trueは発火しません)。「一度閉じてから開き直す」用途には、既存ウィンドウの有無に関わらず発火するlaunch.newWindowを使ってください。

定義外ウィンドウの扱い (unlistedWindows)

unlistedWindowsで、現在のSpaceで表示されている標準ウィンドウのうち、レイアウトで実際に選ばれたウィンドウ以外の扱いを指定できます。

  • "close": 定義外のウィンドウをすべて閉じます。
  • { "screen": <UUIDまたは別名(任意)>, "area": <エリア名> }: 定義外のウィンドウをすべて指定位置へ一律配置します。screen省略時は各ウィンドウが現在いるディスプレイに配置するため、{ "area": "full" }で「残りは全部いまいるディスプレイの全面へ」といった指定ができます。
  • 省略時は何もしません(定義外のウィンドウには一切触りません)。
"layouts": [
  {
    "name": "dev",
    "unlistedWindows": { "screen": "desk", "area": "full" },
    "windows": [ /* ... */ ]
  }
]

unlistedWindowsはレイアウト対象のマッチ数に関わらず適用されます(1枚もマッチしなくても実行されます)。一律配置はレイアウト対象の背面に置かれます(前面には出しません)。

unlistedWindowsを指定していればwindowsは省略できます。すべての標準ウィンドウが定義外扱いになるため、「全ウィンドウを閉じる」「全ウィンドウを一律配置する」といったレイアウトを定義できます(windowscloseWindowsunlistedWindowsをすべて省略すると設定エラーです)。

"layouts": [
  {
    "name": "clear",
    "hotkey": { "modifiers": ["ctrl", "alt"], "key": "0" },
    "unlistedWindows": "close"
  }
]

適用時の挙動

  • closeWindowsで指定したウィンドウは、配置より先に閉じられます。
  • 最小化されたウィンドウは、解除してから配置します。
  • フルスクリーンのウィンドウは、フルスクリーンを自動で解除してから配置します。
  • 適用後は、focus: trueを指定したエントリのウィンドウへフォーカスします。focus: trueは1レイアウトに1件だけ指定できます。
  • focus: trueを省略した場合、または指定したエントリにマッチするウィンドウが見つからない場合は、windows配列で最後にマッチしたエントリのウィンドウへフォーカスします。
  • windowMover.behavior.cursor.afterMovetrue(デフォルト)の場合、フォーカスしたウィンドウの中央へカーソルも移動します。