Xlib 窗口屬性

所有的 InputOutput 窗口都可以有零個或者多個像素的邊框寬度,一個可選的背景,一個事件壓制掩碼(它壓制來自孩子的事件傳播),和一個 property 列表。窗口的邊框和背景可以是一個實心顏色或者是一個稱爲平鋪的調色板。除了根窗口之外的所有的窗口都有父親並且都是由它們的父親所裁剪。如果一個窗口是 在壓棧壓在另一個窗口的上面,它遮擋用於輸入的其它窗口。如果一個窗口有背景(大多數都有),它遮擋其它用於輸出的窗口。嘗試輸出到被遮擋的區域將不起任 何作用,並且對於被遮擋區域不會生成輸入事件。

 
      窗口也會與 property 列表相關聯。
 
      InputOutput 和 InputOnly 窗口都有下面的共同屬性,但是 InputOnly 窗口只有這些屬性:
  • win-gravity
  • event-mask
  • do-not-propagate-mask
  • override-redirect
  • cursor
      如果你爲一個 InputOnly 窗口指定任何其它的屬性,就會產生一個 BadMatch 錯誤。
 
      InputOnly 窗口是用於在不必要使用 InputOutput 窗口的情況下控制輸入事件的。InputOnly 窗口是不可見的;可能只被用於控制像光標、輸入事件生成以及捕獲等的一些東西;並且不能用在任何圖形請求中。注意 InputOnly 窗口不能作爲 InputOutput 窗口的下級窗口。
 
      窗口有可編程寬度的邊框和調色板以及背景調色板或者平鋪貼片。像素值可以用作實心顏色。如果沒有產生更進一步對它們明確地引用,那麼背景和邊框位圖可以在 創建窗口之後立即釋放。調色板要麼可以與它的父親有關,要麼完全無關。如果 ParentRelative,就會使用父親的背景。當窗口是第一次創建,它們在屏幕上並不可見(還沒有被映射)。對於在屏幕上不可見並且沒有回填窗口的 任何輸出都將會被丟棄。某個應用程序可能希望在窗口被映射到屏幕之前很久創建這個窗口。當窗口最終被映射到屏幕上(使用 XMapWindow),如果並沒有維護回填,X server 爲窗口生成 Expose 事件。
 
      窗口管理器可以覆蓋你爲頂層窗口選擇的大小、邊框寬度和位置。你的程序必須準備使用頂層窗口的實際大小和位置。對於客戶應用程序而言去重新改變它自己的大 小是不可接受的,除非是爲了直接響應人的指令才這麼做。而是你的程序要麼使用給它的空間,要麼如果對於任何有用的工作而言空間太小的話,你的程序可能要求 用戶去改變窗口的大小。對於窗口管理器而言,你的頂層窗口的邊框被認爲是可以改變的。
 
      要設置窗口的屬性,設置 XSetWindowAttributes 結構適當的成員,並且與你隨後調用 XCreateWindow 和 XChangeWindowAttributes 中對應的值位掩碼做或(OR)運算,或者使用任何設置適當屬性的其它便利函數之一。用於值掩碼位的符號和 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)
 
/* 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;
  usngined long bakcing_pixel;
  Bool save_under;
  long event_mask;
  long do_not_propagate_mask;
  Bool override_redirect;
  Colormap colormap;
  Cursor cursor;
} XSetWindowAttributes;
 
      下面列出了每一個窗口屬性的缺省值並且標誌着這個屬性對於 InputOutput 和 InputOnly 窗口而言是否可以接受:
屬性 缺省值 InputOutput InputOnly
background-pixmap None Yes No
background-pixel Undefined Yes No
border-pixmap CopyFromParent Yes No
border-pixel Undefined Yes No
bit-gravity ForgetGravity Yes No
win-gravity NorthWestGravity Yes Yes
backing-store NotUseful Yes No
backing-planes All ones Yes No
backing-pixel zero Yes No
save-under False Yes No
event-mask empty set Yes Yes
do-not-propagate-mask empty set Yes Yes
override-redirect False Yes Yes
colormap CopyFromParent Yes No
cursor None Yes Yes
 
背景屬性
 
      只有 InputOutput 窗口可以有背景。你可以通過使用像素或者位圖來設置 InputOutput 窗口的背景。
 
      窗口的 background-pixmap 屬性指定的位圖被用於窗口的背景。這個位圖可以是任何大小,儘管一些大小可以比另一些快。窗口的 background-pixel 屬性指定用於以一種單一顏色繪製窗口的背景。
 
     你可以將 background-pixmap 設置成一個位圖、None(缺省)或者 ParentRelative。你可以將窗口的 background-pixel 設置成任何像素值(沒有缺省值)。如果你指定了 background-pixel,它要麼覆蓋缺省的 background-pixmap,要麼覆蓋你可能在 background-pixmap 中設置的任何值。用 background-pixel 填充的未定義大小的 pixmap 用作背景。對背景像素並不進行範圍檢查;它簡單地截取成適當的位數。
 
      如果你設置 background-pixmap,它覆蓋缺省值。這個 background-pixmap 和窗口必須有相同的深度,或者產生 BadMatch 錯誤。如果你將 background-pixmap 設爲 None,窗口就沒有定義的背景。如果你將 background-pixmap 設置爲 ParentRelative:
  • 使用父窗口的 background-pixmap。不過,子窗口必須與其父親有相同的深度,或者產生 BadMatch 錯誤。
  • 如果父窗口的 background-pixmap 爲 None,那麼窗口的 background-pixmap 也是 None。
  • 背景平鋪的原點總是與父窗口的背景平鋪原點對齊。如果 background-pixmap 並不是 ParentRelative,背景平鋪原點就是子窗口的原點。
      是通過設置 background-pixmap 或者 background-pixel 來設置新背景,都覆蓋任何以前的背景。如果沒有對它進一步明確的引用(X server 將在需要的時候保持一份拷貝來使用)的話,background-pixmap 可以立即被釋放。如果你隨後將位圖用於背景的話,結果是未定義的,因爲 X 實現是自由地創建位圖的副本或者使用相同的位圖。
 
      當窗口的區域並沒有有效的內容時,並且要麼區域是可見的,要麼服務器正在維護回填,服務器自動地用窗口背景平鋪區域,除非窗口的背景爲 None。如果背景是 None,來自其它與這個窗口具有相同深度窗口的前一屏內容被簡單地留在適當的位置,只要內容是來自這個窗口父親或者父親的後繼。否則被暴露區域的內容是 未定義的。隨後爲這個區域生成 Expose 事件,即使 background-pixmap 是 None。
 
邊框屬性
 
      只有 InputOnly 窗口可以有邊框。你可以通過使用像素或者位圖來設置 InputOutput 窗口的邊框。
 
      窗口的 border-pixmap 屬性指定用於窗口邊框的位圖。窗口的 border-pixel 屬性指定由用於窗口邊框的像素填充的未定義大小的位圖。在背景像素上不必執行範圍檢查;它簡單地截取成合適的位數。邊框平鋪的原點總是與背景平鋪原點一樣。
 
      你也可以將 border-pixmap 設置爲任意大小的位圖(一些可能比另一些快)或者 CopyFromParent(缺省)。你可以將 border-pixel 設置爲任何像素值(非缺省)。
 
      如果你設置 border-pixmap,它覆蓋缺省值。這個 border-pixmap 和窗口必須有相同的深度,或者產生 BadMatch 錯誤。如果你將 border-pixmap 設置爲 CopyFromParent,父窗口的 border-pixmap 就會被複制。對父窗口邊框屬性的後續更改並不會影響子窗口。不過,子窗口與父窗口必須有相同的深度,或者產生 BadMatch 錯誤。
 
      如果沒有更進一步對這個 border-pixmap 的引用,它可立即釋放它。如果你隨後將位圖用於邊框,後果是未定義的,因爲 X 實現對於是創建一個位圖的副本還是使用相同的位圖是自由的。如果你指定一個 border-pixel,它要麼覆蓋缺省的 border-pixmap,要麼你可以將 border-pixmap 設置成任何值。在窗口邊框中的所有像素都將被設置爲 border-pixel。不論是通過設置 border-pixel 還是通過設置 border-pixmap 來設置新邊框,都會覆蓋前面的邊框。
 
      向一個窗口輸出總是會在這個窗口的範圍以內進行裁剪。因此,圖形操作從不會影響窗口邊框。
 
Override Redirect 標誌
 
      要控制窗口的放置或者增加裝飾,窗口管理器常常需要解釋(重定向)任何映射或者配置請求。不過,彈出式窗口常常需要被映射但無須窗口管理器這樣做。要控制 InputOutput 或者 InputOnly 窗口是否忽略這些結構控制功能,使用 override-redirect 標誌。
 
      Override-redirect 標誌指定在這個窗口上的映射和配置是否應當在覆蓋其父窗口的 SubstructureRedirectMask。你可以將 override-redirect 標誌設置爲 True 或者 False(缺省)。窗口管理器使用這個信息以避免影響彈出式窗口。
 
控制輸入焦點
 
      Xlib 提供了可用於移動鼠標指針位置以及設置和獲取輸入焦點的函數。
 
      要將鼠標指針移動到屏幕上的任意一處時,使用 XWarpPointer。
 
      XWarpPointer(display, src_w, dest_w, src_x, src_y, src_width, src_height, dest_x, dest_y )
        Display *display ;
        Window scr_w , dest_w ;
        int src_x , src_y ;
        unsigned int src_width , src_height ;
        int dest_x , dest_y ;
 
      要設置焦點,使用 XSetInputFocus。
 
      XSetInputFocus(display, focus, revert_to, time )
        Display *display ;
        Window focus ;
        int revert_to ;
        Time time ;
      display   指定要連接到的 X server。
      focus   指定的窗口、PointerRoot、或者 None。
      revert_to   如果窗口變得不可視的話,其指定輸入焦點應該回到何處。你可以指定 RevertToParent、RevertToRoot、或者 RevertToNone。
      time   指定時間。你可以發送一個時間戳或者 CurrentTime。
 
      XSetInputFocus 函數改變輸入焦點和 last-focus-change 時間。如果指定的時間比當前 last-focus-change 時間還早或者比當前 X server 時間還晚的話,它不產生任何影響。否則,last-focus-change 時間就被設置爲指定的時間(CurrentTime 由當前 X server 時間所取代)。XSetInputFocus 導致 X server 生成 FocusIn 和 FocusOut 事件。
 
      取決於焦點參數,會發生如下情況:
  • 如果焦點是 None,所有的鍵盤事件都會被丟棄,直到設置了一個新的焦點窗口,並且 revert_to 參數被忽略。
  • 如果焦點是一個窗口,它就變成鍵盤的焦點窗口。如果生成的鍵盤事件會正常地報告給這個窗口或者它的後代之一的話,那麼這個事件報告照常。否則,事件報告給相關的焦點窗口。
  • 如果焦點是 PointerRoot,焦點窗口就動態地趨向於在第一個鍵盤事件上鼠標指針所指向的任何屏幕的根窗口。在這種情況下,忽略 revert_to 參數。
     指定的焦點窗口在 XSetInputFocus 被調用時必須是可視的,或者產生一個 BadMatch 錯誤結果。如果焦點窗口後來變成不可視的話,X server 會評估 revert_to 參數來按如下方案決定新的焦點窗口:
  • 如果 revert_to 是 RevertToParent,焦點還原到父窗口(或者最近的可視祖先窗口),並且新的 revert_to 值變成 RevertToNone。
  • 如果 revert_to 是 RevertToPointerRoot 或者 RevertToNone,焦點分別還原到 PointerRoot 或者 None。當焦點還原時,X server 生成 FocusIn 和 FocusOut 事件,但是 last-focus-change 時間並不受影響。
      XSetInputFocus 可以生成 BadMatch、BadValue、以及 BadWindow 錯誤。
 
      要獲得當前的輸入焦點,使用 XGetInputFocus。
 
      XGetInputFocus(display, focus_return, revert_to_return )
        Display *display ;
        Window *focus_return ;
        int *revert_to_return ;
 
  
映射窗口
 
      如果在一個窗口上已經調用過 XMapWindow 的話,它就被視作已映射的。它出於以下幾個原因之一在屏幕上可能並不可見:
  • 它是由另外一個不透明的窗口所遮擋。
  • 它的祖先之一並沒有被映射。
  • 它整個地被某個祖先所剪切。
      當窗口的部分或者全部在屏幕上可見時才生成 Exposure 事件。客戶程序只有在它已經請求了 Expose 事件的情況下才能接收到它們。當窗口被解除映射時,按照棧順序保留它們的位置。
 
      窗口管理器可能想去控制子窗口的放置。如果窗口管理器在父窗口(通常是一個根窗口)中已經選擇了 SubstructureRedirectMask 的話,那麼由其它客戶程序在子窗口上發起的映射請求就不會被執行,並且會向窗口管理器發送一個 MapRequest 請求。不過,如果子窗口的 override-redirect 標誌被設置爲 True(通常只是在彈出菜單上)的話,映射請求會被執行。
 
      一個鋪開窗口的窗口管理器可能決定重新定位並且重新調整其它客戶程序的窗口大小,然後決定將窗口映射到它的最終位置。想提供裝飾的窗口管理器可能會將子窗 口的父屬關係重新調整到第一個幀。只有單個客戶程序在一個時間可以選擇 SubstructureRedirectMask。
 
      類似地,單個的客戶程序可以在父窗口上選擇 ResizeRedirectMask。然後,其它客戶程序對窗口的大小進行調整的嘗試都會被壓制,並且客戶程序會接收到 ResizeRequest 事件。
 
      要映射一個給定的窗口,使用 XMapWindow。
 
      XMapWindow(display, w)
        Display *display;
        Window w;
      display  指定到 X server 的連接。
      w  指定窗口。
 
      XMapWindow 函數映射窗口及其有映射請求的所有子窗口。映射一個具有未映射祖先的窗口並不能顯示這個窗口,而是將它標記爲具備在這個祖先變成映 射後顯示的條件。這樣的窗口稱爲不可視的。當它的所有祖先都被映射時,如果這個窗口沒有被其它的窗口所遮蓋的話,它就變成可視的並且會在屏幕上看見。如果 這個窗口已經被映射過了,這個函數也沒有任何影響。
 
      如果窗口的 override-redirect 是 False,並且如果一些其它的客戶程序已經在父窗口上選擇了 SubstructureRedirectMask 的話,那麼 X server 生成一個 MapRequest 事件,並且 XMapWindow 函數並不映射窗口。否則,窗口會被映射,並且 X server 生成 MapNotify 事件。
 
      如果窗口變成可視的,並且它早期的內容並沒有被記下,X server 用它的背景平鋪這個窗口。如果窗口的背景沒有定義,現有的屏幕內容就不會被更新,並且 X server 生成零個或者多個 Expose 事件。如果回填是在窗口沒有被映射的時候進行維護,那麼就沒有 Expose 事件生成。如果回填將會在現在維護,全部窗口的暴露就總會被生成。否則,只有可見的區域會被報告。類似的平鋪和暴露會發生在任何級別的新的可視窗口上。
 
      如果窗口是 InputOutput 窗口,XMapWindow 在每一個它所主導要被顯示的 InputOutput 窗口上生成 Expose 事件。如果客戶程序映射並且描繪了窗口,並且如果客戶程序開始處理事件,那麼窗口會被描繪兩次。要避免這一點,首先詢問 Expose 事件,然後映射窗口,以使客戶程序正常處理輸入事件。事件列表將爲每一個出現在屏幕上的窗口包括 Expose。客戶程序對 Expose 事件的正常響應應當是重繪窗口。這種方式通常導致更簡單的程序以及與窗口管理器之間的正確交互。
 
      XMapWindow 可以生成 BadWindow 錯誤。
 
      要映射並且提升窗口,使用 XMapRaised。
 
      XMapRaised(display, w)
        Display *display;
        Window w;
     
      XMapRaised 函數本質上是類似於 XMapWindow 中其映射窗口以及窗口的所有有映射請求的子窗口。不過,它也提升指定的窗口到顯式棧的棧頂。
 
      XMapRaised 可以生成多個 BadWindow 錯誤。
 
      要爲某個指定的窗口映射所有的子窗口,使用 XMapSubwindows。
 
      XMapSubwindows(display, w)
        Display *display;
        Window w;
 
      XMapSubwindows 函數按照從頂到底的棧順序爲指定的窗口映射其所有的子窗口。X server 在每一個新顯示的窗口上生成 Expose 事件。這可能比每次映射許多窗口更加有效,因爲 server 只需要一次就能對所有的窗口,而不是一個窗口執行很多工作。
 
配置窗口
 
      Xlib 提供了可用於移動窗口、重新改變窗口大小、移動並重新改變窗口大小,或者改變窗口邊框寬度等的函數。要改變這些參數之一,設置 XWindowChanges 結構的恰當成員並且或上(OR)在隨後調用的 XConfigureWindow 中對應的值掩碼。對於值掩碼位和 XWindowChanges 結構的符號是:
 
/* Configure window value mask bits */
#define CWX (1<<0)
#define CWY(1<<1)
#define CWWidth(1<<2)
#define CWHeight(1<<3)
#define CWBorderWidth(1<<4)
#define CWSibling(1<<5)
#define CWStackMode(1<<6)
/* Values */
typedef struct {
  int x, y;
  int width, height;
  int border_width;
  Window sibling;
  int stack_mode;
} XWindowChanges;
 
      成員 x 和 y 用於設置窗口的 x 和 y 座標,它是與父窗口的原點有關的,並且指示窗口的左上角的位置。寬度和高度成員用於設置窗口的內部大小,不包括邊框,並且必須非零,或者產生 BadValue 錯誤。嘗試配置根窗口不會產生任何效果。
 
      成員 border_width 成員用於設置以像素爲單位的邊框寬度。注意只是設置邊框寬度使窗口的外層左上角在一個固定的位置,而移動相對於窗口原點的絕對位置。如果嘗試將 InputOnly 窗口的邊框寬度屬性設置爲非零,會產生一個 BadMatch 錯誤。
 
      成員 sibling 用於爲棧操作設置兄弟窗口。成員 stack_mode 成員用於設置窗口如何被重新調整棧位置並且可以被設置爲 Above、Below、TopIf、BottomIf、或者 Opposite。
 
      如果窗口的 override-redirect 標記是 False 並且如果一些其它的客戶程序在父窗口上選擇了 SubstructureRedirectMask 的話,X server 生成一個 ConfigureRequest 事件,並且不再執行進一步的處理。否則,如果一些其它的客戶程序在窗口上選擇了 ResizeRedirectMask 並且窗口的內部寬度和高度改變的話,會生成一個 ResizeRequest 事件,並且取而代之使用當前的內部寬度和高度。注意
窗口的 override-redirect 標誌對於 ResizeRedirectMask 沒有影響並且父窗口上的 SubstructureRedirectMask 已經先於這個窗口的 ResizeRedirectMask。
 
      當窗口的幾何形狀按所指定的發生了改變,這個窗口會在兄弟中改變棧順序,並且如果窗口的狀態實際上發生了改變,會生成一個 ConfigureNotify 事件。GravityNotify 事件在 ConfigureNotify 事件之後生成。如果窗口內部的寬度和高度已經真正地發生了改變,窗口的孩子都會按照指定的那樣受影響。
 
      如果窗口的大小真正地發生了改變,窗口的子窗口按照它們的窗口重心移動。取決於窗口的位重心,窗口的內容也可能被移動。
 
      如果窗口的區域應當被遮擋,但是現在還沒有的話,會在這些原來被遮擋窗口上執行暴露處理,包括窗口自身和它的下層窗口。寬度和高度的增加,會導致在窗口的任何新區域和窗口內容丟失的任何區域上也執行暴露處理。
 
      重新排列棧順序的檢查(特別是對於 BottomIf、TopIf、和 Opposite 的計算)是遵照窗口最終的大小和位置(由請求的其它參數來控制)來執行的,而不是其初始位置。如果指定了一個兄弟窗口而不是一個 stack_mode,生成一個 BadMatch 錯誤。
 
      如果兄弟窗口和 stack_mode 都被指定的話,窗口按如下方式重新調整棧順序:
 
      Above  窗口正好放在兄弟窗口之上。
      Below  窗口正好放在兄弟窗口之下。
      TopIf  如果兄弟窗口包藏住了這個窗口,那麼它放置在棧頂。
      BottomIf  如果窗口包藏住了兄弟窗口,這個窗口放在棧底。
      Opposite  如果兄弟窗口包藏住了這個窗口,那麼它放在棧頂。如果這個窗口包藏住了兄弟窗口,那麼它放在棧底。
 
      如果指定了 stack_mode 而沒有指定兄弟窗口,那麼這個窗口按照下列方式調整棧順序:
 
      Above  窗口正好放在兄弟窗口之上。
      Below  窗口正好放在兄弟窗口之下。
      TopIf  如果兄弟窗口包藏住了這個窗口,那麼它放置在棧頂。
      BottomIf  如果窗口包藏住了兄弟窗口,這個窗口放在棧底。
      Opposite  如果兄弟窗口包藏住了這個窗口,那麼它放在棧頂。如果這個窗口包藏住了兄弟窗口,那麼它放在棧底。
 
      嘗試去配置根窗口將不會產生任何效果。
 
      要配置窗口的大小、位置、棧序或者邊框,使用 XConfigureWindow。
 
      XConfigureWindow(display, w, value_mask, values )
        Display *display ;
        Window w ;
        unsigned int value_mask ;
        XWindowChanges *values ;
      display   指定到 X server 的連接。
      w   指定要被重新配置的窗口。
      value_mask   指定值結構中的哪些值要被設置。這個掩碼是有效的配置窗口值位的包括或(OR)位運算。
      values   指定 XWindowChanges 結構。
 
      XConfigureWindow 函數使用在 XWindowChanges 結構中指定的值來重新配置窗口的大小、位置、邊框和棧序。沒有指定的是從窗口的現有幾何狀態中拿過來的。
 
      如果指定了兄弟窗口而沒有 stack_mode 或者如果窗口實際上並不是兄弟窗口,會生成 BadMatch 錯誤。注意對於 BottomIf、TopIf 和 Oppsite 的計算都是遵照窗口最終的幾何狀態(由發送到 XConfigureWindow 的其它參數來控制)來執行的,而不是它的最初幾何狀態。窗口的任何回填內容,它的下層窗口以及其它新的可見窗口都要麼被丟棄,要麼被改變以反映出當前的屏 幕內容(取決於實現)。
 
      XConfigureWindow 可以生成 BadMatch、BadValue、和 BadWindow 錯誤。
 
      要移動窗口而不改變它的大小,使用 XMoveWindow。
 
      XMoveWindow(display, w, x, y )
        Display *display ;
        Window w ;
        int x, y ;
      display   指定連接到的 X server。
      w   指定要被移動的窗口。窗口的邊框,如果窗口沒有邊框就是窗口自身。
      x, y   指定定義窗口邊框左上角像素新位置的 x 和 y 座標,或者如果窗口沒有邊框,就是窗口自身。
 
      XMoveWindow 函數移動指定的窗口到指定的 x 和 y 座標,但是它並不改變窗口的大小,提升窗口或者改變窗口的映射狀態。移動已映射的窗口可能會或者可能不會丟失窗口的內容,取決於窗口是否被非子窗口所遮檔 以及是否沒有回填存在。如果窗口的內容丟失,X server 生成 Expose 事件。移動已映射的窗口在任何以前被遮擋的窗口上生成 Expose 事件。
 
      如果窗口的 override-redirect 是 False 並且一些其它的客戶程序在父窗口上選擇 SubstructureRedirectMask,X server 生成 ConfigureRequest 事件,並不執行進一步的處理。否則,窗口被移動。
 
      XMoveWindow 可以生成 BadWindow 錯誤。
 
     
     

事件(Event)

      一個事件是作爲一些設備活動由 X server 異步生成的數據,或者作爲由 Xlib 函數發送請求的副作用而產生的數據。

      所有的事件結構都有下列的通用成員:

      typedef struct {

        int type;

        unsigned long serial;

        Bool send_event;

        Display *display;

        Window window;

      } XAnyEvent;

      除了爲每一種事件類型聲明單獨的結構之外,XEvent 結構是一個爲每一種事件類型而聲明的單獨結構的聯合。取決於類型,你應當通過使用 XEvent 聯合來訪問每一個事件的成員。

      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;

        XConfigureRequestEvent 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;

Expose 事件

      X server 會向希望得到窗口區域的內容何時丟失的客戶程序報告 Expose 事件。其中 X server 生成 Expose 事件的情形並不像其它事件一樣明確。不過,X server 從不對你指定爲 InputOnly 的窗口生成 Expose 事件。X server 可以在窗口的區域沒有可用的內容時生成 Expose 事件,並且區域要麼是可見的,區域是可視的並且 server 正在(可能是最近)維護窗口上的存儲回填,要麼窗口是不可視的,但 server 正在(可能是最近)尊重了窗口的 Always 或者 WhenMapped 存儲回填屬性。區域分解成一組(或任意多組)矩形框,並且爲每一個矩形生成一個 Expose 事件。對於任何已有的窗口,X server 保證連續地報告由一些引起 Expose 事件的動作,例如像提升窗口,所暴露的全部區域。

      要接收 Expose 事件,將窗口的事件掩碼屬性中的 ExposureMask 置位。

      這個事件類型的結構包含:

      typedef struct {

        int type;

        unsigned long serial;

        Bool send_event;

        Display *display;

        Window window;

        int x, y;

        int width, height;

        int count;

      } XExposeEvent;

      窗口成員被設置爲暴露的(危險的)窗口。成員 x 和 y 設置爲相對於窗口中心的座標,並且表示矩形的左上角。成員 width 和 height 被置爲矩形的大小(範圍)。成員 count 設置爲隨後緊跟的 Expose 事件的數目。如果 count 是零,就表示沒有更多的 Expose 事件緊隨這個窗口。不過,如果 count 不是零,緊隨這個窗口的 Expose 事件的數目至少是有一個。並不想去優化區別其窗口子區域重新顯示的簡單應用程序只是忽略所有 count 值爲非零的 Expose 事件並且對 count 爲零的事件執行全部的重新顯示。

 
事件隊列管理
 
      Xlib 維護一個事件隊列。不過,操作系統也可能在其還沒有讀入事件隊列的網絡連接中緩衝數據。
 
      要檢查事件隊列中的事件數目,使用 XEventsQueued。
 
      int XEventsQueued(display, mode )
            Display *display ;
            int mode ;
      display   指定到 X server 的連接。
      mode    指定模式。你可以發送 QueuedAlready、QueuedAfterFlush、或者 QueuedAfterReadiing。
 
      如果模式是 QueuedAlready,XEventsQueued 返回已經在事件隊列中的事件數目(並且從不執行系統調用)。如果模式是 QueuedAfterFlush,如果已經在事件隊列中的事件數目不是零的話,XEventsQueued 返回它。如果沒有事件在隊列中,XEventsQueued 刷新輸出緩衝區,嘗試將更多的事件從應用程序的連接中讀出,並且返回讀取的數目。如果 mode 是 QueuedAfterReading,並且如果已經在隊列中的事件數目不是零,XEventsQueued 返回它。如果隊列中沒有事件,XEventsQueued 嘗試從應用程序的連接中讀出更多的事件但並不刷新輸出緩衝區,並且返回讀出的數目。
 
      如果隊列中已有事件,XEventsQueued 總是立即返回而無須任何 I/O。模式爲 QueuedAfterFlush 的 XEventsQueued 在行爲上與 XPending 是一致的。模式爲 QueuedAlready 的 XEventsQueued 與 XQLength 函數一致。
 
      用 XPending 返回未決的事件數目,
      int XPending(display )
        Display *display ;
      display   指定到 X server 的連接。
 
      XPending 函數返回已經從 X server 接收到但還沒有從隊列中移出的事件數目。XPending 與模式指定爲 QueuedAfterFlush 的 XEventsQueued 一致。
 
維護事件隊列
 
      Xlib 提供用於維護事件隊列的函數。包括三部分:
  • 獲取事件,隨後將它們從隊列中移出
  • 在隊列中窺探事件而不用將它們移出
  • 獲取與事件掩碼或者你提供的任意斷言過程匹配的事件
1. 返回下一個事件
 
      要得到下一個事件並將其從隊列中移出,使用 XNextEvent。
      XNextEvent(display, event_return )
        Display *display ;
        XEvent *event_return ;
      display   指定到 X server 的連接。
      event_return   返回隊列中的下一個事件。
      XNextEvent 函數從事件隊列拷貝第一個事件到指定的 XEvent 結構中,然後將這個事件從隊列中移出。如果事件隊列是空的,XNextEvent 刷新輸出緩衝區並阻塞直到收到事件。
 
      使用 XPeekEvent 來窺探事件隊列。
      XPeekEvent(display, event_return
        Display *display ;
        XEvent *event_return ;
      display   指定到 X server 的連接。
      event_return   返回與相關結構匹配事件的一個副本。
      XPeekEvent 函數從隊列中返回第一個事件,但是它並不將事件從隊列中移出。如果隊列爲空,XPeekEvent 刷新輸出緩衝區並阻塞直到接收到事件。它隨後將事件複製到客戶程序補充的 XEvent 結構中,而不將事件從事件隊列中移出。
 
2. 使用斷言過程選擇事件
 
      在這一部分中討論的每一個函數都要求你傳送一個斷言過程來判斷某個事件是否與你想要的相匹配。你的斷言過程必須決定事件是否有用,並且絕不能調用 Xlib 函數。特別是,斷言過程是從事件程序內部調用的,這個事件程序必須鎖定數據結構以使事件隊列在多線程環境中是一致的。
 
      斷言過程以及其相關的參數是:
      Bool (*predicate)(display, event, arg )
        Display *display ;
        XEvent *event ;
        char *arg ;
      display  指定到 X server 的連接。
      event  指定 XEvent 結構。
      arg  指定從 XIfEvent、XCheckIfEvent、或者 XPeekIfEvent 函數中傳送入的參數。
      隊列中的每一個事件都調用斷言過程一次,直到它找到一個匹配的事件。找到匹配的以後,斷言過程必須返回 True。如果它不能找到匹配的,必須返回 False。
 
      爲了匹配事件,要檢查事件隊列,並且如果找到,用 XIfEvent 將事件從隊列中移出。
      XIfEvent(display, event_return, predicate, arg )
        Display *display ;
        XEvent *event_return ;
        Bool (*predicate )();
        char *arg ;
      display   指定到 X server 的連接。
      event_return   返回與相關結構匹配的事件。
      predicate   指定用來判斷隊列中的下一個事件是否匹配你所要的東西的過程。
      arg   指定由用戶補充,將會發送給斷言過程的參數。
      XIfEvent 函數只有當指定的斷言過程爲這個事件返回 True 纔算完成,這表示隊列中有一個事件匹配。如果 XIfEvent 阻塞等待另外的事件,那麼它刷新輸出緩衝區。XIfEvent 將匹配的事件從隊列中移去並且將結構複製到客戶程序補充的 XEvent 結構。
 
      爲匹配事件檢查隊列,而並不阻塞的話,使用 XCheckIfEvent。
      Bool XCheckIfEvent(display, event_return, predicate, arg )
        Display *display ;
        XEvent *event_return ;
        Bool (*predicate )();
        char *arg ;
      display   指定到 X server 的連接。
      event_return   返回與相關結構匹配的事件副本。
      predicate   指定用來判斷隊列中下一個事件是否匹配你想要的東西的過程。
      arg   指定由用戶補充,將發送給斷言過程的參數。
      當斷言過程找到一個匹配,XCheckIfEvent 複製匹配的事件到客戶程序補充的 XEvent 結構中並且返回 True。(這個事件已經從隊列中移出。)如果斷言過程沒有找到匹配的事件,XCheckIfEvent 返回 False,並且輸出緩衝區將被刷新。所有早先存放在隊列中的事件並不會被丟棄。
 
      爲了匹配事件檢查隊列而又不用將事件從隊列中移出,用 XPeekIfEvent。
      XPeekIfEvent(display, event_return, predicate, arg)
        Display *display;
        XEvent *event_return;
        Bool (*predicate)();
        char *arg;
 
 3. 使用窗口或者事件掩碼選擇事件
 
      XWindowEvent(display, w, event_mask, event_return )
        Display *display ;
        Window w ;
        long event_mask ;
        XEvent *event_return ;
 
      Bool XCheckWindowEvent(display, w, event_mask, event_return )
        Display *display ;
        Window w ;
        long event_mask ;
        XEvent *event_return ;
 
      XMaskEvent(display, event_mask, event_return )
        Display *display ;
        long event_mask ;
        XEvent *event_return ;
 
      Bool XCheckMaskEvent(display, event_mask, event_return )
        Display *display ;
        long event_mask ;
        XEvent *event_return ;
 
      Bool XCheckTypedEvent(display, event_type, event_return )
        Display *display ;
        int event_type ;
        XEvent *event_return ;
 
      Bool XCheckTypedWindowEvent(display, w, event_type, event_return )
        Display *display ;
        Window w ;
        int event_type ;
        XEvent *event_return ;
 
將事件放回隊列
 
      要將事件放回事件隊列,使用 XPutBackEvent。
 
      XPutBackEvent(display, event )
        Display *display ;
        XEvent *event ;
 
      XPutBackEvent 函數通過將事件複製到隊列中從而將事件放置在顯示的事件隊列的前頭。如果你讀取事件,然後決定你寧願稍候再去處理它,那麼這個函數可能比較有用。對你可以連續調用 XPutBackEvent 的次數沒有限制。
 
發送事件給其它應用程序
 
      要發送事件給指定的窗口,使用 XSendEvent。這個函數通常在 selection 的處理中。例如,當 selection 已經被轉換並且作爲 property 儲存的時候,selection 的擁有者應當使用 XSendEvent 來發送 SelectionNotify 事件給請求者。
 
      Status XSendEvent(display, w, propagate, event_mask, event_send )
        Display *display ;
        Window w ;
        Bool propagate ;
        long event_mask ;
        XEvent *event_send ;
      display   指定到 X server 的連接。
      w   指定事件要發送到的窗口、PointerWindow、或者 InputFocus。
      propagate   指定一個布爾值。
      event_mask   指定事件掩碼。
      event_send   指定要發送的事件。
 
      XSendEvent 函數標識目的地窗口,判斷哪一個客戶程序應當接受指定的事件,並且忽略任何活動的抓取。這個函數要求你發送一個事件掩碼。這個函數使用 w 參數所標識的目的地窗口如下:
  • 如果 w 是 PointerWindow,目的地窗口就是包含鼠標指針的窗口。
  • 如果 w 是 InputFocus 並且如果焦點窗口包含鼠標指針的話,目的地窗口就是包含鼠標指針的窗口;否則,目的地窗口就是焦點窗口。

      要判斷哪一個客戶程序應當接收指定的事件,XSendEvent 對於傳播參數的使用如下:

  • 如果 event_mask 是空集,事件應當發送給創建目的地窗口的客戶程序。如果客戶程序不再存在,就不用發送事件。
  • 如果 propagate 是 False,事件就會被髮送給將目的地選擇爲 event_mask 參數中任何事件類型的每一個客戶程序。
  • 如果 propagate 是 True 並且沒有客戶程序已經將目的地選擇爲 event_mask 中的任何事件類型,那麼對於一些已經選擇了 event_mask 中類型的客戶程序,並且對於類型在其 do-not-propagate-mask 中的不可干預窗口而言,目的地應當被最接近於目的地的祖先所取代。如果沒有這樣的窗口存在,或者說如果窗口是焦點窗口的祖先,並且 InputFocus 最初被指定作爲目的地,那麼事件不會發送給任何客戶程序。否則,事件會被傳播到將最終的目的地選擇爲 event_mask 中指定類型的每一個客戶程序。
      如果到包裝協議格式的轉換失敗的話, XSendEvent 返回零,否則返回非零。
 
      XSendEvent 可以生成 BadValue 和 BadWindow 錯誤。
 
KeyPress、KeyRelease、ButtonPress、ButtonRelease、MotionNotif
 
      root, event: WINDOW
      child: WINDOW or None
      same-screen: BOOL
      root-x, root-y, event-x, event-y: INT16
      detail: <see below>
      state: SETofKEYBUTMASK
      time: TIMESTAMP
 
      在某個鍵或者鼠標按鈕邏輯上改變了狀態的時候,或者在鼠標的指針邏輯上移動位置的時候生成這些事件。如果設備事件處理被凍結的話,這些邏輯改變的生成可能 滯後於物理上的改變。注意 所有的鍵都生成 KeyPress 和 KeyRelease,儘管這些鍵映射到編輯位。事件的來源是鼠標指針指進的窗口。接到報告相關事件的窗口是被調用的事件窗口。事件窗口是通過從源窗口開 始並且從第一個客戶程序在其上選擇有興趣的事件(所提供的沒有干預的窗口阻止通過在其 do-not-propgagate-mask 中包含事件類型進行的事件生成)的窗口開始逐層進行查找而來的。用於報告的實際窗口可以通過活動捕獲來進行修改,並且在鍵盤事件的情況下,可以通過焦點窗 口來修改。
 
      root 是源窗口的根窗口,並且 root-x 和 root-y 都是在事件發生時刻相對於根原點的鼠標指針座標。事件是事件窗口。如果事件窗口在同一個屏幕上是作爲根窗口,那麼 event-x 和 event-y 都是相對於事件窗口原點的鼠標指針座標。否則,event-x 和 event-y 都是零。如果源窗口是事件窗口的下級窗口,那麼孩子就被設置成作爲源窗口祖先的事件窗口的孩子。否則,它被設置爲 None。狀態組件給出了事件之前的按鈕和編輯鍵的邏輯狀態。細節的組件類型隨事件類型而變化:
 
Event Component
KeyPress, KeyRelease KEYCODE
ButtonPress, ButtonRelease BUTTON
MotionNotify {Normal, Hint}
 
      MotionNotify 事件只是在窗口中的運動開始和結束時生成。運動事件的粒度並不能保證,但是客戶程序對運動事件的選擇保證在鼠標指針移動並且休息的時候至少得到一個事件。 選擇 PointerMotion 接收事件獨立於鼠標指針的狀態。通過選擇一些 Button[1-5]Motion 的子集來代替,MotionNotify 事件將只會在一個或者多個指定的按鈕被按下時纔會接收到。通過選擇 ButtonMotion,MotionNotify 事件將只是在至少有一個按鈕被按下時就會接收到。類型總是 MotionNotify 的事件獨立於選擇。如果 PointerMotionHint 被選擇,那麼服務器會自由地只爲事件窗口發送一個 MotionNotify 事件(帶有詳細的 Hint)給客戶程序,指針離開事件窗口,或者客戶程序發起 QueryPointer 或者 GetMotionEvents 請求。
 
選擇事件
 
      有兩種途徑來選擇你希望報告給你的客戶程序的事件。一是在你調用 XCreateWindow 和 XChangeWindowAttributes 的時候設置 XSetWindowAttributes 結構的 event_mask 成員。另一個是使用 XSelectInput。
 
      XSelectInput(display, w, event_mask)
        Display *display;
        Window w;
        long event_mask;
 
      XSelectionInput 函數請求 X server 提供與指定的事件掩碼相關的事件。最初,X 將不會報告任何這些事件。報告與窗口相關的事件。如果窗口並不對設備事件感興趣,它通常傳播到感興趣的最近的祖先,除非 do-not-propagate 掩碼禁止了它。
 
      設置窗口的事件掩碼屬性會覆蓋任何以前對相同窗口的屬性設置調用,而不是對其它的客戶程序。多個客戶程序可能對相同窗口選擇相同的事件有以下的限制:
  • 多個客戶程序在相同的窗口上選擇事件,因爲它們的事件掩碼是不脫節的。當 X server 生成一個事件時,它會將這個事件報告給所有感興趣的客戶程序。
  • 一次只有一個客戶程序可以選擇 CirculateRequest、ConfigureRequest 或者 MapRequest 事件,這些是與事件掩碼 SubstructureRedirectMask 相關的。
  • 一次只有一個客戶程序可以選擇 ResizeRequest 事件,它與事件掩碼 ResizeRedirectMask 相關。
  • 一次只有一個客戶程序可以選擇與事件掩碼 ButtonPressMask 相關的 ButtonPress 事件。
      服務器報告事件給所有感興趣的客戶程序。
 
      XSelectInput 可以生成一個 BadWindow 錯誤。 
 
鼠標指針的剝奪
 
      Xlib 提供了用於控制來自指針輸入的函數,通常是鼠標的指針。窗口管理器最經常使用這些功能來實現某些用戶接口的風格。一些工具箱也需要將這些功能用於某些特殊用途。
 
      通常,一旦鍵盤和鼠標事件發生,X server 將它們遞送給恰當的客戶程序,這個客戶程序由窗口和輸入焦點所決定。X server 在事件遞送方面提供足夠的控制以允許窗口管理器來進一步支持鼠標以及不同的其它用戶接口風格。許多這些用戶接口中取決於事件的同步遞送,鼠標指針和鍵盤事 件的遞送可以單獨地進行控制。
 
      當鼠標按鈕或者鍵盤按鍵被剝奪後,事件將被髮送到剝奪它們的客戶程序而不是正常情況下應該接收到它們的客戶程序。如果鍵盤或者鼠標指針處於異步模式下,後 續的鼠標和鍵盤事件將繼續被處理。如果鍵盤或者鼠標指針處於同步模式,就沒有進一步的事件要處理,直到剝奪的客戶程序允許事件(參見 XAllowEvents)。在這段時間間隔內,鍵盤和鼠標指針認爲是被凍結的。觸發這個剝奪的事件也可以重放。
 
      注意如果設備事件處理被凍結的話,設備的邏輯狀態(正如客戶應用程序所看到)可能滯後於其物理狀態
 
      有兩種類型的剝奪:主動的和被動的。主動的剝奪發生在單個的客戶顯式地剝奪鍵盤或者鼠標指針(參見 XGrabPointer 和 XGrabKeyboard)的時候。被動的剝奪發生在客戶程序在某個窗口中剝奪某個特定的鍵盤按鍵或者鼠標按鈕,並且剝奪將會在這個按鍵或者按鈕真正被 按下的時候被激活。被動剝奪對於實現可靠的彈出菜單來說是很便利的。例如,你可以保證彈出是通過剝奪某個按鈕請求的同步行爲在鬆開指針按鈕之前被映射。按 下事件將會觸發剝奪並凍結指針事件的進一步處理,直到你有機會去映射彈出窗口。
 
      對於許多操作來說,有一些函數接受一個時間參數。X server 在不同的事件中包括一個時間戳。有一個稱爲 CurrentTime 的特殊時間表示當前的服務器時間。X server 在輸入焦點最後被改變時,在鍵盤最後被剝奪時,在鼠標指針最後被剝奪時,或者在某個 selection 最後被改變時維護這個時間。你的應用程序對某個事件的反應可能會慢。你常常需要用一些辦法來指定在另一個應用程序控制鍵盤、指針或者 selection 的期間,你的請求不應當發生。通過在請求中提供來自事件的時間戳,如果某個人在這期間已經另外執行了一個操作,你可以安排這個操作並不生效。
 
      時間戳是一個以毫秒錶達的時間值。它一般是自最後一次服務器重置起的時間。時間戳評估時間段(大約在 49.7 天之後)。服務給出它的由時間戳 T 表示的當前時間,總是通過將時間戳空間的一半視爲在時間上比 T 要遲的方式解釋來自客戶程序的時間戳。命名爲 CurrentTime 的時間戳值從不會由服務器生成。這個值被保留用於表示當前服務器時間的請求中。
 
      對於在這一部分的許多函數中,你發送鼠標指針事件掩碼位。有效的指針事件掩碼位是:ButtonPressMask、 ButtonReleaseMask、EnterWindowMask、LeaveWindowMask、PointerMotionMask、 PointerMotionHintMask、Button1MotionMask、Button2MotionMask、 Button3MotionMask、Button4MotionMask、Button5MotionMask、ButtonMotionMask 以及 KeyMapStateMask。對於本部分中的其它函數,它發送按鍵掩碼位。有效的按鍵掩碼位是:ShiftMask、LockMask、 ControlMask、Mod1Mask、Mod2Mask、Mod3Mask、Mod4Mask 以及 Mod5Mask。
 
      要剝奪鼠標指針,使用 XGrabPointer。
 
      int XGrabPointer(display, grab_window, owner_events, event_mask, pointer_mode, keyboard_mode, confine_to, cursor, time )
        Display *display ;
        Window grab_window ;
        Bool owner_events ;
        unsigned int event_mask ;
        int pointer_mode , keyboard_mode ;
        Window confine_to ;
        Cursor cursor ;
        Time time ;
      display   指定到 X server 的連接。
      grab_window   指定剝奪的窗口。
      owner_events   指定一個布爾值表示是否照常報告指針事件或者如果是通過事件掩碼選擇的話,遵照剝奪窗口來報告。
      event_mask  指定哪些指針事件要被報告給客戶程序。掩碼是有效鼠標指針事件掩碼位的“或”(OR)位運算。
      pointer_mode  指定進一步的鼠標指針事件處理。你可以發送 GrabModeSync 或者 GrabModeAsync。
      keyboard_mode  指定鍵盤事件的進一步處理。你可以發送 GrabModeSync 或者 GrabModeAsync。
      confine_to  指定限制鼠標指針的窗口或者 None。
      cursor  指定在剝奪期間顯示的光標或者 None。
      time  指定時間,你可以發送一個時間戳或者 CurrentTime。
 
      XGrabPointer 函數主動地剝奪鼠標指針的控制並且如果剝奪成功的話返回 GrabSuccess。進一步的鼠標指針事件只報告給進行剝奪的客戶程序。XGrabPointer 通過這個客戶程序覆蓋任何主動的剝奪。如果 owner_events 是 False,報告關於 grab_window 的所有生成指針事件並且只報告通過 event_mask 選擇的事件。如果 owner_events 是 True 並且如果生成的指針事件會正常地報告給這個客戶程序的話,它就照常報告。否則,報告產於 grab_window 的事件並且只報告由 event_mask 選擇的事件。對於 owner_events 的兩個值的任何一個來說,沒有報告的事件都被丟棄。
 
      如果 pointer_mode 是 GrabModeAsync,指針事件處理照常繼續。如果指針當前被這個客戶程序凍結,對於指針的事件處理就被掛起。如果 pointer_mode 是 GrabModeSync,作爲客戶應用程序來看,指針的狀態看來是凍結的,並且 X server 並不進一步地生成指針事件,直到進行剝奪的客戶程序調用 XAllowEvents 或者直到指針的剝奪被釋放。當鼠標指針被凍結時,實際上的指針改變並不會丟失;它們被簡單地放置在服務器的隊列中以備後來處理。
 
      如果 keyboard_mode 是 GrabModeAsync,鍵盤事件處理不會因剝奪的激活所影響。如果 keyboard_mode 是 GrabModeSync,作爲客戶應用程序來看,鍵盤的狀態看來是凍結的,並且 X server 不會生成進一步的事件,直到進行剝奪的客戶程序調用 XAllowEvents 或者直到指針的剝奪被釋放。當鼠標指針被凍結的時候,實際上的鍵盤改變並不會丟失;它們被簡單地放置在服務器的隊列中以備後來處理。
 
      如果指定了光標,它就會被顯示,而不管鼠標指針指在什麼窗口內。如果指定的是 None,當指針指向 grab_window 或者其子窗口之一時,顯示用於這個窗口的正常光標;否則,顯示用於 grab_window 的光標。
 
      如果指定了 confine_to 窗口,指針被限制停留在包含它的那個窗口內。這個 confine_to 窗口需要與 grab_window 沒有任何關係。如果指針最初並不在 confine_to 窗口中,在剝奪激活之前它就自動地被最近的邊界所彎曲,並且進入/離開事件照常生成。如果 confine_to 窗口隨後被重新配置,指針就被自動彎曲,作爲必要的條件,要將其保持在包含它的窗口中。
 
      參數 time 允許你去避免某些在如果應用程序花費了較長的時間進行響應下或者如果有較長的網絡延遲下出現的情況。考慮你有兩個應用程序的情況,這兩個應用程序在點擊的 時候正常地剝奪指針。如果這兩個應用程序指定了來自事件的時間戳,第二個應用程序可能會更快地喚醒並且在第一個程序之前成功地剝奪指針。第一個應用程序然 後將會得到一個其它應用程序在它的請求被處理之前已經剝奪了指針的標誌。
 
      XGrabPointer 生成 EnterNotify 和 LeaveNotify 事件。
 
      如果 grab_window 或者 confine_to 窗口並不是可視的,或者如果 confine_to 窗口完全位於根窗口的邊界之外,XGrabPointer 失敗並且返回 GrabNotViewable。如果指針被某些其它的客戶程序主動地剝奪,它會失敗並且返回 AlreadyGrabbed。如果鼠標指針被其它應用程序的某個剝奪所凍結,它會失敗並且返回 GrabFrozen。如果指定的時間早於 last-pointer-grab 時間或者遲於當前 X server 的時間,它會失敗並且返回 GrabInvalidTime。否則,last-pointer-grab 時間被設置爲指定的時間(CurrentTime 被當前 X server 時間所取代)。
 
      XGrabPointer 可以生成 BadCursor、BadValue、和 BadWindow 錯誤。
 
      要取消剝奪指針,使用 XUngrabPointer。
 
      XUngrabPointer(display, time )
        Display *display ;
        Time time ;
      display   指定到 X server 的連接。
      time   指定時間。你可以發送一個時間戳或者 CurrentTime。
 
      如果這個客戶程序通過 XGrabPointer、XGrabButton、或者某個一般的鍵被按下來主動地剝奪,XUngrabPointer 函數釋放指針和任何排進隊列的事件。如果指定的時間早於 last-pointer-grab 或者晚於當前 X server 的時間,XUngrabPointer 並不釋放指針。它也生成 EnterNotify 和 LeaveNotify 事件。如果主動的指針剝奪的事件窗口或者 confine_to 窗口變成不可視的或者如果窗口的重新配置引起 confine_to 窗口完全處於根窗口的邊界之外的話,X server 自動地執行一個 UngrabPointer 請求。
 
      要改變激活的指針剝奪,使用 XChangeActivePointerGrab。
 
      XChangeActivePointerGrab(display, event_mask, cursor, time )
        Display *display ;
        unsigned int event_mask ;
        Cursor cursor ;
        Time time ;
      display   指定到 X server 的連接。
      event_mask   指定哪些指針事件被報告給客戶程序。掩碼是有效指針事件掩碼位的“或”(OR)運算。
      cursor   指定要被顯式的光標或者 None。
      time   指定時間。你可以發送時間戳或者 CurrentTime。
 
      如果鼠標指針主動地被客戶程序所剝奪並且如果指定的時間不早於 last-pointer-grab 並且不晚於當前的 X server 的時間,那麼 XChangeActivePointerGrab 函數改變指定的動態參數。這個函數對於 XGrabButton 的被動參數不起作用。對於 event_mask 和 cursor 的解釋和在上面說明的 XGrabPointer 中一樣。
 
      XChangeActivePointerGrab 可以生成 BadCursor 和 BadValue 錯誤。
 
      要剝奪鼠標指針的按鈕,使用 XGrabButton。
 
      XGrabButton(display, button, modifiers, grab_window, owner_events, event_mask, pointer_mode, keyboard_mode, confine_to, cursor)
        Display *display;
        unsigned int button;
        unsigned int modifiers;
        Window grab_window;
        Bool owner_events;
        unsigned int event_mask;
        int pointer_mode, keyboard_mode;
        Window confine_to;
        Cursor cursor;
      display  指定到 X server 的連接。
      button  指定要被剝奪的指針按鈕或者 AnyButton。
      modifier  指定一組按鍵掩碼或者 AnyModifier。這個掩碼是有效的按鍵掩碼位的“或”(OR)運算。
      grab_window  指定剝奪窗口
      owner_events  指定一個布爾值標識指針事件是否照常報告或者只報告由事件掩碼選擇的關於剝奪窗口的事件。
      event_mask  指定哪些事件要報告給客戶程序。掩碼是有效指針事件掩碼位的或(OR)運算。
      pointer_mode  指定鼠標指針事件的進一步處理。你可以發送 GrabModeSync 或者 GrabModeAsync。
      keyboard_mode  指定鍵盤事件的進一步處理。你可以發送 GrabModeSync 或者 GrabModeAsync。
      confine_to  指定窗口以限制鼠標指針的指向或者 None。
      cursor  指定要被顯示的光標或者 None。
 
      XGrabButton 函數建立一個被動的剝奪。以後,指針被主動剝奪(用 XGrabPointer),last-pointer-grab 時間被設置爲按鈕被按下的時間(在 ButtonPress 事件中傳送),並且如果下列所有的條件值都是真的話,ButtonPress 事件就被報告:
  • 指針沒有被剝奪,並且指定的按鈕邏輯上是當指定的編輯(modifier)鍵被邏輯上按下時才被按下,並且沒有其它按鈕或者編輯鍵邏輯上被按下。
  • 這個 grab_window 包含鼠標指針。
  • 這個 confine_to 窗口(如果有)是可視的。
  • 在相同的按鈕/按鍵組合上的被動剝奪並不會存在於 grab_window 的任何祖先窗口上。
 
      剩餘參數的解釋與 XGrabPointer 一樣。主動的剝奪在當鼠標指針的邏輯狀態上所有的按鈕都被釋放時自動地終止(獨立於邏輯編輯鍵的狀態)。
 
      注意如果設備事件處理被凍結的話,設備的邏輯狀態(作爲客戶應用程序來看)可能滯後於物理狀態。
 
      這個請求會覆蓋所有通過相同的客戶程序在相同窗口上的用相同的按鈕/按鍵組合產生的所有以前的剝奪。值爲 AnyModifier 的編輯標誌等於發起對所有可能編輯標誌組合(包括非編輯標誌的組合)的剝奪。並不要求指定的所有編輯標誌當前都被指派了 KeyCode。值爲 AnyButton 的按鈕等於發起對所有可能按鈕的請求。否則不要求指定的按鈕當前被指派了一個物理按鈕。
 
      如果一些其它的客戶程序已經用相同的按鈕/按鍵組合在相同的窗口上發起了一個 XGrabButton,那麼會產生一個 BadAccess 錯誤。當使用 AnyModifier 或者 AnyButton 時,如果有對於任何組合有衝突的剝奪的話,那麼請求會完全失敗,並且產生一個 BadAccess 錯誤(沒有建立起剝奪)。XGrabButton 對於主動的剝奪沒有作用。
 
      XGrabButton 可以生成 BadCursor、BadValue、以及 BadWindow 錯誤。
 
      要取消對指針按鈕的剝奪,使用 XUngrabButton。
 
      XUngrabButton(display, button, modifiers, grab_window)
        Display *display;
        unsigned int button;
        unsigned int modifiers;
        Window grab_window;
      display  指定到 X server 的連接。
      button  指定 要被釋放的按鈕或者 AnyButton。
      modifiers  指定一組按鍵掩碼或者 AnyModifier。掩碼是有效位按鍵掩碼位的或(OR)運算。
      grab_window  指定剝奪窗口。
 
      如果窗口被這個客戶程序剝奪的話,XUngrabButton 函數釋放在指定窗口上的被動按鈕/按鍵組合。值爲 AnyModifier 的編輯標誌等於發起對所有可能的編輯組合的取消剝奪請求。值爲 AnyButton 的按鈕等於發起對所有可能按鈕的請求。XUngrabButton 對於主動的剝奪沒有作用。
 
      XUngrabButton 可以生成 BadValue 和 BadWindow 錯誤。
 
鍵盤剝奪
 
      Xlib 提供用於剝奪和取消剝奪鍵盤以及允許事件的函數。
 
      int XGrabKeyboard(display, grab_window, owner_events, pointer_mode, keyboard_mode, time )
        Display *display ;
        Window grab_window ;
        Bool owner_events ;
        int pointer_mode , keyboard_mode ;
        Time time ;
      display   指定到 X server 的連接。
      grab_window   指定剝奪窗口。     
      owner_events   指定一個布爾值指示鍵盤事件是否照常報告。
      pointer_mode   指定進一步的指針事件處理。你可以發送 GrabModeSync 或者 GrabModeAsync。
      keyboard_mode   指定進一步的鍵盤事件處理。你可以發送 GrabModeSync 或者 GrabModeAsync。
      time   指定時間。你可以發送一個時間戳或者 CurrentTime。
 
      XUngrabKeyboard(display, time )
        Display *display ;
        Time time ;
      display   指定到 X server 的連接。
      time   指定時間。你可以發送時間戳或者 CurrentTime。
 
      要被動地剝奪鍵盤的某個鍵,使用 XGrabKey。
 
      XGrabKey(display, keycode, modifiers, grab_window, owner_events, pointer_mode, keyboard_mode)
        Display *display;
        int keycode;
        unsigned int modifiers;
        Window grab_window;
        Bool owner_events;
        int pointer_mode, keyboard_mode;
      display  指定到 X server 的連接。
      keycode  指定 KeyCode 或者 AnyKey。
      modifiers   指定一組按鍵掩碼或者 AnyModifer。掩碼是有效按鍵掩碼位的或(OR)運算。
      grab_window  指定剝奪窗口。
      owner_events  指定一個布爾值來標識鍵盤事件是否照常報告。
      pointer_mode  指定對指針事件的進一步處理。你可以發送 GrabModeSync 或者 GrabModeAsync。
      keyboard_mode  指定對鍵盤事件的進一步處理。你可以發送 GrabModeSync 或者 GrabModeAsync。
 
      要取消剝奪一個按鍵,使用 XUngrabKey。
 
      XUngrabKey(display, keycode, modifiers, grab_window )
        Display *display ;
        int keycode ;
        unsigned int modifiers ;
        Window grab_window ;
      display   指定到 X server 的連接。
      keycode   指定 KeyCode 或者 AnyKey。
      modifiers   指定一組按鍵掩碼或者 AnyModifier。掩碼是有效按鍵掩碼位的或(OR)運算。
      grab_window   指定剝奪窗口。
 
      爲了允許進一步的事件在設置被凍結時可以被處理,使用 XAllowEvents。
 
      XAllowEvents(display, event_mode, time)
        Display *display;
        int event_mode;
        Time time;
      display  指定到 X server 的連接。
      event_mode  指定事件模式。你可以發送 AsyncPointer、SyncPointer、AsyncKeyboard、SyncKeyboard、ReplayPointer、 ReplayKeyboard、AsyncBoth、或者 SyncBoth。
      time  指定時間。你可以發送一個時間戳或者 CurrentTime。
 
      如果客戶程序已經引起設備凍結,那麼 XAllowEvents 函數釋放一些放入隊列的事件。如果指定的時間早於針對客戶程序的最近一次主動剝奪的 last-grab-time 或者如果指定的時間晚於當前 X server 的時間,那麼它沒有作用。取決於 event_mode 參數,會發生下列的情況:
 
AsyncPointer 如果指針是被客戶程序所凍結,指針事件處理照常繼續。如果指針被客戶程序以兩次分開的剝奪的形式凍結兩次,AsyncPointer 爲這兩次凍結解凍。如果指針並沒有被客戶程序凍結,AsyncPointer 沒有作用,但是指針不需要由客戶程序來剝奪。
SyncPointer 如果指針是被客戶程序所凍結並且是主動地剝奪,指針事件處理照常繼續,直到十一個 ButtonPress 或者 ButtonRelease 事件報告給客戶程序。在此時,指針再次出現凍結。不過,如果報告的事件引起指針剝奪被釋放,那麼指針並不會凍結。如果指針沒有被客戶程序所凍結或者如果指 針沒有被客戶程序所剝奪,那麼 SyncPointer 就沒有作用。
ReplayPointer 如果指針是被客戶程序主動地剝奪,並且作爲發送到客戶程序的某個事件的結果而被凍結(來自 XGrabButton 的激活或者來自前一個具有模式 SyncPointer 的 XAllowEvents,而不是來自 XGrabPointer),那麼指針剝奪被釋放並且事件被完全重新處理。不過,此時,函數忽略在剝奪剛剛被釋放的 grab_window 或者其上(到根窗口)窗口的任何被動的剝奪。如果指針並沒有被客戶程序剝奪或者如果指針並沒有作爲某個事件的結果而被凍結,那麼請求就沒有作用。
AsyncKeyboard 如果鍵盤是被客戶程序所凍結,鍵盤事件處理照常繼續。如果鍵盤被客戶程序以兩次分開的剝奪的形式凍結兩次,AsyncKeyboard 爲這兩次凍結解凍。如果鍵盤並沒有被客戶程序凍結,AsyncKeyboard 沒有作用,但是指針不需要由客戶程序來剝奪。
SyncKeyboard 如果鍵盤是被客戶程序所凍結並且是主動地剝奪,鍵盤事件處理照常繼續,直到十一個 KeyPress 或者 KeyRelease 事件報告給客戶程序。在此時,鍵盤再次出現凍結。不過,如果報告的事件引起鍵盤剝奪被釋放,那麼鍵盤並不會凍結。如果鍵盤沒有被客戶程序所凍結或者如果鍵 盤沒有被客戶程序所剝奪,那麼 SyncKeyboard 就沒有作用。
ReplayKeyboard 如果鍵盤是被客戶程序主動地剝奪,並且作爲發送到客戶程序的某個事件的結果而被凍結(來自 XGrabKeyboard 的激活或者來自前一個具有模式 SyncKeyboard 的 XAllowEvents,而不是來自 XGrabKeyboard),那麼指針剝奪被釋放並且事件被完全重新處理。不過,此時,函數忽略在剝奪剛剛被釋放的 grab_window 或者其上(到根窗口)窗口的任何被動的剝奪。如果鍵盤並沒有被客戶程序剝奪或者如果鍵盤並沒有作爲某個事件的結果而被凍結,那麼請求就沒有作用。
SyncBoth 如果指針和鍵盤兩者都是被客戶程序所凍結,對於這兩個設備的事件處理照常,直到下一個 ButtonPress、ButtonRelease、KeyPress、或者 KeyRelease 事件報告給爲了剝奪某個設備(按鈕事件用於指針,按鍵事件用於鍵盤)的客戶程序,在此時設備再次出現凍結。不過,如果報告的事件引起剝奪被釋放,然後設備 並不凍結(但是如果其它的設備仍然被剝奪的話,那麼對於它的後續事件將仍然引起這兩個設備凍結)。SyncBoth 沒有影響,除非指針和鍵盤都被客戶程序凍結。如果指針或者鍵盤是被客戶程序以兩次分開的剝奪的方式凍結兩次的話,SyncBoth 爲這兩次凍結解凍(但是以後對於 SyncBoth 的凍結將只凍結每個設備一次)。
AsyncBoth 如果指針和鍵盤都是被客戶程序所凍結的話,對於這兩個設置的事件處理照常。如果某個設備被客戶程序以兩次分開剝奪的方式凍結了兩次的話,AsyncBoth 爲這兩次凍結解凍。AsyncBoth 沒有影響,除非指針和鍵盤都是被客戶程序所凍結。
 
      AsyncPointer、SyncPointer、和 ReplayPointer 對於鍵盤事件的處理沒有作用。AsyncKeyboard、SyncKeyboard、和 ReplayKeyboard 對於指針事件的處理沒有作用。同時激活對於指針的剝奪和鍵盤的剝奪(被相同或者不同的客戶程序)這兩者是可能的。如果某個設備以其中任何一種剝奪方式的行 爲而被凍結,對於這個設備而言沒有事件處理要被執行。對於單個設備而言因爲兩種剝奪而被凍結是有可能的。在這種情況下,在事件可以被再次處理之前,代表兩 種剝奪的凍結必須被釋放。如果某個設備被單個客戶程序凍結兩次,那麼單個的 AllowEvents 釋放這兩次凍結。
 
      XAllowEvents 可以生成 BadValue 錯誤。 
 
服務器的剝奪
 
      Xlib 提供用於剝奪和取消剝奪服務器的函數。這些函數可以用於控制通過窗口系統服務器到其它連接上的輸出處理。當服務器被剝奪時,並沒有請求的處理或者任何其它 連接關閉會發生。客戶程序對其連接的自動關閉取消對服務器的剝奪。儘管非常不鼓勵剝奪服務器,它有時是必要的。
 
      要剝奪服務器,使用 XGrabServer。
 
      XGrabServer(display)
        Display *display;
      display  指定到 X server 的連接。
 
      XGrabServer 函數禁止對請求的處理並且關閉除這個請求所到達的連接之外的所有其它連接。除非絕對必要,你不應當剝奪服務器。
 
      要取消剝奪服務器,使用 XUngrabServer。
 
      XUngrabServer(display)
        Display *display;
      display  指定到 X server 的連接。
 
      XUngrabServer 函數重新開始請求的處理並關閉其它的連接。你應當儘可能地避免剝奪服務器。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章