使用XCB编写X Window程序(01):快速起步

时间:2014-06-27 00:51:46   收藏:0   阅读:2551

  估计现在已经没有谁使用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库的头文件:

bubuko.com,布布扣

 

  下面是一个最简单的XCB程序,它的功能是创建一个窗口。由于没有任何事件处理的机制,所以使用了pause()让程序暂停,要退出程序,必须得按Ctrl+C。

 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 
16     xcb_connection_t *connection = xcb_connect(NULL, NULL);
17     const xcb_setup_t *setup = xcb_get_setup(connection);
18     xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
19     xcb_screen_t *screen = iter.data;
20 
21     xcb_window_t window = xcb_generate_id(connection);
22     xcb_create_window(
23             connection,
24             XCB_COPY_FROM_PARENT,
25             window,
26             screen->root,
27             100,100,
28             400, 300,
29             10,
30             XCB_WINDOW_CLASS_INPUT_OUTPUT,
31             screen->root_visual,
32             0, NULL);
33     xcb_map_window(connection, window);
34     xcb_flush(connection);
35 
36     printf("花费时间:%f秒。",get_time()-start_time);
37     fflush(stdout);
38 
39     pause();
40     xcb_disconnect(connection);
41     return 0;
42 }

   从这段代码可以看出,要创建一个简单的窗口程序,必须经过如下步骤:

  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()函数来获取一个精确到微秒的时间,用来查看应用程序的耗时。

  程序运行如下图:

bubuko.com,布布扣

  这个新创建的窗口自己没有背景,所以它创建的时候屏幕上有什么,它窗口里面就有什么。对于程序中用到的数据结构和枚举的含义,可以直接查看xcb的头文件,配合ctags和taglist.vim插件使用的话,只需要按Ctrl+]键,就可以自动跳转到这些数据结构的定义处(在Vim中使用taglist的方法见这里Linux江湖02:打造属于自己的Vim),如下两图:

bubuko.com,布布扣

bubuko.com,布布扣

 

  最后,我对第一个简单的程序进行适当的扩展,看看怎么获取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 }

   最后运行效果如下图:

bubuko.com,布布扣

 

(京山游侠于2014-06-25发布于博客园,转载请注明出处。)

使用XCB编写X Window程序(01):快速起步,布布扣,bubuko.com

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!