Unconditionally set input focus on activation

Wine windows had WM_HINTS.input set to False, and expected use of the
WM_TAKE_FOCUS protocol, but Wayland input is much more absolute, so this
protocol is useless to us. Always focusing windows seems to be fine, so
just do that.
Should fix #35.
This commit is contained in:
Shawn Wallace 2024-07-07 16:41:34 -04:00
parent 891d056497
commit 03a0e1754d
3 changed files with 22 additions and 95 deletions

View file

@ -255,6 +255,9 @@ impl SurfaceData {
let activated = states.contains(&(u32::from(xdg_toplevel::State::Activated) as u8)); let activated = states.contains(&(u32::from(xdg_toplevel::State::Activated) as u8));
if activated { if activated {
// Technically this is wrong - activated doesn't necessarily mean focused
// - but it works and no one's complained yet.
// TODO: base focus on keyboard enter instead.
state.to_focus = Some(self.window.unwrap()); state.to_focus = Some(self.window.unwrap());
} }

View file

@ -697,7 +697,6 @@ bitflags! {
bitflags! { bitflags! {
/// https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.2.4 /// https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.2.4
pub struct WmHintsFlags: u32 { pub struct WmHintsFlags: u32 {
const Input = 1;
const WindowGroup = 64; const WindowGroup = 64;
} }
} }
@ -739,7 +738,6 @@ impl From<&[u32]> for WmNormalHints {
#[derive(Default, Debug, PartialEq, Eq)] #[derive(Default, Debug, PartialEq, Eq)]
pub struct WmHints { pub struct WmHints {
pub input: Option<bool>,
pub window_group: Option<x::Window>, pub window_group: Option<x::Window>,
} }
@ -748,9 +746,6 @@ impl From<&[u32]> for WmHints {
let mut ret = Self::default(); let mut ret = Self::default();
let flags = WmHintsFlags::from_bits_truncate(value[0]); let flags = WmHintsFlags::from_bits_truncate(value[0]);
if flags.contains(WmHintsFlags::Input) {
ret.input = Some(value[1] == 1);
}
if flags.contains(WmHintsFlags::WindowGroup) { if flags.contains(WmHintsFlags::WindowGroup) {
let window = unsafe { x::Window::new(value[8]) }; let window = unsafe { x::Window::new(value[8]) };
ret.window_group = Some(window); ret.window_group = Some(window);
@ -817,30 +812,11 @@ impl super::XConnection for Arc<xcb::Connection> {
} }
fn focus_window(&mut self, window: x::Window, atoms: Self::ExtraData) { fn focus_window(&mut self, window: x::Window, atoms: Self::ExtraData) {
let prop = unwrap_or_skip_bad_window!(self.send_and_check_request(&x::SetInputFocus {
unwrap_or_skip_bad_window!(self.wait_for_reply(self.send_request(&x::GetProperty { focus: window,
delete: false, revert_to: x::InputFocus::None,
window, time: x::CURRENT_TIME,
property: x::ATOM_WM_HINTS, }));
r#type: x::ATOM_WM_HINTS,
long_offset: 0,
long_length: 9,
})));
let set_focus = if prop.r#type() == x::ATOM_NONE {
true
} else {
WmHints::from(prop.value()).input.unwrap_or(true)
};
if set_focus {
// might fail if window is not visible but who cares
let _ = self.send_and_check_request(&x::SetInputFocus {
focus: window,
revert_to: x::InputFocus::None,
time: x::CURRENT_TIME,
});
}
unwrap_or_skip_bad_window!(self.send_and_check_request(&x::ChangeProperty { unwrap_or_skip_bad_window!(self.send_and_check_request(&x::ChangeProperty {
mode: x::PropMode::Replace, mode: x::PropMode::Replace,

View file

@ -482,68 +482,22 @@ fn input_focus() {
let mut f = Fixture::new(); let mut f = Fixture::new();
let mut connection = Connection::new(&f.display); let mut connection = Connection::new(&f.display);
fn tst( let win = connection.new_window(connection.root, 0, 0, 20, 20, false);
f: &mut Fixture, connection.map_window(win);
connection: &mut Connection, f.wait_and_dispatch();
set_props: impl FnOnce(&mut Connection, x::Window), let surface = f
check: impl FnOnce(/* win: */ x::Window, /* focus: */ x::Window), .testwl
) { .last_created_surface_id()
let win = connection.new_window(connection.root, 0, 0, 20, 20, false); .expect("No surface created!");
set_props(connection, win); f.configure_and_verify_new_toplevel(&mut connection, win, surface);
connection.map_window(win);
f.wait_and_dispatch();
let surface = f
.testwl
.last_created_surface_id()
.expect("No surface created!");
f.configure_and_verify_new_toplevel(connection, win, surface);
let focus = connection let focus = connection
.wait_for_reply(connection.send_request(&x::GetInputFocus {})) .wait_for_reply(connection.send_request(&x::GetInputFocus {}))
.unwrap() .unwrap()
.focus(); .focus();
check(win, focus); assert_eq!(win, focus);
f.close_toplevel(connection, win, surface); f.close_toplevel(&mut connection, win, surface);
}
// Input field unset
tst(
&mut f,
&mut connection,
|_, _| {},
|win, focus| assert_eq!(win, focus),
);
// Input field set to false
tst(
&mut f,
&mut connection,
|connection, win| {
connection.set_property(
win,
x::ATOM_WM_HINTS,
x::ATOM_WM_HINTS,
&[WmHintsFlags::Input.bits(), 0],
);
},
|win, focus| assert_ne!(win, focus),
);
// Input field set to true
tst(
&mut f,
&mut connection,
|connection, win| {
connection.set_property(
win,
x::ATOM_WM_HINTS,
x::ATOM_WM_HINTS,
&[WmHintsFlags::Input.bits(), 1],
);
},
|win, focus| assert_eq!(win, focus),
);
} }
#[test] #[test]
@ -558,12 +512,6 @@ fn quick_delete() {
.testwl .testwl
.last_created_surface_id() .last_created_surface_id()
.expect("No surface created"); .expect("No surface created");
connection.set_property(
window,
x::ATOM_WM_HINTS,
x::ATOM_WM_HINTS,
&[WmHintsFlags::Input.bits(), 0],
);
connection.set_property( connection.set_property(
window, window,
x::ATOM_STRING, x::ATOM_STRING,