2

X11/Xlib インターフェイスを持つプログラムを書いています。イベント処理ループは次のようになります。

while (XNextEvent(display, &ev) >= 0) {
    switch (ev.type) {
        // Process events
    }
}

問題は、ウィンドウのサイズが変更されたときに、ウィンドウのExposeどの部分を再描画するかを伝える一連のイベントを取得することです。イベントに直接応答してそれらを再描画すると、再描画操作が非常に遅いため、非常に遅くなります (サイズ変更後、新しく無効化されたすべての四角形が 1 つずつ更新されることがわかります)。

私がやりたいことは、更新されたウィンドウ サイズが変更されたときに記録し、処理するイベントが残っていないときに、ウィンドウ全体 (または少なくとも 2 つの四角形) に対して 1 回だけ再描画操作を実行することです。

残念ながら、これを行う方法がわかりません。私はこれを試しました:

do {
    XPeekEvent(display, &ev);
    while (XCheckMaskEvent(display, ExposureMask | StructureNotifyMask, &ev)) {
        switch (ev.type) {
            // Process events, record but don't process redraw events
        }
    }
    // No more events, do combined redraw here
}

これは実際には機能しますが、少し効率が悪く、呼び出しに興味のないイベントが到着してXCheckMaskEventもキューから削除されないため、ブロックを停止してそこにとどまり、XPeekEventCPU 使用率が 100% になります。

私が求めている遅延/結合再描画を実現する標準的な方法があるかどうか疑問に思っていましたか? Xlib のイベント処理関数の多くはブロックしているように見えるので、ブロックする直前に何らかの処理を行いたい場合に使用するのにはあまり適していませんが、ブロックする場合に限ります!


編集:記録のために、これは私が使用したソリューションです。これは nm の簡略版です。

while (XNextEvent(display, &ev) >= 0) {
    switch (ev.type) {
        // Process events, remember any redraws needed later
    }
    if (!XPending(display)) {
        // No more events, redraw if needed
    }
}
4

2 に答える 2

4

FWIW GTK+ などの UI ツールキットは次のようにします。

  • ウィンドウごとに、「損傷領域」(すべての露出イベントの結合) を維持します。
  • ダメージ領域が空でなくなると、他に何もすることがないときにイベントループが実行される関数である「アイドルハンドラー」を追加します
  • poll()アイドル ハンドラは、イベント キューが空で、かつ X ソケットに読み取るものが何もない場合に実行されます ( onに従ってConnectionNumber(dpy))
  • もちろん、アイドルハンドラーは損傷領域を再描画します

GTK+ では、将来のバージョンでこれをより現代的な 3D エンジン指向の方法 (垂直同期で損傷領域をクリーンアップする) に変更していますが、上記のかなり単純な方法で長年にわたって機能しています。

生の Xlib に変換すると、これは nm の答えのように見えます: 損傷領域がある場合は再描画し、!XPending(). ですから、その答えを自由に受け入れてください。少し情報を追加すると思いました。

タイマーやアイドルなどが必要な場合は、libev http://software.schmorp.de/pkg/libev.htmlのようなものを検討できます。これは、アプリにいくつかのソース ファイルをドロップするように設計されています (セットアップされていません)。外部依存関係になる)。ディスプレイのファイル記述子をイベント ループに追加します。

損傷領域を追跡するために、X サーバーの「マシンに依存しない」コードからのファイル「miregion.c」をカット アンド ペーストすることがよくあります。miregion.c をググるか、X サーバーのソースをダウンロードして探してください。ここでの「領域」は、結合や交差などの操作をサポートする長方形のリストです。ダメージを追加するには、古い領域と結合し、ダメージを修復するには、減算します。

于 2012-10-14T02:21:20.303 に答える
3

次のようなことを試してください (実際にはテストされていません)。

while (TRUE) {
  if (XPending(display) || !pendingRedraws) {
    // if an event is pending, fetch it and process it
    // otherwise, we have neither events nor pending redraws, so we can
    // safely block on the event queue
    XNextEvent (display, &ev);
    if (isExposeEvent(&ev)) {
      pendingRedraws = TRUE;
    }
    else {
      processEvent(&ev);
    }
  }
  else {
    // we must have a pending redraw
    redraw();
    pendingRedraws = FALSE;
  }
}

再描画を行う前に 10 ミリ秒ほど待つと効果的です。残念ながら、生の Xlib にはタイマー用のインターフェイスがありません。そのためには、より高度なツールキットが必要です (Xt を含むすべてのツールキットには、何らかのタイマー インターフェイスがあります)。または、X11 接続の基礎となるソケットを直接操作します。

于 2012-10-13T09:02:57.483 に答える