X Window 程式设计入门--第四章 Event

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 之後, 图形不会因为被其它视窗盖掉而无 法恢复了.
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值