I know it's a deliberate decision that clicking or touching anywhere on an unfocused monitor should focus the output. Clicking on an empty workspace or a shell layer surface (e.g., waybar) focuses the output so it can be primed for a new window to open on, etc. This makes sense. But I consider it a definite bug that clicking or tapping on an on-screen keyboard (or maybe virtual trackpad, etc) also causes this focus shift on a multi-monitor setup.
Interacting with an onscreen keyboard of virtual pointer should forward its actions on to what was already focused. Focus should not change.
This is applicable for any multi-monitor setup where the user is using an onscreen keyboard or virtual pointer, but most understandable on a tablet connected to an external screen, say a projector at a conference. The touchscreen would have the onscreen keyboard, and the external screen would have the target client. Currently, interacting with the onscreen keyboard causes the focus to jump to the touchscreen, rendering the onscreen keyboard unusuable. If there is a regular window open on the touchscreen, it receives focus. If no windows are open, the blank (save for the shell layers, including the keyboard) output itself receives focus.
My suggestion is that the click or touch target should be checked to see if it's a client that has instantiated any zwp_virtual_keyboard_v1 or zwlr_virtual_pointer_v1 objects, and if it has, focus should not change.
I'm not very familiar with Rust, or its conventions, but I have somewhat of a rough preliminary idea for on_pointer_down in input/mod.rs, from line 3013. At this point, the pointer has failed to find a toplevel window under it, so it's about to focus the output. Instead, check to see if a shell layer surface is under. If it is, check to see if the client owning this surface has any object of the aforementioned interfaces, and set a flag. Only if this flag has not been set should the output be focused. (I only really expect a virtual keyboard to make sense as a shell layer... a toplevel window seems kinda strange for this, so I'm not trying to catch it earlier.) Further considerations may have to be made for focus-follows-mouse, but I haven't had time to look at that yet. Learning Rust just for this tiny issue is time-consuming. 🥲
} else if let Some(output) = self.niri.output_under_cursor() {
self.update_pointer_contents();
has_updated_pointer_contents = true; // new variable added further above, to prevent calling update_pointer_contents() a second time at the usual call spot below
let mut is_virtual_input_source = false;
if let Some(layer) = self.niri.pointer_contents.layer.clone() {
if let Some(client) = layer.wl_surface().client() {
let _ = self.niri.display_handle.backend_handle().with_all_objects_for(client.id(), |obj| {
if is_virtual_input_source {
return; // no need to keep checking, but can't break the loop
}
if same_interface(obj.interface(), ZwpVirtualKeyboardV1::interface())
|| same_interface(obj.interface(), ZwlrVirtualPointerV1::interface()) {
is_virtual_input_source = true;
}
});
}
}
if !is_virtual_input_source {
self.niri.layout.focus_output(&output);
// FIXME: granular.
self.niri.queue_redraw_all();
}
}
};
// this usual call spot
if !has_updated_pointer_contents {
self.update_pointer_contents();
}
System Information
- niri version: niri 25.11
- Distro: Fedora 43 (Sway spin, updated to use Niri)
- GPU: Nvidia GeForce RTX 3050 Laptop
- CPU: Intel Core i5-12450H
I know it's a deliberate decision that clicking or touching anywhere on an unfocused monitor should focus the output. Clicking on an empty workspace or a shell layer surface (e.g., waybar) focuses the output so it can be primed for a new window to open on, etc. This makes sense. But I consider it a definite bug that clicking or tapping on an on-screen keyboard (or maybe virtual trackpad, etc) also causes this focus shift on a multi-monitor setup.
Interacting with an onscreen keyboard of virtual pointer should forward its actions on to what was already focused. Focus should not change.
This is applicable for any multi-monitor setup where the user is using an onscreen keyboard or virtual pointer, but most understandable on a tablet connected to an external screen, say a projector at a conference. The touchscreen would have the onscreen keyboard, and the external screen would have the target client. Currently, interacting with the onscreen keyboard causes the focus to jump to the touchscreen, rendering the onscreen keyboard unusuable. If there is a regular window open on the touchscreen, it receives focus. If no windows are open, the blank (save for the shell layers, including the keyboard) output itself receives focus.
My suggestion is that the click or touch target should be checked to see if it's a client that has instantiated any
zwp_virtual_keyboard_v1orzwlr_virtual_pointer_v1objects, and if it has, focus should not change.I'm not very familiar with Rust, or its conventions, but I have somewhat of a rough preliminary idea for
on_pointer_downininput/mod.rs, from line 3013. At this point, the pointer has failed to find a toplevel window under it, so it's about to focus the output. Instead, check to see if a shell layer surface is under. If it is, check to see if the client owning this surface has any object of the aforementioned interfaces, and set a flag. Only if this flag has not been set should the output be focused. (I only really expect a virtual keyboard to make sense as a shell layer... a toplevel window seems kinda strange for this, so I'm not trying to catch it earlier.) Further considerations may have to be made forfocus-follows-mouse, but I haven't had time to look at that yet. Learning Rust just for this tiny issue is time-consuming. 🥲System Information