diff --git a/src/clientside.rs b/src/clientside.rs index fe2295c..b2aea37 100644 --- a/src/clientside.rs +++ b/src/clientside.rs @@ -4,9 +4,9 @@ use std::os::unix::net::UnixStream; use std::sync::mpsc; use wayland_client::protocol::{ wl_buffer::WlBuffer, wl_callback::WlCallback, wl_compositor::WlCompositor, - wl_keyboard::WlKeyboard, wl_output::WlOutput, wl_pointer::WlPointer, wl_registry::WlRegistry, - wl_seat::WlSeat, wl_shm::WlShm, wl_shm_pool::WlShmPool, wl_surface::WlSurface, - wl_touch::WlTouch, wl_region::WlRegion + wl_keyboard::WlKeyboard, wl_output::WlOutput, wl_pointer::WlPointer, wl_region::WlRegion, + wl_registry::WlRegistry, wl_seat::WlSeat, wl_shm::WlShm, wl_shm_pool::WlShmPool, + wl_surface::WlSurface, wl_touch::WlTouch, }; use wayland_client::{delegate_noop, Connection, Dispatch, EventQueue, Proxy, QueueHandle}; use wayland_protocols::wp::relative_pointer::zv1::client::{ diff --git a/src/xstate.rs b/src/xstate.rs index d698c43..4cb7560 100644 --- a/src/xstate.rs +++ b/src/xstate.rs @@ -336,7 +336,7 @@ impl XState { }, title, class, - group: wm_hints.map(|h| h.window_group).flatten(), + group: wm_hints.and_then(|h| h.window_group), size_hints, } } @@ -640,6 +640,9 @@ impl From<&[u32]> for WmHints { let mut ret = Self::default(); let flags = WmHintsFlags::from_bits_truncate(value[0]); + if flags.contains(WmHintsFlags::Input) { + ret.input = Some(value[1] == 1); + } if flags.contains(WmHintsFlags::WindowGroup) { let window = unsafe { x::Window::new(value[8]) }; ret.window_group = Some(window); @@ -713,20 +716,17 @@ impl super::XConnection for Arc { property: x::ATOM_WM_HINTS, r#type: x::ATOM_WM_HINTS, long_offset: 0, - long_length: 8, + long_length: 9, })) .unwrap(); - let fields: &[u32] = prop.value(); - let mut input = false; - if !fields.is_empty() { - let flags = fields[0]; - if (flags & 0x1) > 0 { - input = fields[1] > 0; - } - } + let set_focus = if prop.r#type() == x::ATOM_NONE { + true + } else { + WmHints::from(prop.value()).input.unwrap_or(true) + }; - if input { + if set_focus { // might fail if window is not visible but who cares let _ = self.send_and_check_request(&x::SetInputFocus { focus: window, diff --git a/tests/integration.rs b/tests/integration.rs index dcc5b1d..b074f1d 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -12,7 +12,7 @@ use wayland_protocols::xdg::shell::server::xdg_toplevel; use wayland_server::Resource; use xcb::{x, Xid}; use xwayland_satellite as xwls; -use xwayland_satellite::xstate::WmSizeHintsFlags; +use xwayland_satellite::xstate::{WmHintsFlags, WmSizeHintsFlags}; #[derive(Default)] struct TestDataInner { @@ -300,6 +300,11 @@ impl Connection { .unwrap(); } + fn unmap_window(&self, window: x::Window) { + self.send_and_check_request(&x::UnmapWindow { window }) + .unwrap(); + } + fn set_property( &self, window: x::Window, @@ -423,7 +428,7 @@ fn toplevel_flow() { #[test] fn reparent() { let mut f = Fixture::new(); - let connection = Connection::new(&f.display); + let mut connection = Connection::new(&f.display); let parent = connection.new_window(connection.root, 0, 0, 1, 1, false); let child = connection.new_window(parent, 0, 0, 20, 20, false); @@ -437,9 +442,80 @@ fn reparent() { }) .unwrap(); - connection - .send_and_check_request(&x::MapWindow { window: child }) - .unwrap(); - + connection.map_window(child); f.wait_and_dispatch(); + let surface = f + .testwl + .last_created_surface_id() + .expect("No surface created!"); + f.configure_and_verify_new_toplevel(&mut connection, child, surface); +} + +#[test] +fn input_focus() { + let mut f = Fixture::new(); + let mut connection = Connection::new(&f.display); + + fn tst( + f: &mut Fixture, + connection: &mut Connection, + set_props: impl FnOnce(&mut Connection, x::Window), + check: impl FnOnce(/* win: */ x::Window, /* focus: */ x::Window), + ) { + let win = connection.new_window(connection.root, 0, 0, 20, 20, false); + set_props(connection, win); + 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 + .wait_for_reply(connection.send_request(&x::GetInputFocus {})) + .unwrap() + .focus(); + check(win, focus); + + f.close_toplevel(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), + ); } diff --git a/wl_drm/src/lib.rs b/wl_drm/src/lib.rs index 31058d2..6ecaf17 100644 --- a/wl_drm/src/lib.rs +++ b/wl_drm/src/lib.rs @@ -2,8 +2,8 @@ pub mod client { use wayland_client::{self, protocol::*}; pub mod __interfaces { - use wayland_client::protocol::__interfaces::*; use wayland_client::backend as wayland_backend; + use wayland_client::protocol::__interfaces::*; wayland_scanner::generate_interfaces!("src/drm.xml"); } use self::__interfaces::*; @@ -11,9 +11,8 @@ pub mod client { } pub mod server { - use wayland_server::{self, protocol::*}; - pub use super::client::__interfaces; use self::__interfaces::*; + pub use super::client::__interfaces; + use wayland_server::{self, protocol::*}; wayland_scanner::generate_server_code!("src/drm.xml"); } -