2011-11-18 6 views
16

बिना X11 कार्यक्रम से बाहर जाते हैं मैं एक काफी सरल "नमस्ते दुनिया" 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. 

अद्यतन

एक्सपेंडिंग() के लूप को चलाने की तरह कई चीजों को बदलने की कोशिश की। किसी और के hello world चलाने का निर्णय लिया और मुझे उनके कोड के साथ एक ही समस्या मिलती है। मेरे सेटअप के साथ कुछ गलत होना चाहिए।

अद्यतन स्पष्ट रूप से बहुत से लोगों को यह समस्या है। Google ftk में यह समस्या थी और उन्होंने इसे change log में ठीक किया। वे FTK_QUIT() को कॉल करते हैं जिन्हें मैं अनुमान लगा रहा हूं जैसे बाहर निकलें()। तो मैंने लूप के अंदर वहां अपनी वापसी डाली और समस्या को हल किया। यकीन नहीं है कि क्यों किया लेकिन यह किया। निश्चित कोड:

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

अभी भी किसी को सही जवाब है जो क्यों और यदि संभव हो तो है ले जाने के वापसी कथन (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 बयान कोड काम नहीं करता है में चल रहा है। भले ही यह किसी अन्य एक्स फ़ंक्शन को कॉल किए बिना लूप से बाहर निकल जाए। आपके switch कथन से पहले if कथन ऊपर दिए गए कथन को लूप के अंदर प्रोग्राम से वापस किए बिना समस्या को हल करता है।

+0

लूप से बच निकला क्योंकि एहसास हुआ कि यह कभी भी टूट नहीं जाता है। अभी भी एक ही त्रुटि संदेश। –

+0

आप सीधे X11 प्रोग्रामिंग क्यों करना चाहते हैं? मैं दृढ़ता से ग्राफ़िकल टूलकिट का उपयोग करने की अनुशंसा करता हूं, जैसे जीटीके या क्यूटी (लेकिन अन्य भी हैं: FLTK, फॉक्स ...) –

+0

@Starynkevitch यह समझने के लिए और अधिक काम करता है। काम या स्कूल के लिए नहीं। –

उत्तर

16

इस समस्या का समाधान स्पष्ट है:

आप XDestroyWindow() फ़ंक्शन के साथ सही संरचना सदस्य उपयोग करना चाहिए।

एक्स 11 घटना संरचनाओं के कार्यान्वयन मानक के कारण, वे एक-दूसरे के समान हैं। प्रत्येक संरचना 'प्रकार' सदस्य के साथ शुरू होती है, और पहले सदस्य व्यावहारिक रूप से वही होते हैं।

अब मान:

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 बाइट दूर होंगे।

चूंकि आप XDestroyWindow() को गलत विंडो तर्क के साथ कॉल करने जा रहे हैं, तो यह असफल हो जाएगा। इसके बजाय यदि आप इसे e.xdestroywindow.event (जो घटना संरचना की शुरुआत से 24 बाइट दूर है) का उपयोग करते हुए कॉल करते हैं, तो पता सही होगा और समारोह शानदार ढंग से काम करेगा।

आप एक Xlib.h फ़ाइल पर अपने आप को देखने के लिए लेते हैं, तो आप देखेंगे कि दो संरचनाओं खिड़की तत्व अलग ढंग से तैनात की है।

यह बताते हुए, याद रखें कि Xlib वर्षों से विकसित किया गया है और कई प्रोग्रामर हर दिन इसके साथ काम करते हैं, इसलिए यदि कोई रहस्यमय त्रुटि है, तो शायद यह एक्सलिब के भीतर नहीं है। आखिरी संकेत के रूप में मैं आपको बताना चाहता हूं: यदि आप एक्सलिब प्रोग्रामिंग के साथ आगे बढ़ना चाहते हैं, तो हमेशा हेडर फाइलों को प्राथमिक संदर्भ के रूप में लें, उसके बाद सिस्टम मैनुअल, फिर बाकी सभी।

अंत में अपने कोड के साथ ही त्रुटि है:

XDestroyWindow(display,e.xdestroywindow.window); 

कौन सा यह करने के लिए परिवर्तित किया जाना चाहिए:

XDestroyWindow(display,e.xclient.window); 

इसके बजाय स्विच के उपयोग अच्छा है, और सबसे है एक्स 11 कोड पर कोई समस्या नहीं के साथ लागू किया गया।

नोट: मैंने केवल उस पंक्ति को बदलकर, और फिर परिणाम प्रिंट करके विभिन्न परीक्षण कर अपने कोड का परीक्षण किया है।XDestroyWindow() लाइन निश्चित रूप से केवल त्रुटि है।

+0

+1 न केवल एक समाधान बल्कि समस्या/समाधान के _explanation_ के लिए। धन्यवाद। – tjklemz

3

बस ठीक XCloseDisplay() से पहले XDestroyWindow() कहते हैं।

संपादित करें:

क्षमा करें, मैं XSetWMProtocols बात समझ में नहीं आया। अब मैंने इसे पढ़ लिया है। मुझे लगता है कि आप इवेंट यूनियन के गलत सदस्य तक पहुंच रहे हैं।

XDestroyWindow (प्रदर्शन, e.xdestroywindow.window);

शायद होना चाहिए:

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

यह त्रुटि को ठीक नहीं करता है। –

+0

@JoeMcGrath मेरा जवाब बदल गया। गलत दिशा के लिए खेद है। –

+0

धन्यवाद, मैंने कुछ सीखा, भले ही समस्या ठीक न हो। कम से कम मेरे पास अभी सही विंडो हैंडल है। –

3

मुझे एक ही समस्या थी, और एक्सलिब दस्तावेज़ीकरण के माध्यम से खुदाई करने के बाद और मुझे लगता है कि मुझे लगता है कि मुझे आपके प्रश्न का उत्तर पता है और मैं इसे आपको समझा सकता हूं।

जब आप XCreateWindow या XCreateSimpleWindow और XMapWindow पर कॉल करते हैं, तो आप एक्स सर्वर को अपनी विंडो बनाने और स्क्रीन पर मानचित्र बनाने के निर्देश देते हैं। इन आदेशों को स्थानीय बफर से सर्वर पर भेजने के बाद (XFlush या किसी भी फ़ंक्शन को सर्वर से कुछ डेटा अनुरोध करने के बाद, क्योंकि यह निश्चित रूप से कमांड बफर को फ़्लश करता है), एक्स सर्वर आपकी विंडो प्रदर्शित करता है। फिर यह खिड़की प्रबंधक का काम है जो सभी सजावट को आपकी खिड़की पर संलग्न करता है, उदा। खिड़की को कम/अधिकतम/बंद करने के लिए कुछ सीमाएं, शीर्षक पट्टी, खिड़की मेनू और उन बटन।

अब आपकी विंडो प्रदर्शित की जा रही है, और थोड़ी देर के बाद आप XDestroyWindow के साथ इसे नष्ट करने का निर्णय ले सकते हैं और XCloseDisplay पर कॉल करके एक्स सर्वर से कनेक्शन बंद कर सकते हैं, और सब ठीक हो जाएगा, कोई त्रुटि नहीं।

समस्या यह है कि जब उपयोगकर्ता कि एक्स अपने विंडो के शीर्षक बार पर पर क्लिक करता है, यह X सर्वर इसे संभाल करने के लिए का काम नहीं है, लेकिन विंडो प्रबंधक की नौकरी (X सर्वर उन सजावट के बारे में कुछ नहीं जानता और यह परवाह नहीं है)। विंडो प्रबंधक की सामान्य प्रतिक्रिया जब उपयोगकर्ता आपके प्रोग्राम के शीर्ष-स्तरीय विंडो को बंद करता है तो विंडो को नष्ट कर देता है और X सर्वर से कनेक्शन बंद कर देता है, क्योंकि अधिकांश उपयोगकर्ता अपेक्षा करते हैं। आपका प्रोग्राम अभी भी ऑफ-स्क्रीन चला सकता है, लेकिन शीर्ष-स्तरीय विंडो आमतौर पर विंडो प्रबंधक द्वारा एक्स सर्वर कनेक्शन से जुड़ी होती है।

तो जब विंडो प्रबंधक आपकी विंडो को नष्ट कर देता है, तो आप XDestroyWindow पर कॉल नहीं कर सकते हैं, क्योंकि विंडो पहले ही नष्ट हो चुकी है और इसकी Window हैंडल अमान्य है। आपको BadWindow के बारे में त्रुटि मिलेगी। आप XCloseDisplay पर भी कॉल नहीं कर सकते हैं, क्योंकि एक्स सर्वर से कनेक्शन पहले ही बंद हो चुका है, और इससे XIO: fatal IO error 11 (Resource temporarily unavailable) on X server त्रुटि हो जाएगी जो कई उपयोगकर्ताओं को उन अनुप्रयोगों से अनुभव करते हैं जिनके लेखकों को यह नहीं पता था। यह एक आम गलती है, क्योंकि एक तरफ आपको अपने आप को साफ करने के लिए प्रोत्साहित किया जाता है, लेकिन दूसरी ओर दस्तावेज इस बारे में भ्रामक है कि यह ठीक से कैसे किया जाना चाहिए।

एक सम्मेलन है, हालांकि, कैसे एक्स सर्वर और विंडो प्रबंधक को सहयोग करना चाहिए, जिसमें शीर्ष-स्तरीय विंडो को बंद करने के लिए उपयोगकर्ता के आदेशों का जवाब भी शामिल है। एक्स प्रोटोकॉल का एक विस्तार है जो इसे संभालता है। यहाँ कैसे Xlib documentation यह बताते है:

ग्राहकों, आम तौर पर अनेक शीर्ष स्तरीय खिड़कियां, जिसका सर्वर कनेक्शन उनका शीर्ष-स्तर खिड़कियों में से कुछ का विलोपन जीवित रहने चाहिए साथ उन लोगों के, WM_PROTOCOLS संपत्ति पर में परमाणु WM_DELETE_WINDOW शामिल होना चाहिए ऐसी प्रत्येक खिड़की। उन्हें ClientMessage ईवेंट प्राप्त होगा जैसा कि ऊपर वर्णित है data[0] फ़ील्ड WM_DELETE_WINDOW है।
[...]
WM_PROTOCOLS संपत्ति में WM_DELETE_WINDOW शामिल करने का विकल्प चुनने वाले ग्राहक सर्वर से डिस्कनेक्ट हो सकते हैं यदि उपयोगकर्ता क्लाइंट की शीर्ष-स्तरीय विंडो को हटाने के लिए कहता है।

तो इस समस्या का दो समाधान हैं: या तो XDestroyWindow और XCloseDisplay बुला जब अपने खिड़की खुद के द्वारा विंडो प्रबंधक द्वारा बंद कर दिया जा रहा है और नहीं से बचने के (आप वास्तव में शीर्ष स्तर के खिड़की साफ करने के लिए की जरूरत नहीं है चूंकि एक्स सर्वर इसे तब भी नष्ट कर देगा जब आपका प्रोग्राम समाप्त होता है), या आपको WM_DESTROY_WINDOW एक्सटेंशन पंजीकृत करने की आवश्यकता है और विंडो प्रबंधक से सूचना के लिए प्रतीक्षा करें जब उपयोगकर्ता द्वारा आपकी विंडो बंद करने के लिए निर्देश दिया जाता है (यह आपको ClientMessage ईवेंट भेज देगा , इसके data[0] पर WM_DELETE_WINDOW पर सेट किया गया है)। और इसे प्राप्त करने के बाद बस खिड़की को नष्ट कर दें और एक्स सर्वर से कनेक्शन बंद करें, और अपना प्रोग्राम समाप्त करें। या यदि आप चाहें तो इसके साथ कुछ और संचार करने के लिए एक्स सर्वर को कनेक्शन छोड़ दें। जब आप WM_DESTROY_WINDOW को संभालते हैं, तो विंडो प्रबंधक आपकी विंडो को नष्ट करने की कोशिश नहीं करेगा और न ही एक्स सर्वर से कनेक्शन बंद कर देगा।

संबंधित मुद्दे