From 5c0351ff33d70e1cb6137634820702f9fe72f75d Mon Sep 17 00:00:00 2001 From: Shawn Wallace Date: Tue, 27 May 2025 19:35:10 -0400 Subject: [PATCH] Properly handle rotated outputs Fixes #160 --- src/server/event.rs | 40 ++++++++++++++++++++++++++++++++++------ tests/integration.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/src/server/event.rs b/src/server/event.rs index 26fafc1..b8586a4 100644 --- a/src/server/event.rs +++ b/src/server/event.rs @@ -551,6 +551,12 @@ impl HandleEvent for Pointer { warn!("could not move pointer to surface ({serial}): stale surface"); } } else { + trace!( + target: "pointer_position", + "pointer motion {} {}", + surface_x * self.scale, + surface_y * self.scale + ); self.server .motion(time, surface_x * self.scale, surface_y * self.scale); } @@ -795,6 +801,7 @@ pub struct Output { pub(super) dimensions: OutputDimensions, name: String, scale: i32, + swap_dimensions: bool, } impl Output { @@ -820,6 +827,7 @@ impl Output { }, name: "".to_string(), scale: 1, + swap_dimensions: false, } } @@ -993,6 +1001,24 @@ impl Output { model, convert_wenum(transform), ); + self.swap_dimensions = transform.into_result().is_ok_and(|t| { + matches!( + t, + client::wl_output::Transform::_90 + | client::wl_output::Transform::_270 + | client::wl_output::Transform::Flipped90 + | client::wl_output::Transform::Flipped270 + ) + }); + if let Some(xdg) = &self.xdg { + if self.swap_dimensions { + xdg.server + .logical_size(self.dimensions.height, self.dimensions.width); + } else { + xdg.server + .logical_size(self.dimensions.width, self.dimensions.height); + } + } } Event::Mode { flags, @@ -1000,11 +1026,9 @@ impl Output { height, refresh, } => { - if matches!(self.dimensions.source, OutputDimensionsSource::Wl { .. }) { - self.dimensions.width = width; - self.dimensions.height = height; - debug!("{} dimensions: {width}x{height} (wl)", self.server.id()); - } + self.dimensions.width = width; + self.dimensions.height = height; + debug!("{} dimensions: {width}x{height}", self.server.id()); self.server .mode(convert_wenum(flags), width, height, refresh); } @@ -1065,7 +1089,11 @@ impl Output { ); } Event::LogicalSize { .. } => { - xdg.logical_size(self.dimensions.width, self.dimensions.height); + if self.swap_dimensions { + xdg.logical_size(self.dimensions.height, self.dimensions.width); + } else { + xdg.logical_size(self.dimensions.width, self.dimensions.height); + } } _ => simple_event_shunt! { xdg, event: zxdg_output_v1::Event => [ diff --git a/tests/integration.rs b/tests/integration.rs index b9b3529..6224fdf 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -14,6 +14,7 @@ use std::time::{Duration, Instant}; use wayland_protocols::xdg::{ decoration::zv1::server::zxdg_toplevel_decoration_v1, shell::server::xdg_toplevel, }; +use wayland_server::protocol::wl_output; use wayland_server::Resource; use xcb::{x, Xid}; use xwayland_satellite as xwls; @@ -1892,3 +1893,43 @@ fn xsettings_switch_owner() { owner ); } + +#[test] +fn rotated_output() { + let mut f = Fixture::new_preset(|testwl| { + testwl.enable_xdg_output_manager(); + testwl.new_output(0, 0); + }); + let mut connection = Connection::new(&f.display); + + connection + .send_and_check_request(&x::ChangeWindowAttributes { + window: connection.root, + value_list: &[x::Cw::EventMask(x::EventMask::STRUCTURE_NOTIFY)], + }) + .unwrap(); + + let output = f.testwl.get_output("WL-1").unwrap(); + output.mode(wl_output::Mode::Current, 100, 1000, 60); + output.geometry( + 0, + 0, + 50, + 50, + wl_output::Subpixel::Unknown, + "satellite".to_string(), + "WL-1".to_string(), + wl_output::Transform::_90, + ); + output.done(); + f.testwl.dispatch(); + + match connection.await_event() { + xcb::Event::X(x::Event::ConfigureNotify(e)) => { + assert_eq!(e.window(), connection.root); + assert_eq!(e.width(), 1000); + assert_eq!(e.height(), 100); + } + other => panic!("unexpected event {other:?}"), + } +}