Commit ea84a35c5001
tarball4 files changed+71-6
@@ -34,9 +34,9 @@ unfocused = "#3b4252"
3434
# Variable refresh rate on outputs that support it, off, on, or fullscreen.3535
vrr = "fullscreen"3636
37
-# Per connector, read when the output connects. transform is normal, 90, 180,38
-# 270, flipped, flipped-90, flipped-180 or flipped-270. Outputs without a39
-# position line up left to right.37
+# Per connector. transform and position follow a reload, mode needs a replug.38
+# transform is normal, 90, 180, 270, flipped, flipped-90, flipped-180 or39
+# flipped-270. Outputs without a position line up left to right.4040
# [output.DP-1]4141
# transform = "90"4242
# position = [2560, 0]@@ -86,8 +86,8 @@ pub struct Outputs {
8686
pub named: std::collections::BTreeMap<String, OutputConfig>,8787
}8888
89
-/// Applied when the output connects. Changing them needs a restart or a90
-/// replug, since a new mode or rotation means a modeset.89
+/// Transform and position follow a reload. A new mode waits for a restart90
+/// or a replug, since it means a modeset.9191
#[derive(Deserialize, Debug, Clone, PartialEq, Default)]9292
#[serde(default, deny_unknown_fields)]9393
pub struct OutputConfig {@@ -224,6 +224,7 @@ impl State {
224224
if keyboard_changed {225225
self.reconfigure_keyboard();226226
}227
+ crate::drm::reconfigure_outputs(self);227228
tracing::info!("config reloaded");228229
Ok(())229230
}@@ -34,7 +34,7 @@ use smithay::reexports::drm::Device as _;
3434
use smithay::reexports::drm::control::{self, ModeTypeFlags, connector, crtc};3535
use smithay::reexports::input::Libinput;3636
use smithay::reexports::rustix::fs::OFlags;37
-use smithay::utils::{DeviceFd, Point, Transform};37
+use smithay::utils::{DeviceFd, Logical, Point, Transform};3838
use smithay::wayland::drm_syncobj::{DrmSyncobjState, supports_syncobj_eventfd};3939
use smithay_drm_extras::drm_scanner::{DrmScanEvent, DrmScanner};4040
use std::collections::HashMap;@@ -438,6 +438,70 @@ fn transform(t: OutputTransform) -> Transform {
438438
}439439
}440440
441
+/// Outputs without a configured position are laid out left to right in442
+/// their current order, so one rotating pushes its neighbours along.443
+pub fn reconfigure_outputs(state: &mut State) {444
+ let State {445
+ backend: Backend::Drm(drm),446
+ wm: Wm { layout, space, .. },447
+ settings,448
+ ..449
+ } = state450
+ else {451
+ return;452
+ };453
+ let mut surfaces: Vec<&mut Surface> = drm.surfaces.values_mut().collect();454
+ surfaces.sort_by_key(|s| s.output.current_location().x);455
+ let mut right = 0;456
+ let mut changed = false;457
+ for s in surfaces {458
+ let config = settings459
+ .config460
+ .output461
+ .named462
+ .get(&s.output.name())463
+ .cloned()464
+ .unwrap_or_default();465
+ let Some(mode) = s.output.current_mode() else {466
+ continue;467
+ };468
+ let transform = transform(config.transform);469
+ let size = transform.transform_size(mode.size);470
+ let position: Point<i32, Logical> = match config.position {471
+ Some([x, y]) => (x, y).into(),472
+ None => (right, 0).into(),473
+ };474
+ right = right.max(position.x + size.w);475
+ if s.output.current_transform() == transform && s.output.current_location() == position {476
+ continue;477
+ }478
+ s.output479
+ .change_current_state(None, Some(transform), None, Some(position));480
+ space.map_output(&s.output, position);481
+ let area = Rect::new(482
+ f64::from(position.x),483
+ f64::from(position.y),484
+ f64::from(size.w),485
+ f64::from(size.h),486
+ );487
+ layout.set_output_area(s.id, area);488
+ s.redraw = true;489
+ changed = true;490
+ tracing::info!(491
+ name = s.output.name(),492
+ ?transform,493
+ x = position.x,494
+ y = position.y,495
+ "output reconfigured"496
+ );497
+ }498
+ if changed {499
+ state.reserve_layers();500
+ state.reconfigure_lock();501
+ state.apply_layout();502
+ }503
+}504
+441505
fn disconnect(state: &mut State, crtc: crtc::Handle) {442506
let Some(drm) = state.backend.drm_mut() else {443507
return;