@@ -454,11 +454,26 @@ impl WmState { |
| 454 | let ws = self.workspaces.get(ws_idx); | 454 | let ws = self.workspaces.get(ws_idx); |
| 455 | let screen_rect = self.monitor_rect(mi); | 455 | let screen_rect = self.monitor_rect(mi); |
| 456 | let geometries = self.workspace_render_geometries(ws_idx, screen_rect); | 456 | let geometries = self.workspace_render_geometries(ws_idx, screen_rect); |
| | 457 | + // Only the active member of each stack lives at the tile rect. |
| | 458 | + // Non-active members get staged off-screen via hide_window so |
| | 459 | + // macOS's per-app global z-order cannot surface a non-active |
| | 460 | + // member above the active one (which happened when stacks |
| | 461 | + // contained windows from different apps and the user focused |
| | 462 | + // a sibling of one of those apps elsewhere — e.g. a Ghostty |
| | 463 | + // member of a Messages-active stack rising to the top of the |
| | 464 | + // tile when the user focused a different Ghostty on another |
| | 465 | + // monitor). focus_geometries returns one entry per visible |
| | 466 | + // tile (active for stacks, the leaf window for BSP leaves), so |
| | 467 | + // the difference vs render geometries is exactly the set of |
| | 468 | + // non-active stack members. |
| | 469 | + let actives = self.workspace_focus_geometries(ws_idx, screen_rect); |
| | 470 | + let active_ids: std::collections::HashSet<super::window::WindowId> = |
| | 471 | + actives.iter().map(|(w, _)| *w).collect(); |
| 457 | tracing::debug!(monitor = mi, workspace = %ws.id, windows = geometries.len(), | 472 | tracing::debug!(monitor = mi, workspace = %ws.id, windows = geometries.len(), |
| 458 | sr_x = screen_rect.x, sr_y = screen_rect.y, sr_w = screen_rect.width, | 473 | sr_x = screen_rect.x, sr_y = screen_rect.y, sr_w = screen_rect.width, |
| 459 | sr_h = screen_rect.height, "apply_layout"); | 474 | sr_h = screen_rect.height, "apply_layout"); |
| 460 | | 475 | |
| 461 | - for (wid, rect) in &geometries { | 476 | + for (wid, rect) in &actives { |
| 462 | tracing::debug!( | 477 | tracing::debug!( |
| 463 | wid, | 478 | wid, |
| 464 | x = rect.x, | 479 | x = rect.x, |
@@ -469,6 +484,12 @@ impl WmState { |
| 469 | ); | 484 | ); |
| 470 | self.show_window(*wid, *rect); | 485 | self.show_window(*wid, *rect); |
| 471 | } | 486 | } |
| | 487 | + for (wid, _) in &geometries { |
| | 488 | + if !active_ids.contains(wid) { |
| | 489 | + tracing::debug!(wid, "stack non-active hidden off-screen"); |
| | 490 | + self.hide_window(*wid); |
| | 491 | + } |
| | 492 | + } |
| 472 | | 493 | |
| 473 | for fw in &ws.floating { | 494 | for fw in &ws.floating { |
| 474 | tracing::debug!( | 495 | tracing::debug!( |