c++linuxc++20xcb

How to correctly set an utf8 window title using xcb?


EDIT: it was a typo, see answer below. I'll leave this question up anyway, because it might help people in the future who are looking for an answer to the question stated in the title (it wasn't trivial to find it).

If I go to a website with UTF8 characters, then Chromium shows the correct title in its window (I'm using fluxbox; so apparently that can show utf8 titles).

I tried to set the same title in my own application, but the result looks quite different: two window title bars. The one on top is chromium, the one below that is my own application.

Also xprop shows a difference:

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

whereas my application gives:

_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"

Thus, despite that xprop says that the type is 'UTF8_STRING' in both cases, in my case it isn't displaying the values as utf8 strings.

The (C++20) code that I used looks as follows:

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);

What am I doing wrong?


Solution

  • Argh - mere seconds after I posted the question I see it...

    It should be:

    xcb_intern_atom_cookie_t  utf8_string_cookie = xcb_intern_atom(m_connection, 0, 11, "UTF8_STRING");
    

    I passed 12 as string length, so the type wasn't UTF8_STRING, but something with a literal 0 appended, while still displaying the same with xprop...

    It works now!