srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/wayland/src/udev/drm.rs
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2025-02-15 14:56:00 +0200
committersrdusr <[email protected]>2025-02-15 14:56:00 +0200
commit0a4c4b5941fe982ccb3d3175e26d9d83f0025ffd (patch)
tree7672d0af277664f457c6c9462925c0005fe35dcf /crates/wayland/src/udev/drm.rs
parent413daa7ba2ea0ebd1424c024fd0566423aaea3f8 (diff)
downloadsrdwm-0a4c4b5941fe982ccb3d3175e26d9d83f0025ffd.tar.gz
srdwm-0a4c4b5941fe982ccb3d3175e26d9d83f0025ffd.zip
Checkpoint: preserve all uncommitted rust-rewrite worktree work
Safety commit before reconciling this worktree with main, which has diverged with its own separate fixes today. Nothing here is reviewed or curated yet - this exists purely so none of this work can be lost to a git operation, disk issue, or worktree cleanup while that reconciliation happens.
Diffstat (limited to 'crates/wayland/src/udev/drm.rs')
-rw-r--r--crates/wayland/src/udev/drm.rs49
1 files changed, 46 insertions, 3 deletions
diff --git a/crates/wayland/src/udev/drm.rs b/crates/wayland/src/udev/drm.rs
index fd06619..efe53aa 100644
--- a/crates/wayland/src/udev/drm.rs
+++ b/crates/wayland/src/udev/drm.rs
@@ -12,12 +12,22 @@ fn mode_refresh_mhz(mode: &DrmMode) -> i32 {
/// Brings one connector up: allocates its scanout buffers, sets the mode,
/// and creates the `wl_output` global. Shared by startup and hotplug so a
/// monitor plugged in later is set up exactly like one present at boot.
+///
+/// `scale` is `srd.monitor.scale(name, ...)`'s stored value for this
+/// connector, if any - an explicit override always wins. `None` no
+/// longer means "always 1.0": it falls through to `srdwm_core::monitor::
+/// auto_scale_for`, computed fresh from this connector's own real EDID
+/// physical size and resolution, so a physically large, low-density
+/// monitor gets a sensible scale with no per-connector-name config
+/// needed at all.
pub(crate) fn bring_up_head(
card: &Card,
dh: &DisplayHandle,
probe: &ConnectorProbe,
crtc: crtc::Handle,
x_offset: i32,
+ logical_x: i32,
+ scale: Option<f64>,
) -> PlatformResult<(UdevHead, crate::state::OutputEntry)> {
let (width, height) = probe.mode.size();
let (width, height) = (width as i32, height as i32);
@@ -32,7 +42,8 @@ pub(crate) fn bring_up_head(
// Physical size in millimeters comes straight from EDID via the
// connector, not the hardcoded (0, 0) this used to be - some clients
// compute their own effective DPI from it (independently of the
- // compositor's own scale factor, which srdwm always reports as 1), so
+ // compositor's own scale factor, which defaults to 1 unless `srd.
+ // monitor.scale` overrides it for this connector), so
// reporting "no physical size at all" was live, wrong data reaching
// every client, not just an unfilled-in placeholder.
let (phys_w, phys_h) = probe.info.size().unwrap_or((0, 0));
@@ -42,7 +53,28 @@ pub(crate) fn bring_up_head(
PhysicalProperties { size: physical_mm.into(), subpixel: Subpixel::Unknown, make: "srdwm".into(), model: "drm".into() },
);
let mode = OutputMode { size: (width, height).into(), refresh: mode_refresh_mhz(&probe.mode) };
- output.change_current_state(Some(mode), Some(Transform::Normal), None, Some((x_offset, 0).into()));
+ let resolved_scale = scale.unwrap_or_else(|| srdwm_core::monitor::auto_scale_for(physical_mm, (width, height)));
+ // `x_offset` is physical (the caller accumulates it from real head
+ // widths - see `UdevHead::location`'s own doc comment for why that's
+ // the space this compositor tracks output position in internally),
+ // but `change_current_state`'s own position parameter is a real
+ // Wayland-protocol value and `wl_output`/`xdg_output` always report
+ // position to clients in logical points - so it needs the caller's
+ // own *separately*-accumulated `logical_x`, not a value derived from
+ // `x_offset` and this head's own scale alone. Dividing `x_offset` by
+ // just this head's own `resolved_scale` (what this used to do) is only
+ // correct for the first head in a layout, or when every head shares
+ // the same scale - for any later head following one with a
+ // *different* scale, this head's own scale has nothing to do with how
+ // much logical space the *previous* heads actually occupy, so it
+ // computed the wrong logical position for anything past the first
+ // output. Reported live (measured from inside GTK, not inferred) as
+ // two monitors' logical rectangles overlapping by a few hundred
+ // pixels whenever one had a non-1.0 scale - ambiguous "which monitor
+ // is this point on" answers, and hit-testing/screenshots landing on
+ // the wrong output in the overlap band. See `platform.rs`'s startup
+ // loop for how `logical_x` is actually accumulated correctly.
+ output.change_current_state(Some(mode), Some(Transform::Normal), Some(smithay::output::Scale::Fractional(resolved_scale)), Some((logical_x, 0).into()));
output.set_preferred(mode);
let global = output.create_global::<CompState>(dh);
@@ -56,9 +88,11 @@ pub(crate) fn bring_up_head(
buffers,
front: 0,
flip_pending: false,
+ flip_pending_since: Instant::now(),
ages: [0, 0],
location,
size: (width, height),
+ mode: probe.mode,
};
Ok((head, crate::state::OutputEntry { output, location }))
}
@@ -87,7 +121,16 @@ pub(crate) fn probe_connected(card: &Card) -> PlatformResult<Vec<ConnectorProbe>
if info.state() != connector::State::Connected {
continue;
}
- let name = format!("{:?}-{}", info.interface(), info.interface_id());
+ // `info.interface()`'s `Debug` output is Rust's own enum variant
+ // name (`HDMIA`, `EmbeddedDisplayPort`) - neither string exists
+ // anywhere else. The kernel, `ddcutil`, `/sys/class/drm`, and any
+ // config the user already has for another compositor all use the
+ // strings in `Interface::as_str()` (`HDMI-A`, `eDP`, and so on --
+ // taken directly from the kernel's own `drm_connector_enum_list`).
+ // Reported live: `srd monitors` showed `HDMIA-1`, a name that
+ // matched nothing, while `/sys/class/drm` and `ddcutil detect`
+ // both said `HDMI-A-1` for the same physical connector.
+ let name = format!("{}-{}", info.interface().as_str(), info.interface_id());
// Prefer the mode the display advertises as PREFERRED (its native
// resolution) rather than whatever happens to be listed first --
// the list order is not guaranteed, and picking wrong means running