Cairo C 程序不会绘制到 x11 window
Cairo C program won't draw to x11 window
我正在尝试使用 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);
在屏幕上放了一些东西,但是有 2 个问题:
- 我用这种方法绘制的文本是持久的,产生了涂抹效果。
- 我不想在我的程序和 x11 window 之间使用一些 .png 文件。直接发数据吧!
几个问题:
- 在 X11 中,X11 服务器不会将您绘制的内容保存到 window,而是向您的 window 发送一个
ExposeEvent
,告诉它重新绘制。这意味着你得到一个黑色 window,因为你没有处理这个事件。
getchar
只会在换行后给你一些东西,所以只输入一些东西是没有用的。
- libX11 缓冲内容,仅在您等待事件(或缓冲区填满)时将其发送到 X11 服务器。由于您从不等待事件,因此它永远不会刷新。明确地调用
XFlush
有帮助。
- 你推的群没用。摆脱它。
- 您将字符串向左移动一个方向的代码很容易超出字符串的末尾。你显然已经知道了,因为你 'fixed' this with a
strnlen
.
这里有一个更好的解决方案,但它仍然给你一个最初的黑色 window,因为你在它被映射之前绘制它:
#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。这是它的业务 none。您链接到的指南甚至提供了一个完整的、有效的和独立的示例:https://www.cypherpunk.at/files/2014/11/cairo_xlib_simple.c
我知道你已经阅读了这个 "imcomplete guide" 的完整文本,你会看到完整示例中有一个 link:https://www.cypherpunk.at/files/2014/11/cairo_xlib_simple.c .
我正在尝试使用 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);
在屏幕上放了一些东西,但是有 2 个问题:
- 我用这种方法绘制的文本是持久的,产生了涂抹效果。
- 我不想在我的程序和 x11 window 之间使用一些 .png 文件。直接发数据吧!
几个问题:
- 在 X11 中,X11 服务器不会将您绘制的内容保存到 window,而是向您的 window 发送一个
ExposeEvent
,告诉它重新绘制。这意味着你得到一个黑色 window,因为你没有处理这个事件。 getchar
只会在换行后给你一些东西,所以只输入一些东西是没有用的。- libX11 缓冲内容,仅在您等待事件(或缓冲区填满)时将其发送到 X11 服务器。由于您从不等待事件,因此它永远不会刷新。明确地调用
XFlush
有帮助。 - 你推的群没用。摆脱它。
- 您将字符串向左移动一个方向的代码很容易超出字符串的末尾。你显然已经知道了,因为你 'fixed' this with a
strnlen
.
这里有一个更好的解决方案,但它仍然给你一个最初的黑色 window,因为你在它被映射之前绘制它:
#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。这是它的业务 none。您链接到的指南甚至提供了一个完整的、有效的和独立的示例:https://www.cypherpunk.at/files/2014/11/cairo_xlib_simple.c
我知道你已经阅读了这个 "imcomplete guide" 的完整文本,你会看到完整示例中有一个 link:https://www.cypherpunk.at/files/2014/11/cairo_xlib_simple.c .