Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions src/backend/wayland/compositor/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ use smithay::{
buffer::BufferHandler,
compositor::{CompositorHandler, get_parent, is_sync_subsurface},
dmabuf::{DmabufGlobal, DmabufHandler, DmabufState, ImportNotifier},
keyboard_shortcuts_inhibit::{
KeyboardShortcutsInhibitHandler, KeyboardShortcutsInhibitState,
KeyboardShortcutsInhibitor,
},
output::OutputHandler,
seat::WaylandFocus,
selection::data_device::{ClientDndGrabHandler, ServerDndGrabHandler},
Expand Down Expand Up @@ -210,8 +214,24 @@ impl XWaylandKeyboardGrabHandler for WaylandState {
}
}
// For unmanaged X11 surfaces (like dmenu), search in the space
self.window_for_surface(surface)
.map(KeyboardFocusTarget::Window)
if let Some(window) = self.window_for_surface(surface) {
return Some(KeyboardFocusTarget::Window(window));
}

// Fallback: If XWayland requests a grab for a surface that isn't mapped
// as a full window (e.g., grabbing the root window or a dummy surface),
// we must still allow the grab by returning the raw WlSurface.
Some(KeyboardFocusTarget::WlSurface(surface.clone()))
}
}

impl KeyboardShortcutsInhibitHandler for WaylandState {
fn keyboard_shortcuts_inhibit_state(&mut self) -> &mut KeyboardShortcutsInhibitState {
&mut self.keyboard_shortcuts_inhibit_state
}

fn new_inhibitor(&mut self, _inhibitor: KeyboardShortcutsInhibitor) {
// We handle the inhibitor implicitly via KeyboardShortcutsInhibitState::keyboard_shortcuts_inhibited
}
}

Expand Down
9 changes: 5 additions & 4 deletions src/backend/wayland/compositor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ pub use state::{WaylandClientState, WaylandState, WindowIdMarker};

use smithay::{
delegate_compositor, delegate_data_device, delegate_dmabuf, delegate_idle_inhibit,
delegate_layer_shell, delegate_output, delegate_pointer_gestures, delegate_relative_pointer,
delegate_seat, delegate_session_lock, delegate_shm, delegate_viewporter,
delegate_xdg_activation, delegate_xdg_decoration, delegate_xdg_shell,
delegate_xwayland_keyboard_grab, delegate_xwayland_shell,
delegate_keyboard_shortcuts_inhibit, delegate_layer_shell, delegate_output,
delegate_pointer_gestures, delegate_relative_pointer, delegate_seat, delegate_session_lock,
delegate_shm, delegate_viewporter, delegate_xdg_activation, delegate_xdg_decoration,
delegate_xdg_shell, delegate_xwayland_keyboard_grab, delegate_xwayland_shell,
};

// ---------------------------------------------------------------------------
Expand All @@ -67,5 +67,6 @@ delegate_xdg_activation!(WaylandState);
delegate_xdg_decoration!(WaylandState);
delegate_xdg_shell!(WaylandState);
delegate_session_lock!(WaylandState);
delegate_keyboard_shortcuts_inhibit!(WaylandState);
delegate_xwayland_keyboard_grab!(WaylandState);
delegate_xwayland_shell!(WaylandState);
4 changes: 4 additions & 0 deletions src/backend/wayland/compositor/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use smithay::{
dmabuf::{DmabufFeedbackBuilder, DmabufGlobal, DmabufState},
foreign_toplevel_list::{ForeignToplevelHandle, ForeignToplevelListState},
idle_inhibit::IdleInhibitManagerState,
keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState,
output::OutputManagerState,
pointer_gestures::PointerGesturesState,
relative_pointer::RelativePointerManagerState,
Expand Down Expand Up @@ -114,6 +115,7 @@ pub struct WaylandState {
pub session_lock_manager_state: SessionLockManagerState,
pub lock_state: SessionLockState,
pub lock_surfaces: HashMap<String, LockSurface>,
pub keyboard_shortcuts_inhibit_state: KeyboardShortcutsInhibitState,
pub idle_inhibiting_surfaces: HashSet<WlSurface>,
pub(super) render_node: Option<DrmNode>,

Expand Down Expand Up @@ -224,6 +226,7 @@ impl WaylandState {
let viewporter_state = ViewporterState::new::<Self>(&dh);
let idle_inhibit_manager_state = IdleInhibitManagerState::new::<Self>(&dh);
let session_lock_manager_state = SessionLockManagerState::new::<Self, _>(&dh, |_| true);
let keyboard_shortcuts_inhibit_state = KeyboardShortcutsInhibitState::new::<Self>(&dh);

// -- Seat (input devices) --
let cursor_config = wm.g.cfg.cursor.clone();
Expand Down Expand Up @@ -257,6 +260,7 @@ impl WaylandState {
viewporter_state,
idle_inhibit_manager_state,
session_lock_manager_state,
keyboard_shortcuts_inhibit_state,
lock_state: SessionLockState::Unlocked,
lock_surfaces: HashMap::new(),
idle_inhibiting_surfaces: HashSet::new(),
Expand Down
11 changes: 0 additions & 11 deletions src/backend/wayland/compositor/window/classify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,6 @@ impl WaylandState {
WindowType::Normal
}

/// Check if a window should suppress WM keyboard shortcuts when focused.
///
/// Returns true for overlay windows (dmenu, popups, menus) where
/// keyboard input should go to the window without triggering keybindings.
pub fn should_suppress_shortcuts_for(&self, window: &Window) -> bool {
match self.classify_window(window) {
WindowType::Overlay | WindowType::Launcher | WindowType::Unmanaged => true,
WindowType::Normal | WindowType::Dying => false,
}
}

/// Iterator over windows in z-order (top-to-bottom), along with their type.
///
/// This follows the render-order defined in `assemble_scene_elements!`:
Expand Down
40 changes: 27 additions & 13 deletions src/wayland/input/keyboard/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::backend::wayland::compositor::{KeyboardFocusTarget, WaylandState};
use crate::wayland::common::modifiers_to_x11_mask;

use smithay::utils::SERIAL_COUNTER;
use smithay::wayland::keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitorSeat;

/// Handle keyboard events.
pub fn handle_keyboard<B: InputBackend>(
Expand All @@ -17,20 +18,33 @@ pub fn handle_keyboard<B: InputBackend>(
event: impl KeyboardKeyEvent<B>,
) {
let serial = SERIAL_COUNTER.next_serial();
let wm_shortcuts_allowed = match keyboard_handle.current_focus() {
None => true,
Some(KeyboardFocusTarget::Window(ref w)) => !state.should_suppress_shortcuts_for(w),
Some(KeyboardFocusTarget::WlSurface(ref s)) => {
let interactivity = with_states(s, |states| {
states
.cached_state
.get::<LayerSurfaceCachedState>()
.current()
.keyboard_interactivity
});
interactivity != KeyboardInteractivity::Exclusive
let wm_shortcuts_allowed = if keyboard_handle.is_grabbed() {
false
} else {
if state.seat.keyboard_shortcuts_inhibited() {
false
} else {
match keyboard_handle.current_focus() {
None => true,
Some(KeyboardFocusTarget::Window(_)) => true,
Some(KeyboardFocusTarget::WlSurface(ref s)) => {
let is_exclusive = with_states(s, |states| {
if states.cached_state.has::<LayerSurfaceCachedState>() {
states
.cached_state
.get::<LayerSurfaceCachedState>()
.current()
.keyboard_interactivity
== KeyboardInteractivity::Exclusive
} else {
false
}
});
!is_exclusive
}
Some(KeyboardFocusTarget::Popup(_)) => false,
}
}
Some(KeyboardFocusTarget::Popup(_)) => false,
};
let key_code = event.key_code();
let key_state = event.state();
Expand Down
Loading