cairo / xlib 未更新 window 内容
cairo / xlib not updating window content
我正在尝试学习如何将 Cairo 2D drawing library 与 xlib 表面一起使用。
我写了一个允许创建多个 windows 的小测试程序。每个函数都可能有一个自定义的 paint() 函数,该函数会定期调用以将一些图形内容添加到 window,或者根据需要完全重绘它。还有一个选项可以定义鼠标和按键侦听器。主例程检查 X 事件(将它们委托给鼠标和按键侦听器)以及定期调用这些 paint() 函数的超时。
我尝试使用 1.14.6 版本的 Cairo(目前在 Ubuntu 16.04 中作为软件包提供)和最新的 1.15.12,但结果是一样的。
此演示的预期行为是打开 3 windows。一个将添加随机矩形,另一个将添加随机文本,第三个将添加随机圆圈。
此外,点击进入windows应该会产生线条(连接到鼠标点击,或随机),并且使用箭头键应该在window中用圆圈画一条红线。
圆圈和文字似乎按预期定期显示。所有三个 windows 都应该是白色背景,但其中两个是黑色的。最糟糕的是,带有矩形的 window 并没有得到太多更新(并且它是否是第一个 window 创建的并不重要,它总是没有正确显示的矩形)。
它们仅在焦点从 window 改变或改变时显示 - 然后本应同时绘制的其余矩形突然出现。
我在添加任何内容后在每个 window 的表面上调用 cairo_surface_flush(),但这没有帮助。我还尝试将 XEvents 发布到 window 各种类型(例如焦点),它们到达了,但是没有显示矩形。
此外,即使用鼠标画线工作正常,用键箭头画线也会遇到同样的问题——它被画了,但没有正确显示。
我对这个库可以做什么的一些假设显然是错误的,但我不确定在哪里。
似乎显示了两个竞争版本的绘图,因为有时会出现一个或两个矩形或红线段在闪烁。某种奇怪的缓冲、缓存?
这可能只是我程序中的一些错误,我不知道。
另一个观察 - 黑色背景是因为绘制白色背景发生在 window 显示之前,因此那些 cairo_paint 调用以某种方式被丢弃。我不知道如何让 window 出现得更早,它似乎只是在屏幕上进行一些稍后的更改后才会出现。
经过几天的绝望,我被困在这个问题上,你能至少帮助我部分吗?
节目在这里:test_cairo.c
示例屏幕截图(按键绘制的红色虚线,以及未正确显示的矩形):test_cairo.png
要编译(在 Ubuntu 16.04 或类似系统上):
gcc -o test_cairo test_cairo.c -I/usr/include/cairo -lX11 -lcairo
X11 不会为您保留 window 内容。当您收到 Expose 事件时,您必须完全重新绘制该事件描述的区域。
All three windows should have white background, but two of them are black.
您使用 XCreateSimpleWindow
创建了 window,因此它们的背景属性设置为黑色。 X11 服务器会在发送暴露事件之前为您用黑色填充暴露区域。由于您没有告诉 cairo 绘制白色背景,因此黑色保持不变。
试试这个:
--- 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++)
我正在尝试学习如何将 Cairo 2D drawing library 与 xlib 表面一起使用。
我写了一个允许创建多个 windows 的小测试程序。每个函数都可能有一个自定义的 paint() 函数,该函数会定期调用以将一些图形内容添加到 window,或者根据需要完全重绘它。还有一个选项可以定义鼠标和按键侦听器。主例程检查 X 事件(将它们委托给鼠标和按键侦听器)以及定期调用这些 paint() 函数的超时。
我尝试使用 1.14.6 版本的 Cairo(目前在 Ubuntu 16.04 中作为软件包提供)和最新的 1.15.12,但结果是一样的。
此演示的预期行为是打开 3 windows。一个将添加随机矩形,另一个将添加随机文本,第三个将添加随机圆圈。
此外,点击进入windows应该会产生线条(连接到鼠标点击,或随机),并且使用箭头键应该在window中用圆圈画一条红线。
圆圈和文字似乎按预期定期显示。所有三个 windows 都应该是白色背景,但其中两个是黑色的。最糟糕的是,带有矩形的 window 并没有得到太多更新(并且它是否是第一个 window 创建的并不重要,它总是没有正确显示的矩形)。
它们仅在焦点从 window 改变或改变时显示 - 然后本应同时绘制的其余矩形突然出现。
我在添加任何内容后在每个 window 的表面上调用 cairo_surface_flush(),但这没有帮助。我还尝试将 XEvents 发布到 window 各种类型(例如焦点),它们到达了,但是没有显示矩形。
此外,即使用鼠标画线工作正常,用键箭头画线也会遇到同样的问题——它被画了,但没有正确显示。
我对这个库可以做什么的一些假设显然是错误的,但我不确定在哪里。
似乎显示了两个竞争版本的绘图,因为有时会出现一个或两个矩形或红线段在闪烁。某种奇怪的缓冲、缓存? 这可能只是我程序中的一些错误,我不知道。
另一个观察 - 黑色背景是因为绘制白色背景发生在 window 显示之前,因此那些 cairo_paint 调用以某种方式被丢弃。我不知道如何让 window 出现得更早,它似乎只是在屏幕上进行一些稍后的更改后才会出现。
经过几天的绝望,我被困在这个问题上,你能至少帮助我部分吗?
节目在这里:test_cairo.c
示例屏幕截图(按键绘制的红色虚线,以及未正确显示的矩形):test_cairo.png
要编译(在 Ubuntu 16.04 或类似系统上):
gcc -o test_cairo test_cairo.c -I/usr/include/cairo -lX11 -lcairo
X11 不会为您保留 window 内容。当您收到 Expose 事件时,您必须完全重新绘制该事件描述的区域。
All three windows should have white background, but two of them are black.
您使用 XCreateSimpleWindow
创建了 window,因此它们的背景属性设置为黑色。 X11 服务器会在发送暴露事件之前为您用黑色填充暴露区域。由于您没有告诉 cairo 绘制白色背景,因此黑色保持不变。
试试这个:
--- 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++)