2011-11-18 91 views
16

在問題結束時,我在X11中有一個相當簡單的「Hello World」。但是,它退出時,我得到以下運行時錯誤信息:如何退出X11程序沒有錯誤

$ ./xtest 
XIO: fatal IO error 11 (Resource temporarily unavailable) on X server ":0" 
     after 9 requests (7 known processed) with 0 events remaining. 

所以,我想處理wmDeleteMessage自己,我能夠從關閉停止窗口,所以我知道我得到正確的事件。比我添加一個XDestroyWindow()事件處理,我得到新的錯誤。

X Error of failed request: BadWindow (invalid Window parameter) 
    Major opcode of failed request: 4 (X_DestroyWindow) 
    Resource id in failed request: 0x130 
    Serial number of failed request: 12 
    Current serial number in output stream: 12 

這聽起來像我試圖破壞已毀窗口,但如果我拿出XDestroyWindow()它保持活着我的屏幕上。

下面是我試圖銷燬窗口處理程序的代碼。我如何退出而沒有任何錯誤?

#include<X11/Xlib.h> 
#include <iostream> 

int main() 
{ 
    Display *display; 
    if(!(display=XOpenDisplay(NULL))) 
    { 
     std::cerr << "ERROR: could not open display\n"; 
     return 1; 
    } 

    int screen = DefaultScreen(display); 
    Window rootwind = RootWindow(display, screen); 
    Colormap cmap = DefaultColormap(display, screen);  
    Atom wmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", False); 

    int blackColor = BlackPixel(display, screen); 
    int whiteColor = WhitePixel(display, screen); 

    Window w = XCreateSimpleWindow(display, rootwind, 0, 0, 200, 100, 0, blackColor, blackColor); 
    XMapWindow(display, w); 
    XSetWMProtocols(display, w, &wmDeleteMessage, 1); 
    bool running = true; 
    while(running) 
    { 
    XEvent e; 
    XNextEvent(display, &e);  
    switch (e.type) 
    { 
     case ClientMessage: 
     if(e.xclient.data.l[0] == wmDeleteMessage) 
     { 
      std::cout << "Shutting down now!!!" << std::endl; 
      XDestroyWindow(display,e.xdestroywindow.window); 
      running=false; 
      break; 
     } 
     break; 
    } 
    } 

    XCloseDisplay(display); 
    return 0; 
} 

更新

更改行:

std::cout << "Shutting down now!!!" << std::endl; 
     XDestroyWindow(display,w); 

我不喜歡,因爲我打算具有比窗口的更多,但現在我 回到第一我有錯誤信息:

XIO: fatal IO error 11 (Resource temporarily unavailable) on X server ":0" 
     after 9 requests (7 known processed) with 0 events remaining. 

更新

試圖改變許多事情,如循環運行XPending()。 決定運行其他人的hello world,我得到了與他們的代碼相同的問題。必須是我的設置有問題。

更新 顯然很多人都有這個問題。谷歌ftk有這個問題,他們修復了他們的change log。他們調用FTK_QUIT(),我猜測它就像Exit()。所以我把我的回報放在循環裏面,解決了問題。不知道爲什麼,但確實如此。固定碼:

case ClientMessage: 
    if(e.xclient.data.l[0] == wmDeleteMessage) 
    { 
     XDestroyWindow(display,e.xclient.window); 
     XCloseDisplay(display); 
     return 0; 
    } 

還是會給予正確答案的人誰可以解釋爲什麼,如果是可能的移動return語句(與XCloseDisplay一起)的循環之外。


事件循環應該是這樣的正確退出:

XEvent e; 
    do 
    { 
    XNextEvent(display, &e);  
    if(e.type == ClientMessage && e.xclient.data.l[0] == wmDeleteMessage) 
    { 
     XDestroyWindow(display,e.xclient.window); 
     break;  
    } 
    //... 
    }while (XPending(display) > 0) 
    XCloseDisplay(display); 
    return 0; 

當在switch語句的代碼不能正常工作運行。即使它退出循環而不調用另一個X函數。上面的if語句放在您的switch語句之前,可以解決問題,而不會從循環內的程序返回。

+0

增加了逃避循環,因爲意識到它從不發生。還是一樣的錯誤信息。 –

+0

爲什麼你想直接做X11編程?我強烈建議使用一個圖形工具包,比如GTK或Qt(但也有其他的:FLTK,Fox ...) –

+0

@Starynkevitch瞭解它是如何工作的。不適用於工作或學校。 –

回答

16

解決這個問題很簡單:

必須使用與XDestroyWindow()函數的權利結構成員。

由於X11事件結構的實現標準,它們彼此非常相似。每個結構都以「類型」成員開始,第一個成員幾乎總是相同的。

現在假設:

int = 4 bytes 
Bool = 4 bytes 
unsigned long = 8 bytes 
Display* = 8 bytes 
Window = 4 bytes 

如果你打電話XDestroyWindow()與e.xdestroywindow.window,你會從事件結構開始28個字節了,而如果你使用e.xclient.window,你會有24個字節。

由於您打算使用錯誤的Window參數調用XDestroyWindow(),它將失敗。相反,如果你使用e.xdestroywindow.event(它離事件結構開頭24字節)來調用它,那麼地址是正確的,並且該函數可以正常工作。

如果你把一個在Xlib.h文件來看一下吧,你會發現,這兩個結構具有不同定位的窗口元素。說到這一點,請記住Xlib已經開發多年了,許多程序員每天都在使用它,所以如果有一個神祕的錯誤,它可能不在Xlib中。作爲最後一個提示,我想告訴你:如果你希望進一步使用Xlib編程,總是把頭文件作爲主要參考,然後是系統手冊,然後是其餘的。

與最終代碼的唯一錯誤是:

XDestroyWindow(display,e.xdestroywindow.window); 

必須改成這樣:

XDestroyWindow(display,e.xclient.window); 

相反開關的使用是好的,而且是最在X11代碼中沒有問題。

注意:我已經測試了你自己的代碼,只改變了那一行,然後做了各種測試,打印結果。XDestroyWindow()行肯定是唯一的錯誤。

+0

+1不僅是解決方案,而且是解決問題的解決方案。謝謝。 – tjklemz

3

只需在XCloseDisplay()之前撥打XDestroyWindow()即可。

編輯:

對不起,我聽不懂的XSetWMProtocols事情。現在我讀了它。我認爲你正在訪問活動聯盟的錯誤成員。

XDestroyWindow(display,e.xdestroywindow.window);

大概應該是:

XDestroyWindow(display,e.xclient.window); 
+0

這並不能解決這個錯誤。 –

+0

@JoeMcGrath改變了我的答案。抱歉,誤導。 –

+0

謝謝,我學到了一些東西,儘管沒有解決問題。至少我現在有正確的窗口句柄。 –

3

我有同樣的問題,在深入挖掘Xlib文檔和大量實驗後,我想我知道你的問題的答案,我可以向你解釋。

當你調用XCreateWindowXCreateSimpleWindow,然後XMapWindow,您指示X Server來創建你的窗口,並映射到屏幕上。將這些命令從本地緩衝區發送到服務器之後(通過調用XFlush或從服務器請求某些數據的任何函數,因爲它隱式刷新命令緩衝區),X服務器顯示您的窗口。然後,窗口管理器的任務是將所有裝飾物附加到你的窗口,例如一些邊框,標題欄,窗口菜單以及用於最小化/最大化/關閉窗口的按鈕。

現在正在顯示你的窗口,並在一段時間後,你可以決定與XDestroyWindow摧毀它,並通過調用XCloseDisplay關閉到X服務器的連接,一切都會好起來的,沒有錯誤。

的問題是,當用戶點擊該X你的窗口的標題欄,它不是X服務器來處理它的工作,但窗口管理器的作業(X服務器一無所知的那些修飾它不關心)。當用戶關閉程序的頂級窗口時,窗口管理器通常會對銷燬窗口並關閉與X服務器的連接,因爲這是大多數用戶所期望的。您的程序仍可能在屏幕外運行,但頂層窗口通常與Window Manager的X Server連接相關聯。

所以當窗口管理器破壞你的窗口時,你不能調用XDestroyWindow,因爲窗口已經被銷燬,並且它的Window句柄無效。您將收到關於BadWindow的錯誤。您也不能撥打XCloseDisplay,因爲到X服務器的連接已關閉,這會導致很多用戶在作者不知道該應用程序的應用程序中遇到錯誤XIO: fatal IO error 11 (Resource temporarily unavailable) on X server。這是一個常見的錯誤,因爲一方面鼓勵你自己清理一下,另一方面,文檔會誤導這些應該如何正確完成。

雖然有一個關於X Server和Window Manager應該如何協作的約定,它還包括響應用戶關閉頂層窗口的命令。 X協議有一個擴展來處理它。下面是如何Xlib documentation解釋它:

客戶,通常是那些擁有多個頂級窗口,其服務器的連接必須生存他們的一些頂層窗口的缺失,應包括在WM_PROTOCOLS財產上的原子WM_DELETE_WINDOW每個這樣的窗口。他們將收到ClientMessage事件,如上所述,其data[0]字段爲WM_DELETE_WINDOW

如果用戶要求刪除某個客戶端的頂級窗口,那麼選擇不包含WM_DELETE_WINDOW屬於WM_PROTOCOLS屬性的客戶端可能會與服務器斷開連接。

所以有兩個解決問題的對策:要麼避免調用XDestroyWindowXCloseDisplay當通過窗口管理器關閉,你的窗口,而不是自己(你實際上沒有清理頂層窗口因爲X服務器會在你的程序結束時將其銷燬),或者你需要註冊WM_DESTROY_WINDOW擴展,並在用戶指示關閉窗口時等待來自窗口管理器的通知(它會向你發送ClientMessage事件,然後,其data[0]設置爲WM_DELETE_WINDOW)。收到它後,只需銷燬窗口並自行關閉與X服務器的連接,並結束程序。或者如果你願意的話,把X服務器的連接打開以便與它進行更多的通信。當您處理WM_DESTROY_WINDOW時,窗口管理器不會嘗試銷燬您的窗口,也不會關閉與X服務器的連接。

相關問題