在 C 或 C++ 中从 X11 合成 WM 请求图像
Request image from X11 compositing WM in C or C++
我需要从 X 服务器或 WM 请求并检索 window 的图像(我相信 WM 进行实际合成)。我需要能够获取 window 的图像,即使它被另一个 window 遮挡或位于另一个工作区(但仍映射)。我需要使用 C 或 C++,并且想使用 XCB 或 Xlib。我想我也安装了 Gtk+ 开发工具,但是我已经有一段时间没有使用它们了。
我尝试使用 xcb_composite_name_window_pixmap() 但没有成功(XCB 错误)。
我尝试使用渲染扩展将 window 渲染为一张没有产生错误的图片,但我仍然需要将图像加载到我的程序内存中。
我尝试使用 xcb_get_image 来获取图片,但 IIRC 失败了(我认为是错误的资源)。
我试图将图片复制到像素图并在其上使用 xcb_get_image。我能够下载看似图像的内容,但它看起来更像是屏幕的随机区域,而不是实际的 window。
总之,我目前只是猜测
我很难找到有条理的完整文档。我能找到的关于 X11、XCB 或 Xlib 的最新出版物是 1994 年的(The O'Reilly book on Xlib and/or X11R6),我怀疑它对这些扩展是否有效(如果有的话)。大多数手册页和在线文档都有很多 "TODO: explain this" and/or 功能描述,例如 "deliver a request to the X server"。任何人可以提供的任何帮助都会对我有用。
我目前 运行 compiz 用于我的 WM 和 emerald 用于 window 装饰,就 "desktop environment" 而言没有其他标准。我正在为自定义桌面开发一些实用程序,我计划在它们准备就绪时发布。我希望我所做的任何事情都能与其他一些 WM 一起使用,但是,如果每个都需要特殊的代码路径,我可以添加其他的。
编辑:我最初在这里添加了一个非工作示例,然后是一个精简的工作示例,已按照评论中的建议将其全部移至答案。
我现在有一个工作示例,我将在此处post:
#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 的像素图,而是我只需要它的新 ID。事实证明,它真的和我想象的一样简单。您只需要 Window ID 和大小,进行一些检查以确保复合材料存在并且版本正确(在本例中为 >=0.2),然后调用 xcb_composite_redirect_window、xcb_composite_name_window_pixmap (带有生成的像素图 ID)和 xcb_get_image(+回复,data_len,数据)的顺序,然后你就有了图像。
我需要从 X 服务器或 WM 请求并检索 window 的图像(我相信 WM 进行实际合成)。我需要能够获取 window 的图像,即使它被另一个 window 遮挡或位于另一个工作区(但仍映射)。我需要使用 C 或 C++,并且想使用 XCB 或 Xlib。我想我也安装了 Gtk+ 开发工具,但是我已经有一段时间没有使用它们了。
我尝试使用 xcb_composite_name_window_pixmap() 但没有成功(XCB 错误)。
我尝试使用渲染扩展将 window 渲染为一张没有产生错误的图片,但我仍然需要将图像加载到我的程序内存中。
我尝试使用 xcb_get_image 来获取图片,但 IIRC 失败了(我认为是错误的资源)。
我试图将图片复制到像素图并在其上使用 xcb_get_image。我能够下载看似图像的内容,但它看起来更像是屏幕的随机区域,而不是实际的 window。
总之,我目前只是猜测
我很难找到有条理的完整文档。我能找到的关于 X11、XCB 或 Xlib 的最新出版物是 1994 年的(The O'Reilly book on Xlib and/or X11R6),我怀疑它对这些扩展是否有效(如果有的话)。大多数手册页和在线文档都有很多 "TODO: explain this" and/or 功能描述,例如 "deliver a request to the X server"。任何人可以提供的任何帮助都会对我有用。
我目前 运行 compiz 用于我的 WM 和 emerald 用于 window 装饰,就 "desktop environment" 而言没有其他标准。我正在为自定义桌面开发一些实用程序,我计划在它们准备就绪时发布。我希望我所做的任何事情都能与其他一些 WM 一起使用,但是,如果每个都需要特殊的代码路径,我可以添加其他的。
编辑:我最初在这里添加了一个非工作示例,然后是一个精简的工作示例,已按照评论中的建议将其全部移至答案。
我现在有一个工作示例,我将在此处post:
#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 的像素图,而是我只需要它的新 ID。事实证明,它真的和我想象的一样简单。您只需要 Window ID 和大小,进行一些检查以确保复合材料存在并且版本正确(在本例中为 >=0.2),然后调用 xcb_composite_redirect_window、xcb_composite_name_window_pixmap (带有生成的像素图 ID)和 xcb_get_image(+回复,data_len,数据)的顺序,然后你就有了图像。