Skip to content

Instantly share code, notes, and snippets.

@Noitidart
Last active August 29, 2015 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Noitidart/5a24e8a4f8886ce7bbf6 to your computer and use it in GitHub Desktop.
Save Noitidart/5a24e8a4f8886ce7bbf6 to your computer and use it in GitHub Desktop.
_ff-addon-snippet-X11_WindowsMatchingPid - Itterates through windows getting PIDs of them and returns windows found with specific PID. (js-ctypes) (X11)
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
/*
* 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);
/*
* 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);
/*
* 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 http://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 = [];
}
//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) {
console.error('No such atom ("_NET_WM_PID"), _atomPID:', _atomPID);
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');
/*
if (isRecurse) {
console.log('isRecurse so return b1');
return;
}
*/
//console.log('XGetWindowProperty', 'rez:', rez, 'returnType:', returnType, 'nItemsReturned:', nItemsReturned, 'nBytesAfterReturn:', nBytesAfterReturn, 'propData:', propData);
if (rez == Success) {
var nElements = ctypes.cast(nItemsReturned, ctypes.unsigned_int).value;
if(nElements) {
//var rezArr = [propData, nElements];
console.log('nElements > 0:', nElements, '(should always be one, as per window should have only one pid, but its an array so lets loop through just to make sure)');
if (nElements > 1) {
throw new Error('how on earth??? nElements is > 1, windows should only have one pid...', 'nElements:', nElements);
}
//var clientList = ctypes.cast(res[0], X11Window.array(nClients).ptr).contents,
var pidList = ctypes.cast(propData, ctypes.unsigned_long.array(nElements).ptr).contents;
for (var i=0; i<nElements; i++) {
var pid = pidList.addressOfElement(i).contents;
console.log('pid:', pid);
//if (pid == targetPid) {
if (ctypes.UInt64.compare(pid, ctypes.UInt64(targetPid)) == 0) { //if == 0 then they are equal
console.log('pid match at', pid.toString(), targetPid);
_matchingWins.push(w);
}
}
//var rez = XFree(propData); //i dont know if i should xfree anything
//console.log('rez of XFree on propData:', rez);
} else {
console.log('no elements, nElements:', nElements, 'THUS meaning no pid on this window');
}
} else {
console.error('failed on XGetWindowProperty, rez:', rez);
}
/*
if (isRecurse) {
console.log('isRecurse so return');
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;
console.log('nChildrenCasted:', nChildrenCasted);
if (nChildrenCasted > 0) {
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);
}
} else {
console.log('this window has no children, nChildrenCasted:', nChildrenCasted);
}
} else {
console.warn('XQueryTree failed:', rez);
}
return _matchingWins;
}
//end - searchForPidStartingAtWindow func
var wins = searchForPidStartingAtWindow(_x11RootWindow, _x11Display, 4398); //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();
@Noitidart
Copy link
Author

README

Rev1

  • Error on passing prop_value.address() to XGetWindowProperty on L#221, I can't figure it out, I did it exactly like the place I'm copying from does it: GitHub :: foudfou / FireTray - FiretrayWindow.jsm L#421
    • It keeps throwing this error:

      expected type pointer, got ctypes.unsigned_char.ptr.ptr(ctypes.UInt64("0xa33ec2a0"))
      doit@Scratchpad/1:221:7
      

Rev2

  • Fixed the rev 1 L221 error with using the code from where I jacked the x11 framework, so from here: GitHub :: zotero / zotero - integration.js L#571

    function _X11GetProperty(win, propertyName, propertyType) {
      Components.utils.import("resource://gre/modules/ctypes.jsm");
      var returnType = new X11Atom(),
          returnFormat = new ctypes.int(),
          nItemsReturned = new ctypes.unsigned_long(),
          nBytesAfterReturn = new ctypes.unsigned_long(),
          data = new ctypes.char.ptr();
      if (!XGetWindowProperty(_x11Display, win, XInternAtom(_x11Display, propertyName, 0), 0, 1024,
          0, propertyType, returnType.address(), returnFormat.address(),
          nItemsReturned.address(), nBytesAfterReturn.address(), data.address())) {
          var nElements = ctypes.cast(nItemsReturned, ctypes.unsigned_int).value;
          if (nElements) return [data, nElements];
      }
      return null;
    }
  • Setup recurse child beginnings

Rev3

  • Turned the search into a function called searchForPidStartAtWindow

Rev4

  • Is succesfully getting children count
  • However bug: I'm trying to work on passing wChild[i] to searchForPidStartAtWindow to recurse
  • Note: There is the debugSingleRecurse thing to make sure it only recurses once i should remove this

Rev5

  • Got wChild[i] passing into searchForPidStartAtWindow however its coming into some error

    expected type unsigned_long, got (void 0)
    searchForPidStartingAtWindow@Scratchpad/1:230:7
    searchForPidStartingAtWindow@Scratchpad/1:272:6
    doit@Scratchpad/1:283:6
    @Scratchpad/1:293:1
    WCA_evalWithDebugger@resource://gre/modules/commonjs/toolkit/loader.js -> resource://gre/modules/devtools/server/actors/webconsole.js:1069:7
    WCA_onEvaluateJS@resource://gre/modules/commonjs/toolkit/loader.js -> resource://gre/modules/devtools/server/actors/webconsole.js:734:9
    DSC_onPacket@resource://gre/modules/commonjs/toolkit/loader.js -> resource://gre/modules/devtools/server/main.js:1098:9
    LDT_send/<@resource://gre/modules/devtools/dbg-client.jsm -> resource://gre/modules/devtools/server/transport.js:279:11
    makeInfallible/<@resource://gre/modules/commonjs/toolkit/loader.js -> resource://gre/modules/devtools/DevToolsUtils.js:84:7" scratchpad.js:999
    

Rev6

Rev7

  • Working pretty good now, its returning an array
  • I updated comparison of pid to targetPid to properly use ctypes.UInt.compare even though it seemed pid == 4398 was working, I don't know if its the right thing to do.

Rev8

  • Renamed to WindowsMatchingPid so it matches from the SO topic

Rev9

  • Removed unused skeleton functions, now that I exported skeleton to another gist
    • Left in XFree as I think I need to use that, I'm just not sure how yet, I think I know where, it's just I didn't see an affect so I didn't use it, but commented out in previous revs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment