为什么 WM_NAME atom 没有为某些区域设置

Why is WM_NAME atom not set for certain locales

我最近发现,当 LANG 设置为 C.utf8 时,X11 原子 WM_NAME 没有在 Swing JFrame 中设置,而是为 LANG 的其他值设置。这发生在 Linux 带有 OpenJDK 11.0.9 的 Redhat 8.2 上。

当 LANG=C.utf8

时结果为 xprop | grep -i name
_NET_WM_ICON_NAME(UTF8_STRING) = "title 123"
_NET_WM_NAME(UTF8_STRING) = "title 123"

当 LANG=en_GB.UTF-8

时结果为 xprop | grep -i name
_NET_WM_ICON_NAME(UTF8_STRING) = "title 123"
WM_ICON_NAME(STRING) = "title 123"
_NET_WM_NAME(UTF8_STRING) = "title 123"
WM_NAME(STRING) = "title 123

使用了标题的简单 JFrame

public class Example {
    public static void main(String[] args) {
        new javax.swing.JFrame("title 123").setVisible(true);
    }
}

我已经追踪到 sun.awt.X11.XBaseWindow.updateWMName() 无条件更新 VM_NAME 和 _NET_WM_NAME

XAtom nameAtom = XAtom.get(XAtom.XA_WM_NAME);
nameAtom.setProperty(getWindow(), name);
XAtom netNameAtom = XAtom.get("_NET_WM_NAME");
netNameAtom.setPropertyUTF8(getWindow(), name);

所以我猜测在 X11 库的某个较低位置,原子要么没有被设置要么被拒绝,可能与字符编码有关。

我知道 WM_NAME 是遗留的和可选的,_NET_WM_NAME 是现代的替代品。这对我来说很重要的原因是我维护了一些遗留的定制 window 管理器样式代码,它们只查找 WM_NAME。我将很快增强它以寻找 _NET_WM_NAME。我只是为了自己的学术极客兴趣而想充分理解这一点

进一步跟踪 sun.awt.X11.XAtom.setProperty(long, String) 调用本机方法 sun.awt.X11.XlibWrapper.SetProperty(long, long, long, String)

这是由https://github.com/openjdk/jdk/blob/master/src/java.desktop/unix/native/libawt_xawt/xawt/XlibWrapper.c

实现的
#ifdef X_HAVE_UTF8_STRING
    status = Xutf8TextListToTextProperty((Display *)jlong_to_ptr(display), &cname, 1,
                                   XStdICCTextStyle, &tp);
#else
    status = XmbTextListToTextProperty((Display *)jlong_to_ptr(display), &cname, 1,
                                   XStdICCTextStyle, &tp);
#endif

if (status == Success || status > 0) {
    XChangeProperty((Display *)jlong_to_ptr(display), window, atom, tp.encoding, tp.format, PropModeReplace, tp.value, tp.nitems);
    if (tp.value != NULL) {
        XFree(tp.value);
    }
}

这意味着如果 Xutf8TextListToTextProperty 不成功则不会报告错误。

Xutf8TextListToTextProperty 由 Xutils.h 提供,来自 https://gitlab.freedesktop.org/xorg/lib/libx11

看来 libX11 有自己的 i18n 实现,直到 libX11 1.7.1 它才“理解”LANG=C.utf8,尽管它确实有 C.UTF-8 的别名,这已得到纠正通过提交 https://github.com/mirror/libX11/commit/cc9f8878f2cbe17c7b4035b4ff4352b52ece38e0 为 /usr/share/X11/locale/locale.alias

添加别名
C.utf8:                     en_US.UTF-8

提交信息简明扼要地回答了问题

The normal form is 'C.UTF-8', but 'C.utf8' has been seen in the wild.

如果我手动更改 /usr/share/X11/locale/locale.alias 和 运行 我使用 LANG=C.utf8 的示例,那么 WM_NAME 和其他原子设置正确。