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 {
974
                         border_width as u16,
974
                         border_width as u16,
975
                     )?;
975
                     )?;
976
 
976
 
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
+
977
                     tracing::debug!(
983
                     tracing::debug!(
978
                         "apply_layout: TILED+FRAME window={} at ({}, {}) size {}x{} (titlebar: {})",
984
                         "apply_layout: TILED+FRAME window={} at ({}, {}) size {}x{} (titlebar: {})",
979
                         window, gapped_x, gapped_y, final_width.max(1), final_height.max(1), titlebar_height
985
                         window, gapped_x, gapped_y, final_width.max(1), final_height.max(1), titlebar_height
@@ -992,6 +998,10 @@ impl WindowManager {
992
                         final_height.max(1),
998
                         final_height.max(1),
993
                         border_width,
999
                         border_width,
994
                     )?;
1000
                     )?;
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)?;
995
                 }
1005
                 }
996
 
1006
 
997
                 // Store the actual geometry for pointer warping
1007
                 // Store the actual geometry for pointer warping
@@ -1034,18 +1044,17 @@ impl WindowManager {
1034
                     if let Some(frame) = self.frames.frame_for_client(window_id) {
1044
                     if let Some(frame) = self.frames.frame_for_client(window_id) {
1035
                         let aux = ConfigureWindowAux::new().stack_mode(StackMode::ABOVE);
1045
                         let aux = ConfigureWindowAux::new().stack_mode(StackMode::ABOVE);
1036
                         self.conn.conn.configure_window(frame, &aux)?;
1046
                         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
+                        );
1037
                     }
1056
                     }
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
-                    );
1043
                 } else {
1057
                 } 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
-
1049
                     // Configure geometry
1058
                     // Configure geometry
1050
                     self.conn.configure_window(
1059
                     self.conn.configure_window(
1051
                         window_id,
1060
                         window_id,
@@ -1059,6 +1068,11 @@ impl WindowManager {
1059
                     // Raise to top of stack (each subsequent window goes above the previous)
1068
                     // Raise to top of stack (each subsequent window goes above the previous)
1060
                     let aux = ConfigureWindowAux::new().stack_mode(StackMode::ABOVE);
1069
                     let aux = ConfigureWindowAux::new().stack_mode(StackMode::ABOVE);
1061
                     self.conn.conn.configure_window(window_id, &aux)?;
1070
                     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
+                    );
1062
                 }
1076
                 }
1063
 
1077
 
1064
                 // Store the actual geometry for pointer warping
1078
                 // Store the actual geometry for pointer warping
gar/src/x11/connection.rsmodified
@@ -65,6 +65,7 @@ pub struct Connection {
65
     pub net_wm_state: Atom,
65
     pub net_wm_state: Atom,
66
     pub net_wm_state_modal: Atom,
66
     pub net_wm_state_modal: Atom,
67
     pub net_wm_state_fullscreen: Atom,
67
     pub net_wm_state_fullscreen: Atom,
68
+    pub net_wm_state_above: Atom,
68
     // EWMH atoms for workspaces
69
     // EWMH atoms for workspaces
69
     pub net_supported: Atom,
70
     pub net_supported: Atom,
70
     pub net_supporting_wm_check: Atom,
71
     pub net_supporting_wm_check: Atom,
@@ -133,6 +134,7 @@ impl Connection {
133
         let net_wm_state = conn.intern_atom(false, b"_NET_WM_STATE")?.reply()?.atom;
134
         let net_wm_state = conn.intern_atom(false, b"_NET_WM_STATE")?.reply()?.atom;
134
         let net_wm_state_modal = conn.intern_atom(false, b"_NET_WM_STATE_MODAL")?.reply()?.atom;
135
         let net_wm_state_modal = conn.intern_atom(false, b"_NET_WM_STATE_MODAL")?.reply()?.atom;
135
         let net_wm_state_fullscreen = conn.intern_atom(false, b"_NET_WM_STATE_FULLSCREEN")?.reply()?.atom;
136
         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;
136
 
138
 
137
         // Intern EWMH atoms for workspaces and WM identification
139
         // Intern EWMH atoms for workspaces and WM identification
138
         let net_supported = conn.intern_atom(false, b"_NET_SUPPORTED")?.reply()?.atom;
140
         let net_supported = conn.intern_atom(false, b"_NET_SUPPORTED")?.reply()?.atom;
@@ -199,6 +201,7 @@ impl Connection {
199
             net_wm_state,
201
             net_wm_state,
200
             net_wm_state_modal,
202
             net_wm_state_modal,
201
             net_wm_state_fullscreen,
203
             net_wm_state_fullscreen,
204
+            net_wm_state_above,
202
             net_supported,
205
             net_supported,
203
             net_supporting_wm_check,
206
             net_supporting_wm_check,
204
             net_client_list,
207
             net_client_list,
@@ -769,7 +772,7 @@ impl Connection {
769
             }
772
             }
770
         }
773
         }
771
 
774
 
772
-        // 3. Check _NET_WM_STATE for modal windows
775
+        // 3. Check _NET_WM_STATE for modal or above windows
773
         if let Ok(cookie) = self.conn.get_property(
776
         if let Ok(cookie) = self.conn.get_property(
774
             false,
777
             false,
775
             window,
778
             window,
@@ -786,6 +789,10 @@ impl Connection {
786
                             tracing::debug!("Window {} is modal, should float", window);
789
                             tracing::debug!("Window {} is modal, should float", window);
787
                             return true;
790
                             return true;
788
                         }
791
                         }
792
+                        if atom == self.net_wm_state_above {
793
+                            tracing::debug!("Window {} has ABOVE state, should float", window);
794
+                            return true;
795
+                        }
789
                     }
796
                     }
790
                 }
797
                 }
791
             }
798
             }
@@ -1067,6 +1074,8 @@ impl Connection {
1067
             self.net_close_window,
1074
             self.net_close_window,
1068
             self.net_wm_state,
1075
             self.net_wm_state,
1069
             self.net_wm_state_fullscreen,
1076
             self.net_wm_state_fullscreen,
1077
+            self.net_wm_state_modal,
1078
+            self.net_wm_state_above,
1070
             self.net_wm_name,
1079
             self.net_wm_name,
1071
         ];
1080
         ];
1072
         self.conn.change_property32(
1081
         self.conn.change_property32(
gar/src/x11/events.rsmodified
@@ -1059,8 +1059,11 @@ impl WindowManager {
1059
                 self.conn.flush()?;
1059
                 self.conn.flush()?;
1060
                 return Ok(());
1060
                 return Ok(());
1061
             }
1061
             }
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
1063
             if self.focused_window == Some(window) {
1065
             if self.focused_window == Some(window) {
1066
+                self.raise_window(window)?;
1064
                 self.conn.conn.allow_events(
1067
                 self.conn.conn.allow_events(
1065
                     x11rb::protocol::xproto::Allow::REPLAY_POINTER,
1068
                     x11rb::protocol::xproto::Allow::REPLAY_POINTER,
1066
                     x11rb::CURRENT_TIME,
1069
                     x11rb::CURRENT_TIME,
@@ -1777,6 +1780,19 @@ impl WindowManager {
1777
                     _ => {}
1780
                     _ => {}
1778
                 }
1781
                 }
1779
             }
1782
             }
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
+            }
1780
         } else {
1796
         } else {
1781
             tracing::trace!("Unhandled ClientMessage type: {}", msg_type);
1797
             tracing::trace!("Unhandled ClientMessage type: {}", msg_type);
1782
         }
1798
         }
@@ -2987,8 +3003,10 @@ impl WindowManager {
2987
         // Raise in X11 - if window has a frame, raise the frame instead
3003
         // Raise in X11 - if window has a frame, raise the frame instead
2988
         let aux = ConfigureWindowAux::new().stack_mode(StackMode::ABOVE);
3004
         let aux = ConfigureWindowAux::new().stack_mode(StackMode::ABOVE);
2989
         if let Some(frame) = self.frames.frame_for_client(window) {
3005
         if let Some(frame) = self.frames.frame_for_client(window) {
3006
+            tracing::info!("raise_window: window={} -> raising frame={}", window, frame);
2990
             self.conn.conn.configure_window(frame, &aux)?;
3007
             self.conn.conn.configure_window(frame, &aux)?;
2991
         } else {
3008
         } else {
3009
+            tracing::info!("raise_window: window={} (no frame)", window);
2992
             self.conn.conn.configure_window(window, &aux)?;
3010
             self.conn.conn.configure_window(window, &aux)?;
2993
         }
3011
         }
2994
         self.conn.flush()?;
3012
         self.conn.flush()?;