Я пишу приложение в Linux с помощью Xlib для управления окном и Каира нарисовать какой-нибудь текст в нем. Текстовое содержимое окна изменяется во время выполнения, поэтому я хочу адаптировать размер окна, чтобы он соответствовал размеру текста. Если размер текста не изменяется, окно всегда корректно обновляется новым текстом.После XResizeWindow, новое содержимое окна обращается не отображается
Но когда размер текста изменяется, и поэтому окно изменяется соответственно, окно очищается, но новый текст никогда не отображается. Только если нет вызова 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, который черпает методы cairo_surface_flush и XFlush (прокомментировал в пример), но ничего не изменяет текст.
EDIT: Я решил проблему с помощью две темы: первый поток с обычной петлей для прослушивания разоблачительных событий плюс код для перерисовки содержимого и второго потока, который выдает изменения размера окна и отправляет событие Expose для пробуждения первого потока.
В этом примере окно изменяется каждые 500 мс до случайной ширины и высоты, и при каждом изменении размера отображается прогрессивный счетчик. Я использую C++ 11, компилировать с:
g++ -std=c++11 -o test test.cpp -lX11 -lcairo -lpthread
Код:
#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;
}
}
}
Но вопрос остается: можно ли получить тот же результат, используя только один нить?
У вас есть самодостаточный пример, который можно было бы проверить? Как выглядит ваш цикл событий, т. Е. Что вы делаете в событиях Expose? –
Хорошо, я дам компактный самодостаточный пример кода, который воспроизводит поведение. – disquisitiones