【问题标题】:X11: Get the list of main windows using xcbX11:使用 xcb 获取主窗口列表
【发布时间】:2019-03-29 21:22:54
【问题描述】:

我正在尝试使用使用 xcb 库的 C 程序获取已启动的 X 应用程序的主窗口列表。根据这个问题,这些窗口似乎是“顶级窗口”:X11: list top level windows

所以我的程序要求 Openbox 窗口管理器给出这些窗口的列表,然后询问每个窗口的名称,但它不起作用。我正在使用 EWMH 原子,并且我已阅读 Openbox 符合 EWMH。

编辑:当我运行控制台命令:xprop -root _NET_CLIENT_LIST 时,它会给出几个窗口的标识符。所以看起来 Openbox 支持这个原子。看了xprop的代码,但是是用Xlib写的,由于多线程支持需要用到xcb。

当我的程序收到Openbox的回复时,回复的长度为0。

这里是源代码:

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <xcb/xcb.h>

xcb_atom_t getatom(xcb_connection_t* c, char *atom_name)
{
    xcb_intern_atom_cookie_t atom_cookie;
    xcb_atom_t atom;
    xcb_intern_atom_reply_t *rep;

    atom_cookie = xcb_intern_atom(c, 0, strlen(atom_name), atom_name);
    rep = xcb_intern_atom_reply(c, atom_cookie, NULL);
    if (NULL != rep)
    {
        atom = rep->atom;
        free(rep);
        printf("\natom: %ld",atom);
        fflush(stdout);
        return atom;
    }
    printf("\nError getting atom.\n");
    exit(1);
}

int main() {
  xcb_generic_error_t *e;
  int i,j,k;

  xcb_connection_t* c = xcb_connect(NULL, NULL);
  xcb_atom_t net_client_list = getatom(c,"_NET_CLIENT_LIST");
  xcb_atom_t net_wm_visible_name = getatom(c,"_NET_WM_VISIBLE_NAME");

  xcb_screen_t* screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data;

  xcb_get_property_cookie_t prop_cookie_list,prop_cookie;
  xcb_get_property_reply_t *reply_prop_list,*reply_prop;

  prop_cookie_list = xcb_get_property(c, 0, screen->root, net_client_list, XCB_GET_PROPERTY_TYPE_ANY, 0, 0);
  reply_prop_list = xcb_get_property_reply(c, prop_cookie_list, &e);
  if(e) {
    printf("\nError: %d",e->error_code);
    free(e);
  }
  if(reply_prop_list) {
    int value_len = xcb_get_property_value_length(reply_prop_list);
    printf("\nvalue_len: %d",value_len);
    if(value_len) {
      xcb_window_t* win = xcb_get_property_value(reply_prop_list);
      for(i=0; i<value_len; i++) {
        prop_cookie = xcb_get_property(c, 0, win[i], net_wm_visible_name, XCB_GET_PROPERTY_TYPE_ANY, 0, 0);
        reply_prop = xcb_get_property_reply(c, prop_cookie, &e);
        if(e) {
          printf("\nError: %d",e->error_code);
          free(e);
        }
        if(reply_prop) {
          int value_len2 = xcb_get_property_value_length(reply_prop);
          printf("\nvalue_len2: %d",value_len2);
          if(value_len2) {
            char* name = xcb_get_property_value(reply_prop);
            printf("\nName: %s",name);
            fflush(stdout);
          }
          free(reply_prop);
        }
      }
    }
    free(reply_prop_list);
  }
  printf("\n\n");
  fflush(stdout);
  exit(0);
}

【问题讨论】:

    标签: x11 xcb


    【解决方案1】:

    我终于找到了问题,在我在互联网上阅读的示例中,xcb_get_property() 的字段long_length 设置为0,但似乎要获得一致的回复,该字段必须有一个值大于或等于回复将具有的 32 位字数。所以我选择100进行测试,但是如果指定根窗口的子树中的顶层窗口超过100个,那么回复将被截断为前100个窗口。

    我还必须将value_len 除以4 以获得回复中的元素数量,因为value_len 以字节为单位,而回复值是xcb_window_t 元素的数组,每个元素有4 个字节长。

    为了获得每个顶级窗口的名称,我选择将xcb_get_property()的字段long_length设置为1000,以确保有完整的名称。但是好像在回复中,分配的字符串的真实大小没有最后的\0字符,所以我只好分配一个长度为value_len2 + 1的内存块,然后用strncpy()把字符串复制到这个新位置。最后,添加最后一个 \0 字符。

    这是获取属性的正确代码:

      prop_cookie_list = xcb_get_property(c, 0, screen->root, net_client_list, XCB_GET_PROPERTY_TYPE_ANY, 0, 100);
      reply_prop_list = xcb_get_property_reply(c, prop_cookie_list, &e);
      if(e) {
        printf("\nError: %d",e->error_code);
        free(e);
      }
      if(reply_prop_list) {
        int value_len = xcb_get_property_value_length(reply_prop_list);
        printf("\nvalue_len: %d",value_len);
        if(value_len) {
          xcb_window_t* win = xcb_get_property_value(reply_prop_list);
          for(i=0; i<value_len/4; i++) {
            printf("\n--------------------------------\nwin id: %d",win[i]);
            prop_cookie = xcb_get_property(c, 0, win[i], net_wm_visible_name, XCB_GET_PROPERTY_TYPE_ANY, 0, 1000);
            reply_prop = xcb_get_property_reply(c, prop_cookie, &e);
            if(e) {
              printf("\nError: %d",e->error_code);
              free(e);
            }
            if(reply_prop) {
              int value_len2 = xcb_get_property_value_length(reply_prop);
              printf("\nvalue_len2: %d",value_len2);
              if(value_len2) {
                char* name = malloc(value_len2+1);
                strncpy(name,xcb_get_property_value(reply_prop),value_len2);
                name[value_len2] = '\0';
                printf("\nName: %s",name);
                fflush(stdout);
                free(name);
              }
              free(reply_prop);
            }
          }
        }
        free(reply_prop_list);
      }
    

    【讨论】:

    • 如果你想让它在你free()xcb_get_property_reply()返回的回复之后持续存在,你只需要为窗口名称分配一个字符串。否则,您可以直接从xcb_get_property_value() 返回的指针打印出来(将其从void* 转换为char*)!
    猜你喜欢
    • 2023-04-08
    • 2020-11-10
    • 2021-01-26
    • 1970-01-01
    • 2018-11-30
    • 1970-01-01
    • 2014-09-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多