linux应用程序开发指南之21-16.pdf
下载第16章 GDK 基 础16.1 GDK和XlibG T K是用于实现图形用户接口的函数库。在 L i n u x平台上,G U I(图形用户接口)使用的是称为X 窗口(X Wi n d o w)的系统。X窗口系统是1 9 8 4年由美国麻省理工学院(M I T)开发的。在 L i n u x上使用的 X窗口系统是一种称为 X F r e e 8 6的X版本。X窗口系统与 M i c r o s o f tWi n d o w s的图形用户接口有所不同,它是基于客户/服务器的。X服务器在计算机上运行,控制监视器、鼠标和键盘。X客户通过网络与服务器通讯。X服务器为X客户提供图形显示服务。也就是说,X客户和X服务器可能在同一台计算机上运行,也可能在不同的计算机上运行。X窗口系统带有一套低级的库函数,称为 X l i b。X l i b提供了许多对X窗口的屏幕进行操作的函数。当然,使用X l i b函数在屏幕上创建构件是很复杂的。G T K要在屏幕上绘制各种构件,就需要与X服务器打交道。但是 G T K提供的构件库并未直接使用 X l i b,而是使用了一个称为G D K的库。G D K的意思是GIMP Drawing To o l k i t,亦即G I M P绘图工具包。差不多每个G d k函数都是一个相应X l i b函数的封装。但是X l i b的某些复杂性(和功能)被隐藏起来了。这样是为了简化编程,使G d k更容易移植到其他窗口系统(有一个在Wi n d o w s平台上的G d k版本)。被隐藏的X l i b功能一般是程序员极少用到的,例如,X l i b的许多特性只有窗口管理器才会用到,所以没有封装到G d k当中。如果需要,可以在应用程序中直接调用 X l i b函数,只要在文件头部包含g d k/g d k x.h头文件就可以了。一般情况下,如果要创建普通的图形接口应用程序,使用 G T K就可以了。G t k+和G n o m e构件库提供了极为丰富的构件,足以构造非常复杂的用户界面。但是,如果需要开发新构件,或者要创建绘图程序,仅使用 G T K就不够了。这时可以采用X l i b,更好的方法是使用G D K库,它可以应付绝大多数的编程需要。本章介绍了关于G D K的一些基本知识,这些也是创建构件和绘图的基础。更多的 G D K细节内容,请参考g d k.h头文件。如果想了解G d k函数的实现细节(比如它对应于 X l i b的哪一个函数),可以看一下G d k的源代码以确定它所封装的 X l i b函数,然后用 m a n指令参看该函数的手册页。例如,下面是g d k _ d r a w _ p o i n t()函数的实现代码:v o i dgdk_draw_point(GdkDrawable*drawable,GdkGC *gc,gint x,gint y)GdkWindowPrivate*drawable_private;GdkGCPrivate*gc_private;g_return_if_fail(drawable!=NULL);g_return_if_fail(gc!=NULL);drawable_private=(GdkWindowPrivate*)drawable;if(drawable_private-destroyed)r e t u r n;gc_private=(GdkGCPrivate*)gc;XDrawPoint(drawable_private-xdisplay,drawable_private-xwindow,gc_private-xgc,x,y);每一个数据结构都被转换给它的一个“私有”版本,该“私有”版本包含了与 G D K正在使用的特定窗口系统的相关信息,这样可以将与特定窗口系统相关的函数声明排除在gdk/gdk.h 头文件外。每个数据结构的“私有”版本都包含一个封装的 X l i b数据结构,且这个数据结构被传递到 X D r a w P o i n t()函数中,所以 X D r a w P o i n t()函数的文档也适用于g d k _ d r a w _ p o i n t()函数。16.2 GdkWindowG d k Wi n d o w是X l i b窗口对象的封装。一个G d k Window 代表屏幕上的一个区域,可以显示或隐藏起来(在X l i b里面称为映射或反映射窗口),也可以捕获G d k Wi n d o w接收到的事件,还可以在里面绘制图像,移动或调整图像的尺寸。G d k Window 是以树状结构组织的,也就是说,每一个窗口都可以有子窗口。子窗口是相对于父窗口的位置定位的,当父窗口移动时,子窗口也会移动。子窗口不会在父窗口边界外的区域绘出(也就是说,它们会被父窗口剪裁)。所谓G d k Wi n d o w窗口的树状组织并不是针对每个应用程序的,实际上有一个由 X服务器和窗口管理器控制的窗口的全局树。根窗口没有父窗口,所有窗口都是从它派生而来的。作为桌面背景,根窗口的全部或部分总是可见的。每个窗口都可以为不同的 L i n u x进程所拥有,一些窗口是由窗口管理器所创建的,还有一些来自于用户的应用程序。G d k Wi n d o w和G t k Wi n d o w是完全不同的东西。G t k Wi n d o w是一个G t k+构件,用于表示顶级(t o p l e v e l)窗口(顶级窗口是在窗口层次中由应用程序控制的最高级别的窗口)。典型情况下,窗口管理器为顶级窗口创建各种装饰,包括标题条、关闭按钮以及窗口外观等。要理解X窗口首先要知道它是 X服务器上的一个对象,这一点很重要。X客户对每一个窗口获得一个独一无二的整数 I D号,并用I D号码引用该窗口。这样,所有的窗口操作都发生在服务器上,并且所有与X窗口打交道的函数都要通过网络传输。G d k Wi n d o w是由X返回的整数I D号的一个封装。它确实保存一些信息的本地拷贝(比如说窗口的尺寸),所以一些G d k操作比相应的X l i b操作效率更高。还有,G d k Wi n d o w本质上是服务器端对象的一个句柄。许多G d k对象都是相似的,字体、像素映射图片、鼠标光标等等也是服务器端对象的句柄。16.2.1 GdkWindow和GtkWidget许多G t k Wi d g e t子类都有一个相关联的 G d k Wi n d o w窗口。理论上,G t k+应用程序可以只创建一个顶级窗口,并将所有构件画在里面。然而,这么做并没有什么实际意义,因为G d k Wi n d o w允许X窗口系统自动处理许多细节。例如,G d k所接收到的事件都使用它们所发生的窗口标志,这使得G t k+能很快确定每个事件是哪个构件发生的。有一些构件是没有与之相关联的 G d k Wi n d o w窗口的,它们称为“无窗口”的构件,用一第1 6章GDK 基础使237下载个G T K _ N O _ W I N D O W标记来标志它们(可以用G T K _ W I D G E T _ N O _ W I N D O W()宏来测试它们)。没有窗口的构件会将自身绘制在其父构件容器的 G d k Wi n d o w窗口上。无窗口构件相对较小,占用资源较少,一般将它们称为“轻量级”的,G t k L a b e l构件就是一个最常见的例子。因为事件总是由G d k Wi n d o w窗口接收的,无窗口构件不能接收事件。如果想让无窗口构件捕获事件,可以使用G t k E v e n t B o x容器构件。16.2.2 GdkWindow属性创建G d k Wi n d o w时,gdk_window_new()函数允许指定窗口的所有属性,这些属性以后也可以再改变。要指定多个属性,可以向函数传递一个 G d k Wi n d o w A t t r对象。G d k Wi n d o w A t t r对象的内容就是G d k Wi n d o w窗口的属性。下面是G d k Wi n d o w A t t r结构的定义:typedef struct _GdkWindowAttr GdkWindowAttr;struct _GdkWindowAttrgchar*title;gint event_mask;gint16 x,y;gint16 width;gint16 height;GdkWindowClass wclass;GdkVisual*visual;GdkColormap*colormap;GdkWindowType window_type;GdkCursor*cursor;gchar*wmclass_name;gchar*wmclass_class;gboolean override_redirect;因为G d k Wi n d o w A t t r结构的一些成员是可选的,所以 g d k _ w i n d o w _ n e w()函数用一个a t t r i b u t e s _ m a s k参数指定哪一个可选成员里包含有效的数据。Gdk 只检查在屏蔽值里面指定的成员,这样可以让不感兴趣的成员保留缺省值。下面的函数列表简要概括了这些值。没有a t t r i b u t e s _ m a s k标志的成员必须指定,因为它们没有缺省值。g d k _ w i n d o w _ n e w()函数最典型的是用在构件的实现中,用来创建构件的 G d k Wi n d o w。在其他场合下极少用到它。g d k _ w i n d o w _ d e s t r o y()函数销毁G d k Wi n d o w窗口。函数列表:G d k Window#include GdkWindow*gdk_window_new(GdkWindow*parent,GdkWindowAttr*attributes,gint attributes_mask)void gdk_window_destroy(GdkWindow*window)下面简要介绍G d k WindowAttr 结构中各个成员的意义。第一个成员t i t l e是G d k Wi n d o w的标题,它只对顶级窗口才有实际意义,大多数窗口管理器把它放在标题条上。通常,不要在创建 G d k Wi n d o w窗口时指定 t i t l e值,应该让用户调用g t k _ w i n d o w _ s e t _ t i t l e()函数来指定它。238使第二部分 Linux编程常用C语言函数库及构件库下载第二个成员e v e n t _ m a s k是窗口的事件屏蔽,它决定这个窗口接收什么事件。后面会有详细的介绍。第三个和第四个成员x、y是窗口的X、Y坐标,它们是以像素度量的;这两个坐标是相对于父窗口原点的坐标。每个窗口的原点都是它的左上角(西北角)。注意,它们是1 6位的有符号整数。X窗口最大可以是32 768像素,它可以是负数值,不过会被它的父窗口剪裁掉(只有在父窗口内部的区域才是可见的)。第五个和第六个成员 w i d t h、h e i g h t是窗口的宽度和高度,它们是以像素度量的,也是1 6位的有符号整数。第七个成员G d k Wi n d o w C l a s s可取以下两种值:GDK_INPUT_OUTPUT:G d k Wi n d o w是一个普通窗口 G D K _ I N P U T _ O N LY:G d k Wi n d o w是一个窗口,它有一个位置,能接收事件,但没有视觉上的表示,也就是说它是不可见的。它的子窗口也必须是这种类型的。你可以为这种窗口设置光标和其他的属性,但是没有办法把窗口画出来(因为它是不可见的)。这种窗口有时候用于捕获事件或改变两个普通窗口重叠区域的鼠标光标。第八个成员v i s u a l(视件)描述了一个显示器的颜色处理特征;第九个成员 c o l o r m a p(颜色表)包含了用于绘画的颜色。第十个成员w i n d o w _ t y p e指定G d k Wi n d o w的类型。窗口可以是下面几种不同类型之一,由G d k Wi n d o w Ty p e枚举类型指定:GDK_WINDOW_ROOT:是根窗口的G d k封装类型,在初始化时创建。G D K _ W I N D O W _ TO P L E V E L:是一个顶级窗口。在这种情况下,g d k _ w i n d o w _ n e w()函数的p a r e n t参数应该设为N U L L。G d k自动使用根窗口作为它的父窗口。GDK_WINDOW_CHILD:是一个在顶级窗口中的下级窗口。G D K _ W I N D O W _ D I A L O G:基本上与顶级窗口是一样的。它的父窗口应该是 N U L L,并且G d k会替换根窗口。应该设置一个窗口类提示(w m c l a s s _ n a m e)告诉窗口管理器这个窗口是一个对话框,一些窗口管理器会考虑这些情况并作适当的处理。G D K _ W I N D O W _ T E M P:用于弹出菜单或其他类似的东西。它是一个只需暂时存在的窗口。它是一个顶级窗口,所以它的父窗口应该是 N U L L。这种窗口的鼠标光标总是与它们父窗口的一样。所以它们会忽略属性结构中的相关成员值。G D K _ W I N D O W _ P I X M A P:根本就不是窗口。在 G d k中G d k P i x m a p和G d k Wi n d o w差不多是同样处理的,所以G d k用同样的结构表示它们;它们可以视为 G d k D r a w a b l e类型。G D K _ W I N D O W _ F O R E I G N:标识一个不是由G d k创建的窗口的封装。对g d k _ w i n d o w _ n e w()来说,只有G D K _ W I N D O W _ TO P L E V E L、G D K _ W I N D O W _ C H I L D、G D K _ W I N D O W _ T E M P和G D K _ W I N D O W _ D I A L O G是有效的。库用户不会创建一个G D K _ W I N D O W _ R O O T。p i x m a p(G D K _ W I N D O W _ P I X M A P)是用g d k _ p i x m a p _ n e w()创建的。外来窗口(G D K _ W I N D O W _ F O R E I G N)是在G d k外部创建并用g d k _ w i n d o w _ f o r e i g n _ n e w()封装的X窗口。第十一个成员c u r s o r指定在这个窗口中的鼠标的指针(光标)形状。第十二个成员w m c l a s s _ n a m e前面已经介绍过了。写构件时,通常不设置类提示,它只与顶级窗口有关。G t k+提供了g t k _ w i n d o w _ s e t _ w m c l a s s()函数,程序员可以将它设置为具有确切含义的值。第1 6章GDK 基础使239下载G d k Wi n d o w A t t r的最后一个成员 o v e r r i d e _ r e d i r e c t决定窗口是否“替换重定向”的。通常,窗口管理器截获所有对顶级窗口的显示、隐藏、移动或尺寸调整请求。你可以重定向或取消这些请求,让顶级窗口按窗口管理器的布局策略行事。将o v e r r i d e _ r e d i r e c t设置为T R U E,禁止窗口管理器对窗口的管理。因为窗口管理器不能移动设置了这个标志的窗口,通常也不会为这样的窗口设置标题条或其他的装饰。注意,所有的G D K _ W I N D O W _ T E M P窗口都将这个成员设为 T R U E;G D K _ W I N D O W _ T E M P通常用作弹出菜单,窗口管理器不能控制它。一般不应该改变o v e r r i d e _ r e d i r e c t成员。如果指定了正确的 G d k Wi n d o w q Ty p e,缺省值差不多总是正确的。不过还是有一些例外,例如 G n o m e面板应用程序设置了这个成员。16.3 视件和颜色表硬件之间总存在差别。最原始的 X服务器只支持两种颜色,每一个像素只能是 o n或o ff(开或关)。这就是“每像素一位”(b p p)显示模式。每像素一位的显示模式称为深度为 1。多数高级的X服务器支持每像素 2 4或3 2位,还允许以窗口为基础指定不同的深度。每像素 2 4位允许22 4(16 777 216)种像素,包含了比人眼能分辨的还要多的颜色。从概念上说,位图显示由一个矩形的像素网格组成。每个像素由一些固定的位数组成;像素以一种硬件相关的方法映射为可视的颜色。考虑这种概念的一种方法就是想象一个二维的整数数组,整数的大小等于要求的位数。换一种说法,可以想象一种显示就像一个“位平面”栈,或“位”的二维数组。如果每个平面都平行于其他平面,那么一个像素就是一根在相同坐标处穿过每个平面的垂线,并且从每一个平面处获得一位。这就是术语“深度”的起源,因为每个像素的位数等于位平面栈的深度。在X窗口系统中,像素代表在一个颜色查找表中的入口。一种颜色就是一组红、绿、蓝(R G B)值监视器以一定比率混合红绿蓝光以显示每个像素。例如,考虑一种八位的显示模式:八位不足以为现实中的颜色编码,只可能为很少部分的 R G B值编码。作为替代,数据位被解释为整数,用于为R G B颜色值做索引。这个颜色表称为 c o l o r m a p(颜色表),有时,你也可以修改它以包含要使用的颜色,虽然这样做是硬件相关的(一些c o l o r m a p是只读的)。视件(v i s u a l)用来决定像素的位模式如何转换为一个可见的颜色。因而,视件还定义了颜色表如何工作。在八位显示中,X服务器也许将每个像素解释为一个包含 2 5 6种可能颜色值的颜色表的索引。典型情况下,2 4位视件有三个颜色表:一个是红色的浓淡值,一个是绿色的浓淡值,一个是蓝色的浓淡值。每个颜色表用一个八位的值索引;三个八位值组成2 4位的像素。视件定义了像素内容的含义,还定义了颜色表是只读的还是可修改的。简而言之,视件就是特定 X服务器的颜色容量的描述。在 X l i b中,你得围绕视件做很多罗嗦的事,但是G d k和G t k+能极大地简化了这些繁琐工作。16.3.1 GdkVisualX l i b能报告一个所有可用的视件以及相关信息的列表;G d k在一个称为G d k Vi s u a l的结构中保持一个这些信息的客户端拷贝。G d k能报告可用的视件,并将它们以不同的方式分级。在多数时候,只需用 g d k _ v i s u a l _ g e t _ s y s t e m()函数就可以了,它返回一个指向缺省视件的指针。如果正在写一个G t k Wi d g e t构件,g t k _ w i d g e t _ g e t _ v i s u a l()函数将返回应该使用的视件。返回的240使第二部分 Linux编程常用C语言函数库及构件库下载视件不是一个拷贝,所以不需要释放它,G d k将永久保存视件。获取缺省视件#include GdkVisual*gdk_visual_get_system()下面是G d k Vi s u a l结构的定义,大多数成员都用于由颜色计算像素值。typedef struct _GdkVisual GdkVisual;struct _GdkVisualGdkVisualType type;gint depth;GdkByteOrder byte_order;gint colormap_size;gint bits_per_rgb;guint32 red_mask;gint red_shift;gint red_prec;guint32 green_mask;gint green_shift;gint green_prec;guint32 blue_mask;gint blue_shift;gint blue_prec;16.3.2 视件的类型视件用不同的度量方法加以区分。它们可以是灰度级或者 R G B值,颜色表可以是可修改的或者固定的,像素值可以是单个的颜色表或者包含了压缩的红、绿、蓝的索引值。下面是G d k Vi s u a l Ty p e的可能取值:G D K _ V I S U A L _ S TAT I C _ G R AY:意味着显示器是单色的或者灰度的,颜色表不能修改。一个像素值只是一个灰度级别,每个像素都是“硬编码”,分别代表一个确定的屏幕上的颜色。G D K _ V I S U A L _ G R AY S C A L E:意味着显示器是可修改的,但是只有灰度的级别才可能修改。像素代表在颜色表中的一个入口,所以给定的像素在不同的时候能够代表不同的灰度级别。G D K _ V I S U A L _ S TAT I C _ C O L O R:代表一种颜色显示,它使用单个只读的颜色表而不是红、绿、蓝每种颜色各一个单独的颜色表。这种显示差不多就是 1 2位或更少(使用单个颜色表的2 4位显示器需要一个带 22 4个入口的颜色表,差不多有 5 0 0 M B)。这是一种恼人的视件,因为它的可用颜色太少,而且不能改变成它们的实际颜色。G D K _ V I S U A L _ P S E U D O _ C O L O R:从很多年前开始,就一直是低端P C硬件的常用视件。如果有一个1 M B显存、2 5 6色的显示卡,这极有可能就是你的 X服务器的视件。它代表一种具有读/写颜色表的颜色显示。像素只对单个颜色表索引。第1 6章GDK 基础使241下载 G D K _ V I S U A L _ T R U E _ C O L O R:是带三个只读颜色表的颜色显示,红、绿、蓝每种颜色有一个颜色表。一个像素包含三个索引,每个颜色表一个。在像素值和 R G B三元组之间有固定的数学关系,可以用下面的公式从 0,2 5 5 间的红、绿、蓝值获取像素值:gulong pixel=(gulong)(red*65536+green*256+blue)。G D K _ V I S U A L _ D I R E C T _ C O L O R:是一种有三个读写颜色表的颜色显示。如果使用G d k颜色处理例程,它们只是简单地填充所有三个颜色表以模拟真彩显示。16.3.3 颜色和GdkColormapG D K使用G d k C o l o r存储R G B值和像素值。红、绿、蓝值是以 1 6位无符号整数给出的,取值范围为0到6 5 5 3 5。像素的内容依赖于视件。下面是 G d k C o l o r结构定义:typedef struct _GdkColor GdkColor;struct _GdkColorgulong pixel;gushort red;gushort green;gushort blue;在用一种颜色绘画时,必须:保证像素值包含合适的值。保证颜色值在要使用的可绘区的颜色表中存在(可绘区是一个可以在上面绘画的窗口或p i x m a p)。在X l i b中,这是一个非常复杂的过程,因为需要对每种不同的视件做不同的工作。G d k对这个过程作了大量的简化。你只需调用 g d k _ c o l o r m a p _ a l l o c _ c o l o r()函数来填充像素值并将颜色值添加到颜色表中即可。下面是一个例子,它使用一个现有的颜色表,这个颜色表应该是要绘画的可绘区的颜色表:GdkColor color;/*纯红色*/color.red =65535;color.green=0;color.blue =0;if(gdk_colormap_alloc_color(colormap,&color,FALSE,TRUE)/*成功!*/如果g d k _ c o l o r m a p _ a l l o c _ c o l o r()函数返回T R U E,然后分配了一个颜色,c o l o r.p i x e l中包含了一个有效的值,这个颜色就可以用于绘画了。g d k _ c o l o r m a p _ a l l o c _ c o l o r()函数中的两个布尔型参数指定了这个颜色是否可写,以及当颜色不能分配时是否尽量找到一个“最匹配的”颜色。如果使用了最匹配的颜色而不是分配一个新颜色,颜色的R G B值会变成最匹配的值。如果为一个不可写的颜色表请求一个最匹配值,颜色分配不应该会失败。因为即使是在黑白显示器中,黑或者白也会是最好的匹配,只有空的颜色表会导致失败。获得空颜色表的唯一方法就是自己创建一个定制的颜色表。如果不要求最好匹配,在有限颜色数的显示器中极有242使第二部分 Linux编程常用C语言函数库及构件库下载可能会失败。在可写的颜色表中很容易会发生失败(此时“最匹配”颜色并没有意义,因为该颜色表能被修改)。“可写”的颜色表是可以在任何时间改变的颜色表,一些视件支持它,还有一些视件不支持。可写颜色表的作用是改变屏幕的颜色而不用重绘图形。一些硬件在它的颜色查找表中将像素作为索引存储,所以改变查找表就改变了像素的显示。可写颜色表的缺点非常多。最特别的几点:不是所有的视件支持它们,并且可写的颜色表不能由其他应用程序所用,而只读的颜色表可以共享,因为其他的应用程序知道颜色会保持不变。因而,应该尽量避免分配可写的颜色值。在较新的硬件中,使用“可写”颜色表的坏处比获得的好处更多;与直接重绘相比,它并不能显著提高绘图的速度。使用完一种颜色后,应该用g d k _ c o l o r m a p _ f r e e _ c o l o r s()函数将它从颜色表中删除。这只对伪彩色和灰度级的视件很重要,在这两种情况下,颜色不够使用,颜色表能被客户修改。G d k会自动对每一种视件类型做适当的事情,所以调用这个函数就可以了。获得R G B值最方便的方法是 g d k _ c o l o r _ p a r s e()函数。这个函数采用 X颜色规范,填充G d k C o l o r的红、绿、蓝值。X颜色规范可以有多种形式,一种可能形式是 R G B字符串:R G B:F F/F F/F F这指定了一个白色(红绿蓝全部是全亮度)。“R G B:”指定一个“颜色空间”,并决定后面数字的意义。X系统还能理解其他更晦涩的“颜色空间”。如果颜色规范字符串不是以一个可识别的“颜色空间”开头,X系统假定它是一个颜色名,并在一个颜色名称数据库中查找。所以可以写下面这样的代码:GdkColor color;if(gdk_color_parse(orange,&color)if(gdk_colormap_alloc_color(colormap,&color,FALSE,TRUE)/*得到橙色!*/可以看到,如果g d k _ c o l o r _ p a r s e()函数认出了传给它的字符串,它会返回 T R U E。只能使用很少的颜色名,比如“o r a n g e”,但是绝大多数颜色都没有相对应的颜色名,也没有办法知道什么名字在数据库里面能找到,所以应该检查函数的返回值。函数列表:颜色分配#include gboolean gdk_colormap_alloc_color(GdkColormap*colormap,GdkColor*color,gboolean writeable,gboolean best_match)void gdk_colormap_free_colors(GdkColormap*colormap,GdkColor*colors,gint ncolors)gint gdk_color_parse(gchar*spec,GdkColor*color)第1 6章GDK 基础使243下载16.3.4 获得颜色表如果正在写一个 G t k Wi d g e t子类,获得颜色表的正确方法就是使用g t k _ w i d g e t _ g e t_ c o l o r m a p()函数。另外,系统(缺省)的颜色表通常就是所想要的,调用 g d k _ c o l o r m a p _ g e t_ s y s t e m()函数时不需要参数,它返回缺省的颜色表。G d k R G B模块是另一种处理颜色的方法,在它的其他功能中,它能用 R G B值设置S图形上下文的背景色和前景色。相关的函数是g d k _ rg b _ g c _ s e t _ f o r e g r o u n d()和g d k _ rgb _gc_set_ b a c k g r o u n d()。G d k R G B有一个预先分配的颜色表,用来拾取一个最匹配的颜色,使用它意味着应用程序能够与其他使用 G d k R G B的应用程序(比如G I M P)共享有限的颜色表资源。你还能获得G d k R G B的颜色表,可以直接使用它。16.4 可绘区和pixmap一个 p i x m a p(像素映射图片)是一个屏幕外的缓冲,可以在里面绘图。当图片存在p i x m a p中之后,可以将它复制到一个窗口,当窗口可见时,让它显示在屏幕上。当然,还可以直接在窗口中绘制。使用 p i x m a p作为缓冲可以快速更新屏幕而不需要重复一系列原始的绘图操作。p i x m a p用来存储从磁盘加载的图像数据,比如图标和徽标。然后可以将图像复制到窗口中。在G d k中,p i x m a p类型称为G d k P i x m a p。每个像素只有一位p i x m a p称为位图,在G d k中用G d k B i t m a p代表位图。位图(B i t m a p)并不真是一种单独的类型,从 X系统的观点来说,它只是一个深度为1 的p i x m a p。像窗口一样,B i t m a p是服务器端资源。在X的术语学中,一个可绘区就是所有可以在上面绘图的东西。在 G d k中有一个相应的类型,称为G d k D r a w a b l e。可绘区包括窗口、p i x m a p以及位图。下面是在G d k里面的类型定义:typedef struct _GdkWindow GdkWindow;typedef struct _GdkWindow GdkPixmap;typedef struct _GdkWindow GdkBitmap;typedef struct _GdkWindow GdkDrawable;在客户端,p i x m a p和位图只是类型为 GDK_WINDOW_PIXMAP 的G d k Wi n d o w窗口。G d k D r a w a b l e用在可接受窗口或者 p i x m a p为参数的函数声明中。绘制图形的函数使用这两种类型作为参数,移动或者设置“窗口管理器提示”的函数只接受窗口为参数。只有窗口能够接收事件。G D K _ I N P U T _ O N LY窗口是一种特殊情况,它们不是可绘区,不能在上面绘画。实际上,上面四种可绘区有三种逻辑组合:可绘制的不可绘制的具有窗口特性普通窗口只能输入的窗口无窗口特性P i x m a p/B i t m a p-不幸的是,所有这三种逻辑上截然不同的情形从类型检查的观点来看都是一样的。所以要小心使用,不要弄错了。还有,要记住普通窗口在实际显示在屏幕上之前并不是可绘区,应该等到接收到一个“e x p o s e”事件后才能开始绘画。像G d k Wi n d o w一样,一个G d k P i x m a p仅仅是位于X服务器上的对象的客户端句柄。因为这一点,某些操作从性能的观点来看是完全不可行的,例如,如果正在做任何要求对单个像素进行大量操作的事情,可绘区反应会非常慢。另一方面,复制一个 p i x m a p到窗口中并没有想象的慢,因为两个对象都是在同一台机器上的。244使第二部分 Linux编程常用C语言函数库及构件库下载创建一个p i x m a p比创建一个窗口要简单得多,因为大多数窗口属性与 p i x m a p是不相关的。用g d k _ p i x m a p _ n e w()函数创建p i x m a p。它以初始尺寸和位深度为参数。如果深度值是-1,从它的G d k Wi n d o w参数中复制深度。不能为深度随意指定一个值服务器不支持所有的深度,并且p i x m a p的深度必须与要复制到的窗口的深度一致。调用 g d k _ p i x m a p _ u n r e f()函数可以销毁一个p i x m a p。传递到g d k _ p i x m a p _ n e w()函数中的G d k Wi n d o w参数不是严格需要的。不过,该函数中封装了一个X C r e a t e P i x m a p()函数,它以一个X窗口作为参数。它用这个参数决定在哪个屏幕上创建窗口,一些X服务器有多个显示器。屏幕是一个完全由 G d k隐藏起来的X l i b概念,G d k一次只支持一个屏幕。这样,从 G d k的观点来看,g d k _ p i x m a p _ n e w()函数中的w i n d o w参数很神秘。函数列表:G d k P i x m a p构建函数#include G d k P i x m a p*gdk_pixmap_new(GdkWindow*window,gint width,gint height,gint depth)void gdk_pixmap_unref(GdkPixmap*pixmap)16.5 事件事件传送到应用程序中,以指明在一个 G d k Wi n d o w中的变化或者有意义的用户动作。所有的事件都与一个 G d k Wi n d o w相关联。它们也与一个 G t k Wi d g e t相关联,G t k+主循环将事件从G d k传递给G t k+构件树。16.5.1 事件类型事件G D K中有多种类型,可以使用 G d k E v e n t联合体代表任何类型。有一个特殊的事件类型G d k E v e n t A n y,它包含了所有事件都有的三个成员,任何事件都可以转换为 G d k E v e n t A n y。G d k E v e n t A n y中的第一个成员是一个类型标志,G d k E v e n t Ty p e。G d k E v e n t联合体中也包含G d k E v e n t Ty p e。下面是G d k E v e n t A n y结构定义:struct _GdkEventAnyGdkEventType type;GdkWindo-w*window;gint8 send_event;下面是GdkEvent 联合体的定义:union _GdkEventGdkEventType type;GdkEventAny any;GdkEventAny any;GdkEventExpose expose;GdkEventNoExpose no_expose;第1 6章GDK 基础使245下载GdkEventVisibility visibility;GdkEventMotion motion;GdkEventButton button;GdkEventKey key;GdkEventCrossing crossing;GdkEventFocus focus_change;GdkEventCo