= 入力フォーカスについて = ICCCM 4.1.7および4.2.7にフォーカスの扱いに関するあれこれが書いてあるがとても分かりにくい。とりあえず、WMの視点で必要な情報をまとめる。 == 入力モデル == ICCCMではキーボード入力の扱い方に関して4通りの方法が示されている。WMがこれを無視すると使い物にならなくなる。 * No Input - 一切のキーボード入力を受け取らない。フォーカスを与えられることを意図していない * 出力のみを行うようなクライアント * Passive Input - キーボード入力を受けとるが、自分自身で明示的に入力フォーカスを設定することはない * 子ウィンドウを持たない単純なクライアントなど。WMがフォーカスを設定してくれることを期待する * Locally Active Input - 自分(クライアント)のウィンドウのどれかが既にフォーカスを得ているときのみ、自分自身で明示的にフォーカスを設定する * 親ウィンドウがフォーカスを得たとき、子ウィンドウにフォーカスを与えたいような場合(例:テキストボックス) * Globally Active Input - フォーカスの所在に関わらず自分自身で明示的にフォーカスを設定する * ICCCM 4.1.7にはスクロールバーを持ったウィンドウの例が書いてあるが良く分からない クライアントがどの入力モデルを採用しているかは、WM_HINTSプロパティのInputフィールドの値、および当該クライアントがWM_TAKE_FOCUSプロトコルに対応しているか、の組み合わせで示される。 || 入力モデル || WM_HINTSのInputフィールド || WM_TAKE_FOCUS || || No Input || False || 非対応 || || Passive || True || 非対応 || || Locally Active || True || 対応 || || Globally Active || False || 対応 || * Inputフィールドの意味 * True: 当該クライアントがフォーカスを得るためにWMの助けを必要とする * False: WMが当該クライアントにフォーカスを設定しないことを期待する * ユーザにフォーカス設定を指示させる方法はWMが好きに決めて良い * WM_TAKE_FOCUSに対応しているクライアントにWM_TAKE_FOCUSを送ると、向こうで勝手にフォーカスを設定する * ただし、Locally Activeの場合はWM_TAKE_FOCUSに先だってWM側で一度フォーカスを与えておく必要がある == フォーカスの設定 == フォーカスの設定はSetInputFocusリクエストを送ることで行う。 * timestampフィールド: 競合状態を防ぐためのタイムスタンプ * ICCCMには、現在のサーバ時刻を使わず、SetInputFocusする原因となったイベントのタイムスタンプを使わなければならないと書いてある * しかし全てのイベントにタイムスタンプがある訳ではないし、そもそもWMはイベントへの反応としてのみフォーカスを設定するとは限らない… * 色々なWMでの実装 * awesome,twm: タイムスタンプ付きイベントが来たときにタイムスタンプを更新し、以後それを使う * Openbox: 上記+フェイクのタイムスタンプ付きイベントを自作自演してタイムスタンプを更新(同じタイムスタンプを2度使わない?) * fluxbox,dwm,evilwm,aewm: 現在のサーバ時刻 * revert-toフィールド: フォーカス後、対象ウィンドウが不可視になった際にどこにフォーカスを与えるかを指定する * フォーカス設定時点で対象ウィンドウは可視でなければならない * 指定できる値にはParent, PointerRoot, Noneがあるが、基本的にParent(最も近い祖先)を指定すべき(PointerRootもNoneもそれぞれに問題があるらしい) * WM終了時はフォーカスを返す * いくつかのWMを読んでみた所、マウスカーソルのあるルートウィンドウにフォーカスすれば良いらしい * 少なくとも、終了時に関しては現在のサーバ時刻を使っても良さそう(twmもそうしている) = タイムスタンプについて = クライアント間の競合状態(レースコンディション)を防ぐためにタイムスタンプが使われる。 * 時刻はミリ秒単位となっている * いくつかのイベント(全部ではない)にはタイムスタンプが付いている * マウスボタンのイベントにはタイムスタンプがついており、ダブルクリックの判定に使える(Xには「ダブルクリックイベント」は存在しない) * いくつかのリクエストを送信する際にはタイムスタンプを指定する必要がある * 「現在のサーバ時刻」を表すための特別な値がある * Xlibでは`CurrentTime`、XCBでは`XCB_CURRENT_TIME` Xサーバは以下の時刻を保持しているらしい: * 最後に入力フォーカスが変化した時刻 * 最後にキーボードがグラブされた時刻 * 最後にマウスポインタがグラブされた時刻 * 最後にセレクションが変更された時刻