2016-12-26 4 views
1

표시되지 않습니다. 실행하는 동안 창의 텍스트 내용이 변경되므로 텍스트 크기와 일치하도록 창 크기를 조정하고 싶습니다. 텍스트 범위의 크기가 변경되지 않으면 창은 항상 새 텍스트로 올바르게 업데이트됩니다.는 XResizeWindow 후, 그려 새로운 윈도우 내용은 내가 그 안에 텍스트를 그릴 창 및 <strong>카이로</strong>을 관리 할 수 ​​<strong>Xlib를</strong>를 사용하여 리눅스에서 응용 프로그램을 쓰고 있어요

그러나 텍스트 범위가 변경되어 그에 따라 창의 크기가 조정되면 창은 지워지지 만 새 텍스트는 표시되지 않습니다. XResizeWindow에 대한 호출이없는 경우에만 텍스트가 실제로 표시됩니다. 내가 사용하고 코드 나 또한 텍스트를 방법 cairo_surface_flushXFlush (예에서 주석)하지만 아무것도 변경되지 무 카이로 코드 뒤에 추가하는 시도

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); 

입니다.

편집 : 내가 두 개의 스레드를 사용하여 문제 해결 : 내용과 창의 크기 조정을 발행 두 번째 스레드를 다시 그리기 위해 노출 사건 플러스 코드를 듣고에 대한 일반적인 루프를 사용하여 첫 번째 스레드를하고 첫 번째 스레드를 깨우기 위해 Expose 이벤트를 보냅니다.

이 예제에서는 임의의 너비와 높이로 500ms마다 창 크기가 조정되고 모든 크기 조정시 프로그레시브 카운터가 표시됩니다.

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

코드는 다음과 같습니다 : 나는 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; 
     } 
    } 
} 

을하지만 문제는 남아있다 : ​​그것은 만 가능 하나의 스레드를 사용하여 동일한 결과를 얻을?

+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 인 노출 이벤트 만 처리해야합니다. 다른 문제가 발생할 가능성이 큽니다. –

+0

그래, 알았어 ...하지만 여전히 의심의 여지가 X 서버의 작동에 대해, 그리고 그것은 사실 내 질문의 원점에있다. 클라이언트가 XFlush 또는 XSync를 호출 한 후에도 서버가 창에서 실제 그리기를 수행하지 않는 이유를 이해할 수 없습니다.클라이언트가 일반적인 루프에서 XNextEvent로 Expose 이벤트를 읽는 경우에만 서버가 실제로 클라이언트 그리기 요청을 따르는 것으로 보입니다. 왜 이런거야? 클라이언트가 Expose 이벤트를 읽었는지 서버가 확인한 다음 실제 그리기를 수행합니까? – disquisitiones