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

如何使用XCB正确设置UTF-8编码的窗口标题?

问题:Fluxbox下用XCB设置UTF-8窗口标题显示异常?

编辑:这是一个笔误,详见下方回答。我仍保留此问题,因为它可能对未来寻求该标题问题答案的人有所帮助(相关答案并不容易找到)。

我使用Fluxbox窗口管理器,访问包含UTF-8字符的网站时,Chromium能正确显示窗口标题,说明Fluxbox支持UTF-8标题。但我自己的应用设置相同标题时,显示效果差异很大:上方是Chromium的正确标题,下方是我的应用显示乱码的标题。

通过xprop查看发现明显差异:

Chromium的xprop输出:

WM_NAME(UTF8_STRING) = "Apple (Россия) – Официальный сайт - Chromium"
_NET_WM_NAME(UTF8_STRING) = "Apple (Россия) – Официальный сайт - Chromium"

我的应用的xprop输出:

_NET_WM_NAME(UTF8_STRING) = 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x28, 0xd0, 0xa0, 0xd0, 0xbe, 0xd1, 0x81, 0xd1, 0x81, 0xd0, 0xb8, 0xd1, 0x8f, 0x29, 0x20, 0xe2, 0x80, 0x93, 0x20, 0xd0, 0x9e, 0xd1, 0x84, 0xd0, 0xb8, 0xd1, 0x86, 0xd0, 0xb8, 0xd0, 0xb0, 0xd0, 0xbb, 0xd1, 0x8c, 0xd0, 0xbd, 0xd1, 0x8b, 0xd0, 0xb9, 0x20, 0xd1, 0x81, 0xd0, 0xb0, 0xd0, 0xb9, 0xd1, 0x82, 0x20, 0x2d, 0x20, 0x43, 0x68, 0x72, 0x6f, 0x6d, 0x69, 0x75, 0x6d
WM_NAME(UTF8_STRING) = "Apple (\320\240\320\276\321\201\321\201\320\270\321\217) \342\200\223 \320\236\321\204\320\270\321\206\320\270\320\260\320\273\321\214\320\275\321\213\320\271 \321\201\320\260\320\271\321\202 - Chromium"

可见,尽管xprop显示两者的属性类型均为UTF8_STRING,但我的应用的标题并未被正确解析为UTF-8字符串。

我使用的C++20代码如下:

xcb_connection_t* m_connection = ...;
xcb_window_t handle = ...;
xcb_atom_t m_utf8_string_atom;
xcb_atom_t m_net_wm_name_atom;

...

xcb_intern_atom_cookie_t  utf8_string_cookie = xcb_intern_atom(m_connection, 0, 12, "UTF8_STRING");
xcb_intern_atom_reply_t*  utf8_string_reply  = xcb_intern_atom_reply(m_connection, utf8_string_cookie, 0);
m_utf8_string_atom = utf8_string_reply->atom;
free(utf8_string_reply);

xcb_intern_atom_cookie_t  net_wm_name_cookie = xcb_intern_atom(m_connection, 0, 12, "_NET_WM_NAME");
xcb_intern_atom_reply_t*  net_wm_name_reply  = xcb_intern_atom_reply(m_connection, net_wm_name_cookie, 0);
m_net_wm_name_atom = net_wm_name_reply->atom;
free(net_wm_name_reply);

...

xcb_void_cookie_t ret = xcb_create_window(m_connection, XCB_COPY_FROM_PARENT, handle,
  parent_handle ? parent_handle : m_screen->root, x, y, width, height,
  border_width, _class, m_screen->root_visual, value_mask, value_list.data());

std::u8string t = u8"Apple (Россия) – Официальный сайт - Chromium";
// Set window name.
xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, handle,
  XCB_ATOM_WM_NAME, m_utf8_string_atom, 8,
  t.size(), t.data());
xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, handle,
  m_net_wm_name_atom, m_utf8_string_atom, 8,
  t.size(), t.data());

...

// Display window.
xcb_map_window(m_connection, handle);
xcb_flush(m_connection);

请问我哪里出错了?


回答

问题出在WM_NAME属性的类型设置上。

X11规范中,WM_NAME的标准类型应为STRING(对应系统本地编码),而非UTF8_STRING。虽然Chromium可能同时设置了两种类型,但Fluxbox这类窗口管理器处理WM_NAME时,会严格按照属性类型的预期解析——当你把WM_NAME的类型设为UTF8_STRING,它仍会按STRING(比如ISO-8859-1)解码,导致UTF-8字节被当作单字节字符显示,出现乱码。

正确的处理方式是:

  • 对于_NET_WM_NAME,继续使用UTF8_STRING类型(符合EWMH规范);
  • 对于WM_NAME,改用STRING类型,传入对应系统本地编码的字符串(若系统locale为UTF-8,直接传入UTF-8字节即可,但类型必须是STRING)。

修改后的代码片段如下:

首先获取STRING原子:

xcb_intern_atom_cookie_t  string_cookie = xcb_intern_atom(m_connection, 0, 6, "STRING");
xcb_intern_atom_reply_t*  string_reply  = xcb_intern_atom_reply(m_connection, string_cookie, 0);
xcb_atom_t m_string_atom = string_reply->atom;
free(string_reply);

然后设置WM_NAME时使用STRING类型:

// 设置WM_NAME,采用STRING类型
xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, handle,
  XCB_ATOM_WM_NAME, m_string_atom, 8,
  t.size(), t.data());
// _NET_WM_NAME保持UTF8_STRING类型不变
xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, handle,
  m_net_wm_name_atom, m_utf8_string_atom, 8,
  t.size(), t.data());

这样Fluxbox就能正确解析_NET_WM_NAME的UTF-8内容,显示正常的窗口标题了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 05:57:21