config: tell the config about drm devices
This commit is contained in:
parent
99fcd63438
commit
e27cf29693
23 changed files with 581 additions and 50 deletions
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)]
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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() {}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 _),
|
||||||
|
|
|
||||||
|
|
@ -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")]
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 { .. } => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
22
src/state.rs
22
src/state.rs
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
120
src/tasks/drmdev.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
104
src/udev.rs
104
src/udev.rs
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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>),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue