user19087
user19087

Reputation: 2063

python: PID to X11 Window ID using XResQueryClientIds

Note: This is a continuation of the answer to What process created this X11 window? from unix.stackexchange. That answer mentions XResQueryClientIds from X-Resource v1.2 extension. I'd like to know how to use it.

How can I use python's xcffib module to find all X11 window IDs associated with a provided PID (assuming no race conditions; windows or processes aren't being created or destroyed).

I don't know much about X11, the XCB API documentation seems incomplete, and the auto-generated xcffib python bindings are undocumented. From what I gather, I need:

  1. Create a connection: xcb_connect
  2. Get the extension: ?undocumented?
  3. Query the extension: ?xcb_get_extension_data mentions "?QueryExtension requests"
  4. Get the query response: xcb_get_extension_data
  5. Use the extension documentation and the protocol stub API to unpack the response.

Upvotes: 4

Views: 1095

Answers (1)

Ingo Bürk
Ingo Bürk

Reputation: 20043

assuming no race conditions; windows or processes aren't being created or destroyed

Assuming is bad if you know that the assumption doesn't hold. Luckily, you don't need this assumption. Just use xcb_grab_server and xcb_ungrab_server around your operations and this won't be an issue.

Now, as for XResQueryClientIds, you can actually just type in man xcb_res_query_client_ids. XCB just provides this, no need to actually query the extension. Here's a sample program. Compile it with gcc -lxcb -lxcb-res main.c and then execute it by passing a window ID as the only argument (e.g., ./a.out 0x2c00004).

#include <stdio.h>
#include <stdlib.h>
#include <xcb/xcb.h>
#include <xcb/res.h>

int main(int argc, char *argv[]) {
    int screen;
    xcb_connection_t *conn = xcb_connect(NULL, &screen);

    xcb_res_client_id_spec_t spec = {0};
    spec.client = strtol(argv[1], NULL, 0);
    spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;

    xcb_generic_error_t *err = NULL;
    xcb_res_query_client_ids_cookie_t cookie = xcb_res_query_client_ids(conn, 1, &spec);
    xcb_res_query_client_ids_reply_t *reply = xcb_res_query_client_ids_reply(conn, cookie, &err);

    if (reply == NULL) {
        fprintf(stderr, "Uh-Oh! :(\n");
        return -1;
    }

    uint32_t *pid = NULL;
    xcb_res_client_id_value_iterator_t it = xcb_res_query_client_ids_ids_iterator(reply);
    for (; it.rem; xcb_res_client_id_value_next(&it)) {
        spec = it.data->spec;
        if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
            pid = xcb_res_client_id_value_value(it.data);
            break;
        }
    }

    free(reply);
    xcb_disconnect(conn);

    fprintf(stderr, "PID: %d\n", *pid);
}

To give proper attribution, I didn't know any of this myself either, I just googled for the XCB function name and came across this. To understand the individual parts I suggest reading the Xlib documentation of it. XCB is often rather… "under-documented", as you've noticed, but it's really just the same as Xlib with other slightly different names for the most part.

Upvotes: 5

Related Questions