git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commitf08ed90c267ed7e277425f7d9ef80415be0f5a5a
parent8f4cde87ce
authorLucas Galante <[email protected]>
date2026-08-20 12:33
overview: chrome windows (Popup/Overlay) stay fully interactive

The cce-cloud launcher opened during overview was focused but dead to
input: the overview keyboard gate only passed presses to Overlay-mode
windows and the launcher runs as Popup — every press was silently
eaten (and worked after a click only because that click EXITED
overview, lifting the gate). The click itself was the second bug: the
overview content-press handler grabbed any window into the move-op,
whose tap-release focuses and zooms out of overview.

Popup now counts as chrome alongside Overlay in all three places: the
keyboard gate, the click-block exemption, and the overview press
handler, where chrome presses fall through to normal handling — the
launcher takes clicks and keys like always, and overview stays up.
Clicking a world window still zooms to it; background clicks still
exit.

Co-Authored-By: Claude Fable 5 <[email protected]>

 src/server/cursor.rs         | 26 +++++++++++++++++++++++---
 src/server/keyboard_group.rs |  5 +++++
 2 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/src/server/cursor.rs b/src/server/cursor.rs
index f65d8ea..a784707 100644
--- a/src/server/cursor.rs
+++ b/src/server/cursor.rs
@@ -974,7 +974,11 @@ unsafe extern "C" fn handle_button(listener: *mut ffi::wl_listener, data: *mut s
             SceneNodeDataVal::Window(window) => {
                 if !(*window).is_status_bar() && !(*window).is_wallpaper() {
                     is_app_surface = true;
-                    if (*window).tiling_mode == crate::tiling::TilingMode::Overlay {
+                    // Popup counts as chrome like Overlay: the cce-cloud
+                    // launcher must keep receiving clicks in overview.
+                    if (*window).tiling_mode == crate::tiling::TilingMode::Overlay
+                        || (*window).tiling_mode == crate::tiling::TilingMode::Popup
+                    {
                         is_overlay_window = true;
                     }
                 }
@@ -1110,6 +1114,16 @@ unsafe extern "C" fn handle_button(listener: *mut ffi::wl_listener, data: *mut s
             // border path below (move/resize by zone, zoom-aware) — the
             // resize controls work at any zoom. Content presses grab the
             // whole window; true background presses exit overview.
+            //
+            // Chrome windows (Overlay docks, Popup surfaces like the
+            // cce-cloud launcher) are neither: they stay interactive UI
+            // during overview, so their presses fall through to the normal
+            // path (focus + delivery to the app) and overview stays up.
+            let overview_chrome = !clicked_win.is_null()
+                && matches!(
+                    (*clicked_win).tiling_mode,
+                    crate::tiling::TilingMode::Overlay | crate::tiling::TilingMode::Popup
+                );
             let overview_win_valid = !clicked_win.is_null()
                 && !(*clicked_win).is_status_bar()
                 && !(*clicked_win).is_wallpaper();
@@ -1118,7 +1132,9 @@ unsafe extern "C" fn handle_button(listener: *mut ffi::wl_listener, data: *mut s
             } else {
                 BorderZone::None
             };
-            if overview_win_valid && matches!(overview_border_zone, BorderZone::None) {
+            if overview_chrome {
+                // fall through
+            } else if overview_win_valid && matches!(overview_border_zone, BorderZone::None) {
                 (*server).wm.stop_panning_animation();
                 let cursor_x = (*cursor.wlr_cursor).x;
                 let cursor_y = (*cursor.wlr_cursor).y;
@@ -2097,7 +2113,11 @@ unsafe extern "C" fn handle_touch_down(listener: *mut ffi::wl_listener, data: *m
             SceneNodeDataVal::Window(window) => {
                 if !(*window).is_status_bar() && !(*window).is_wallpaper() {
                     is_app_surface = true;
-                    if (*window).tiling_mode == crate::tiling::TilingMode::Overlay {
+                    // Popup counts as chrome like Overlay: the cce-cloud
+                    // launcher must keep receiving clicks in overview.
+                    if (*window).tiling_mode == crate::tiling::TilingMode::Overlay
+                        || (*window).tiling_mode == crate::tiling::TilingMode::Popup
+                    {
                         is_overlay_window = true;
                     }
                 }
diff --git a/src/server/keyboard_group.rs b/src/server/keyboard_group.rs
index 6a55c66..8cabb76 100644
--- a/src/server/keyboard_group.rs
+++ b/src/server/keyboard_group.rs
@@ -443,7 +443,12 @@ unsafe extern "C" fn handle_group_key(listener: *mut ffi::wl_listener, data: *mu
         KeyConsumer::Focus => {
             let is_overlay_mode = if let crate::seat::Focus::Window(fw) = (*group.seat).focused {
                 if !fw.is_null() {
+                    // Overlay AND Popup: desktop chrome (docks, the
+                    // cce-cloud launcher) stays keyboard-interactive in
+                    // overview — only world windows (spatial thumbnails)
+                    // have their presses eaten.
                     (*fw).tiling_mode == crate::tiling::TilingMode::Overlay
+                        || (*fw).tiling_mode == crate::tiling::TilingMode::Popup
                 } else {
                     false
                 }