From 26ccb653b75c80179bf017f2c92c5e109994bcc3 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Wed, 26 Jun 2024 13:05:25 +0200 Subject: [PATCH] output: Store position as u32 and offset bad configs --- src/backend/kms/device.rs | 22 +++++---- src/backend/kms/mod.rs | 4 +- src/config/mod.rs | 2 +- src/state.rs | 9 ++-- src/wayland/handlers/output_configuration.rs | 47 ++++++++++++++++++-- 5 files changed, 66 insertions(+), 18 deletions(-) diff --git a/src/backend/kms/device.rs b/src/backend/kms/device.rs index bde92613..48f6910e 100644 --- a/src/backend/kms/device.rs +++ b/src/backend/kms/device.rs @@ -22,7 +22,7 @@ use smithay::{ rustix::fs::OFlags, wayland_server::{protocol::wl_buffer::WlBuffer, DisplayHandle, Weak}, }, - utils::{DevPath, DeviceFd, Transform}, + utils::{DevPath, DeviceFd, Point, Transform}, wayland::drm_lease::{DrmLease, DrmLeaseState}, }; use tracing::{error, info, warn}; @@ -222,7 +222,7 @@ impl State { let connectors = device.enumerate_surfaces()?.added; // There are no removed outputs on newly added devices let mut wl_outputs = Vec::new(); - let mut w = self.common.shell.read().unwrap().global_space().size.w; + let mut w = self.common.shell.read().unwrap().global_space().size.w as u32; { for (conn, maybe_crtc) in connectors { @@ -237,7 +237,7 @@ impl State { ) { Ok((output, should_expose)) => { if should_expose { - w += output.config().mode_size().w; + w += output.config().mode_size().w as u32; wl_outputs.push(output.clone()); } device.outputs.insert(conn, output); @@ -286,7 +286,7 @@ impl State { if let Some(device) = backend.drm_devices.get_mut(&drm_node) { let changes = device.enumerate_surfaces()?; - let mut w = self.common.shell.read().unwrap().global_space().size.w; + let mut w = self.common.shell.read().unwrap().global_space().size.w as u32; for conn in changes.removed { // contains conns with updated crtcs, just drop the surface and re-create if let Some(pos) = device @@ -306,7 +306,11 @@ impl State { { let surface = device.surfaces.remove(&crtc).unwrap(); // TODO: move up later outputs? - w -= surface.output.current_mode().map(|m| m.size.w).unwrap_or(0); + w -= surface + .output + .current_mode() + .map(|m| m.size.w as u32) + .unwrap_or(0); } if !changes.added.iter().any(|(c, _)| c == &conn) { @@ -331,7 +335,7 @@ impl State { ) { Ok((output, should_expose)) => { if should_expose { - w += output.config().mode_size().w; + w += output.config().mode_size().w as u32; outputs_added.push(output.clone()); } @@ -472,7 +476,7 @@ impl Device { primary_node: Option<&DrmNode>, conn: connector::Handle, maybe_crtc: Option, - position: (i32, i32), + position: (u32, u32), evlh: &LoopHandle<'static, State>, shell: Arc>, startup_done: Arc, @@ -608,7 +612,7 @@ fn populate_modes( drm: &mut DrmDevice, output: &Output, conn: connector::Handle, - position: (i32, i32), + position: (u32, u32), ) -> Result<()> { let conn_info = drm.get_connector(conn, false)?; let max_bpc = drm_helpers::get_max_bpc(drm, conn)?.map(|(_val, range)| range.end.min(16)); @@ -638,7 +642,7 @@ fn populate_modes( // TODO: Readout property for monitor rotation Some(Transform::Normal), None, - Some(position.into()), + Some(Point::from((position.0 as i32, position.1 as i32))), ); let mut output_config = output diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index e160912c..6bc72613 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -642,7 +642,7 @@ impl KmsState { } // add new ones - let mut w = shell.read().unwrap().global_space().size.w; + let mut w = shell.read().unwrap().global_space().size.w as u32; if !test_only { for (conn, crtc) in new_pairings { let (output, _) = device.connector_added( @@ -655,7 +655,7 @@ impl KmsState { startup_done.clone(), )?; if output.mirroring().is_none() { - w += output.config().mode_size().w; + w += output.config().mode_size().w as u32; } all_outputs.push(output); } diff --git a/src/config/mod.rs b/src/config/mod.rs index 626a6817..b456fd05 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -136,7 +136,7 @@ pub struct OutputConfig { pub scale: f64, #[serde(with = "TransformDef")] pub transform: Transform, - pub position: (i32, i32), + pub position: (u32, u32), #[serde(default = "default_enabled")] pub enabled: OutputState, #[serde(default, skip_serializing_if = "Option::is_none")] diff --git a/src/state.rs b/src/state.rs index e53d7dfc..dbbf4969 100644 --- a/src/state.rs +++ b/src/state.rs @@ -57,7 +57,7 @@ use smithay::{ Client, DisplayHandle, Resource, }, }, - utils::{Clock, IsAlive, Monotonic}, + utils::{Clock, IsAlive, Monotonic, Point}, wayland::{ alpha_modifier::AlphaModifierState, compositor::{CompositorClientState, CompositorState, SurfaceData}, @@ -306,8 +306,11 @@ impl BackendData { Some(final_config.transform.into()).filter(|x| *x != output.current_transform()); let scale = Some(final_config.scale) .filter(|x| *x != output.current_scale().fractional_scale()); - let location = - Some(final_config.position.into()).filter(|x| *x != output.current_location()); + let location = Some(Point::from(( + final_config.position.0 as i32, + final_config.position.1 as i32, + ))) + .filter(|x| *x != output.current_location()); output.change_current_state(mode, transform, scale.map(Scale::Fractional), location); output.set_adaptive_sync(final_config.vrr); diff --git a/src/wayland/handlers/output_configuration.rs b/src/wayland/handlers/output_configuration.rs index 4b5993b3..eb900ddc 100644 --- a/src/wayland/handlers/output_configuration.rs +++ b/src/wayland/handlers/output_configuration.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only -use smithay::output::Output; +use smithay::{output::Output, utils::Point}; use tracing::{error, warn}; use crate::{ @@ -31,7 +31,7 @@ impl State { fn output_configuration( &mut self, test_only: bool, - conf: Vec<(Output, OutputConfiguration)>, + mut conf: Vec<(Output, OutputConfiguration)>, ) -> bool { if conf .iter() @@ -40,6 +40,47 @@ impl State { return false; // we don't allow the user to accidentally disable all their outputs } + // sanitize negative positions + { + let (offset_x, offset_y) = conf.iter().fold((0, 0), |mut offset, (_, conf)| { + if let OutputConfiguration::Enabled { + position: Some(position), + .. + } = conf + { + if position.x.is_negative() { + offset.0 = offset.0.max(position.x.abs()); + } + if position.y.is_negative() { + offset.1 = offset.1.max(position.y.abs()); + } + } + offset + }); + + if offset_x > 0 || offset_y > 0 { + for (output, conf) in conf.iter_mut() { + if let OutputConfiguration::Enabled { + ref mut position, .. + } = conf + { + let current_config = output + .user_data() + .get::>() + .unwrap() + .borrow(); + + *position = Some( + position.unwrap_or(Point::from(( + current_config.position.0 as i32, + current_config.position.1 as i32, + ))) + Point::from((offset_x, offset_y)), + ); + } + } + } + } + let mut backups = Vec::new(); for (output, conf) in &conf { { @@ -76,7 +117,7 @@ impl State { current_config.transform = *transform; } if let Some(position) = position { - current_config.position = (*position).into(); + current_config.position = (position.x as u32, position.y as u32); } if let Some(vrr) = adaptive_sync { current_config.vrr = *vrr;