Set window icon on X11 (#40096)

Closes #30644

Many X11 environments expect a window icon to be supplied [as pixel data
on a window property
`_NET_WM_ICON`](https://specifications.freedesktop.org/wm-spec/1.4/ar01s05.html#id-1.6.13).

I confirmed this change fixes the icon in xfce4 for me, I think its
likely it also fixes https://github.com/zed-industries/zed/issues/37961
but I haven't tested it.

## Questions
* [`image::RgbaImage` is exposed to the public API of
gpui](https://github.com/zed-industries/zed/pull/40096/files#diff-318f166d72ad9476bd0a116446f5db3897fc1a4eb1d49aaf8105608bcf49ea53R1136).
I would guess this is undesirable, but I wasn't sure of the best way to
use gpui's native `Image` type..
* Currently [the icon is embedded into the
binary](https://github.com/zed-industries/zed/pull/40096/files#diff-89af0b4072205c53b518aa977d6be48997e1a51fa4dbf06c7ddd1fec99fc510eR101).
If this is undesirable, zed could alternatively implement [icon
lookup](https://specifications.freedesktop.org/icon-theme-spec/latest/#icon_lookup)
and try and find its icon from the system at runtime.

## Future work
* It might be nice to expose a `set_window_icon` method also (it could
be used for example to show dirty state in the icon somehow), but I'm
unfamiliar with what other platforms support and if this could be beyond
X11 (there is a [wayland
protocol](https://wayland.app/protocols/xdg-toplevel-icon-v1) though!).

Release Notes:

- Fixed missing window icon on X11

---------

Co-authored-by: Yara <git@yara.blue>
This commit is contained in:
kittandYara authored and GitHub committed 2026-04-14 16:21:28 +02:00
1 parent 450bb9f2e3
commit bb990ab9ac
9 files changed
+111

No files matched your search

+24
View File
@@ -60,6 +60,7 @@ x11rb::atom_manager! {
WM_TRANSIENT_FOR,
_NET_WM_PID,
_NET_WM_NAME,
_NET_WM_ICON,
_NET_WM_STATE,
_NET_WM_STATE_MAXIMIZED_VERT,
_NET_WM_STATE_MAXIMIZED_HORZ,
@@ -743,6 +744,29 @@ impl X11WindowState {
size_hints.set_normal_hints(xcb, x_window),
)?;
if let Some(image) = params.icon {
// https://specifications.freedesktop.org/wm-spec/1.4/ar01s05.html#id-1.6.13
let property_size = 2 + (image.width() * image.height()) as usize;
let mut property_data: Vec<u32> = Vec::with_capacity(property_size);
property_data.push(image.width());
property_data.push(image.height());
property_data.extend(image.pixels().map(|px| {
let [r, g, b, a]: [u8; 4] = px.0;
u32::from_le_bytes([b, g, r, a])
}));
check_reply(
|| "X11 ChangeProperty32 for _NET_ICON_NAME failed.",
xcb.change_property32(
xproto::PropMode::REPLACE,
x_window,
atoms._NET_WM_ICON,
xproto::AtomEnum::CARDINAL,
&property_data,
),
)?;
}
let display = Rc::new(X11Display::new(xcb, scale_factor, x_screen_index)?);
Ok(Self {