reparentingとsaveset

トップレベルウィンドウWに対して装飾(タイトルバー等)を行う場合、装飾用のウィンドウAを作ってWの親ウィンドウとする。つまり、
{{{
root - W
}}}
だったのを
{{{
root - A - W
}}}
にし(reparenting)、その上でAに対して描画を行うことで装飾を行う。「閉じる」ボタンなどを付けたいときは、さらにボタンウィンドウを作ってAの子とするのがセオリーらしい。
{{{
root - A - W
         ` ボタン
}}}
このようにreparentを行うWMをreparenting WMと呼ぶ。だいたいのWMはreparenting WMだが、装飾を行わないタイル型WMにはそうでないもの(non-reparenting WM)も多い。
 * JavaのAWTを使用したクライアント + non-reparenting WMでUIの表示が崩れる問題があったりする
  * これはAWT側の問題なのでどうしようもない。強いて言うならre-parentすればいい
  * 広く使われているワークアラウンドとして`wmname`コマンドを使ってAWTが知っているnon-reparenting WMに偽装する方法がある

基本的にはこれだけだが、WMが終了する際に問題が起こる。一般にXクライアントが終了するとき(正確にはclose-down modeが`DestroyAll`のときらしいが普通これだろう)、そのクライアントが作成したウィンドウは階層構造に従って全て破棄される。そのため、reparent後にWMを終了するとクライアントによって作成されたウィンドウ(上のW)まで破棄されてしまう。WMの終了が即Xセッションの終了に繋がる場合(要するにexecしている場合)はそれほど問題にならないが、そうでない状況でWMの再起動や変更、クラッシュが起こった際には問題となる。

この問題に対処するためにsave-setという仕組みが用意されている。これはウィンドウのリストで、このリストにウィンドウを登録しておくとクライアント終了時に破棄されなくなる(クライアント終了時に最も近い先祖にreparentされる。上の例では、Wは再度rootの子となる)。Xlibなら`XAddToSaveSet/XRemoveFromSaveSet`、XCBなら`xcb_change_save_set`を使う。