From d915d08f80aa07bb71494a693edbdb24049aa8a3 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Thu, 31 Jul 2025 13:01:16 +0200 Subject: [PATCH] input: Don't follow focus for resize borders --- src/debug.rs | 4 +-- src/input/mod.rs | 29 ++++++++++++++++----- src/shell/element/stack.rs | 10 +++++-- src/shell/element/window.rs | 10 +++++-- src/shell/focus/target.rs | 52 +++++++++++++++++++++++++++---------- src/shell/seats.rs | 5 ++++ 6 files changed, 83 insertions(+), 27 deletions(-) diff --git a/src/debug.rs b/src/debug.rs index f6b8e6ce..3c658bcc 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -287,7 +287,7 @@ fn format_pointer_focus(focus: Option) -> String { } _ => format!("Surface {}", surface.id().protocol_id()), }, - Some(StackUI(stack)) => format!( + Some(StackUI { stack, .. }) => format!( "Stack SSD {} ({})", match stack.active().0.underlying_surface() { WindowSurface::Wayland(t) => t.wl_surface().id().protocol_id(), @@ -295,7 +295,7 @@ fn format_pointer_focus(focus: Option) -> String { }, stack.active().title() ), - Some(WindowUI(window)) => format!( + Some(WindowUI { window, .. }) => format!( "Window SSD {} ({})", match window.surface().0.underlying_surface() { WindowSurface::Wayland(t) => t.wl_surface().id().protocol_id(), diff --git a/src/input/mod.rs b/src/input/mod.rs index 9e252569..b0cc60a1 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -22,7 +22,7 @@ use crate::{ tiling::{NodeDesc, SwapWindowGrab, TilingLayout}, }, zoom::ZoomState, - LastModifierChange, SeatExt, Trigger, + LastAcknowlegedElement, LastModifierChange, SeatExt, Trigger, }, utils::{float::NextDown, prelude::*, quirks::workspace_overview_is_open}, wayland::{ @@ -391,18 +391,33 @@ impl State { //If the pointer isn't grabbed, we should check if the focused element should be updated } else if self.common.config.cosmic_conf.focus_follows_cursor { let shell = self.common.shell.read(); - let old_keyboard_target = State::element_under( - original_position, - ¤t_output, - &*shell, - &seat, - ); + let old_keyboard_target = seat + .user_data() + .get::() + .unwrap() + .0 + .lock() + .unwrap() + .clone(); let new_keyboard_target = State::element_under(position, &output, &*shell, &seat); if old_keyboard_target != new_keyboard_target && new_keyboard_target.is_some() + && new_under.as_ref().is_some_and(|(target, relative_offset)| { + target.should_follow_focus( + position.as_logical() - relative_offset.clone(), + ) + }) { + *seat + .user_data() + .get::() + .unwrap() + .0 + .lock() + .unwrap() = new_keyboard_target.clone(); + let create_source = if self.common.pointer_focus_state.is_none() { true } else { diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index 2384e060..a2fdd6f0 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -507,14 +507,20 @@ impl CosmicStack { && point_i32.y - geo.loc.y < geo.size.h + TAB_HEIGHT + RESIZE_BORDER) { stack_ui = Some(( - PointerFocusTarget::StackUI(self.clone()), + PointerFocusTarget::StackUI { + stack: self.clone(), + is_border: true, + }, Point::from((0., 0.)), )); } if point_i32.y - geo.loc.y < TAB_HEIGHT { stack_ui = Some(( - PointerFocusTarget::StackUI(self.clone()), + PointerFocusTarget::StackUI { + stack: self.clone(), + is_border: false, + }, Point::from((0., 0.)), )); } diff --git a/src/shell/element/window.rs b/src/shell/element/window.rs index ab195e47..464eaa4d 100644 --- a/src/shell/element/window.rs +++ b/src/shell/element/window.rs @@ -262,14 +262,20 @@ impl CosmicWindow { && point_i32.y - geo.loc.y < geo.size.h + ssd_height + RESIZE_BORDER) { window_ui = Some(( - PointerFocusTarget::WindowUI(self.clone()), + PointerFocusTarget::WindowUI { + window: self.clone(), + is_border: true, + }, Point::from((0., 0.)), )); } if has_ssd && (point_i32.y - geo.loc.y < SSD_HEIGHT) { window_ui = Some(( - PointerFocusTarget::WindowUI(self.clone()), + PointerFocusTarget::WindowUI { + window: self.clone(), + is_border: false, + }, Point::from((0., 0.)), )); } diff --git a/src/shell/focus/target.rs b/src/shell/focus/target.rs index ed01e9ff..5c448502 100644 --- a/src/shell/focus/target.rs +++ b/src/shell/focus/target.rs @@ -42,8 +42,14 @@ pub enum PointerFocusTarget { surface: WlSurface, toplevel: Option, }, - StackUI(CosmicStack), - WindowUI(CosmicWindow), + StackUI { + stack: CosmicStack, + is_border: bool, + }, + WindowUI { + window: CosmicWindow, + is_border: bool, + }, ResizeFork(ResizeForkTarget), ZoomUI(ZoomFocusTarget), } @@ -114,8 +120,8 @@ impl PointerFocusTarget { fn inner_pointer_target(&self) -> &dyn PointerTarget { match self { PointerFocusTarget::WlSurface { surface, .. } => surface, - PointerFocusTarget::StackUI(u) => u, - PointerFocusTarget::WindowUI(u) => u, + PointerFocusTarget::StackUI { stack, .. } => stack, + PointerFocusTarget::WindowUI { window, .. } => window, PointerFocusTarget::ResizeFork(f) => f, PointerFocusTarget::ZoomUI(e) => e, } @@ -124,8 +130,8 @@ impl PointerFocusTarget { fn inner_touch_target(&self) -> &dyn TouchTarget { match self { PointerFocusTarget::WlSurface { surface, .. } => surface, - PointerFocusTarget::StackUI(u) => u, - PointerFocusTarget::WindowUI(u) => u, + PointerFocusTarget::StackUI { stack, .. } => stack, + PointerFocusTarget::WindowUI { window, .. } => window, PointerFocusTarget::ResizeFork(f) => f, PointerFocusTarget::ZoomUI(e) => e, } @@ -174,8 +180,8 @@ impl PointerFocusTarget { .find(|(w, _)| w.wl_surface().map(|s2| s == *s2).unwrap_or(false)) .map(|(s, _)| s) }), - PointerFocusTarget::StackUI(stack) => Some(stack.active()), - PointerFocusTarget::WindowUI(window) => Some(window.surface()), + PointerFocusTarget::StackUI { stack, .. } => Some(stack.active()), + PointerFocusTarget::WindowUI { window, .. } => Some(window.surface()), _ => None, } } @@ -188,6 +194,24 @@ impl PointerFocusTarget { _ => false, } } + + pub fn should_follow_focus(&self, relative_pos: Point) -> bool { + match self { + PointerFocusTarget::WlSurface { toplevel, .. } => { + toplevel.as_ref().is_none_or(|toplevel| match toplevel { + PointerFocusToplevel::Popup(popup) => { + popup.geometry().contains(relative_pos.to_i32_round()) + } + PointerFocusToplevel::Surface(surface) => { + surface.0.geometry().contains(relative_pos.to_i32_round()) + } + }) + } + PointerFocusTarget::StackUI { is_border, .. } + | PointerFocusTarget::WindowUI { is_border, .. } => !*is_border, + PointerFocusTarget::ResizeFork(_) | PointerFocusTarget::ZoomUI(_) => false, + } + } } impl KeyboardFocusTarget { @@ -259,8 +283,8 @@ impl IsAlive for PointerFocusTarget { match self { // XXX? does this change anything PointerFocusTarget::WlSurface { surface, .. } => surface.alive(), - PointerFocusTarget::StackUI(e) => e.alive(), - PointerFocusTarget::WindowUI(e) => e.alive(), + PointerFocusTarget::StackUI { stack, .. } => stack.alive(), + PointerFocusTarget::WindowUI { window, .. } => window.alive(), PointerFocusTarget::ResizeFork(f) => f.alive(), PointerFocusTarget::ZoomUI(_) => true, } @@ -547,8 +571,8 @@ impl WaylandFocus for PointerFocusTarget { Some(match self { PointerFocusTarget::WlSurface { surface, .. } => Cow::Borrowed(surface), PointerFocusTarget::ResizeFork(_) - | PointerFocusTarget::StackUI(_) - | PointerFocusTarget::WindowUI(_) + | PointerFocusTarget::StackUI { .. } + | PointerFocusTarget::WindowUI { .. } | PointerFocusTarget::ZoomUI(_) => { return None; } @@ -557,12 +581,12 @@ impl WaylandFocus for PointerFocusTarget { fn same_client_as(&self, object_id: &ObjectId) -> bool { match self { PointerFocusTarget::WlSurface { surface, .. } => surface.id().same_client_as(object_id), - PointerFocusTarget::StackUI(stack) => stack + PointerFocusTarget::StackUI { stack, .. } => stack .active() .wl_surface() .map(|s| s.id().same_client_as(object_id)) .unwrap_or(false), - PointerFocusTarget::WindowUI(window) => window + PointerFocusTarget::WindowUI { window, .. } => window .wl_surface() .map(|s| s.id().same_client_as(object_id)) .unwrap_or(false), diff --git a/src/shell/seats.rs b/src/shell/seats.rs index c1f6dbae..ccdf556b 100644 --- a/src/shell/seats.rs +++ b/src/shell/seats.rs @@ -6,6 +6,7 @@ use crate::{ backend::render::cursor::CursorState, config::{xkb_config_to_wl, Config}, input::{ModifiersShortcutQueue, SupressedButtons, SupressedKeys}, + shell::focus::target::KeyboardFocusTarget, state::State, }; use smithay::{ @@ -175,6 +176,9 @@ struct FocusedOutput(pub Mutex>); #[derive(Default)] pub struct LastModifierChange(pub Mutex>); +#[derive(Default)] +pub struct LastAcknowlegedElement(pub Mutex>); + pub fn create_seat( dh: &DisplayHandle, seat_state: &mut SeatState, @@ -190,6 +194,7 @@ pub fn create_seat( userdata.insert_if_missing(SupressedButtons::default); userdata.insert_if_missing(ModifiersShortcutQueue::default); userdata.insert_if_missing(LastModifierChange::default); + userdata.insert_if_missing(LastAcknowlegedElement::default); userdata.insert_if_missing_threadsafe(SeatMoveGrabState::default); userdata.insert_if_missing_threadsafe(SeatMenuGrabState::default); userdata.insert_if_missing_threadsafe(CursorState::default);