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

基于wlroots-0.19的自定义Wayland合成器:xdg_surface无法映射且wlr_surface_get_texture()始终返回NULL

基于wlroots-0.19的自定义Wayland合成器:xdg_surface无法映射且wlr_surface_get_texture()始终返回NULL

看起来你遇到的问题根源是核心逻辑判断完全颠倒,再加上几个关键步骤的实现疏漏,导致窗口根本没被正确处理,自然不会有纹理和映射事件。我来一步步帮你排查修复:

1. 最致命的错误:窗口类型判断逻辑完全搞反了

先看你的_handle_new_xdg_shell_surface函数,这段条件判断直接把所有需要处理的窗口都跳过了:

if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL || xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
    return;
}

你现在的逻辑是:只要是普通窗口(TOPLEVEL)或弹窗(POPUP),就直接返回不处理——这完全和你需要的逻辑相反!Wayland中只有TOPLEVEL(普通应用窗口)和POPUP(右键菜单、弹窗)是需要合成器处理的有效窗口类型,其他小众角色才应该跳过。

修复后的判断逻辑:

// 只跳过非TOPLEVEL/非POPUP的无效surface类型
if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL && xdg_surface->role != WLR_XDG_SURFACE_ROLE_POPUP) {
    return;
}

修正后,你的合成器才会真正处理那些需要显示的窗口,而不是直接丢弃它们。

2. 为什么没收到map事件?

客户端只有在收到合成器的configure事件后,才会发送map事件并提交窗口纹理。你之前的逻辑跳过了TOPLEVEL窗口的处理,自然不会调用_configure_xdg发送configure事件,客户端就一直处于"等待合成器确认"的状态,永远不会映射窗口。

另外,你_configure_xdg函数的代码被截断了,而且wl_array_add的用法也错了——它需要传入枚举值的指针,而不是直接传枚举值:

修复后的_configure_xdg:

void Window::_configure_xdg() {
    wl_array states;
    wl_array_init(&states);

    uint32_t state;
    if (_maximized) {
        state = XDG_TOPLEVEL_STATE_MAXIMIZED;
        wl_array_add(&states, &state);
    }
    if (_fullscreened) {
        state = XDG_TOPLEVEL_STATE_FULLSCREEN;
        wl_array_add(&states, &state);
    }
    if (_resizing) {
        state = XDG_TOPLEVEL_STATE_RESIZING;
        wl_array_add(&states, &state);
    }
    if (_activated) { // 替换成你判断窗口是否激活的逻辑
        state = XDG_TOPLEVEL_STATE_ACTIVATED;
        wl_array_add(&states, &state);
    }

    // 发送configure事件,告诉客户端我们接受这个窗口,并传递尺寸/状态
    wlr_xdg_toplevel_send_configure(_xdg_surface->toplevel, &states, static_cast<int>(_width), static_cast<int>(_height));
    wl_array_release(&states);
}

3. 为什么wlr_surface_get_texture()返回NULL?

即使修复了上面的问题,你也需要在获取纹理前做一个关键检查:只有当surface被映射(mapped)后,才会有有效纹理。你可以在commit handler中添加这个判断:

void Window::_handle_commit(struct wl_listener *listener, void *data) {
    auto surface = static_cast<struct wlr_surface*>(data);
    if (!wlr_surface_mapped(surface)) {
        return; // 跳过未映射的surface,此时没有有效纹理
    }

    wlr_texture *texture = wlr_surface_get_texture(surface);
    if (texture != nullptr) {
        // 这里可以处理纹理更新,比如标记窗口需要重绘
        _dirty = true;
    }
}

4. 其他需要注意的细节

  • 确保wlr_scene_xdg_surface_create返回的场景节点是有效的:你的Node::alloc_scene_tree需要正确创建或返回合成器的根场景树,否则窗口不会被添加到渲染队列中。
  • 检查Window构造函数中的listener是否正确绑定:比如_map_listener、_commit_listener等,要确保它们的notify函数被正确设置并添加到对应的wl_signal上。
  • wlr_xdg_surface_ping的位置没问题,但要确保在创建完所有listener后调用,避免客户端响应ping时我们还没准备好处理事件。

总结修复步骤

  1. 立刻修正_handle_new_xdg_shell_surface中的窗口类型判断逻辑,这是一切问题的根源。
  2. 修复_configure_xdg函数,确保正确发送configure事件给客户端。
  3. 在commit handler中添加surface映射状态检查,避免获取无效纹理。
  4. 验证所有wl_signal listener都正确绑定,没有遗漏关键事件(比如map、unmap、destroy)。

按照这些步骤修复后,你应该能正常收到map事件,并且wlr_surface_get_texture()也能返回有效纹理了。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 11:58:41