From 4eb1cb4555f74fb1cffa42e2df17e5827c07e82b Mon Sep 17 00:00:00 2001
From: Janis <noonebtw@gmail.com>
Date: Sun, 8 May 2022 01:09:42 +0200
Subject: [PATCH] added WindowType enum

---
 src/backends/mod.rs      | 15 +++++++++++++
 src/backends/traits.rs   |  6 ++++-
 src/backends/xlib/mod.rs | 47 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/src/backends/mod.rs b/src/backends/mod.rs
index 73f4ef0..5b1d5a6 100644
--- a/src/backends/mod.rs
+++ b/src/backends/mod.rs
@@ -4,3 +4,18 @@ pub mod window_event;
 pub mod xlib;
 
 pub use traits::*;
+
+pub mod structs {
+
+    #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
+    pub enum WindowType {
+        Splash,
+        Dialog,
+        Normal,
+        Utility,
+        Menu,
+        Toolbar,
+        Dock,
+        Desktop,
+    }
+}
diff --git a/src/backends/traits.rs b/src/backends/traits.rs
index 0d6104b..7928a57 100644
--- a/src/backends/traits.rs
+++ b/src/backends/traits.rs
@@ -1,4 +1,7 @@
-use super::window_event::{self, KeyOrMouseBind};
+use super::{
+    structs::WindowType,
+    window_event::{self, KeyOrMouseBind},
+};
 use crate::util::{Point, Size};
 
 pub trait WindowServerBackend {
@@ -32,6 +35,7 @@ pub trait WindowServerBackend {
     fn screen_size(&self) -> Size<i32>;
     fn get_window_size(&self, window: Self::Window) -> Option<Size<i32>>;
     fn get_window_name(&self, window: Self::Window) -> Option<String>;
+    fn get_window_type(&self, window: Self::Window) -> WindowType;
 
     fn grab_cursor(&self);
     fn ungrab_cursor(&self);
diff --git a/src/backends/xlib/mod.rs b/src/backends/xlib/mod.rs
index 92ca57d..b559a41 100644
--- a/src/backends/xlib/mod.rs
+++ b/src/backends/xlib/mod.rs
@@ -22,6 +22,7 @@ use self::{
 
 use super::{
     keycodes::VirtualKeyCode,
+    structs::WindowType,
     window_event::{
         ButtonEvent, ConfigureEvent, DestroyEvent, EnterEvent, FullscreenEvent,
         FullscreenState, KeyEvent, KeyOrMouseBind, KeyState, MapEvent,
@@ -291,6 +292,14 @@ pub mod ewmh {
                 .map(|atoms| Self { inner: atoms })
         }
 
+        pub fn reverse_lookup(&self, atom: Atom) -> Option<EWMHAtom> {
+            self.inner
+                .iter()
+                .position(|a| *a == atom)
+                .map(|position| EWMHAtom::from_repr(position))
+                .flatten()
+        }
+
         pub fn set_supported_atoms<C: Borrow<XLibConnection>>(&self, con: C) {
             let supported_atoms = [
                 self[EWMHAtom::NetActiveWindow],
@@ -1505,6 +1514,44 @@ impl WindowServerBackend for XLib {
                     .get_text_property(window, self.atoms[ICCCMAtom::WmName])
             })
     }
+
+    fn get_window_type(
+        &self,
+        window: Self::Window,
+    ) -> super::structs::WindowType {
+        match self
+            .get_atom_property(
+                window,
+                self.ewmh_atoms[EWMHAtom::NetWmWindowType],
+            )
+            .and_then(|atom| self.ewmh_atoms.reverse_lookup(*atom))
+            .and_then(|atom| WindowType::try_from(atom).ok())
+        {
+            Some(window_type) => window_type,
+            None => match self.get_parent_window(window) {
+                Some(_) => WindowType::Dialog,
+                None => WindowType::Normal,
+            },
+        }
+    }
+}
+
+impl TryFrom<EWMHAtom> for WindowType {
+    type Error = ();
+
+    fn try_from(value: EWMHAtom) -> Result<Self, Self::Error> {
+        match value {
+            EWMHAtom::NetWmWindowTypeDesktop => Ok(Self::Desktop),
+            EWMHAtom::NetWmWindowTypeDock => Ok(Self::Dock),
+            EWMHAtom::NetWmWindowTypeUtility => Ok(Self::Utility),
+            EWMHAtom::NetWmWindowTypeMenu => Ok(Self::Menu),
+            EWMHAtom::NetWmWindowTypeToolbar => Ok(Self::Toolbar),
+            EWMHAtom::NetWmWindowTypeSplash => Ok(Self::Splash),
+            EWMHAtom::NetWmWindowTypeDialog => Ok(Self::Dialog),
+            EWMHAtom::NetWmWindowTypeNormal => Ok(Self::Normal),
+            _ => Err(()),
+        }
+    }
 }
 
 #[allow(dead_code)]