@@ -50,6 +50,8 @@ pub struct Connection { |
| 50 | 50 | pub net_wm_window_type_toolbar: Atom, |
| 51 | 51 | pub net_wm_window_type_splash: Atom, |
| 52 | 52 | pub net_wm_window_type_notification: Atom, |
| 53 | + pub net_wm_window_type_dock: Atom, |
| 54 | + pub net_wm_window_type_desktop: Atom, |
| 53 | 55 | // EWMH atoms for window state |
| 54 | 56 | pub net_wm_state: Atom, |
| 55 | 57 | pub net_wm_state_modal: Atom, |
@@ -99,6 +101,8 @@ impl Connection { |
| 99 | 101 | let net_wm_window_type_toolbar = conn.intern_atom(false, b"_NET_WM_WINDOW_TYPE_TOOLBAR")?.reply()?.atom; |
| 100 | 102 | let net_wm_window_type_splash = conn.intern_atom(false, b"_NET_WM_WINDOW_TYPE_SPLASH")?.reply()?.atom; |
| 101 | 103 | let net_wm_window_type_notification = conn.intern_atom(false, b"_NET_WM_WINDOW_TYPE_NOTIFICATION")?.reply()?.atom; |
| 104 | + let net_wm_window_type_dock = conn.intern_atom(false, b"_NET_WM_WINDOW_TYPE_DOCK")?.reply()?.atom; |
| 105 | + let net_wm_window_type_desktop = conn.intern_atom(false, b"_NET_WM_WINDOW_TYPE_DESKTOP")?.reply()?.atom; |
| 102 | 106 | |
| 103 | 107 | // Intern EWMH atoms for window state |
| 104 | 108 | let net_wm_state = conn.intern_atom(false, b"_NET_WM_STATE")?.reply()?.atom; |
@@ -145,6 +149,8 @@ impl Connection { |
| 145 | 149 | net_wm_window_type_toolbar, |
| 146 | 150 | net_wm_window_type_splash, |
| 147 | 151 | net_wm_window_type_notification, |
| 152 | + net_wm_window_type_dock, |
| 153 | + net_wm_window_type_desktop, |
| 148 | 154 | net_wm_state, |
| 149 | 155 | net_wm_state_modal, |
| 150 | 156 | net_wm_state_fullscreen, |
@@ -558,6 +564,39 @@ impl Connection { |
| 558 | 564 | false |
| 559 | 565 | } |
| 560 | 566 | |
| 567 | + /// Check if a window should be ignored entirely (not managed by the WM). |
| 568 | + /// Returns true for dock windows (status bars like polybar) and desktop windows. |
| 569 | + pub fn should_ignore(&self, window: Window) -> bool { |
| 570 | + // Check _NET_WM_WINDOW_TYPE for dock/desktop types |
| 571 | + if let Ok(cookie) = self.conn.get_property( |
| 572 | + false, |
| 573 | + window, |
| 574 | + self.net_wm_window_type, |
| 575 | + AtomEnum::ATOM, |
| 576 | + 0, |
| 577 | + 32, |
| 578 | + ) { |
| 579 | + if let Ok(reply) = cookie.reply() { |
| 580 | + if reply.type_ == u32::from(AtomEnum::ATOM) && reply.format == 32 { |
| 581 | + let ignore_types = [ |
| 582 | + self.net_wm_window_type_dock, |
| 583 | + self.net_wm_window_type_desktop, |
| 584 | + ]; |
| 585 | + |
| 586 | + for chunk in reply.value.chunks_exact(4) { |
| 587 | + let atom = u32::from_ne_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]); |
| 588 | + if ignore_types.contains(&atom) { |
| 589 | + tracing::debug!("Window {} is dock/desktop type, ignoring", window); |
| 590 | + return true; |
| 591 | + } |
| 592 | + } |
| 593 | + } |
| 594 | + } |
| 595 | + } |
| 596 | + |
| 597 | + false |
| 598 | + } |
| 599 | + |
| 561 | 600 | /// Get WM_CLASS property (instance, class) for a window. |
| 562 | 601 | pub fn get_wm_class(&self, window: Window) -> Option<(String, String)> { |
| 563 | 602 | let wm_class_atom = self.conn.intern_atom(false, b"WM_CLASS").ok()?.reply().ok()?.atom; |