サイズ: 3395
コメント:
|
サイズ: 3661
コメント:
|
削除された箇所はこのように表示されます。 | 追加された箇所はこのように表示されます。 |
行 7: | 行 7: |
* これが一番真っ当な方法に思えるが、やってみるとイベントを適切なタイミングで拾えない(`MapNotify`直後の`Expose`とか、`DestroyNotify`とか) | * これが一番真っ当な方法に思えるが、やってみるとイベントを適切なタイミングで拾えない(`MapNotify`直後の`Expose`とか、`DestroyNotify`とか<<FootNote(後から考えたが、この手のイベントはリクエスト(`MapWindow`とか`DestroyWindow`)に反応して発生する->リプライとかと一緒に届いてイベントキューに入る->selectでは適切なタイミングで拾えない?)>>) |
2013年1月
- あけました
01/01
stdinから与えられた文字列をひたすらウィンドウに表示するツール1が欲しくなったので作ろうとしている(xcbで書いてる)が、Xのイベントを捌きつつstdinからの入力を処理する必要がある。しばらく前からいくつかの方法を試しているが中々上手く行かなかった。
stdin(0番)とXのfd(xcb_get_file_descriptor()で取れる)をselectする
これが一番真っ当な方法に思えるが、やってみるとイベントを適切なタイミングで拾えない(MapNotify直後のExposeとか、DestroyNotifyとか2)
xevやxmonなどのツールで確認したところ、サーバからイベントは届いている(が、上手く取得できていない)
イベントをポーリング(xcb_poll_for_event)して、イベントが来てないときは標準入力を読む
WindowsでよくあるPeekMessageを使う方法と同じ発想。Unix的ではない?
普通にやるとreadがブロックしてイベントを拾えなくなるので、待ち時間0でselectする
- このままだと全力で回り続けるのでCPUを100%食う
sched_yieldで残りタイムスライスを放棄できるらしい(Windows APIで言うところのSleep(0))。これを使ってみたが、依然としてそれなりに(手元のマシンで5%ほど)CPUを食う
- もっと長くスリープすればCPU使用率は下がるだろうが、イベント処理が遅れる可能性がある
- イベントを取りこぼす問題は起こらない
まだ試していないのはマルチスレッド化(Xイベント処理/入力処理の2スレッド)だがあまりやりたくない。最初の方法でイベントを上手く拾えない原因を突き止めたいところ。
- もしかして: イベントキューに入ってる
イベントがソケットのバッファから読み出されてXCBのイベントキューに入ってしまえば、selectでは検知不能
この場合select + キューにイベントがあるかの確認を行えばキューにイベントがあるかを確認して、イベントがあれば処理し、無ければselectすれば良さそう
xcb_poll_for_queued_event()という非常にそれっぽい関数を発見した
- FreeBSDのportsにあるlibxcbはバージョンが古く、この関数がない
- 自分で最新のxcbをビルドして試したところ期待通りに動いたので、仮説は正しかった模様
最終的にはこうなった。
1 xcb_connection_t *conn;
2 xcb_generic_event_t *event;
3 // ...
4 int fd_x = xcb_get_file_descriptor(conn);
5 for (;;) {
6 if (event = xcb_poll_for_queued_event(conn)) {
7 eventを処理
8 } else {
9 0とfd_xをselect
10 if (FD_ISSET(fd_x, ...)) {
11 event = xcb_wait_for_event(conn);
12 eventを処理
13 } else if (FD_ISSET(0, ...)) {
14 stdinからの入力を処理
15 }
16 }
17 }