X Window 程式設計入門--第二章 X Programming 的第一步



http://cnpa.yzu.edu.tw/~thinker 作者:李圭烽 (Thinker; [email protected]) (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)
發佈了2 篇原創文章 · 獲贊 3 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章