我正在尝试学习如何在xlib表面上使用Cairo 2D drawing library。
我写了一个小的测试程序,可以创建多个窗口。每个函数都有一个自定义的paint()函数,该函数会定期调用以向窗口添加一些图形内容,或者根据需要完全重绘它。还有一个选项可以定义鼠标和按键侦听器。主要例程检查X事件(将它们委派给鼠标和按键侦听器),并检查是否定期超时调用这些paint()函数。
我尝试了1.14.6版本的Cairo(目前可在Ubuntu 16.04中作为软件包使用)和最新的1.15.12,但是结果是相同的。
此演示的预期行为是打开3个窗口。一个将添加随机矩形,另一个将添加随机文本,第三个将随机添加圆形。
此外,单击窗口应会产生线条(连接到鼠标单击或随机单击),并使用箭头键在窗口中用圆圈绘制一条红线。
圈子和文字似乎按预期规律显示。所有三个窗口都应具有白色背景,但其中两个是黑色。最糟糕的是,带有矩形的窗口更新得并不多(无论是否创建了第一个窗口,它始终不会正确显示矩形)。
仅当焦点切换到该窗口或从该窗口更改焦点时才显示它们-然后本应绘制的其余矩形突然出现。
添加任何内容后,我在每个窗口的表面上调用cairo_surface_flush(),但这无济于事。我还尝试过将XEvents发布到各种类型的窗口(例如焦点),它们到达了,但是矩形不显示。
此外,即使使用鼠标绘制线条效果很好,但带有键箭头的绘制线条也存在相同的问题-已绘制,但显示不正确。
在我对该库可以做什么的某些假设中,我显然是错误的,但是我不确定在哪里。
似乎显示了一些相互竞争的图形版本,因为有时会发生一个或两个矩形或红线闪烁的情况。某种奇怪的缓冲,缓存? 我不知道这可能只是我程序中的一些错误。
另一个观察结果-黑色背景是因为绘制白色背景发生在显示窗口之前,因此以某种方式丢弃了这些cairo_paint调用。我不知道如何使窗口更早出现,似乎仅在稍后在屏幕上进行更改后才出现。
经过几天的绝望,我被困在了这里,请您至少部分帮助我吗?
程序在这里:test_cairo.c
一个示例屏幕截图(按键绘制了一条红色虚线,矩形显示不正确):test_cairo.png
要编译(在Ubuntu 16.04或类似系统上):
gcc -o test_cairo test_cairo.c -I/usr/include/cairo -lX11 -lcairo
答案 0 :(得分:1)
X11不会为您保留窗口内容。当您遇到Expose事件时,必须完全重绘该事件描述的区域。
所有三个窗口都应具有白色背景,但是其中两个是黑色。
您使用XCreateSimpleWindow
创建窗口,因此其背景属性设置为黑色。 X11服务器将在发送暴露事件之前为您填充黑色的暴露区域。由于您不告诉开罗绘制白色背景,因此黑色保持不变。
尝试一下:
--- test_cairo.c.orig 2018-07-28 09:53:10.000000000 +0200
+++ test_cairo.c 2018-07-29 10:52:43.268867754 +0200
@@ -63,6 +63,7 @@ static gui_mouse_callback mouse_callback
static cairo_t *windows[MAX_GUI_WINDOWS_COUNT];
static cairo_surface_t *surfaces[MAX_GUI_WINDOWS_COUNT];
+static cairo_surface_t *real_surfaces[MAX_GUI_WINDOWS_COUNT];
static Window x11windows[MAX_GUI_WINDOWS_COUNT];
static char *window_names[MAX_GUI_WINDOWS_COUNT];
@@ -79,7 +80,12 @@ long long usec()
void repaint_window(int window_handle)
{
draw_callbacks[window_handle](windows[window_handle]);
- cairo_surface_flush(surfaces[window_handle]);
+
+ cairo_t *cr = cairo_create(real_surfaces[window_handle]);
+ cairo_set_source_surface(cr, surfaces[window_handle], 0, 0);
+ cairo_paint(cr);
+ cairo_destroy(cr);
+ cairo_surface_flush(real_surfaces[window_handle]);
}
int gui_cairo_check_event(int *xclick, int *yclick, int *win)
@@ -149,7 +155,6 @@ void draw_windows_title(int window_handl
sprintf(fullname, "Mikes - %d - [%s]", window_handle, context_names[current_context]);
else
sprintf(fullname, "Mikes - %s - [%s]", window_names[window_handle], context_names[current_context]);
- cairo_surface_flush(surfaces[window_handle]);
XStoreName(dsp, x11windows[window_handle], fullname);
}
@@ -179,20 +184,17 @@ int gui_open_window(gui_draw_callback pa
}
if (window_handle < 0) return -1;
- surfaces[window_handle] = gui_cairo_create_x11_surface(&width, &height, window_handle);
+ real_surfaces[window_handle] = gui_cairo_create_x11_surface(&width, &height, window_handle);
+ surfaces[window_handle] = cairo_surface_create_similar(real_surfaces[window_handle], CAIRO_CONTENT_COLOR, width, height);
windows[window_handle] = cairo_create(surfaces[window_handle]);
mouse_callbacks[window_handle] = 0;
draw_callbacks[window_handle] = paint;
window_update_periods[window_handle] = update_period_in_ms;
window_names[window_handle] = 0;
-
- cairo_surface_flush(surfaces[window_handle]);
cairo_set_source_rgb(windows[window_handle], 1, 1, 1);
cairo_paint(windows[window_handle]);
-
- cairo_surface_flush(surfaces[window_handle]);
draw_callbacks[window_handle](windows[window_handle]);
@@ -201,7 +203,6 @@ int gui_open_window(gui_draw_callback pa
else next_window_update[window_handle] = 0;
draw_windows_title(window_handle);
- cairo_surface_flush(surfaces[window_handle]);
window_in_use[window_handle] = 1;
return window_handle;
@@ -213,6 +214,7 @@ void gui_close_window(int window_handle)
cairo_destroy(windows[window_handle]);
cairo_surface_destroy(surfaces[window_handle]);
+ cairo_surface_destroy(real_surfaces[window_handle]);
window_in_use[window_handle] = 0;
int no_more_windows = 1;
for (int i = 0; i < MAX_GUI_WINDOWS_COUNT; i++)