X11合成:如何手动更新重定向窗口

问题描述 投票:0回答:1

我正在尝试对任意应用程序窗口进行一些后处理(颜色处理、锐化、模糊等)。我使用 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
c linux x11 xcb compositing
1个回答
0
投票

仔细检查 compWindowUpdateAutomatic() 并多次阅读 Composite 扩展文档后,我发现我做错了什么。复制的目标不应是重定向的窗口,而是其父窗口。

-    xcb_create_gc(conn, gc, wid, 0, NULL);
+    xcb_window_t parent;
+    {
+        xcb_query_tree_reply_t *r = xcb_query_tree_reply(conn, xcb_query_tree(conn, wid), NULL);
+        parent = r->parent;
+        free(r);
+    }
+    xcb_create_gc(conn, gc, parent, XCB_GC_SUBWINDOW_MODE, (const uint32_t[]){XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS});
...
-                xcb_copy_area(conn, pixmap, wid, gc, 0, 0, 0, 0, geom->width, geom->height);
+                xcb_copy_area(conn, pixmap, parent, gc, 0, 0, geom->x, geom->y, geom->width, geom->height);
© www.soinside.com 2019 - 2024. All rights reserved.