summaryrefslogtreecommitdiff
path: root/src/clients/hints.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/clients/hints.rs')
-rw-r--r--src/clients/hints.rs104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/clients/hints.rs b/src/clients/hints.rs
new file mode 100644
index 0000000..0250401
--- /dev/null
+++ b/src/clients/hints.rs
@@ -0,0 +1,104 @@
+use xcb::{
+ x::{self, ChangeProperty, GetProperty, Pixmap, PropMode, Window},
+ Xid, XidNew,
+};
+
+use crate::conn_info::Connection;
+
+pub struct Xwm {
+ flags: u32,
+ input: bool,
+ initial_state: i32,
+ icon_pixmap: Pixmap,
+ icon_window: Window,
+ icon_x: i32,
+ icon_y: i32,
+ icon_mask: Pixmap,
+ window_group: u32,
+}
+
+impl Xwm {
+ /// Get the EWM hints for the given window, if they exist and are valid.
+ pub fn get(conn: &Connection<'_>, window: Window) -> Option<Self> {
+ // https://github.com/mirror/libX11/blob/ff8706a5eae25b8bafce300527079f68a201d27f/src/GetHints.c#L106
+ // https://github.com/mirror/libX11/blob/master/src/Xatomtype.h#L111
+ let hints = conn
+ .wait_for_reply(conn.send_request(&GetProperty {
+ window,
+ delete: false,
+ property: x::ATOM_WM_HINTS,
+ r#type: x::ATOM_WM_HINTS,
+ long_offset: 0,
+ long_length: 9,
+ }))
+ .ok()?;
+
+ if hints.r#type() != x::ATOM_WM_HINTS || hints.length() < 8 || hints.format() != 32 {
+ return None;
+ }
+
+ let [flags, input, initial_state, icon_pixmap, icon_window, icon_x, icon_y, icon_mask, window_group] =
+ match hints.value::<u32>() {
+ [f, i, is, ip, iw, ix, iy, im, wg] => [f, i, is, ip, iw, ix, iy, im, wg],
+ [f, i, is, ip, iw, ix, iy, im] => [f, i, is, ip, iw, ix, iy, im, &0],
+ _ => unreachable!(),
+ };
+
+ unsafe {
+ Some(Self {
+ flags: *flags,
+ input: *input > 0,
+ initial_state: std::mem::transmute::<u32, i32>(*initial_state),
+ icon_pixmap: Pixmap::new(*icon_pixmap),
+ icon_window: Window::new(*icon_window),
+ icon_x: std::mem::transmute::<u32, i32>(*icon_x),
+ icon_y: std::mem::transmute::<u32, i32>(*icon_y),
+ icon_mask: Pixmap::new(*icon_mask),
+ window_group: *window_group,
+ })
+ }
+ }
+
+ /// Set these WM hints on the given window.
+ /// This function does not check for success, so `conn.flush()` should be called after.
+ pub fn apply(&self, conn: &Connection<'_>, window: Window) {
+ conn.send_request(&ChangeProperty {
+ mode: PropMode::Replace,
+ window,
+ property: x::ATOM_WM_HINTS,
+ r#type: x::ATOM_WM_HINTS,
+ data: unsafe {
+ &[
+ self.flags,
+ u32::from(self.input),
+ std::mem::transmute::<i32, u32>(self.initial_state),
+ self.icon_pixmap.resource_id(),
+ self.icon_window.resource_id(),
+ std::mem::transmute::<i32, u32>(self.icon_x),
+ std::mem::transmute::<i32, u32>(self.icon_y),
+ self.icon_mask.resource_id(),
+ self.window_group,
+ ]
+ },
+ });
+ }
+
+ /// If the window is flagged as urgent
+ pub const fn is_urgent(&self) -> bool {
+ (self.flags & 1 << 8) > 0
+ }
+
+ /// Set the urgent flag. [`Self::apply`] should be called afterwards.
+ pub fn set_urgent(&mut self, urgent: bool) {
+ self.flags &= u32::from(urgent) << 8;
+ }
+
+ /// Whether the window has the `input` flag set, unset, or not specified.
+ pub const fn input(&self) -> Option<bool> {
+ if (self.flags & 1 << 0) > 0 {
+ Some(self.input)
+ } else {
+ None
+ }
+ }
+}