通过开罗表面绘画时清除 X window 的正确方法是什么
What is the proper way of clearing an X window when painting on it via a Cairo surface
我正在尝试使用 Cairo 在透明 X window 上绘图。根据官方 Cairo FAQ,清除透明表面的一种方法是将 Cairo 运算符设置为 CLEAR。这在我的情况下似乎不起作用。我正在画一个不断扩大和缩小的实心圆圈。最初,圆圈变大,但当它缩小时,大圆圈仍留在 window 上。这让我觉得也许我应该在每次重绘时也清除 X window 本身。
这是我想出的代码
XClearWindow(self->display, self->win_id);
cairo_push_group(self->context);
// Re-draw the whole canvas: Doesn't work as expected
// cairo_save(self->context);
// cairo_set_operator(self->context, CAIRO_OPERATOR_CLEAR);
// cairo_paint(self->context);
// cairo_restore(self->context);
// Invoke the draw callback <- Cairo drawing done here from Python
Canvas_on_draw(self, args_tuple, NULL);
cairo_pop_group_to_source(self->context);
cairo_paint(self->context);
cairo_surface_flush(self->surface);
XFlush(self->display);
如您所见,我的解决方案是在使用 Cairo 绘图之前调用 XClearWindow
,然后使用 XFlush
刷新所有内容。但是,我不确定这是最干净的解决方案,感觉有点像 hack 而不是正确的方法。例如,如果没有 XFlush
,我会出现相当大的闪烁,但 Xlib 文档似乎暗示大多数应用程序不需要直接调用此函数。
编辑:在下面的答案之后,这就是我的代码:
cairo_push_group(self->context);
// Draw stuff
cairo_pop_group_to_source(self->context);
// The following cairo paradigm seems to have the same
// effect as the following commented out lines:
// XClearWindow(self->display, self->win_id);
// cairo_paint(self->context);
cairo_save(self->context);
cairo_set_operator(self->context, CAIRO_OPERATOR_SOURCE);
cairo_paint(self->context);
cairo_restore(self->context);
这达到了预期的效果。
在最后的 cairo_paint()
之前添加 cairo_set_operator(self->context, CAIRO_OPERATOR_SOURCE);
。
您正在清除您创建的中间组。这意味着它在圆圈外是完全透明的。然后使用默认运算符 OVER
将此组绘制到目标 window。在任何东西上绘制完全透明只会留下旧内容。使用 SOURCE
绘图实际上将源复制到目标表面。
旁注:您的 XClearWindow
方法不能保证有效,除非您根据需要调用 cairo_surface_flush
和 cairo_surface_mark_dirty
。
我正在尝试使用 Cairo 在透明 X window 上绘图。根据官方 Cairo FAQ,清除透明表面的一种方法是将 Cairo 运算符设置为 CLEAR。这在我的情况下似乎不起作用。我正在画一个不断扩大和缩小的实心圆圈。最初,圆圈变大,但当它缩小时,大圆圈仍留在 window 上。这让我觉得也许我应该在每次重绘时也清除 X window 本身。
这是我想出的代码
XClearWindow(self->display, self->win_id);
cairo_push_group(self->context);
// Re-draw the whole canvas: Doesn't work as expected
// cairo_save(self->context);
// cairo_set_operator(self->context, CAIRO_OPERATOR_CLEAR);
// cairo_paint(self->context);
// cairo_restore(self->context);
// Invoke the draw callback <- Cairo drawing done here from Python
Canvas_on_draw(self, args_tuple, NULL);
cairo_pop_group_to_source(self->context);
cairo_paint(self->context);
cairo_surface_flush(self->surface);
XFlush(self->display);
如您所见,我的解决方案是在使用 Cairo 绘图之前调用 XClearWindow
,然后使用 XFlush
刷新所有内容。但是,我不确定这是最干净的解决方案,感觉有点像 hack 而不是正确的方法。例如,如果没有 XFlush
,我会出现相当大的闪烁,但 Xlib 文档似乎暗示大多数应用程序不需要直接调用此函数。
编辑:在下面的答案之后,这就是我的代码:
cairo_push_group(self->context);
// Draw stuff
cairo_pop_group_to_source(self->context);
// The following cairo paradigm seems to have the same
// effect as the following commented out lines:
// XClearWindow(self->display, self->win_id);
// cairo_paint(self->context);
cairo_save(self->context);
cairo_set_operator(self->context, CAIRO_OPERATOR_SOURCE);
cairo_paint(self->context);
cairo_restore(self->context);
这达到了预期的效果。
在最后的 cairo_paint()
之前添加 cairo_set_operator(self->context, CAIRO_OPERATOR_SOURCE);
。
您正在清除您创建的中间组。这意味着它在圆圈外是完全透明的。然后使用默认运算符 OVER
将此组绘制到目标 window。在任何东西上绘制完全透明只会留下旧内容。使用 SOURCE
绘图实际上将源复制到目标表面。
旁注:您的 XClearWindow
方法不能保证有效,除非您根据需要调用 cairo_surface_flush
和 cairo_surface_mark_dirty
。