diff --git a/src/notifications/popup.rs b/src/notifications/popup.rs index 394e136..a45e402 100644 --- a/src/notifications/popup.rs +++ b/src/notifications/popup.rs @@ -172,9 +172,21 @@ fn create_window() -> gtk4::Window { window.init_layer_shell(); window.set_namespace(Some("breadbar-notif")); crate::surface::apply(&window, "breadbar-notif"); - // OnDemand so an inline-reply GtkEntry can take keys without the popup - // stealing every keystroke the rest of the time. - window.set_keyboard_mode(KeyboardMode::OnDemand); + // Toasts are purely informational: they never grab keyboard focus... + window.set_keyboard_mode(KeyboardMode::None); + // ...and click through entirely, via an empty input region — every + // pointer event passes straight to whatever's underneath instead of + // hitting the toast. `make_card` below does build action buttons and, + // when a notification carries INLINE_REPLY_KEY, a reply `GtkEntry` — + // but with no input region reaching the toast at all, neither is ever + // clickable or focusable from here regardless of keyboard mode, so + // OnDemand would grant a focus capability nothing can trigger. Those + // controls are only reachable from the history window (history.rs), + // which is opened deliberately and correctly keeps OnDemand + normal + // hit-testing. If the toast itself grows real click interactivity + // later, this needs to become a real (non-empty) input region sized to + // just the interactive rows, not a blanket revert to OnDemand. + crate::surface::click_through(&window); crate::theme::bind_auto(&window); window } diff --git a/src/surface.rs b/src/surface.rs index 4b69705..10adcdc 100644 --- a/src/surface.rs +++ b/src/surface.rs @@ -86,3 +86,28 @@ pub fn apply(window: >k4::Window, namespace: &str) { window.set_size_request(px, -1); } } + +/// Makes `window` fully click-through: an empty layer-shell input region +/// means every pointer event passes to whatever is underneath instead of +/// being consumed by this surface. Deliberately opt-in, not part of +/// `apply()` — like `exclusive` zone and `keyboard` mode (see the module +/// doc comment), this isn't a `[surfaces.*]` schema concept, and most of +/// breadbar's satellites (history, the panel, the dismiss-scrim) genuinely +/// need real hit-testing. Only a purely-informational surface — today just +/// the notification toast — should call this. +/// +/// Must be applied in a `connect_map` handler: the surface (and therefore +/// `window.surface()`) doesn't exist until the window is mapped. +/// +/// This exists so a future migration of a surface's window-setup code +/// (like the one from hand-rolled layer-shell calls to this module) can't +/// silently drop a click-through requirement the way `breadbar-notif` did +/// once already — see the git history of `notifications/popup.rs` around +/// the "stop toast popups from stealing focus or blocking clicks" fix. +pub fn click_through(window: >k4::Window) { + window.connect_map(|win| { + if let Some(surface) = win.surface() { + surface.set_input_region(Some(>k4::cairo::Region::create())); + } + }); +}