轉自:http://blog.csdn.net/linuxheik/article/details/7659090
File: x11_test.cxx
#include <X11/Xlib.h>
每一個Xlib 程式都必須包含這個頭檔案
#include <stdio.h>
int main(void) {
Display *display = XopenDisplay(NULL);
首先打開與server 的連接配接。在你的程式可以使用display 之前,必須先建立一個和X server 的連接配接。這個連接配接建立以後,就可以使用Xlib 的函數或宏定義來獲得display 的資訊了。
參數為hardware display name,當設為NULL時,為預設的DISPLAY環境變量。這個函數傳回一個指向Display類型的結構的指針,表明已與X server建立了連接配接,并且包含了這個X serer的所有資訊。
這樣我們就可以使用display之上的所有視窗了。
int screen = DefaultScreen(display);
得到display打開之後的視窗号。本例中,得到。我了解是:尚未建立視窗,是以視窗号為。不知道對不對。
DefaultScreen是個宏,對應的函數為XDefaultScreen。兩者作用相同。
int width = DisplayWidth(display, screen)/;
int height = DisplayHeight(display, screen)/;
函數DisplayWidth得到視窗的寬,DisplayHeight得到視窗的高。視窗雖然沒有建立,但是有關視窗的預設資訊在display打開之時就已經從X server處獲得了。本例,獲得預設的尺寸為*,就是顯示器的尺寸。
int black_pixel = BlackPixel(display, screen);
int white_pixel = WhitePixel(display, screen);
X使用一種很複雜的顔色模型,每個顔色用一個整數表示。但是當機器不同,甚至程式不同時,一個整數不一定就代表固定的某個顔色。X能夠保證的顔色隻有兩個:黑和白。用 BlackPixel和 WhitePixel可以得到這兩個顔色的值。
Window win = XCreateSimpleWindow(display, RootWindow(display, screen), , , width, height, , black_pixel, white_pixel);
建立視窗的最普遍的函數是XCreateWindow和XCreateSimpleWindow(我目前還沒有研究兩者具體差别)。
Window XcreateSimpleWindow(
Display *display,
Window parent,
int x,
int y,
unsigned int width,
unsigned int height,
unsigned int border_width,
unsigned long border,
unsigned long background
);
其中, RootWindow函數産生的是我們建立的視窗的父視窗(我還不太明白到底是哪個);x, y為建立的視窗的起始坐标;width, height為視窗的尺寸;border_width為視窗邊框的像素數;border為邊框的顔色;background為視窗的背景色。
函數傳回建立的視窗的ID,并使得X server産生一個CreateNotify事件。
XSelectInput(display, win, ExposureMask|StructureNotifyMask);
我們知道,X是一個伺服器-用戶端的結構。由伺服器向用戶端發送事件資訊,讓用戶端知道發生了什麼事情,然後用戶端告訴伺服器它感興趣的是什麼事情,也就是說,用戶端會對那些事件産生反應。用XSelectInput這個函數,就是告訴伺服器,這個視窗會對那些消息,也就是事件有響應。這裡講的“事件”,比如又建立,畫,改變大小等等。
XselectInput(
Display *display,
Window w,
long event_mask
);
其中,w為希望對事件作出響應的視窗;event_mask為事件号。希望視窗會有那些響應,就在參數中加上這個事件對應的名字。
XMapWindow(display, win);
用XCreateSimpleWindow建立視窗之後,視窗并不能顯示出來,需要調用這個函數來畫視窗讓它顯示。如果這個視窗有父視窗,那麼在所有父視窗沒有畫出來之前,這個視窗即使用了這個函數,也是不能顯示出來的。必須等所有父視窗都顯示了,這個視窗才能畫。(不太明白這一步)
(沒看明白在什麼情況下)X server産生一個MapNotify事件。
GC gc = XCreateGC(display, win, , NULL);
X并不能記住要畫的視窗的屬性,那麼每次要畫視窗時都要把它的全部屬性傳給server,為了避免每次都傳太多參數,X使用了一個結構Graphics Context,簡稱GC,存儲圖形操作的大部分屬性,比如線的寬度,風格,背景色等等。
While()
{
XEvent event = {};
XNextEvent(display, &event);
}
接下來就是進入事件循環了。獲得事件,處理或丢棄。上面講到,調用XMapWindow函數後,X server會發出一個MapNotify事件給用戶端,這時用戶端就已經有相應操作了,就是畫視窗,是以事件循環裡并沒有寫出來。
Return ;
}
至此,整個程式結束。
編譯:g++ -lX11 -o x11_test x11_test.cxx
運作,螢幕上就顯示一個最簡單的視窗了。
如果我們想看看MapNotify事件到底是怎麼回事,就這樣寫:
while()
{
XEvent event;
XNextEvent(display, &event);
if(event.type == MapNotify) break;
}
//sleep(3);
return ;
運作發現,視窗一閃而過。也就是說,用戶端一接收到這個事件就顯示視窗,一顯示視窗就break了。把注釋拿掉,則顯示視窗秒鐘後才消失。
這裡看到,接收到的事件由XNextEvent函數從消息隊列裡獲得,把事件放到event.type裡并從隊列裡删除該消息。當隊列為空也就是沒有下一個事件被接收時,XNextEvent“flushes the output buffer”,也就是視窗最終被顯示,并且程式就一直停留在XNextEvent裡直到有下一個事件,除非有跳出循環的語句。
繼續改程式:
while()
{
XEvent event;
XNextEvent(display, &event);
if(event.type == MapNotify) break;
}
XDrawLine(display, win, gc, , , , );
//XFlush(display);
sleep();
return ;
跳出循環後,用XDrawLine畫一條線。這時運作程式,視窗上并沒有出現直線。因為視窗的資訊改變了,就需要XFlush函數來flush一下,讓視窗重畫。而之前之是以沒有XFlush函數,是因為XNextEvent函數隐式地調用XFlush了,而且調用後并沒有改變視窗資訊。
繼續改,添加事件:
XSelectInput(display, win, ExposureMask|KeyPressMask|StructureNotifyMask);
while()
{
XEvent event = {};
XNextEvent(display, &event);
switch(event.type)
{
case ConfigureNotify:
{
width = event.xconfigure.width;
height = event.xconfigure.height;
break;
}
case Expose:
{
XSetForeground(display, gc, WhitePixel(display, screen));
XFillRectangle(display, win, gc, , , width, height);
XSetForeground(display, gc, BlackPixel(display, screen));
XDrawString(display, win, gc, width/, height/, "XWindow", );
break;
}
case KeyPress:
{
if(event.xkey.keycode == XKeysymToKeycode(display, XK_Escape))
{
XFreeGC(display, gc);
XCloseDisplay(display);
return ;
}
}
default: break;
}
}
return ;
事件類型StructureNotifyMask對應事件ConfigureNotify,即改變視窗狀态,比如尺寸,位置等;ExposureMask對應事件Expose(我不知道怎麼解釋這個事件),本例中是在這裡設定視窗顔色,畫字元串并設定字元串顔色;KeyPressMask對應KeyPress,即鍵盤響應,本例是當Escape鍵按下時,退出視窗。退出視窗時,需要釋放或者說銷毀GC,最開始曾打開display,在這裡需要關閉和X server的連接配接,于是也就銷毀了相關資源,關閉了視窗。
在這種循環的寫法中,退出switch,并沒有退出整個循環,XNextEvent仍然在顯示視窗,是以不需要我們自己調用XFlush。
有這樣一個網址:http://tronche.com/gui/x/xlib-tutorial/