2015-10-28 27 views
2

我想在C語言的Linux上使用Cairo圖形庫來製作一個非常輕量級的x11 GUI。開羅C程序不會畫到x11窗口

拼命跟隨woefully incomplete guide開羅給出了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; 
} 

在已經安裝了開羅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個問題:

  1. 文字,我用這種方法得出的持久,造成塗抹效應。
  2. 我不想在我的程序和x11窗口之間調解一些.png文件。數據應該直接發送!
+2

你的問題在於你選擇開羅的後端。你可以選擇png,pdf,svg,或者你可以直接寫入gtk窗口(它看起來是你想要做的)。請參閱[**開羅教程 - zetcode **](http://zetcode.com/gfx/cairo/cairobackends/)中的示例以獲取每個示例。 –

+0

對不起,我在這裏;我通常是嵌入式系統開發人員,我很少編寫Linux代碼。 gtk和x11有什麼區別? gtk聽起來比我讀過的更復雜。我不能直接寫入x11窗口:而不是「直接到gtk窗口」嗎? –

+1

不用擔心,只需稍微放慢一點,然後完成教程並慢慢開始消化不同的功能。你在C學習的東西,記住它不是一場比賽,你急着飛過的細節 - 真的很重要,所以盡情享受騎行吧(不是比賽) –

回答

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; 
} 

編輯:此外,到底爲什麼你覺得開羅只給你一個可悲的不完整的指導?它告訴你如何讓開羅部件工作,它也解釋了一些關於X11的部分,儘管如果你想使用cairo-x11你應該已經知道這些。這不關它的事。您所連結的指導,甚至還提供了完整的,工作和自足例如:https://www.cypherpunk.at/files/2014/11/cairo_xlib_simple.c

+0

「你爲什麼覺得像開羅只給你一個可悲的不完整的指導?」也許我有點苛刻,但所有到cypherpunk.at的鏈接已經死了,所以我無法查看示例代碼(這會非常有幫助) –

+0

cypherpunk.at的鏈接沒有死,但其服務器使用自簽名證書(或其他未知的證書),因此Firefox在繼續之前警告您; Chrome瀏覽器更加挑剔,因此它可能似乎被打破,但這只是一個安全問題。 – JvO