开罗C计划不会吸引到x11窗口

时间:2015-10-28 07:30:04

标签: c linux x11 cairo

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

在非常努力地遵循cairo为x11提供的woefully incomplete guide之后,这是我得到的最好的:

#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文件。数据应该直接发送!

2 个答案:

答案 0 :(得分:2)

几个问题:

  • 在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只给你一个可悲的不完整指南?它告诉你如何让cairo部件工作,它也解释了你关于X11的一些部分,即使你应该已经知道如果你想使用cairo-x11。这不关乎它的业务。您链接的指南甚至提供了完整的工作和自包含的示例:https://www.cypherpunk.at/files/2014/11/cairo_xlib_simple.c

答案 1 :(得分:1)

我已经阅读了这篇&#34;不完整指南的全文&#34;你会看到有一个完整样本的链接:https://www.cypherpunk.at/files/2014/11/cairo_xlib_simple.c