Xlib test window names

2020-03-08 06:46发布

问题:

I'm trying to get control of the the Xterm with Xlib. For that i'm making a Xterm with a strange title. After I list all window and check they names. But something is bugged the nammes of my Xterm does not appear when they are listed. Here is the code for list all window :

void CMD::getWindowTerminal()
{
    Atom a = XInternAtom(m_display, "_NET_CLIENT_LIST", true);
    Atom actualType;
    int format;
    unsigned long numItems, bytesAfter;
    unsigned char *data = 0;
    int status = XGetWindowProperty(m_display, m_root_win, a, 0L, (~0L), false,
                                AnyPropertyType, &actualType, &format, &numItems,
                                &bytesAfter, &data);

    if (status >= Success && numItems)
    {
        long *array = (long*) data;
        for (unsigned long k = 0; k < numItems; k++)
        {
            // get window Id:
            Window w = (Window) array[k];

            char* name = '\0';
            status = XFetchName(m_display, w, &name);
            if (status >= Success)
            {
                std::cout << w << " " << name << std::endl;
                if (name == NULL)
                {
                    m_window_terminal = w;
                    std::cout << "TERMINAL FOUND" << std::endl;
                }
            }
            XFree(name);
        }
        XFree(data);
    }
}

回答1:

I cannot reproduce the error; your code finds my xterm windows. Are you querying the window of an xterm you only just spawned? If so, you might have a race condition in that you try to find the window before xterm had a chance of making it. In that case, a crummy solution would be to wait a bit and try again several times.

If that is not the case, I can only speculate (more) about causes (my speculations involve a misbehaving window manager or very old software), but perhaps I can suggest a solution: if the xterm doesn't show up in the root window's _NET_CLIENT_LIST, let's dig directly into the window tree and see if we can find it there. This bit of C code (porting to C++ should not be difficult, and anyway it's enough to try it out) traverses the window tree recursively with XQueryTree, so it queries all windows:

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>

Window window_from_name_search(Display *display, Window current, char const *needle) {
  Window retval, root, parent, *children;
  unsigned children_count;
  char *name = NULL;

  /* Check if this window has the name we seek */
  if(XFetchName(display, current, &name) > 0) {
    int r = strcmp(needle, name);
    XFree(name);
    if(r == 0) {
      return current;
    }
  }

  retval = 0;

  /* If it does not: check all subwindows recursively. */
  if(0 != XQueryTree(display, current, &root, &parent, &children, &children_count)) {
    unsigned i;
    for(i = 0; i < children_count; ++i) {
      Window win = window_from_name_search(display, children[i], needle);

      if(win != 0) {
        retval = win;
        break;
      }
    }

    XFree(children);
  }

  return retval;
}

// frontend function: open display connection, start searching from the root window.
Window window_from_name(char const *name) {
  Display *display = XOpenDisplay(NULL);
  Window w = window_from_name_search(display, XDefaultRootWindow(display), name);
  XCloseDisplay(display);
  return w;
}

Since it handles all windows, your xterm window has to be among them. If it is not, refer back to the beginning (the bit about a possible race condition). And if that's not it, then something's very strange.



回答2:

After search if I don't add a cout the function don't work, why ? I added a cout here :

if(XFetchName(display, current, &name) > 0) {
        int r = strcmp(needle, name);
        std::cout << current << " : " << name << std::endl;
        XFree(name);
        if(r == 0) {
            return current;
        }
}