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

首頁 > 編程技術 > 其它 > 正文
X Window 程式設計入門--第四章 Event
http://cnpa.yzu.edu.tw/~thinker 作者:李圭烽 (Thinker; Thinker.bbs@bbs.yzu.edu.tw) (2001-06-01 21:04:00)
Index:
Event Types and Event Masks 
Events Propagation 
Event Handling 
Events 
MapNotify 
UnmapNotify 
Expose 
ButtonPress, ButtonRelease, KeyPress, KeyRelease, MotionNotify 
CreateNotify 
DestroyNotify 
ResizeRequest 
FocusIn, FocusOut 
例 

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

X Window 的 client 應用程式,透過和 X Server 之間的 connection 和 Server 進行通訊。client 應用程式會通過 Xlib,向 X Server 發出 request (要求)。而有時侯,X Server 也會產生 Event (事件), 需要經由 connection 通知 client 程式。這些 Event 可能是因為使用 者按下按鍵或是移動滑鼠,也可能是因為 client 發出的 request 而使 得 X Server 產生的。X Server 可以經由產生 Event,通知 client 所 發生的所有事件。

Event Types and Event Masks
由 Server 傳給 client 的 Event,依不同的 Event,各使用不同的 structure 表示。而在不同 Event 之間,還是有其相同存在。不同 Event 使用的 structure 有一部分是相同的,每個 sturcture 最前面 相同的部分可以使用 XAnyEvent 這個 structure 表示。 
--------------------------------------------------------------------------------

typedef struct {
int type;
unsigned long serial;
Bool send_event;
Display *display;
Window window;
} XAnyEvent;


--------------------------------------------------------------------------------
這個 sturcture 收集各個 Event 相同的部分,包括 type。透過 type ,我可以辨識出各個不同的 Event,以做對應的處理。

Event 可以 _XEvent 這個 union type 表示: 
--------------------------------------------------------------------------------

typedef union _XEvent {
int type;
XAnyEvent xany;
XKeyEvent xkey;
XButtonEvent xbutton;
XMotionEvent xmotion;
XCrossingEvent xcrossing;
XFocusChangeEvent xfocus;
XExposeEvent xexpose;
XGraphicsExposeEvent xgraphicsexpose;
XNoExposeEvent xnoexpose;
XVisibilityEvent xvisibility;
XCreateWindowEvent xcreatewindow;
XDestroyWindowEvent xdestroywindow;
XUnmapEvent xunmap;
XMapEvent xmap;
XMapRequestEvent xmaprequest;
XReparentEvent xreparent;
XConfigureEvent xconfigure;
XGravityEvent xgravity;
XResizeRequestEvent xresizerequest;
XConfigureeRequestEvent xconfigurerequest;
XCirculateEvent xcirculate;  
XCirculateRequestEvent xcirculaterequest;
XPropertyEvent xproperty;
XSelectionClearEvent xselectionclear;
XSelectionRequestEvent xselectionrequest;
XSelectionEvent xselection;
XColormapEvent xcolormap;
XClientMessageEvent xclient;
XMappingEvent xmapping;
XErrorEvent xerror;
XKeymapEvent xkeymap;
long pad[24];
} XEvent;


--------------------------------------------------------------------------------
根據 type 這個欄位, 我們可以分辨出不同的 Event。依據不同的 Event, 我就可以透過對映該 Event 的欄位, 取得該 Event 的相關 訊息和資料。

下面是用來標示各種 Event type 的 mask: 
--------------------------------------------------------------------------------

NoEventMask
KeyPressMask
KeyReleaseMask
ButtonPressMask
ButtonReleaseMask
EnterWindowMask
LeaveWindowMask
PointerMotionMask
PointerMotionHintMask
Button1MotionMask
Button2MotionMask
Button3MotionMask
Button4MotionMask
Button5MotionMask
ButtonMotionMask
KeymapStateMask
ExposureMask
VisibilityChangeMask
StructureNotifyMask
ResizeRedirectMask
SubstructureNotifyMask
SubstructureRedirectMask
FocusChangeMask
PropertyChangeMask
ColormapChangeMask
OwnerGrabButtonMask


--------------------------------------------------------------------------------
使用這些 mask 檢查 _XEvent 中表示 Event type 的 type 欄位, 可以得知處理之 Event 的 type。

下表是不同的 Event type, 在 _XEvent 中所該對映的欄位。多個 type 可能對映到同一個欄位。 
Event Mask Event Type Structure Generic Structure 

--------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------
 
ButtonMotionMask MotionNotify XPointerMoveEvent XMotionEvent 
Button1MotionMask 
Button2MotionMask 
Button3MotionMask 
Button4MotionMask 
Button5MotionMask 
ButtonPressMask ButtonPress XButtonPressedEvent XButtonEvent 
ButtonReleaseMask ButtonRelease XButtonReleaseEvent XButtonEvent 
ColormapChangeMask ColormapNotify XColormapEvent 
EnterWindowMask EnterNotify XEnterWindowEvent XCrossingEvent 
LeaveWindowMask LeaveNotify XLeaveWindowEvent XCrossingEvent 
ExposureMask Expose XExposeEvent 
GCGraphicsExposures in GC GraphicsExpose XGraphicsExposeEvent 
 NoExpose XNoExposeEvent 
FocusChangeMask FocusIn XFocusInEvent XFocusChangeEvent 
 FocusOut XFocusOutEvent XFocusChangeEvent 
KeymapStateMask KeymapNotify XKeymapEvent 
KeyPressMask KeyPress XKeyPressEvent XKeyEvent 
KeyReleaseMask KeyRelease XKeyReleaseEvent XKeyEvent 
OwnerGrabButtonMask N.A. N.A. 
PointerMotionMask MotionNotify XPointerMovedEvent XMotionEvent 
PointerMotionHintMask N.A. N.A. 
PropertyChangeMask PropertyNotify XPropertyEvent 
ResizeRedirectMask ResizeRequest XResizeRequestEvent 
StructureNotifyMask CirculateNotify XCirculateEvent 
 ConfigureNotify XConfigureEvent 
 DestroyNotify XDestroyWindowEvent 
 GravityNotify XGravityEvent 
 MapNotify XMapEvent 
 ReparentNotify XReparentEvent 
 UnmapNotify XUnmapEvent 
SubstructureNotifyMask CirculateNotify XCirculateEvent 
 ConfigureNotify XConfigureNotify 
 CreateNotify XCreateWindowEvent 
 DestroyNotify XDestroyWindowEvent 
 GravityNotify  
 MapNotify XMapEvent 
 ReparentNotify XReparentEvent 
 UnmapNotify XUnmapEvent 
SubstructureRedirectMask CirculateRequest XCirculateRequestEvent 
 ConfigureRequest XConfigureRequestEvent 
 MapRequest XMapRequestEvent 
N.A. ClientMessage XClientMessageEvent 
N.A. MappingNotify XMappingEvent 
N.A. SelectionClear XSelectionClearEvent 
N.A. SelectionNotify XSelectionEvent 
N.A. SelectionRequest XSelectionRequestEvent 
VisibilityChangeMask VisibilityNotify XVisibilityEvent 
 

第一欄是代表的 Event Mask, 第二欄是 Event type, 第三欄是在 _XEvent 中所對映之 structure type。當有兩個以上的 Event type 在 _XEvent 中共用一個 structure type, 則該 structure type 會出現在第四欄。表中的 N.A. 表示該欄位在該列不具任何意義。

Events Propagation 
當視窗有事件發生時,對相對應的 Event 卻可能不是由該視窗產生, 由其它的視窗產生。在我們設定視窗屬性時,有一個 do_not_propagate_mask 欄位。do_not_propagate_mask 用來選擇那 些 event 不能往先視窗(ancestor window)傳遞。一般來說 KeyPress KeyRelease ButtonPress ButtonRelease PointerMotion Button1Motion - Button2Motion 這些 event 發生之後,如果在 發生的視窗要求知道這些訊息,則這 evnet 會往父視窗(parent window)傳遞(propagation)。如果父視窗也不要,就會再往父視窗 的父視窗傳遞,一直到遇到其中的一個先視窗(ancester window) 有 client 向 其要求這項 evnet 為止,這時 Event 就會在這個祖先視窗產生。 我們稱這個祖先視窗為 Event Window,而發生 event 的視窗我們 稱之為 Source Window。如果在傳遞 event 的過程中,若有任何 一個傳遞經過的視窗,在該視窗的 do_not_propagate_mask 設定 設 evnet,則傳遞將會停止下來,不再繼續往先視窗傳遞。

Event Handling
X Server 會針對各個視窗產生各種的 Event, 但是對於 client 程 式而言, 並不是所有的 Event 都是需要的。而大量的訊息傳送, 會 使的整個系統的效率降低, 所以我們並不希望 X Server 對 client 送出所有的 Evnet。因此在 X 的設計上, X Server 讓 client 可 以選擇每個視窗所需要的 Event, 只傳送需要的 Event 給 client 。在 client 程式端, 由 X Server 送過來的 Event 都會存在 Event Queue 等待程式讀取和處理。程式可以透過 XLib 所提供的 函數, 讀取 Event Queue 內的 Event 並取得關於 Event Queue 的 資訊。當 request 產生時, XLib 並不會馬上將之傳到 X Server。 因為小量而多次的資料傳送, 對於網路的效率是一個很大的傷害。 為了提高傳送的效率, XLib 會將產生的 Request 先暫存在 output buffer, 到達某一程度的量時, 再一口氣將之傳送到 X Server。 然而這個使的 X Server 的反應延遲, 我們可能希望 X Server 立 即做出反應和處理。諸如此類, 我們可以要求 XLib 立即將 output buffer 的 request 全部傳送給 X Server,讓 X Server 可以即 時收到 request 並做出反應。

設定視窗需要產生那些 Event 的方法有很多種, 我們可以在呼叫 XCreateWindow 和 XChangeWindowAttributes 時, 設定 XSetWindowAttributes 的 event_mask 欄位, 將之作為 XCreateWindow 和 XChangeWindowAttributes 的參數。另外就是透 過 XSelectInput這個函數來選擇。 
--------------------------------------------------------------------------------

XSelectInput(display, w, event_mask)
Display *display;
Window w;
long event_mask;

w 指定選擇事件的視窗
event_mask 指定 event mask


--------------------------------------------------------------------------------
XSelectInput 可以為你的 client 選取任何視窗上的 Event, 只要該視窗有你需要的 Event 發生, X Server 就會送 Event 給 client。而 X Server 會為任何向他登記需要該 Event 的 client 發送 Event。

在選擇好所需要的 Event 之後, 我們就可以開始接受 X Server 送來的 Event。一個 client 程式, 可能同時會使用到多個 視窗, 但所有視窗的 Event 傳送到 client 後, 都會存在 Event Queue。雖然各個視窗的 Event 會因而混在一起, 但是我們可以 透過 XEvent 這個 union type 的 XAnyEvent 結構的 window 欄位區分出該 Event 所屬的視窗。

透過 XNextEvent, 可以從 Event Queue 取出下一個從 X Server 送來的 Event, 並將之從 Event Queue 移除。 
--------------------------------------------------------------------------------

XNextEvent(display, event_return)
Display *display;
XEvent *event_return;

event_return 傳回 event queue 的下一個 event


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


XPeekEvent 和 XNextEvent 的功能大致相同, 只差於 XPeekEvent 不會將傳回的 Event 從 Event Queue 移除。 
--------------------------------------------------------------------------------

XPeekEvent(display, event_return)
Display *display;
XEvent *event_return;

event_return 傳回 event queue 的下一個 event


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


XFlush 會將暫存在 output buffer 的所有 request 立即傳送出 去。 
--------------------------------------------------------------------------------

XFlush(display)
Display *display;


--------------------------------------------------------------------------------
一般程式中並不會使用到這個函數, 因為 XPending, XNextEvent 和 XWindowEvent 會自動 flush output buffer。

XSync 會像 XFlush 一樣, 將 output buffer 所有的 request 傳送出去, 並且還會等待所有的 request 都被 X Server 處理。 
--------------------------------------------------------------------------------

XSync(display, discard)
Display *display;
Bool discard;

discard 指示 XSync 是否要放棄現在 Event Queue
的所有 Event。


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


當 Event 源源不斷的從 X Server 傳來時, Event Queue 可能 放滿了一些尚未被取出處理的 Event。XEventsQueued 會傳回 Event Queue , 目前所存放的 Event 數量。 
--------------------------------------------------------------------------------

int XEventsQueued(display, mode)
Display *display;
int mode;

mode 指定設定模式。你可以指定 QueuedAlready,
QueuedAfterFlush, 或 QueuedAfterReading。


--------------------------------------------------------------------------------
XEventsQueued 可以指定三種模式: 
QueuedAlready: 
傳回目前 Event Queue 的 evnet數量。 
QueuedAfterFlush: 
如果 Event Queue 不是空的, 則傳回 Event Queue 的 Event 數量。若是空的, 則先 flush output buffer, 並試著從 connection 讀出更 多的 Event, 然後傳回讀到的 Event 數量。 
QueuedAfterReading: 
如果 Event Queue 不是空的, 則傳 回 Event Queue 的 Event 數量。反之, 則試著從 connection 讀出所有的 Event, 但是並不 flush output buffer, 然後傳回所讀到的 Event 數量。 

傳回 Event Queue , 第一個和指定視窗和 evnet mask 符 合之 Event。 
--------------------------------------------------------------------------------

XWindowEvent(display, w, event_mask, event_return)
Display *display;
Window w;
long event_mask;
XEvent *event_return;

w 指定視窗
event_mask 指定 event mask
event_return 傳回符合的 event structure


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


傳回 Event Queue , 第一個符合指定之 evnet mask 的 Event。 
--------------------------------------------------------------------------------

XMaskEvent(display, event_mask, event_return)
Display *display;
long event_mask;
XEvent *event_return;

event_mask 指定要求之 event mask
event_return 傳回符合條件的 event structure


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


Events
MapNotify
當視窗從未映射(unmapped)的狀態變為映射(mapped)狀態時, 會發生 MapNotify Event,並傳送到需要該 Event 的 client。 而使視窗從未映射的狀態轉變成映射狀態進而使 X Server 產生 MapNotify Event 的原因,可能是因為 client 呼叫 XMapWindow XMapRaised XMapSubwindows 或 XReparentWindow 等 Xlib 函數。 而需要視窗 MapNotify Event 的 client,必需設定 event mask 的 StructureNotifyMask bit 或是 SubstructureNotifyMask, 如此 X Server 才會將產生的 MapNotify Event 傳送給 client。SubstructureNotifyMask 是設在父視窗(parent window) 的,一旦 client 在視窗的 event mask 設定 SubstructureNotifyMask bit,則只要有任何的子視窗(child window) 被映射(mapped),就會產生 MapNotify。下面是 MapNotify Event 的結構: 
--------------------------------------------------------------------------------

typedef struct {
int type;
unsigned long serial;
Bool send_event; /* true 如果是以 SendEvent 產生 */
Display *display;
Window event;
Window window;
Bool override_redirect;
} XMapEvent;


--------------------------------------------------------------------------------
event 所存的 Window ID 要看 UnmapNotify Event 是因為設定 StructureNotifyMask 或是 SbustructureNotifyMask 而產生。 如果是因為 StructureNotifyMask ,則 event 的內容是變成 未映射(unmapped) 視窗的 Window ID,反之若是因為 SubstructureNotifyMask 而產生的,則 event 欄位被設定為被 變成未映射之視窗的父視窗(parent window) 的 Window ID。 window 則是被映射的視窗的 Window ID。

UnmapNotify
這是和 MapNotify 相反的情況。當視窗從映射(mapped)狀態轉變 為未映射(unmapped)狀態時,X Server 會產生 UnmapNotify Evnet ,並傳送給需要該 Evnet 的 client。client 若需要接收 UnmapNotify Event,則必需在 event mask 設定 StructureNotifyMask bit 或 SubstructureNotifyMask bit。SubstructureNotifyMask 是 設在父視窗(parent window),當 client 在視窗的 event mask 設定 SubstructureNotifyMask bit 時,任何的子視窗(child window)變成 未映射(unmapped)時,就會產生 UnmapNotify。這個 event type 的結構(structure) 如下所示: 
--------------------------------------------------------------------------------

typedef struct {
int type;
unsigned long serial;
Bool send_event; /* true 如果是以 SendEvent 產生 */
Display *display;
Window event;
Window window;
Bool from_configure;
} XUnmapEvent;


--------------------------------------------------------------------------------
event 所存的 Window ID 要看 UnmapNotify Event 是因為設定 StructureNotifyMask 或是 SbustructureNotifyMask 而產生。 如果是因為 StructureNotifyMask ,則 event 的內容是變成 未映射(unmapped) 視窗的 Window ID,反之若是因為 SubstructureNotifyMask 而產生的,則 event 欄位被設定為被 變成未映射之視窗的父視窗(parent window) 的 Window ID。 window 則是被映射的視窗的 Window ID。

Expose
Expose 產生的時機是在,當視窗的某一個區塊的資料己經 遺失了,而且該區域也看的見時,這時 X Server 必需通知那 些想要得知這個訊息的 client,以便這些 client 補上這塊被 遺失的資料或做其它合適處置。當我們在同一個畫面上同時開 上兩個以上的視窗時,往往會覺的畫面不夠大而使的視窗相互 重疊。在重疊的部分,下面的視窗中,也許原本在該區有顯示 什麼資料,但現在被上面的視窗蓋掉了。經過我們的操作,經 過一段時間,原本被蓋住的部分又會重新被顯示出來。如我把 在上面的視窗關掉,其它視窗被該視窗蓋住的部分又會顯示出 來。或是我們把某個視窗顯小成小圖示(icon)那麼其它視窗被 其蓋住的部分也會再度顯示出來。當這些被上層蓋住的區塊被 再度裸露出來時,X Server 必需為這些區塊重新畫上在下層 視窗的資料,以使產生上層視窗被移掉,而下層視窗浮出來 的效果,但往往 X Server 並沒有記錄下這些被遮蓋區塊的 內容。這時 X Server 就需要 client 的協助,重新把這個失 落的環節補上。視窗被重新裸露出來時,被裸露出來的區塊往往 並不是規則的四方形。被裸露出來的部分可能成梯狀或某種由 四方形方塊相疊而形成的圖形。每個 Expose Event 都包含著 一個在視窗內被裸露出來的方形區塊的位置和大小,X Server 會為每個該被重新補上的方形區塊產生一個 Expose Event。 而 X Server 會把同一次裸露事件所產生的 Expose Evnet 一 起且連續的送出。要接收 Expose Event 的 client 必需在 event mask 設定 ExposureMask。Expose Event 的結構如下: 
--------------------------------------------------------------------------------

typedef struct {
int type;
unsigned long serial;
Bool send_event;
Display *display;
Window window;
int x, y;
int width, height;
int count;
} XExposeEvent;


--------------------------------------------------------------------------------
window 是被裸露出來的視窗的 Window ID。x 和 y 則是該 被重繪的方形區塊的右上角座標,width 和 height 則是該 區塊的寬度和高度。而 count 若為 0,則表示這個 Expose Event 是這次視窗被裸所產生的最後一個 Expose Event。 若不為 0,則表示後面至還有這麼多個 Expose Event 在等 著,而且還可能比 count 所指示的數量多。

ButtonPress
ButtonRelease
KeyPress
KeyRelease
MotionNotify
X Window 提供 KeyPress 和 KeyRelease Event。當使用者 按下鍵盤上的按鍵時,X Server 會產生 KeyPress Event 給登記需要按鍵按下去的訊息的 client。當使用者放開按 鍵時,X Server 又會產生 KeyRelease Evnet 給登記需要 KeyRelease Event 這項訊息的 client。X Server 會對鍵盤 上所有的按鍵產生這兩種 Event。ButtonPress 和 ButtonRelease 則是在滑鼠(mouse) 被按下和放開時產生。 client 要接收 KeyPress KeyRelease ButtonPress ButtonRelease 等 Event,需要在 event mask 設定 KeyPressMask KeyReleaseMask ButtonPressMask ButtonReleaseMask 對等的 bit。

當滑鼠在視窗內移動時,會產生一連串的 MotionNotify Event。滑鼠不斷的移動而 MotionNotify 也不斷的產生, 難道你的滑鼠每移動一點 X Server 就產生一個 MotionNotify 嗎? 當然不是這麼張。X Server 並不包証多遠的距離 產生一個 MotionNotify Event,但包証至少在移動的起 始點和終點各會產生一次 MotionNotify Event。 在 event mask 設定 Button1MotionMask - Button5MotionMask,ButtonMotionMask PointerMotionMask 等,可以使 X Server 傳送 MotionNotify Event 給 client。 
--------------------------------------------------------------------------------

Button1MotionMask - Button5MotionMask 
當被指定的滑鼠按鈕(button)被按住且滑鼠一邊在移動時,X Server 會產生 MotionNotify。 
ButtonMotionMask 
當任何一個滑鼠按鈕(button)按住且滑鼠一邊移動時,X Server 會產生 MotionNotify。 
PointerMotionMask 
不論滑鼠按鈕(button)是否被按下,只要滑鼠移動 X Server 就會產生 MotionNotify。 
--------------------------------------------------------------------------------
除了上面幾個之外,還有 PointerMotionHintMask。 PointerMotionMask 是和上面幾個 Mask 合使用的, 當指定任何上面所提的 Mask 後,再加上 PointerMotionHintMask ,X Server 可以只產生一次 MotionNotify 給 client。除此之外,滑鼠按鈕的狀態改變 (按下變放開或反之),滑鼠的標離開視窗,或 client 呼叫 XQueryPointer 或 XGetMotionEvents,X Server 也會產生 MotionNotify Event。這些狀況產生的 MotionNotify 都會設定 Event Structure 的 is_hint 欄位(is_hint memeber)。除了上面的狀況外, X Server 可能依然產生沒有設定 is_hint 欄位的 MotionNotify Event (也就是沒在 event mask 設定 PointerMotionMask 情況下所產生的 MotionNotify)。 
--------------------------------------------------------------------------------

typedef struct {
int type;
unsigned long serial;
Bool send_event;
Display *display;
Window window;
Window root;
Window subwindow;
Time time;
int x, y;
int x_root, y_root;
unsigned int state;
unsigned int botton;
Bool same_screen;
} XButtonEvent;
typedef XButtonEvent XButtonPressedEvent;
typedef XButtonEvent XButtonReleasedEvent;

typedef struct {
int type;
unsigned long serial;
Bool send_event;
Display *display;
Window window;
Window root;
Window subwindow;
Time time;
int x, y;
int x_root, y_root;
unsigned int state;
unsigned int keycode;
Bool same_screen;
} XKeyEvent;
typedef XKeyEvent XKeyPressedEvent;
typedef XKeyEvent XKeyReleasedEvent;

typedef struct {
int type;
unsigned long serial;
Bool send_event;
Display *display;
Window window;
Window root;
Window subwindow;
Time time;
int x, y;
int x_root, y_root;
unsigned int state;
unsigned int is_hint;
Bool same_screen;
} XMotionEvent;
typedef XMotionEvent XPointerMoveEvent;


--------------------------------------------------------------------------------
window 是指 event window,也就是產生事件的 window。root 是指 source window 所在 screen 之 root window。前面有提及 事件會尋著視窗的階層架構,往祖先視窗(ancester window)傳遞 (propagate)。若 event window 和 source window 是不同個視 窗時(從視窗階層下層傳遞上來),則 subwindow 則是 event window 的 child window,這個 child window 是事件傳遞過程經過的視 窗。若 event window 和 source window 是同一個時(也就是產生 Event 和事件發生是同一個視窗),則 subwindow 設為 None。 x 和 y 則是事件發生時,標相對於 event window 左上角的 座標。x_root 和 y_root 則是標在 root window 上的座標。 state 是事件發生時滑鼠按鈕和鍵盤上修飾鍵的狀態,是由一個 或數個狀態做 OR 運算的組合。這些狀態是 Button1Mask, Button2Mask,Button3Mask,Button4Mask,Button5Mask, ShiftMask,LockMask,ControlMask,Mod1Mask,Mod2Mask, Mod3Mask,Mod4Mask,Mod5Mask。same_screen 是指示 root window 和 event window 是否在同一個 screen,內容是 True or False。 button 是 XButtonPressedEvent 和 XButtonReleasedEvent 事件結構內的欄位,用以紀錄滑鼠按鈕狀態改變。XKeyPressedEvent 和 XKeyReleasedEvent 的 keycode 是任何按鍵的 keycode 即 鍵盤按鍵的代碼(在後面會述及)。XPointerMovedEvent 事件結構 內的 is_hint 在前面有說明,內容是 NotifyNormal 或 NotifyHint。 

CreateNotify
CreateNotify 是在視窗建立時產生的事件,client 在視窗的 evnet mask 設定 SubstructureNotifyMask,則任何子視窗(child window)的建立都會產生 CreateNotify。這個事件的結構包含下面 幾個資訊: 
--------------------------------------------------------------------------------

typedef struct {
int type;
unsigned long serial;
Bool send_event;
Display *display;
Window parent;
Window window;
int x, y;
int width, height;
int border_width;
Bool override_redirect;
} XCreateWindowEvent;


--------------------------------------------------------------------------------
parent 是被建立之視窗的 parent window 的 Window ID,window 則是新建立的 window。x 和 y 則是新視窗相於 parent window 左上角的座標。width 和 height 則是新視窗的寬度和高度。 override_redirect 則是視窗的 override_redirect 屬性,若 為 True 則 window manager 不會幫這個視窗做處理,乎略這個 視窗。

DestroyNotify
DestroyNotify 是在視窗被刪除 (destroy) 時產生的事件。當視窗 被刪除時,其所有的子視窗也會跟著被刪除,而子視窗 (child window) 的 DestroyNotify 會在父視窗 (parent window) 之前產生。client 在視窗的 event mask 設定 StructureNotifyMask,則視窗被刪 除時會收到 DestroyNotify,若設定 SubstructureNotifyMask 則是子視窗 (child window) 被刪除時會收到 DestroyNotify。 
--------------------------------------------------------------------------------

typedef struct {
int type;
unsigned long serial;
Bool send_event;
Display *display;
Window event;
Window window;
} XDestroyWindowEvent;


--------------------------------------------------------------------------------
若是設定 StructureNotifyMask 則 event 是被刪除(destroyed) 視窗的 Window ID,若是 SubstructureNotifyMask 則 event 是被刪除視窗的父視窗 (parent window) 的 window ID。

ResizeRequest
如果有任何的 client 試途要改變視窗的大小, 則 X Server 會向其它要求知道這項訊息的 client 傳送 ResizeRequest。 當 client 需要知道這個訊息時,必需在視窗的 event mask 設定 ResizeRedirect,這樣子只要有任何的其它 client 試 圖改變該視窗大小,X Server 就會傳送 ResizeRequest 給 client。這個事件的結構如下: 
--------------------------------------------------------------------------------

typedef struct {
int type;
unsigned long serial;
Bool send_event;
Display *display;
Window window;
int width, height;
} XResizeRequestEvent;


--------------------------------------------------------------------------------
width 和 height 是另一個 client 試圖要把視窗改成的大小。

FocusIn
FocusOut
當你在鍵盤上敲下 'A' 時,X Server 會將「按下按鍵'A'」這個 event 送到目前 focus 的視窗。也就是當視窗為目前的 focus 時 ,X Server 才會把鍵盤輸入的事件傳送給視窗。而 focus 會在不 同的視窗之間轉移,不同的 Window Manager 有不同的轉移方式。 可能是你把滑鼠指標移到那某個視窗,focus 就會轉移到該視窗。 也可能是你要在該視窗的 title 上面按一下,focus 才會轉移過 去。當 focus 進入某一視窗時,代表 focus 從另一個視窗移走。 focus 進入視窗時,會在該視窗產生 FocusIn event。focus 從 視窗移除時,X Server 會在該視窗產生 FocusOut event。如果你 希望 client 程式接收這兩個 event,必需在視窗的 event-mask 設定 FocusChangeMask 這個 bit。

下面是 FocusIn 和 FocusOut 這兩個 event 的結構: 
--------------------------------------------------------------------------------

typedef struct {
       int type;
       unsigned long serial;
       Bool send_event;
       Display *display;
       Window window;
       int mode;
       int detail;
} XFocusChangeEvent;

typedef XFocusChangeEvent XFocusInEvent;
typedef XFocusChangeEvent XFocusOutEvent;


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



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

/* ------ XEvent.c ------ */
#include 
#include 
#include 
#include 


GC gc;
Display *display;
Window window;


void
reshow(void)
{
/*
 * 畫方框
 */
XDrawRectangle(display, window, gc, 10, 10, 100, 100);

/*
 * 畫直線
 */
XDrawLine(display, window, gc, 200, 10, 200, 290);
}


int
main_loop(XEvent *xe)
{
if(xe->type == Expose)
{
printf("Expose! \n");
reshow();
}

return False;
}


void
init(void)
{
XSetWindowAttributes attr;
Colormap colormap;
XColor color1, color2;
XGCValues gcvalue;
XSizeHints *sz;

display = XOpenDisplay("0:0");

colormap = DefaultColormap(display, DefaultScreen(display));
/*
 * 配置 colorcell
 */
color1.red = color1.blue = 0xffff;
color1.green = 0;
color2.red = color2.green = color2.blue = 0xff;
color1.flags = color2.flags = DoRed | DoGreen | DoBlue; 
XAllocColor(display, colormap, &color1);
XAllocColor(display, colormap, &color2);

attr.background_pixel = color2.pixel; /* background color */
attr.event_mask = ExposureMask; /* receive expose event */

window = XCreateWindow(display,
       XDefaultRootWindow(display),
       100, 100, /* 左上角位置 */
       300, 300, /* 視窗大小 */
       2, /* border 的寬度 */
       XDefaultDepth(display, 0),
       InputOutput, /* window class */
       CopyFromParent, /* visual */
       CWBackPixel | CWEventMask,
       &attr); /* attributes */

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
 */
XMapWindow(display, window);

gcvalue.foreground = color1.pixel;
gcvalue.background = color2.pixel;
gcvalue.line_width = 5;
gcvalue.line_style = LineOnOffDash;
gcvalue.cap_style = CapButt;
gcvalue.join_style = JoinRound;
gc = XCreateGC(display, window,
       GCForeground | GCBackground | 
       GCLineWidth | GCLineStyle |
       GCCapStyle | GCJoinStyle,
       &gcvalue);
}


main() 
{
XEvent xe;
int i = 0;

init();

while(1)
{
printf("while %d\n", i++);
XFlush(display);
XNextEvent(display, &xe); /* 取得下一個 event */
if(main_loop(&xe)) /* 處理 event */
return 0;
}
}


--------------------------------------------------------------------------------
這個程式和第三章的例程式相似, 但處理了 expose event. 執行之後 會發現處理 expose event 之後, 圖形不會因為被其它視窗蓋掉而無 法恢復了. 
(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)
 

★  樊強制作 歡迎分享  ★