You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Xorg透明窗口中添加完全不透明元素的实现方法

实现半透明背景+完全不透明元素的X11窗口(Cairo+XCB)

完全可以实现你要的效果——窗口背景保持半透明,图标、文字等元素完全不透明。核心问题在于你当前用_NET_WM_WINDOW_OPACITY全局控制窗口透明度,会让所有元素都被统一透明化。正确的做法是让窗口本身支持像素级Alpha通道,通过Cairo直接绘制带Alpha的背景和不透明的元素。

核心修改思路

  1. 替换窗口的visual为支持32位ARGB的类型,让X11允许窗口渲染带Alpha通道的内容。
  2. 移除_NET_WM_WINDOW_OPACITY的全局透明度设置,改用Cairo绘制半透明背景。
  3. 在Cairo中直接绘制不透明的元素(alpha设为1.0),利用混合模式叠加在半透明背景上。

具体代码调整

1. 查找并使用ARGB32 Visual

X11默认的root visual可能不支持Alpha通道,需要先找到屏幕上的32位真彩色visual:

xcb_visualtype_t* find_argb_visual(xcb_connection_t* conn, xcb_screen_t* screen) {
    xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(screen);
    for (; depth_iter.rem; xcb_depth_next(&depth_iter)) {
        xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
        for (; visual_iter.rem; xcb_visualtype_next(&visual_iter)) {
            xcb_visualtype_t* visual = visual_iter.data;
            // 筛选32位真彩色visual,适配CAIRO_FORMAT_ARGB32
            if (depth_iter.data->depth == 32 && visual->class == XCB_VISUAL_CLASS_TRUE_COLOR) {
                return visual;
            }
        }
    }
    // 找不到则回退到默认root visual
    return screen->root_visual;
}

然后修改窗口创建代码,替换原有的root_visual:

// 替换原有的visual_type获取逻辑
xcb_visualtype_t* argb_visual = find_argb_visual(win->con->connection, win->con->screen);

// 创建对应colormap
xcb_colormap_t colormap = xcb_generate_id(win->con->connection);
xcb_create_colormap(win->con->connection, XCB_COLORMAP_ALLOC_NONE, colormap, win->con->screen->root, argb_visual->visual_id);

// 窗口创建时使用argb_visual
xcb_create_window(win->con->connection,
                  XCB_COPY_FROM_PARENT,
                  win->window, win->con->screen->root,
                  win->x, win->y,
                  win->width, win->height,
                  0, // border
                  XCB_WINDOW_CLASS_INPUT_OUTPUT,
                  argb_visual->visual_id, // 替换为ARGB visual
                  value_mask,
                  value_list);

2. 调整Cairo绘制逻辑

保留你现有的半透明背景绘制代码,添加不透明元素的绘制逻辑(注意元素的alpha设为1.0):

cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
cairo_t *cr = cairo_create(surface);
cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);

// 绘制半透明背景(alpha=0.8)
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(cr, 0.3, 0.3, 0.3, 0.8);
cairo_paint(cr);

// 绘制完全不透明的图标(示例)
cairo_surface_t* icon_surface = cairo_image_surface_create_from_png("icon.png");
if (cairo_surface_status(icon_surface) == CAIRO_STATUS_SUCCESS) {
    cairo_set_operator(cr, CAIRO_OPERATOR_OVER); // 覆盖模式,默认就是这个,可省略
    cairo_set_source_surface(cr, icon_surface, 20, 20);
    cairo_paint(cr); // 图标本身不透明的话,会完全覆盖背景
    cairo_surface_destroy(icon_surface);
}

// 绘制完全不透明的文字
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); // rgb默认alpha=1.0
cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cr, 18);
cairo_move_to(cr, 20, 80);
cairo_show_text(cr, "这是完全不透明的文字");

// 清理资源
cairo_destroy(cr);

3. 窗口绘制与属性调整

确保你的Cairo XCB表面使用ARGB visual创建:

// 初始化窗口的Cairo表面时传入argb_visual
win->surface = cairo_xcb_surface_create(win->con->connection, win->window, argb_visual, win->width, win->height);
win->cr = cairo_create(win->surface);

同时移除_NET_WM_WINDOW_OPACITY的设置代码——全局窗口透明度会覆盖像素级的Alpha通道,导致元素也被透明化。

4. 保留Shape扩展(可选)

你之前用的Shape扩展可以继续保留,用来实现自定义窗口形状,这和像素级Alpha通道不冲突:Shape控制窗口的输入/可见区域,Alpha控制像素的透明度,两者可以配合使用。

关键注意事项

  • 确保窗口管理器支持ARGB窗口(现代WM如KWin、Mutter、i3都支持)。
  • 绘制元素时,无论是图片还是文字,都要保证其Alpha通道为1.0(或直接使用RGB颜色)。
  • 使用Cairo的CAIRO_OPERATOR_OVER混合模式(默认),可以让不透明元素正确叠加在半透明背景上。

内容的提问来源于stack exchange,提问作者nect

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 01:25:57