X11合成:如何手动更新重定向窗口
如何在Composite MANUAL模式下更新处理后的窗口像素?
我想要对任意应用程序窗口进行后期处理(色彩调整、锐化、模糊等)。我使用Composite扩展将窗口内容获取为离屏像素图,再对其应用特效。为避免闪烁,我尝试使用MANUAL更新模式,以便在单帧中显示处理后的像素。根据Composite文档:
可以禁用这种自动更新机制,以便父窗口内容完全由外部应用程序决定。
但文档并未说明具体如何执行更新操作。我猜测不应直接将离屏像素图复制回窗口,因为源和目标本质上是同一个对象?
更新:我查阅了扩展源代码,找到了自动更新逻辑中执行复制操作的位置(compWindowUpdateAutomatic()),但使用xcb_render_composite()尝试后得到的结果依然无效。
以下是我当前的代码尝试,但显然复制回窗口的操作没有效果:
#include <cairo/cairo-xcb.h> #include <stdio.h> #include <stdlib.h> #include <xcb/composite.h> #include <xcb/damage.h> #include <xcb/xcb_aux.h> #include <xcb/xcb_event.h> int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "Usage: %s <window_id>\n", argv[0]); return -1; } xcb_window_t wid = (xcb_window_t)strtoul(argv[1], NULL, 0); xcb_connection_t *conn = xcb_connect(NULL, NULL); xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data; xcb_visualtype_t *visual = xcb_aux_find_visual_by_attrs(screen, XCB_VISUAL_CLASS_TRUE_COLOR, 24); xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, wid), NULL); xcb_damage_query_version(conn, XCB_DAMAGE_MAJOR_VERSION, XCB_DAMAGE_MINOR_VERSION); uint8_t DAMAGE_EVENT = xcb_get_extension_data(conn, &xcb_damage_id)->first_event; { //track damage in subwindows: xcb_query_tree_reply_t *r = xcb_query_tree_reply(conn, xcb_query_tree_unchecked(conn, wid), NULL); xcb_window_t *w = xcb_query_tree_children(r); for (int i = 0; i < r->children_len; ++i) { xcb_damage_damage_t damage = xcb_generate_id(conn); xcb_damage_create(conn, damage, w[i], XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY); xcb_flush(conn); } { xcb_damage_damage_t damage = xcb_generate_id(conn); xcb_damage_create(conn, damage, wid, XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY); xcb_flush(conn); } free(r); } xcb_composite_redirect_window(conn, wid, XCB_COMPOSITE_REDIRECT_MANUAL); xcb_pixmap_t pixmap = xcb_generate_id(conn); xcb_composite_name_window_pixmap(conn, wid, pixmap); xcb_gcontext_t gc = xcb_generate_id(conn); xcb_create_gc(conn, gc, wid, 0, NULL); xcb_generic_event_t *event; while ((event = xcb_wait_for_event(conn))) { if (XCB_EVENT_RESPONSE_TYPE(event) == DAMAGE_EVENT + XCB_DAMAGE_NOTIFY) { xcb_damage_notify_event_t *de = (xcb_damage_notify_event_t *)event; { // draw a translucent layer: cairo_surface_t *surface = cairo_xcb_surface_create(conn, pixmap, visual, geom->width, geom->height); cairo_t *cr = cairo_create(surface); cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.5); cairo_paint(cr); cairo_destroy(cr); cairo_surface_destroy(surface); } { // copy back: xcb_copy_area(conn, pixmap, wid, gc, 0, 0, 0, 0, geom->width, geom->height); } xcb_damage_subtract(conn, de->damage, XCB_NONE, XCB_NONE); xcb_flush(conn); } free(event); } return -1; }
编译命令:
cc main.c -o main -lxcb-composite -lxcb-damage -lcairo -lxcb-render -lxcb-util -lxcb
内容的提问来源于stack exchange,提问作者svlasov
相关产品推荐
相关产品推荐

