1
0
Fork 0
forked from wry/wry

autocommit 2022-03-09 14:01:21 CET

This commit is contained in:
Julian Orth 2022-03-09 14:01:21 +01:00
parent aa0cb94143
commit 4df6b559b7
32 changed files with 1121 additions and 172 deletions

View file

@ -15,6 +15,9 @@ mod pixman;
#[path = "../src/xkbcommon/consts.rs"]
mod xkbcommon;
#[path = "../src/libinput/consts.rs"]
mod libinput;
fn get_target() -> repc::Target {
let rustc_target = env::var("TARGET").unwrap();
repc::TARGET_MAP
@ -193,6 +196,67 @@ fn write_egl_procs<W: Write>(f: &mut W) -> anyhow::Result<()> {
}
pub fn main() -> anyhow::Result<()> {
let mut f = open("libinput_tys.rs")?;
write_ty(
&mut f,
libinput::LIBINPUT_LOG_PRIORITY,
"libinput_log_priority",
)?;
write_ty(
&mut f,
libinput::LIBINPUT_DEVICE_CAPABILITY,
"libinput_device_capability",
)?;
write_ty(&mut f, libinput::LIBINPUT_KEY_STATE, "libinput_key_state")?;
write_ty(&mut f, libinput::LIBINPUT_LED, "libinput_led")?;
write_ty(
&mut f,
libinput::LIBINPUT_BUTTON_STATE,
"libinput_button_state",
)?;
write_ty(
&mut f,
libinput::LIBINPUT_POINTER_AXIS,
"libinput_pointer_axis",
)?;
write_ty(
&mut f,
libinput::LIBINPUT_POINTER_AXIS_SOURCE,
"libinput_pointer_axis_source",
)?;
write_ty(
&mut f,
libinput::LIBINPUT_TABLET_PAD_RING_AXIS_SOURCE,
"libinput_tablet_pad_ring_axis_source",
)?;
write_ty(
&mut f,
libinput::LIBINPUT_TABLET_PAD_STRIP_AXIS_SOURCE,
"libinput_tablet_pad_strip_axis_source",
)?;
write_ty(
&mut f,
libinput::LIBINPUT_TABLET_TOOL_TYPE,
"libinput_tablet_tool_type",
)?;
write_ty(
&mut f,
libinput::LIBINPUT_TABLET_TOOL_PROXIMITY_STATE,
"libinput_tablet_tool_proximity_state",
)?;
write_ty(
&mut f,
libinput::LIBINPUT_TABLET_TOOL_TIP_STATE,
"libinput_tablet_tool_tip_state",
)?;
write_ty(
&mut f,
libinput::LIBINPUT_SWITCH_STATE,
"libinput_switch_state",
)?;
write_ty(&mut f, libinput::LIBINPUT_SWITCH, "libinput_switch")?;
write_ty(&mut f, libinput::LIBINPUT_EVENT_TYPE, "libinput_event_type")?;
let mut f = open("pixman_tys.rs")?;
write_ty(&mut f, pixman::FORMATS, "PixmanFormat")?;
write_ty(&mut f, pixman::OPS, "PixmanOp")?;

View file

@ -13,23 +13,23 @@ pub enum AcceptorError {
#[error("XDG_RUNTIME_DIR ({0:?}) is too long to form a unix socket address")]
XrdTooLong(String),
#[error("Could not create a wayland socket")]
SocketFailed(#[source] std::io::Error),
SocketFailed(#[source] crate::utils::oserror::OsError),
#[error("Could not stat the existing socket")]
SocketStat(#[source] std::io::Error),
SocketStat(#[source] crate::utils::oserror::OsError),
#[error("Could not start listening for incoming connections")]
ListenFailed(#[source] std::io::Error),
ListenFailed(#[source] crate::utils::oserror::OsError),
#[error("Could not open the lock file")]
OpenLockFile(#[source] std::io::Error),
OpenLockFile(#[source] crate::utils::oserror::OsError),
#[error("Could not lock the lock file")]
LockLockFile(#[source] std::io::Error),
LockLockFile(#[source] crate::utils::oserror::OsError),
#[error("The wayland socket is in an error state")]
ErrorEvent,
#[error("Could not accept new connections")]
AcceptFailed(#[source] std::io::Error),
AcceptFailed(#[source] crate::utils::oserror::OsError),
#[error("Could not spawn an event handler for a new connection")]
SpawnFailed(#[source] ClientError),
#[error("Could not bind the socket to an address")]
BindFailed(#[source] std::io::Error),
BindFailed(#[source] crate::utils::oserror::OsError),
#[error("All wayland addresses in the range 0..1000 are already in use")]
AddressesInUse,
#[error("The event loop caused an error")]

View file

@ -3,8 +3,8 @@ use crate::event_loop::{EventLoop, EventLoopError};
use crate::utils::copyhashmap::CopyHashMap;
use crate::utils::numcell::NumCell;
use crate::wheel::{Wheel, WheelError};
pub use fd::{AsyncFd, FdStatus};
use fd::AsyncFdData;
pub use fd::{AsyncFd, FdStatus};
use queue::{DispatchQueue, Dispatcher};
use std::cell::{Cell, RefCell};
use std::future::Future;
@ -562,7 +562,10 @@ mod fd {
let res = self.el.modify(self.id, events);
if res.is_err() {
if let Err(e) = self.el.remove(self.id) {
log::error!("Fatal error: Cannot remove file descriptor from event loop: {:?}", e);
log::error!(
"Fatal error: Cannot remove file descriptor from event loop: {:?}",
e
);
self.el.stop();
}
}

View file

@ -1,12 +1,19 @@
mod input;
mod monitor;
use crate::async_engine::AsyncFd;
use crate::dbus::DbusError;
use crate::libinput::device::RegisteredDevice;
use crate::libinput::{LibInput, LibInputAdapter, LibInputError};
use crate::logind::{LogindError, Session};
use crate::{AsyncQueue, ErrorFmt, State, Udev};
use crate::udev::{UdevError, UdevMonitor};
use crate::utils::copyhashmap::CopyHashMap;
use crate::{AsyncQueue, CloneCell, ErrorFmt, NumCell, State, Udev};
use std::cell::{Cell, RefCell};
use std::ffi::{CStr, CString};
use std::rc::Rc;
use thiserror::Error;
use uapi::OwnedFd;
use crate::async_engine::{AsyncFd, FdStatus};
use crate::libinput::{LibInput, LibInputError};
use crate::udev::{UdevError, UdevMonitor};
use uapi::{c, OwnedFd};
#[derive(Debug, Error)]
pub enum MetalError {
@ -16,12 +23,14 @@ pub enum MetalError {
LogindSession(#[source] LogindError),
#[error("Could not take control of the logind session")]
TakeControl(#[source] LogindError),
#[error("Could not enumerate devices")]
Enumerate(#[source] Box<Self>),
#[error(transparent)]
Udev(#[from] UdevError),
#[error(transparent)]
LibInput(#[from] LibInputError),
#[error("Dupfd failed")]
Dup(#[source] std::io::Error),
Dup(#[source] crate::utils::oserror::OsError),
}
pub async fn run(state: Rc<State>) {
@ -30,6 +39,18 @@ pub async fn run(state: Rc<State>) {
}
}
struct MetalBackend {
state: Rc<State>,
udev: Rc<Udev>,
monitor: Rc<UdevMonitor>,
monitor_fd: AsyncFd,
libinput: Rc<LibInput>,
libinput_fd: AsyncFd,
device_holder: Rc<DeviceHolder>,
session: Session,
ids: NumCell<u64>,
}
async fn run_(state: Rc<State>) -> Result<(), MetalError> {
let socket = match state.dbus.system() {
Ok(s) => s,
@ -39,90 +60,83 @@ async fn run_(state: Rc<State>) -> Result<(), MetalError> {
Ok(s) => s,
Err(e) => return Err(MetalError::LogindSession(e)),
};
// if let Err(e) = session.take_control().await {
// return Err(MetalError::TakeControl(e));
// }
if let Err(e) = session.take_control().await {
return Err(MetalError::TakeControl(e));
}
let device_holder = Rc::new(DeviceHolder {
input_devices: Default::default(),
input_devices_: Default::default(),
});
let udev = Rc::new(Udev::new()?);
let monitor = Rc::new(udev.create_monitor()?);
monitor.add_match_subsystem_devtype(Some("input"), None)?;
monitor.enable_receiving()?;
let libinput = Rc::new(LibInput::new()?);
let libinput = Rc::new(LibInput::new(device_holder.clone())?);
let monitor_fd = match uapi::fcntl_dupfd_cloexec(monitor.fd(), 0) {
Ok(m) => state.eng.fd(&Rc::new(m)).unwrap(),
Err(e) => return Err(MetalError::Dup(e.into())),
};
let libinput_fd = match uapi::fcntl_dupfd_cloexec(libinput.fd(), 0) {
Ok(m) => state.eng.fd(&Rc::new(m)).unwrap(),
Err(e) => return Err(MetalError::Dup(e.into())),
};
let metal = Rc::new(MetalBackend {
state: state.clone(),
udev,
monitor,
monitor_fd,
libinput,
libinput_fd,
device_holder,
session,
ids: Default::default(),
});
let _monitor = state.eng.spawn(metal.clone().monitor_devices());
let mut queue = AsyncQueue::<String>::new();
let _events = state.eng.spawn(metal.clone().handle_libinput_events());
if let Err(e) = metal.enumerate_devices() {
return Err(MetalError::Enumerate(Box::new(e)));
}
let queue = AsyncQueue::<String>::new();
queue.pop().await;
Ok(())
// let libinput_fd = match uapi::fcntl_dupfd_cloexec(monitor.fd(), 0) {
// Ok(m) => m,
// Err(e) => Err(MetalError::Dup(e.into())),
// };
// let mut enumerate = udev.create_enumerate()?;
// enumerate.add_match_subsystem("input")?;
// enumerate.scan_devices()?;
// let mut entry_opt = enumerate.get_list_entry()?;
// while let Some(entry) = entry_opt {
// let device = udev.create_device_from_syspath(entry.name()?)?;
// if device.sysname()?.to_bytes().starts_with(b"event") {
// let devnode = device.devnode()?;
// }
// }
}
struct MetalBackend {
state: Rc<State>,
udev: Rc<Udev>,
monitor: Rc<UdevMonitor>,
monitor_fd: AsyncFd,
libinput: Rc<LibInput>,
libinput_fd: AsyncFd,
struct MetalDevice {
slot: usize,
device_id: u64,
devnum: c::dev_t,
fd: CloneCell<Option<Rc<OwnedFd>>>,
inputdev: Cell<Option<RegisteredDevice>>,
devnode: CString,
sysname: CString,
}
struct DeviceHolder {
input_devices: CopyHashMap<c::dev_t, Rc<MetalDevice>>,
input_devices_: RefCell<Vec<Option<Rc<MetalDevice>>>>,
}
impl LibInputAdapter for DeviceHolder {
fn open(&self, path: &CStr) -> Result<OwnedFd, LibInputError> {
let stat = match uapi::stat(path) {
Ok(s) => s,
Err(e) => return Err(LibInputError::Stat(e.into())),
};
match self.input_devices.get(&stat.st_rdev) {
Some(d) => match d.fd.get() {
Some(fd) => match uapi::fcntl_dupfd_cloexec(fd.raw(), 0) {
Ok(fd) => Ok(fd),
Err(e) => Err(LibInputError::DupFd(e.into())),
},
_ => Err(LibInputError::DeviceUnavailable),
},
_ => Err(LibInputError::DeviceUnavailable),
}
}
}
impl MetalBackend {
async fn monitor_devices(self: Rc<Self>) {
loop {
match self.monitor_fd.readable().await {
Err(e) => {
log::error!("Cannot wait for udev_monitor to become readable: {}", ErrorFmt(e));
break;
}
Ok(FdStatus::Err) => {
log::error!("udev_monitor fd is in an error state");
break;
}
_ => { },
}
while let Some(dev) = self.monitor.receive_device() {
log::info!("x {:?}", dev.devnode());
}
}
log::error!("Monitor task exited. Future hotplug events will be ignored.");
}
async fn handle_libinput_events(self: Rc<Self>) {
loop {
match self.libinput_fd.readable().await {
Err(e) => {
log::error!("Cannot wait for udev_monitor to become readable: {}", ErrorFmt(e));
break;
}
Ok(FdStatus::Err) => {
log::error!("udev_monitor fd is in an error state");
break;
}
_ => { },
}
self.libinput.fd()
}
log::error!("Monitor task exited. Future hotplug events will be ignored.");
fn id(&self) -> u64 {
self.ids.fetch_add(1)
}
}

View file

@ -0,0 +1,55 @@
use crate::async_engine::FdStatus;
use crate::libinput::consts::LIBINPUT_EVENT_KEYBOARD_KEY;
use crate::libinput::event::LibInputEvent;
use crate::metal::MetalBackend;
use crate::ErrorFmt;
use std::rc::Rc;
impl MetalBackend {
pub async fn handle_libinput_events(self: Rc<Self>) {
loop {
match self.libinput_fd.readable().await {
Err(e) => {
log::error!(
"Cannot wait for libinput fd to become readable: {}",
ErrorFmt(e)
);
break;
}
Ok(FdStatus::Err) => {
log::error!("libinput fd fd is in an error state");
break;
}
_ => {}
}
if let Err(e) = self.libinput.dispatch() {
log::error!("Could not dispatch libinput events: {}", ErrorFmt(e));
break;
}
while let Some(event) = self.libinput.event() {
self.handle_event(event);
}
}
log::error!("Libinput task exited. Future input events will be ignored.");
}
fn handle_event(self: &Rc<Self>, event: LibInputEvent) {
match event.ty() {
LIBINPUT_EVENT_KEYBOARD_KEY => self.handle_keyboard_event(event),
_ => {}
}
}
fn handle_keyboard_event(self: &Rc<Self>, event: LibInputEvent) {
let event = match event.keyboard_event() {
Some(event) => event,
_ => return,
};
log::info!(
"key: {}, state: {:?}, time: {}",
event.key(),
event.key_state(),
event.time_usec()
);
}
}

View file

@ -0,0 +1,131 @@
use crate::async_engine::FdStatus;
use crate::dbus::TRUE;
use crate::metal::{MetalBackend, MetalDevice, MetalError};
use crate::udev::UdevDevice;
use crate::ErrorFmt;
use std::rc::Rc;
impl MetalBackend {
pub async fn monitor_devices(self: Rc<Self>) {
loop {
match self.monitor_fd.readable().await {
Err(e) => {
log::error!(
"Cannot wait for udev_monitor to become readable: {}",
ErrorFmt(e)
);
break;
}
Ok(FdStatus::Err) => {
log::error!("udev_monitor fd is in an error state");
break;
}
_ => {}
}
while let Some(dev) = self.monitor.receive_device() {
log::info!("x {:?}", dev.devnode());
}
}
log::error!("Monitor task exited. Future hotplug events will be ignored.");
}
pub fn enumerate_devices(self: &Rc<Self>) -> Result<(), MetalError> {
let mut enumerate = self.udev.create_enumerate()?;
enumerate.add_match_subsystem("input")?;
enumerate.scan_devices()?;
let mut entry_opt = enumerate.get_list_entry()?;
while let Some(entry) = entry_opt.take() {
'inner: {
let device = match self.udev.create_device_from_syspath(entry.name()) {
Ok(d) => d,
_ => break 'inner,
};
let sysname = match device.sysname() {
Ok(s) => s,
_ => break 'inner,
};
if sysname.to_bytes().starts_with(b"event") {
self.add_input_device(&device);
}
}
entry_opt = entry.next();
}
Ok(())
}
fn add_input_device(self: &Rc<Self>, dev: &UdevDevice) {
let slf = self.clone();
let device_id = self.id();
let devnum = dev.devnum();
let devnode = match dev.devnode() {
Ok(n) => n,
Err(e) => {
log::error!("Could not retrieve devnode of udev device: {}", ErrorFmt(e));
return;
}
};
let sysname = match dev.sysname() {
Ok(n) => n,
Err(e) => {
log::error!("Could not retrieve sysname of udev device: {}", ErrorFmt(e));
return;
}
};
let mut slots = self.device_holder.input_devices_.borrow_mut();
let slot = 'slot: {
for (i, s) in slots.iter().enumerate() {
if s.is_none() {
break 'slot i;
}
}
slots.push(None);
slots.len() - 1
};
let dev = Rc::new(MetalDevice {
slot,
device_id,
devnum,
fd: Default::default(),
inputdev: Default::default(),
devnode: devnode.to_owned(),
sysname: sysname.to_owned(),
});
slots[slot] = Some(dev.clone());
self.device_holder.input_devices.set(devnum, dev);
self.session.get_device(devnum, move |res| {
let id = &slf.device_holder.input_devices;
let mut slots = slf.device_holder.input_devices_.borrow_mut();
let dev = 'dev: {
if let Some(dev) = id.get(&devnum) {
if dev.device_id == device_id {
break 'dev dev;
}
}
return;
};
let res = match res {
Ok(r) => r,
Err(e) => {
log::error!("Could not take control of input device: {}", ErrorFmt(e));
slots[dev.slot] = None;
id.remove(&devnum);
return;
}
};
if res.inactive == TRUE {
return;
}
dev.fd.set(Some(res.fd.clone()));
let inputdev = match slf.libinput.open(dev.devnode.as_c_str()) {
Ok(d) => d,
Err(_) => {
slots[dev.slot] = None;
id.remove(&devnum);
return;
}
};
inputdev.device().set_slot(slot);
dev.inputdev.set(Some(inputdev));
});
}
}

View file

@ -87,7 +87,7 @@ impl Clients {
Err(e) => {
log::error!(
"Cannot determine peer credentials of new connection: {:?}",
std::io::Error::from(e)
crate::utils::oserror::OsError::from(e)
);
return Ok(());
}

View file

@ -10,11 +10,11 @@ use uapi::c::raise;
#[derive(Debug, Error)]
pub enum ClientMemError {
#[error("Could not install the sigbus handler")]
SigactionFailed(#[source] std::io::Error),
SigactionFailed(#[source] crate::utils::oserror::OsError),
#[error("A SIGBUS occurred while accessing mapped memory")]
Sigbus,
#[error("mmap failed")]
MmapFailed(#[source] std::io::Error),
MmapFailed(#[source] crate::utils::oserror::OsError),
}
pub struct ClientMem {

View file

@ -67,13 +67,13 @@ pub enum DbusError {
#[error("Variant has an invalid type")]
InvalidVariantType,
#[error("Could not create a socket")]
Socket(#[source] std::io::Error),
Socket(#[source] crate::utils::oserror::OsError),
#[error("Could not connect")]
Connect(#[source] std::io::Error),
Connect(#[source] crate::utils::oserror::OsError),
#[error("Could not write to the dbus socket")]
WriteError(#[source] std::io::Error),
WriteError(#[source] crate::utils::oserror::OsError),
#[error("Could not read from the dbus socket")]
ReadError(#[source] std::io::Error),
ReadError(#[source] crate::utils::oserror::OsError),
#[error("timeout")]
AsyncError(#[source] Box<AsyncError>),
#[error("Server did not accept our authentication")]

View file

@ -49,7 +49,11 @@ impl Outgoing {
return;
}
if let Err(e) = self.socket.fd.writable().await {
log::error!("{}: Cannot wait for fd to become readable: {}", self.socket.bus_name, ErrorFmt(e));
log::error!(
"{}: Cannot wait for fd to become readable: {}",
self.socket.bus_name,
ErrorFmt(e)
);
self.socket.kill();
return;
}

View file

@ -12,13 +12,13 @@ use uapi::{c, Errno, OwnedFd, Ustring};
#[derive(Debug, Error)]
pub enum DrmError {
#[error("Could not reopen a node")]
ReopenNode(#[source] std::io::Error),
ReopenNode(#[source] crate::utils::oserror::OsError),
#[error("Could not retrieve the render node name")]
RenderNodeName,
#[error("Could not retrieve the device node name")]
DeviceNodeName,
#[error("Could not retrieve device")]
GetDevice(#[source] std::io::Error),
GetDevice(#[source] crate::utils::oserror::OsError),
}
#[allow(dead_code)]

View file

@ -9,17 +9,17 @@ use uapi::{c, Errno, OwnedFd};
#[derive(Debug, Error)]
pub enum EventLoopError {
#[error("Could not create an epoll fd: {0}")]
CreateFailed(std::io::Error),
CreateFailed(crate::utils::oserror::OsError),
#[error("epoll_wait failed: {0}")]
WaitFailed(std::io::Error),
WaitFailed(crate::utils::oserror::OsError),
#[error("A dispatcher returned a fatal error: {0}")]
DispatcherError(Box<dyn std::error::Error>),
#[error("Could not insert an fd to wait on: {0}")]
InsertFailed(std::io::Error),
InsertFailed(crate::utils::oserror::OsError),
#[error("Could not modify an fd to wait on: {0}")]
ModifyFailed(std::io::Error),
ModifyFailed(crate::utils::oserror::OsError),
#[error("Could not remove an fd to wait on: {0}")]
RemoveFailed(std::io::Error),
RemoveFailed(crate::utils::oserror::OsError),
#[error("Entry is not registered")]
NoEntry,
#[error("Event loop is already destroyed")]

View file

@ -43,9 +43,9 @@ struct PidfdHandoff {
#[derive(Debug, Error)]
pub enum ForkerError {
#[error("Could not create a socketpair")]
Socketpair(#[source] std::io::Error),
Socketpair(#[source] crate::utils::oserror::OsError),
#[error("Could not fork")]
Fork(#[source] std::io::Error),
Fork(#[source] crate::utils::oserror::OsError),
#[error("Could not read the next message")]
ReadFailed(#[source] BufFdError),
#[error("Could not write the next message")]
@ -235,7 +235,10 @@ impl ForkerProxy {
async fn check_process(self: Rc<Self>, state: Rc<State>) {
let pidfd = state.eng.fd(&self.pidfd).unwrap();
if let Err(e) = pidfd.readable().await {
log::error!("Cannot wait for the forker pidfd to become readable: {}", ErrorFmt(e));
log::error!(
"Cannot wait for the forker pidfd to become readable: {}",
ErrorFmt(e)
);
} else {
let _ = uapi::waitpid(self.pid, 0);
}
@ -417,7 +420,10 @@ impl Forker {
let spawn = self.ae.spawn(async move {
let read = slf.ae.fd(&Rc::new(read)).unwrap();
if let Err(e) = read.readable().await {
log::error!("Cannot wait for the child fd to become readable: {}", ErrorFmt(e));
log::error!(
"Cannot wait for the child fd to become readable: {}",
ErrorFmt(e)
);
} else {
let mut s = String::new();
let _ = Fd::new(read.raw()).read_to_string(&mut s);
@ -476,9 +482,9 @@ impl Forker {
#[derive(Debug, Error)]
enum SpawnError {
#[error("exec failed")]
Exec(#[source] std::io::Error),
Exec(#[source] crate::utils::oserror::OsError),
#[error("Could not unset cloexec flag")]
Cloexec(#[source] std::io::Error),
Cloexec(#[source] crate::utils::oserror::OsError),
}
fn setup_fds(mut socket: OwnedFd) -> OwnedFd {

View file

@ -125,9 +125,9 @@ pub enum WlKeyboardError {
#[error("Could not process a `release` request")]
ReleaseError(#[from] ReleaseError),
#[error("Could not create a keymap memfd")]
KeymapMemfd(#[source] std::io::Error),
KeymapMemfd(#[source] crate::utils::oserror::OsError),
#[error("Could not copy the keymap")]
KeymapCopy(#[source] std::io::Error),
KeymapCopy(#[source] crate::utils::oserror::OsError),
}
efrom!(WlKeyboardError, ClientError, ClientError);

View file

@ -1,31 +1,31 @@
use crate::udev::Udev;
#![allow(non_camel_case_types)]
pub mod consts;
pub mod device;
pub mod event;
mod sys;
use crate::libinput::consts::{
LogPriority, LIBINPUT_LOG_PRIORITY_DEBUG, LIBINPUT_LOG_PRIORITY_ERROR,
LIBINPUT_LOG_PRIORITY_INFO,
};
use crate::libinput::device::RegisteredDevice;
use crate::libinput::event::LibInputEvent;
use crate::libinput::sys::{
libinput, libinput_device_ref, libinput_dispatch, libinput_get_event, libinput_get_fd,
libinput_interface, libinput_log_priority, libinput_log_set_handler, libinput_log_set_priority,
libinput_path_add_device, libinput_path_create_context, libinput_unref,
};
use crate::udev::UdevError;
use crate::utils::oserror::OsError;
use crate::utils::ptr_ext::PtrExt;
use std::ops::DerefMut;
use crate::utils::vasprintf::vasprintf_;
use crate::ErrorFmt;
use bstr::ByteSlice;
use std::ffi::{CStr, VaList};
use std::rc::Rc;
use thiserror::Error;
use uapi::{c, OwnedFd};
#[link(name = "input")]
extern "C" {
type libinput;
fn libinput_path_create_context(
interface: *const libinput_interface,
user_data: *mut c::c_void,
) -> *mut libinput;
fn libinput_unref(libinput: *mut libinput) -> *mut libinput;
fn libinput_get_fd(libinput: *mut libinput) -> c::c_int;
}
#[repr(C)]
struct libinput_interface {
open_restricted: unsafe extern "C" fn(
path: *const c::c_char,
flags: c::c_int,
user_data: *mut c::c_void,
) -> c::c_int,
close_restricted: unsafe extern "C" fn(fd: c::c_int, user_data: *mut c::c_void),
}
use uapi::{c, Errno, IntoUstr, OwnedFd};
static INTERFACE: libinput_interface = libinput_interface {
open_restricted,
@ -34,23 +34,47 @@ static INTERFACE: libinput_interface = libinput_interface {
unsafe extern "C" fn open_restricted(
path: *const c::c_char,
flags: c::c_int,
_flags: c::c_int,
user_data: *mut c::c_void,
) -> c::c_int {
let ud = (user_data as *const UserData).deref();
-1
match ud.adapter.open(CStr::from_ptr(path)) {
Ok(f) => f.unwrap(),
Err(e) => {
log::error!("Could not open device for libinput: {}", ErrorFmt(e));
-1
}
}
}
unsafe extern "C" fn close_restricted(fd: c::c_int, _user_data: *mut c::c_void) {
drop(OwnedFd::new(fd));
}
struct UserData {}
struct UserData {
adapter: Rc<dyn LibInputAdapter>,
}
pub trait LibInputAdapter {
fn open(&self, path: &CStr) -> Result<OwnedFd, LibInputError>;
}
#[derive(Debug, Error)]
pub enum LibInputError {
#[error("Could not create a libinput instance")]
New,
#[error("Could not open a libinput device")]
Open,
#[error("Could not dispatch libinput events")]
Dispatch(#[source] OsError),
#[error("The requested device is not available")]
DeviceUnavailable,
#[error("Dupfd failed")]
DupFd(#[source] OsError),
#[error("The udev subsystem produced an error")]
Udev(#[from] UdevError),
#[error("Stat failed")]
Stat(#[source] OsError),
}
pub struct LibInput {
@ -59,20 +83,71 @@ pub struct LibInput {
}
impl LibInput {
pub fn new() -> Result<Self, LibInputError> {
let mut ud = Box::new(UserData {});
pub fn new(adapter: Rc<dyn LibInputAdapter>) -> Result<Self, LibInputError> {
let mut ud = Box::new(UserData { adapter });
let li = unsafe {
libinput_path_create_context(&INTERFACE, &mut *ud as *mut _ as *mut c::c_void)
};
if li.is_null() {
return Err(LibInputError::New);
}
unsafe {
libinput_log_set_handler(li, log_handler);
let priority = if log::log_enabled!(log::Level::Debug) {
LIBINPUT_LOG_PRIORITY_DEBUG
} else if log::log_enabled!(log::Level::Info) {
LIBINPUT_LOG_PRIORITY_INFO
} else {
LIBINPUT_LOG_PRIORITY_ERROR
};
libinput_log_set_priority(li, priority.raw() as _);
}
Ok(Self { data: ud, li })
}
pub fn fd(&self) -> c::c_int {
unsafe { libinput_get_fd(self.li) }
}
pub fn open<'a>(
self: &Rc<Self>,
path: impl IntoUstr<'a>,
) -> Result<RegisteredDevice, LibInputError> {
let path = path.into_ustr();
let res = unsafe { libinput_path_add_device(self.li, path.as_ptr()) };
if res.is_null() {
Err(LibInputError::Open)
} else {
unsafe {
libinput_device_ref(res);
}
Ok(RegisteredDevice {
li: self.clone(),
dev: res,
})
}
}
pub fn dispatch(&self) -> Result<(), LibInputError> {
let res = unsafe { libinput_dispatch(self.li) };
if res < 0 {
Err(LibInputError::Dispatch(Errno(-res).into()))
} else {
Ok(())
}
}
pub fn event(&self) -> Option<LibInputEvent> {
let res = unsafe { libinput_get_event(self.li) };
if res.is_null() {
None
} else {
Some(LibInputEvent {
event: res,
_phantom: Default::default(),
})
}
}
}
impl Drop for LibInput {
@ -82,3 +157,25 @@ impl Drop for LibInput {
}
}
}
unsafe extern "C" fn log_handler(
_libinput: *mut libinput,
priority: libinput_log_priority,
format: *const c::c_char,
args: VaList,
) {
let str = match vasprintf_(format, args) {
Some(s) => s,
_ => {
log::error!("Could not format log message");
return;
}
};
let priority = match LogPriority(priority as _) {
LIBINPUT_LOG_PRIORITY_DEBUG => log::Level::Debug,
LIBINPUT_LOG_PRIORITY_INFO => log::Level::Info,
LIBINPUT_LOG_PRIORITY_ERROR => log::Level::Error,
_ => log::Level::Error,
};
log::log!(priority, "libinput: {}", str.to_bytes().trim().as_bstr());
}

152
src/libinput/consts.rs Normal file
View file

@ -0,0 +1,152 @@
#![allow(dead_code)]
cenum! {
LogPriority, LIBINPUT_LOG_PRIORITY;
LIBINPUT_LOG_PRIORITY_DEBUG = 10,
LIBINPUT_LOG_PRIORITY_INFO = 20,
LIBINPUT_LOG_PRIORITY_ERROR = 30,
}
cenum! {
DeviceCapability, LIBINPUT_DEVICE_CAPABILITY;
LIBINPUT_DEVICE_CAP_KEYBOARD = 0,
LIBINPUT_DEVICE_CAP_POINTER = 1,
LIBINPUT_DEVICE_CAP_TOUCH = 2,
LIBINPUT_DEVICE_CAP_TABLET_TOOL = 3,
LIBINPUT_DEVICE_CAP_TABLET_PAD = 4,
LIBINPUT_DEVICE_CAP_GESTURE = 5,
LIBINPUT_DEVICE_CAP_SWITCH = 6,
}
cenum! {
KeyState, LIBINPUT_KEY_STATE;
LIBINPUT_KEY_STATE_RELEASED = 0,
LIBINPUT_KEY_STATE_PRESSED = 1,
}
cenum! {
Led, LIBINPUT_LED;
LIBINPUT_LED_NUM_LOCK = 1 << 0,
LIBINPUT_LED_CAPS_LOCK = 1 << 1,
LIBINPUT_LED_SCROLL_LOCK = 1 << 2,
}
cenum! {
ButtonState, LIBINPUT_BUTTON_STATE;
LIBINPUT_BUTTON_STATE_RELEASED = 0,
LIBINPUT_BUTTON_STATE_PRESSED = 1,
}
cenum! {
PointerAxis, LIBINPUT_POINTER_AXIS;
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL = 0,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL = 1,
}
cenum! {
PointerAxisSource, LIBINPUT_POINTER_AXIS_SOURCE;
LIBINPUT_POINTER_AXIS_SOURCE_WHEEL = 1,
LIBINPUT_POINTER_AXIS_SOURCE_FINGER = 2,
LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS = 3,
LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT = 4,
}
cenum! {
TabletPadRingAxisSource, LIBINPUT_TABLET_PAD_RING_AXIS_SOURCE;
LIBINPUT_TABLET_PAD_RING_SOURCE_UNKNOWN = 1,
LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER = 2,
}
cenum! {
TabletPadStripAxisSource, LIBINPUT_TABLET_PAD_STRIP_AXIS_SOURCE;
LIBINPUT_TABLET_PAD_STRIP_SOURCE_UNKNOWN = 1,
LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER = 2,
}
cenum! {
TabletToolType, LIBINPUT_TABLET_TOOL_TYPE;
LIBINPUT_TABLET_TOOL_TYPE_PEN = 1,
LIBINPUT_TABLET_TOOL_TYPE_ERASER = 2,
LIBINPUT_TABLET_TOOL_TYPE_BRUSH = 3,
LIBINPUT_TABLET_TOOL_TYPE_PENCIL = 4,
LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH = 5,
LIBINPUT_TABLET_TOOL_TYPE_MOUSE = 6,
LIBINPUT_TABLET_TOOL_TYPE_LENS = 7,
LIBINPUT_TABLET_TOOL_TYPE_TOTEM = 8,
}
cenum! {
TabletToolProximityState, LIBINPUT_TABLET_TOOL_PROXIMITY_STATE;
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT = 0,
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN = 1,
}
cenum! {
TabletToolTipState, LIBINPUT_TABLET_TOOL_TIP_STATE;
LIBINPUT_TABLET_TOOL_TIP_UP = 0,
LIBINPUT_TABLET_TOOL_TIP_DOWN = 1,
}
cenum! {
SwitchState, LIBINPUT_SWITCH_STATE;
LIBINPUT_SWITCH_STATE_OFF = 0,
LIBINPUT_SWITCH_STATE_ON = 1,
}
cenum! {
Switch, LIBINPUT_SWITCH;
LIBINPUT_SWITCH_LID = 1,
LIBINPUT_SWITCH_TABLET_MODE = 2,
}
cenum! {
EventType, LIBINPUT_EVENT_TYPE;
LIBINPUT_EVENT_NONE = 0,
LIBINPUT_EVENT_DEVICE_ADDED = 1,
LIBINPUT_EVENT_DEVICE_REMOVED = 2,
LIBINPUT_EVENT_KEYBOARD_KEY = 300,
LIBINPUT_EVENT_POINTER_MOTION = 400,
LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE = 401,
LIBINPUT_EVENT_POINTER_BUTTON = 402,
LIBINPUT_EVENT_POINTER_AXIS = 403,
LIBINPUT_EVENT_POINTER_SCROLL_WHEEL = 404,
LIBINPUT_EVENT_POINTER_SCROLL_FINGER = 405,
LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS = 406,
LIBINPUT_EVENT_TOUCH_DOWN = 500,
LIBINPUT_EVENT_TOUCH_UP = 501,
LIBINPUT_EVENT_TOUCH_MOTION = 502,
LIBINPUT_EVENT_TOUCH_CANCEL = 503,
LIBINPUT_EVENT_TOUCH_FRAME = 504,
LIBINPUT_EVENT_TABLET_TOOL_AXIS = 600,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY = 601,
LIBINPUT_EVENT_TABLET_TOOL_TIP = 602,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON = 603,
LIBINPUT_EVENT_TABLET_PAD_BUTTON = 700,
LIBINPUT_EVENT_TABLET_PAD_RING = 701,
LIBINPUT_EVENT_TABLET_PAD_STRIP = 702,
LIBINPUT_EVENT_TABLET_PAD_KEY = 703,
LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN = 800,
LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE = 801,
LIBINPUT_EVENT_GESTURE_SWIPE_END = 802,
LIBINPUT_EVENT_GESTURE_PINCH_BEGIN = 803,
LIBINPUT_EVENT_GESTURE_PINCH_UPDATE = 804,
LIBINPUT_EVENT_GESTURE_PINCH_END = 805,
LIBINPUT_EVENT_GESTURE_HOLD_BEGIN = 806,
LIBINPUT_EVENT_GESTURE_HOLD_END = 807,
LIBINPUT_EVENT_SWITCH_TOGGLE = 900,
}

51
src/libinput/device.rs Normal file
View file

@ -0,0 +1,51 @@
use crate::libinput::sys::{
libinput_device, libinput_device_set_user_data, libinput_device_unref,
libinput_path_remove_device,
};
use crate::libinput::LibInput;
use std::marker::PhantomData;
use std::rc::Rc;
pub struct LibInputDevice<'a> {
pub(super) dev: *mut libinput_device,
pub(super) _phantom: PhantomData<&'a ()>,
}
pub struct RegisteredDevice {
pub(super) li: Rc<LibInput>,
pub(super) dev: *mut libinput_device,
}
impl<'a> LibInputDevice<'a> {
pub fn set_slot(&self, slot: usize) {
self.set_slot_(slot + 1)
}
pub fn unset_slot(&self) {
self.set_slot_(0)
}
fn set_slot_(&self, slot: usize) {
unsafe {
libinput_device_set_user_data(self.dev, slot as _);
}
}
}
impl RegisteredDevice {
pub fn device(&self) -> LibInputDevice {
LibInputDevice {
dev: self.dev,
_phantom: Default::default(),
}
}
}
impl Drop for RegisteredDevice {
fn drop(&mut self) {
unsafe {
libinput_path_remove_device(self.dev);
libinput_device_unref(self.dev);
}
}
}

66
src/libinput/event.rs Normal file
View file

@ -0,0 +1,66 @@
use crate::libinput::consts::{EventType, KeyState};
use crate::libinput::device::LibInputDevice;
use crate::libinput::sys::{
libinput_event, libinput_event_destroy, libinput_event_get_device,
libinput_event_get_keyboard_event, libinput_event_get_type, libinput_event_keyboard,
libinput_event_keyboard_get_key, libinput_event_keyboard_get_key_state,
libinput_event_keyboard_get_time_usec,
};
use std::marker::PhantomData;
pub struct LibInputEvent<'a> {
pub(super) event: *mut libinput_event,
pub(super) _phantom: PhantomData<&'a ()>,
}
pub struct LibInputEventKeyboard<'a> {
pub(super) event: *mut libinput_event_keyboard,
pub(super) _phantom: PhantomData<&'a ()>,
}
impl<'a> Drop for LibInputEvent<'a> {
fn drop(&mut self) {
unsafe {
libinput_event_destroy(self.event);
}
}
}
impl<'a> LibInputEvent<'a> {
pub fn ty(&self) -> EventType {
unsafe { EventType(libinput_event_get_type(self.event)) }
}
pub fn device(&self) -> LibInputDevice {
LibInputDevice {
dev: unsafe { libinput_event_get_device(self.event) },
_phantom: Default::default(),
}
}
pub fn keyboard_event(&self) -> Option<LibInputEventKeyboard> {
let res = unsafe { libinput_event_get_keyboard_event(self.event) };
if res.is_null() {
None
} else {
Some(LibInputEventKeyboard {
event: res,
_phantom: Default::default(),
})
}
}
}
impl<'a> LibInputEventKeyboard<'a> {
pub fn key(&self) -> u32 {
unsafe { libinput_event_keyboard_get_key(self.event) }
}
pub fn key_state(&self) -> KeyState {
unsafe { KeyState(libinput_event_keyboard_get_key_state(self.event)) }
}
pub fn time_usec(&self) -> u64 {
unsafe { libinput_event_keyboard_get_time_usec(self.event) }
}
}

64
src/libinput/sys.rs Normal file
View file

@ -0,0 +1,64 @@
use std::ffi::VaList;
use uapi::c;
include!(concat!(env!("OUT_DIR"), "/libinput_tys.rs"));
pub type libinput_log_handler = unsafe extern "C" fn(
libinput: *mut libinput,
priority: libinput_log_priority,
format: *const c::c_char,
args: VaList,
);
#[link(name = "input")]
extern "C" {
pub type libinput;
pub type libinput_device;
pub type libinput_event;
pub type libinput_event_keyboard;
pub fn libinput_log_set_handler(libinput: *mut libinput, log_handler: libinput_log_handler);
pub fn libinput_log_set_priority(libinput: *mut libinput, priority: libinput_log_priority);
pub fn libinput_path_create_context(
interface: *const libinput_interface,
user_data: *mut c::c_void,
) -> *mut libinput;
pub fn libinput_device_set_user_data(device: *mut libinput_device, user_data: *mut c::c_void);
pub fn libinput_device_get_user_data(device: *mut libinput_device) -> *mut c::c_void;
pub fn libinput_device_ref(device: *mut libinput_device) -> *mut libinput_device;
pub fn libinput_device_unref(device: *mut libinput_device) -> *mut libinput_device;
pub fn libinput_path_add_device(
libinput: *mut libinput,
path: *const c::c_char,
) -> *mut libinput_device;
pub fn libinput_path_remove_device(device: *mut libinput_device);
pub fn libinput_unref(libinput: *mut libinput) -> *mut libinput;
pub fn libinput_get_fd(libinput: *mut libinput) -> c::c_int;
pub fn libinput_dispatch(libinput: *mut libinput) -> c::c_int;
pub fn libinput_get_event(libinput: *mut libinput) -> *mut libinput_event;
pub fn libinput_event_destroy(event: *mut libinput_event);
pub fn libinput_event_get_type(event: *mut libinput_event) -> libinput_event_type;
pub fn libinput_event_get_device(event: *mut libinput_event) -> *mut libinput_device;
pub fn libinput_event_get_keyboard_event(
event: *mut libinput_event,
) -> *mut libinput_event_keyboard;
pub fn libinput_event_keyboard_get_key(event: *mut libinput_event_keyboard) -> u32;
pub fn libinput_event_keyboard_get_key_state(
event: *mut libinput_event_keyboard,
) -> libinput_key_state;
pub fn libinput_event_keyboard_get_time_usec(event: *mut libinput_event_keyboard) -> u64;
}
#[repr(C)]
pub struct libinput_interface {
pub open_restricted: unsafe extern "C" fn(
path: *const c::c_char,
flags: c::c_int,
user_data: *mut c::c_void,
) -> c::c_int,
pub close_restricted: unsafe extern "C" fn(fd: c::c_int, user_data: *mut c::c_void),
}

View file

@ -1,8 +1,9 @@
use crate::dbus::{DbusError, DbusSocket, Reply};
use crate::org::freedesktop::login1::session::TakeControlReply;
use crate::dbus::{DbusError, DbusSocket};
use crate::org::freedesktop::login1::session::TakeDeviceReply;
use crate::{org, FALSE};
use std::rc::Rc;
use thiserror::Error;
use uapi::c;
const LOGIND_NAME: &str = "org.freedesktop.login1";
const MANAGER_PATH: &str = "/org/freedesktop/login1";
@ -72,8 +73,22 @@ impl Session {
)
.await;
match res {
Ok(r) => Ok(()),
Ok(_) => Ok(()),
Err(e) => Err(LogindError::TakeControl(e)),
}
}
pub fn get_device<F>(&self, dev: c::dev_t, f: F)
where
F: FnOnce(Result<&TakeDeviceReply, DbusError>) + 'static,
{
let major = uapi::major(dev) as _;
let minor = uapi::minor(dev) as _;
self.socket.call(
LOGIND_NAME,
&self.session_path,
org::freedesktop::login1::session::TakeDevice { major, minor },
move |r| f(r),
);
}
}

View file

@ -330,6 +330,7 @@ macro_rules! assert_size_eq {
}};
}
#[allow(unused_macros)]
macro_rules! assert_size_le {
($t:ty, $u:ty) => {{
struct AssertLeSize<T, U>(std::marker::PhantomData<T>, std::marker::PhantomData<U>);

View file

@ -17,10 +17,11 @@
use crate::acceptor::AcceptorError;
use crate::async_engine::{AsyncError, Phase};
use crate::backends::dummy::DummyBackend;
use crate::backends::xorg::{XorgBackend, XorgBackendError};
use crate::backends::metal;
use crate::backends::xorg::XorgBackendError;
use crate::client::Clients;
use crate::clientmem::ClientMemError;
use crate::dbus::{Dbus, FALSE, TRUE};
use crate::dbus::{Dbus, FALSE};
use crate::event_loop::EventLoopError;
use crate::forker::ForkerError;
use crate::globals::Globals;
@ -55,7 +56,6 @@ use std::ops::Deref;
use std::rc::Rc;
use thiserror::Error;
use wheel::Wheel;
use crate::backends::metal;
#[macro_use]
mod macros;

View file

@ -10,15 +10,15 @@ use uapi::{c, Errno, OwnedFd};
#[derive(Debug, Error)]
pub enum ServerMemError {
#[error("memfd_create failed")]
MemfdCreate(#[source] std::io::Error),
MemfdCreate(#[source] crate::utils::oserror::OsError),
#[error("The provided size does not fit into off_t")]
SizeOverflow,
#[error("ftruncate failed")]
Ftruncate(#[source] std::io::Error),
Ftruncate(#[source] crate::utils::oserror::OsError),
#[error("mmap failed")]
MmapFailed(#[source] std::io::Error),
MmapFailed(#[source] crate::utils::oserror::OsError),
#[error("sealing failed")]
Seal(#[source] std::io::Error),
Seal(#[source] crate::utils::oserror::OsError),
}
pub struct ServerMem {

View file

@ -10,11 +10,11 @@ pub enum SighandError {
#[error("The signal fd is in an error state")]
ErrorEvent,
#[error("Could not read from the signal fd")]
ReadFailed(#[source] std::io::Error),
ReadFailed(#[source] crate::utils::oserror::OsError),
#[error("Could not block the signalfd signals")]
BlockFailed(#[source] std::io::Error),
BlockFailed(#[source] crate::utils::oserror::OsError),
#[error("Could not create a signalfd")]
CreateFailed(#[source] std::io::Error),
CreateFailed(#[source] crate::utils::oserror::OsError),
#[error("The event loop caused an error")]
EventLoopError(#[from] EventLoopError),
}

View file

@ -8,7 +8,7 @@ use uapi::c;
#[derive(Debug, Error)]
pub enum TimeError {
#[error("clock_gettime failed: {0}")]
ClockGettime(std::io::Error),
ClockGettime(crate::utils::oserror::OsError),
}
#[derive(Copy, Clone)]

View file

@ -1,10 +1,9 @@
use crate::dbus::DbusError;
use std::ffi::CStr;
use std::marker::PhantomData;
use std::ptr;
use std::rc::Rc;
use thiserror::Error;
use uapi::{c, Errno, IntoUstr, Ustr};
use uapi::{c, Errno, IntoUstr};
#[link(name = "udev")]
extern "C" {
@ -47,32 +46,33 @@ extern "C" {
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_devnode(udev_device: *mut udev_device) -> *const c::c_char;
fn udev_device_get_devnum(udev_device: *mut udev_device) -> c::dev_t;
}
#[derive(Debug, Error)]
pub enum UdevError {
#[error("Could not create a new udev instance")]
New(#[source] std::io::Error),
New(#[source] crate::utils::oserror::OsError),
#[error("Could not create a new udev_monitor instance")]
NewMonitor(#[source] std::io::Error),
NewMonitor(#[source] crate::utils::oserror::OsError),
#[error("Could not create a new udev_enumerate instance")]
NewEnumerate(#[source] std::io::Error),
NewEnumerate(#[source] crate::utils::oserror::OsError),
#[error("Could not enable receiving on a udev_monitor")]
EnableReceiving(#[source] std::io::Error),
EnableReceiving(#[source] crate::utils::oserror::OsError),
#[error("Could not add a match rule to a udev_monitor")]
MonitorAddMatch(#[source] std::io::Error),
MonitorAddMatch(#[source] crate::utils::oserror::OsError),
#[error("Could not add a match rule to a udev_enumerate")]
EnumerateAddMatch(#[source] std::io::Error),
EnumerateAddMatch(#[source] crate::utils::oserror::OsError),
#[error("Could not list devices of a udev_enumerate")]
EnumerateGetListEntry(#[source] std::io::Error),
EnumerateGetListEntry(#[source] crate::utils::oserror::OsError),
#[error("Could not scan devices of a udev_enumerate")]
ScanDevices(#[source] std::io::Error),
ScanDevices(#[source] crate::utils::oserror::OsError),
#[error("Could not create a udev_device from a syspath")]
DeviceFromSyspath(#[source] std::io::Error),
DeviceFromSyspath(#[source] crate::utils::oserror::OsError),
#[error("Could not retrieve the sysname of a udev_device")]
GetSysname(#[source] std::io::Error),
GetSysname(#[source] crate::utils::oserror::OsError),
#[error("Could not retrieve the devnode of a udev_device")]
GetDevnode(#[source] std::io::Error),
GetDevnode(#[source] crate::utils::oserror::OsError),
}
pub struct Udev {
@ -193,9 +193,7 @@ impl UdevMonitor {
}
pub fn receive_device(&self) -> Option<UdevDevice> {
let res = unsafe {
udev_monitor_receive_device(self.monitor)
};
let res = unsafe { udev_monitor_receive_device(self.monitor) };
if res.is_null() {
None
} else {
@ -303,6 +301,10 @@ impl UdevDevice {
}
}
pub fn devnum(&self) -> c::dev_t {
unsafe { udev_device_get_devnum(self.device) }
}
pub fn is_initialized(&self) -> bool {
unsafe { udev_device_get_is_initialized(self.device) != 0 }
}

View file

@ -13,7 +13,7 @@ mod parser;
#[derive(Debug, Error)]
pub enum BufFdError {
#[error("An IO error occurred")]
Io(#[source] std::io::Error),
Io(#[source] crate::utils::oserror::OsError),
#[error("An async error occurred")]
Async(#[from] AsyncError),
#[error("The peer did not send a file descriptor")]

View file

@ -1,5 +1,6 @@
pub mod array;
pub mod asyncevent;
pub mod bitfield;
pub mod bitflags;
pub mod buffd;
pub mod clonecell;
@ -9,12 +10,13 @@ pub mod errorfmt;
pub mod hex;
pub mod linkedlist;
pub mod numcell;
pub mod oserror;
pub mod ptr_ext;
pub mod queue;
pub mod run_toplevel;
pub mod smallmap;
pub mod stack;
pub mod tri;
pub mod vasprintf;
pub mod vec_ext;
pub mod vecstorage;
pub mod bitfield;

181
src/utils/oserror.rs Normal file
View file

@ -0,0 +1,181 @@
use once_cell::sync::Lazy;
use std::error::Error;
use std::fmt::{Display, Formatter};
use uapi::{c, Errno};
static ERRORS: Lazy<&'static [Option<&'static str>]> = Lazy::new(|| {
static MSGS: &'static [(c::c_int, &'static str)] = &[
(c::EWOULDBLOCK, "Operation would block"),
(c::ENOTSUP, "Not supported"),
(c::EHWPOISON, "Memory page has hardware error"),
(c::ERFKILL, "Operation not possible due to RF-kill"),
(c::EKEYREJECTED, "Key was rejected by service"),
(c::EKEYREVOKED, "Key has been revoked"),
(c::EKEYEXPIRED, "Key has expired"),
(c::ENOKEY, "Required key not available"),
(c::EMEDIUMTYPE, "Wrong medium type"),
(c::ENOMEDIUM, "No medium found"),
(c::EREMOTEIO, "Remote I/O error"),
(c::EISNAM, "Is a named type file"),
(c::ENAVAIL, "No XENIX semaphores available"),
(c::ENOTNAM, "Not a XENIX named type file"),
(c::EUCLEAN, "Structure needs cleaning"),
(c::ESTRPIPE, "Streams pipe error"),
(c::ELIBEXEC, "Cannot exec a shared library directly"),
(
c::ELIBMAX,
"Attempting to link in too many shared libraries",
),
(c::ELIBSCN, ".lib section in a.out corrupted"),
(c::ELIBBAD, "Accessing a corrupted shared library"),
(c::ELIBACC, "Can not access a needed shared library"),
(c::EREMCHG, "Remote address changed"),
(c::EBADFD, "File descriptor in bad state"),
(c::ENOTUNIQ, "Name not unique on network"),
(c::EDOTDOT, "RFS specific error"),
(c::ECOMM, "Communication error on send"),
(c::ESRMNT, "Srmount error"),
(c::EADV, "Advertise error"),
(c::ENOPKG, "Package not installed"),
(c::ENONET, "Machine is not on the network"),
(c::EBFONT, "Bad font file format"),
(c::EBADSLT, "Invalid slot"),
(c::EBADRQC, "Invalid request code"),
(c::ENOANO, "No anode"),
(c::EXFULL, "Exchange full"),
(c::EBADR, "Invalid request descriptor"),
(c::EBADE, "Invalid exchange"),
(c::EL2HLT, "Level 2 halted"),
(c::ENOCSI, "No CSI structure available"),
(c::EUNATCH, "Protocol driver not attached"),
(c::ELNRNG, "Link number out of range"),
(c::EL3RST, "Level 3 reset"),
(c::EL3HLT, "Level 3 halted"),
(c::EL2NSYNC, "Level 2 not synchronized"),
(c::ECHRNG, "Channel number out of range"),
(c::ERESTART, "Interrupted system call should be restarted"),
(c::ENOTRECOVERABLE, "State not recoverable"),
(c::EOWNERDEAD, "Owner died"),
(c::ECANCELED, "Operation canceled"),
(c::ETIME, "Timer expired"),
(c::EPROTO, "Protocol error"),
(c::EOVERFLOW, "Value too large for defined data type"),
(c::ENOSTR, "Device not a stream"),
(c::ENOSR, "Out of streams resources"),
(c::ENOMSG, "No message of desired type"),
(c::ENOLINK, "Link has been severed"),
(c::ENODATA, "No data available"),
(c::EMULTIHOP, "Multihop attempted"),
(c::EIDRM, "Identifier removed"),
(c::EBADMSG, "Bad message"),
(
c::EILSEQ,
"Invalid or incomplete multibyte or wide character",
),
(c::ENOSYS, "Function not implemented"),
(c::ENOLCK, "No locks available"),
(c::EREMOTE, "Object is remote"),
(c::ESTALE, "Stale file handle"),
(c::EDQUOT, "Disk quota exceeded"),
(c::EUSERS, "Too many users"),
(c::ENOTEMPTY, "Directory not empty"),
(c::EHOSTUNREACH, "No route to host"),
(c::EHOSTDOWN, "Host is down"),
(c::ENAMETOOLONG, "File name too long"),
(c::ELOOP, "Too many levels of symbolic links"),
(c::ECONNREFUSED, "Connection refused"),
(c::ETIMEDOUT, "Connection timed out"),
(c::ETOOMANYREFS, "Too many references: cannot splice"),
(
c::ESHUTDOWN,
"Cannot send after transport endpoint shutdown",
),
(c::EDESTADDRREQ, "Destination address required"),
(c::ENOTCONN, "Transport endpoint is not connected"),
(c::EISCONN, "Transport endpoint is already connected"),
(c::ENOBUFS, "No buffer space available"),
(c::ECONNRESET, "Connection reset by peer"),
(c::ECONNABORTED, "Software caused connection abort"),
(c::ENETRESET, "Network dropped connection on reset"),
(c::ENETUNREACH, "Network is unreachable"),
(c::ENETDOWN, "Network is down"),
(c::EADDRNOTAVAIL, "Cannot assign requested address"),
(c::EADDRINUSE, "Address already in use"),
(c::EAFNOSUPPORT, "Address family not supported by protocol"),
(c::EPFNOSUPPORT, "Protocol family not supported"),
(c::EOPNOTSUPP, "Operation not supported"),
(c::ESOCKTNOSUPPORT, "Socket type not supported"),
(c::EPROTONOSUPPORT, "Protocol not supported"),
(c::ENOPROTOOPT, "Protocol not available"),
(c::EPROTOTYPE, "Protocol wrong type for socket"),
(c::EMSGSIZE, "Message too long"),
(c::ENOTSOCK, "Socket operation on non-socket"),
(c::EALREADY, "Operation already in progress"),
(c::EINPROGRESS, "Operation now in progress"),
(c::EAGAIN, "Resource temporarily unavailable"),
(c::ERANGE, "Numerical result out of range"),
(c::EDOM, "Numerical argument out of domain"),
(c::EPIPE, "Broken pipe"),
(c::EMLINK, "Too many links"),
(c::EROFS, "Read-only file system"),
(c::ESPIPE, "Illegal seek"),
(c::ENOSPC, "No space left on device"),
(c::EFBIG, "File too large"),
(c::ETXTBSY, "Text file busy"),
(c::ENOTTY, "Inappropriate ioctl for device"),
(c::ENFILE, "Too many open files in system"),
(c::EMFILE, "Too many open files"),
(c::EINVAL, "Invalid argument"),
(c::EISDIR, "Is a directory"),
(c::ENOTDIR, "Not a directory"),
(c::ENODEV, "No such device"),
(c::EXDEV, "Invalid cross-device link"),
(c::EEXIST, "File exists"),
(c::EBUSY, "Device or resource busy"),
(c::ENOTBLK, "Block device required"),
(c::EFAULT, "Bad address"),
(c::EACCES, "Permission denied"),
(c::ENOMEM, "Cannot allocate memory"),
(c::EDEADLK, "Resource deadlock avoided"),
(c::ECHILD, "No child processes"),
(c::EBADF, "Bad file descriptor"),
(c::ENOEXEC, "Exec format error"),
(c::E2BIG, "Argument list too long"),
(c::ENXIO, "No such device or address"),
(c::EIO, "Input/output error"),
(c::EINTR, "Interrupted system call"),
(c::ESRCH, "No such process"),
(c::ENOENT, "No such file or directory"),
(c::EPERM, "Operation not permitted"),
];
let mut res = vec![];
for &(idx, msg) in MSGS {
let idx = idx as usize;
while res.len() <= idx {
res.push(None);
}
res[idx] = Some(msg);
}
res.leak()
});
#[derive(Debug)]
pub struct OsError(pub c::c_int);
impl From<Errno> for OsError {
fn from(e: Errno) -> Self {
Self(e.0)
}
}
impl Error for OsError {}
impl Display for OsError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let msg = ERRORS
.get(self.0 as usize)
.and_then(|v| *v)
.unwrap_or("unknown error");
write!(f, "{} (os error {})", msg, self.0)
}
}

38
src/utils/vasprintf.rs Normal file
View file

@ -0,0 +1,38 @@
use std::ffi::{CStr, VaList};
use std::ops::Deref;
use std::ptr;
use uapi::c;
extern "C" {
fn vasprintf(strp: *mut *mut c::c_char, fmt: *const c::c_char, ap: VaList) -> c::c_int;
}
pub struct OwnedCStr {
val: &'static CStr,
}
impl Deref for OwnedCStr {
type Target = CStr;
fn deref(&self) -> &Self::Target {
self.val
}
}
impl Drop for OwnedCStr {
fn drop(&mut self) {
unsafe {
c::free(self.val.as_ptr() as _);
}
}
}
pub unsafe fn vasprintf_(fmt: *const c::c_char, ap: VaList) -> Option<OwnedCStr> {
let mut res = ptr::null_mut();
if vasprintf(&mut res, fmt, ap) == -1 {
return None;
}
Some(OwnedCStr {
val: CStr::from_ptr(res),
})
}

View file

@ -14,9 +14,9 @@ use uapi::{c, OwnedFd};
#[derive(Debug, Error)]
pub enum WheelError {
#[error("Could not create the timerfd: {0}")]
CreateFailed(std::io::Error),
CreateFailed(crate::utils::oserror::OsError),
#[error("Could not set the timerfd: {0}")]
SetFailed(std::io::Error),
SetFailed(crate::utils::oserror::OsError),
#[error("The timerfd is in an error state")]
ErrorEvent,
#[error("An event loop error occurred: {0}")]

View file

@ -20,11 +20,11 @@ use uapi::{c, pipe2, Errno, OwnedFd};
#[derive(Debug, Error)]
enum XWaylandError {
#[error("Could not create a wayland socket")]
SocketFailed(#[source] std::io::Error),
SocketFailed(#[source] crate::utils::oserror::OsError),
#[error("/tmp/.X11-unix does not exist")]
MissingSocketDir,
#[error("Could not stat /tmp/.X11-unix")]
StatSocketDir(#[source] std::io::Error),
StatSocketDir(#[source] crate::utils::oserror::OsError),
#[error("/tmp/.X11-unix is not a directory")]
NotASocketDir,
#[error("/tmp/.X11-unix is writable")]
@ -38,17 +38,17 @@ enum XWaylandError {
#[error("The socket is already in use")]
AlreadyInUse,
#[error("Could not bind the socket to an address")]
BindFailed(#[source] std::io::Error),
BindFailed(#[source] crate::utils::oserror::OsError),
#[error("All X displays in the range 0..1000 are already in use")]
AddressesInUse,
#[error("The async engine returned an error")]
AsyncError(#[from] AsyncError),
#[error("pipe(2) failed")]
Pipe(#[source] std::io::Error),
Pipe(#[source] crate::utils::oserror::OsError),
#[error("dupfd(2) failed")]
Dupfd(#[source] std::io::Error),
Dupfd(#[source] crate::utils::oserror::OsError),
#[error("socketpair(2) failed")]
Socketpair(#[source] std::io::Error),
Socketpair(#[source] crate::utils::oserror::OsError),
#[error("Could not start Xwayland")]
ExecFailed(#[source] ForkerError),
#[error("Could not load the atoms")]
@ -224,7 +224,10 @@ async fn log_xwayland(state: Rc<State>, stderr: OwnedFd) {
let mut done = false;
while !done {
if let Err(e) = afd.readable().await {
log::error!("Cannot wait for the xwayland stderr to become readable: {}", ErrorFmt(e));
log::error!(
"Cannot wait for the xwayland stderr to become readable: {}",
ErrorFmt(e)
);
return;
}
loop {
@ -242,7 +245,7 @@ async fn log_xwayland(state: Rc<State>, stderr: OwnedFd) {
Err(e) => {
log::error!(
"Could not read from stderr fd: {}",
ErrorFmt(std::io::Error::from(e))
ErrorFmt(crate::utils::oserror::OsError::from(e))
);
return;
}