Update pointer focus before motion occurs

If the surface under the pointer has changed, we should send an `enter`
event immediately, instead of waiting for the next motion event. This
seems to fix that, without producing unnecessary events.

Instead of `time: 0`, this and other synthesized events should probably
use `CLOCK_MONOTONIC`. It seems libinput does document that it uses
that.
This commit is contained in:
Ian Douglas Scott 2024-08-20 19:05:51 -07:00 committed by Victoria Brekenfeld
parent 889499b64d
commit ca6f05c585

View file

@ -7,7 +7,7 @@ use crate::{
use indexmap::IndexSet;
use smithay::{
desktop::{layer_map_for_output, PopupUngrabStrategy},
input::Seat,
input::{pointer::MotionEvent, Seat},
output::Output,
reexports::wayland_server::Resource,
utils::{IsAlive, Serial, SERIAL_COUNTER},
@ -261,6 +261,8 @@ impl Common {
.cloned()
.collect::<Vec<_>>();
for seat in &seats {
update_pointer_focus(state, &seat);
let mut shell = state.common.shell.write().unwrap();
let output = seat.active_output();
if !shell.outputs().any(|o| o == &output) {
@ -481,6 +483,30 @@ fn update_focus_target(
}
}
fn update_pointer_focus(state: &mut State, seat: &Seat<State>) {
if let Some(pointer) = seat.get_pointer() {
let output = seat.active_output();
let position = pointer.current_location().as_global();
let mut shell = state.common.shell.write().unwrap();
let under = State::surface_under(position, &output, &mut shell)
.map(|(target, pos)| (target, pos.as_logical()));
drop(shell);
if pointer.current_focus().as_ref() != under.as_ref().map(|(target, _)| target) {
pointer.motion(
state,
under,
&MotionEvent {
location: pointer.current_location(),
serial: SERIAL_COUNTER.next_serial(),
time: 0,
},
);
}
}
}
// Get the top-most layer, if any, with at least one surface with exclusive keyboard interactivity.
// Only considers surface in `Top` or `Overlay` layer.
fn exclusive_layer_surface_layer(shell: &Shell) -> Option<Layer> {