gardesk/gar / 6c9c79b

Browse files

fix floating window stacking and add _NET_WM_STATE_ABOVE support

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
6c9c79b1eae1bda2922af220f7b2aa8c2dc74cd7
Parents
73a9223
Tree
0fef584

3 changed files

StatusFile+-
M gar/src/core/mod.rs 24 10
M gar/src/x11/connection.rs 10 1
M gar/src/x11/events.rs 19 1
gar/src/core/mod.rsmodified
@@ -974,6 +974,12 @@ impl WindowManager {
974974
                         border_width as u16,
975975
                     )?;
976976
 
977
+                    // Ensure tiled frame is below floating windows by stacking at bottom
978
+                    if let Some(frame) = self.frames.frame_for_client(*window) {
979
+                        let aux = ConfigureWindowAux::new().stack_mode(StackMode::BELOW);
980
+                        self.conn.conn.configure_window(frame, &aux)?;
981
+                    }
982
+
977983
                     tracing::debug!(
978984
                         "apply_layout: TILED+FRAME window={} at ({}, {}) size {}x{} (titlebar: {})",
979985
                         window, gapped_x, gapped_y, final_width.max(1), final_height.max(1), titlebar_height
@@ -992,6 +998,10 @@ impl WindowManager {
992998
                         final_height.max(1),
993999
                         border_width,
9941000
                     )?;
1001
+
1002
+                    // Ensure tiled window is below floating windows
1003
+                    let aux = ConfigureWindowAux::new().stack_mode(StackMode::BELOW);
1004
+                    self.conn.conn.configure_window(*window, &aux)?;
9951005
                 }
9961006
 
9971007
                 // Store the actual geometry for pointer warping
@@ -1034,18 +1044,17 @@ impl WindowManager {
10341044
                     if let Some(frame) = self.frames.frame_for_client(window_id) {
10351045
                         let aux = ConfigureWindowAux::new().stack_mode(StackMode::ABOVE);
10361046
                         self.conn.conn.configure_window(frame, &aux)?;
1047
+                        tracing::info!(
1048
+                            "apply_layout: FLOATING+FRAME window={} frame={} raised ABOVE (at ({}, {}) size {}x{})",
1049
+                            window_id, frame, geom.x, geom.y, adjusted_width.max(1), adjusted_height.max(1)
1050
+                        );
1051
+                    } else {
1052
+                        tracing::warn!(
1053
+                            "apply_layout: FLOATING window={} has_frame=true but no frame found!",
1054
+                            window_id
1055
+                        );
10371056
                     }
1038
-
1039
-                    tracing::debug!(
1040
-                        "apply_layout: FLOATING+FRAME window={} at ({}, {}) size {}x{} (raising)",
1041
-                        window_id, geom.x, geom.y, adjusted_width.max(1), adjusted_height.max(1)
1042
-                    );
10431057
                 } else {
1044
-                    tracing::debug!(
1045
-                        "apply_layout: FLOATING window={} at ({}, {}) size {}x{} (raising)",
1046
-                        window_id, geom.x, geom.y, adjusted_width.max(1), adjusted_height.max(1)
1047
-                    );
1048
-
10491058
                     // Configure geometry
10501059
                     self.conn.configure_window(
10511060
                         window_id,
@@ -1059,6 +1068,11 @@ impl WindowManager {
10591068
                     // Raise to top of stack (each subsequent window goes above the previous)
10601069
                     let aux = ConfigureWindowAux::new().stack_mode(StackMode::ABOVE);
10611070
                     self.conn.conn.configure_window(window_id, &aux)?;
1071
+
1072
+                    tracing::info!(
1073
+                        "apply_layout: FLOATING window={} raised ABOVE (at ({}, {}) size {}x{})",
1074
+                        window_id, geom.x, geom.y, adjusted_width.max(1), adjusted_height.max(1)
1075
+                    );
10621076
                 }
10631077
 
10641078
                 // Store the actual geometry for pointer warping
gar/src/x11/connection.rsmodified
@@ -65,6 +65,7 @@ pub struct Connection {
6565
     pub net_wm_state: Atom,
6666
     pub net_wm_state_modal: Atom,
6767
     pub net_wm_state_fullscreen: Atom,
68
+    pub net_wm_state_above: Atom,
6869
     // EWMH atoms for workspaces
6970
     pub net_supported: Atom,
7071
     pub net_supporting_wm_check: Atom,
@@ -133,6 +134,7 @@ impl Connection {
133134
         let net_wm_state = conn.intern_atom(false, b"_NET_WM_STATE")?.reply()?.atom;
134135
         let net_wm_state_modal = conn.intern_atom(false, b"_NET_WM_STATE_MODAL")?.reply()?.atom;
135136
         let net_wm_state_fullscreen = conn.intern_atom(false, b"_NET_WM_STATE_FULLSCREEN")?.reply()?.atom;
137
+        let net_wm_state_above = conn.intern_atom(false, b"_NET_WM_STATE_ABOVE")?.reply()?.atom;
136138
 
137139
         // Intern EWMH atoms for workspaces and WM identification
138140
         let net_supported = conn.intern_atom(false, b"_NET_SUPPORTED")?.reply()?.atom;
@@ -199,6 +201,7 @@ impl Connection {
199201
             net_wm_state,
200202
             net_wm_state_modal,
201203
             net_wm_state_fullscreen,
204
+            net_wm_state_above,
202205
             net_supported,
203206
             net_supporting_wm_check,
204207
             net_client_list,
@@ -769,7 +772,7 @@ impl Connection {
769772
             }
770773
         }
771774
 
772
-        // 3. Check _NET_WM_STATE for modal windows
775
+        // 3. Check _NET_WM_STATE for modal or above windows
773776
         if let Ok(cookie) = self.conn.get_property(
774777
             false,
775778
             window,
@@ -786,6 +789,10 @@ impl Connection {
786789
                             tracing::debug!("Window {} is modal, should float", window);
787790
                             return true;
788791
                         }
792
+                        if atom == self.net_wm_state_above {
793
+                            tracing::debug!("Window {} has ABOVE state, should float", window);
794
+                            return true;
795
+                        }
789796
                     }
790797
                 }
791798
             }
@@ -1067,6 +1074,8 @@ impl Connection {
10671074
             self.net_close_window,
10681075
             self.net_wm_state,
10691076
             self.net_wm_state_fullscreen,
1077
+            self.net_wm_state_modal,
1078
+            self.net_wm_state_above,
10701079
             self.net_wm_name,
10711080
         ];
10721081
         self.conn.change_property32(
gar/src/x11/events.rsmodified
@@ -1059,8 +1059,11 @@ impl WindowManager {
10591059
                 self.conn.flush()?;
10601060
                 return Ok(());
10611061
             }
1062
-            // Not on edge - if this is a focused floating window, replay the click
1062
+            // Not on edge - if this is a focused floating window, raise it and replay the click
1063
+            // This ensures clicking on a floating window that somehow ended up behind
1064
+            // other windows will bring it to the front
10631065
             if self.focused_window == Some(window) {
1066
+                self.raise_window(window)?;
10641067
                 self.conn.conn.allow_events(
10651068
                     x11rb::protocol::xproto::Allow::REPLAY_POINTER,
10661069
                     x11rb::CURRENT_TIME,
@@ -1777,6 +1780,19 @@ impl WindowManager {
17771780
                     _ => {}
17781781
                 }
17791782
             }
1783
+            // Handle ABOVE state changes - raise window when requested
1784
+            else if property == self.conn.net_wm_state_above {
1785
+                match action {
1786
+                    1 | 2 => {
1787
+                        // Add or toggle ABOVE - raise the window
1788
+                        tracing::info!("Window {} requesting ABOVE state, raising", window);
1789
+                        if self.windows.contains_key(&window) {
1790
+                            self.raise_window(window)?;
1791
+                        }
1792
+                    }
1793
+                    _ => {}
1794
+                }
1795
+            }
17801796
         } else {
17811797
             tracing::trace!("Unhandled ClientMessage type: {}", msg_type);
17821798
         }
@@ -2987,8 +3003,10 @@ impl WindowManager {
29873003
         // Raise in X11 - if window has a frame, raise the frame instead
29883004
         let aux = ConfigureWindowAux::new().stack_mode(StackMode::ABOVE);
29893005
         if let Some(frame) = self.frames.frame_for_client(window) {
3006
+            tracing::info!("raise_window: window={} -> raising frame={}", window, frame);
29903007
             self.conn.conn.configure_window(frame, &aux)?;
29913008
         } else {
3009
+            tracing::info!("raise_window: window={} (no frame)", window);
29923010
             self.conn.conn.configure_window(window, &aux)?;
29933011
         }
29943012
         self.conn.flush()?;