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)