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

使用XCB編寫X Window程序(一) 快速起步

編輯:關於C++

估計現在已經沒有誰使用XCB這麼底層的庫寫應用程序了,要用也是用經過精心封裝的Motif, LessTiff, GTK, Qt, EWL,  ETK或者Cairo等高層次的庫。我之所以這麼費心地去折騰XCB,其實主要也是為了學習。畢竟,使用最接近底層的UI庫寫代碼是學習X協議及GUI編程原理的最好方法。

XCB的主要教程可以參考這裡:http://xcb.freedesktop.org/tutorial/

和X協議有關的文檔,在這裡:http://www.x.org/releases/X11R7.7/doc/

在這裡要繼續吐槽freedesktop.org。沒錯,XCB的官網又是在freedesktop.org,而且正如我前幾篇隨筆中提到的Xft、Freetype一樣,文檔極其不完善。不過在其XcbApi頁面有這樣的提示“Refactoring this page...please be patient...”,那就耐心等待吧。好在代碼是最好的文檔,在Fedora 20中安裝libxcb-devel軟件包後,可以直接到/usr/include/xcb目錄下查看XCB庫的頭文件,所以真要學習XCB也不是很難。如下圖,我系統中的XCB庫的頭文件:

下面是一個最簡單的XCB程序,它的功能是創建一個窗口。由於沒有任何事件處理的機制,所以使用了pause()讓程序暫停,要退出程序,必須得按Ctrl+C。

#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <xcb/xcb.h>
#include <stdio.h>
    
double get_time(){
    struct timeval timeval;
    gettimeofday(&timeval, NULL);
    return (double)timeval.tv_sec + (((double)timeval.tv_usec)/1000000);
}
    
int main(){
    double start_time = get_time();
    
    xcb_connection_t *connection = xcb_connect(NULL, NULL);
    const xcb_setup_t *setup = xcb_get_setup(connection);
    xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
    xcb_screen_t *screen = iter.data;
    
    xcb_window_t window = xcb_generate_id(connection);
    xcb_create_window(
            connection,
            XCB_COPY_FROM_PARENT,
            window,
            screen->root,
            100,100,
            400, 300,
            10,
            XCB_WINDOW_CLASS_INPUT_OUTPUT,
            screen->root_visual,
            0, NULL);
    xcb_map_window(connection, window);
    xcb_flush(connection);
    
    printf("花費時間:%f秒。",get_time()-start_time);
    fflush(stdout);
    
    pause();
    xcb_disconnect(connection);
    return 0;
}

從這段代碼可以看出,要創建一個簡單的窗口程序,必須經過如下步驟:

1、連接到XServer的Display,通過xcb_connect()函數進行,返回一個xcb_connection_t的指針,在這一步中,同時可以獲得當前屏幕的Screen number;

2、獲得xcb_setup,通過xcb_get_setup()函數進行。xcb_setup裡面保存的是應用程序和XServer之間通訊時需要用到的信息,包括協議的版本、字節的順序等。一般情況下,我們不需要關注這些細節;

3、獲得Screen對象,這一步很重要,也很復雜。重要是因為只有獲得一個Screen後,才能在屏幕上創建窗口,創建窗口時需要用到Screen中的一些信息。復雜是因為一個Display可以有多個Screen,所以通過xcb_setup_roots_iterator()函數返回的是一個迭代器,可以通過該迭代器對所有的Screen進行遍歷。如果只有一個Screen,則返回的第一個迭代器中的data就指向該Screen。XCB中使用xcb_screen_t結構來保存Screen的信息;

4、創建窗口並顯示窗口,這需要三步,第一步先使用xcb_generate_id()函數生成一個ID,第二步使用xcb_create_window()函數創建一個窗口,第三步使用xcb_map_window讓窗口顯示出來。

通過以上的代碼,我還學到了一個技巧,那就是使用gettimeofday()函數來獲取一個精確到微秒的時間,用來查看應用程序的耗時。

程序運行如下圖:

這個新創建的窗口自己沒有背景,所以它創建的時候屏幕上有什麼,它窗口裡面就有什麼。對於程序中用到的數據結構和枚舉的含義,可以直接查看xcb的頭文件,配合ctags和taglist.vim插件使用的話,只需要按Ctrl+]鍵,就可以自動跳轉到這些數據結構的定義處(在Vim中使用taglist的方法見這裡Linux江湖02:打造屬於自己的Vim),如下兩圖:

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

最後,我對第一個簡單的程序進行適當的擴展,看看怎麼獲取Display中有幾個Screen以及怎麼遍歷Screen,最後顯示Screen的一些信息。程序如下:

 1 #include <stdlib.h>
2 #include <sys/time.h>
3 #include <unistd.h>
4 #include <xcb/xcb.h>
5 #include <stdio.h>
6
7 double get_time(){
8 struct timeval timeval;
9 gettimeofday(&timeval, NULL);
10 return (double)timeval.tv_sec + (((double)timeval.tv_usec)/1000000);
11 }
12
13 int main(){
14 double start_time = get_time();
15 int screen_number;
16
17 xcb_connection_t *connection = xcb_connect(NULL, &screen_number);
18 const xcb_setup_t *setup = xcb_get_setup(connection);
19 xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
20 printf("當前的Screen Number為:%d\n",screen_number);
21 printf("iter.rem = %d,下面開始遍歷:\n",iter.rem);
22
23 xcb_screen_t *screen;
24 for(; iter.rem!=0; xcb_screen_next(&iter)){
25 screen = iter.data;
26 printf("*****看到多少行這個提示,就說明有多少個Screen。*****\n");
27 printf(" Screen->root:%d\n",screen->root);
28 printf(" Screen->root_depth:%d\n",screen->root_depth);
29 printf(" Screen->white_pixel:%d\n",screen->white_pixel);
30 printf(" Screen->black_pixel:%d\n",screen->black_pixel);
31 printf(" Screen->width_in_pixels:%d\n",screen->width_in_pixels);
32 printf(" Screen->height_in_pixels:%d\n",screen->height_in_pixels);
33 printf(" Screen->width_in_millimeters:%d\n",screen->width_in_millimeters);
34 printf(" Screen->height_in_millimeters:%d\n",screen->height_in_millimeters);
35 }
36
37
38 xcb_window_t window = xcb_generate_id(connection);
39 xcb_create_window(
40 connection,
41 XCB_COPY_FROM_PARENT,
42 window,
43 screen->root,
44 100,100,
45 400, 300,
46 10,
47 XCB_WINDOW_CLASS_INPUT_OUTPUT,
48 screen->root_visual,
49 0, NULL);
50 xcb_map_window(connection, window);
51 xcb_flush(connection);
52
53 printf("花費時間:%f秒。",get_time()-start_time);
54 fflush(stdout);
55
56 pause();
57 xcb_disconnect(connection);
58 return 0;
59 }

最後運行效果如下圖:

作者:cnblogs 京山游俠

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