X Window 程式设计入门--第二章 X Programming 的第一步

来源:互联网 发布:js怎么延迟加载 编辑:程序博客网 时间:2024/05/16 15:59


http://cnpa.yzu.edu.tw/~thinker 作者:李圭烽 (Thinker; Thinker.bbs@bbs.yzu.edu.tw) (2001-06-01 19:00:01)
Index: 
基本步骤  
建立一个 display至 X Server  
取得 display的相关资料  
建立视窗  
和视窗管理程式(Window Manager)沟通  
显示视窗  
关闭(destroy)视窗  
关闭 display  
例  

-------------------------------------------------------------------------------- 


一个 X 的程式的几个基本步骤:  
main() { 
建立一个 display 至 X Server; 
取得 display 的相关资料; 
设定视窗(window)特性(Attributes); 
建立视窗(window); 
和视窗管理程式(window manager)进行沟通; 
显示(map)视窗; 
......  ...... 
... 程式处理 ... 
............. 
关闭(destroy)视窗; 
关闭 display; 



1. 建立一个 display 至 X Server 
在程式开始向 X Server 进行任何的动作之前,程式必需先和 X Server 之间建立一个连线(connection),我们称之为 display。 XOpenDisplay 即为 Xlib 提供给我建立 display 的函数。  
-------------------------------------------------------------------------------- 


Display *XOpenDisplay(display_name) 
char *display_name; 


display_name 指定要连接之 server。如果 display_name 设定为 
NULL,则内定使用环境变数(environment variable) 
DISPLAY 的内容为连接对像。 




-------------------------------------------------------------------------------- 
呼叫 XOpenDisplay 之後,会传回一个 Display 结构。 Display 结构 存放着一些关於 display 的资讯。 虽然我们可以直接存取 Display 结构,但我们不该迳自改变其内容。 Xlib 有提供一系列的函数和巨集 (macro),我应该透过这些函数和巨集(macro)存取 Display 的内容。 以维持 Xlib 的正常运作。 
display_name 或是 DISPLAY 环境变数(environment variable)的格式 如下:  

-------------------------------------------------------------------------------- 

hostname:number.screen_number 


hostname 
设定 display 所在主机(host)之名称,在主机名称之後紧接着的是单 
个冒号(:)或是双冒号(::)。 
number 指定主机上,display server 的编号。一台主机(host)上可能同时存 
有多个 server,每个 server 都会给与一个编号,这个编号从零开始 
。在 server 的编号後面有一个句点(.),这个依你是否设定後面的 
screen_number 而决定是否该加。 
screen_number 
每一个 server 可能同时管理着多个显示幕,而每一个显示幕我们也给 
与一个从零开始的编号。screen_number 也就是设定着这个编号,做为 
default 的 screen。当你使用 DefaultScreen 巨集或是  
XDefaultScreen 函数时,即会存取到这个值。 


-------------------------------------------------------------------------------- 
举例:  
Display *display; 


display = XOpenDisplay("cnpa.yzu.edu.tw:0"); 


建立与 cnpa.yzu.edu.tw 上第零个 server 的 display。  
2. 取得 display 的相关资料 
在我们建立视窗之前,我们必需对目标 display 和萤幕(screen)的属 性状况有所了解。 我们可以透过 Xlib 所提供的巨集(macro)和函数 (function)取得指定 display 和萤幕(screen)的资料,利用这些资料 以设定视窗参数,以应不同的萤幕建构合适的视窗。 


建立视窗,我们必需设定多种和目标萤幕(screen)相关的参数。我们就 这些参数设定的需要,介绍如何利用 Xlib 来取得关於 display 的资 料。 




-------------------------------------------------------------------------------- 


DefaultRootWindow(display) 


Window XDefaultRootWindow(display) 
Display *display; 


display 指定至 X server 的连结(connection),即 
XOpenDisplay 所传回之结构。 


-------------------------------------------------------------------------------- 
传回预定萤幕(default screen)的根(root)视窗。每一个视窗都有父视 窗(parent window),当你要在程式开启一个最上层的视窗(top window);不是程式其它视窗的子视窗。那麽,由於己没有其它更上层 的视窗可以当父视窗,所以必需设根视窗(root window)为该视窗的父视窗 (parent window)。我们使用 DefaultRootWindow 取得预定萤幕的根视 窗(root window),可以在建立新视窗时,以任一根视窗(root window) 做为新视窗的父视窗(parent window)。透过指定父视窗(root window) ,我们也指定了负责显示新视窗的萤幕(screen)。 


-------------------------------------------------------------------------------- 


DefaultDepth(display, screen_number) 


int XDefaultDepth(display, screen_number) 
Display *display; 
int screen_number; 


display 指定连至 X Server 的连接(connection)。 
screen_number 指定萤幕的编号。 




-------------------------------------------------------------------------------- 
传回指定萤幕根视窗(root window)的预定深度(depth)。每个视窗都有 自己的深度(depth),深度影着该视窗所能显示的颜色数。当一个视窗 的的深度大,则其同时能显示的颜色总数也会随之增加。但,深度( depth)并非无限量的增加,会受限於硬的限制。一般我们会参考根视 窗(root window)的设定。 




-------------------------------------------------------------------------------- 


DefaultScreenOfDisplay(display) 


Screen *XDefaultScreenOfDisplay(display) 
Display *display; 


display 指定一个 X Server 的连结(connection) 




-------------------------------------------------------------------------------- 
传回指向预定萤幕(default screen)的指标。预定萤幕(default screen)即建立 display 时,在 display name 指定的 screen number。 




-------------------------------------------------------------------------------- 


DefaultVisualOfScreen(screen) 


Visual *XDefaultVisualOfScreen(screen) 
Screen *screen; 


screen 指定适当的 Screen 结构。 


-------------------------------------------------------------------------------- 
传回预定萤幕(default screen)的预定视觉(default visual)。在某些 显示设备上,允许同时以多种不同的方式理颜色的显示。我们可以任意 的方式,将深度(depth)为 8-bits 的图素(pixel)对映到显示的颜色。 也可以将深度(depth)为 24-bits 的图素(pixel),以红、黄、蓝各为 8-bits 的方式对映到实际的颜色。图素(pixel)指的是画面上的一个点 ,这指的是代表该点颜色的一个编号。例如,我们可能以 7 做为RGB 值为 0x9f7071 的颜色的编码,则任何图素(pixel)为 7 的点,其颜色 则为 RGB 0x7f7071。 


3. 建立视窗 
我现在开始建立新视窗(window)。视窗(window)建立之後,并不会马上 在我们指定的显示器(screen)上显示出来。我们要经过一道 map 的手 序後,视窗(window)才会正式在显示器上显示出来。在我们建立视窗( window)之後,在 map 之前,我们可以对新视窗(window)做一些设定的 动作,以设定视窗(window)的行为特性。 


建立新视窗(window)要透过 Xlib 所提供的 XCreateWindow 函数或者 XCreateSimpleWindow 函数,XCreateSimpleWindow 是 XCreateWindow 的简化版。这两个函数可用来建立新的子视窗。  
-------------------------------------------------------------------------------- 


Window XCreateWindow(display, parent, x, y, width, height, 
border_width, depth, class, visual, valuemask, 
attributes) 


Display *display; 
Window parent; 
int x, y; 
unsigned int width, height; 
unsigned int border_width; 
int depth; 
unsigned int class; 
Visual *visual; 
unigned long valuemask; 
XSetWindowAttributes *attributes; 


display 指定到 X Server 的连结。 
parent 指定父视窗(parent window)。 
x, y 指定视窗边框(border)的左上角相对於父视窗(parent 
window的座标。也就是以父视窗(parent window)内部 
的左上角做为原点所求得的相对座标。此座标用来指 
定视窗的显示位子。 
width, height 视窗内部尺寸的宽度和高度,高度和宽度并不包括边框 
(border)的部分。这些尺寸不能为度,否则会造成 
BadValue 的错误结果。 
border_width 设定视窗边框(border)的宽度,其单位为图素(pixels) 
,也就是指定其边框的宽度是几个图素(pixels)。 
depth 设定新视窗的颜色深度(depth),若指定 depth 的值为 
CopyFromParent,则深度(depth)将会从父视窗(parent 
window)取得。 
class 指定视窗的类别(class)。你可以指定为 InputOutput 
,InputOnly 或 CopyFromParent 其中一种。若指定为 
CopyFromParent 则表示将由父视窗(parent window)取 
得。 
visual 设定视觉(visual)的种类。设为 CopyFromParent 则会 
取自父视窗。 
valuemask 用以设定在 attributes 参数设定了那些视窗属性 
(attribut)的遮罩(mask)。在这个遮罩(mask),每一 
bit 代表着一项属性(attribut),我们以 OR 位元运算 
,将代表各项属性的遮罩(mask)组合起来。若为零,则 
会乎略 attributes 参数。 
attributes 这是一个存放视窗属性(attribut)的结构(structure) 
,配合设定正确的遮罩(mask),用以设定视窗的属性。 




-------------------------------------------------------------------------------- 


/* Values */ 


typedef struct { 
Pixmap background_pixmap; 
unsigned long background_pixel; 
Pixmap border_pixmap; 
unsigned long border_pixel; 
int bit_gravity; 
int win_gravity; 
int backing__store; 
unsigned long backing_planes; 
unsigned long backing_pixel; 
Bool save_under; 
long event_mask; 
long do_not_propagate_mask; 
Bool override_redirect; 
long event_mask; 
long do_not_propagate_mask; 
Bool override_redirect; 
Colormap colormap; 
Cursor cursor; 
} XSetWindowAttributes; 


/* Window attribute value mask bits */ 


#define CWBackPixmap (1L<<0) 
#define CWBackPixel (1L<<1) 
#define CWBorderPixmap (1L<<2) 
#define CWBorderPixel (1L<<3) 
#define CWBitGravity (1L<<4) 
#define CWWinGravity (1L<<5) 
#define CWBackingStore (1L<<6) 
#define CWBackingPlanes (1L<<7) 
#define CWBackingPixel (1L<<8) 
#define CWOverrideRedirect (1L<<9) 
#define CWSaveUnder (1L<<10) 
#define CWEventMask (1L<<11) 
#define CWDontPropagate (1L<<12) 
#define CWColormap (1L<<13) 
#define CWCursor (1L<<14) 




-------------------------------------------------------------------------------- 
使用 XCreateWindow 可以建立任一视窗的子视窗(child window)。但在 程式一开始时,还没有建立任何的视窗,因此也就无法建立任何视窗的 子视窗。我们使用根视窗(root window)做为父视窗(parent window)建 立其子视窗(child window),以根视窗(root window)的子视窗(child window)做为我们程式最上阶层的视窗。 


每个都有各种的属性,我们设定其属性即会改变视窗表现出来的行为。 例如,深度(depth),边框(border)的宽度等等的。Xlib 提供 XChangeWindowAttributes 这个函数,设定任一 window 大部分的 Attributes(属性)。  
-------------------------------------------------------------------------------- 


XChangeWindowAttributes(display, w, valuemask, attributes) 
Display *display; 
Window w; 
unsigned long valuemask; 
XSetWindowAttributes *attributes; 


w 指定设定的 window。 
valuemask 指定在 attributes 这个参数,设定了那些 window 
attributes。这个 mask 也是用 OR 运算,将所有的属性的 mask 
(遮罩)值组合起来。 
attributes 指定储存属性设定值的 XSetWindowAttributes 结构。 




-------------------------------------------------------------------------------- 


4. 和视窗管理程式(Window Manager)沟通 
在 X Window 环境下的程式,由於其视窗外观并不是直接由 X Server 处理,代而之的是交由 Window Manager 处理。因此,我们的程式,必 需和 Window Manager 沟通合作,才能得到合适的视窗外观并和其它视 窗和平共处。Window Manager 只会处理 top window,其它的非 top level 的 window 并不在其处理的围。 
和 Window Manager 沟通的方式,是透过传送 Hint 的方式。因为 Window Manager 对 client 对其视窗的设定,并不一定要完全接受, 只是做为参考而已,所以我们称之为 Hint。除了这些 Hint 之外, 我们还可以透过 Window Manager ,操作 top level 的视窗,使之 缩成 icon ,设定视窗 title 的名称等等的。 






-------------------------------------------------------------------------------- 


XStoreName(display, w, window_name) 
Display *display; 
Window w; 
char *window_name; 


window_name 指定视窗名称,此名称会被显示在 title 上。 




-------------------------------------------------------------------------------- 
此函数用来设定视窗的名称,这个名称将会被显示在该视窗的 title 处。title 就像文章的标题一样,用来指明此一视窗,让使用者可以 依据 title 辨别不同的视窗。 




-------------------------------------------------------------------------------- 


XSetIconName(display, w, icon_name) 
Display *display; 
Window w; 
char *icon_name; 


icon_name 指定 icon 的名称,此名称在视窗缩成 icon 时显示 
出来。 




-------------------------------------------------------------------------------- 
XSetIconName 用来设定 icon 的名称。有时侯,当我们在萤幕上同时 开太多个视窗时,整个画面可能会显的很杂乱。因此,我们会借由把一 些暂时用不到的视窗缩小成一小图示,也就是 icon,以减少所占的空 间,清理一下桌面。等到要用到该视窗时,才将之放大回原来的大小。 而 XSetIconName 所设定的名称,则会在视窗变成 icon 时显示出来。  




-------------------------------------------------------------------------------- 


void XSetWMNormalHints(display, w, hints) 
Display *display; 
Window w; 
XSizeHints *hints; 


hints 指定视窗在一般状况下的 size hints。 




-------------------------------------------------------------------------------- 


#define USPosition(1L << 0) 
#define USSize(1L << 1) 
#define PPosition(1L << 2) 
#define PSize (1L << 3) 
#define PMinSize (1L << 4) 
#define PMaxSize (1L << 5) 
#define PResizeInc(1L << 6) 
#define PAspect(1L << 7) 
#define PBaseSize (1L << 8) 
#define PWinGravity(1L << 9) 
#define PAllHints 


typedef struct { 
long flags; 
int x, y; 
int width, height; 
int min_width, min_height; 
int max_width, max_height; 
int width_inc, height_inc; 
struct { 
int x; 
int y; 
} min_aspect, max_aspect; 
int base_width, base_height; 
int win_gravity; 
} XSizeHints; 




-------------------------------------------------------------------------------- 


XSizeHints *XAllocSizeHints() 




-------------------------------------------------------------------------------- 


XFree(data) 
void *data; 


data 要释放掉的记忆。 




-------------------------------------------------------------------------------- 
XSetWMNormalHints 用以设定有关视窗大小的和缩放的限制等等的。 由於 XSizeHints 的内容以後可能会有所增长,所以必需透动态记忆 的配,以避免以後因为改版之後,而造成和新版的 Xlib 不和的 情形。Xlib 提供 XAllocSizeHints 配置一个 XSizeHints 的 structure。所有将由 Xlib 所提供的函数所配的记忆,都要使用 XFree 释放。 


5. 显示视窗 
视窗建好之後, 仍然不会出现在萤幕上, 而是要经过一道 mapping 的手序。 视窗都已经设定好了,再来正式显示在显示器上就很容易了。这个步骤,mapping ,只要呼叫一个函数就 ok 了!!  
-------------------------------------------------------------------------------- 


XMapWindow(display, w) 
Display *display; 
Window w; 


w 要显示的视窗。 




-------------------------------------------------------------------------------- 


XFlush(display) 
Display *display; 




-------------------------------------------------------------------------------- 
嗯!! 就这麽简单。但,当你程式执行到这一个步骤时,也许你会发现, 显示器上跟本就没有视窗出现。这是因为 Xlib 设有 buffer,将所有 要传送的讯息都先存在一个 buffer 内,待 buffer 满了之後才会将之 一起送出,以减少网路的流量,加过程式执行的速度。然而,我们无法 知道什麽时侯才会满,我们总不能一直等下去,等到程式结束了,也许 画面都还没出现。为了解决这个问题,Xlib 提供 XFlush 这个函数, 可以强迫 Xlib 立即将 buffer 内,现有的全部讯息都传送出去,以让 X Server 立即可以做处理。 


6. 关闭(destroy)视窗 


-------------------------------------------------------------------------------- 


XDestroy(display, w) 
Display *display; 
Window w; 


w 要关闭的视窗。 




-------------------------------------------------------------------------------- 


7. 关闭 display 


-------------------------------------------------------------------------------- 


XCloseDisplay(display); 
Display display; 




-------------------------------------------------------------------------------- 


8. 例 


-------------------------------------------------------------------------------- 


/* --- Xtest.c --- */ 


#include  
#include  
#include  
#include  


main() { 
Display *display; 
Window window; 
XSetWindowAttributes attr; 
XSizeHints *sz; 


/* 建立一个 display 的 connection */ 
display = XOpenDisplay("0:0"); 


/* 建立和设定 window 的属性 */ 
window = XCreateWindow(display, XDefaultRootWindow(display), 
100, 100, 300, 300, 2, XDefaultDepth(display, 0), 
InputOutput, CopyFromParent, 0, &attr); 


/* 和 Window Manager 进行沟通 */ 
XStoreName(display, window, "hello!! world!!"); 
sz = XAllocSizeHints(); 
sz->x = 100; 
sz->y = 100; 
sz->width = 300; 
sz->height = 300; 
sz->flags = USPosition | USSize; 
XSetNormalHints(display, window, sz); 


/* Mapping Window  正式影射到显示器画面*/ 
printf("Map window\n"); 
XMapWindow(display, window); 
getchar(); /* 至此,视窗已执行 Map 的动作了,但 
   显示器上,却可能看不到。*/ 


printf("XFlush\n"); 
XFlush(display); 
getchar(); /* 这,你应该就看到显示器上的变化了 */ 


/* 
   ................. 
   .... 程式处理部分 .. 
   .................... 
*/ 


/* 关闭视窗 */ 
printf("Destory Window\n"); 
XDestroyWindow(display, window); 
getchar(); 


printf("XFlush\n"); 
XFlush(display); 
getchar(); 


/* 关闭 display */ 
printf("close display\n"); 
XCloseDisplay(display); 
getchar(); 





-------------------------------------------------------------------------------- 


gcc -o Xtest Xtest.c -L/usr/X11R6/lib -lX11 




-------------------------------------------------------------------------------- 
上面是一个简单的例程式和 compile 的方法。 
(http://www.fanqiang.com)     进入【UNIX论坛】
相关文章
X Window 程式设计入门--第六章 Inter-Client Communication (2001-06-02 18:08:00)
X Window 程式设计入门--第五章 Window (2001-06-02 00:16:10)
X Window 程式设计入门--第四章 Event (2001-06-01 21:04:00)
X Window 程式设计入门--第三章 绘图(Graphic) (2001-06-01 20:10:00)
X Window 程式设计入门--第二章 X Programming 的第一步 (2001-06-01 19:00:01)
X Window 程式设计入门--第一章 什麽是 X Window (2001-06-01 18:08:00)
X Window 程式设计入门 (2001-06-01 17:04:00)