Cairo C 程序不会绘制到 x11 窗口

问题描述 投票:0回答:3

我正在尝试在 Linux 上使用 C 语言的 Cairo 图形库来制作一个非常轻量级的 x11 GUI。

在非常努力地遵循开罗为 x11 提供的非常不完整的指南之后,这是我得到的最好的:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <cairo.h>
#include <cairo-xlib.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xrender.h>
#include <X11/extensions/renderproto.h>

//This function should give us a new x11 surface to draw on.
cairo_surface_t* create_x11_surface(int x, int y)
{
    Display* d;
    Drawable da;
    int screen;
    cairo_surface_t* sfc;

    if((d = XOpenDisplay(NULL)) == NULL)
    {
        printf("failed to open display\n");
        exit(1);
    }

    screen = DefaultScreen(d);
    da = XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, x, y, 0, 0, 0);
    XSelectInput(d, da, ButtonPressMask | KeyPressMask);
    XMapWindow(d, da);

    sfc = cairo_xlib_surface_create(d, da, DefaultVisual(d, screen), x, y);
    cairo_xlib_surface_set_size(sfc, x, y);

    return sfc;
}

int main(int argc, char** argv)
{
    //create a new cairo surface in an x11 window as well as a cairo_t* to draw
    //on the x11 window with.
    cairo_surface_t* surface = create_x11_surface(300, 200);
    cairo_t* cr = cairo_create(surface);

    while(1)
    {
        //save the empty drawing for the next time through the loop.
        cairo_push_group(cr);

        //draw some text
        cairo_select_font_face(cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
        cairo_set_font_size(cr, 32.0);
        cairo_set_source_rgb(cr, 0, 0, 1.0);
        cairo_move_to(cr, 10.0, 25.0);

        if((argc == 2) && (strnlen(argv[1], 100) < 50))
            cairo_show_text(cr, argv[1]);
        else
            cairo_show_text(cr, "usage: ./p1 <string>");

        //put the drawn text onto the screen(?)
        cairo_pop_group_to_source(cr);
        cairo_paint(cr);
        cairo_surface_flush(surface);

        //pause for a little bit.
        int c = getchar();

        //change the text around so we can see the screen update.
        for(int i = 0; i < strnlen(argv[1], 100); i++)
        {
            argv[1][i] = argv[1][i + 1];
        }

        if(c == 'q')
        {
            break;
        }
    }

    cairo_surface_destroy(surface);
    return 0;
}

在安装了 Cairo 的 Linux 系统上,可以使用

进行编译
gcc -o myprog $(pkg-config --cflags --libs cairo x11) -std=gnu99 main.c

它应该使用单个参数运行。

由于我根本不明白的原因,插入该行

cairo_pop_group_to_source(cr);
cairo_paint(cr);
cairo_surface_write_to_png (surface, "hello.png");    //<--------- inserted
cairo_surface_flush(surface);

在屏幕上放一些东西,但有两个问题:

  1. 我用这种方法绘制的文本是持久的,产生涂抹效果。
  2. 我不希望在我的程序和 x11 窗口之间使用一些 .png 文件。数据应该直接发送!
c linux x11 cairo
3个回答
3
投票

几个问题:

  • 在 X11 中,X11 服务器不会保存您在窗口中绘制的内容,而是发送一个
    ExposeEvent
    到您的窗口,告诉它重新绘制。这意味着您会看到一个黑色窗口,因为您没有处理此事件。
  • getchar
    只会在换行后给你一些东西,所以仅仅输入一些东西是没有帮助的。
  • libX11 缓冲内容,并且仅在等待事件(或缓冲区填满)时将其发送到 X11 服务器。由于您从不等待事件,因此它永远不会刷新。明确调用
    XFlush
    有帮助。
  • 你推的群是没用的。摆脱它吧。
  • 将字符串向左移动一个方向的代码很容易超出字符串的末尾。您显然已经知道这一点,因为您用
    strnlen
    “修复”了这个问题。

这里有一个更好的解决方案,但它仍然给你一个最初的黑色窗口,因为你在它被映射之前绘制它:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <cairo-xlib.h>
#include <X11/Xlib.h>

//This function should give us a new x11 surface to draw on.
cairo_surface_t* create_x11_surface(Display *d, int x, int y)
{
    Drawable da;
    int screen;
    cairo_surface_t* sfc;

    screen = DefaultScreen(d);
    da = XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, x, y, 0, 0, 0);
    XSelectInput(d, da, ButtonPressMask | KeyPressMask);
    XMapWindow(d, da);

    sfc = cairo_xlib_surface_create(d, da, DefaultVisual(d, screen), x, y);

    return sfc;
}

int main(int argc, char** argv)
{
    Display *d = XOpenDisplay(NULL);
    if (d == NULL) {
        fprintf(stderr, "Failed to open display\n");
        return 1;
    }
    //create a new cairo surface in an x11 window as well as a cairo_t* to draw
    //on the x11 window with.
    cairo_surface_t* surface = create_x11_surface(d, 300, 200);
    cairo_t* cr = cairo_create(surface);
    char *text = argv[1];
    size_t text_len = 0;

    if (argc != 2)
        text = NULL;
    else
        text_len = strlen(text);

    while(1)
    {
        // Clear the background
        cairo_set_source_rgb(cr, 0, 0, 0);
        cairo_paint(cr);

        //draw some text
        cairo_select_font_face(cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
        cairo_set_font_size(cr, 32.0);
        cairo_set_source_rgb(cr, 0, 0, 1.0);
        cairo_move_to(cr, 10.0, 25.0);

        if (text)
            cairo_show_text(cr, text);
        else
            cairo_show_text(cr, "usage: ./p1 <string>");

        cairo_surface_flush(surface);
        XFlush(d);

        //pause for a little bit.
        int c = getchar();

        //change the text around so we can see the screen update.
        memmove(text, &text[1], text_len);
        if (text_len > 0)
            text_len--;

        printf("got char %c\n", c);
        if(c == 'q')
        {
            break;
        }
    }

    // XXX: Lots of other stuff isn't properly destroyed here
    cairo_surface_destroy(surface);
    return 0;
}

编辑:另外,为什么你觉得开罗只给你提供了一个非常不完整的指南?它告诉您如何让 cairo 部件工作,并且还向您解释了有关 X11 的一些部件,尽管如果您想使用 cairo-x11,您应该已经知道这些部件。那不关它的事。您链接到的指南甚至提供了一个完整的、工作且独立的示例:https://www.cypherpunk.at/files/2014/11/cairo_xlib_simple.c


2
投票

我已经阅读了这个“不完整指南”的完整文本,您会发现有一个完整示例的链接:https://www.cypherpunk.at/files/2014/11/cairo_xlib_simple。 c .


0
投票

托管开罗示例所基于的代码的服务器已失效。如果有人有副本,请将其发布到 gitrepo 的某个地方。

© www.soinside.com 2019 - 2024. All rights reserved.