使用XCB编写X Window程序(02):在窗口中绘图

  在上一篇中,我展示了怎么连接X服务器以及怎么创建一个窗口。创建窗口是编写GUI程序的根本。在GUI编程中还有另外两个重点,其一是事件处理,其二是在窗口中绘图。这一篇中,将展示如何使用XCB在窗口中进行绘图。

  先看一个示例代码及其运行效果,代码如下:

  1     #include <stdlib.h>
  2     #include <stdio.h>
  3
  4     #include <xcb/xcb.h>
  5
  6     int
  7     main ()
  8     {
  9         /* geometric objects */
 10         xcb_point_t          points[] = {
 11             {40, 40},
 12             {40, 80},
 13             {80, 40},
 14             {80, 80}};
 15
 16         xcb_point_t          polyline[] = {
 17             {200, 40},
 18             { 20, 80},     /* rest of points are relative */
 19             {100,-80},
 20             {40, 40}};
 21
 22         xcb_segment_t        segments[] = {
 23             {400, 40, 560, 120},
 24             {440, 100, 520, 240}};
 25
 26         xcb_rectangle_t      rectangles[] = {
 27             { 40, 200, 160, 80},
 28             { 320, 200, 40, 160}};
 29
 30         xcb_arc_t            arcs[] = {
 31             {40, 400, 240, 160, 0, 90 << 6},
 32             {360, 400, 220, 160, 0, 270 << 6}};
 33
 34
 35         /* Open the connection to the X server */
 36         xcb_connection_t *connection = xcb_connect (NULL, NULL);
 37
 38         /* Get the first screen */
 39         xcb_screen_t *screen = xcb_setup_roots_iterator (xcb_get_setup (connection)).data;
 40
 41         /* Create black (foreground) graphic context */
 42         xcb_drawable_t  window     = screen->root;
 43         xcb_gcontext_t  gc = xcb_generate_id (connection);
 44         uint32_t        mask       = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
 45         uint32_t        values[2]  = {screen->black_pixel, 0};
 46
 47         xcb_create_gc (connection, gc, window, mask, values);
 48
 49
 50         /* Create a window */
 51         window = xcb_generate_id (connection);
 52
 53         mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
 54         values[0] = screen->white_pixel;
 55         values[1] = XCB_EVENT_MASK_EXPOSURE;
 56
 57         xcb_create_window (connection,                    /* connection          */
 58                            XCB_COPY_FROM_PARENT,          /* depth               */
 59                            window,                        /* window Id           */
 60                            screen->root,                  /* parent window       */
 61                            0, 0,                          /* x, y                */
 62                            800, 600,                      /* width, height       */
 63                            10,                            /* border_width        */
 64                            XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class               */
 65                            screen->root_visual,           /* visual              */
 66                            mask, values );                /* masks */
 67
 68
 69         /* Map the window on the screen and flush*/
 70         xcb_map_window (connection, window);
 71         xcb_flush (connection);
 72
 73
 74         /* draw primitives */
 75         xcb_generic_event_t *event;
 76         while ((event = xcb_wait_for_event (connection))) {
 77             switch (event->response_type & ~0x80) {
 78             case XCB_EXPOSE:
 79                 /* We draw the points */
 80                 xcb_poly_point (connection, XCB_COORD_MODE_ORIGIN, window, gc, 4, points);
 81
 82                 /* We draw the polygonal line */
 83                 xcb_poly_line (connection, XCB_COORD_MODE_PREVIOUS, window, gc, 4, polyline);
 84
 85                 /* We draw the segments */
 86                 xcb_poly_segment (connection, window, gc, 2, segments);
 87
 88                 /* draw the rectangles */
 89                 xcb_poly_rectangle (connection, window, gc, 2, rectangles);
 90
 91                 /* draw the arcs */
 92                 xcb_poly_arc (connection, window, gc, 2, arcs);
 93
 94                 /* flush the request */
 95                 xcb_flush (connection);
 96
 97                 break;
 98             default:
 99                 /* Unknown event type, ignore it */
100                 break;
101             }
102
103             free (event);
104         }
105
106         return 0;
107     }

  运行效果如下图:

  下面,对以上GUI绘图的程序进行分析:

  1、任何绘图程序,无论使用的是Win32 API,还是Java Swing,都离不开GC和DC的概念,使用XCB编写窗口程序也是如此。这两个概念,一个代表了图怎么绘,一个代表了图绘在哪里。由于绘图时需要指定太多的信息,比如画笔的粗细、线型、前景色、背景色等等,如果把这些信息统统作为参数传递给绘图函数,就会产生两个问题:一是调用这些函数太复杂,二是效率太低。所以,目前所有主流的GUI库都采用了一致的做法,那就是把这些信息组织成一个context,我们称之为graphic context,可简称gcontext或GC。DC可以认为是绘图时所用的画布,我们可以直接把图绘到屏幕上,也可以把图绘到窗口中,当然,也可以绘到控件中(因为控件的本质也是窗口)。在面向对象的编程语言中,可以绘图的组件往往都继承自Drawable。在XCB中,从绘图函数的签名可以看出,它仍然将绘图的目标称为drawable,虽然它只是一个id。

  2、什么时候绘图。理论上讲,任何时候都可以调用绘图函数。但是从实践上来讲,所有的GUI程序都是在窗口重绘的事件中调用绘图函数。窗口重绘事件,有的叫onPaint,有的叫onDraw,XCB中比较奇怪,叫EXPOSE。不管叫什么,其道理是一样的。那就是当窗口初次显示、从隐藏到显示或窗口内容需要刷新时,都会触发该事件,所以在处理该事件的代码中调用绘图函数是最好的,既可以保证我们看到绘图的结果,又兼顾效率(窗口不可见时绘图函数不用执行,窗口不变化时绘图函数也不用执行)。MVC模式也是构建在这样的基础之上,将数据与显示分离,数据可以随时被操作,但是绘图只在窗口重绘时进行。

  3、调用绘图函数。这个不需要多讲,因为几乎所有的绘图函数都是自解释的,看到函数名,就知道它要进行什么操作。

  在XCB中,创建GC可以通过xcb_create_gc()函数进行,创建窗口可以通过xcb_create_window()函数进行。在这两个函数中,都有一个比较奇怪的模式,那就是通过一个mask和value数组来设定GC和窗口的具体信息。在上一篇中,创建的窗口没有背景,而这一篇中,窗口具有白色背景,就是因为这里调用xcb_create_window时,在其mask参数中指定了XCB_CW_BACK_PIXEL。

  借助于ctags和Vim的taglist.vim插件,可以非常方便地查看这些mask的取值及其意义,只需按下Ctrl+]就可以跳到相应的定义处。如下两图,是enum xcb_gc_t中定义的一系列XCB_GC_***:

  再下面两个图,是创建窗口是可以用到的mask值:

  这些枚举都有很详细的注释,所以我就不在这里啰嗦了。libxcb的头文件中的注释,本身就是一种很好的学习资料,不是吗?

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

使用XCB编写X Window程序(02):在窗口中绘图

时间: 2024-11-15 05:29:13

使用XCB编写X Window程序(02):在窗口中绘图的相关文章

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

估计现在已经没有谁使用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

使用XCB编写X Window程序(06):XCB取代Xlib的理由

我经常访问Xorg的官网,希望能找到一些对理解Linux和X Window有用的东西.结果也确实是偶有所得.比如,在Xorg的官网中就建议大家不用Xlib了,改用XCB.不可否认,Xlib确实是一个比较老的东西,老到最新的一本关于Xlib的书都已经是N多年前出版的了.有了Xorg官方的指导,我自然不用学Xlib了,直接上XCB. 经过这一段时间的学习,对XCB有了一定的了解.我的学习是根据XCB官方的教程来的,当然,如果有一点点在GUI编程领域的经验和悟性学习起来会更加事半功倍.在XCB的官方教

使用XCB编写X Window程序(04):在窗口中绘制文字

在前面的几节中,我展示了使用XCB创建窗口.在窗口中画图以及捕获并处理事件.在这一篇中,我将展示在窗口中绘制文字.绘制文字当然离不开字体,所以我还会简单地探讨一下X Server的核心字体系统.老规矩,先上代码和运行效果图,代码如下: 1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <string.h> 4 #include <inttypes.h> 5 #include <xcb/xcb.h

使用XCB编写X Window程序(05):使用异步的方式和X Server通讯及获取和设置窗口的属性

在前面的例子中,我们从来没有关心过调用XCB函数时,该函数和X Server的通讯是同步的还是异步的.因为在前面的例子中,我们基本上不关心XCB函数的返回值,只有在上一篇中,由于某些操作需要关心它们是否成功(比如是否成功打开字体.是否成功创建GC等),才涉及到XCB函数的返回值. 在这一篇中会更进一步,因为是获取窗口的属性,所以肯定要关注从X Server获取的数据,这时,将会涉及到XCB函数同X Server的通讯是同步的还是异步的.什么是同步?就是说调用一个函数向X Server发出一个请求

使用XCB编写X Window程序(06):XCB官方教程中缺少什么

这将是我所写的关于XCB的最后一篇随笔. 在XCB的官方教程中,还有三篇内容,一篇是将Colormap和Pixelmap的,一篇是讲如何更改窗口的鼠标指针的,还有一篇,则是讲如何将Xlib程序转换成xcb程序的.很显然,以上内容都不是我所想要的,所以我就不再一一依葫芦画瓢将它们再写成中文的了(其实理解Colormap和Pixelmap对理解OpenGL很有用).我曾经多次吐槽XCB文档语焉不详,我说它语焉不详是指它对它自己的一些设计理念都没有讲清楚.比如在XCB的示例代码中,大量出现*_iter

MFC小程序—————02 不规则窗口小应用程序

什么不说了,先上程序截图: 运行结果是有一棵有星星在闪烁的圣诞树,还会循环播放背景音乐. 之前也是在网上看到类似的一个程序,然后自己最近也在学MFC,所以就模仿着写了一个, 其中使用的是GDI+来显示.png透明背景的图片,图片是在网上找的一张,然后又用PS把其中发光的星星给去掉了,做了一张不带发光星星的 .png图片,然后在程序中使用一个定时器来定时刷新窗口背景,使用这两张图片交替变换,实现星星闪烁的动画效果,利用MCI来播放.mp3的 背景音乐(如果想更改背景音乐,请先删除res文件夹下的s

转:假设有一个字符串aabcad,请编写一段程序,去掉字符串中不相邻的重复字符。

假设有一个字符串aabcad,请编写一段程序,去掉字符串中不相邻的重复字符.即上述字串处理之后结果是为:aabcd; 分析,重点考查 char 与int 的隐式转换.程序如下: -(void) removeRepeat:(NSString *)aNum { NSMutableArray *mArr = [[NSMutableArray alloc]initWithCapacity:10]; for(int i = 0; i<aNum.length; i++) { [mArr addObject:

VS2013+win8编写的C++程序在xp/win7中执行

使用Visual Studio 2013在Windows 8下编写的C++程序在Windows XP系统执行错误,报错信息为:"不是有效的win32应用程序". 在Windows 7报错信息例如以下图. 解决方法: 依照例如以下步骤操作就可以解决. 第一步:打开project的属性.点击[配置属性]->[常规]->[平台工具集],选择"Visual Studio 2013 - Windows XP (v120_xp)",例如以下图. * 假设你的程序为M

初始window程序

window 操作系统中,处处是窗体 简单 强大 方便 灵活 步骤 新建项目  项目类型 visual C#项目 模板 window应用程序 用partial 将同一个窗体的代码分开放在两个文件中:一个存放在vs自动生成的代码中 冒号表示继承像孩子继承父母的特征所有窗体都继承Form 窗体标题 : Name窗体图标: Icon图片背景Backgroundimage背景颜色 backcolor最大化按钮:MaximinBox最小化按钮:Minimun窗体边框样式 :FROMBorderStyle窗