[ 永遠的UNIX::UNIX技術資料的寶庫 ]   GB | BIG5

首頁 > 編程技術 > 其它 > 正文
X Window 程式設計入門--第二章 X Programming 的第一步
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)
 

★  樊強制作 歡迎分享  ★