Properly offset popups on offset outputs
This commit is contained in:
parent
d8a9c28fa7
commit
3794c4b945
3 changed files with 96 additions and 31 deletions
|
|
@ -157,8 +157,8 @@ impl SurfaceData {
|
||||||
};
|
};
|
||||||
let output: &mut Output = object.as_mut();
|
let output: &mut Output = object.as_mut();
|
||||||
if let Some(win) = self.window {
|
if let Some(win) = self.window {
|
||||||
if let Some(data) = state.windows.get(&win) {
|
if let Some(data) = state.windows.get_mut(&win) {
|
||||||
output.add_surface(self, data.attrs.dims, state.connection.as_mut().unwrap());
|
output.add_surface(self, &mut data.attrs.dims, state.connection.as_mut().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&output.server
|
&output.server
|
||||||
|
|
@ -661,11 +661,13 @@ impl Output {
|
||||||
fn add_surface<C: XConnection>(
|
fn add_surface<C: XConnection>(
|
||||||
&mut self,
|
&mut self,
|
||||||
surface: &SurfaceData,
|
surface: &SurfaceData,
|
||||||
dims: WindowDims,
|
dims: &mut WindowDims,
|
||||||
connection: &mut C,
|
connection: &mut C,
|
||||||
) {
|
) {
|
||||||
self.surfaces.insert(surface.client.clone());
|
self.surfaces.insert(surface.client.clone());
|
||||||
let window = surface.window.unwrap();
|
let window = surface.window.unwrap();
|
||||||
|
dims.x = self.x as _;
|
||||||
|
dims.y = self.y as _;
|
||||||
|
|
||||||
debug!("moving surface to {}x{}", self.x, self.y);
|
debug!("moving surface to {}x{}", self.x, self.y);
|
||||||
connection.set_window_dims(
|
connection.set_window_dims(
|
||||||
|
|
|
||||||
|
|
@ -817,10 +817,14 @@ impl<C: XConnection> ServerState<C> {
|
||||||
let parent_window = self.windows.get(&parent).unwrap();
|
let parent_window = self.windows.get(&parent).unwrap();
|
||||||
let parent_surface: &SurfaceData =
|
let parent_surface: &SurfaceData =
|
||||||
self.objects[parent_window.surface_key.unwrap()].as_ref();
|
self.objects[parent_window.surface_key.unwrap()].as_ref();
|
||||||
|
let parent_dims = parent_window.attrs.dims;
|
||||||
|
|
||||||
|
let x = window.attrs.dims.x - parent_dims.x;
|
||||||
|
let y = window.attrs.dims.y - parent_dims.y;
|
||||||
|
|
||||||
let positioner = self.xdg_wm_base.create_positioner(&self.qh, ());
|
let positioner = self.xdg_wm_base.create_positioner(&self.qh, ());
|
||||||
positioner.set_size(window.attrs.dims.width as _, window.attrs.dims.height as _);
|
positioner.set_size(window.attrs.dims.width as _, window.attrs.dims.height as _);
|
||||||
positioner.set_offset(window.attrs.dims.x as i32, window.attrs.dims.y as i32);
|
positioner.set_offset(x as i32, y as i32);
|
||||||
positioner.set_anchor(Anchor::TopLeft);
|
positioner.set_anchor(Anchor::TopLeft);
|
||||||
positioner.set_gravity(Gravity::BottomRight);
|
positioner.set_gravity(Gravity::BottomRight);
|
||||||
positioner.set_anchor_rect(
|
positioner.set_anchor_rect(
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ use wayland_client::{
|
||||||
wl_compositor::WlCompositor,
|
wl_compositor::WlCompositor,
|
||||||
wl_display::WlDisplay,
|
wl_display::WlDisplay,
|
||||||
wl_keyboard::WlKeyboard,
|
wl_keyboard::WlKeyboard,
|
||||||
|
wl_output::WlOutput,
|
||||||
wl_pointer::WlPointer,
|
wl_pointer::WlPointer,
|
||||||
wl_registry::WlRegistry,
|
wl_registry::WlRegistry,
|
||||||
wl_seat::{self, WlSeat},
|
wl_seat::{self, WlSeat},
|
||||||
|
|
@ -226,6 +227,7 @@ struct TestFixture {
|
||||||
/// Exwayland's display - must dispatch this for our server state to advance
|
/// Exwayland's display - must dispatch this for our server state to advance
|
||||||
exwl_display: Display<FakeServerState>,
|
exwl_display: Display<FakeServerState>,
|
||||||
surface_serial: u64,
|
surface_serial: u64,
|
||||||
|
registry: TestObject<WlRegistry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
static INIT: std::sync::Once = std::sync::Once::new();
|
static INIT: std::sync::Once = std::sync::Once::new();
|
||||||
|
|
@ -259,12 +261,20 @@ impl TestFixture {
|
||||||
exwayland.connect(ex_server);
|
exwayland.connect(ex_server);
|
||||||
|
|
||||||
exwayland.set_x_connection(FakeXConnection::default());
|
exwayland.set_x_connection(FakeXConnection::default());
|
||||||
|
|
||||||
|
let exwl_connection = Connection::from_socket(fake_client).unwrap();
|
||||||
|
let registry = TestObject::<WlRegistry>::from_request(
|
||||||
|
&exwl_connection.display(),
|
||||||
|
Req::<WlDisplay>::GetRegistry {},
|
||||||
|
);
|
||||||
|
|
||||||
let mut f = TestFixture {
|
let mut f = TestFixture {
|
||||||
testwl,
|
testwl,
|
||||||
exwayland,
|
exwayland,
|
||||||
exwl_connection: Connection::from_socket(fake_client).unwrap().into(),
|
exwl_connection: exwl_connection.into(),
|
||||||
exwl_display: display,
|
exwl_display: display,
|
||||||
surface_serial: 1,
|
surface_serial: 1,
|
||||||
|
registry,
|
||||||
};
|
};
|
||||||
f.run();
|
f.run();
|
||||||
f
|
f
|
||||||
|
|
@ -282,13 +292,7 @@ impl TestFixture {
|
||||||
|
|
||||||
fn compositor(&mut self) -> Compositor {
|
fn compositor(&mut self) -> Compositor {
|
||||||
let mut ret = CompositorOptional::default();
|
let mut ret = CompositorOptional::default();
|
||||||
let wl_display = self.exwl_connection.display();
|
let events = std::mem::take(&mut *self.registry.data.events.lock().unwrap());
|
||||||
|
|
||||||
let registry =
|
|
||||||
TestObject::<WlRegistry>::from_request(&wl_display, Req::<WlDisplay>::GetRegistry {});
|
|
||||||
self.run();
|
|
||||||
|
|
||||||
let events = std::mem::take(&mut *registry.data.events.lock().unwrap());
|
|
||||||
assert!(!events.is_empty());
|
assert!(!events.is_empty());
|
||||||
|
|
||||||
for event in events {
|
for event in events {
|
||||||
|
|
@ -306,25 +310,25 @@ impl TestFixture {
|
||||||
match interface {
|
match interface {
|
||||||
x if x == WlCompositor::interface().name => {
|
x if x == WlCompositor::interface().name => {
|
||||||
ret.compositor = Some(TestObject::from_request(
|
ret.compositor = Some(TestObject::from_request(
|
||||||
®istry.obj,
|
&self.registry.obj,
|
||||||
bind_req(WlCompositor::interface()),
|
bind_req(WlCompositor::interface()),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
x if x == WlShm::interface().name => {
|
x if x == WlShm::interface().name => {
|
||||||
ret.shm = Some(TestObject::from_request(
|
ret.shm = Some(TestObject::from_request(
|
||||||
®istry.obj,
|
&self.registry.obj,
|
||||||
bind_req(WlShm::interface()),
|
bind_req(WlShm::interface()),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
x if x == XwaylandShellV1::interface().name => {
|
x if x == XwaylandShellV1::interface().name => {
|
||||||
ret.shell = Some(TestObject::from_request(
|
ret.shell = Some(TestObject::from_request(
|
||||||
®istry.obj,
|
&self.registry.obj,
|
||||||
bind_req(XwaylandShellV1::interface()),
|
bind_req(XwaylandShellV1::interface()),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
x if x == WlSeat::interface().name => {
|
x if x == WlSeat::interface().name => {
|
||||||
ret.seat = Some(TestObject::from_request(
|
ret.seat = Some(TestObject::from_request(
|
||||||
®istry.obj,
|
&self.registry.obj,
|
||||||
bind_req(WlSeat::interface()),
|
bind_req(WlSeat::interface()),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
@ -361,12 +365,40 @@ impl TestFixture {
|
||||||
// Get our events
|
// Get our events
|
||||||
let res = self.exwl_connection.prepare_read().unwrap().read();
|
let res = self.exwl_connection.prepare_read().unwrap().read();
|
||||||
if res.is_err()
|
if res.is_err()
|
||||||
&& !matches!(res, Err(WaylandError::Io(ref e)) if e.kind() == std::io::ErrorKind::WouldBlock)
|
&& matches!(res, Err(WaylandError::Io(ref e)) if e.kind() != std::io::ErrorKind::WouldBlock)
|
||||||
{
|
{
|
||||||
panic!("Read failed: {res:?}")
|
panic!("Read failed: {res:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_output(&mut self, x: i32, y: i32) -> wayland_server::protocol::wl_output::WlOutput {
|
||||||
|
self.testwl.new_output(x, y);
|
||||||
|
self.run();
|
||||||
|
self.run();
|
||||||
|
let mut events = std::mem::take(&mut *self.registry.data.events.lock().unwrap());
|
||||||
|
assert_eq!(events.len(), 1);
|
||||||
|
let event = events.pop().unwrap();
|
||||||
|
let Ev::<WlRegistry>::Global {
|
||||||
|
name,
|
||||||
|
interface,
|
||||||
|
version,
|
||||||
|
} = event
|
||||||
|
else {
|
||||||
|
panic!("Unexpected event: {event:?}");
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(interface, WlOutput::interface().name);
|
||||||
|
TestObject::<WlOutput>::from_request(
|
||||||
|
&self.registry.obj,
|
||||||
|
Req::<WlRegistry>::Bind {
|
||||||
|
name,
|
||||||
|
id: (WlOutput::interface(), version),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
self.run();
|
||||||
|
self.testwl.last_created_output()
|
||||||
|
}
|
||||||
|
|
||||||
fn register_window(&mut self, window: Window, data: WindowData) {
|
fn register_window(&mut self, window: Window, data: WindowData) {
|
||||||
self.exwayland
|
self.exwayland
|
||||||
.connection
|
.connection
|
||||||
|
|
@ -510,14 +542,17 @@ impl TestFixture {
|
||||||
&mut self,
|
&mut self,
|
||||||
comp: &Compositor,
|
comp: &Compositor,
|
||||||
window: Window,
|
window: Window,
|
||||||
parent_id: testwl::SurfaceId,
|
parent_window: Window,
|
||||||
|
parent_surface: testwl::SurfaceId,
|
||||||
|
x: i16,
|
||||||
|
y: i16,
|
||||||
) -> (TestObject<WlSurface>, testwl::SurfaceId) {
|
) -> (TestObject<WlSurface>, testwl::SurfaceId) {
|
||||||
let (buffer, surface) = comp.create_surface();
|
let (buffer, surface) = comp.create_surface();
|
||||||
let data = WindowData {
|
let data = WindowData {
|
||||||
mapped: true,
|
mapped: true,
|
||||||
dims: WindowDims {
|
dims: WindowDims {
|
||||||
x: 10,
|
x,
|
||||||
y: 10,
|
y,
|
||||||
width: 50,
|
width: 50,
|
||||||
height: 50,
|
height: 50,
|
||||||
},
|
},
|
||||||
|
|
@ -529,7 +564,7 @@ impl TestFixture {
|
||||||
self.run();
|
self.run();
|
||||||
|
|
||||||
let popup_id = self.check_new_surface();
|
let popup_id = self.check_new_surface();
|
||||||
assert_ne!(popup_id, parent_id);
|
assert_ne!(popup_id, parent_surface);
|
||||||
|
|
||||||
{
|
{
|
||||||
let surface_data = self.testwl.get_surface_data(popup_id).unwrap();
|
let surface_data = self.testwl.get_surface_data(popup_id).unwrap();
|
||||||
|
|
@ -549,7 +584,7 @@ impl TestFixture {
|
||||||
|
|
||||||
let toplevel_xdg = &self
|
let toplevel_xdg = &self
|
||||||
.testwl
|
.testwl
|
||||||
.get_surface_data(parent_id)
|
.get_surface_data(parent_surface)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.xdg()
|
.xdg()
|
||||||
.surface;
|
.surface;
|
||||||
|
|
@ -557,18 +592,23 @@ impl TestFixture {
|
||||||
|
|
||||||
let pos = &surface_data.popup().positioner_state;
|
let pos = &surface_data.popup().positioner_state;
|
||||||
assert_eq!(pos.size.as_ref().unwrap(), &testwl::Vec2 { x: 50, y: 50 });
|
assert_eq!(pos.size.as_ref().unwrap(), &testwl::Vec2 { x: 50, y: 50 });
|
||||||
|
|
||||||
|
let parent_win = &self.connection().windows[&parent_window];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
pos.anchor_rect.as_ref().unwrap(),
|
pos.anchor_rect.as_ref().unwrap(),
|
||||||
&testwl::Rect {
|
&testwl::Rect {
|
||||||
size: testwl::Vec2 { x: 100, y: 100 },
|
size: testwl::Vec2 {
|
||||||
|
x: parent_win.dims.width as _,
|
||||||
|
y: parent_win.dims.height as _
|
||||||
|
},
|
||||||
offset: testwl::Vec2::default()
|
offset: testwl::Vec2::default()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
pos.offset,
|
pos.offset,
|
||||||
testwl::Vec2 {
|
testwl::Vec2 {
|
||||||
x: dims.x as _,
|
x: (dims.x - parent_win.dims.x) as _,
|
||||||
y: dims.y as _
|
y: (dims.y - parent_win.dims.y) as _
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(pos.anchor, xdg_positioner::Anchor::TopLeft);
|
assert_eq!(pos.anchor, xdg_positioner::Anchor::TopLeft);
|
||||||
|
|
@ -692,7 +732,7 @@ fn popup_flow_simple() {
|
||||||
let (_, toplevel_id) = f.create_toplevel(&compositor, win_toplevel);
|
let (_, toplevel_id) = f.create_toplevel(&compositor, win_toplevel);
|
||||||
|
|
||||||
let win_popup = unsafe { Window::new(2) };
|
let win_popup = unsafe { Window::new(2) };
|
||||||
let (popup_surface, popup_id) = f.create_popup(&compositor, win_popup, toplevel_id);
|
let (popup_surface, popup_id) = f.create_popup(&compositor, win_popup, win_toplevel, toplevel_id, 10, 10);
|
||||||
|
|
||||||
f.exwayland.unmap_window(win_popup);
|
f.exwayland.unmap_window(win_popup);
|
||||||
f.exwayland.destroy_window(win_popup);
|
f.exwayland.destroy_window(win_popup);
|
||||||
|
|
@ -756,11 +796,8 @@ fn pass_through_globals() {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut globals = SupportedGlobals::default();
|
let mut globals = SupportedGlobals::default();
|
||||||
let display = f.exwl_connection.display();
|
|
||||||
let registry =
|
|
||||||
TestObject::<WlRegistry>::from_request(&display, Req::<WlDisplay>::GetRegistry {});
|
|
||||||
f.run();
|
f.run();
|
||||||
let events = std::mem::take(&mut *registry.data.events.lock().unwrap());
|
let events = std::mem::take(&mut *f.registry.data.events.lock().unwrap());
|
||||||
assert!(!events.is_empty());
|
assert!(!events.is_empty());
|
||||||
for event in events {
|
for event in events {
|
||||||
let Ev::<WlRegistry>::Global { interface, .. } = event else {
|
let Ev::<WlRegistry>::Global { interface, .. } = event else {
|
||||||
|
|
@ -809,7 +846,7 @@ fn popup_window_changes_surface() {
|
||||||
let (_, toplevel_id) = f.create_toplevel(&comp, t_win);
|
let (_, toplevel_id) = f.create_toplevel(&comp, t_win);
|
||||||
|
|
||||||
let win = unsafe { Window::new(2) };
|
let win = unsafe { Window::new(2) };
|
||||||
let (surface, old_id) = f.create_popup(&comp, win, toplevel_id);
|
let (surface, old_id) = f.create_popup(&comp, win, t_win, toplevel_id, 0, 0);
|
||||||
|
|
||||||
f.exwayland.unmap_window(win);
|
f.exwayland.unmap_window(win);
|
||||||
surface.obj.destroy();
|
surface.obj.destroy();
|
||||||
|
|
@ -1178,6 +1215,28 @@ fn override_redirect_choose_hover_window() {
|
||||||
assert_eq!(&popup_data.popup().parent, win1_xdg);
|
assert_eq!(&popup_data.popup().parent, win1_xdg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn offset_output() {
|
||||||
|
let (mut f, comp) = TestFixture::new_with_compositor();
|
||||||
|
let output = f.new_output(500, 100);
|
||||||
|
|
||||||
|
let window = unsafe { Window::new(1) };
|
||||||
|
let (_, surface_id) = f.create_toplevel(&comp, window);
|
||||||
|
f.testwl.move_surface_to_output(surface_id, output);
|
||||||
|
f.run();
|
||||||
|
let data = &f.connection().windows[&window];
|
||||||
|
assert_eq!(data.dims.x, 500);
|
||||||
|
assert_eq!(data.dims.y, 100);
|
||||||
|
|
||||||
|
let popup = unsafe { Window::new(2) };
|
||||||
|
let (_, p_id) = f.create_popup(&comp, popup, window, surface_id, 510, 110);
|
||||||
|
let data = f.testwl.get_surface_data(p_id).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
data.popup().positioner_state.offset,
|
||||||
|
testwl::Vec2 { x: 10, y: 10 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// See Pointer::handle_event for an explanation.
|
/// See Pointer::handle_event for an explanation.
|
||||||
#[test]
|
#[test]
|
||||||
fn popup_pointer_motion_workaround() {}
|
fn popup_pointer_motion_workaround() {}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue