我需要重新申请并取得从X服务器或WM窗口的图像(我相信WM执行实际的合成)。我需要能够得到窗口的图像,即使它被另一个窗口遮挡或位于另一个工作区(但仍映射)。我需要使用C或C ++,并想用XCB或Xlib的。我想我也有安装了GTK +的开发工具,但是,因为我用他们来说,这已经有一段时间。
我一直在使用xcb_composite_name_window_pixmap(),但没有成功(XCB错误)尝试。
我试着用渲染扩展来渲染窗口,其生产的没有错误的照片,但我仍然需要得到加载到我的程序内存中的图像。
我试图用xcb_get_image要获取的,IIRC,失败的图片(坏的资源,我相信)。
我试图将图片复制到一个像素映射,并在使用xcb_get_image。我能下载什么似乎是一个形象,但它看起来更像屏幕比实际窗口的任意区域。
总之,我只是在这一点上做的猜测。
我有困难的时候找到有组织和完整的文档。最近出版我可以找到关于X11,XCB,或Xlib的是自1994年(O'Reilly的书的Xlib和/或X11R6),我怀疑有多少,如果有的话,在这些扩展有效。大多数人的网页和在线文档有很多的“TODO:解释”和/或功能的描述,如“交付给X服务器的请求”。任何帮助,任何人都可以提供将使用的给我。
我目前正在运行WM我和翡翠用于窗口的装饰,没有其他标准的compiz在“桌面环境”的条款。我正在为一个自定义桌面一些实用的应用程序,我打算当他们准备释放。我想不管我做了一些窗口管理等工作,但是,如果它需要为每个特殊codepaths,我可以添加其他的路线。
编辑:我原本在这里添加非工作实例,然后剥离下来的工作示例,它已全部转移到一个答案,在意见建议。
我现在有一个工作的例子,我将张贴在这里:
#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,数据)的顺序,和你有图像。