程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 使用XCB編寫X Window程序(四) 在窗口中繪制文字

使用XCB編寫X Window程序(四) 在窗口中繪制文字

編輯:關於C++

在前面的幾節中,我展示了使用XCB創建窗口、在窗口中畫圖以及捕獲並處理事件。在這一篇中,我將展示在窗口中繪制文字。繪制文字當然離不開字體,所以我還會簡單地探討一下X Server的核心字體系統。老規矩,先上代碼和運行效果圖,代碼如下:

1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <inttypes.h>
5 #include <xcb/xcb.h>
6
7
8 #define WIDTH 600
9 #define HEIGHT 400
10 #define TEST_COOKIE(fn,errMessage) \
11 cookie=fn; \
12 error=xcb_request_check(connection,cookie); \
13 if(error){ \
14 fprintf(stderr, "Error: %s : %"PRIu8"\n", errMessage, error->error_code); \
15 } \
16
17 static void drawText(xcb_connection_t *connection, xcb_screen_t *screen, xcb_window_t window,
18 int16_t x, int16_t y, const char *font_name, const char *string){
19 /*cookie and error, for TEST_COOKIE */
20 xcb_void_cookie_t cookie;
21 xcb_generic_error_t *error;
22
23 xcb_font_t font = xcb_generate_id(connection);
24 TEST_COOKIE(xcb_open_font_checked(connection, font, strlen(font_name), font_name), "Can't open font");
25 xcb_gcontext_t gc = xcb_generate_id(connection);
26 uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
27 uint32_t values[3] = {screen->black_pixel, screen->white_pixel, font};
28 TEST_COOKIE(xcb_create_gc_checked(connection, gc, window, mask, values), "Can't create GC")
29 /*draw the text*/
30 TEST_COOKIE(xcb_image_text_8_checked(connection, strlen(string), window, gc, x, y, string), "Can't draw text");
31 /*close the font*/
32 xcb_close_font(connection, font);
33 xcb_free_gc(connection, gc);
34 }
35
36 int main()
37 {
38 xcb_connection_t *connection = xcb_connect(NULL, NULL);
39 xcb_screen_t *screen = xcb_setup_roots_iterator( xcb_get_setup(connection)).data;
40
41 /*Create the window*/
42 xcb_window_t window = xcb_generate_id(connection);
43 uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
44 uint32_t values[2];
45 values[0] = screen->white_pixel;
46 values[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS |
47 XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_POINTER_MOTION;
48 xcb_create_window(connection, screen->root_depth,
49 window, screen->root, 20, 200,
50 WIDTH, HEIGHT,
51 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
52 screen->root_visual,
53 mask, values);
54 xcb_map_window(connection, window);
55 xcb_flush(connection);
56
57 /*event loop*/
58 xcb_generic_event_t *event;
59 while((event = xcb_wait_for_event(connection))){
60 switch(event->response_type & ~0x80){
61 case XCB_EXPOSE:
62 {
63 drawText(connection, screen, window, 10, 20,"fixed", "Press ESC key to exit.");
64 drawText(connection, screen, window, 10, 40, "Dejavu Sans Mono", "Press ESC key to exit.");
65 drawText(connection, screen, window, 10, 60, "文泉驿正黑", "按ESC鍵退出。");
66 break;
67 }
68 case XCB_KEY_RELEASE:
69 {
70 xcb_key_release_event_t *kr = (xcb_key_release_event_t*)event;
71 switch(kr->detail){
72 case 9: /* ESC */
73 {
74 free(event);
75 xcb_disconnect(connection);
76 return 0;
77 }
78 }
79 }
80 }
81 free(event);
82 }
83 return 0;
84 }

運行效果如下圖:

我承認,這段代碼寫得有點亂,不過說明怎麼在窗口中繪制文字已經足夠了。在窗口中繪制文字只需要用到如下函數:

1、使用xcb_generate_id()生成一個ID,用來表示一個字體;

2、使用xcb_open_font()或者xcb_open_font_checked()函數打開一個字體;

3、使用前面打開的字體創建一個gc;創建gc前面已經講過了,只需要調用xcb_generate_id()和xcb_create_gc()或者xcb_create_gc_checked()函數即可,不過在這裡,要注意創建gc時的mask和values值,mask需要XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT,分別代表前景色、背景色和字體,在values中設置相應的值;

4、使用xcb_image_text_8()或者xcb_image_text_8_checked()函數在窗口上繪制文字。

返回欄目頁:http://www.bianceng.cn/Programming/cplus/

現在再回過頭來看代碼,是不是覺得豁然開朗?就這麼幾個API而已。而且可以看出,在XCB中,每一個有可能出錯的函數都有另外一個加上了_checked的版本,帶_checked的版本會返回一個cookie,通過xcb_request_check()函數可以檢查該cookie,從而判斷該函數調用是否成功。使用C語言的API就是這一點很麻煩,經常要去檢查函數調用是否成功,所以使用C語言寫程序經常會寫成這樣:

int error;
error = some_function(...);
if(error){
    printf("...some message...");
    ...
}
error = another_function(...);
if(error){
    printf("....another message...");
    ...
}

這實在是太痛苦了。好在C語言中還有宏這麼一個東西,所以我就在程序的開頭定義了一個宏TEST_COOKIE,專門用來干這個事。宏定義得不好,還有改進的余地,不過已經讓我的代碼寫起來和讀起來都舒服了不少。

在程序中,我使用了三個drawText,要求程序分別用fixed字體、Dejavu San Mono字體和文泉驿正黑字體繪制三行文字,但是最終的結果只有fixed那一行成功繪制,剩下的兩行都在控制台顯示有錯誤信息,都表示字體打不開、gc創建不了、所以文字當然繪制不了。之所以出現這種情況,就是因為這裡選擇的字體只能是X Server核心字體系統裡安裝的字體。我在《Linux江湖05:Linux桌面系統字體配置要略(下)》裡面寫過,Xorg中有兩種字體系統,一種是X Server核心字體系統,另一種是Xft。雖然X Server核心字體系統經過多年的發展,功能已經很完善了,能比較完美地支持TrueType字體,但是Xorg官方反復建議大家不要使用核心字體系統,而是推薦大家使用Xft。可能是因為X Server核心字體系統對字體的安裝和管理都比較麻煩吧。使用xlsfonts命令可以列出X Server中安裝有哪些字體,如下圖:

可以看到每一個字體的信息都又臭又長,只有最後三行短一點,所以我才在程序中選擇了最短的fixed字體作為示例。而且X Server核心字體系統安裝字體時需要使用mkfontdir、mkfontscale等極其麻煩的命令。

最後有一點想不通的是,為什麼xcb_image_text_8()函數後面有一個8呢?是不是還有xcb_image_text_16()和xcb_image_text_32()這樣的函數呢?沒關系,使用Ctrl+]跳到XCB的頭文件裡面看一下。如下圖:

裡面的注釋還是很詳細的。特別是下圖的最後一句:

最後一句再次強調X core fonts是過時的、不建議使用的,再次推薦大家使用Xft。我在寫這一系列XCB文章的時候就說過,使用XCB只是為了學習,學習X協議的底層知識,學習GUI系統的構建原理等。真正寫應用程序的時候,是沒有誰使用XCB這麼底層的庫的。而高層次的庫中需要繪制文字時,估計早就都是Xft一統天下了,所以並不需要我們費太多的心。

作者:cnblogs 京山游俠

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved