From 1c5729ba97bb9e46e4642ed8a1d7d0771aa3f3a5 Mon Sep 17 00:00:00 2001 From: Fedor Logachev Date: Sat, 19 Oct 2024 16:28:05 -0600 Subject: [PATCH] linux/x11: Support window icons --- src/native/linux_x11/libx11.rs | 12 +++++++ src/native/linux_x11/libx11_ex.rs | 54 ++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/native/linux_x11/libx11.rs b/src/native/linux_x11/libx11.rs index 8000b342..f30ce722 100644 --- a/src/native/linux_x11/libx11.rs +++ b/src/native/linux_x11/libx11.rs @@ -989,6 +989,8 @@ pub struct X11Extensions { pub _wm_state: Atom, pub net_wm_name: Atom, pub net_wm_icon_name: Atom, + pub net_wm_icon: Atom, + pub cardinal: Atom, } #[derive(Clone)] @@ -1133,6 +1135,16 @@ impl LibX11 { b"_NET_WM_ICON_NAME\x00" as *const u8 as *const libc::c_char, false as _, ), + net_wm_icon: (self.XInternAtom)( + display, + b"_NET_WM_ICON\x00" as *const u8 as *const libc::c_char, + false as _, + ), + cardinal: (self.XInternAtom)( + display, + b"CARDINAL\x00" as *const u8 as *const libc::c_char, + false as _, + ), }; } } diff --git a/src/native/linux_x11/libx11_ex.rs b/src/native/linux_x11/libx11_ex.rs index b5077645..fdd6183c 100644 --- a/src/native/linux_x11/libx11_ex.rs +++ b/src/native/linux_x11/libx11_ex.rs @@ -85,7 +85,7 @@ impl LibX11 { window, self.extensions.net_wm_name, self.extensions.utf8_string, - 8 as libc::c_int, + 8, PropModeReplace, c_title.as_ptr() as *mut libc::c_uchar, libc::strlen(c_title.as_ptr()) as libc::c_int, @@ -103,6 +103,53 @@ impl LibX11 { (self.XFlush)(display); } + pub unsafe fn update_window_icon( + &mut self, + display: *mut Display, + window: Window, + icon: &crate::conf::Icon, + ) { + let bytes_length = (icon.small.len() + icon.medium.len() + icon.big.len()) / 4 + 3 * 2; + + // "This is an array of 32bit packed CARDINAL ARGB" (c) freedesktop + // While, in fact, X11 expect this to be 64bit on 64bit systems, which is proved + // by quite a few "unsigned long icon[]" I've seen in quite a few real-life programs. + // Leaving this comment nn case of icon-related bugs in the future. + let mut icon_bytes: Vec = vec![0; bytes_length]; + let icons = [ + (16, &icon.small[..]), + (32, &icon.medium[..]), + (65, &icon.big[..]), + ]; + + { + let mut target = icon_bytes.iter_mut(); + for (dim, pixels) in icons { + *target.next().unwrap() = dim; + *target.next().unwrap() = dim; + for pixels in pixels.chunks(4) { + let r = pixels[0] as u32; + let g = pixels[1] as u32; + let b = pixels[2] as u32; + let a = pixels[3] as u32; + + *target.next().unwrap() = ((r << 16) | (g << 8) | (b << 0) | (a << 24)) as usize; + } + } + } + + (self.XChangeProperty)( + display, + window, + self.extensions.net_wm_icon, + self.extensions.cardinal, + 32, + PropModeReplace, + icon_bytes.as_mut_ptr() as *mut _ as *mut _, + icon_bytes.len() as _, + ); + } + pub unsafe fn create_window( &mut self, root: Window, @@ -186,6 +233,11 @@ impl LibX11 { (self.XSetWMNormalHints)(display, window, hints); (self.XFree)(hints as *mut libc::c_void); + if let Some(ref icon) = conf.icon { + self.update_window_icon(display, window, icon); + } + // For an unknown reason, this should happen after update_window_icon, + // otherwise X11 will skip ChangeProperty(WM_ICON) self.update_window_title(display, window, &conf.window_title); window