c - Xlib और Firefox व्यवहार



x11 (1)

उपयोग xtruss - एक आसान करने के लिए उपयोग एक्स प्रोटोकॉल अनुरेखण कार्यक्रम

अवलोकन

किसी भी प्रोग्रामर को लिनक्स या सिस्टम वी-टाइप यूनिक्स पर प्रोग्राम लिखने का आदी हो गया है, जो प्रोग्राम को विभिन्न रूप से स्ट्रेस या ट्रस के रूप में जाना जाता है, जो दूसरे प्रोग्राम पर नजर रखता है और प्रोग्राम को बनाने वाले हर सिस्टम का एक विस्तृत लॉग बनाता है - दूसरे शब्दों में, सभी प्रोग्राम ओएस कर्नेल के साथ बातचीत। यह अक्सर एक अमूल्य डिबगिंग उपकरण है, और लगभग एक शैक्षिक एक के रूप में अच्छा है।

जब यह GUI प्रोग्राम (या यों कहें, GUI-संबंधित व्यवहार का प्रोग्राम) जिसे आप समझना या डीबग करना चाहते हैं, हालांकि, OS कर्नेल के साथ सहभागिता का स्तर शायद ही कभी सबसे उपयोगी होता है। अधिक सहायक रूप से, एक ही तरह से एक्स सर्वर के साथ प्रोग्राम के सभी इंटरैक्शन को लॉग करना चाहेंगे।

प्रोग्राम पहले से मौजूद हैं जो ऐसा करेंगे। मैं Xmon और Xtrace से वाकिफ हूं। लेकिन उन्हें स्थापित करने के लिए बहुत प्रयास करने की आवश्यकता होती है: आपको सुनने वाले सर्वर को स्थापित करने के लिए प्रोग्राम को चलाना होगा, फिर मैन्युअल रूप से वास्तविक सर्वर के बजाय संपर्क करने के लिए लक्ष्य कार्यक्रम की व्यवस्था करें - जिसमें xuth के साथ कुछ काम भी शामिल है। आदर्श रूप से, आप अपने कर्नेल सिस्टम कॉल को ट्रेस करने के लिए एक प्रोग्राम के एक्स ऑपरेशन को ट्रेस करना उतना ही आसान चाहेंगे: आप एक कमांड को स्ट्रेस प्रोग्राम नाम के तर्कों के रूप में सरल रूप में टाइप करना चाहते हैं, और आपके लिए सब कुछ स्वचालित रूप से संभाल लेंगे।

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

इसलिए यह पृष्ठ xtruss प्रस्तुत करता है, एक्स प्रोटोकॉल लॉगर के क्षेत्र में मेरा अपना योगदान है। इसमें स्ट्रेस के समान एक कमांड-लाइन सिंटैक्स है - इसके डिफ़ॉल्ट मोड में, आप अभी भी उसी कमांड लाइन के लिए "xtruss" उपसर्ग करते हैं, जो आप वैसे भी चलाएंगे - और इसका आउटपुट स्वरूप भी स्ट्रेस की तरह अधिक है, उसी पर अनुरोध और प्रतिक्रियाएं डालना। जहां संभव हो उत्पादन की लाइन।

स्ट्रेस पहले से चल रही प्रक्रिया से जुड़ने और इसके रन के बीच से इसे ट्रेस करने की सुविधा का भी समर्थन करता है - जब कोई चीज लंबे समय से चल रही प्रक्रिया के साथ कुछ गलत हो जाती है जो आपको पहले से पता नहीं था कि आपको ट्रेस करने की आवश्यकता है। xtruss इसी सुविधा का समर्थन करता है, X RECORD एक्सटेंशन के माध्यम से (बशर्ते आपका X सर्वर इसका समर्थन करता है, जो आधुनिक X.Org वाले करते हैं); तो उस मोड में, आप माउस के साथ एक विंडो (xwininfo और xkill जैसे मानक कार्यक्रमों के लिए) की पहचान कर सकते हैं, और xtruss एक्स क्लाइंट प्रोग्राम से संलग्न होगा जो आपके द्वारा निर्दिष्ट विंडो का मालिक है, और इसे ट्रेस करना शुरू करें।

विवरण

xtruss एक उपयोगिता है जो एक्स सर्वर और एक या अधिक एक्स क्लाइंट प्रोग्राम के बीच से गुजरने वाली हर चीज को लॉग करता है। इसमें यह xmon (1) के समान है, लेकिन इसका मतलब है कि xmon की मूल कार्यक्षमता को strace (1) के समान इंटरफ़ेस के साथ संयोजित करना।

Xmon की तरह, अपने डिफ़ॉल्ट मोड में xtruss एक प्रॉक्सी X सर्वर सेट करके काम करता है, जो कि कनेक्शन के लिए इंतजार कर रहा है, और उन्हें असली X सर्वर पर अग्रेषित करता है। हालांकि, एक्समोन के विपरीत, आपको हाथ से उस में से किसी से भी निपटने की ज़रूरत नहीं है: एक टर्मिनल में ट्रेस उपयोगिता शुरू करने और मैन्युअल रूप से इसे दूसरे से संसाधित करने की आवश्यकता नहीं है, जब तक कि आप वास्तव में नहीं चाहते हैं (किस मामले में - P विकल्प ऐसा करेगा)। उपयोग की मुख्य विधि आपके एक्स प्रोग्राम की कमांड लाइन के बाद xtruss टाइप करने के लिए है; xtruss अपने प्रॉक्सी सर्वर पर इंगित करने के लिए नए प्रोग्राम के वातावरण को समायोजित करने के लिए स्वचालित रूप से ध्यान रखेगा, और (xmon के विपरीत भी) यह स्वचालित रूप से X प्राधिकरण की देखभाल करेगा।

उपयोग के एक वैकल्पिक मोड के रूप में, आप xtruss को पहले से चल रहे X एप्लिकेशन से भी जोड़ सकते हैं, अगर आपको यह महसूस नहीं हुआ कि आप इसे तब तक ट्रेस करना चाहते हैं जब तक कि यह पहले से ही चालू न हो जाए। इस मोड को एक्स सर्वर से सहयोग की आवश्यकता है - विशेष रूप से, यह तब तक काम नहीं कर सकता है जब तक कि सर्वर RECORD प्रोटोकॉल एक्सटेंशन का समर्थन नहीं करता है - लेकिन चूंकि आधुनिक X.Org सर्वर इसे प्रदान करते हैं, यह अक्सर उपयोगी होता है।

मैं एक छोटा विंडो मैनेजर बनाने की कोशिश कर रहा हूं (सिर्फ मनोरंजन के लिए), लेकिन मुझे फ़ायरफ़ॉक्स द्वारा बनाई गई खिड़कियों को संभालने में समस्या आ रही है (केवल उस एप्लिकेशन के साथ, अन्य एप्लिकेशन ठीक काम करते हैं)

समस्या यह है कि फ़ायरफ़ॉक्स लॉन्च करने और अपनी सजावट जोड़ने के बाद, यह ठीक काम करने लगता है, लेकिन अगर उदाहरण के लिए मैं मेनू बटन पर क्लिक करने की कोशिश करता हूं, तो (उप) विंडो दिखाई नहीं देती है।

क्या प्रतीत होता है कि क्लिक करने के बाद, क्लायंट मेसेजेज ईवेंट को निम्न मानों के साथ निकाल दिया जाता है:

Data: (null)
Data: _NET_WM_STATE_HIDDEN
Data: (null)
Data: (null)
Data: (null)

अब समस्या यह है कि मैं नहीं जानता कि खिड़की, किस खिड़की को दिखाना है। मैंने कोशिश की:

  • XRaiseWindow
  • XMapWindow
  • मैंने क्षणिक खिड़की को पाने और दिखाने की कोशिश की

लेकिन सफलता के बिना। मुझे समझ में नहीं आता है कि अगर यह क्लाइंट संदेश मेनू सबविंडो द्वारा उत्पन्न होता है या नहीं।

मुझे ऐसी विंडो कैसे दिखानी चाहिए जो _NET_WM_STATE_HIDDEN में है?

एक और अजीब समस्या यह है कि ClientMessage प्राप्त करने के बाद, मुझे हमेशा 2 UnMapNotify इवेंट प्राप्त होते हैं।

मेरे पास एक और सवाल भी है, अगर मैं "फ़ाइल, एडिट" मेनू दिखाना चाहता हूं (फ़ायरफ़ॉक्स में यह प्रकट होता है, अगर मुझे सही याद है, जब आप Alt बटन दबाते हैं।

शायद फ़ायरफ़ॉक्स खिड़कियों का एक पेड़ बनाता है?

यह वह पाश है जहाँ मैं घटनाओं को संभालता हूँ:

while(1){
    XNextEvent(display, &local_event);
    switch(local_event.type){
        case ConfigureNotify:
            configure_notify_handler(local_event, display);
        break;
        case MotionNotify:
            motion_handler(local_event, display);
        break;
        case CreateNotify:
            cur_win = local_event.xcreatewindow.window;
            char *window_name;
            XFetchName(display, cur_win, &window_name);
            printf("Window name: %s\n", window_name);
            if(window_name!=NULL){
                if(!strcmp(window_name, "Parent")){
                    printf("Adding borders\n");
                    XSetWindowBorderWidth(display, cur_win, BORDER_WIDTH);
                }
                XFree(window_name);
            }
        break;
        case MapNotify:
            map_notify_handler(local_event,display, infos);
        break;
        case UnmapNotify: 
            printf("UnMapNotify\n");
        break;
        case DestroyNotify:
            printf("Destroy Event\n");
            destroy_notify_handler(local_event,display);
        break;
        case ButtonPress:
            printf("Event button pressed\n");
            button_handler(local_event, display, infos);
        break;
        case KeyPress:
            printf("Keyboard key pressed\n");
            keyboard_handler(local_event, display);
        break;
        case ClientMessage:
            printf("------------ClientMessage\n");
            printf("\tMessage: %s\n", XGetAtomName(display,local_event.xclient.message_type));
            printf("\tFormat: %d\n", local_event.xclient.format); 
            Atom *atoms = (Atom *)local_event.xclient.data.l;
            int i =0;
            for(i=0; i<=5; i++){
                printf("\t\tData %d: %s\n", i, XGetAtomName(display, atoms[i]));
            }
            int nchild;
            Window *child_windows;
            Window parent_window;
            Window root_window;
            XQueryTree(display, local_event.xclient.window, &root_window, &parent_window, &child_windows, &nchild);
            printf("\tNumber of childs: %d\n", nchild);
        break;
    }

अब मुवक्किल में वास्तव में मैं बस यह समझने की कोशिश कर रहा हूं कि जो कुछ हो रहा है उसे समझने के लिए कुछ जानकारी एकत्र करें। और जो मैं ऊपर दिए गए कोड से देख सकता हूं, वह यह है कि घटना को उठाने वाली खिड़की में एक बच्चा होता है (फिर: क्या वह मेनू है? या नहीं?)

MapNotify इवेंट के लिए कोड, जहां मैं सजावट जोड़ता हूं, निम्नलिखित है:

void map_notify_handler(XEvent local_event, Display* display, ScreenInfos infos){
    printf("----------Map Notify\n");
    XWindowAttributes win_attr;
    char *child_name;
    XGetWindowAttributes(display, local_event.xmap.window, &win_attr);
    XFetchName(display, local_event.xmap.window, &child_name);
    printf("\tAttributes: W: %d - H: %d - Name: %s - ID %lu\n", win_attr.width, win_attr.height, child_name, local_event.xmap.window);
    Window trans = None;    
    XGetTransientForHint(display, local_event.xmap.window, &trans); 
    printf("\tIs transient: %ld\n", trans);
    if(child_name!=NULL){
      if(strcmp(child_name, "Parent") && local_event.xmap.override_redirect == False){
        Window new_win = draw_window_with_name(display, RootWindow(display, infos.screen_num), "Parent", infos.screen_num, 
                           win_attr.x, win_attr.y, win_attr.width, win_attr.height+DECORATION_HEIGHT, 0, 
                           BlackPixel(display, infos.screen_num));
        XMapWindow(display, new_win);
        XReparentWindow(display,local_event.xmap.window, new_win,0, DECORATION_HEIGHT);
        set_window_item(local_event.xmap.window, new_win);
        XSelectInput(display, local_event.xmap.window, StructureNotifyMask);
        printf("\tParent window id: %lu\n", new_win);
        put_text(display, new_win, child_name, "9x15", 10, 10, BlackPixel(display,infos.screen_num), WhitePixel(display, infos.screen_num));
      }
    }
    XFree(child_name);
}

अब क्या कोई मेरी इन समस्याओं में मदद कर सकता है? दुर्भाग्य से मैंने पहले ही कई बार गुगली की, लेकिन सफलता के बिना।

सारांश करने के लिए, मेरे मुद्दे दो हैं: 1. फ़ायरफ़ॉक्स से सबवॉच कैसे दिखाना है 2. फ़ाइल, संपादन मेनू कैसे दिखाना है।

अपडेट करें

मैंने देखा कि कुछ अजीबोगरीब परीक्षण फ़ायरफ़ॉक्स को एक्सव के साथ समझने के लिए कि किसी एप्लिकेशन को दिखाने के लिए किन घटनाओं को निकाल दिया जाता है। मैंने देखा कि एकता में फ़ायरफ़ॉक्स का उपयोग करना, और फ़ायरफ़ॉक्स का उपयोग किसी अन्य विंडो मैनर में करना, निकाल दी गई घटनाएं पूरी तरह से अलग हैं। एकता में मेरे पास केवल:

  1. ClientMessage
  2. UnmapNotify

फ़ायरफ़ॉक्स का उपयोग करने के बजाय, उदाहरण के लिए xfce4 के साथ, उत्पन्न किए गए एक्सवेट अधिक हैं:

  1. विज़िबिलिटी नॉटिफाई (एक से अधिक)
  2. घटना को उजागर करें (एक से अधिक)

लेकिन अगर मैं अपने wm में VisibilityChangeMask को सक्षम करने का प्रयास करता हूं, तो मुझे निम्नलिखित घटनाएं प्राप्त होती हैं:

  • ConfigureNotify
  • ClientMessage
  • MapNotify
  • 2 UnMapNotify

अद्यतन २

मैंने क्लाइंटमैसेज विंडो (शायद मेन विंडो) में XWMhints गुण पढ़ने की कोशिश की और मान हैं:

  • झंडे 67 के लिए = InputHint, StateHint, WIndowGroupHint

  • प्रारंभिक अवस्था NormalState के लिए

अद्यतन 3

मैंने यह देखने की कोशिश की कि एक अन्य विंडो प्रबंधक कैसे काम करता है, और मैं शांत कोड के स्रोत कोड को देख रहा था। मेरी समझ क्या है, जब ClientMessage ईवेंट आता है, एक _NET_WM_STATE संदेश के साथ, यह इन गुणों को अद्यतन करता है, और _NET_WM_STATE_HIDDEN के मामले में यह इस संपत्ति को साफ़ करता है, और इसका परिणाम यह होगा कि संपत्ति हटा दी जाएगी। इसलिए मैंने उस संपत्ति को हटाने के लिए अपना कोड अपडेट करने की कोशिश की, लेकिन यह अभी भी काम नहीं कर रहा है। वैसे भी client_message_handler में प्रासंगिक अद्यतन कोड अब इस तरह दिखता है:

Atom *atoms = (Atom *)local_event.xclient.data.l;
int i =0;
for(i=0; i<=5; i++){
    printf("\t\tData %d: %s\n", i, XGetAtomName(display, atoms[i]));
    if(i==1){
        printf("\t Deleting Property: _NET_WM_STATE_HIDDEN \n");
        XDeleteProperty(display, cur_window, atoms[i]);
    }
}

यह केवल एक परीक्षण है, और मुझे यकीन है कि i = 1 मेरे मामले में _NET_WM_STATE_HIDDEN संपत्ति है।

यहाँ शांत स्रोत कोड के लिए एक लिंक: https://github.com/chneukirchen/cwm/blob/linux/xevents.c

इसलिए मैं अभी भी उस बिंदु पर अटका हुआ हूं।

अद्यतन 4

वास्तव में मुझे नहीं पता कि यह मदद करता है, लेकिन मैंने MapNotify Event में विंडो विशेषताओं को पढ़ने की कोशिश की, और window_state isViewable (2) है।

अद्यतन 5

मैं एसओ में यहाँ एक समान समस्या पाई, अजगर के साथ xlib का उपयोग कर: Xlib अजगर: फ़ायरफ़ॉक्स मेनू को मैप नहीं कर सकता

समाधान XSetInputFocus का उपयोग करने का सुझाव देता है, मैंने कोशिश की कि मेरे XMapNotify हैंडलर पर:

XSetInputFocus(display, local_event.xmap.window, RevertToParent, CurrentTime);

लेकिन यह अभी भी मदद नहीं करता है, फ़ायरफ़ॉक्स मेनू अभी भी प्रकट नहीं होता है !! और मुझे राइट-क्लिक में भी यही समस्या है।

अद्यतन 6

Xconfigurenotify इवेंट और अनमैप इवेंट के साथ खेलते हुए मैंने पाया कि: Xconfigure अनुरोध में 2 विंडो फ़ील्ड हैं: विंडो और ऊपर, और जब xconfigurerequest.window मान xunmap.window मान के समान है।

और यह भी कि xconfigurerequest.above हमेशा बदलता रहता है, लेकिन सभी घटनाओं में xconfigurerequest.window हमेशा समान होता है।

ऐसा लगता है कि xconfigurerequest.above किस मेनू से संबंधित है जिसे मैं खोलने की कोशिश कर रहा हूं। उदाहरण के लिए:

  • यदि किसी पृष्ठ पर राइट-क्लिक करें तो मुझे एक आईडी मिलती है (हमेशा हर बाद के क्लिक के लिए समान)
  • यदि मैं एक टैब पर राइट-क्लिक करता हूं, तो उपरोक्त मान एक और है
  • और ऐसा ही होता है अगर मैं फायरफॉक्स मेन मेन्यू पर लेफ्ट-क्लिक करता हूं

अभी भी पता नहीं है कि अगर मदद करता है।

वास्तव में किसी को भी कोई विचार नहीं पता है?





xlib