2016-12-26 6 views
1

表示されません。実行中にウィンドウのテキスト内容が変化するので、ウィンドウサイズをテキストエクステントのサイズに合わせて調整したい。テキストエクステントのサイズが変更されない場合、ウィンドウは常に新しいテキストで正しく更新されます。はXResizeWindow後、描かれた新しいウィンドウの内容は、私はそれにいくつかのテキストを描画するウィンドウと<strong>カイロ</strong>を管理するために<strong>Xlibの</strong>を使用してLinuxでアプリケーションを書いている

しかし、ときにテキストの範囲の変更、およびウィンドウがそれに応じてサイズが変更されるので、ウィンドウがクリアされているが、新しいテキストが表示されることはありません。 XResizeWindowへの呼び出しがない場合にのみ、テキストが実際に表示されます。私が使用しているコードは

if (/* Text extent is changed */) 
{ 
    XResizeWindow (display, window, new_width, new_height); 
    cairo_xlib_surface_set_size (surface, new_width, new_height); 
} 

XClearWindow (display, window); 

/* ... Cairo code to draw the text ... */ 

// cairo_surface_flush (surface); 
// XFlush (display); 

である私は、テキストの方法cairo_surface_flushXFlush(例ではコメント)何も変更を描くカイロコードの後に​​追加しようとしました。

EDIT:私は二つのスレッド使用して問題を解決:コンテンツとウィンドウのリサイズを発行秒のスレッドを再描画するために公開するイベントプラスコードを聴くための通常のループを備えた最初のスレッドをし、 Exposeイベントを送信して、最初のスレッドを起動します。

この例では、ウィンドウは、ランダム幅と高さ毎に500ミリ秒をリサイズされ、プログレッシブカウンタはすべてのサイズ変更時に、その中に表示されます。私はC++ 11を使用し、使用してコンパイル:

#include <random> 
#include <chrono> 
#include <thread> 
#include <string> 
#include <X11/Xlib.h> 
#include <cairo/cairo-xlib.h> 

Display * d; 
Window w; 
cairo_surface_t * surface; 
int width = 300, height = 300; 
unsigned char counter = 0; 
std::random_device rd; 
std::knuth_b gen (rd()); 
std::uniform_int_distribution < > dist (150, 300); 

void logic() 
{ 
    XEvent send_event; 
    send_event.type = Expose; 
    send_event.xexpose.window = w; 

    while (true) 
    { 
     std::this_thread::sleep_for (std::chrono::milliseconds (500)); 
     ++ counter; 
     width = dist (gen); 
     height = dist (gen); 
     cairo_xlib_surface_set_size (surface, width, height); 
     XResizeWindow (d, w, width, height); 
     XSendEvent (d, w, False, ExposureMask, & send_event); 
     XFlush (d); 
    } 
} 

int main () 
{ 
    XInitThreads(); 

    d = XOpenDisplay (NULL); 
    w = XCreateSimpleWindow (d, RootWindow (d, 0), 0, 0, width, height, 0, 0, 0x000000); 
    XMapWindow (d, w); 
    XSelectInput (d, w, ExposureMask | KeyPressMask); 

    surface = cairo_xlib_surface_create (d, w, DefaultVisual (d, 0), width, height); 
    cairo_t * cairo = cairo_create (surface); 
    cairo_select_font_face (cairo, "FreeSans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); 
    cairo_set_font_size (cairo, 40); 
    cairo_set_source_rgb (cairo, 0.8, 0.8, 0.8); 
    cairo_move_to (cairo, 40.0, 60.0); 
    cairo_show_text (cairo, std::to_string (counter).c_str()); 
    XFlush (d); 

    std::thread T (logic); 

    XEvent event; 
    while (true) 
    { 
     XNextEvent (d, & event); 
     if (event.type == Expose) 
     { 
      XClearWindow (d, w); 
      cairo_move_to (cairo, 40.0, 60.0); 
      cairo_show_text (cairo, std::to_string (counter).c_str()); 
     } 
     else if (event.type == KeyPress) 
     { 
      XCloseDisplay (d); 
      return 0; 
     } 
    } 
} 

しかし、問題はまま:

g++ -std=c++11 -o test test.cpp -lX11 -lcairo -lpthread 

コードがあるだけつのスレッドを使用して同じ結果を得ることができるのですか?

+0

あなたがテストできる自己完結型の例はありますか?イベントループの外観はどのようになっていますか?つまり、露出イベントでは何をしていますか? –

+1

私は、動作を再現するコンパクトな自己完結型のコード例を提供します。 – disquisitiones

答えて

1

コードのシングルスレッドバージョンです。それはいいものではありませんが、うまくいくようです。難しい部分は、X11サーバーからのイベントとタイムアウトを同時に待っています。次のコードでselect()でこれを行います。 XResizeWindowは常に私たちが望むものと仮定するのではなく、ConfigureNotifyイベントを処理することに注意してください。

#include <random> 
#include <chrono> 
#include <thread> 
#include <string> 
#include <X11/Xlib.h> 
#include <cairo/cairo-xlib.h> 
#include <sys/time.h> 

Display * d; 
Window w; 
cairo_surface_t * surface; 
int width = 300, height = 300; 
unsigned char counter = 0; 
std::random_device rd; 
std::knuth_b gen (rd()); 
std::uniform_int_distribution < > dist (150, 300); 

void do_update() 
{ 
     ++ counter; 
     width = dist (gen); 
     height = dist (gen); 
     XResizeWindow (d, w, width, height); 
     // Force a redraw 
     XClearArea(d, w, 0, 0, 0, 0, True); 
} 

int main () 
{ 
    XInitThreads(); 

    d = XOpenDisplay (NULL); 
    w = XCreateSimpleWindow (d, RootWindow (d, 0), 0, 0, width, height, 0, 0, 0x000000); 
    XMapWindow (d, w); 
    XSelectInput (d, w, ExposureMask | KeyPressMask); 

    surface = cairo_xlib_surface_create (d, w, DefaultVisual (d, 0), width, height); 
    cairo_t * cairo = cairo_create (surface); 
    cairo_select_font_face (cairo, "FreeSans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); 
    cairo_set_font_size (cairo, 40); 
    cairo_set_source_rgb (cairo, 0.8, 0.8, 0.8); 
    cairo_move_to (cairo, 40.0, 60.0); 
    cairo_show_text (cairo, std::to_string (counter).c_str()); 
    XFlush (d); 

    struct timeval next_update; 
    struct timeval now; 
    struct timeval interval = { 0, 500000 }; 
    gettimeofday(&now, NULL); 
    timeradd(&now, &interval, &next_update); 

    while (true) 
    { 
     XEvent event; 

     gettimeofday(&now, NULL); 
     if (timercmp(&now, &next_update, >)) { 
      // Store time of next update 
      timeradd(&now, &interval, &next_update); 
      puts("update"); 
      do_update(); 
     } 

     if (!XPending(d)) { 
      struct timeval remaining; 
      fd_set fds; 
      int fd = ConnectionNumber(d); 
      FD_ZERO(&fds); 
      FD_SET(fd, &fds); 
      timersub(&next_update, &now, &remaining); 
      select(fd + 1, &fds, NULL, NULL, &remaining); 
     } else { 
      XNextEvent (d, & event); 
      if (event.type == Expose) 
      { 
       XClearWindow (d, w); 
       cairo_move_to (cairo, 40.0, 60.0); 
       cairo_show_text (cairo, std::to_string (counter).c_str()); 
      } 
      if (event.type == ConfigureNotify) 
      { 
       cairo_xlib_surface_set_size (surface, event.xconfigure.width, event.xconfigure.height); 
      } 
      else if (event.type == KeyPress) 
      { 
       XCloseDisplay (d); 
       return 0; 
      } 
     } 
    } 
} 
+0

コードは非常に興味深いです、ありがとう。いくつかの質問があります:1)** select **関数は、単にタイマーを待機し実装するために使用されますか?また、ディスプレイのファイル記述子で非ブロック読み取りを待つことに関連するものがありますか? 2)update()で使用されるClearArea関数は、サーバーからのExposeイベントの送信をトリガするためにのみ使用されますか? – disquisitiones

+0

1)まあ... select()は "時間が経過するまで待つが、到着したらすぐにサーバーからのすべてのイベントを処理する"のに使われる。 2)うん。 3)私はこのコードをどのようにも最適化しなかったことに注意してください。描画後にcairo_surface_flush()を呼び出さなければなりません。それは、カウント項目がゼロであるイベントの公開のみを処理する必要があります。 –

+0

しかし、それを得ました...しかし、まだ疑いが残っているのは、Xサーバの動作です。実際は私の質問の元になっています。クライアントがXFlushまたはXSyncを呼び出した後でさえ、サーバーが実際の描画をウィンドウで実行しない理由がわかりません。クライアントが通常のループでExposeイベントをXNextEventで読み取っている場合にのみ、サーバーは実際にクライアントの描画要求を受け入れます。どうしてこれなの?クライアントがExposeイベントを読み取った後、実際の描画を実行しているかどうかサーバーがチェックしていますか? – disquisitiones

関連する問題

 関連する問題