Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions anvil/src/udev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,10 @@ impl AnvilState<UdevData> {
} => {
self.connector_disconnected(node, connector, crtc);
}
// The connector's mode list changed while it stayed connected (e.g. EDID
// arrived after the initial probe returned empty/fallback modes). Compositors
// should re-evaluate the output's mode selection and recreate the surface here.
DrmScanEvent::Changed { .. } => {}
_ => {}
}
}
Expand Down
3 changes: 2 additions & 1 deletion smithay-drm-extras/examples/simple.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{collections::HashMap, path::PathBuf, time::Duration};

use ::drm::control::{connector, crtc};
use drm::control::{connector, crtc};
use smithay_drm_extras::{
display_info,
drm_scanner::{self, DrmScanEvent},
Expand Down Expand Up @@ -192,6 +192,7 @@ impl State {
} => {
self.connector_disconnected(node, connector, crtc);
}
DrmScanEvent::Changed { .. } => {}
_ => {}
}
}
Expand Down
52 changes: 34 additions & 18 deletions smithay-drm-extras/src/drm_scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,11 @@
//! match event {
//! DrmScanEvent::Connected { .. } => {},
//! DrmScanEvent::Disconnected { .. } => {},
//! DrmScanEvent::Changed { .. } => {},
//! }
//! }
//! ```
use std::{
collections::HashMap,
iter::{Chain, Map},
};
use std::collections::HashMap;

use drm::control::{connector, crtc, Device as ControlDevice};

Expand Down Expand Up @@ -93,14 +91,15 @@ where
/// let res = scanner.scan_connectors(&drm_device).expect("failed to scan connectors");
///
/// // You can extract scan info manually
/// println!("Plugged {} connectors", res.added.len());
/// println!("Unplugged {} connectors", res.removed.len());
/// println!("Plugged {} connectors", res.connected.len());
/// println!("Unplugged {} connectors", res.disconnected.len());
///
/// // Or simply iterate over it
/// for event in res {
/// match event {
/// DrmScanEvent::Connected { .. } => {},
/// DrmScanEvent::Disconnected { .. } => {},
/// DrmScanEvent::Changed { .. } => {},
/// }
/// }
/// ```
Expand All @@ -127,9 +126,19 @@ where
})
.collect();

let changed = scan
.changed
.into_iter()
.map(|info| {
let crtc = self.crtc_mapper.crtc_for_connector(&info.handle());
(info, crtc)
})
.collect();

Ok(DrmScanResult {
disconnected: removed,
connected: added,
changed,
})
}

Expand Down Expand Up @@ -166,6 +175,8 @@ pub struct DrmScanResult {
pub connected: Vec<DrmScanItem>,
/// Connectors that got unplugged since last scan
pub disconnected: Vec<DrmScanItem>,
/// Connectors whose mode list changed while staying connected
pub changed: Vec<DrmScanItem>,
}

impl DrmScanResult {
Expand Down Expand Up @@ -194,6 +205,13 @@ pub enum DrmScanEvent {
/// Crtc that is no longer mapped to this connector
crtc: Option<crtc::Handle>,
},
/// The connector's mode list changed while staying connected
Changed {
/// Info about the connector whose modes changed
connector: connector::Info,
/// Crtc that is mapped to this connector
crtc: Option<crtc::Handle>,
},
}

impl DrmScanEvent {
Expand All @@ -204,25 +222,23 @@ impl DrmScanEvent {
fn disconnected((connector, crtc): (connector::Info, Option<crtc::Handle>)) -> Self {
DrmScanEvent::Disconnected { connector, crtc }
}
}

type DrmScanItemToEvent = fn(DrmScanItem) -> DrmScanEvent;
fn changed((connector, crtc): (connector::Info, Option<crtc::Handle>)) -> Self {
DrmScanEvent::Changed { connector, crtc }
}
}

impl IntoIterator for DrmScanResult {
type Item = DrmScanEvent;
type IntoIter = Chain<
Map<std::vec::IntoIter<DrmScanItem>, DrmScanItemToEvent>,
Map<std::vec::IntoIter<DrmScanItem>, DrmScanItemToEvent>,
>;
type IntoIter = std::vec::IntoIter<DrmScanEvent>;

fn into_iter(self) -> Self::IntoIter {
self.disconnected
.into_iter()
.map(DrmScanEvent::disconnected as DrmScanItemToEvent)
.chain(
self.connected
.into_iter()
.map(DrmScanEvent::connected as DrmScanItemToEvent),
)
.map(DrmScanEvent::disconnected)
.chain(self.connected.into_iter().map(DrmScanEvent::connected))
.chain(self.changed.into_iter().map(DrmScanEvent::changed))
.collect::<Vec<_>>()
.into_iter()
}
}
41 changes: 24 additions & 17 deletions smithay-drm-extras/src/drm_scanner/connector_scanner.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use std::{
collections::HashMap,
iter::{Chain, Map},
};
use std::collections::HashMap;

use drm::control::{connector, Device as ControlDevice};

Expand All @@ -19,6 +16,7 @@ use drm::control::{connector, Device as ControlDevice};
/// match event {
/// ConnectorScanEvent::Connected(conn) => {},
/// ConnectorScanEvent::Disconnected(conn) => {},
/// ConnectorScanEvent::Changed(conn) => {},
/// }
/// }
#[derive(Debug, Default)]
Expand All @@ -39,6 +37,7 @@ impl ConnectorScanner {

let mut added = Vec::new();
let mut removed = Vec::new();
let mut changed = Vec::new();

for conn in connector_handles
.iter()
Expand All @@ -52,7 +51,16 @@ impl ConnectorScanner {
(State::Connected, State::Disconnected) => removed.push(conn),
(State::Disconnected | State::Unknown, State::Connected) => added.push(conn),
//
(State::Connected, State::Connected) => {}
// Emit Changed when the mode list changes while staying
// connected. This covers the EDID race where the kernel
// initially reports a connector as Connected with an
// empty or fallback mode list (EDID not yet read) and a
// later rescan finds the real modes populated.
(State::Connected, State::Connected) => {
if old.modes() != conn.modes() {
changed.push(conn);
}
}
(State::Disconnected, State::Disconnected) => {}
//
(State::Unknown, _) => {}
Expand All @@ -66,6 +74,7 @@ impl ConnectorScanner {
Ok(ConnectorScanResult {
connected: added,
disconnected: removed,
changed,
})
}

Expand All @@ -86,6 +95,8 @@ pub struct ConnectorScanResult {
pub connected: Vec<connector::Info>,
/// Connectors that got unplugged since last scan
pub disconnected: Vec<connector::Info>,
/// Connectors whose mode list changed while staying connected
pub changed: Vec<connector::Info>,
}

/// Created from [`ConnectorScanResult`], informs about connector events.
Expand All @@ -95,6 +106,8 @@ pub enum ConnectorScanEvent {
Connected(connector::Info),
/// A connector got unplugged in since last scan
Disconnected(connector::Info),
/// The connector's mode list changed while staying connected
Changed(connector::Info),
}

impl ConnectorScanResult {
Expand All @@ -106,23 +119,17 @@ impl ConnectorScanResult {
}
}

type ConnectorScanItemToEvent = fn(connector::Info) -> ConnectorScanEvent;

impl IntoIterator for ConnectorScanResult {
type Item = ConnectorScanEvent;
type IntoIter = Chain<
Map<std::vec::IntoIter<connector::Info>, ConnectorScanItemToEvent>,
Map<std::vec::IntoIter<connector::Info>, ConnectorScanItemToEvent>,
>;
type IntoIter = std::vec::IntoIter<ConnectorScanEvent>;

fn into_iter(self) -> Self::IntoIter {
self.disconnected
.into_iter()
.map(ConnectorScanEvent::Disconnected as ConnectorScanItemToEvent)
.chain(
self.connected
.into_iter()
.map(ConnectorScanEvent::Connected as ConnectorScanItemToEvent),
)
.map(ConnectorScanEvent::Disconnected)
.chain(self.connected.into_iter().map(ConnectorScanEvent::Connected))
.chain(self.changed.into_iter().map(ConnectorScanEvent::Changed))
.collect::<Vec<_>>()
.into_iter()
}
}
Loading