ウィンドウが消えます。Alt-Tab に出ず、タスクバーにも並ばない。プロセスは動いたままです。
GlazeWM は非アクティブなワークスペースのウィンドウを画面外へ退かしません。DWM の cloak をかけます。cloak されたウィンドウは合成の対象から外れ、それ以外は元のままです。API に聞けば可視だと答え、画面内の矩形を返し、最小化フラグも立っていません。 z オーダーを上げても出てきません。
GlazeWM を起動し直すと、シェルが報告するウィンドウを列挙します。cloak されているものもそこに並びますが、直前まで管理下にあったという情報は付いてきません。管理だけが失われ、cloak は残ったままになります。
意図的な再起動は稀
実際にこの状態を作るのは 3 つです。
- GlazeWM がクラッシュして起動し直したとき
- モニターを挿したとき、外したとき
- プレゼンテーションモードを on / off したとき
後ろの 2 つは同じ事象です。ディスプレイ構成が変わると、GlazeWM はモニターとワークスペースの対応を作り直します。そこで参照するのはシェルの報告で、cloak は現在値としてしか読めません。誰がいつ付けたかは、どこにも残っていないのです。
見ていないワークスペースへウィンドウを送る設定は、どれも該当件数を押し上げます。送られた先で即座に cloak されるからです。起動時にアプリを所定のワークスペースへ配置する window_rules が、たいていの発生源になります。
cloak を外せるのは所有プロセスだけ
別プロセスから DwmSetWindowAttribute(DWMWA_CLOAK, 0) を呼ぶとE_ACCESSDENIED が返ります。権限を上げても変わりません。GlazeWM 自身も同じユーザーの非昇格プロセスで、cloak には未文書のシェル COM 経由で触れていて、その
vtable レイアウトは Windows のビルドごとに変わる。汎用の復帰手段はここで消えます。残るのは、アプリ側が入口を持っている場合だけ。
wezterm は持っています。GUI プロセスごとに~/.local/share/wezterm/gui-sock-<pid> へ制御ソケットを開いているので、WEZTERM_UNIX_SOCKET をそこへ向ければ wezterm cli の宛先がそのプロセスに固定されます。ペインを新しいウィンドウへ移すよう指示すると、ウィンドウを作るのは
wezterm 自身です。作られたばかりのウィンドウに cloak は付いていません。
glazewm/rescue-window.ps1 は、そのプロセスが持つペインを全部集めます。cloak
されていないウィンドウに既にあったぶんも一緒に、新しいウィンドウへ移します。それ以外のアプリでは、分かっていることを表示して終わりです。アプリを再起動するか、explorer.exe を再起動してシェル側の cloak を全ウィンドウ分リセットするか。
「管理されていない」は 3 種類ある
難しいのは復帰よりも一覧のほうでした。「GlazeWM が管理していない」という条件は、異常 1 種と正常 2 種を同時に拾ってしまいます。
| cloak | immersive | ||
|---|---|---|---|
| 管理を失った | > 0 | いいえ | どこにも描かれない。対処すべきもの |
| 未管理だが描画済み | 0 | — | config.yaml の ignore ルール |
| サスペンド中の UWP | > 0 | はい | シェルによる cloak で GlazeWM は無関係 |
このマシンでは ignore ルールが 11 プロセスぶん動いていて、UWP のサスペンドも常時起きています。3 つを同じ扱いで出すと、直したい 1 件が十数件の中に沈みます。
1 行目と 3 行目を分けるのが IsImmersiveProcess です。現在管理下にあるハンドルはglazewm query windows が JSON で返すので、全体からそれを引きます。全体のほうはEnumWindows の結果を、タイトルを持つトップレベルのうち最小化でもツールウィンドウでもないものに絞ったものです。