Merge pull request #820 from mahkoh/jorth/warp-to-focused
config: add warp-mouse-to-focus action
This commit is contained in:
commit
6727f3e4bc
13 changed files with 74 additions and 2 deletions
|
|
@ -407,6 +407,10 @@ impl ConfigClient {
|
||||||
self.send(&ClientMessage::SeatMove { seat, direction });
|
self.send(&ClientMessage::SeatMove { seat, direction });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn seat_warp_mouse_to_focus(&self, seat: Seat) {
|
||||||
|
self.send(&ClientMessage::SeatWarpMouseToFocus { seat });
|
||||||
|
}
|
||||||
|
|
||||||
pub fn window_move(&self, window: Window, direction: Direction) {
|
pub fn window_move(&self, window: Window, direction: Direction) {
|
||||||
self.send(&ClientMessage::WindowMove { window, direction });
|
self.send(&ClientMessage::WindowMove { window, direction });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -858,6 +858,9 @@ pub enum ClientMessage<'a> {
|
||||||
RemoveVirtualOutput {
|
RemoveVirtualOutput {
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
},
|
},
|
||||||
|
SeatWarpMouseToFocus {
|
||||||
|
seat: Seat,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
|
|
||||||
|
|
@ -645,6 +645,11 @@ impl Seat {
|
||||||
pub fn enable_unicode_input(self) {
|
pub fn enable_unicode_input(self) {
|
||||||
get!().seat_enable_unicode_input(self);
|
get!().seat_enable_unicode_input(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Warps the cursor to the center of the currently focused window.
|
||||||
|
pub fn warp_mouse_to_focus(self) {
|
||||||
|
get!().seat_warp_mouse_to_focus(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A focus-follows-mouse mode.
|
/// A focus-follows-mouse mode.
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ use {
|
||||||
},
|
},
|
||||||
jay_screencast::{perform_screencast_realloc, perform_toplevel_screencasts},
|
jay_screencast::{perform_screencast_realloc, perform_toplevel_screencasts},
|
||||||
wl_output::{BlendSpace, OutputId, PersistentOutputState, WlOutputGlobal},
|
wl_output::{BlendSpace, OutputId, PersistentOutputState, WlOutputGlobal},
|
||||||
wl_seat::handle_position_hint_requests,
|
wl_seat::{handle_position_hint_requests, handle_warp_mouse_to_focus},
|
||||||
wl_surface::{
|
wl_surface::{
|
||||||
NoneSurfaceExt, xdg_surface::handle_xdg_surface_configure_events,
|
NoneSurfaceExt, xdg_surface::handle_xdg_surface_configure_events,
|
||||||
zwp_input_popup_surface_v2::input_popup_positioning,
|
zwp_input_popup_surface_v2::input_popup_positioning,
|
||||||
|
|
@ -377,6 +377,7 @@ fn start_compositor2(
|
||||||
toplevel_managers: Default::default(),
|
toplevel_managers: Default::default(),
|
||||||
node_at_tree: Default::default(),
|
node_at_tree: Default::default(),
|
||||||
position_hint_requests: Default::default(),
|
position_hint_requests: Default::default(),
|
||||||
|
pending_warp_mouse_to_focus: Default::default(),
|
||||||
backend_connector_state_serials: Default::default(),
|
backend_connector_state_serials: Default::default(),
|
||||||
head_names: Default::default(),
|
head_names: Default::default(),
|
||||||
head_managers: Default::default(),
|
head_managers: Default::default(),
|
||||||
|
|
@ -605,6 +606,10 @@ fn start_global_event_handlers(state: &Rc<State>) -> Vec<SpawnedFuture<()>> {
|
||||||
"redraw control centers",
|
"redraw control centers",
|
||||||
redraw_control_centers(state.clone()),
|
redraw_control_centers(state.clone()),
|
||||||
),
|
),
|
||||||
|
eng.spawn(
|
||||||
|
"warp mouse to focus",
|
||||||
|
handle_warp_mouse_to_focus(state.clone()),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2415,6 +2415,12 @@ impl ConfigProxyHandler {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_seat_warp_mouse_to_focus(&self, seat: Seat) -> Result<(), CphError> {
|
||||||
|
let seat = self.get_seat(seat)?;
|
||||||
|
seat.schedule_warp_mouse_to_focus();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn get_sized(&self, sized: Resizable) -> Result<ThemeSized, CphError> {
|
fn get_sized(&self, sized: Resizable) -> Result<ThemeSized, CphError> {
|
||||||
use jay_config::theme::sized::*;
|
use jay_config::theme::sized::*;
|
||||||
let sized = match sized {
|
let sized = match sized {
|
||||||
|
|
@ -3329,6 +3335,9 @@ impl ConfigProxyHandler {
|
||||||
ClientMessage::SeatEnableUnicodeInput { seat } => self
|
ClientMessage::SeatEnableUnicodeInput { seat } => self
|
||||||
.handle_seat_enable_unicode_input(seat)
|
.handle_seat_enable_unicode_input(seat)
|
||||||
.wrn("seat_enable_unicode_input")?,
|
.wrn("seat_enable_unicode_input")?,
|
||||||
|
ClientMessage::SeatWarpMouseToFocus { seat } => self
|
||||||
|
.handle_seat_warp_mouse_to_focus(seat)
|
||||||
|
.wrn("seat_warp_mouse_to_focus")?,
|
||||||
ClientMessage::ConnectorSetUseNativeGamut {
|
ClientMessage::ConnectorSetUseNativeGamut {
|
||||||
connector,
|
connector,
|
||||||
use_native_gamut,
|
use_native_gamut,
|
||||||
|
|
|
||||||
|
|
@ -258,6 +258,7 @@ pub struct WlSeatGlobal {
|
||||||
modifiers_forward: EventSource<dyn LedsListener>,
|
modifiers_forward: EventSource<dyn LedsListener>,
|
||||||
simple_im: CloneCell<Option<Rc<SimpleIm>>>,
|
simple_im: CloneCell<Option<Rc<SimpleIm>>>,
|
||||||
simple_im_enabled: Cell<bool>,
|
simple_im_enabled: Cell<bool>,
|
||||||
|
warp_mouse_to_focus_scheduled: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for WlSeatGlobal {
|
impl PartialEq for WlSeatGlobal {
|
||||||
|
|
@ -400,6 +401,7 @@ impl WlSeatGlobal {
|
||||||
modifiers_forward: Default::default(),
|
modifiers_forward: Default::default(),
|
||||||
simple_im: CloneCell::new(simple_im),
|
simple_im: CloneCell::new(simple_im),
|
||||||
simple_im_enabled: Cell::new(true),
|
simple_im_enabled: Cell::new(true),
|
||||||
|
warp_mouse_to_focus_scheduled: Cell::new(false),
|
||||||
});
|
});
|
||||||
slf.pointer_cursor.set_owner(slf.clone());
|
slf.pointer_cursor.set_owner(slf.clone());
|
||||||
slf.modifiers_listener
|
slf.modifiers_listener
|
||||||
|
|
@ -820,6 +822,12 @@ impl WlSeatGlobal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn schedule_warp_mouse_to_focus(self: &Rc<Self>) {
|
||||||
|
if !self.warp_mouse_to_focus_scheduled.replace(true) {
|
||||||
|
self.state.pending_warp_mouse_to_focus.push(self.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn move_focused(self: &Rc<Self>, direction: Direction) {
|
pub fn move_focused(self: &Rc<Self>, direction: Direction) {
|
||||||
let kb_node = self.keyboard_node.get();
|
let kb_node = self.keyboard_node.get();
|
||||||
let Some(tl) = kb_node.node_toplevel() else {
|
let Some(tl) = kb_node.node_toplevel() else {
|
||||||
|
|
@ -2007,3 +2015,25 @@ pub async fn handle_position_hint_requests(state: Rc<State>) {
|
||||||
req.seat.motion_event_abs(state.now_usec(), x, y);
|
req.seat.motion_event_abs(state.now_usec(), x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn handle_warp_mouse_to_focus(state: Rc<State>) {
|
||||||
|
loop {
|
||||||
|
state.pending_warp_mouse_to_focus.non_empty().await;
|
||||||
|
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 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;
|
||||||
|
}
|
||||||
|
let (x, y) = (Fixed::from_int(x), Fixed::from_int(y));
|
||||||
|
seat.motion_event_abs(state.now_usec(), x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -284,6 +284,7 @@ pub struct State {
|
||||||
pub caps_thread: Option<PrCapsThread>,
|
pub caps_thread: Option<PrCapsThread>,
|
||||||
pub node_at_tree: RefCell<Vec<FoundNode>>,
|
pub node_at_tree: RefCell<Vec<FoundNode>>,
|
||||||
pub position_hint_requests: AsyncQueue<PositionHintRequest>,
|
pub position_hint_requests: AsyncQueue<PositionHintRequest>,
|
||||||
|
pub pending_warp_mouse_to_focus: AsyncQueue<Rc<WlSeatGlobal>>,
|
||||||
pub backend_connector_state_serials: BackendConnectorStateSerials,
|
pub backend_connector_state_serials: BackendConnectorStateSerials,
|
||||||
pub head_names: HeadNames,
|
pub head_names: HeadNames,
|
||||||
pub head_managers:
|
pub head_managers:
|
||||||
|
|
@ -1175,6 +1176,7 @@ impl State {
|
||||||
self.tl_matcher_manager.clear();
|
self.tl_matcher_manager.clear();
|
||||||
self.node_at_tree.borrow_mut().clear();
|
self.node_at_tree.borrow_mut().clear();
|
||||||
self.position_hint_requests.clear();
|
self.position_hint_requests.clear();
|
||||||
|
self.pending_warp_mouse_to_focus.clear();
|
||||||
self.head_managers.clear();
|
self.head_managers.clear();
|
||||||
self.head_managers_async.clear();
|
self.head_managers_async.clear();
|
||||||
self.const_40hz_latch.clear();
|
self.const_40hz_latch.clear();
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,7 @@ pub enum SimpleCommand {
|
||||||
ReloadSimpleIm,
|
ReloadSimpleIm,
|
||||||
EnableUnicodeInput,
|
EnableUnicodeInput,
|
||||||
OpenControlCenter,
|
OpenControlCenter,
|
||||||
|
WarpMouseToFocus,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,7 @@ impl ActionParser<'_> {
|
||||||
"reload-simple-im" => ReloadSimpleIm,
|
"reload-simple-im" => ReloadSimpleIm,
|
||||||
"enable-unicode-input" => EnableUnicodeInput,
|
"enable-unicode-input" => EnableUnicodeInput,
|
||||||
"open-control-center" => OpenControlCenter,
|
"open-control-center" => OpenControlCenter,
|
||||||
|
"warp-mouse-to-focus" => WarpMouseToFocus,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(
|
return Err(
|
||||||
ActionParserError::UnknownSimpleAction(string.to_string()).spanned(span)
|
ActionParserError::UnknownSimpleAction(string.to_string()).spanned(span)
|
||||||
|
|
|
||||||
|
|
@ -247,6 +247,10 @@ impl Action {
|
||||||
b.new(move || persistent.seat.enable_unicode_input())
|
b.new(move || persistent.seat.enable_unicode_input())
|
||||||
}
|
}
|
||||||
SimpleCommand::OpenControlCenter => b.new(open_control_center),
|
SimpleCommand::OpenControlCenter => b.new(open_control_center),
|
||||||
|
SimpleCommand::WarpMouseToFocus => {
|
||||||
|
let persistent = state.persistent.clone();
|
||||||
|
b.new(move || persistent.seat.warp_mouse_to_focus())
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Action::Multi { actions } => {
|
Action::Multi { actions } => {
|
||||||
let actions: Vec<_> = actions.into_iter().map(|a| a.into_fn(state)).collect();
|
let actions: Vec<_> = actions.into_iter().map(|a| a.into_fn(state)).collect();
|
||||||
|
|
|
||||||
|
|
@ -1995,7 +1995,8 @@
|
||||||
"toggle-simple-im-enabled",
|
"toggle-simple-im-enabled",
|
||||||
"reload-simple-im",
|
"reload-simple-im",
|
||||||
"enable-unicode-input",
|
"enable-unicode-input",
|
||||||
"open-control-center"
|
"open-control-center",
|
||||||
|
"warp-mouse-to-focus"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"SimpleIm": {
|
"SimpleIm": {
|
||||||
|
|
|
||||||
|
|
@ -4559,6 +4559,10 @@ The string should have one of the following values:
|
||||||
|
|
||||||
Opens the control center.
|
Opens the control center.
|
||||||
|
|
||||||
|
- `warp-mouse-to-focus`:
|
||||||
|
|
||||||
|
Warps the cursor to the center of the currently focused window.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="types-SimpleIm"></a>
|
<a name="types-SimpleIm"></a>
|
||||||
|
|
|
||||||
|
|
@ -1193,6 +1193,9 @@ SimpleActionName:
|
||||||
This has no effect if the simple IM is not currently active.
|
This has no effect if the simple IM is not currently active.
|
||||||
- value: open-control-center
|
- value: open-control-center
|
||||||
description: Opens the control center.
|
description: Opens the control center.
|
||||||
|
- value: warp-mouse-to-focus
|
||||||
|
description: |
|
||||||
|
Warps the cursor to the center of the currently focused window.
|
||||||
|
|
||||||
|
|
||||||
Color:
|
Color:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue