【发布时间】:2023-03-16 20:10:01
【问题描述】:
我正在 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;
}
}
}
但还有一个问题:是否有可能只使用一个线程获得相同的结果?
【问题讨论】:
-
您有可以测试的独立示例吗?你的事件循环是什么样子的,即你在 Expose 事件上做了什么?
-
好的,我将提供一个紧凑的独立代码示例来重现该行为。
标签: linux resize window cairo xlib