fix: only cancel grabs the compositor started for its own interactions

This commit is contained in:
Hojjat 2026-09-15 17:35:18 -06:00 • committed by Ashley Wulber
parent 26daf75d93
commit 50c170c355

View file

@ -19,7 +19,7 @@ use crate::{
Stage, render_input_order, Stage, render_input_order,
target::{KeyboardFocusTarget, PointerFocusTarget}, target::{KeyboardFocusTarget, PointerFocusTarget},
}, },
grabs::{ReleaseMode, ResizeEdge}, grabs::{MenuGrab, MoveGrab, ReleaseMode, ResizeEdge, ResizeGrab},
layout::{ layout::{
floating::ResizeGrabMarker, floating::ResizeGrabMarker,
tiling::{NodeDesc, SwapWindowGrab, TilingLayout}, tiling::{NodeDesc, SwapWindowGrab, TilingLayout},
@ -49,7 +49,7 @@ use smithay::{
PointerAxisEvent, ProximityState, TabletToolButtonEvent, TabletToolEvent, PointerAxisEvent, ProximityState, TabletToolButtonEvent, TabletToolEvent,
TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TouchEvent, TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TouchEvent,
}, },
desktop::{PopupKeyboardGrab, WindowSurfaceType, utils::under_from_surface_tree}, desktop::{WindowSurfaceType, utils::under_from_surface_tree},
input::{ input::{
Seat, Seat,
keyboard::KeyboardHandle, keyboard::KeyboardHandle,
@ -2306,17 +2306,15 @@ impl State {
let keyboard = seat.get_keyboard().unwrap(); let keyboard = seat.get_keyboard().unwrap();
let pointer = seat.get_pointer().unwrap(); let pointer = seat.get_pointer().unwrap();
// We're only interested in filtering keyboard grabs if we initiated them. // Escape only cancels grabs the compositor started for its own interactions
// The easiest way to check that is to check the type of the grab. // For keyboard: SwapWindowGrab
let keyboard_grabbed = keyboard.with_grab(|_serial, grab| { // For pointer: MoveGrab, ResizeGrab, and MenuGrab
grab.is::<SwapWindowGrab>() || grab.is::<PopupKeyboardGrab<State>>() let keyboard_grabbed =
keyboard.with_grab(|_serial, grab| grab.is::<SwapWindowGrab>()) == Some(true);
let pointer_grabbed = pointer.with_grab(|_serial, grab| {
grab.is::<MoveGrab>() || grab.is::<ResizeGrab>() || grab.is::<MenuGrab>()
}) == Some(true); }) == Some(true);
// A virtual-keyboard key can arrive while the seat's pointer is grabbed by that let is_grabbed = keyboard_grabbed || pointer_grabbed;
// same on-screen keyboard's own button press (the implicit grab from clicking an OSK
// key). That pointer grab must not capture the injected key, otherwise e.g.
// pressing esc on a virtual keyboard gets swallowed here
let from_vk = matches!(backend_id, InputBackendId::VirtualKeyboard);
let is_grabbed = keyboard_grabbed || (pointer.is_grabbed() && !from_vk);
let current_focus = keyboard.current_focus(); let current_focus = keyboard.current_focus();
//this should fall back to active output since there may not be a focused output //this should fall back to active output since there may not be a focused output