我正在Linux中编写一个应用程序,使用Xlib管理窗口,使用cairo在窗口中绘制一些文本。窗口的文本内容在执行过程中会发生变化,因此我想调整窗口大小以匹配文本范围。如果文本范围的大小不变,窗口将始终正确更新为新文本。
但是当文本范围改变时,窗口会相应地调整大小,窗口会被清除,但新文本永远不会显示。只有当没有调用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(在示例中注解),但没有任何变化。
编辑:我用两个线程解决了这个问题:第一个线程使用通常的循环来监听Expose事件,加上重绘内容的代码,第二个线程发出窗口的大小调整,并发送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;
}
}
}
- 但还有一个问题 * 是否可以只使用一个线程获得相同的结果?
1条答案
按热度按时间ttygqcqt1#
下面是您的代码的单线程版本。这不是很好,但它似乎工作。困难的部分是同时等待来自X11服务器的事件和超时。我在下面的代码中使用
select()
来实现这一点。请注意,我还处理ConfigureNotify
事件,而不是假设XResizeWindow
总是按照我们的要求运行。