1
0
Fork 0
forked from wry/wry

config: tell the config about drm devices

This commit is contained in:
Julian Orth 2022-05-10 16:43:09 +02:00
parent 99fcd63438
commit e27cf29693
23 changed files with 581 additions and 50 deletions

View file

@ -9,12 +9,12 @@ use {
}, },
drm::{ drm::{
connector_type::{ConnectorType, CON_UNKNOWN}, connector_type::{ConnectorType, CON_UNKNOWN},
Connector, Mode, Connector, DrmDevice, Mode,
}, },
input::{acceleration::AccelProfile, capability::Capability, InputDevice, Seat}, input::{acceleration::AccelProfile, capability::Capability, InputDevice, Seat},
keyboard::keymap::Keymap, keyboard::keymap::Keymap,
theme::Color, theme::Color,
Axis, Command, Direction, LogLevel, ModifiedKeySym, Timer, Workspace, Axis, Command, Direction, LogLevel, ModifiedKeySym, PciId, Timer, Workspace,
}, },
std::{ std::{
cell::{Cell, RefCell}, cell::{Cell, RefCell},
@ -40,6 +40,8 @@ pub(crate) struct Client {
on_connector_connected: RefCell<Option<Rc<dyn Fn(Connector)>>>, on_connector_connected: RefCell<Option<Rc<dyn Fn(Connector)>>>,
on_graphics_initialized: Cell<Option<Box<dyn FnOnce()>>>, on_graphics_initialized: Cell<Option<Box<dyn FnOnce()>>>,
on_new_connector: RefCell<Option<Rc<dyn Fn(Connector)>>>, on_new_connector: RefCell<Option<Rc<dyn Fn(Connector)>>>,
on_new_drm_device: RefCell<Option<Rc<dyn Fn(DrmDevice)>>>,
on_del_drm_device: RefCell<Option<Rc<dyn Fn(DrmDevice)>>>,
bufs: RefCell<Vec<Vec<u8>>>, bufs: RefCell<Vec<Vec<u8>>>,
reload: Cell<bool>, reload: Cell<bool>,
} }
@ -124,6 +126,8 @@ pub unsafe extern "C" fn init(
on_connector_connected: Default::default(), on_connector_connected: Default::default(),
on_graphics_initialized: Default::default(), on_graphics_initialized: Default::default(),
on_new_connector: Default::default(), on_new_connector: Default::default(),
on_new_drm_device: Default::default(),
on_del_drm_device: Default::default(),
bufs: Default::default(), bufs: Default::default(),
reload: Cell::new(false), reload: Cell::new(false),
}); });
@ -400,6 +404,36 @@ impl Client {
self.send(&ClientMessage::ConnectorSetPosition { connector, x, y }); self.send(&ClientMessage::ConnectorSetPosition { connector, x, y });
} }
pub fn device_connectors(&self, device: DrmDevice) -> Vec<Connector> {
let res = self.send_with_response(&ClientMessage::GetDeviceConnectors { device });
get_response!(res, vec![], GetDeviceConnectors, connectors);
connectors
}
pub fn drm_device_syspath(&self, device: DrmDevice) -> String {
let res = self.send_with_response(&ClientMessage::GetDrmDeviceSyspath { device });
get_response!(res, String::new(), GetDrmDeviceSyspath, syspath);
syspath
}
pub fn drm_device_vendor(&self, device: DrmDevice) -> String {
let res = self.send_with_response(&ClientMessage::GetDrmDeviceVendor { device });
get_response!(res, String::new(), GetDrmDeviceVendor, vendor);
vendor
}
pub fn drm_device_model(&self, device: DrmDevice) -> String {
let res = self.send_with_response(&ClientMessage::GetDrmDeviceModel { device });
get_response!(res, String::new(), GetDrmDeviceModel, model);
model
}
pub fn drm_device_pci_id(&self, device: DrmDevice) -> PciId {
let res = self.send_with_response(&ClientMessage::GetDrmDevicePciId { device });
get_response!(res, Default::default(), GetDrmDevicePciId, pci_id);
pci_id
}
pub fn connector_connected(&self, connector: Connector) -> bool { pub fn connector_connected(&self, connector: Connector) -> bool {
let res = self.send_with_response(&ClientMessage::ConnectorConnected { connector }); let res = self.send_with_response(&ClientMessage::ConnectorConnected { connector });
get_response!(res, false, ConnectorConnected, connected); get_response!(res, false, ConnectorConnected, connected);
@ -429,6 +463,20 @@ impl Client {
} }
} }
pub fn drm_devices(&self) -> Vec<DrmDevice> {
let res = self.send_with_response(&ClientMessage::GetDrmDevices);
get_response!(res, vec![], GetDrmDevices, devices);
devices
}
pub fn on_new_drm_device<F: Fn(DrmDevice) + 'static>(&self, f: F) {
*self.on_new_drm_device.borrow_mut() = Some(Rc::new(f));
}
pub fn on_del_drm_device<F: Fn(DrmDevice) + 'static>(&self, f: F) {
*self.on_del_drm_device.borrow_mut() = Some(Rc::new(f));
}
pub fn on_new_connector<F: Fn(Connector) + 'static>(&self, f: F) { pub fn on_new_connector<F: Fn(Connector) + 'static>(&self, f: F) {
*self.on_new_connector.borrow_mut() = Some(Rc::new(f)); *self.on_new_connector.borrow_mut() = Some(Rc::new(f));
} }
@ -591,6 +639,18 @@ impl Client {
ServerMessage::Clear => { ServerMessage::Clear => {
// only used by test config // only used by test config
} }
ServerMessage::NewDrmDev { device } => {
let handler = self.on_new_drm_device.borrow_mut();
if let Some(handler) = handler.deref() {
handler(device);
}
}
ServerMessage::DelDrmDev { device } => {
let handler = self.on_del_drm_device.borrow_mut();
if let Some(handler) = handler.deref() {
handler(device);
}
}
} }
} }

View file

@ -1,10 +1,10 @@
use { use {
crate::{ crate::{
drm::{connector_type::ConnectorType, Connector}, drm::{connector_type::ConnectorType, Connector, DrmDevice},
input::{acceleration::AccelProfile, capability::Capability, InputDevice, Seat}, input::{acceleration::AccelProfile, capability::Capability, InputDevice, Seat},
keyboard::{keymap::Keymap, mods::Modifiers, syms::KeySym}, keyboard::{keymap::Keymap, mods::Modifiers, syms::KeySym},
theme::Color, theme::Color,
Axis, Direction, LogLevel, Timer, Workspace, Axis, Direction, LogLevel, PciId, Timer, Workspace,
}, },
bincode::{BorrowDecode, Decode, Encode}, bincode::{BorrowDecode, Decode, Encode},
std::time::Duration, std::time::Duration,
@ -46,6 +46,12 @@ pub enum ServerMessage {
timer: Timer, timer: Timer,
}, },
Clear, Clear,
NewDrmDev {
device: DrmDevice,
},
DelDrmDev {
device: DrmDevice,
},
} }
#[derive(Encode, BorrowDecode, Debug)] #[derive(Encode, BorrowDecode, Debug)]
@ -241,6 +247,22 @@ pub enum ClientMessage<'a> {
seat: Seat, seat: Seat,
}, },
Reload, Reload,
GetDeviceConnectors {
device: DrmDevice,
},
GetDrmDeviceSyspath {
device: DrmDevice,
},
GetDrmDeviceVendor {
device: DrmDevice,
},
GetDrmDeviceModel {
device: DrmDevice,
},
GetDrmDevices,
GetDrmDevicePciId {
device: DrmDevice,
},
} }
#[derive(Encode, Decode, Debug)] #[derive(Encode, Decode, Debug)]
@ -303,6 +325,24 @@ pub enum Response {
GetFullscreen { GetFullscreen {
fullscreen: bool, fullscreen: bool,
}, },
GetDeviceConnectors {
connectors: Vec<Connector>,
},
GetDrmDeviceSyspath {
syspath: String,
},
GetDrmDeviceVendor {
vendor: String,
},
GetDrmDeviceModel {
model: String,
},
GetDrmDevices {
devices: Vec<DrmDevice>,
},
GetDrmDevicePciId {
pci_id: PciId,
},
} }
#[derive(Encode, Decode, Debug)] #[derive(Encode, Decode, Debug)]

View file

@ -1,9 +1,12 @@
use { use {
crate::drm::connector_type::{ crate::{
ConnectorType, CON_9PIN_DIN, CON_COMPONENT, CON_COMPOSITE, CON_DISPLAY_PORT, CON_DPI, drm::connector_type::{
CON_DSI, CON_DVIA, CON_DVID, CON_DVII, CON_EDP, CON_EMBEDDED_WINDOW, CON_HDMIA, CON_HDMIB, ConnectorType, CON_9PIN_DIN, CON_COMPONENT, CON_COMPOSITE, CON_DISPLAY_PORT, CON_DPI,
CON_LVDS, CON_SPI, CON_SVIDEO, CON_TV, CON_UNKNOWN, CON_USB, CON_VGA, CON_VIRTUAL, CON_DSI, CON_DVIA, CON_DVID, CON_DVII, CON_EDP, CON_EMBEDDED_WINDOW, CON_HDMIA,
CON_WRITEBACK, CON_HDMIB, CON_LVDS, CON_SPI, CON_SVIDEO, CON_TV, CON_UNKNOWN, CON_USB, CON_VGA,
CON_VIRTUAL, CON_WRITEBACK,
},
PciId,
}, },
bincode::{Decode, Encode}, bincode::{Decode, Encode},
std::str::FromStr, std::str::FromStr,
@ -88,6 +91,18 @@ impl Connector {
} }
} }
pub fn drm_devices() -> Vec<DrmDevice> {
get!().drm_devices()
}
pub fn on_new_drm_device<F: Fn(DrmDevice) + 'static>(f: F) {
get!().on_new_drm_device(f)
}
pub fn on_drm_device_removed<F: Fn(DrmDevice) + 'static>(f: F) {
get!().on_del_drm_device(f)
}
pub fn on_new_connector<F: Fn(Connector) + 'static>(f: F) { pub fn on_new_connector<F: Fn(Connector) + 'static>(f: F) {
get!().on_new_connector(f) get!().on_new_connector(f)
} }
@ -186,3 +201,28 @@ pub mod connector_type {
pub const CON_USB: ConnectorType = ConnectorType(20); pub const CON_USB: ConnectorType = ConnectorType(20);
pub const CON_EMBEDDED_WINDOW: ConnectorType = ConnectorType(u32::MAX); pub const CON_EMBEDDED_WINDOW: ConnectorType = ConnectorType(u32::MAX);
} }
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct DrmDevice(pub u64);
impl DrmDevice {
pub fn connectors(self) -> Vec<Connector> {
get!().device_connectors(self)
}
pub fn syspath(self) -> String {
get!().drm_device_syspath(self)
}
pub fn vendor(self) -> String {
get!().drm_device_vendor(self)
}
pub fn model(self) -> String {
get!().drm_device_model(self)
}
pub fn pci_id(self) -> PciId {
get!().drm_device_pci_id(self)
}
}

View file

@ -156,9 +156,7 @@ pub fn get_seats() -> Vec<Seat> {
} }
pub fn input_devices() -> Vec<InputDevice> { pub fn input_devices() -> Vec<InputDevice> {
let mut res = vec![]; get!().get_input_devices(None)
(|| res = get!().get_input_devices(None))();
res
} }
pub fn remove_all_seats() {} pub fn remove_all_seats() {}

View file

@ -1,7 +1,11 @@
use { use {
crate::keyboard::{keymap::Keymap, ModifiedKeySym}, crate::keyboard::{keymap::Keymap, ModifiedKeySym},
bincode::{Decode, Encode}, bincode::{Decode, Encode},
std::{collections::HashMap, time::Duration}, std::{
collections::HashMap,
fmt::{Debug, Display, Formatter},
time::Duration,
},
}; };
#[macro_use] #[macro_use]
@ -129,3 +133,15 @@ pub fn reload() {
pub fn is_reload() -> bool { pub fn is_reload() -> bool {
get!(false).is_reload() get!(false).is_reload()
} }
#[derive(Encode, Decode, Debug, Copy, Clone, Hash, Eq, PartialEq, Default)]
pub struct PciId {
pub vendor: u32,
pub model: u32,
}
impl Display for PciId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:04x}:{:04x}", self.vendor, self.model)
}
}

View file

@ -11,10 +11,12 @@ use {
fmt::{Debug, Display, Formatter}, fmt::{Debug, Display, Formatter},
rc::Rc, rc::Rc,
}, },
uapi::c,
}; };
linear_ids!(ConnectorIds, ConnectorId); linear_ids!(ConnectorIds, ConnectorId);
linear_ids!(InputDeviceIds, InputDeviceId); linear_ids!(InputDeviceIds, InputDeviceId);
linear_ids!(DrmDeviceIds, DrmDeviceId);
pub trait Backend { pub trait Backend {
fn run(self: Rc<Self>) -> SpawnedFuture<Result<(), Box<dyn Error>>>; fn run(self: Rc<Self>) -> SpawnedFuture<Result<(), Box<dyn Error>>>;
@ -77,6 +79,7 @@ pub trait Connector {
fn event(&self) -> Option<ConnectorEvent>; fn event(&self) -> Option<ConnectorEvent>;
fn on_change(&self, cb: Rc<dyn Fn()>); fn on_change(&self, cb: Rc<dyn Fn()>);
fn damage(&self); fn damage(&self);
fn drm_dev(&self) -> Option<DrmDeviceId>;
} }
#[derive(Debug)] #[derive(Debug)]
@ -121,6 +124,7 @@ pub enum InputDeviceAccelProfile {
} }
pub enum BackendEvent { pub enum BackendEvent {
NewDrmDevice(Rc<dyn BackendDrmDevice>),
NewConnector(Rc<dyn Connector>), NewConnector(Rc<dyn Connector>),
NewInputDevice(Rc<dyn InputDevice>), NewInputDevice(Rc<dyn InputDevice>),
} }
@ -163,3 +167,15 @@ pub enum InputEvent {
AxisDiscrete(i32, ScrollAxis), AxisDiscrete(i32, ScrollAxis),
Frame, Frame,
} }
pub enum DrmEvent {
#[allow(dead_code)]
Removed,
}
pub trait BackendDrmDevice {
fn id(&self) -> DrmDeviceId;
fn event(&self) -> Option<DrmEvent>;
fn on_change(&self, cb: Rc<dyn Fn()>);
fn dev_t(&self) -> c::dev_t;
}

View file

@ -1,7 +1,9 @@
use { use {
crate::{ crate::{
async_engine::SpawnedFuture, async_engine::SpawnedFuture,
backend::{Backend, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId}, backend::{
Backend, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId, DrmDeviceId,
},
video::drm::ConnectorType, video::drm::ConnectorType,
}, },
std::{any::Any, error::Error, rc::Rc}, std::{any::Any, error::Error, rc::Rc},
@ -46,4 +48,8 @@ impl Connector for DummyOutput {
fn damage(&self) { fn damage(&self) {
// nothing // nothing
} }
fn drm_dev(&self) -> Option<DrmDeviceId> {
None
}
} }

View file

@ -111,8 +111,6 @@ pub enum MetalError {
DeviceResumeSignalHandler(#[source] DbusError), DeviceResumeSignalHandler(#[source] DbusError),
} }
linear_ids!(DrmIds, DrmId);
pub struct MetalBackend { pub struct MetalBackend {
state: Rc<State>, state: Rc<State>,
udev: Rc<Udev>, udev: Rc<Udev>,
@ -122,7 +120,6 @@ pub struct MetalBackend {
libinput_fd: AsyncFd, libinput_fd: AsyncFd,
device_holder: Rc<DeviceHolder>, device_holder: Rc<DeviceHolder>,
session: Session, session: Session,
drm_ids: DrmIds,
pause_handler: Cell<Option<SignalHandler>>, pause_handler: Cell<Option<SignalHandler>>,
resume_handler: Cell<Option<SignalHandler>>, resume_handler: Cell<Option<SignalHandler>>,
ctx: CloneCell<Option<Rc<MetalRenderContext>>>, ctx: CloneCell<Option<Rc<MetalRenderContext>>>,
@ -252,7 +249,6 @@ pub async fn create(state: &Rc<State>) -> Result<Rc<MetalBackend>, MetalError> {
libinput_fd, libinput_fd,
device_holder, device_holder,
session, session,
drm_ids: Default::default(),
pause_handler: Default::default(), pause_handler: Default::default(),
resume_handler: Default::default(), resume_handler: Default::default(),
ctx: Default::default(), ctx: Default::default(),

View file

@ -183,7 +183,7 @@ impl MetalBackend {
} }
let devnum = dev.devnum(); let devnum = dev.devnum();
let devnode = dev.devnode()?; let devnode = dev.devnode()?;
let id = self.drm_ids.next(); let id = self.state.drm_dev_ids.next();
log::info!("Device added: {}", devnode.to_bytes().as_bstr()); log::info!("Device added: {}", devnode.to_bytes().as_bstr());
let dev = PendingDrmDevice { let dev = PendingDrmDevice {
id, id,

View file

@ -2,9 +2,10 @@ use {
crate::{ crate::{
async_engine::{AsyncFd, Phase, SpawnedFuture}, async_engine::{AsyncFd, Phase, SpawnedFuture},
backend::{ backend::{
BackendEvent, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId, MonitorInfo, BackendDrmDevice, BackendEvent, Connector, ConnectorEvent, ConnectorId,
ConnectorKernelId, DrmDeviceId, MonitorInfo,
}, },
backends::metal::{DrmId, MetalBackend, MetalError}, backends::metal::{MetalBackend, MetalError},
edid::Descriptor, edid::Descriptor,
format::{Format, XRGB8888}, format::{Format, XRGB8888},
ifs::wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC}, ifs::wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC},
@ -35,11 +36,11 @@ use {
fmt::{Debug, Formatter}, fmt::{Debug, Formatter},
rc::Rc, rc::Rc,
}, },
uapi::c, uapi::{c, c::dev_t},
}; };
pub struct PendingDrmDevice { pub struct PendingDrmDevice {
pub id: DrmId, pub id: DrmDeviceId,
pub devnum: c::dev_t, pub devnum: c::dev_t,
pub devnode: CString, pub devnode: CString,
} }
@ -51,7 +52,7 @@ pub struct MetalRenderContext {
#[derive(Debug)] #[derive(Debug)]
pub struct MetalDrmDeviceStatic { pub struct MetalDrmDeviceStatic {
pub id: DrmId, pub id: DrmDeviceId,
pub devnum: c::dev_t, pub devnum: c::dev_t,
pub devnode: CString, pub devnode: CString,
pub master: Rc<DrmMaster>, pub master: Rc<DrmMaster>,
@ -67,6 +68,24 @@ pub struct MetalDrmDeviceStatic {
pub handle_events: HandleEvents, pub handle_events: HandleEvents,
} }
impl BackendDrmDevice for MetalDrmDeviceStatic {
fn id(&self) -> DrmDeviceId {
self.id
}
fn event(&self) -> Option<crate::backend::DrmEvent> {
None
}
fn on_change(&self, _cb: Rc<dyn Fn()>) {
// nothing
}
fn dev_t(&self) -> dev_t {
self.devnum
}
}
pub struct HandleEvents { pub struct HandleEvents {
pub handle_events: Cell<Option<SpawnedFuture<()>>>, pub handle_events: Cell<Option<SpawnedFuture<()>>>,
} }
@ -249,6 +268,10 @@ impl Connector for MetalConnector {
self.schedule_present(); self.schedule_present();
} }
} }
fn drm_dev(&self) -> Option<DrmDeviceId> {
Some(self.dev.id)
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -760,13 +783,17 @@ impl MetalBackend {
let (connectors, futures) = get_connectors(&self, &dev, &resources.connectors)?; let (connectors, futures) = get_connectors(&self, &dev, &resources.connectors)?;
let slf = Rc::new(MetalDrmDevice { let slf = Rc::new(MetalDrmDevice {
dev, dev: dev.clone(),
connectors, connectors,
futures, futures,
}); });
self.init_drm_device(&slf)?; self.init_drm_device(&slf)?;
self.state
.backend_events
.push(BackendEvent::NewDrmDevice(dev.clone()));
for connector in slf.connectors.values() { for connector in slf.connectors.values() {
self.state self.state
.backend_events .backend_events

View file

@ -3,8 +3,9 @@ use {
async_engine::{Phase, SpawnedFuture}, async_engine::{Phase, SpawnedFuture},
backend::{ backend::{
AxisSource, Backend, BackendEvent, Connector, ConnectorEvent, ConnectorId, AxisSource, Backend, BackendEvent, Connector, ConnectorEvent, ConnectorId,
ConnectorKernelId, InputDevice, InputDeviceAccelProfile, InputDeviceCapability, ConnectorKernelId, DrmDeviceId, InputDevice, InputDeviceAccelProfile,
InputDeviceId, InputEvent, KeyState, Mode, MonitorInfo, ScrollAxis, TransformMatrix, InputDeviceCapability, InputDeviceId, InputEvent, KeyState, Mode, MonitorInfo,
ScrollAxis, TransformMatrix,
}, },
fixed::Fixed, fixed::Fixed,
format::XRGB8888, format::XRGB8888,
@ -948,6 +949,10 @@ impl Connector for XOutput {
fn damage(&self) { fn damage(&self) {
// nothing // nothing
} }
fn drm_dev(&self) -> Option<DrmDeviceId> {
None
}
} }
struct XSeat { struct XSeat {

View file

@ -157,6 +157,7 @@ fn start_compositor2(
logger, logger,
connectors: Default::default(), connectors: Default::default(),
outputs: Default::default(), outputs: Default::default(),
drm_devs: Default::default(),
status: Default::default(), status: Default::default(),
idle: IdleState { idle: IdleState {
input: Default::default(), input: Default::default(),
@ -180,6 +181,7 @@ fn start_compositor2(
config_file_id: NumCell::new(1), config_file_id: NumCell::new(1),
tracker: Default::default(), tracker: Default::default(),
data_offer_ids: Default::default(), data_offer_ids: Default::default(),
drm_dev_ids: Default::default(),
}); });
state.tracker.register(ClientId::from_raw(0)); state.tracker.register(ClientId::from_raw(0));
create_dummy_output(&state); create_dummy_output(&state);
@ -350,6 +352,7 @@ fn create_dummy_output(state: &Rc<State>) {
handler: Cell::new(None), handler: Cell::new(None),
connected: Cell::new(true), connected: Cell::new(true),
name: "Dummy".to_string(), name: "Dummy".to_string(),
drm_dev: None,
}), }),
0, 0,
&backend::Mode { &backend::Mode {

View file

@ -4,7 +4,7 @@ mod handler;
use crate::it::test_config::TEST_CONFIG_ENTRY; use crate::it::test_config::TEST_CONFIG_ENTRY;
use { use {
crate::{ crate::{
backend::{ConnectorId, InputDeviceId}, backend::{ConnectorId, DrmDeviceId, InputDeviceId},
config::handler::ConfigProxyHandler, config::handler::ConfigProxyHandler,
ifs::wl_seat::SeatId, ifs::wl_seat::SeatId,
state::State, state::State,
@ -19,7 +19,7 @@ use {
ipc::{InitMessage, ServerMessage, V1InitMessage}, ipc::{InitMessage, ServerMessage, V1InitMessage},
ConfigEntry, VERSION, ConfigEntry, VERSION,
}, },
drm::Connector, drm::{Connector, DrmDevice},
input::{InputDevice, Seat}, input::{InputDevice, Seat},
keyboard::ModifiedKeySym, keyboard::ModifiedKeySym,
}, },
@ -70,6 +70,18 @@ impl ConfigProxy {
}); });
} }
pub fn new_drm_dev(&self, dev: DrmDeviceId) {
self.send(&ServerMessage::NewDrmDev {
device: DrmDevice(dev.raw() as _),
});
}
pub fn del_drm_dev(&self, dev: DrmDeviceId) {
self.send(&ServerMessage::DelDrmDev {
device: DrmDevice(dev.raw() as _),
});
}
pub fn new_connector(&self, connector: ConnectorId) { pub fn new_connector(&self, connector: ConnectorId) {
self.send(&ServerMessage::NewConnector { self.send(&ServerMessage::NewConnector {
device: Connector(connector.raw() as _), device: Connector(connector.raw() as _),

View file

@ -2,12 +2,13 @@ use {
crate::{ crate::{
async_engine::{AsyncError, SpawnedFuture, Timer}, async_engine::{AsyncError, SpawnedFuture, Timer},
backend::{ backend::{
self, ConnectorId, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId, self, ConnectorId, DrmDeviceId, InputDeviceAccelProfile, InputDeviceCapability,
InputDeviceId,
}, },
compositor::MAX_EXTENTS, compositor::MAX_EXTENTS,
config::ConfigProxy, config::ConfigProxy,
ifs::wl_seat::{SeatId, WlSeatGlobal}, ifs::wl_seat::{SeatId, WlSeatGlobal},
state::{ConnectorData, DeviceHandlerData, OutputData, State}, state::{ConnectorData, DeviceHandlerData, DrmDevData, OutputData, State},
tree::{ContainerNode, ContainerSplit, FloatNode, Node, NodeVisitorBase}, tree::{ContainerNode, ContainerSplit, FloatNode, Node, NodeVisitorBase},
utils::{ utils::{
copyhashmap::CopyHashMap, debug_fn::debug_fn, errorfmt::ErrorFmt, numcell::NumCell, copyhashmap::CopyHashMap, debug_fn::debug_fn, errorfmt::ErrorFmt, numcell::NumCell,
@ -21,7 +22,7 @@ use {
bincode_ops, bincode_ops,
ipc::{ClientMessage, Response, ServerMessage}, ipc::{ClientMessage, Response, ServerMessage},
}, },
drm::Connector, drm::{Connector, DrmDevice},
input::{ input::{
acceleration::{AccelProfile, ACCEL_PROFILE_ADAPTIVE, ACCEL_PROFILE_FLAT}, acceleration::{AccelProfile, ACCEL_PROFILE_ADAPTIVE, ACCEL_PROFILE_FLAT},
capability::{ capability::{
@ -152,6 +153,53 @@ impl ConfigProxyHandler {
res res
} }
fn handle_get_drm_device_connectors(&self, dev: DrmDevice) -> Result<(), CphError> {
let dev = self.get_drm_device(dev)?;
let mut connectors = vec![];
for c in dev.connectors.lock().values() {
connectors.push(Connector(c.connector.id().raw() as _));
}
self.respond(Response::GetDeviceConnectors { connectors });
Ok(())
}
fn handle_get_drm_device_syspath(&self, dev: DrmDevice) -> Result<(), CphError> {
let dev = self.get_drm_device(dev)?;
let syspath = dev.syspath.clone().unwrap_or_default();
self.respond(Response::GetDrmDeviceSyspath { syspath });
Ok(())
}
fn handle_get_drm_device_vendor(&self, dev: DrmDevice) -> Result<(), CphError> {
let dev = self.get_drm_device(dev)?;
let vendor = dev.vendor.clone().unwrap_or_default();
self.respond(Response::GetDrmDeviceVendor { vendor });
Ok(())
}
fn handle_get_drm_devices(&self) {
let devs = self.state.drm_devs.lock();
let mut res = vec![];
for dev in devs.values() {
res.push(DrmDevice(dev.dev.id().raw() as _));
}
self.respond(Response::GetDrmDevices { devices: res });
}
fn handle_get_drm_device_model(&self, dev: DrmDevice) -> Result<(), CphError> {
let dev = self.get_drm_device(dev)?;
let model = dev.model.clone().unwrap_or_default();
self.respond(Response::GetDrmDeviceModel { model });
Ok(())
}
fn handle_get_drm_device_pci_id(&self, dev: DrmDevice) -> Result<(), CphError> {
let dev = self.get_drm_device(dev)?;
let pci_id = dev.pci_id.unwrap_or_default();
self.respond(Response::GetDrmDevicePciId { pci_id });
Ok(())
}
fn handle_reload(&self) { fn handle_reload(&self) {
log::info!("Reloading config"); log::info!("Reloading config");
let config = match ConfigProxy::from_config_dir(&self.state) { let config = match ConfigProxy::from_config_dir(&self.state) {
@ -357,6 +405,13 @@ impl ConfigProxyHandler {
} }
} }
fn get_drm_device(&self, dev: DrmDevice) -> Result<Rc<DrmDevData>, CphError> {
match self.state.drm_devs.get(&DrmDeviceId::from_raw(dev.0 as _)) {
Some(dev) => Ok(dev),
_ => Err(CphError::DrmDeviceDoesNotExist(dev)),
}
}
fn get_seat(&self, seat: Seat) -> Result<Rc<WlSeatGlobal>, CphError> { fn get_seat(&self, seat: Seat) -> Result<Rc<WlSeatGlobal>, CphError> {
let seats = self.state.globals.seats.lock(); let seats = self.state.globals.seats.lock();
for seat_global in seats.values() { for seat_global in seats.values() {
@ -944,6 +999,22 @@ impl ConfigProxyHandler {
self.handle_get_fullscreen(seat).wrn("get_fullscreen")? self.handle_get_fullscreen(seat).wrn("get_fullscreen")?
} }
ClientMessage::Reload => self.handle_reload(), ClientMessage::Reload => self.handle_reload(),
ClientMessage::GetDeviceConnectors { device } => self
.handle_get_drm_device_connectors(device)
.wrn("get_device_connectors")?,
ClientMessage::GetDrmDeviceSyspath { device } => self
.handle_get_drm_device_syspath(device)
.wrn("get_drm_device_syspath")?,
ClientMessage::GetDrmDeviceVendor { device } => self
.handle_get_drm_device_vendor(device)
.wrn("get_drm_device_vendor")?,
ClientMessage::GetDrmDeviceModel { device } => self
.handle_get_drm_device_model(device)
.wrn("get_drm_device_model")?,
ClientMessage::GetDrmDevices => self.handle_get_drm_devices(),
ClientMessage::GetDrmDevicePciId { device } => self
.handle_get_drm_device_pci_id(device)
.wrn("get_drm_device_pci_id")?,
} }
Ok(()) Ok(())
} }
@ -985,6 +1056,8 @@ enum CphError {
KeymapDoesNotExist(Keymap), KeymapDoesNotExist(Keymap),
#[error("Seat {0:?} does not exist")] #[error("Seat {0:?} does not exist")]
SeatDoesNotExist(Seat), SeatDoesNotExist(Seat),
#[error("DRM device {0:?} does not exist")]
DrmDeviceDoesNotExist(DrmDevice),
#[error("Workspace {0:?} does not exist")] #[error("Workspace {0:?} does not exist")]
WorkspaceDoesNotExist(Workspace), WorkspaceDoesNotExist(Workspace),
#[error("Keyboard {0:?} does not exist")] #[error("Keyboard {0:?} does not exist")]

View file

@ -3,8 +3,9 @@ use {
async_engine::SpawnedFuture, async_engine::SpawnedFuture,
backend::{ backend::{
AxisSource, Backend, BackendEvent, Connector, ConnectorEvent, ConnectorId, AxisSource, Backend, BackendEvent, Connector, ConnectorEvent, ConnectorId,
ConnectorKernelId, InputDevice, InputDeviceAccelProfile, InputDeviceCapability, ConnectorKernelId, DrmDeviceId, InputDevice, InputDeviceAccelProfile,
InputDeviceId, InputEvent, KeyState, Mode, MonitorInfo, ScrollAxis, TransformMatrix, InputDeviceCapability, InputDeviceId, InputEvent, KeyState, Mode, MonitorInfo,
ScrollAxis, TransformMatrix,
}, },
compositor::TestFuture, compositor::TestFuture,
fixed::Fixed, fixed::Fixed,
@ -241,6 +242,10 @@ impl Connector for TestConnector {
fn damage(&self) { fn damage(&self) {
// nothing // nothing
} }
fn drm_dev(&self) -> Option<DrmDeviceId> {
None
}
} }
pub struct TestMouseClick { pub struct TestMouseClick {

View file

@ -102,6 +102,8 @@ unsafe extern "C" fn handle_msg(data: *const u8, msg: *const u8, size: usize) {
ServerMessage::TimerExpired { .. } => {} ServerMessage::TimerExpired { .. } => {}
ServerMessage::GraphicsInitialized => tc.graphics_initialized.set(true), ServerMessage::GraphicsInitialized => tc.graphics_initialized.set(true),
ServerMessage::Clear => tc.clear(), ServerMessage::Clear => tc.clear(),
ServerMessage::NewDrmDev { .. } => {}
ServerMessage::DelDrmDev { .. } => {}
} }
} }

View file

@ -3,8 +3,8 @@ use {
acceptor::Acceptor, acceptor::Acceptor,
async_engine::{AsyncEngine, SpawnedFuture}, async_engine::{AsyncEngine, SpawnedFuture},
backend::{ backend::{
Backend, BackendEvent, Connector, ConnectorId, ConnectorIds, InputDevice, Backend, BackendDrmDevice, BackendEvent, Connector, ConnectorId, ConnectorIds,
InputDeviceId, InputDeviceIds, MonitorInfo, DrmDeviceId, DrmDeviceIds, InputDevice, InputDeviceId, InputDeviceIds, MonitorInfo,
}, },
backends::dummy::DummyBackend, backends::dummy::DummyBackend,
cli::RunArgs, cli::RunArgs,
@ -43,7 +43,7 @@ use {
xwayland::{self, XWaylandEvent}, xwayland::{self, XWaylandEvent},
}, },
ahash::AHashMap, ahash::AHashMap,
jay_config::Direction, jay_config::{Direction, PciId},
std::{ std::{
cell::{Cell, RefCell}, cell::{Cell, RefCell},
fmt::{Debug, Formatter}, fmt::{Debug, Formatter},
@ -71,6 +71,7 @@ pub struct State {
pub clients: Clients, pub clients: Clients,
pub globals: Globals, pub globals: Globals,
pub connector_ids: ConnectorIds, pub connector_ids: ConnectorIds,
pub drm_dev_ids: DrmDeviceIds,
pub seat_ids: SeatIds, pub seat_ids: SeatIds,
pub idle_inhibitor_ids: IdleInhibitorIds, pub idle_inhibitor_ids: IdleInhibitorIds,
pub input_device_ids: InputDeviceIds, pub input_device_ids: InputDeviceIds,
@ -95,6 +96,7 @@ pub struct State {
pub logger: Option<Arc<Logger>>, pub logger: Option<Arc<Logger>>,
pub connectors: CopyHashMap<ConnectorId, Rc<ConnectorData>>, pub connectors: CopyHashMap<ConnectorId, Rc<ConnectorData>>,
pub outputs: CopyHashMap<ConnectorId, Rc<OutputData>>, pub outputs: CopyHashMap<ConnectorId, Rc<OutputData>>,
pub drm_devs: CopyHashMap<DrmDeviceId, Rc<DrmDevData>>,
pub status: CloneCell<Rc<String>>, pub status: CloneCell<Rc<String>>,
pub idle: IdleState, pub idle: IdleState,
pub run_args: RunArgs, pub run_args: RunArgs,
@ -171,6 +173,7 @@ pub struct ConnectorData {
pub handler: Cell<Option<SpawnedFuture<()>>>, pub handler: Cell<Option<SpawnedFuture<()>>>,
pub connected: Cell<bool>, pub connected: Cell<bool>,
pub name: String, pub name: String,
pub drm_dev: Option<Rc<DrmDevData>>,
} }
pub struct OutputData { pub struct OutputData {
@ -179,6 +182,16 @@ pub struct OutputData {
pub node: Rc<OutputNode>, pub node: Rc<OutputNode>,
} }
pub struct DrmDevData {
pub dev: Rc<dyn BackendDrmDevice>,
pub handler: Cell<Option<SpawnedFuture<()>>>,
pub connectors: CopyHashMap<ConnectorId, Rc<ConnectorData>>,
pub syspath: Option<String>,
pub vendor: Option<String>,
pub model: Option<String>,
pub pci_id: Option<PciId>,
}
impl State { impl State {
pub fn set_render_ctx(&self, ctx: Option<&Rc<RenderContext>>) { pub fn set_render_ctx(&self, ctx: Option<&Rc<RenderContext>>) {
self.render_ctx.set(ctx.cloned()); self.render_ctx.set(ctx.cloned());
@ -486,6 +499,9 @@ impl State {
self.xwayland.handler.borrow_mut().take(); self.xwayland.handler.borrow_mut().take();
self.xwayland.queue.clear(); self.xwayland.queue.clear();
self.idle.inhibitors.clear(); self.idle.inhibitors.clear();
for (_, drm_dev) in self.drm_devs.lock().drain() {
drm_dev.handler.take();
}
for (_, connector) in self.connectors.lock().drain() { for (_, connector) in self.connectors.lock().drain() {
connector.handler.take(); connector.handler.take();
} }

View file

@ -1,5 +1,6 @@
mod backend; mod backend;
mod connector; mod connector;
mod drmdev;
mod idle; mod idle;
mod input_device; mod input_device;
mod slow_clients; mod slow_clients;

View file

@ -1,4 +1,5 @@
use { use {
super::drmdev,
crate::{ crate::{
backend::BackendEvent, backend::BackendEvent,
state::State, state::State,
@ -23,6 +24,7 @@ impl BackendEventHandler {
match event { match event {
BackendEvent::NewConnector(connector) => connector::handle(&self.state, &connector), BackendEvent::NewConnector(connector) => connector::handle(&self.state, &connector),
BackendEvent::NewInputDevice(s) => input_device::handle(&self.state, s), BackendEvent::NewInputDevice(s) => input_device::handle(&self.state, s),
BackendEvent::NewDrmDevice(d) => drmdev::handle(&self.state, d),
} }
} }
} }

View file

@ -13,13 +13,24 @@ use {
}; };
pub fn handle(state: &Rc<State>, connector: &Rc<dyn Connector>) { pub fn handle(state: &Rc<State>, connector: &Rc<dyn Connector>) {
let mut drm_dev = None;
if let Some(dev_id) = connector.drm_dev() {
drm_dev = match state.drm_devs.get(&dev_id) {
Some(dev) => Some(dev),
_ => panic!("connector's drm device does not exist"),
};
}
let id = connector.id(); let id = connector.id();
let data = Rc::new(ConnectorData { let data = Rc::new(ConnectorData {
connector: connector.clone(), connector: connector.clone(),
handler: Default::default(), handler: Default::default(),
connected: Cell::new(false), connected: Cell::new(false),
name: connector.kernel_id().to_string(), name: connector.kernel_id().to_string(),
drm_dev: drm_dev.clone(),
}); });
if let Some(dev) = drm_dev {
dev.connectors.set(id, data.clone());
}
let oh = ConnectorHandler { let oh = ConnectorHandler {
id, id,
state: state.clone(), state: state.clone(),
@ -150,5 +161,8 @@ impl ConnectorHandler {
self.state.root.outputs.remove(&self.id); self.state.root.outputs.remove(&self.id);
self.data.connected.set(false); self.data.connected.set(false);
self.state.outputs.remove(&self.id); self.state.outputs.remove(&self.id);
if let Some(dev) = &self.data.drm_dev {
dev.connectors.remove(&self.id);
}
} }
} }

120
src/tasks/drmdev.rs Normal file
View file

@ -0,0 +1,120 @@
use {
crate::{
backend::{BackendDrmDevice, DrmDeviceId, DrmEvent},
state::{DrmDevData, State},
udev::{Udev, UdevDeviceType},
utils::{asyncevent::AsyncEvent, errorfmt::ErrorFmt},
},
jay_config::PciId,
std::{cell::Cell, rc::Rc},
};
pub fn handle(state: &Rc<State>, dev: Rc<dyn BackendDrmDevice>) {
let id = dev.id();
let mut syspath = None;
let mut vendor = None;
let mut model = None;
let mut pci_id = None;
'properties: {
let udev = match Udev::new() {
Ok(udev) => Rc::new(udev),
Err(e) => {
log::error!("Could not create a udev instance: {}", e);
break 'properties;
}
};
let odev = match udev.create_device_from_devnum(UdevDeviceType::Character, dev.dev_t()) {
Ok(dev) => dev,
Err(e) => {
log::error!("{}", ErrorFmt(e));
break 'properties;
}
};
let dev = match odev.parent() {
Ok(dev) => dev,
Err(e) => {
log::error!("{}", ErrorFmt(e));
break 'properties;
}
};
syspath = dev.syspath().map(|s| s.to_string_lossy().into_owned());
vendor = dev.vendor().map(|s| s.to_string_lossy().into_owned());
model = dev.model().map(|s| s.to_string_lossy().into_owned());
'get_pci_id: {
let id = match dev.pci_id() {
Some(id) => id,
_ => break 'get_pci_id,
};
let id = id.to_string_lossy();
let colon = match id.find(':') {
Some(pos) => pos,
_ => break 'get_pci_id,
};
let vendor = &id[..colon];
let model = &id[colon + 1..];
let vendor = match u32::from_str_radix(vendor, 16) {
Ok(v) => v,
_ => break 'get_pci_id,
};
let model = match u32::from_str_radix(model, 16) {
Ok(v) => v,
_ => break 'get_pci_id,
};
pci_id = Some(PciId { vendor, model });
}
}
let data = Rc::new(DrmDevData {
dev: dev.clone(),
handler: Cell::new(None),
connectors: Default::default(),
syspath,
vendor,
model,
pci_id,
});
let oh = DrvDevHandler {
id,
state: state.clone(),
data: data.clone(),
};
let future = state.eng.spawn(oh.handle());
data.handler.set(Some(future));
if state.drm_devs.set(id, data).is_some() {
panic!("Drm device id has been reused");
}
}
struct DrvDevHandler {
id: DrmDeviceId,
state: Rc<State>,
data: Rc<DrmDevData>,
}
impl DrvDevHandler {
async fn handle(self) {
let ae = Rc::new(AsyncEvent::default());
{
let ae = ae.clone();
self.data.dev.on_change(Rc::new(move || ae.trigger()));
}
if let Some(config) = self.state.config.get() {
config.new_drm_dev(self.id);
}
'outer: loop {
while let Some(event) = self.data.dev.event() {
match event {
DrmEvent::Removed => break 'outer,
}
}
ae.triggered().await;
}
if !self.data.connectors.is_empty() {
panic!("DRM device removed before its connectors");
}
if let Some(config) = self.state.config.get() {
config.del_drm_dev(self.id);
}
self.data.handler.set(None);
self.state.drm_devs.remove(&self.id);
}
}

View file

@ -1,7 +1,8 @@
use { use {
crate::utils::oserror::OsError,
std::{ffi::CStr, marker::PhantomData, ptr, rc::Rc}, std::{ffi::CStr, marker::PhantomData, ptr, rc::Rc},
thiserror::Error, thiserror::Error,
uapi::{c, Errno, IntoUstr}, uapi::{c, ustr, Errno, IntoUstr, Ustr},
}; };
#[link(name = "udev")] #[link(name = "udev")]
@ -42,36 +43,52 @@ extern "C" {
fn udev_device_new_from_syspath(udev: *mut udev, syspath: *const c::c_char) fn udev_device_new_from_syspath(udev: *mut udev, syspath: *const c::c_char)
-> *mut udev_device; -> *mut udev_device;
fn udev_device_ref(udev_device: *mut udev_device) -> *mut udev_device;
fn udev_device_unref(udev_device: *mut udev_device) -> *mut udev_device; fn udev_device_unref(udev_device: *mut udev_device) -> *mut udev_device;
fn udev_device_get_sysname(udev_device: *mut udev_device) -> *const c::c_char; fn udev_device_get_sysname(udev_device: *mut udev_device) -> *const c::c_char;
fn udev_device_get_is_initialized(udev_device: *mut udev_device) -> c::c_int; fn udev_device_get_is_initialized(udev_device: *mut udev_device) -> c::c_int;
fn udev_device_get_devnode(udev_device: *mut udev_device) -> *const c::c_char; fn udev_device_get_devnode(udev_device: *mut udev_device) -> *const c::c_char;
fn udev_device_get_syspath(udev_device: *mut udev_device) -> *const c::c_char;
fn udev_device_get_devtype(udev_device: *mut udev_device) -> *const c::c_char; fn udev_device_get_devtype(udev_device: *mut udev_device) -> *const c::c_char;
fn udev_device_get_devnum(udev_device: *mut udev_device) -> c::dev_t; fn udev_device_get_devnum(udev_device: *mut udev_device) -> c::dev_t;
fn udev_device_get_action(udev_device: *mut udev_device) -> *const c::c_char; fn udev_device_get_action(udev_device: *mut udev_device) -> *const c::c_char;
fn udev_device_get_subsystem(udev_device: *mut udev_device) -> *const c::c_char; fn udev_device_get_subsystem(udev_device: *mut udev_device) -> *const c::c_char;
fn udev_device_new_from_devnum(
udev: *mut udev,
ty: c::c_char,
devnum: c::dev_t,
) -> *mut udev_device;
fn udev_device_get_parent(udev_device: *mut udev_device) -> *mut udev_device;
fn udev_device_get_property_value(
udev_device: *mut udev_device,
key: *const c::c_char,
) -> *const c::c_char;
} }
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum UdevError { pub enum UdevError {
#[error("Could not create a new udev instance")] #[error("Could not create a new udev instance")]
New(#[source] crate::utils::oserror::OsError), New(#[source] OsError),
#[error("Could not create a new udev_monitor instance")] #[error("Could not create a new udev_monitor instance")]
NewMonitor(#[source] crate::utils::oserror::OsError), NewMonitor(#[source] OsError),
#[error("Could not create a new udev_enumerate instance")] #[error("Could not create a new udev_enumerate instance")]
NewEnumerate(#[source] crate::utils::oserror::OsError), NewEnumerate(#[source] OsError),
#[error("Could not enable receiving on a udev_monitor")] #[error("Could not enable receiving on a udev_monitor")]
EnableReceiving(#[source] crate::utils::oserror::OsError), EnableReceiving(#[source] OsError),
#[error("Could not add a match rule to a udev_monitor")] #[error("Could not add a match rule to a udev_monitor")]
MonitorAddMatch(#[source] crate::utils::oserror::OsError), MonitorAddMatch(#[source] OsError),
#[error("Could not add a match rule to a udev_enumerate")] #[error("Could not add a match rule to a udev_enumerate")]
EnumerateAddMatch(#[source] crate::utils::oserror::OsError), EnumerateAddMatch(#[source] OsError),
#[error("Could not list devices of a udev_enumerate")] #[error("Could not list devices of a udev_enumerate")]
EnumerateGetListEntry(#[source] crate::utils::oserror::OsError), EnumerateGetListEntry(#[source] OsError),
#[error("Could not scan devices of a udev_enumerate")] #[error("Could not scan devices of a udev_enumerate")]
ScanDevices(#[source] crate::utils::oserror::OsError), ScanDevices(#[source] OsError),
#[error("Could not create a udev_device from a syspath")] #[error("Could not create a udev_device from a syspath")]
DeviceFromSyspath(#[source] crate::utils::oserror::OsError), DeviceFromSyspath(#[source] OsError),
#[error("Could not create a udev_device from a devnum")]
DeviceFromDevnum(#[source] OsError),
#[error("Could not get the device parent")]
DeviceParent(#[source] OsError),
} }
pub struct Udev { pub struct Udev {
@ -94,10 +111,16 @@ pub struct UdevListEntry<'a> {
} }
pub struct UdevDevice { pub struct UdevDevice {
_udev: Rc<Udev>, udev: Rc<Udev>,
device: *mut udev_device, device: *mut udev_device,
} }
pub enum UdevDeviceType {
Character,
#[allow(dead_code)]
Block,
}
impl Udev { impl Udev {
pub fn new() -> Result<Self, UdevError> { pub fn new() -> Result<Self, UdevError> {
let res = unsafe { udev_new() }; let res = unsafe { udev_new() };
@ -139,7 +162,26 @@ impl Udev {
return Err(UdevError::DeviceFromSyspath(Errno::default().into())); return Err(UdevError::DeviceFromSyspath(Errno::default().into()));
} }
Ok(UdevDevice { Ok(UdevDevice {
_udev: self.clone(), udev: self.clone(),
device: res,
})
}
pub fn create_device_from_devnum<'a>(
self: &Rc<Self>,
ty: UdevDeviceType,
devnum: c::dev_t,
) -> Result<UdevDevice, UdevError> {
let ty = match ty {
UdevDeviceType::Character => b'c',
UdevDeviceType::Block => b'b',
};
let res = unsafe { udev_device_new_from_devnum(self.udev, ty as _, devnum) };
if res.is_null() {
return Err(UdevError::DeviceFromDevnum(Errno::default().into()));
}
Ok(UdevDevice {
udev: self.clone(),
device: res, device: res,
}) })
} }
@ -197,7 +239,7 @@ impl UdevMonitor {
None None
} else { } else {
Some(UdevDevice { Some(UdevDevice {
_udev: self.udev.clone(), udev: self.udev.clone(),
device: res, device: res,
}) })
} }
@ -297,6 +339,7 @@ macro_rules! strfn {
impl UdevDevice { impl UdevDevice {
strfn!(sysname, udev_device_get_sysname); strfn!(sysname, udev_device_get_sysname);
strfn!(syspath, udev_device_get_syspath);
strfn!(devnode, udev_device_get_devnode); strfn!(devnode, udev_device_get_devnode);
strfn!(devtype, udev_device_get_devtype); strfn!(devtype, udev_device_get_devtype);
strfn!(action, udev_device_get_action); strfn!(action, udev_device_get_action);
@ -306,10 +349,45 @@ impl UdevDevice {
unsafe { udev_device_get_devnum(self.device) } unsafe { udev_device_get_devnum(self.device) }
} }
pub fn parent(&self) -> Result<UdevDevice, UdevError> {
let res = unsafe { udev_device_get_parent(self.device) };
if res.is_null() {
return Err(UdevError::DeviceParent(Errno::default().into()));
}
unsafe {
udev_device_ref(res);
}
Ok(UdevDevice {
udev: self.udev.clone(),
device: res,
})
}
#[allow(dead_code)] #[allow(dead_code)]
pub fn is_initialized(&self) -> bool { pub fn is_initialized(&self) -> bool {
unsafe { udev_device_get_is_initialized(self.device) != 0 } unsafe { udev_device_get_is_initialized(self.device) != 0 }
} }
fn get_property(&self, prop: &Ustr) -> Option<&CStr> {
let prop = unsafe { udev_device_get_property_value(self.device, prop.as_ptr()) };
if prop.is_null() {
None
} else {
unsafe { Some(CStr::from_ptr(prop)) }
}
}
pub fn vendor(&self) -> Option<&CStr> {
self.get_property(ustr!("ID_VENDOR_FROM_DATABASE"))
}
pub fn model(&self) -> Option<&CStr> {
self.get_property(ustr!("ID_MODEL_FROM_DATABASE"))
}
pub fn pci_id(&self) -> Option<&CStr> {
self.get_property(ustr!("PCI_ID"))
}
} }
impl Drop for UdevDevice { impl Drop for UdevDevice {

View file

@ -293,6 +293,7 @@ pub enum XWaylandEvent {
Activate(Rc<XwindowData>), Activate(Rc<XwindowData>),
ActivateRoot, ActivateRoot,
Close(Rc<XwindowData>), Close(Rc<XwindowData>),
#[allow(dead_code)]
SeatChanged, SeatChanged,
PrimarySelectionCancelSource(Rc<ZwpPrimarySelectionSourceV1>), PrimarySelectionCancelSource(Rc<ZwpPrimarySelectionSourceV1>),