最低限のWM-クライアント間通信

クライアント間通信についてはICCCMやEWMHで規定されているが、全て実装していると日が暮れるどころか年が明けても全然終わらない(そもそもWMの備える機能によっては実装する意味がないものもある)。

しかし、ICCCMで規定されているものには「最低限これはないと不味い」というものがあるので記録しておく。

== WM_DELETE_WINDOW ==
WMからウィンドウを閉じること(タイトルバーとボタンを備えたWMなら、「閉じる」ボタンが押された場合)を考える。単純な方法として`XKillClient`が存在するが、これは問答無用で対象のウィンドウを持っているクライアントを殺してしまうため以下の問題がある。
 1. クライアントの終了処理が行われない(即死する)
 1. クライアントが複数のトップレベルウィンドウを持っており、そのうちの1つを閉じる場合でもクライアント自体を殺してしまう
`WM_DELETE_WINDOW`(正確にはこれを含む`ClientMessage`イベント)をクライアントに送ることで、クライアントに終了を要求することができる。ただし全てのクライアントがこれを扱えるとは限らないので、対象ウィンドウの`WM_PROTOCOLS`プロパティを確認する必要がある。`WM_DELETE_WINDOW`を受け付けないクライアントに対しては単に`XKillClient`を実行してよい。

== WM_STATE ==
ウィンドウの状態を表すプロパティ。各トップレベルウィンドウに対して'''WMが'''設定する。ユーザにウィンドウをクリックすることでウィンドウを指定させるプログラム(例えば`xprop`とか`xkill`)はこのプロパティを使ってウィンドウを検索するらしい。このプロパティを設定しないと`xkill`が`-f`を付けないと動かないことを確認したので、多分設定しておいた方が良い。
 * 2013/02/01追記: reparentを行う場合はこれを正しく設定しないとxkillにWMを殺される悲劇が発生する。reparentによってWMの作成したフレームウィンドウがトップレベルウィンドウとなるが、reparent対象のウィンドウにWM_STATEを設定しないとフレームウィンドウを対象にKillClientリクエストが発行されてWMが死ぬ

値としては、
 * クライアントのトップレベルウィンドウが表示されていれば`NormalState`
 * トップレベルウィンドウがアイコン化されていれば`IconicState`
  * 想定しているのはトップレベルウィンドウの代わりにアイコンウィンドウが表示されている状況らしい<<FootNote(twmのタイトルバー左にあるボタンを押した時のアレ)>>が、これが実際の所どういう意味であるかはWMによる。単に「最小化」として扱っているWMもある<<FootNote(というかその方が多い気がする)>>
  * 非表示だがウィンドウが存在していることは分かるような状態<<FootNote(twmのアイコンウィンドウとか、よくあるAlt-Tabリストのような手段で)>>、と捉えるのが良さそう?
 * トップレベルウィンドウが非表示で、`IconicState`でもない場合は`WithdrawnState`
  * クライアントが、必要なくなったウィンドウを後で使うために破棄せず非表示で残しておくような場合を想定しているらしい
  * 非表示かつウィンドウの存在がユーザからは分からない状態、と捉えるのが良さそう?
作成されたばかりのトップレベルウィンドウは`WithdrawnState`にある。クライアントがトップレベルウィンドウを表示すると、WMはウィンドウの状態を`Normal`か`Iconic`のどちらかに設定する。その後、クライアントは自由に状態を変更できる。また、`WithdrawnState`への移行は'''クライアントのみ'''が行なって良いことになっている。

さらに、ICCCMでは`NormalState`にあるクライアントが`IconicState`への移行をWMに要求するためのプロトコルが定められていて<<FootNote(逆を行いたい時は単にウィンドウを表示(map)すれば良い。ただし、表示の逆(unmap)を行うと`WithdrawnState`への移行となる)>>、要求を行うクライアントはルートウィンドウに対してタイプ`WM_CHANGE_STATE`の`ClientMessage`イベントを送りつけることになっている。WMはこれを受け取って移行処理を行う。

EWMHでは`_NET_WM_STATE`が定義されていて、最大化や最小化、フルスクリーン(最大化とは意味が違う)などの状態が表せるようになっている。
 * `_NET_WM_STATE`の各状態は`NormalState`や`IconicState`に付随するもの(substate)として扱う

== WM_HINTS ==
アプリケーションがWMのために設定するプロパティ。いくつかの値が含まれる。

最低でも`InputHint`は見るべき。この値はウィンドウが入力フォーカスをどう扱うか(受動的に得る、能動的に得る、そもそも必要としない)を示していて、`False`になっているウィンドウは入力フォーカスを得ることを意図していない。代表例は`xload`とか`xclock`のような、そもそも入力を受ける余地がないものだが、より深刻な例としてはJEDのVineに入っているWnnの変換候補ウィンドウがこれに当てはまり、eclipse + Wnn有効の状況で変換候補ウィンドウにフォーカスを持っていかれてまともに入力できなくなる現象を確認した。

取得自体は簡単なので、余裕があれば他に`StateHint`とか`WindowGroupHint`、`UrgencyHint`あたりを見ると良さそう。
{{{#!highlight c
Display *dpy;
Window w;
XWMHints *wm;

wm = XGetWMHints(dpy, w);
if (wm) {
    /* wm->flagsを見て設定されている値を処理する */
    /* ... */
    XFree(wm);
}
}}}

`InputHint`がそもそも設定されていない場合は「受動的に得る」タイプとみなす。

== WM_NORMAL_HINTS ==
各ウィンドウのサイズに関する指示を示すプロパティ。クライアントが設定する。このプロパティにはクライアント側が希望するウィンドウの最小サイズ、最大サイズ、アスペクト比の範囲などの情報が含まれる。無視することもできるが「最小サイズ = 最大サイズ」となっているウィンドウは固定サイズで表示されることを期待しているので、最低限これだけは見ておいた方が良い。
 * See also: [[clear/wm_devel/2013-02-10]]