【问题标题】:cairo / xlib not updating window contentcairo / xlib 不更新窗口内容
【发布时间】:2019-01-05 05:35:48
【问题描述】:

我正在尝试学习如何将Cairo 2D drawing library 与 xlib 表面一起使用。

我编写了一个允许创建多个窗口的小测试程序。每个函数都可能有一个自定义的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 

【问题讨论】:

  • 写下来促使我尝试更多,一些解决方法: 1. 缺少矩形:同时绘制边框(带笔划)和内容(带填充):即使没有矩形也会显示它们应该有的样子中风。 2. 缺少窗口的白色背景:推迟绘制直到 Expose 事件到来(也将它添加到蒙版中)。 3. 未画红线:在每条线后添加一个额外的cairo_surface_flush()。有时还会延迟几秒钟 :( kempelen.dai.fmph.uniba.sk/test_cairo/test_cairo2.c kempelen.dai.fmph.uniba.sk/test_cairo/test_cairo2.png

标签: c x11 cairo


【解决方案1】:

X11 不会为您保留窗口内容。当您收到 Expose 事件时,您必须完全重新绘制该事件所描述的区域。

所有三个窗口都应该有白色背景,但其中两个是黑色的。

您使用XCreateSimpleWindow 创建窗口,因此它们的背景属性设置为黑色。 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++)

【讨论】:

猜你喜欢
  • 2014-10-28
  • 1970-01-01
  • 2012-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多