如何避免cairo在xlib表面绘制时出现闪烁?

5

我正在使用C++中的cairoxlib进行编程,我的代码如下所示。

我遇到了一些闪烁问题,但通过修改代码,它现在通常可以正常工作。
但是当窗口调整为较小的尺寸(大约在我的笔记本电脑上为600x450)时,它仍然会闪烁
我该如何解决?

#include <cairo.h>
#include <cairo-xlib.h>
#include <string>
#include <cstdio>

using namespace std;

int main (int argc, char *argv[])
{
    cairo_surface_t *surface;
    cairo_t *cr;

    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 800, 600);
    cr = cairo_create (surface);
    /* Examples are in 1.0 x
     * 1.0 coordinate space */
    cairo_scale (cr, 800, 600);

    cairo_set_source_rgb (cr, 1.0, 0, 0);
    cairo_rectangle (cr, 0, 0, 1.0, 1.0);
    cairo_fill(cr);
    cairo_destroy(cr);

    Display *display = XOpenDisplay(NULL);
    int default_scr = DefaultScreen(display);
    Visual *visual = DefaultVisual(display, default_scr);
    Window root_win = RootWindow(display, default_scr);
    Drawable drawable = XCreateSimpleWindow(display, root_win, 0, 0, 800, 600, 0,
            BlackPixel(display, default_scr), WhitePixel(display, default_scr));
    cairo_surface_t *x11_sf = cairo_xlib_surface_create(display, drawable, visual, 800, 600);

    XSelectInput(display, drawable, ExposureMask | StructureNotifyMask);
    XMapWindow(display, drawable);
    XFlush(display);
    XSync(display, default_scr);
    Atom wmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", False);
    XSetWMProtocols(display, drawable, &wmDeleteMessage, 1);

    int height;
    int width;
    XEvent event;
    bool running = true;
    while (running)
    {
        XNextEvent(display, &event);
        switch (event.type)
        {
        case Expose:
            {
                cairo_t *x11_cr = cairo_create(x11_sf);
                cairo_scale(x11_cr, double(width) / 800, double(height) / 600);
                cairo_set_source_surface(x11_cr, surface, 0, 0);
                cairo_paint(x11_cr);
                cairo_destroy (x11_cr);
            }
            break;
        case ClientMessage:
            if (event.xclient.data.l[0] == wmDeleteMessage)
            {
                running = false;
            }
            break;
        case ConfigureNotify:
            width = event.xconfigure.width;
            height = event.xconfigure.height;
            cairo_xlib_surface_set_size(x11_sf, width, height);
            break;
        }
    }

    cairo_surface_destroy (surface);

    return 0;
}

我使用cairo_xlib_surface来绘制一个窗口,它的背景颜色是红色的。我尝试捕获XExpose事件并重新绘制它。但有时候重新绘制的结果会变得奇怪。

#include <cairo.h>
#include <cairo-xlib.h>
#include <string>
#include <cstdio>

using namespace std;

int main (int argc, char *argv[])
{
    cairo_surface_t *surface;
    cairo_t *cr;

    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 800, 600);
    cr = cairo_create (surface);
    /* Examples are in 1.0 x 1.0 coordinate space */
    cairo_scale (cr, 800, 600);

    /* Drawing code goes here */
    cairo_set_source_rgb (cr, 1.0, 0, 0);
    cairo_rectangle (cr, 0, 0, 1.0, 1.0);
    cairo_fill(cr);

    Display *display = XOpenDisplay(NULL);
    int default_scr = DefaultScreen(display);
    Visual *visual = DefaultVisual(display, default_scr);
    Window root_win = RootWindow(display, default_scr);
    Drawable drawable = XCreateSimpleWindow(display, root_win, 0, 0, 800, 600, 0,
            BlackPixel(display, default_scr), WhitePixel(display, default_scr));

    XSelectInput(display, drawable, ExposureMask);
    XMapWindow(display, drawable);
    XFlush(display);
    XSync(display, default_scr);


    int height;
    int width;
    XEvent event;
    while (1)
    {
        XNextEvent(display, &event);
        switch (event.type)
        {
        case Expose:
            {
                width = event.xexpose.width;
                height = event.xexpose.height;
                cairo_surface_t *x11_sf = cairo_xlib_surface_create(display, drawable, visual, width, height);
                cairo_t *x11_cr = cairo_create(x11_sf);
                cairo_scale(x11_cr, double(width) / 800, double(height) / 600);
                cairo_set_source_surface(x11_cr, surface, 0, 0);
                cairo_paint(x11_cr);
                cairo_destroy (x11_cr);
                cairo_surface_destroy (x11_sf);
            }
            break;
        }
    }


    /* Write output and clean up */
    cairo_destroy (cr);
    cairo_surface_destroy (surface);

    return 0;
}

当我调整窗口大小时,有时会出现以下结果:The result window。它似乎没有完成绘制红色背景。请问为什么会出现这种情况,如何避免?如果有人想在Linux下编译它,可以使用:g++ \pkg-config --cflags --libs x11 cairo\ src.cpp。谢谢!

你在意地给出了 Cairo_xlib_surface_create() 的暴露区域的宽度和高度作为窗口的大小,这是有意为之的吗?为什么不使用窗口的实际大小?在你的情况下,初始大小将是800x600,当你的窗口被调整大小时,你必须捕获ConfigureNotify并使用cairo_xlib_surface_set_size()。这些信息是否是你要求的?如果不是,我就不明白你的问题了。 - Uli Schlachter
谢谢你的回复。你提供的建议真的很有用。但当窗口大小较小时(小于600x450),重绘过程仍然会闪烁。我修改了我的代码。我错过了其他什么要点吗?谢谢。 - byhc
我测试了一些情况,发现当我创建的“surface”为100x100时,闪烁消失了。然而,当表面为1x1时,结果x11窗口有一个奇怪的背景。 - byhc
1
使用XCreateWindow而不是XCreateSimpleWindow。我猜你的问题是你通过这种机制为窗口使用了白色背景颜色。应该可以使用XCreateWindow(display,root_win,0,0,800,600,0,0,CopyFromParent,CopyFromParent,0,NULL)来解决问题。 - Uli Schlachter
2
XCreateWindow可以使用。谢谢! - byhc
1个回答

2
问题是由于您在白色背景上填充红色区域以制作红色背景,这不是最有效的方法导致的。
相反,您应该将窗口的背景颜色定义为红色而不是白色!
因此,在XCreateSimpleWindow()的background参数(最后一个参数)中,您应该放置0xFF0000,它是24位颜色空间中红色的十六进制值,但如果您使用不同的颜色空间,则可能需要更改它。该行代码如下:
XCreateSimpleWindow(display, root_win, 0, 0, 800, 600, 0,
            BlackPixel(display, default_scr), WhitePixel(display, default_scr));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接