Files
aria 993bc0f88f Integrate native Rime and stabilize input, output, and rendering
- Add optional modifier-only Super binding whose tap is cancelled by
  other input, focus changes, grabs, locks, and session teardown.
- Ship the native ferese-rime user service, Rime defaults, installer
  inventory, package dependencies, session environment, and docs.
- Vendor Smithay 8a27023 with the SHM texture-cache format fix and add
  GPU regressions for format changes and resize snapshots.
- Release reused CRTC owners before staging output modes, then restore
  changed outputs before former owners when a transaction fails.
- Wait for resize-capture GPU completion, expand filtered surface
  damage, and preserve IME popup origin under fractional scaling.
- Mark weekends like holidays in both calendar layouts.
2026-10-30 03:13:43 +09:00

221 lines
6.0 KiB
Rust

use std::{collections::HashMap, path::PathBuf, time::Duration};
use smithay::reexports::drm::control::{connector, crtc};
use smithay_drm_extras::{
display_info,
drm_scanner::{self, DrmScanEvent},
};
use smithay::{
backend::{
drm::{self, DrmDeviceFd, DrmNode},
session::{Session, libseat::LibSeatSession},
udev::{UdevBackend, UdevEvent},
},
reexports::{
calloop::{EventLoop, LoopHandle, timer::Timer},
rustix::fs::OFlags,
},
utils::DeviceFd,
};
struct State {
handle: LoopHandle<'static, Self>,
session: LibSeatSession,
devices: HashMap<DrmNode, Device>,
}
struct Device {
drm: drm::DrmDevice,
drm_scanner: drm_scanner::DrmScanner,
surfaces: HashMap<crtc::Handle, Surface>,
}
#[derive(Clone)]
struct Surface {
// Your gbm surface stuff goes here
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut event_loop = EventLoop::<State>::try_new()?;
let (session, notify) = LibSeatSession::new().unwrap();
event_loop.handle().insert_source(notify, |_, _, _| {}).unwrap();
let mut state = State {
handle: event_loop.handle(),
session,
devices: Default::default(),
};
init_udev(&mut state);
event_loop
.handle()
.insert_source(Timer::from_duration(Duration::from_secs(5)), |_, _, _| {
panic!("Aborted");
})
.unwrap();
event_loop.run(None, &mut state, |_data| {})?;
Ok(())
}
fn init_udev(state: &mut State) {
let backend = UdevBackend::new(state.session.seat()).unwrap();
for (device_id, path) in backend.device_list() {
state.on_udev_event(UdevEvent::Added {
device_id,
path: path.to_owned(),
});
}
state
.handle
.insert_source(backend, |event, _, state| state.on_udev_event(event))
.unwrap();
}
impl State {
fn on_udev_event(&mut self, event: UdevEvent) {
match event {
UdevEvent::Added { device_id, path } => {
if let Ok(node) = DrmNode::from_dev_id(device_id) {
self.device_added(node, path);
}
}
UdevEvent::Changed { device_id } => {
if let Ok(node) = DrmNode::from_dev_id(device_id) {
self.device_changed(node);
}
}
UdevEvent::Removed { device_id } => {
if let Ok(node) = DrmNode::from_dev_id(device_id) {
self.device_removed(node);
}
}
}
}
fn device_added(&mut self, node: DrmNode, path: PathBuf) {
let fd = self
.session
.open(
&path,
OFlags::RDWR | OFlags::CLOEXEC | OFlags::NOCTTY | OFlags::NONBLOCK,
)
.unwrap();
let fd = DrmDeviceFd::new(DeviceFd::from(fd));
let (drm, drm_notifier) = drm::DrmDevice::new(fd, false).unwrap();
self.handle
.insert_source(drm_notifier, move |event, _, _| match event {
drm::DrmEvent::VBlank(_) => {}
drm::DrmEvent::Error(_) => {}
})
.unwrap();
self.devices.insert(
node,
Device {
drm,
drm_scanner: Default::default(),
surfaces: Default::default(),
},
);
self.device_changed(node);
}
fn connector_connected(&mut self, node: DrmNode, connector: connector::Info, crtc: crtc::Handle) {
if let Some(device) = self.devices.get_mut(&node) {
let name = format!("{}-{}", connector.interface().as_str(), connector.interface_id());
let display_info = display_info::for_connector(&device.drm, connector.handle());
let manufacturer = display_info
.as_ref()
.and_then(|info| info.make())
.unwrap_or_else(|| "Unknown".into());
let model = display_info
.as_ref()
.and_then(|info| info.model())
.unwrap_or_else(|| "Unknown".into());
println!("Connected:");
dbg!(name);
dbg!(manufacturer);
dbg!(model);
device.surfaces.insert(crtc, Surface {});
}
}
fn connector_disconnected(&mut self, node: DrmNode, connector: connector::Info, crtc: crtc::Handle) {
let name = format!("{}-{}", connector.interface().as_str(), connector.interface_id());
println!("Disconnected:");
dbg!(name);
if let Some(device) = self.devices.get_mut(&node) {
device.surfaces.remove(&crtc);
}
}
fn device_changed(&mut self, node: DrmNode) {
let device = if let Some(device) = self.devices.get_mut(&node) {
device
} else {
return;
};
for event in device
.drm_scanner
.scan_connectors(&device.drm)
.expect("failed to scan connectors")
{
match event {
DrmScanEvent::Connected {
connector,
crtc: Some(crtc),
} => {
self.connector_connected(node, connector, crtc);
}
DrmScanEvent::Disconnected {
connector,
crtc: Some(crtc),
} => {
self.connector_disconnected(node, connector, crtc);
}
DrmScanEvent::Changed { .. } => {}
_ => {}
}
}
}
fn device_removed(&mut self, node: DrmNode) {
let device = if let Some(device) = self.devices.get_mut(&node) {
device
} else {
return;
};
let crtcs: Vec<_> = device
.drm_scanner
.crtcs()
.map(|(info, crtc)| (info.clone(), crtc))
.collect();
for (connector, crtc) in crtcs {
self.connector_disconnected(node, connector, crtc);
}
self.devices.remove(&node);
}
}