1
0
Fork 0
forked from wry/wry

config: add mouse-follows-focus option

This commit is contained in:
Nicolaus Jacobsen 2026-03-10 09:36:13 +01:00 committed by Julian Orth
parent 0d4ee299d4
commit 216d104b73
14 changed files with 134 additions and 6 deletions

View file

@ -2425,6 +2425,16 @@ impl ConfigProxyHandler {
Ok(())
}
fn handle_seat_set_mouse_follows_focus(
&self,
seat: Seat,
enabled: bool,
) -> Result<(), CphError> {
let seat = self.get_seat(seat)?;
seat.set_mouse_follows_focus(enabled);
Ok(())
}
fn get_sized(&self, sized: Resizable) -> Result<ThemeSized, CphError> {
use jay_config::theme::sized::*;
let sized = match sized {
@ -2597,6 +2607,7 @@ impl ConfigProxyHandler {
return Err(CphError::WindowNotVisible(window_id));
}
seat.focus_toplevel(window);
seat.maybe_schedule_warp_mouse_to_focus();
Ok(())
}
@ -3354,6 +3365,9 @@ impl ConfigProxyHandler {
ClientMessage::SeatWarpMouseToFocus { seat } => self
.handle_seat_warp_mouse_to_focus(seat)
.wrn("seat_warp_mouse_to_focus")?,
ClientMessage::SeatSetMouseFollowsFocus { seat, enabled } => self
.handle_seat_set_mouse_follows_focus(seat, enabled)
.wrn("seat_set_mouse_follows_focus")?,
ClientMessage::ConnectorSetUseNativeGamut {
connector,
use_native_gamut,

View file

@ -232,6 +232,9 @@ impl InputPane {
bool(ui, "Focus Follows Mouse", seat.focus_follows_mouse(), |v| {
seat.set_focus_follows_mouse(v);
});
bool(ui, "Mouse Follows Focus", seat.mouse_follows_focus(), |v| {
seat.set_mouse_follows_focus(v);
});
combo_box_ui(
ui,
"Fallback Output Mode",

View file

@ -260,6 +260,8 @@ pub struct WlSeatGlobal {
simple_im: CloneCell<Option<Rc<SimpleIm>>>,
simple_im_enabled: Cell<bool>,
warp_mouse_to_focus_scheduled: Cell<bool>,
warp_mouse_to_focus_skip_target_check: Cell<bool>,
mouse_follows_focus: Cell<bool>,
}
impl PartialEq for WlSeatGlobal {
@ -403,6 +405,8 @@ impl WlSeatGlobal {
simple_im: CloneCell::new(simple_im),
simple_im_enabled: Cell::new(true),
warp_mouse_to_focus_scheduled: Cell::new(false),
warp_mouse_to_focus_skip_target_check: Cell::new(false),
mouse_follows_focus: Cell::new(false),
});
slf.pointer_cursor.set_owner(slf.clone());
slf.modifiers_listener
@ -537,12 +541,13 @@ impl WlSeatGlobal {
self.get_cursor_output()
}
pub fn set_workspace(&self, ws: &Rc<WorkspaceNode>) {
pub fn set_workspace(self: &Rc<Self>, ws: &Rc<WorkspaceNode>) {
let tl = match self.keyboard_node.get().node_toplevel() {
Some(tl) => tl,
_ => return,
};
toplevel_set_workspace(&self.state, tl, ws);
self.maybe_schedule_warp_mouse_to_focus();
}
pub fn mark_last_active(self: &Rc<Self>) {
@ -743,6 +748,7 @@ impl WlSeatGlobal {
&& let Some(tl) = parent.node_toplevel()
{
self.focus_node(tl);
self.maybe_schedule_warp_mouse_to_focus();
}
}
@ -802,6 +808,7 @@ impl WlSeatGlobal {
.find_output_in_direction(&ws.output.get(), direction)
{
target.take_keyboard_navigation_focus(self, direction);
self.maybe_schedule_warp_mouse_to_focus();
}
return;
}
@ -821,6 +828,14 @@ impl WlSeatGlobal {
c.move_focus_from_child(self, tl.deref(), direction);
}
}
self.maybe_schedule_warp_mouse_to_focus();
}
pub fn maybe_schedule_warp_mouse_to_focus(self: &Rc<Self>) {
if self.mouse_follows_focus() {
self.warp_mouse_to_focus_skip_target_check.set(true);
self.schedule_warp_mouse_to_focus();
}
}
pub fn schedule_warp_mouse_to_focus(self: &Rc<Self>) {
@ -848,10 +863,12 @@ impl WlSeatGlobal {
{
let ws = target.ensure_workspace();
toplevel_set_workspace(&self.state, tl, &ws);
self.maybe_schedule_warp_mouse_to_focus();
} else if let Some(parent) = data.parent.get()
&& let Some(c) = parent.node_into_container()
{
c.move_child(tl, direction);
self.maybe_schedule_warp_mouse_to_focus();
}
}
@ -972,6 +989,7 @@ impl WlSeatGlobal {
}
}
self.focus_node(node);
self.maybe_schedule_warp_mouse_to_focus();
}
pub fn focus_prev(self: &Rc<Self>) {
@ -1035,6 +1053,7 @@ impl WlSeatGlobal {
n.deref()
.clone()
.node_do_focus(self, Direction::Unspecified);
self.maybe_schedule_warp_mouse_to_focus();
return;
}
}
@ -1046,6 +1065,7 @@ impl WlSeatGlobal {
n.deref()
.clone()
.node_do_focus(self, Direction::Unspecified);
self.maybe_schedule_warp_mouse_to_focus();
return;
}
}
@ -1087,6 +1107,7 @@ impl WlSeatGlobal {
&& ws.container_visible()
{
self.focus_node(ws.clone());
self.maybe_schedule_warp_mouse_to_focus();
return;
}
None
@ -1111,6 +1132,7 @@ impl WlSeatGlobal {
if let Some(n) = node {
if node_viable(&*n) {
n.node_do_focus(self, Direction::Unspecified);
self.maybe_schedule_warp_mouse_to_focus();
return;
}
}
@ -1164,6 +1186,7 @@ impl WlSeatGlobal {
};
if node.node_visible() && node.node_accepts_focus() {
node.node_do_focus(self, Direction::Unspecified);
self.maybe_schedule_warp_mouse_to_focus();
}
}
@ -1507,6 +1530,15 @@ impl WlSeatGlobal {
self.focus_follows_mouse.get()
}
pub fn set_mouse_follows_focus(&self, enabled: bool) {
self.mouse_follows_focus.set(enabled);
self.state.trigger_cci(CCI_INPUT);
}
pub fn mouse_follows_focus(&self) -> bool {
self.mouse_follows_focus.get()
}
pub fn set_fallback_output_mode(&self, fallback_output_mode: FallbackOutputMode) {
self.fallback_output_mode.set(fallback_output_mode);
self.state.trigger_cci(CCI_INPUT);
@ -2023,15 +2055,18 @@ pub async fn handle_warp_mouse_to_focus(state: Rc<State>) {
state.eng.yield_now().await;
while let Some(seat) = state.pending_warp_mouse_to_focus.try_pop() {
seat.warp_mouse_to_focus_scheduled.set(false);
let skip_target_check = seat.warp_mouse_to_focus_skip_target_check.take();
let Some(tl) = seat.keyboard_node.get().node_toplevel() else {
continue;
};
let (x, y) = tl.node_absolute_position().center();
let Some(target) = state.node_at(x, y).node.node_toplevel() else {
continue;
};
if target.node_id() != tl.node_id() {
continue;
if !skip_target_check {
let Some(target) = state.node_at(x, y).node.node_toplevel() else {
continue;
};
if target.node_id() != tl.node_id() {
continue;
}
}
let (x, y) = (Fixed::from_int(x), Fixed::from_int(y));
seat.motion_event_abs(state.now_usec(), x, y, Warp);

View file

@ -1084,6 +1084,7 @@ impl WlSeatGlobal {
}
}
self.focus_node(node);
self.maybe_schedule_warp_mouse_to_focus();
}
}

View file

@ -974,6 +974,7 @@ impl State {
}
};
self.show_workspace2(Some(seat), &ws.output.get(), &ws);
seat.maybe_schedule_warp_mouse_to_focus();
}
pub fn float_map_ws(&self) -> Rc<WorkspaceNode> {