X11: получить список основных окон, используя xcb - PullRequest
0 голосов
/ 25 октября 2018

Я пытаюсь получить список основных окон уже запущенных приложений X с программой на C, использующей библиотеку xcb.Кажется, что эти окна являются «окнами верхнего уровня» в соответствии с этим вопросом: X11: список окон верхнего уровня

Поэтому моя программа просит диспетчер окон 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);
}

1 Ответ

0 голосов
/ 25 октября 2018

Я наконец нашел проблему, в примерах, которые я прочитал в интернете, поле long_length из xcb_get_property() было установлено на 0, но похоже, что для получения последовательного ответа поле должно иметь значениебольше или равно количеству 32-битных слов в ответе.Поэтому я выбрал 100 для своего теста, но если в дочернем дереве указанного корневого окна имеется более 100 окон верхнего уровня, то ответ будет усечен до 100 первых окон.

Мне также пришлось разделить value_len на 4, чтобы получить количество элементов в ответе, потому что value_len в байтах, а значение ответа представляет собой массив элементов xcb_window_t, каждый из которых имеет длину 4 байта.

Чтобы получить имя каждого окна верхнего уровня, я решил установить 1000 поле long_length из xcb_get_property(), чтобы иметь полное имя.Но похоже, что в ответе истинный размер строки выделяется без последнего символа \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);
  }
...