Запросить изображение из X11, сочетающего WM на C или C ++ - PullRequest
0 голосов
/ 03 февраля 2019

Мне нужно запросить и получить изображение окна с X-сервера или WM (я полагаю, что WM выполняет фактическое наложение).Мне нужно иметь возможность получить изображение окна, даже если оно скрыто другим окном или находится в другом рабочем пространстве (но все еще отображается).Мне нужно использовать C или C ++ и хотел бы использовать XCB или Xlib.Я думаю, что у меня также установлены инструменты разработки Gtk +, но с тех пор, как я их использовал, прошло некоторое время.

Я попытался использовать xcb_composite_name_window_pixmap () безуспешно (ошибки XCB).

Я пытался использоватьрасширение рендеринга для отображения окна на изображении, которое не вызывало ошибок, но мне все еще нужно было загрузить изображение в память моей программы.

Я пытался использовать xcb_get_image для получения изображения, которое, IIRC, не удалось (плохоресурс, который я считаю).

Я попытался скопировать изображение в растровое изображение и использовать xcb_get_image для этого.Я смог загрузить то, что выглядело как изображение, но оно больше походило на случайные области экрана, чем на фактическое окно.

Короче говоря, я просто догадываюсь на этом этапе.1012 * Мне трудно найти организованную и полную документацию.Самые последние публикации, которые я могу найти на X11, XCB или Xlib, относятся к 1994 году (книга О'Рейли о Xlib и / или X11R6), и я сомневаюсь, что эти расширения, во всяком случае, имеют силу для этих расширений.Большинство справочных страниц и онлайн-документации содержат множество «TODO: объясните это» и / или описания функций, например «доставить запрос на X-сервер».Для меня будет полезна любая помощь, которую может предоставить каждый.

В настоящее время я использую compiz для своего WM и emerald для оформления окон и ничего более стандартного в терминах «среды рабочего стола».Я работаю над некоторыми служебными приложениями для собственного рабочего стола, которые планирую выпустить, когда они будут готовы.Мне бы хотелось, чтобы все, что я делаю, работало с некоторыми другими WM, но, если для каждого из них требуются специальные пути к кодам, я могу добавить другие.

РЕДАКТИРОВАТЬ: я изначально добавил здесь нерабочий пример,а затем урезанный рабочий пример, который был перенесен в ответ, как это предлагается в комментариях.

1 Ответ

0 голосов
/ 05 февраля 2019

Теперь у меня есть рабочий пример, который я опубликую здесь:

#include <xcb/xcb.h>
#include <xcb/xproto.h>
#include <xcb/composite.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv) {
    if (argc < 2) {
        fprintf(stderr, "usage: %s windowId\n", argv[0]);
        return EXIT_FAILURE;
    }
    xcb_window_t req_win_id = strtoul(argv[1], NULL, 0);
    xcb_connection_t *connection = xcb_connect(NULL, NULL);
    xcb_generic_error_t *err = NULL, *err2 = NULL;

    xcb_composite_query_version_cookie_t comp_ver_cookie = xcb_composite_query_version(connection, 0, 2);
    xcb_composite_query_version_reply_t *comp_ver_reply = xcb_composite_query_version_reply(connection, comp_ver_cookie, &err);
    if (comp_ver_reply)
    {
        if (comp_ver_reply->minor_version < 2) {
            fprintf(stderr, "query composite failure: server returned v%d.%d\n", comp_ver_reply->major_version, comp_ver_reply->minor_version);
            free(comp_ver_reply);
            return EXIT_FAILURE;
        }
        free(comp_ver_reply);
    }
    else if (err)
    {
        fprintf(stderr, "xcb error: %d\n", err->error_code);
        free(err);
        return EXIT_FAILURE;
    }

    const xcb_setup_t *setup = xcb_get_setup(connection);
    xcb_screen_iterator_t screen_iter = xcb_setup_roots_iterator(setup);
    xcb_screen_t *screen = screen_iter.data;
    // request redirection of window
    xcb_composite_redirect_window(connection, req_win_id, XCB_COMPOSITE_REDIRECT_AUTOMATIC);
    int win_h, win_w, win_d;

    xcb_get_geometry_cookie_t gg_cookie = xcb_get_geometry(connection, req_win_id);
    xcb_get_geometry_reply_t *gg_reply = xcb_get_geometry_reply(connection, gg_cookie, &err);
    if (gg_reply) {
        win_w = gg_reply->width;
        win_h = gg_reply->height;
        win_d = gg_reply->depth;
        free(gg_reply);
    } else {
        if (err) {
            fprintf(stderr, "get geometry: XCB error %d\n", err->error_code);
            free(err);
        }
        return EXIT_FAILURE;
    }

    // create a pixmap
    xcb_pixmap_t win_pixmap = xcb_generate_id(connection);
    xcb_composite_name_window_pixmap(connection, req_win_id, win_pixmap);

    // get the image
    xcb_get_image_cookie_t gi_cookie = xcb_get_image(connection, XCB_IMAGE_FORMAT_Z_PIXMAP, win_pixmap, 0, 0, win_w, win_h, (uint32_t)(~0UL));
    xcb_get_image_reply_t *gi_reply = xcb_get_image_reply(connection, gi_cookie, &err);
    if (gi_reply) {
        int data_len = xcb_get_image_data_length(gi_reply);
        fprintf(stderr, "data_len = %d\n", data_len);
        fprintf(stderr, "visual = %u\n", gi_reply->visual);
        fprintf(stderr, "depth = %u\n", gi_reply->depth);
        fprintf(stderr, "size = %dx%d\n", win_w, win_h);
        uint8_t *data = xcb_get_image_data(gi_reply);
        fwrite(data, data_len, 1, stdout);
        free(gi_reply);
    }
    return EXIT_SUCCESS;
}

Это был случай переусердствовать.Я понял, что должен использовать Xrender откуда-то и начал извлекать тонны данных из этого расширения, которое мне на самом деле не нужно.Но реальная проблема, с которой я столкнулся, состояла в том, что растровое изображение, переданное xcb_composite_name_window_pixmap, не должно создаваться в первую очередь, а скорее мне просто нужен новый идентификатор для него.Оказывается, это действительно так просто, как я ожидал.Все, что вам нужно, это идентификатор окна и его размер, выполните некоторые проверки, чтобы убедиться, что композит есть, и хорошая версия (> = 0,2 в этом случае), и вызовите xcb_composite_redirect_window, xcb_composite_name_window_pixmap (с созданным идентификатором pixmap) и xcb_get_image (+ответ, data_len, data) в таком порядке, и у вас есть изображение.

...