如何在XCB + C中创建一个叠加层?

后端开发 2026-07-08

我找到了一个使用 xlib 的点击穿透窗口的示例。

xlib中的代码是这样的;

XRectangle rect;
XserverRegion region = XFixesCreateRegion(display, &rect, 1);
XFixesSetWindowShapeRegion(display, window, ShapeInput, 0, 0, region);
XFixesDestroyRegion(display, region);

于是我在xcb中写了如下代码:

xcb_rectangle_t rect [1] = {{0, 0, 0, 0}};
xcb_xfixes_region_t region;
xcb_xfixes_create_region(c, region, 1, rect);
xcb_xfixes_set_window_shape_region(c, window, 2, 0, 0, region);

(我在循环之后放置 xcb_xfixes_destroy_region(c, region);,因为我假设这是清理步骤)

我在Linux Mint上,编译参数: gcc -o pixel_xcb pixel_xcb.c -lxcb -lxcb-image -lxcb-shape -lxcb-xfixes

但问题是,它似乎无法让我对该窗口进行“点击穿透”。

完整代码:

// code adapted from here https://xorg.freedesktop.org/archive/X11R7.7/doc/libxcb/tutorial/index.html#intro

// extra info here https://xcb.freedesktop.org/manual/group__XCB____API.html

// comparisons here https://www.x.org/guide/xlib-and-xcb/#example:convertingxdpyinfoextensionqueriestoxcb

// so can i use this to save an image and then draw it to the screen?
    // https://stackoverflow.com/questions/34176795/any-efficient-way-of-converting-ximage-data-to-pixel-map-e-g-array-of-rgb-quad

// maybe something useful for shm here http://metan.ucw.cz/blog/things-i-wanted-to-know-about-libxcb.html

#include <xcb/xcb.h>
#include <xcb/xcb_image.h> 
#include <xcb/xproto.h>
#include <stdio.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <xcb/shape.h>
#include <xcb/xfixes.h>

//#include "/home/loki/Documents/libxcb-errors-master/src/xcb_errors.c"


// click through xcb https://shallowsky.com/blog/programming/translucent-window-click-thru.html

xcb_screen_t *screen_of_display (xcb_connection_t *c, int screen){
  xcb_screen_iterator_t iter;

  iter = xcb_setup_roots_iterator (xcb_get_setup (c));
  for (; iter.rem; --screen, xcb_screen_next (&iter))
    if (screen == 0)
      return iter.data;

  return NULL;
}

int main(){

// display and screen
    int screen_default_nbr;
    xcb_connection_t *c = xcb_connect (NULL, &screen_default_nbr);

// screen
    xcb_screen_t* screen = screen_of_display (c, screen_default_nbr);

// root display (screen / root window with other screens as background)
    xcb_window_t root_window = { 0 };
    root_window = screen->root;

// gc (black)
    uint32_t values[4];
    uint32_t             mask = 0;
    xcb_gcontext_t       gc;
    gc = xcb_generate_id (c);
    mask = XCB_GC_FUNCTION | XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_SUBWINDOW_MODE;
    values[0] = XCB_GX_COPY;
    values[1] = screen->black_pixel;
    values[2] = screen->white_pixel;
    values[3] = XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS;
    xcb_create_gc (c, gc, root_window, mask, values);

// window
    xcb_window_t window = xcb_generate_id (c);
        xcb_create_window (c,                    /* Connection          */
                           XCB_COPY_FROM_PARENT,          /* depth (same as root)*/
                           window,                        /* window Id           */
                           screen->root,                  /* parent window       */
                           0, 0,                          /* x, y                */
                           150, 150,                      /* width, height       */
                           10,                            /* border_width        */
                           XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class               */
                           screen->root_visual,           /* visual              */
                           0, NULL );                     /* masks, not used yet */


        const uint32_t valuess[] ={1};
         //xcb_change_window_attributes (c, window, XCB_CW_OVERRIDE_REDIRECT, valuess);

                uint32_t client_major_version = XCB_XFIXES_MAJOR_VERSION;
        uint32_t client_minor_version = XCB_XFIXES_MINOR_VERSION;
        xcb_xfixes_query_version_cookie_t cook = xcb_xfixes_query_version(c, client_major_version, client_minor_version);

    //xcb_generic_error_t *err;

    //printf("%d", err->major_code);

    xcb_xfixes_query_version_reply_t* rep = xcb_xfixes_query_version_reply(c, cook, NULL);

    xcb_rectangle_t rect [0] = {};
    xcb_xfixes_region_t region = xcb_generate_id(c);
    xcb_xfixes_create_region(c, region, 0, rect);
    xcb_xfixes_set_window_shape_region(c, window, XCB_SHAPE_SK_BOUNDING, 0, 0, region);

        /* Map the window on the screen */
        xcb_map_window (c, window);


    // https://stackoverflow.com/questions/16400937/click-through-transparent-xlib-windows

    /*
    XRectangle rect;
    XserverRegion region = XFixesCreateRegion(display, &rect, 1);
    XFixesSetWindowShapeRegion(display, window, ShapeInput, 0, 0, region);
    XFixesDestroyRegion(display, region);*/



// pixmap
    /*xcb_pixmap_t pix = xcb_generate_id (c);

    xcb_create_pixmap (c, screen->root_depth,     
                                     pix,       /* Id of the pixmap *
                                     screen->root,
                                     screen->width_in_pixels,     /* Width of the window (in pixels) *
                                     screen->height_in_pixels);

    uint32_t vals [1];
    vals[0] = 0xffffff80;

// image
    xcb_get_image_reply_t* img = xcb_get_image_reply(
        c, 
        xcb_get_image (
            c,
            XCB_IMAGE_FORMAT_Z_PIXMAP,
            root_window,
            0,
            0,
            100,
            100,
            0
        ), 
        NULL
    );

    //for (int x = 0; x < ){
        xcb_point_t points [1];
        points[0].x = 10;
        points[0].y = 10;
        uint32_t vales [1];
        vals[0] = 0x394dfe;
        xcb_change_gc (c, gc, XCB_GC_FOREGROUND, vales);
        xcb_poly_point (c, XCB_COORD_MODE_ORIGIN, pix, gc, 1, points);
    //}*/


    while (1){   
        //XCopyArea(disp, pix, root, gc, 0, 0, width - 100, height - 100, 0, 0); // offset size position#  
        //xcb_copy_area (c, pix, window, gc, 0, 0, 0, 0, screen->width_in_pixels, 500);

        //xcb_image_put(c, pix, gc, img, 0, 0, 0); 

        //xcb_copy_area (c, pix, win, gc, 0, 0, 0, 0, 100, 100);

        //XFlush(disp);
        xcb_flush(c);

        usleep(1);


    }


    xcb_xfixes_destroy_region(c, region);  

    //xcb_free_pixmap (c, pix); 

    xcb_disconnect(c);
}

解决方案

必须先调用 xcb_xfixes_query_version,然后再用 xcb_xfixes_query_version_reply 获取回复。这将初始化该扩展。没有它,xfixes的请求似乎会被静默丢弃。

你还需要用 xcb_generate_id (c) 初始化 region(就像初始化一个窗口或任何其他资源一样)。如果开启编译器警告,你会看到 region 未被初始化。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章