Получение окна X11 из PID - правильный доступ к массиву? грохот

Я конвертирую эти топики в jsctypes для X11:

Работает нормально. Я просто сталкиваюсь с одной проблемой, когда я зацикливаю код, это сбой.

Для тестирования я зацикливаюсь только один раз, но все равно вылетает:

Код проблемы здесь:

searchForPidStartingAtWindow(wChildElementCasted, _disp, targetPid, true);

как только я запускаю этот код, он вылетает. даже если он возвращается на второй итерации этой функции 4 аргумент истинен

Полный код, можно скопировать и вставить в Электронный блокнот (Borwser> Environment) и запустить.

Cu.import('resource://gre/modules/ctypes.jsm');


function doit() {
    try {
        _x11 = ctypes.open('libX11.so.6');
    } catch (e) {
        try {
            var libName = ctypes.libraryName('X11');
        } catch (e) {
            _x11 = false;
            console.error('Integration: Could not get libX11 name; not activating');
            return;
        }

        try {
            _x11 = ctypes.open(libName);
        } catch (e) {
            _x11 = false;
            console.error('Integration: Could not open ' + libName + '; not activating');
            return;
        }
    }

    //start - type constants
    X11Atom = ctypes.unsigned_long;
    X11Bool = ctypes.int;
    X11Display = new ctypes.StructType('Display');
    X11Window = ctypes.unsigned_long;
    X11Status = ctypes.int;
    //end - type constants

    //start - constants
    var XA_CARDINAL = 6; //https://github.com/foudfou/FireTray/blob/d0c49867ea7cb815647bf13f2f1edb26439506ff/src/modules/ctypes/linux/x11.jsm#L117
    var None = 0; //https://github.com/foudfou/FireTray/blob/d0c49867ea7cb815647bf13f2f1edb26439506ff/src/modules/ctypes/linux/x11.jsm#L63
    var Success = 0;
    //end - constants

    /*
     * typedef struct {
     *     int type;
     *     unsigned long serial;    / * # of last request processed by server * /
     *     Bool send_event;         / * true if this came from a SendEvent request * /
     *     Display *display;        / * Display the event was read from * /
     *     Window window;
     *     Atom message_type;
     *     int format;
     *     union {
     *         char b[20];
     *         short s[10];
     *         long l[5];
     *     } data;
     * } XClientMessageEvent;
     */
    XClientMessageEvent = new ctypes.StructType('XClientMessageEvent', [
        {'type': ctypes.int},
        {'serial': ctypes.unsigned_long},
        {'send_event': X11Bool},
        {'display': X11Display.ptr},
        {'window': X11Window},
        {'message_type': X11Atom},
        {'format': ctypes.int},
        {'l0': ctypes.long},
        {'l1': ctypes.long},
        {'l2': ctypes.long},
        {'l3': ctypes.long},
        {'l4': ctypes.long}
    ]);

    /*
     * Status XFetchName(
     *    Display*      display,
     *    Window        w,
     *    char**        window_name_return
     * );
     */
    XFetchName = _x11.declare('XFetchName', ctypes.default_abi, X11Status,
        X11Display.ptr, X11Window, ctypes.char.ptr.ptr);

    /*
     * Status XQueryTree(
     *    Display*      display,
     *    Window        w,
     *    Window*       root_return,
     *    Window*       parent_return,
     *    Window**      children_return,
     *    unsigned int* nchildren_return
     * );
     */
    XQueryTree = _x11.declare('XQueryTree', ctypes.default_abi, X11Status,
        X11Display.ptr, X11Window, X11Window.ptr, X11Window.ptr, X11Window.ptr.ptr,
        ctypes.unsigned_int.ptr);

    /*
     * int XFree(
     *    void*     data
     * );
     */
    XFree = _x11.declare('XFree', ctypes.default_abi, ctypes.int, ctypes.voidptr_t);

    /*
     * Display *XOpenDisplay(
     *     _Xconst char*    display_name
     * );
     */
    XOpenDisplay = _x11.declare('XOpenDisplay', ctypes.default_abi, X11Display.ptr,
        ctypes.char.ptr);

    /*
     * int XCloseDisplay(
     *     Display*     display
     * );
     */
    XCloseDisplay = _x11.declare('XCloseDisplay', ctypes.default_abi, ctypes.int,
        X11Display.ptr);

    /*
     * int XFlush(
     *     Display*     display
     * );
     */
    XFlush = _x11.declare('XFlush', ctypes.default_abi, ctypes.int, X11Display.ptr);

    /*
     * Window XDefaultRootWindow(
     *     Display*     display
     * );
     */
    XDefaultRootWindow = _x11.declare('XDefaultRootWindow', ctypes.default_abi,
        X11Window, X11Display.ptr);

    /*
     * Atom XInternAtom(
     *     Display*         display,
     *     _Xconst char*    atom_name,
     *     Bool             only_if_exists
     * );
     */
    XInternAtom = _x11.declare('XInternAtom', ctypes.default_abi, X11Atom,
        X11Display.ptr, ctypes.char.ptr, X11Bool);

    /*
     * Status XSendEvent(
     *     Display*     display,
     *     Window       w,
     *     Bool         propagate,
     *     long         event_mask,
     *     XEvent*      event_send
     * );
     */
    XSendEvent = _x11.declare('XSendEvent', ctypes.default_abi, X11Status,
        X11Display.ptr, X11Window, X11Bool, ctypes.long, XClientMessageEvent.ptr);

    /*
     * int XMapRaised(
     *     Display*     display,
     *     Window       w
     * );
     */
    XMapRaised = _x11.declare('XMapRaised', ctypes.default_abi, ctypes.int,
        X11Display.ptr, X11Window);

    /*
     * extern int XGetWindowProperty(
     *     Display*      display,
     *     Window        w,
     *     Atom      property,
     *     long      long_offset,
     *     long      long_length,
     *     Bool      delete,
     *     Atom      req_type,
     *     Atom*         actual_type_return,
     *     int*      actual_format_return,
     *     unsigned long*    nitems_return,
     *     unsigned long*    bytes_after_return,
     *     unsigned char**   prop_return
     * );
     */
    XGetWindowProperty = _x11.declare('XGetWindowProperty', ctypes.default_abi,
        ctypes.int, X11Display.ptr, X11Window, X11Atom, ctypes.long, ctypes.long,
        X11Bool, X11Atom, X11Atom.ptr, ctypes.int.ptr, ctypes.unsigned_long.ptr,
        ctypes.unsigned_long.ptr, ctypes.char.ptr.ptr);

    ////////////////////////
    ////END DECLARATIONS
    ////////////////////////

    var _x11Display = XOpenDisplay(null);
    if (!_x11Display) {
        console.error('Integration: Could not open display; not activating');
        _x11 = false;
        return;
    }   


    var _x11RootWindow = XDefaultRootWindow(_x11Display);
    if (!_x11RootWindow) {
        console.error('Integration: Could not get root window; not activating');
        _x11 = false;
        return;
    }

    //start - WindowsMatchingPid from  https://stackoverflow.com/questions/151407/how-to-get-an-x11-window-from-a-process-id
    //start - searchForPidStartingAtWindow func
    var _atomPIDInited = false;
    var _atomPID;
    var _matchingWins = [];
    function searchForPidStartingAtWindow(w, _disp, targetPid, isRecurse) { // when you call must always leave isRecurse null or false, its only used by the function to identify when to clear out _matchingWins
        if (!isRecurse) {
            //user just called this function so clear _matchingWins
            _matchingWins = [];
        } else {
            console.log('isRecurse so return');
        }
        console.log('h1');
        //make sure to clear _matchingWins arr before running this
        if (!_atomPIDInited) {
            _atomPID = XInternAtom(_disp, '_NET_WM_PID', true);
            console.log('_atomPID:', _atomPID, _atomPID.toString(), parseInt(_atomPID));
            if(_atomPID == None) {
                throw new Error('No such atom ("_NET_WM_PID"), _atomPID:', _atomPID);
            }
            _atomPIDInited = true;
        }

        var returnType = new X11Atom(),
        returnFormat = new ctypes.int(),
        nItemsReturned = new ctypes.unsigned_long(),
        nBytesAfterReturn = new ctypes.unsigned_long(),
        propData = new ctypes.char.ptr();
        console.log('h2');
        console.log('_disp:', _disp, 'w:', w, '_atomPID:', _atomPID);
        var rez = XGetWindowProperty(_disp, w, _atomPID, 0, 1024, false, XA_CARDINAL, returnType.address(), returnFormat.address(), nItemsReturned.address(), nBytesAfterReturn.address(), propData.address());
        console.log('h3');
        console.log('XGetWindowProperty', 'rez:', rez, 'returnType:', returnType, 'nItemsReturned:', nItemsReturned, 'nBytesAfterReturn:', nBytesAfterReturn, 'propData:', propData);
        console.log('propData:', ctypes.cast(propData, ctypes.unsigned_int).value);
        if (rez == Success) {
            var nElements = ctypes.cast(nItemsReturned, ctypes.unsigned_int).value;
            if(nElements) {
                var rezArr = [propData, nElements];
                console.log('rezArr:', rezArr);
            } else {
                console.log('no elements for rezArr, nElements:', nElements);
            }
            var nPid = ctypes.cast(propData, ctypes.unsigned_int).value;
            if (nPid != 0) {
                _matchingWins.push(w);
                console.log('h4');
                var rez = XFree(propData);
                console.log('rez of XFree on propData:', rez);
            } else {
                console.log('no pid on this window');
            }
        } else {
            console.error('failed on XGetWindowProperty, rez:', rez);
        }
        if (isRecurse) {
            return;
        }

        console.log('recurse into');

        // recurse into child windows
        var wRoot = new X11Window();
        var wParent = new X11Window();
        var wChild = new X11Window.ptr();
        var nChildren = new ctypes.unsigned_int();

        var rez = XQueryTree(_disp, w, wRoot.address(), wParent.address(), wChild.address(), nChildren.address());
        if(rez != 0) { //can probably test this against `None` instead of `0`
            var nChildrenCasted = ctypes.cast(nChildren, ctypes.unsigned_int).value;
            var wChildCasted = ctypes.cast(wChild, ctypes.ArrayType(X11Window, nChildrenCasted).ptr).contents; //console.log('wChildCasted:', wChildCasted);
            //var wChildElementCasted = ctypes.cast(wChildCasted.addressOfElement(0), X11Window).value;
            //console.log('wChildElementCasted:', wChildElementCasted, 'w:', w);
            //for(var i=0; i<wChildCasted.length; i++) {
            for(var i=0; i<1; i++) {
                var wChildElementCasted = ctypes.cast(wChildCasted.addressOfElement(i), X11Window).value;
                console.log('wChildElementCasted:', wChildElementCasted, 'w:', w);
                searchForPidStartingAtWindow(wChildElementCasted, _disp, targetPid, true);
            }
        } else {
            console.warn('this window has no children, rez:', rez);
        }

        return _matchingWins;
    }
    //end - searchForPidStartingAtWindow func

    var wins = searchForPidStartingAtWindow(_x11RootWindow, _x11Display, 12312132); //dont pass isRecurse here, important, otherwise if use this func multiple times, you'll have left over windows in the returned array from a previous run of this func
    console.log('wins:', wins);

    //end - WindowsMatchingPid

    XCloseDisplay(_x11Display);

    //_X11BringToForeground(win, intervalID);
}

doit();

person Noitidart    schedule 21.09.2014    source источник


Ответы (1)


Решил, пришлось использовать этот код:

            var wChildCasted = ctypes.cast(wChild, X11Window.array(nChildrenCasted).ptr).contents; //SAME AS: `var wChildCasted = ctypes.cast(wChild, ctypes.ArrayType(X11Window, nChildrenCasted).ptr).contents;`

            for(var i=0; i<wChildCasted.length; i++) {
                var wChildElementCasted = wChildCasted.addressOfElement(i).contents; //DO NOT DO `var wChildElementCasted = ctypes.cast(wChildCasted.addressOfElement(i), X11Window).value;`, it crashes on line 234 when passing as `w` into `XGetWindowProperty`
                //console.log('wChildElementCasted:', wChildElementCasted, 'w:', w);
                searchForPidStartingAtWindow(wChildElementCasted, _disp, targetPid, true);
            }

обратите внимание, что wChildElementCasted больше не забрасывается, я просто прочитал .contents. это правильный способ сделать это наверняка.

скопируйте и вставьте и полностью работайте здесь: https://gist.github.com/Noitidart/5a24e8a4f8886ce7bbf6

person Noitidart    schedule 22.09.2014