我需要从X服务器或WM请求并检索窗口图像(我相信WM会进行实际的合成)。我需要能够获得该窗口的图像,即使该图像被另一个窗口遮盖或位于另一个工作区(但仍处于映射状态)也是如此。我需要使用C或C ++,并且想使用XCB或Xlib。我想我也已经安装了Gtk +开发工具,但是自从我使用它们已有一段时间了。
我尝试使用xcb_composite_name_window_pixmap()失败(XCB错误)。
我尝试使用render扩展名将窗口渲染为没有错误的图片,但是我仍然需要将图像加载到程序的内存中。
我试图使用xcb_get_image来获取IIRC失败的图片(我认为是错误的资源)。
我试图将图片复制到像素图上,并在其上使用xcb_get_image。我可以下载看似图像的图像,但它看起来更像是屏幕的随机区域,而不是实际的窗口。
简而言之,我现在只是在猜测。
我很难找到井井有条的完整文档。我可以在X11,XCB或Xlib上找到的最新出版物是1994年(关于Xlib和/或X11R6的O'Reilly书),我怀疑这些扩展是否有效。大多数手册页和在线文档都有很多“待办事项:解释这一点”和/或功能描述,如“向X服务器发送请求”。任何人都可以提供的帮助将对我有用。
我目前正在为我的WM运行compiz,为窗口装饰运行翡翠,而在“桌面环境”方面没有其他标准。我正在为自定义桌面开发一些实用程序应用程序,这些应用程序计划在它们准备就绪时发布。我希望与其他WM一起工作,但是,如果每个WM都需要特殊的代码路径,则可以将其他WM添加到此行。
编辑:我最初在此处添加了一个不起作用的示例,然后添加了一个简化的示例,所有示例均已移至注释中建议的答案。
答案 0 :(得分:0)
我现在有一个工作示例,我将在此处发布:
#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。事实证明,它确实像我期望的那样简单。您所需要做的就是窗口ID和大小,进行一些检查以确保其中有Composite和一个好的版本(在这种情况下,> = 0.2),然后调用xcb_composite_redirect_window,xcb_composite_name_window_pixmap(具有生成的pixmap ID)和xcb_get_image(+依次按顺序回复,data_len,数据),您就会看到图片。