autocommit 2022-03-02 14:24:07 CET
This commit is contained in:
parent
0e9afcbfa5
commit
aa0cb94143
30 changed files with 1059 additions and 123 deletions
|
|
@ -1,3 +1,5 @@
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
use std::io::BufWriter;
|
use std::io::BufWriter;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,12 @@ struct Property {
|
||||||
ty: Type,
|
ty: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Signal {
|
||||||
|
name: BString,
|
||||||
|
fields: Vec<Field>,
|
||||||
|
}
|
||||||
|
|
||||||
struct Parser<'a> {
|
struct Parser<'a> {
|
||||||
pos: usize,
|
pos: usize,
|
||||||
tokens: &'a [Token<'a>],
|
tokens: &'a [Token<'a>],
|
||||||
|
|
@ -57,12 +63,14 @@ impl<'a> Parser<'a> {
|
||||||
let mut res = Component {
|
let mut res = Component {
|
||||||
functions: vec![],
|
functions: vec![],
|
||||||
properties: vec![],
|
properties: vec![],
|
||||||
|
signals: vec![],
|
||||||
};
|
};
|
||||||
while !self.eof() {
|
while !self.eof() {
|
||||||
let (line, ty) = self.expect_ident()?;
|
let (line, ty) = self.expect_ident()?;
|
||||||
match ty.as_bytes() {
|
match ty.as_bytes() {
|
||||||
b"fn" => res.functions.push(self.parse_fn()?.val),
|
b"fn" => res.functions.push(self.parse_fn()?.val),
|
||||||
b"prop" => res.properties.push(self.parse_prop()?.val),
|
b"prop" => res.properties.push(self.parse_prop()?.val),
|
||||||
|
b"sig" => res.signals.push(self.parse_signal()?.val),
|
||||||
_ => bail!("In line {}: Unexpected entry {:?}", line, ty),
|
_ => bail!("In line {}: Unexpected entry {:?}", line, ty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -96,6 +104,29 @@ impl<'a> Parser<'a> {
|
||||||
res.with_context(|| format!("While parsing property starting at line {}", line))
|
res.with_context(|| format!("While parsing property starting at line {}", line))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_signal(&mut self) -> Result<Lined<Signal>> {
|
||||||
|
let (line, name) = self.expect_ident()?;
|
||||||
|
let res: Result<_> = (|| {
|
||||||
|
let (_, body) = self.expect_tree(TreeDelim::Brace)?;
|
||||||
|
let mut parser = Parser {
|
||||||
|
pos: 0,
|
||||||
|
tokens: body,
|
||||||
|
};
|
||||||
|
let mut fields = vec![];
|
||||||
|
while !parser.eof() {
|
||||||
|
fields.push(parser.parse_field()?);
|
||||||
|
}
|
||||||
|
Ok(Lined {
|
||||||
|
line,
|
||||||
|
val: Signal {
|
||||||
|
name: name.to_owned(),
|
||||||
|
fields,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})();
|
||||||
|
res.with_context(|| format!("While parsing signal starting at line {}", line))
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_fn(&mut self) -> Result<Lined<Function>> {
|
fn parse_fn(&mut self) -> Result<Lined<Function>> {
|
||||||
let (line, name) = self.expect_ident()?;
|
let (line, name) = self.expect_ident()?;
|
||||||
let res: Result<_> = (|| {
|
let res: Result<_> = (|| {
|
||||||
|
|
@ -379,9 +410,9 @@ fn write_type2<W: Write>(f: &mut W, lt: &str, ty: &Type) -> Result<()> {
|
||||||
Type::U16 => "u16",
|
Type::U16 => "u16",
|
||||||
Type::I32 => "i32",
|
Type::I32 => "i32",
|
||||||
Type::U32 => "u32",
|
Type::U32 => "u32",
|
||||||
Type::I64 => "AlignedI64",
|
Type::I64 => "i64",
|
||||||
Type::U64 => "AlignedU64",
|
Type::U64 => "u64",
|
||||||
Type::F64 => "AlignedF64",
|
Type::F64 => "f64",
|
||||||
Type::String => {
|
Type::String => {
|
||||||
write!(f, "Cow<{}, str>", lt)?;
|
write!(f, "Cow<{}, str>", lt)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
@ -432,7 +463,7 @@ fn write_type2<W: Write>(f: &mut W, lt: &str, ty: &Type) -> Result<()> {
|
||||||
fn write_message<W: Write>(
|
fn write_message<W: Write>(
|
||||||
f: &mut W,
|
f: &mut W,
|
||||||
el: &Element,
|
el: &Element,
|
||||||
fun: &Function,
|
msg_name: &BStr,
|
||||||
name: &str,
|
name: &str,
|
||||||
indent: &str,
|
indent: &str,
|
||||||
fields: &[Field],
|
fields: &[Field],
|
||||||
|
|
@ -474,7 +505,7 @@ fn write_message<W: Write>(
|
||||||
writeln!(
|
writeln!(
|
||||||
f,
|
f,
|
||||||
"{} const MEMBER: &'static str = \"{}\";",
|
"{} const MEMBER: &'static str = \"{}\";",
|
||||||
indent, fun.name
|
indent, msg_name,
|
||||||
)?;
|
)?;
|
||||||
writeln!(f, "{} type Generic<'b> = {}{};", indent, name, ltb,)?;
|
writeln!(f, "{} type Generic<'b> = {}{};", indent, name, ltb,)?;
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
|
|
@ -540,6 +571,9 @@ fn write_component<W: Write>(
|
||||||
for prop in &component.properties {
|
for prop in &component.properties {
|
||||||
write_property(f, element, prop, indent)?;
|
write_property(f, element, prop, indent)?;
|
||||||
}
|
}
|
||||||
|
for sig in &component.signals {
|
||||||
|
write_signal(f, element, sig, indent)?;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -570,6 +604,25 @@ fn write_property<W: Write>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_signal<W: Write>(f: &mut W, element: &Element, sig: &Signal, indent: &str) -> Result<()> {
|
||||||
|
let name = format!("{}", sig.name);
|
||||||
|
write_message(
|
||||||
|
f,
|
||||||
|
element,
|
||||||
|
sig.name.as_bstr(),
|
||||||
|
&name,
|
||||||
|
indent,
|
||||||
|
&sig.fields,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
let has_lt = sig.fields.iter().any(|f| needs_lifetime(&f.ty));
|
||||||
|
let lt = if has_lt { "<'a>" } else { "" };
|
||||||
|
writeln!(f)?;
|
||||||
|
writeln!(f, "{}impl<'a> Signal<'a> for {}{} {{ }}", indent, name, lt)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn write_function<W: Write>(
|
fn write_function<W: Write>(
|
||||||
f: &mut W,
|
f: &mut W,
|
||||||
element: &Element,
|
element: &Element,
|
||||||
|
|
@ -582,7 +635,7 @@ fn write_function<W: Write>(
|
||||||
write_message(
|
write_message(
|
||||||
f,
|
f,
|
||||||
element,
|
element,
|
||||||
fun,
|
fun.name.as_bstr(),
|
||||||
&in_name,
|
&in_name,
|
||||||
indent,
|
indent,
|
||||||
&fun.in_fields,
|
&fun.in_fields,
|
||||||
|
|
@ -592,7 +645,7 @@ fn write_function<W: Write>(
|
||||||
write_message(
|
write_message(
|
||||||
f,
|
f,
|
||||||
element,
|
element,
|
||||||
fun,
|
fun.name.as_bstr(),
|
||||||
&out_name,
|
&out_name,
|
||||||
indent,
|
indent,
|
||||||
&fun.out_fields,
|
&fun.out_fields,
|
||||||
|
|
@ -630,6 +683,7 @@ fn write_element<W: Write>(f: &mut W, element: Element, indent: &str) -> Result<
|
||||||
struct Component {
|
struct Component {
|
||||||
functions: Vec<Function>,
|
functions: Vec<Function>,
|
||||||
properties: Vec<Property>,
|
properties: Vec<Property>,
|
||||||
|
signals: Vec<Signal>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use crate::event_loop::{EventLoop, EventLoopError};
|
||||||
use crate::utils::copyhashmap::CopyHashMap;
|
use crate::utils::copyhashmap::CopyHashMap;
|
||||||
use crate::utils::numcell::NumCell;
|
use crate::utils::numcell::NumCell;
|
||||||
use crate::wheel::{Wheel, WheelError};
|
use crate::wheel::{Wheel, WheelError};
|
||||||
pub use fd::AsyncFd;
|
pub use fd::{AsyncFd, FdStatus};
|
||||||
use fd::AsyncFdData;
|
use fd::AsyncFdData;
|
||||||
use queue::{DispatchQueue, Dispatcher};
|
use queue::{DispatchQueue, Dispatcher};
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
|
|
@ -21,6 +21,8 @@ pub enum AsyncError {
|
||||||
WheelError(#[from] WheelError),
|
WheelError(#[from] WheelError),
|
||||||
#[error("The event loop caused an error: {0}")]
|
#[error("The event loop caused an error: {0}")]
|
||||||
EventLoopError(#[from] EventLoopError),
|
EventLoopError(#[from] EventLoopError),
|
||||||
|
#[error("The file descriptor is in an error state")]
|
||||||
|
FdError,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
|
|
@ -90,7 +92,6 @@ impl AsyncEngine {
|
||||||
read_registered: Cell::new(false),
|
read_registered: Cell::new(false),
|
||||||
readers: RefCell::new(vec![]),
|
readers: RefCell::new(vec![]),
|
||||||
writers: RefCell::new(vec![]),
|
writers: RefCell::new(vec![]),
|
||||||
erroneous: Cell::new(false),
|
|
||||||
});
|
});
|
||||||
self.el.insert(id, Some(fd.raw()), 0, afd.clone())?;
|
self.el.insert(id, Some(fd.raw()), 0, afd.clone())?;
|
||||||
afd
|
afd
|
||||||
|
|
@ -198,6 +199,7 @@ mod task {
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
|
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub struct SpawnedFuture<T: 'static> {
|
pub struct SpawnedFuture<T: 'static> {
|
||||||
vtable: &'static SpawnedFutureVtable<T>,
|
vtable: &'static SpawnedFutureVtable<T>,
|
||||||
data: *mut u8,
|
data: *mut u8,
|
||||||
|
|
@ -535,7 +537,7 @@ mod fd {
|
||||||
use std::task::{Context, Poll, Waker};
|
use std::task::{Context, Poll, Waker};
|
||||||
use uapi::{c, OwnedFd};
|
use uapi::{c, OwnedFd};
|
||||||
|
|
||||||
type Queue = RefCell<Vec<(Waker, Rc<Cell<bool>>)>>;
|
type Queue = RefCell<Vec<(Waker, Rc<Cell<Option<FdStatus>>>)>>;
|
||||||
|
|
||||||
pub(super) struct AsyncFdData {
|
pub(super) struct AsyncFdData {
|
||||||
pub(super) ref_count: NumCell<u64>,
|
pub(super) ref_count: NumCell<u64>,
|
||||||
|
|
@ -546,7 +548,6 @@ mod fd {
|
||||||
pub(super) read_registered: Cell<bool>,
|
pub(super) read_registered: Cell<bool>,
|
||||||
pub(super) readers: Queue,
|
pub(super) readers: Queue,
|
||||||
pub(super) writers: Queue,
|
pub(super) writers: Queue,
|
||||||
pub(super) erroneous: Cell<bool>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncFdData {
|
impl AsyncFdData {
|
||||||
|
|
@ -560,21 +561,23 @@ mod fd {
|
||||||
}
|
}
|
||||||
let res = self.el.modify(self.id, events);
|
let res = self.el.modify(self.id, events);
|
||||||
if res.is_err() {
|
if res.is_err() {
|
||||||
self.erroneous.set(true);
|
if let Err(e) = self.el.remove(self.id) {
|
||||||
let _ = self.el.remove(self.id);
|
log::error!("Fatal error: Cannot remove file descriptor from event loop: {:?}", e);
|
||||||
|
self.el.stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll(
|
fn poll(
|
||||||
&self,
|
&self,
|
||||||
woken: &Rc<Cell<bool>>,
|
woken: &Rc<Cell<Option<FdStatus>>>,
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
registered: impl Fn(&AsyncFdData) -> &Cell<bool>,
|
registered: impl Fn(&AsyncFdData) -> &Cell<bool>,
|
||||||
queue: impl Fn(&AsyncFdData) -> &Queue,
|
queue: impl Fn(&AsyncFdData) -> &Queue,
|
||||||
) -> Poll<Result<(), AsyncError>> {
|
) -> Poll<Result<FdStatus, AsyncError>> {
|
||||||
if woken.get() || self.erroneous.get() {
|
if let Some(status) = woken.get() {
|
||||||
return Poll::Ready(Ok(()));
|
return Poll::Ready(Ok(status));
|
||||||
}
|
}
|
||||||
if !registered(self).get() {
|
if !registered(self).get() {
|
||||||
registered(self).set(true);
|
registered(self).set(true);
|
||||||
|
|
@ -591,30 +594,31 @@ mod fd {
|
||||||
|
|
||||||
impl EventLoopDispatcher for AsyncFdData {
|
impl EventLoopDispatcher for AsyncFdData {
|
||||||
fn dispatch(self: Rc<Self>, events: i32) -> Result<(), Box<dyn Error>> {
|
fn dispatch(self: Rc<Self>, events: i32) -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut status = FdStatus::Ok;
|
||||||
if events & (c::EPOLLERR | c::EPOLLHUP) != 0 {
|
if events & (c::EPOLLERR | c::EPOLLHUP) != 0 {
|
||||||
self.erroneous.set(true);
|
status = FdStatus::Err;
|
||||||
if let Err(e) = self.el.remove(self.id) {
|
if let Err(e) = self.el.remove(self.id) {
|
||||||
return Err(Box::new(e));
|
return Err(Box::new(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut woke_any = false;
|
let mut woke_any = false;
|
||||||
if events & c::EPOLLIN != 0 || self.erroneous.get() {
|
if events & c::EPOLLIN != 0 || status == FdStatus::Err {
|
||||||
let mut readers = self.readers.borrow_mut();
|
let mut readers = self.readers.borrow_mut();
|
||||||
woke_any |= !readers.is_empty();
|
woke_any |= !readers.is_empty();
|
||||||
for (waker, woken) in readers.drain(..) {
|
for (waker, woken) in readers.drain(..) {
|
||||||
woken.set(true);
|
woken.set(Some(status));
|
||||||
waker.wake();
|
waker.wake();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if events & c::EPOLLOUT != 0 || self.erroneous.get() {
|
if events & c::EPOLLOUT != 0 || status == FdStatus::Err {
|
||||||
let mut writers = self.writers.borrow_mut();
|
let mut writers = self.writers.borrow_mut();
|
||||||
woke_any |= !writers.is_empty();
|
woke_any |= !writers.is_empty();
|
||||||
for (waker, woken) in writers.drain(..) {
|
for (waker, woken) in writers.drain(..) {
|
||||||
woken.set(true);
|
woken.set(Some(status));
|
||||||
waker.wake();
|
waker.wake();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !woke_any && !self.erroneous.get() {
|
if !woke_any && status == FdStatus::Ok {
|
||||||
self.read_registered.set(false);
|
self.read_registered.set(false);
|
||||||
self.write_registered.set(false);
|
self.write_registered.set(false);
|
||||||
if let Err(e) = self.update_interests() {
|
if let Err(e) = self.update_interests() {
|
||||||
|
|
@ -666,25 +670,31 @@ mod fd {
|
||||||
pub fn readable(&self) -> AsyncFdReadable {
|
pub fn readable(&self) -> AsyncFdReadable {
|
||||||
AsyncFdReadable {
|
AsyncFdReadable {
|
||||||
fd: self,
|
fd: self,
|
||||||
woken: Rc::new(Cell::new(false)),
|
woken: Rc::new(Cell::new(None)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writable(&self) -> AsyncFdWritable {
|
pub fn writable(&self) -> AsyncFdWritable {
|
||||||
AsyncFdWritable {
|
AsyncFdWritable {
|
||||||
fd: self,
|
fd: self,
|
||||||
woken: Rc::new(Cell::new(false)),
|
woken: Rc::new(Cell::new(None)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum FdStatus {
|
||||||
|
Ok,
|
||||||
|
Err,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct AsyncFdReadable<'a> {
|
pub struct AsyncFdReadable<'a> {
|
||||||
fd: &'a AsyncFd,
|
fd: &'a AsyncFd,
|
||||||
woken: Rc<Cell<bool>>,
|
woken: Rc<Cell<Option<FdStatus>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Future for AsyncFdReadable<'a> {
|
impl<'a> Future for AsyncFdReadable<'a> {
|
||||||
type Output = Result<(), AsyncError>;
|
type Output = Result<FdStatus, AsyncError>;
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let data = &self.fd.data;
|
let data = &self.fd.data;
|
||||||
|
|
@ -694,11 +704,11 @@ mod fd {
|
||||||
|
|
||||||
pub struct AsyncFdWritable<'a> {
|
pub struct AsyncFdWritable<'a> {
|
||||||
fd: &'a AsyncFd,
|
fd: &'a AsyncFd,
|
||||||
woken: Rc<Cell<bool>>,
|
woken: Rc<Cell<Option<FdStatus>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Future for AsyncFdWritable<'a> {
|
impl<'a> Future for AsyncFdWritable<'a> {
|
||||||
type Output = Result<(), AsyncError>;
|
type Output = Result<FdStatus, AsyncError>;
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let data = &self.fd.data;
|
let data = &self.fd.data;
|
||||||
|
|
|
||||||
128
src/backends/metal.rs
Normal file
128
src/backends/metal.rs
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
use crate::dbus::DbusError;
|
||||||
|
use crate::logind::{LogindError, Session};
|
||||||
|
use crate::{AsyncQueue, ErrorFmt, State, Udev};
|
||||||
|
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};
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum MetalError {
|
||||||
|
#[error("Could not connect to the dbus system socket")]
|
||||||
|
DbusSystemSocket(#[source] DbusError),
|
||||||
|
#[error("Could not retrieve the logind session")]
|
||||||
|
LogindSession(#[source] LogindError),
|
||||||
|
#[error("Could not take control of the logind session")]
|
||||||
|
TakeControl(#[source] LogindError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Udev(#[from] UdevError),
|
||||||
|
#[error(transparent)]
|
||||||
|
LibInput(#[from] LibInputError),
|
||||||
|
#[error("Dupfd failed")]
|
||||||
|
Dup(#[source] std::io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn run(state: Rc<State>) {
|
||||||
|
if let Err(e) = run_(state).await {
|
||||||
|
log::error!("{}", ErrorFmt(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run_(state: Rc<State>) -> Result<(), MetalError> {
|
||||||
|
let socket = match state.dbus.system() {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) => return Err(MetalError::DbusSystemSocket(e)),
|
||||||
|
};
|
||||||
|
let session = match Session::get(&socket).await {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) => return Err(MetalError::LogindSession(e)),
|
||||||
|
};
|
||||||
|
// if let Err(e) = session.take_control().await {
|
||||||
|
// return Err(MetalError::TakeControl(e));
|
||||||
|
// }
|
||||||
|
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 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 metal = Rc::new(MetalBackend {
|
||||||
|
state: state.clone(),
|
||||||
|
udev,
|
||||||
|
monitor,
|
||||||
|
monitor_fd,
|
||||||
|
libinput,
|
||||||
|
});
|
||||||
|
let _monitor = state.eng.spawn(metal.clone().monitor_devices());
|
||||||
|
let mut 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
pub mod dummy;
|
pub mod dummy;
|
||||||
|
pub mod metal;
|
||||||
pub mod xorg;
|
pub mod xorg;
|
||||||
|
|
|
||||||
78
src/dbus.rs
78
src/dbus.rs
|
|
@ -5,10 +5,12 @@ use crate::utils::copyhashmap::CopyHashMap;
|
||||||
use crate::utils::stack::Stack;
|
use crate::utils::stack::Stack;
|
||||||
use crate::utils::vecstorage::VecStorage;
|
use crate::utils::vecstorage::VecStorage;
|
||||||
use crate::{AsyncEngine, AsyncError, AsyncQueue, CloneCell, NumCell, RunToplevel};
|
use crate::{AsyncEngine, AsyncError, AsyncQueue, CloneCell, NumCell, RunToplevel};
|
||||||
|
use ahash::AHashMap;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::fmt::{Debug, Display};
|
use std::fmt::{Debug, Display};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
@ -52,6 +54,8 @@ pub enum DbusError {
|
||||||
Closed,
|
Closed,
|
||||||
#[error("Function call reply does not contain a reply serial")]
|
#[error("Function call reply does not contain a reply serial")]
|
||||||
NoReplySerial,
|
NoReplySerial,
|
||||||
|
#[error("Signal message contains no interface or member or path")]
|
||||||
|
MissingSignalHeaders,
|
||||||
#[error("Error has no error name")]
|
#[error("Error has no error name")]
|
||||||
NoErrorName,
|
NoErrorName,
|
||||||
#[error("The socket was killed")]
|
#[error("The socket was killed")]
|
||||||
|
|
@ -102,6 +106,8 @@ pub enum DbusError {
|
||||||
InvalidProtocol,
|
InvalidProtocol,
|
||||||
#[error("Signature contains an invalid type")]
|
#[error("Signature contains an invalid type")]
|
||||||
InvalidSignatureType,
|
InvalidSignatureType,
|
||||||
|
#[error("The signal already has a handler")]
|
||||||
|
AlreadyHandled,
|
||||||
}
|
}
|
||||||
efrom!(DbusError, AsyncError);
|
efrom!(DbusError, AsyncError);
|
||||||
|
|
||||||
|
|
@ -151,6 +157,7 @@ pub struct DbusSocket {
|
||||||
dead: Cell<bool>,
|
dead: Cell<bool>,
|
||||||
headers: RefCell<VecStorage<(u8, Variant<'static>)>>,
|
headers: RefCell<VecStorage<(u8, Variant<'static>)>>,
|
||||||
run_toplevel: Rc<RunToplevel>,
|
run_toplevel: Rc<RunToplevel>,
|
||||||
|
signal_handlers: RefCell<AHashMap<(&'static str, &'static str), InterfaceSignalHandlers>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const TY_BYTE: u8 = b'y';
|
const TY_BYTE: u8 = b'y';
|
||||||
|
|
@ -188,6 +195,9 @@ const NO_REPLY_EXPECTED: u8 = 0x1;
|
||||||
const NO_AUTO_START: u8 = 0x2;
|
const NO_AUTO_START: u8 = 0x2;
|
||||||
const ALLOW_INTERACTIVE_AUTHORIZATION: u8 = 0x4;
|
const ALLOW_INTERACTIVE_AUTHORIZATION: u8 = 0x4;
|
||||||
|
|
||||||
|
pub const BUS_DEST: &'static str = "org.freedesktop.DBus";
|
||||||
|
pub const BUS_PATH: &'static str = "/org/freedesktop/dbus";
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
struct Headers<'a> {
|
struct Headers<'a> {
|
||||||
path: Option<ObjectPath<'a>>,
|
path: Option<ObjectPath<'a>>,
|
||||||
|
|
@ -279,6 +289,8 @@ pub trait Property {
|
||||||
type Type: DbusType<'static>;
|
type Type: DbusType<'static>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Signal<'a>: Message<'a> {}
|
||||||
|
|
||||||
pub trait MethodCall<'a>: Message<'a> {
|
pub trait MethodCall<'a>: Message<'a> {
|
||||||
type Reply: Message<'static>;
|
type Reply: Message<'static>;
|
||||||
}
|
}
|
||||||
|
|
@ -391,10 +403,74 @@ impl<T: Property> Future for AsyncProperty<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SignalHandlerData<T, F> {
|
||||||
|
path: Option<String>,
|
||||||
|
rule: String,
|
||||||
|
handler: F,
|
||||||
|
_phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
trait SignalHandlerApi {
|
||||||
|
fn interface(&self) -> &'static str;
|
||||||
|
fn member(&self) -> &'static str;
|
||||||
|
fn signature(&self) -> &'static str;
|
||||||
|
fn path(&self) -> Option<&str>;
|
||||||
|
fn rule(&self) -> &str;
|
||||||
|
fn handle(&self, parser: &mut Parser) -> Result<(), DbusError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, F> SignalHandlerApi for SignalHandlerData<T, F>
|
||||||
|
where
|
||||||
|
T: Signal<'static>,
|
||||||
|
F: for<'a> Fn(T::Generic<'a>),
|
||||||
|
{
|
||||||
|
fn interface(&self) -> &'static str {
|
||||||
|
T::INTERFACE
|
||||||
|
}
|
||||||
|
|
||||||
|
fn member(&self) -> &'static str {
|
||||||
|
T::MEMBER
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> &'static str {
|
||||||
|
T::SIGNATURE
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path(&self) -> Option<&str> {
|
||||||
|
self.path.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rule(&self) -> &str {
|
||||||
|
&self.rule
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle<'a>(&self, parser: &mut Parser<'a>) -> Result<(), DbusError> {
|
||||||
|
(self.handler)(T::Generic::<'a>::unmarshal(parser)?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub struct SignalHandler {
|
||||||
|
socket: Rc<DbusSocket>,
|
||||||
|
data: Rc<dyn SignalHandlerApi>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for SignalHandler {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.socket.remove_signal_handler(&*self.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InterfaceSignalHandlers {
|
||||||
|
unconditional: Option<Rc<dyn SignalHandlerApi>>,
|
||||||
|
conditional: AHashMap<String, Rc<dyn SignalHandlerApi>>,
|
||||||
|
}
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use super::{
|
pub use super::{
|
||||||
types::{Bool, DictEntry, ObjectPath, Signature, Variant},
|
types::{Bool, DictEntry, ObjectPath, Signature, Variant},
|
||||||
DbusError, DbusType, Formatter, Message, MethodCall, Parser, Property,
|
DbusError, DbusType, Formatter, Message, MethodCall, Parser, Property, Signal,
|
||||||
};
|
};
|
||||||
pub use std::borrow::Cow;
|
pub use std::borrow::Cow;
|
||||||
pub use std::rc::Rc;
|
pub use std::rc::Rc;
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ impl Auth {
|
||||||
match uapi::read(self.socket.fd.raw(), &mut self.buf[..]) {
|
match uapi::read(self.socket.fd.raw(), &mut self.buf[..]) {
|
||||||
Ok(n) => self.buf_stop = n.len(),
|
Ok(n) => self.buf_stop = n.len(),
|
||||||
Err(Errno(c::EAGAIN)) => {
|
Err(Errno(c::EAGAIN)) => {
|
||||||
let _ = self.socket.fd.readable().await;
|
self.socket.fd.readable().await?;
|
||||||
}
|
}
|
||||||
Err(e) => return Err(DbusError::ReadError(e.into())),
|
Err(e) => return Err(DbusError::ReadError(e.into())),
|
||||||
}
|
}
|
||||||
|
|
@ -99,7 +99,7 @@ impl Auth {
|
||||||
match uapi::write(self.socket.fd.raw(), &buf[start..]) {
|
match uapi::write(self.socket.fd.raw(), &buf[start..]) {
|
||||||
Ok(n) => start += n,
|
Ok(n) => start += n,
|
||||||
Err(Errno(c::EAGAIN)) => {
|
Err(Errno(c::EAGAIN)) => {
|
||||||
let _ = self.socket.fd.writable().await;
|
self.socket.fd.writable().await?;
|
||||||
}
|
}
|
||||||
Err(e) => return Err(DbusError::WriteError(e.into())),
|
Err(e) => return Err(DbusError::WriteError(e.into())),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ impl DynamicType {
|
||||||
DynamicType::U32 => Variant::U32(parser.read_pod()?),
|
DynamicType::U32 => Variant::U32(parser.read_pod()?),
|
||||||
DynamicType::I64 => Variant::I64(parser.read_pod()?),
|
DynamicType::I64 => Variant::I64(parser.read_pod()?),
|
||||||
DynamicType::U64 => Variant::U64(parser.read_pod()?),
|
DynamicType::U64 => Variant::U64(parser.read_pod()?),
|
||||||
DynamicType::F64 => Variant::F64(parser.read_pod()?),
|
DynamicType::F64 => Variant::F64(f64::from_bits(parser.read_pod()?)),
|
||||||
DynamicType::String => Variant::String(parser.read_string()?),
|
DynamicType::String => Variant::String(parser.read_string()?),
|
||||||
DynamicType::ObjectPath => Variant::ObjectPath(parser.read_object_path()?),
|
DynamicType::ObjectPath => Variant::ObjectPath(parser.read_object_path()?),
|
||||||
DynamicType::Signature => Variant::Signature(parser.read_signature()?),
|
DynamicType::Signature => Variant::Signature(parser.read_signature()?),
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ fn connect(
|
||||||
dead: Cell::new(false),
|
dead: Cell::new(false),
|
||||||
headers: Default::default(),
|
headers: Default::default(),
|
||||||
run_toplevel: run_toplevel.clone(),
|
run_toplevel: run_toplevel.clone(),
|
||||||
|
signal_handlers: Default::default(),
|
||||||
});
|
});
|
||||||
let skt = socket.clone();
|
let skt = socket.clone();
|
||||||
socket.call(
|
socket.call(
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use super::{
|
||||||
HDR_SENDER, HDR_SIGNATURE, HDR_UNIX_FDS,
|
HDR_SENDER, HDR_SIGNATURE, HDR_UNIX_FDS,
|
||||||
};
|
};
|
||||||
use crate::dbus::{
|
use crate::dbus::{
|
||||||
CallError, DbusError, DbusSocket, Headers, Parser, MSG_ERROR, MSG_METHOD_RETURN,
|
CallError, DbusError, DbusSocket, Headers, Parser, MSG_ERROR, MSG_METHOD_RETURN, MSG_SIGNAL,
|
||||||
};
|
};
|
||||||
use crate::utils::ptr_ext::{MutPtrExt, PtrExt};
|
use crate::utils::ptr_ext::{MutPtrExt, PtrExt};
|
||||||
use crate::ErrorFmt;
|
use crate::ErrorFmt;
|
||||||
|
|
@ -119,8 +119,8 @@ impl Incoming {
|
||||||
log::error!(
|
log::error!(
|
||||||
"{}: Message reply has an invalid signature: expected: {}, actual: {}",
|
"{}: Message reply has an invalid signature: expected: {}, actual: {}",
|
||||||
self.socket.bus_name,
|
self.socket.bus_name,
|
||||||
|
reply.signature(),
|
||||||
sig,
|
sig,
|
||||||
reply.signature()
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let buf = unsafe { std::mem::take(msg_buf_data.get().deref_mut()) };
|
let buf = unsafe { std::mem::take(msg_buf_data.get().deref_mut()) };
|
||||||
|
|
@ -135,6 +135,39 @@ impl Incoming {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
MSG_SIGNAL => {
|
||||||
|
let (interface, member, path) =
|
||||||
|
match (&headers.interface, &headers.member, &headers.path) {
|
||||||
|
(Some(i), Some(m), Some(p)) => (i, m, p),
|
||||||
|
_ => return Err(DbusError::MissingSignalHeaders),
|
||||||
|
};
|
||||||
|
let handlers = self.socket.signal_handlers.borrow_mut();
|
||||||
|
if let Some(handler) = handlers.get(&(interface.deref(), member.deref())) {
|
||||||
|
let handler = handler
|
||||||
|
.conditional
|
||||||
|
.get(path.deref())
|
||||||
|
.or(handler.unconditional.as_ref());
|
||||||
|
if let Some(handler) = handler {
|
||||||
|
let sig = headers.signature.as_deref().unwrap_or("");
|
||||||
|
if sig != handler.signature() {
|
||||||
|
log::error!(
|
||||||
|
"{}: Signal has an invalid signature: expected: {}, actual: {}",
|
||||||
|
self.socket.bus_name,
|
||||||
|
handler.signature(),
|
||||||
|
sig,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if let Err(e) = handler.handle(&mut parser) {
|
||||||
|
log::error!(
|
||||||
|
"{}: Could not handle signal: {}",
|
||||||
|
self.socket.bus_name,
|
||||||
|
ErrorFmt(e)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
let msg_buf = msg_buf_data.into_inner();
|
let msg_buf = msg_buf_data.into_inner();
|
||||||
|
|
@ -174,7 +207,7 @@ impl Incoming {
|
||||||
if e.0 != c::EAGAIN {
|
if e.0 != c::EAGAIN {
|
||||||
return Err(DbusError::ReadError(e.into()));
|
return Err(DbusError::ReadError(e.into()));
|
||||||
}
|
}
|
||||||
let _ = self.socket.fd.readable().await;
|
self.socket.fd.readable().await?;
|
||||||
}
|
}
|
||||||
if self.buf_start == self.buf_end {
|
if self.buf_start == self.buf_end {
|
||||||
return Err(DbusError::Closed);
|
return Err(DbusError::Closed);
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,11 @@ impl Outgoing {
|
||||||
self.socket.kill();
|
self.socket.kill();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let _ = self.socket.fd.writable().await;
|
if let Err(e) = self.socket.fd.writable().await {
|
||||||
|
log::error!("{}: Cannot wait for fd to become readable: {}", self.socket.bus_name, ErrorFmt(e));
|
||||||
|
self.socket.kill();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,15 @@ use crate::dbus::property::Get;
|
||||||
use crate::dbus::types::{ObjectPath, Signature, Variant};
|
use crate::dbus::types::{ObjectPath, Signature, Variant};
|
||||||
use crate::dbus::{
|
use crate::dbus::{
|
||||||
AsyncProperty, AsyncReply, AsyncReplySlot, DbusError, DbusMessage, DbusSocket, DbusType,
|
AsyncProperty, AsyncReply, AsyncReplySlot, DbusError, DbusMessage, DbusSocket, DbusType,
|
||||||
Formatter, Headers, Message, MethodCall, Parser, Property, Reply, ReplyHandler,
|
Formatter, Headers, InterfaceSignalHandlers, Message, MethodCall, Parser, Property, Reply,
|
||||||
|
ReplyHandler, Signal, SignalHandler, SignalHandlerApi, SignalHandlerData, BUS_DEST, BUS_PATH,
|
||||||
HDR_DESTINATION, HDR_INTERFACE, HDR_MEMBER, HDR_PATH, HDR_SIGNATURE, HDR_UNIX_FDS,
|
HDR_DESTINATION, HDR_INTERFACE, HDR_MEMBER, HDR_PATH, HDR_SIGNATURE, HDR_UNIX_FDS,
|
||||||
MSG_METHOD_CALL, NO_REPLY_EXPECTED,
|
MSG_METHOD_CALL, NO_REPLY_EXPECTED,
|
||||||
};
|
};
|
||||||
|
use crate::{org, ErrorFmt};
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
use std::collections::hash_map::Entry;
|
||||||
|
use std::fmt::Write;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
|
|
@ -116,6 +120,118 @@ impl DbusSocket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn handle_signal<T, F>(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
sender: Option<&str>,
|
||||||
|
path: Option<&str>,
|
||||||
|
handler: F,
|
||||||
|
) -> Result<SignalHandler, DbusError>
|
||||||
|
where
|
||||||
|
T: Signal<'static>,
|
||||||
|
F: for<'a> Fn(T::Generic<'a>) + 'static,
|
||||||
|
{
|
||||||
|
let mut rule = format!(
|
||||||
|
"type='signal',interface='{}',member='{}'",
|
||||||
|
T::INTERFACE,
|
||||||
|
T::MEMBER
|
||||||
|
);
|
||||||
|
if let Some(sender) = sender {
|
||||||
|
let _ = write!(rule, ",sender='{}'", sender);
|
||||||
|
}
|
||||||
|
if let Some(path) = path {
|
||||||
|
let _ = write!(rule, ",path='{}'", path);
|
||||||
|
}
|
||||||
|
let shd: SignalHandlerData<T, _> = SignalHandlerData {
|
||||||
|
path: path.map(|s| s.to_owned()),
|
||||||
|
rule,
|
||||||
|
handler,
|
||||||
|
_phantom: Default::default(),
|
||||||
|
};
|
||||||
|
self.handle_signal_dyn(Rc::new(shd))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_signal_dyn(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
handler: Rc<dyn SignalHandlerApi>,
|
||||||
|
) -> Result<SignalHandler, DbusError> {
|
||||||
|
let mut sh = self.signal_handlers.borrow_mut();
|
||||||
|
let entry = sh
|
||||||
|
.entry((handler.interface(), handler.member()))
|
||||||
|
.or_insert_with(|| InterfaceSignalHandlers {
|
||||||
|
unconditional: Default::default(),
|
||||||
|
conditional: Default::default(),
|
||||||
|
});
|
||||||
|
match handler.path() {
|
||||||
|
Some(p) => match entry.conditional.entry(p.to_owned()) {
|
||||||
|
Entry::Occupied(_) => return Err(DbusError::AlreadyHandled),
|
||||||
|
Entry::Vacant(v) => {
|
||||||
|
v.insert(handler.clone());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ if entry.unconditional.is_some() => return Err(DbusError::AlreadyHandled),
|
||||||
|
_ => entry.unconditional = Some(handler.clone()),
|
||||||
|
}
|
||||||
|
self.call(
|
||||||
|
BUS_DEST,
|
||||||
|
BUS_PATH,
|
||||||
|
org::freedesktop::dbus::AddMatch {
|
||||||
|
rule: handler.rule().into(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
let slf = self.clone();
|
||||||
|
move |res| {
|
||||||
|
if let Err(e) = res {
|
||||||
|
log::error!(
|
||||||
|
"{}: Could not register a signal handler: {}",
|
||||||
|
slf.bus_name,
|
||||||
|
ErrorFmt(e)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
Ok(SignalHandler {
|
||||||
|
socket: self.clone(),
|
||||||
|
data: handler,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn remove_signal_handler(self: &Rc<Self>, handler: &dyn SignalHandlerApi) {
|
||||||
|
let mut sh = self.signal_handlers.borrow_mut();
|
||||||
|
let mut entry = match sh.entry((handler.interface(), handler.member())) {
|
||||||
|
Entry::Occupied(o) => o,
|
||||||
|
Entry::Vacant(_) => return,
|
||||||
|
};
|
||||||
|
match handler.path() {
|
||||||
|
Some(p) => {
|
||||||
|
entry.get_mut().conditional.remove(p);
|
||||||
|
}
|
||||||
|
_ => entry.get_mut().unconditional = None,
|
||||||
|
}
|
||||||
|
if entry.get().unconditional.is_none() && entry.get().conditional.is_empty() {
|
||||||
|
entry.remove();
|
||||||
|
}
|
||||||
|
self.call(
|
||||||
|
BUS_DEST,
|
||||||
|
BUS_PATH,
|
||||||
|
org::freedesktop::dbus::RemoveMatch {
|
||||||
|
rule: handler.rule().into(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
let slf = self.clone();
|
||||||
|
move |res| {
|
||||||
|
if let Err(e) = res {
|
||||||
|
log::error!(
|
||||||
|
"{}: Could not unregister a signal handler: {}",
|
||||||
|
slf.bus_name,
|
||||||
|
ErrorFmt(e)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn send_call<'a, T: Message<'a>>(
|
fn send_call<'a, T: Message<'a>>(
|
||||||
&self,
|
&self,
|
||||||
path: &str,
|
path: &str,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ use crate::dbus::{
|
||||||
TY_INT16, TY_INT32, TY_INT64, TY_OBJECT_PATH, TY_SIGNATURE, TY_STRING, TY_UINT16, TY_UINT32,
|
TY_INT16, TY_INT32, TY_INT64, TY_OBJECT_PATH, TY_SIGNATURE, TY_STRING, TY_UINT16, TY_UINT32,
|
||||||
TY_UINT64, TY_UNIX_FD, TY_VARIANT,
|
TY_UINT64, TY_UNIX_FD, TY_VARIANT,
|
||||||
};
|
};
|
||||||
use crate::utils::aligned::{AlignedF64, AlignedI64, AlignedU64};
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
@ -139,7 +138,7 @@ unsafe impl<'a> DbusType<'a> for u32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'a> DbusType<'a> for AlignedI64 {
|
unsafe impl<'a> DbusType<'a> for i64 {
|
||||||
const ALIGNMENT: usize = 8;
|
const ALIGNMENT: usize = 8;
|
||||||
const IS_POD: bool = true;
|
const IS_POD: bool = true;
|
||||||
type Generic<'b> = Self;
|
type Generic<'b> = Self;
|
||||||
|
|
@ -155,7 +154,7 @@ unsafe impl<'a> DbusType<'a> for AlignedI64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'a> DbusType<'a> for AlignedU64 {
|
unsafe impl<'a> DbusType<'a> for u64 {
|
||||||
const ALIGNMENT: usize = 8;
|
const ALIGNMENT: usize = 8;
|
||||||
const IS_POD: bool = true;
|
const IS_POD: bool = true;
|
||||||
type Generic<'b> = Self;
|
type Generic<'b> = Self;
|
||||||
|
|
@ -171,7 +170,7 @@ unsafe impl<'a> DbusType<'a> for AlignedU64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'a> DbusType<'a> for AlignedF64 {
|
unsafe impl<'a> DbusType<'a> for f64 {
|
||||||
const ALIGNMENT: usize = 8;
|
const ALIGNMENT: usize = 8;
|
||||||
const IS_POD: bool = true;
|
const IS_POD: bool = true;
|
||||||
type Generic<'b> = Self;
|
type Generic<'b> = Self;
|
||||||
|
|
@ -179,11 +178,11 @@ unsafe impl<'a> DbusType<'a> for AlignedF64 {
|
||||||
signature!(TY_DOUBLE);
|
signature!(TY_DOUBLE);
|
||||||
|
|
||||||
fn marshal(&self, fmt: &mut Formatter) {
|
fn marshal(&self, fmt: &mut Formatter) {
|
||||||
fmt.write_packed(self);
|
fmt.write_packed(&self.to_bits());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
|
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
|
||||||
parser.read_pod()
|
Ok(f64::from_bits(parser.read_pod()?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -417,9 +416,9 @@ pub enum Variant<'a> {
|
||||||
U16(u16),
|
U16(u16),
|
||||||
I32(i32),
|
I32(i32),
|
||||||
U32(u32),
|
U32(u32),
|
||||||
I64(AlignedI64),
|
I64(i64),
|
||||||
U64(AlignedU64),
|
U64(u64),
|
||||||
F64(AlignedF64),
|
F64(f64),
|
||||||
String(Cow<'a, str>),
|
String(Cow<'a, str>),
|
||||||
ObjectPath(ObjectPath<'a>),
|
ObjectPath(ObjectPath<'a>),
|
||||||
Signature(Signature<'a>),
|
Signature(Signature<'a>),
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,9 @@ impl EventLoop {
|
||||||
};
|
};
|
||||||
if let Some(fd) = entry.fd {
|
if let Some(fd) = entry.fd {
|
||||||
if let Err(e) = uapi::epoll_ctl(self.epoll.raw(), c::EPOLL_CTL_DEL, fd, None) {
|
if let Err(e) = uapi::epoll_ctl(self.epoll.raw(), c::EPOLL_CTL_DEL, fd, None) {
|
||||||
return Err(EventLoopError::RemoveFailed(e.into()));
|
if e.0 != c::ENOENT {
|
||||||
|
return Err(EventLoopError::RemoveFailed(e.into()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -234,8 +234,11 @@ impl ForkerProxy {
|
||||||
|
|
||||||
async fn check_process(self: Rc<Self>, state: Rc<State>) {
|
async fn check_process(self: Rc<Self>, state: Rc<State>) {
|
||||||
let pidfd = state.eng.fd(&self.pidfd).unwrap();
|
let pidfd = state.eng.fd(&self.pidfd).unwrap();
|
||||||
let _ = pidfd.readable().await;
|
if let Err(e) = pidfd.readable().await {
|
||||||
let _ = uapi::waitpid(self.pid, 0);
|
log::error!("Cannot wait for the forker pidfd to become readable: {}", ErrorFmt(e));
|
||||||
|
} else {
|
||||||
|
let _ = uapi::waitpid(self.pid, 0);
|
||||||
|
}
|
||||||
log::error!("The ol' forker died. Cannot spawn further processes.");
|
log::error!("The ol' forker died. Cannot spawn further processes.");
|
||||||
state.forker.set(None);
|
state.forker.set(None);
|
||||||
self.task_out.take();
|
self.task_out.take();
|
||||||
|
|
@ -413,14 +416,17 @@ impl Forker {
|
||||||
let slf = self.clone();
|
let slf = self.clone();
|
||||||
let spawn = self.ae.spawn(async move {
|
let spawn = self.ae.spawn(async move {
|
||||||
let read = slf.ae.fd(&Rc::new(read)).unwrap();
|
let read = slf.ae.fd(&Rc::new(read)).unwrap();
|
||||||
let _ = read.readable().await;
|
if let Err(e) = read.readable().await {
|
||||||
let mut s = String::new();
|
log::error!("Cannot wait for the child fd to become readable: {}", ErrorFmt(e));
|
||||||
let _ = Fd::new(read.raw()).read_to_string(&mut s);
|
} else {
|
||||||
if s.len() > 0 {
|
let mut s = String::new();
|
||||||
slf.outgoing.push(ForkerMessage::Log {
|
let _ = Fd::new(read.raw()).read_to_string(&mut s);
|
||||||
level: log::Level::Error as _,
|
if s.len() > 0 {
|
||||||
msg: format!("Could not spawn `{}`: {}", prog, s),
|
slf.outgoing.push(ForkerMessage::Log {
|
||||||
});
|
level: log::Level::Error as _,
|
||||||
|
msg: format!("Could not spawn `{}`: {}", prog, s),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
slf.pending_spawns.remove(&pid);
|
slf.pending_spawns.remove(&pid);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -157,13 +157,14 @@ impl WlSeatGlobal {
|
||||||
tree_changed_handler: Cell::new(None),
|
tree_changed_handler: Cell::new(None),
|
||||||
});
|
});
|
||||||
let seat = slf.clone();
|
let seat = slf.clone();
|
||||||
state.eng.spawn(async move {
|
let future = state.eng.spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
seat.tree_changed.triggered().await;
|
seat.tree_changed.triggered().await;
|
||||||
seat.state.tree_changed_sent.set(false);
|
seat.state.tree_changed_sent.set(false);
|
||||||
seat.tree_changed();
|
seat.tree_changed();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
slf.tree_changed_handler.set(Some(future));
|
||||||
slf
|
slf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
84
src/libinput.rs
Normal file
84
src/libinput.rs
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
use crate::udev::Udev;
|
||||||
|
use crate::utils::ptr_ext::PtrExt;
|
||||||
|
use std::ops::DerefMut;
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTERFACE: libinput_interface = libinput_interface {
|
||||||
|
open_restricted,
|
||||||
|
close_restricted,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe extern "C" fn open_restricted(
|
||||||
|
path: *const c::c_char,
|
||||||
|
flags: c::c_int,
|
||||||
|
user_data: *mut c::c_void,
|
||||||
|
) -> c::c_int {
|
||||||
|
let ud = (user_data as *const UserData).deref();
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn close_restricted(fd: c::c_int, _user_data: *mut c::c_void) {
|
||||||
|
drop(OwnedFd::new(fd));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UserData {}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum LibInputError {
|
||||||
|
#[error("Could not create a libinput instance")]
|
||||||
|
New,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LibInput {
|
||||||
|
data: Box<UserData>,
|
||||||
|
li: *mut libinput,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LibInput {
|
||||||
|
pub fn new() -> Result<Self, LibInputError> {
|
||||||
|
let mut ud = Box::new(UserData {});
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
Ok(Self { data: ud, li })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fd(&self) -> c::c_int {
|
||||||
|
unsafe { libinput_get_fd(self.li) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for LibInput {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
libinput_unref(self.li);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1 +1,79 @@
|
||||||
|
use crate::dbus::{DbusError, DbusSocket, Reply};
|
||||||
|
use crate::org::freedesktop::login1::session::TakeControlReply;
|
||||||
|
use crate::{org, FALSE};
|
||||||
|
use std::rc::Rc;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
const LOGIND_NAME: &str = "org.freedesktop.login1";
|
||||||
|
const MANAGER_PATH: &str = "/org/freedesktop/login1";
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum LogindError {
|
||||||
|
#[error("XDG_SESSION_ID is not set")]
|
||||||
|
XdgSessionId,
|
||||||
|
#[error("Could not retrieve the session dbus path")]
|
||||||
|
GetSession(DbusError),
|
||||||
|
#[error("Could not retrieve the session's seat name")]
|
||||||
|
GetSeatName(DbusError),
|
||||||
|
#[error(transparent)]
|
||||||
|
TakeControl(DbusError),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Session {
|
||||||
|
socket: Rc<DbusSocket>,
|
||||||
|
seat: String,
|
||||||
|
session_path: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Session {
|
||||||
|
pub async fn get(socket: &Rc<DbusSocket>) -> Result<Self, LogindError> {
|
||||||
|
let session_id = match std::env::var("XDG_SESSION_ID") {
|
||||||
|
Ok(id) => id,
|
||||||
|
_ => return Err(LogindError::XdgSessionId),
|
||||||
|
};
|
||||||
|
let session_path = {
|
||||||
|
let session = socket
|
||||||
|
.call_async(
|
||||||
|
LOGIND_NAME,
|
||||||
|
MANAGER_PATH,
|
||||||
|
org::freedesktop::login1::manager::GetSession {
|
||||||
|
session_id: session_id.as_str().into(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
match session {
|
||||||
|
Ok(s) => s.get().object_path.to_string(),
|
||||||
|
Err(e) => return Err(LogindError::GetSession(e)),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let seat = {
|
||||||
|
let seat = socket
|
||||||
|
.get_async::<org::freedesktop::login1::session::Seat>(LOGIND_NAME, &session_path)
|
||||||
|
.await;
|
||||||
|
match seat {
|
||||||
|
Ok(s) => s.get().0.to_string(),
|
||||||
|
Err(e) => return Err(LogindError::GetSeatName(e)),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(Self {
|
||||||
|
socket: socket.clone(),
|
||||||
|
seat,
|
||||||
|
session_path,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn take_control(&self) -> Result<(), LogindError> {
|
||||||
|
let res = self
|
||||||
|
.socket
|
||||||
|
.call_async(
|
||||||
|
LOGIND_NAME,
|
||||||
|
&self.session_path,
|
||||||
|
org::freedesktop::login1::session::TakeControl { force: FALSE },
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
match res {
|
||||||
|
Ok(r) => Ok(()),
|
||||||
|
Err(e) => Err(LogindError::TakeControl(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -330,6 +330,21 @@ macro_rules! assert_size_eq {
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! assert_size_le {
|
||||||
|
($t:ty, $u:ty) => {{
|
||||||
|
struct AssertLeSize<T, U>(std::marker::PhantomData<T>, std::marker::PhantomData<U>);
|
||||||
|
impl<T, U> AssertLeSize<T, U> {
|
||||||
|
const VAL: usize = {
|
||||||
|
if std::mem::size_of::<T>() > std::mem::size_of::<U>() {
|
||||||
|
panic!("Left type has size larger than right type");
|
||||||
|
}
|
||||||
|
1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let _ = AssertLeSize::<$t, $u>::VAL;
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! assert_align_eq {
|
macro_rules! assert_align_eq {
|
||||||
($t:ty, $u:ty) => {{
|
($t:ty, $u:ty) => {{
|
||||||
struct AssertEqAlign<T, U>(std::marker::PhantomData<T>, std::marker::PhantomData<U>);
|
struct AssertEqAlign<T, U>(std::marker::PhantomData<T>, std::marker::PhantomData<U>);
|
||||||
|
|
|
||||||
45
src/main.rs
45
src/main.rs
|
|
@ -3,7 +3,8 @@
|
||||||
thread_local,
|
thread_local,
|
||||||
label_break_value,
|
label_break_value,
|
||||||
try_blocks,
|
try_blocks,
|
||||||
generic_associated_types
|
generic_associated_types,
|
||||||
|
extern_types
|
||||||
)]
|
)]
|
||||||
#![allow(
|
#![allow(
|
||||||
clippy::len_zero,
|
clippy::len_zero,
|
||||||
|
|
@ -19,7 +20,7 @@ use crate::backends::dummy::DummyBackend;
|
||||||
use crate::backends::xorg::{XorgBackend, XorgBackendError};
|
use crate::backends::xorg::{XorgBackend, XorgBackendError};
|
||||||
use crate::client::Clients;
|
use crate::client::Clients;
|
||||||
use crate::clientmem::ClientMemError;
|
use crate::clientmem::ClientMemError;
|
||||||
use crate::dbus::{Dbus, FALSE};
|
use crate::dbus::{Dbus, FALSE, TRUE};
|
||||||
use crate::event_loop::EventLoopError;
|
use crate::event_loop::EventLoopError;
|
||||||
use crate::forker::ForkerError;
|
use crate::forker::ForkerError;
|
||||||
use crate::globals::Globals;
|
use crate::globals::Globals;
|
||||||
|
|
@ -36,6 +37,7 @@ use crate::state::State;
|
||||||
use crate::tree::{
|
use crate::tree::{
|
||||||
container_layout, container_titles, float_layout, float_titles, DisplayNode, NodeIds,
|
container_layout, container_titles, float_layout, float_titles, DisplayNode, NodeIds,
|
||||||
};
|
};
|
||||||
|
use crate::udev::Udev;
|
||||||
use crate::utils::clonecell::CloneCell;
|
use crate::utils::clonecell::CloneCell;
|
||||||
use crate::utils::errorfmt::ErrorFmt;
|
use crate::utils::errorfmt::ErrorFmt;
|
||||||
use crate::utils::numcell::NumCell;
|
use crate::utils::numcell::NumCell;
|
||||||
|
|
@ -53,6 +55,7 @@ use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wheel::Wheel;
|
use wheel::Wheel;
|
||||||
|
use crate::backends::metal;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
@ -75,6 +78,7 @@ mod forker;
|
||||||
mod format;
|
mod format;
|
||||||
mod globals;
|
mod globals;
|
||||||
mod ifs;
|
mod ifs;
|
||||||
|
mod libinput;
|
||||||
mod logind;
|
mod logind;
|
||||||
mod object;
|
mod object;
|
||||||
mod pixman;
|
mod pixman;
|
||||||
|
|
@ -88,6 +92,7 @@ mod text;
|
||||||
mod theme;
|
mod theme;
|
||||||
mod time;
|
mod time;
|
||||||
mod tree;
|
mod tree;
|
||||||
|
mod udev;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod wheel;
|
mod wheel;
|
||||||
mod wire;
|
mod wire;
|
||||||
|
|
@ -178,40 +183,10 @@ fn main_() -> Result<(), MainError> {
|
||||||
pending_float_titles: Default::default(),
|
pending_float_titles: Default::default(),
|
||||||
dbus: Dbus::new(&engine, &run_toplevel),
|
dbus: Dbus::new(&engine, &run_toplevel),
|
||||||
});
|
});
|
||||||
let _future = state.eng.spawn({
|
let _future = state.eng.spawn(metal::run(state.clone()));
|
||||||
let dbus = state.dbus.system().unwrap();
|
|
||||||
async move {
|
|
||||||
const LOGIND: &str = "org.freedesktop.login1";
|
|
||||||
let reply = dbus
|
|
||||||
.call_async(
|
|
||||||
LOGIND,
|
|
||||||
"/org/freedesktop/login1",
|
|
||||||
org::freedesktop::login1::manager::GetSession {
|
|
||||||
session_id: std::env::var("XDG_SESSION_ID").unwrap().into(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
let reply = dbus
|
|
||||||
.call_async(
|
|
||||||
LOGIND,
|
|
||||||
&reply.get().object_path,
|
|
||||||
org::freedesktop::login1::session::TakeControl { force: FALSE },
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
log::info!("{:?}", reply);
|
|
||||||
let reply = dbus
|
|
||||||
.get_async::<org::freedesktop::login1::manager::BootLoaderEntries>(
|
|
||||||
LOGIND,
|
|
||||||
"/org/freedesktop/login1",
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
log::info!("{:?}", reply);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
forker.install(&state);
|
forker.install(&state);
|
||||||
let backend = XorgBackend::new(&state)?;
|
// let backend = XorgBackend::new(&state)?;
|
||||||
state.backend.set(backend);
|
// state.backend.set(backend);
|
||||||
let config = config::ConfigProxy::default(&state);
|
let config = config::ConfigProxy::default(&state);
|
||||||
state.config.set(Some(Rc::new(config)));
|
state.config.set(Some(Rc::new(config)));
|
||||||
let _global_event_handler = engine.spawn(tasks::handle_backend_events(state.clone()));
|
let _global_event_handler = engine.spawn(tasks::handle_backend_events(state.clone()));
|
||||||
|
|
|
||||||
317
src/udev.rs
Normal file
317
src/udev.rs
Normal file
|
|
@ -0,0 +1,317 @@
|
||||||
|
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};
|
||||||
|
|
||||||
|
#[link(name = "udev")]
|
||||||
|
extern "C" {
|
||||||
|
type udev;
|
||||||
|
type udev_monitor;
|
||||||
|
type udev_enumerate;
|
||||||
|
type udev_list_entry;
|
||||||
|
type udev_device;
|
||||||
|
|
||||||
|
fn udev_new() -> *mut udev;
|
||||||
|
fn udev_unref(udev: *mut udev) -> *mut udev;
|
||||||
|
|
||||||
|
fn udev_monitor_new_from_netlink(udev: *mut udev, name: *const c::c_char) -> *mut udev_monitor;
|
||||||
|
fn udev_monitor_get_fd(udev_monitor: *mut udev_monitor) -> c::c_int;
|
||||||
|
fn udev_monitor_unref(udev_monitor: *mut udev_monitor) -> *mut udev_monitor;
|
||||||
|
fn udev_monitor_enable_receiving(udev_monitor: *mut udev_monitor) -> c::c_int;
|
||||||
|
fn udev_monitor_filter_add_match_subsystem_devtype(
|
||||||
|
udev_monitor: *mut udev_monitor,
|
||||||
|
subsystem: *const c::c_char,
|
||||||
|
devtype: *const c::c_char,
|
||||||
|
) -> c::c_int;
|
||||||
|
fn udev_monitor_receive_device(udev_monitor: *mut udev_monitor) -> *mut udev_device;
|
||||||
|
|
||||||
|
fn udev_enumerate_new(udev: *mut udev) -> *mut udev_enumerate;
|
||||||
|
fn udev_enumerate_unref(udev_enumerate: *mut udev_enumerate) -> *mut udev_enumerate;
|
||||||
|
fn udev_enumerate_add_match_subsystem(
|
||||||
|
udev_enumerate: *mut udev_enumerate,
|
||||||
|
subsystem: *const c::c_char,
|
||||||
|
) -> c::c_int;
|
||||||
|
fn udev_enumerate_scan_devices(udev_enumerate: *mut udev_enumerate) -> c::c_int;
|
||||||
|
fn udev_enumerate_get_list_entry(udev_enumerate: *mut udev_enumerate) -> *mut udev_list_entry;
|
||||||
|
|
||||||
|
fn udev_list_entry_get_next(list_entry: *mut udev_list_entry) -> *mut udev_list_entry;
|
||||||
|
fn udev_list_entry_get_name(list_entry: *mut udev_list_entry) -> *const c::c_char;
|
||||||
|
fn udev_list_entry_get_value(list_entry: *mut udev_list_entry) -> *const c::c_char;
|
||||||
|
|
||||||
|
fn udev_device_new_from_syspath(udev: *mut udev, syspath: *const c::c_char)
|
||||||
|
-> *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_is_initialized(udev_device: *mut udev_device) -> c::c_int;
|
||||||
|
fn udev_device_get_devnode(udev_device: *mut udev_device) -> *const c::c_char;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum UdevError {
|
||||||
|
#[error("Could not create a new udev instance")]
|
||||||
|
New(#[source] std::io::Error),
|
||||||
|
#[error("Could not create a new udev_monitor instance")]
|
||||||
|
NewMonitor(#[source] std::io::Error),
|
||||||
|
#[error("Could not create a new udev_enumerate instance")]
|
||||||
|
NewEnumerate(#[source] std::io::Error),
|
||||||
|
#[error("Could not enable receiving on a udev_monitor")]
|
||||||
|
EnableReceiving(#[source] std::io::Error),
|
||||||
|
#[error("Could not add a match rule to a udev_monitor")]
|
||||||
|
MonitorAddMatch(#[source] std::io::Error),
|
||||||
|
#[error("Could not add a match rule to a udev_enumerate")]
|
||||||
|
EnumerateAddMatch(#[source] std::io::Error),
|
||||||
|
#[error("Could not list devices of a udev_enumerate")]
|
||||||
|
EnumerateGetListEntry(#[source] std::io::Error),
|
||||||
|
#[error("Could not scan devices of a udev_enumerate")]
|
||||||
|
ScanDevices(#[source] std::io::Error),
|
||||||
|
#[error("Could not create a udev_device from a syspath")]
|
||||||
|
DeviceFromSyspath(#[source] std::io::Error),
|
||||||
|
#[error("Could not retrieve the sysname of a udev_device")]
|
||||||
|
GetSysname(#[source] std::io::Error),
|
||||||
|
#[error("Could not retrieve the devnode of a udev_device")]
|
||||||
|
GetDevnode(#[source] std::io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Udev {
|
||||||
|
udev: *mut udev,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UdevMonitor {
|
||||||
|
udev: Rc<Udev>,
|
||||||
|
monitor: *mut udev_monitor,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UdevEnumerate {
|
||||||
|
udev: Rc<Udev>,
|
||||||
|
enumerate: *mut udev_enumerate,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UdevListEntry<'a> {
|
||||||
|
list_entry: *mut udev_list_entry,
|
||||||
|
_phantom: PhantomData<&'a mut ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UdevDevice {
|
||||||
|
udev: Rc<Udev>,
|
||||||
|
device: *mut udev_device,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Udev {
|
||||||
|
pub fn new() -> Result<Self, UdevError> {
|
||||||
|
let res = unsafe { udev_new() };
|
||||||
|
if res.is_null() {
|
||||||
|
return Err(UdevError::New(Errno::default().into()));
|
||||||
|
}
|
||||||
|
Ok(Self { udev: res })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_monitor(self: &Rc<Self>) -> Result<UdevMonitor, UdevError> {
|
||||||
|
let res = unsafe { udev_monitor_new_from_netlink(self.udev, "udev\0".as_ptr() as _) };
|
||||||
|
if res.is_null() {
|
||||||
|
return Err(UdevError::NewMonitor(Errno::default().into()));
|
||||||
|
}
|
||||||
|
Ok(UdevMonitor {
|
||||||
|
udev: self.clone(),
|
||||||
|
monitor: res,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_enumerate(self: &Rc<Self>) -> Result<UdevEnumerate, UdevError> {
|
||||||
|
let res = unsafe { udev_enumerate_new(self.udev) };
|
||||||
|
if res.is_null() {
|
||||||
|
return Err(UdevError::NewEnumerate(Errno::default().into()));
|
||||||
|
}
|
||||||
|
Ok(UdevEnumerate {
|
||||||
|
udev: self.clone(),
|
||||||
|
enumerate: res,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_device_from_syspath<'a>(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
syspath: impl IntoUstr<'a>,
|
||||||
|
) -> Result<UdevDevice, UdevError> {
|
||||||
|
let syspath = syspath.into_ustr();
|
||||||
|
let res = unsafe { udev_device_new_from_syspath(self.udev, syspath.as_ptr()) };
|
||||||
|
if res.is_null() {
|
||||||
|
return Err(UdevError::DeviceFromSyspath(Errno::default().into()));
|
||||||
|
}
|
||||||
|
Ok(UdevDevice {
|
||||||
|
udev: self.clone(),
|
||||||
|
device: res,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Udev {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
udev_unref(self.udev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UdevMonitor {
|
||||||
|
pub fn fd(&self) -> c::c_int {
|
||||||
|
unsafe { udev_monitor_get_fd(self.monitor) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable_receiving(&self) -> Result<(), UdevError> {
|
||||||
|
let res = unsafe { udev_monitor_enable_receiving(self.monitor) };
|
||||||
|
if res < 0 {
|
||||||
|
Err(UdevError::EnableReceiving(Errno(-res).into()))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_match_subsystem_devtype(
|
||||||
|
&self,
|
||||||
|
subsystem: Option<&str>,
|
||||||
|
devtype: Option<&str>,
|
||||||
|
) -> Result<(), UdevError> {
|
||||||
|
let subsystem = subsystem.map(|s| s.into_ustr());
|
||||||
|
let devtype = devtype.map(|s| s.into_ustr());
|
||||||
|
let res = unsafe {
|
||||||
|
udev_monitor_filter_add_match_subsystem_devtype(
|
||||||
|
self.monitor,
|
||||||
|
subsystem
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.as_ptr())
|
||||||
|
.unwrap_or(ptr::null()),
|
||||||
|
devtype.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null()),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if res < 0 {
|
||||||
|
Err(UdevError::MonitorAddMatch(Errno(-res).into()))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn receive_device(&self) -> Option<UdevDevice> {
|
||||||
|
let res = unsafe {
|
||||||
|
udev_monitor_receive_device(self.monitor)
|
||||||
|
};
|
||||||
|
if res.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(UdevDevice {
|
||||||
|
udev: self.udev.clone(),
|
||||||
|
device: res,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for UdevMonitor {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
udev_monitor_unref(self.monitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UdevEnumerate {
|
||||||
|
pub fn add_match_subsystem(&self, subsystem: &str) -> Result<(), UdevError> {
|
||||||
|
let subsystem = subsystem.into_ustr();
|
||||||
|
let res = unsafe { udev_enumerate_add_match_subsystem(self.enumerate, subsystem.as_ptr()) };
|
||||||
|
if res < 0 {
|
||||||
|
Err(UdevError::EnumerateAddMatch(Errno(-res).into()))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scan_devices(&self) -> Result<(), UdevError> {
|
||||||
|
let res = unsafe { udev_enumerate_scan_devices(self.enumerate) };
|
||||||
|
if res < 0 {
|
||||||
|
Err(UdevError::ScanDevices(Errno(-res).into()))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_list_entry(&mut self) -> Result<Option<UdevListEntry>, UdevError> {
|
||||||
|
let res = unsafe { udev_enumerate_get_list_entry(self.enumerate) };
|
||||||
|
if res.is_null() {
|
||||||
|
let err = Errno::default();
|
||||||
|
if err.0 == c::ENODATA {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Err(UdevError::EnumerateGetListEntry(err.into()))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(Some(UdevListEntry {
|
||||||
|
list_entry: res,
|
||||||
|
_phantom: Default::default(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for UdevEnumerate {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
udev_enumerate_unref(self.enumerate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> UdevListEntry<'a> {
|
||||||
|
pub fn next(self) -> Option<Self> {
|
||||||
|
unsafe {
|
||||||
|
let res = udev_list_entry_get_next(self.list_entry);
|
||||||
|
if res.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Self {
|
||||||
|
list_entry: res,
|
||||||
|
_phantom: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &CStr {
|
||||||
|
unsafe {
|
||||||
|
let s = udev_list_entry_get_name(self.list_entry);
|
||||||
|
CStr::from_ptr(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UdevDevice {
|
||||||
|
pub fn sysname(&self) -> Result<&CStr, UdevError> {
|
||||||
|
let res = unsafe { udev_device_get_sysname(self.device) };
|
||||||
|
if res.is_null() {
|
||||||
|
Err(UdevError::GetSysname(Errno::default().into()))
|
||||||
|
} else {
|
||||||
|
unsafe { Ok(CStr::from_ptr(res)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn devnode(&self) -> Result<&CStr, UdevError> {
|
||||||
|
let res = unsafe { udev_device_get_devnode(self.device) };
|
||||||
|
if res.is_null() {
|
||||||
|
Err(UdevError::GetDevnode(Errno::default().into()))
|
||||||
|
} else {
|
||||||
|
unsafe { Ok(CStr::from_ptr(res)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_initialized(&self) -> bool {
|
||||||
|
unsafe { udev_device_get_is_initialized(self.device) != 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for UdevDevice {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
udev_device_unref(self.device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
use uapi::{Packed, Pod};
|
|
||||||
|
|
||||||
#[repr(C, align(8))]
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
||||||
pub struct AlignedI64(pub i64);
|
|
||||||
|
|
||||||
unsafe impl Pod for AlignedI64 {}
|
|
||||||
unsafe impl Packed for AlignedI64 {}
|
|
||||||
|
|
||||||
#[repr(C, align(8))]
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
||||||
pub struct AlignedU64(pub u64);
|
|
||||||
|
|
||||||
unsafe impl Pod for AlignedU64 {}
|
|
||||||
unsafe impl Packed for AlignedU64 {}
|
|
||||||
|
|
||||||
#[repr(C, align(8))]
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
|
||||||
pub struct AlignedF64(pub f64);
|
|
||||||
|
|
||||||
unsafe impl Pod for AlignedF64 {}
|
|
||||||
unsafe impl Packed for AlignedF64 {}
|
|
||||||
28
src/utils/bitfield.rs
Normal file
28
src/utils/bitfield.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
const SEG_SIZE: usize = 8 * mem::size_of::<usize>();
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Bitfield {
|
||||||
|
vals: Vec<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bitfield {
|
||||||
|
pub fn acquire(&mut self) -> u32 {
|
||||||
|
for (idx, n) in self.vals.iter_mut().enumerate() {
|
||||||
|
if *n != 0 {
|
||||||
|
let pos = n.trailing_zeros();
|
||||||
|
*n &= !(1 << pos);
|
||||||
|
return (idx * SEG_SIZE) as u32 + pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.vals.push(!1);
|
||||||
|
((self.vals.len() - 1) * SEG_SIZE) as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release(&mut self, val: u32) {
|
||||||
|
let idx = val as usize / SEG_SIZE;
|
||||||
|
let pos = val as usize % SEG_SIZE;
|
||||||
|
self.vals[idx] |= 1 << pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -101,7 +101,9 @@ impl BufFdOut {
|
||||||
_ = timeout.as_mut().unwrap() => {
|
_ = timeout.as_mut().unwrap() => {
|
||||||
return Err(BufFdError::Timeout);
|
return Err(BufFdError::Timeout);
|
||||||
},
|
},
|
||||||
res = self.fd.writable().fuse() => res?,
|
res = self.fd.writable().fuse() => {
|
||||||
|
res?;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
pub mod aligned;
|
|
||||||
pub mod array;
|
pub mod array;
|
||||||
pub mod asyncevent;
|
pub mod asyncevent;
|
||||||
pub mod bitflags;
|
pub mod bitflags;
|
||||||
|
|
@ -18,3 +17,4 @@ pub mod stack;
|
||||||
pub mod tri;
|
pub mod tri;
|
||||||
pub mod vec_ext;
|
pub mod vec_ext;
|
||||||
pub mod vecstorage;
|
pub mod vecstorage;
|
||||||
|
pub mod bitfield;
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ pub async fn manage(state: Rc<State>) {
|
||||||
log::info!("Allocated display :{} for Xwayland", xsocket.id);
|
log::info!("Allocated display :{} for Xwayland", xsocket.id);
|
||||||
log::info!("Waiting for connection attempt");
|
log::info!("Waiting for connection attempt");
|
||||||
let res = XWaylandError::tria(async {
|
let res = XWaylandError::tria(async {
|
||||||
let _ = state.eng.fd(&socket)?.readable().await;
|
state.eng.fd(&socket)?.readable().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
@ -168,13 +168,13 @@ async fn run(
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(e) => return Err(XWaylandError::SpawnClient(e)),
|
Err(e) => return Err(XWaylandError::SpawnClient(e)),
|
||||||
};
|
};
|
||||||
let _ = state.eng.fd(&Rc::new(dfdread))?.readable().await;
|
state.eng.fd(&Rc::new(dfdread))?.readable().await?;
|
||||||
let wm = match Wm::get(state, client, wm1, queue.clone()) {
|
let wm = match Wm::get(state, client, wm1, queue.clone()) {
|
||||||
Ok(w) => w,
|
Ok(w) => w,
|
||||||
Err(e) => return Err(XWaylandError::CreateWm(Box::new(e))),
|
Err(e) => return Err(XWaylandError::CreateWm(Box::new(e))),
|
||||||
};
|
};
|
||||||
let wm = state.eng.spawn(wm.run());
|
let wm = state.eng.spawn(wm.run());
|
||||||
let _ = state.eng.fd(&Rc::new(pidfd))?.readable().await;
|
state.eng.fd(&Rc::new(pidfd))?.readable().await?;
|
||||||
drop(wm);
|
drop(wm);
|
||||||
queue.clear();
|
queue.clear();
|
||||||
stderr_read.await;
|
stderr_read.await;
|
||||||
|
|
@ -223,7 +223,10 @@ async fn log_xwayland(state: Rc<State>, stderr: OwnedFd) {
|
||||||
let mut buf2 = [0; 128];
|
let mut buf2 = [0; 128];
|
||||||
let mut done = false;
|
let mut done = false;
|
||||||
while !done {
|
while !done {
|
||||||
let _ = afd.readable().await;
|
if let Err(e) = afd.readable().await {
|
||||||
|
log::error!("Cannot wait for the xwayland stderr to become readable: {}", ErrorFmt(e));
|
||||||
|
return;
|
||||||
|
}
|
||||||
loop {
|
loop {
|
||||||
match uapi::read(afd.raw(), &mut buf2[..]) {
|
match uapi::read(afd.raw(), &mut buf2[..]) {
|
||||||
Ok(buf2) if buf2.len() > 0 => {
|
Ok(buf2) if buf2.len() > 0 => {
|
||||||
|
|
|
||||||
|
|
@ -247,7 +247,12 @@ impl Wm {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
futures::select! {
|
futures::select! {
|
||||||
_ = self.socket.readable().fuse() => { },
|
res = self.socket.readable().fuse() => {
|
||||||
|
if let Err(e) = res {
|
||||||
|
log::error!("Cannot wait for xwm fd to become readable: {}", ErrorFmt(e));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
_ = self.queue.non_empty().fuse() => { },
|
_ = self.queue.non_empty().fuse() => { },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
fn Hello() {
|
fn Hello() {
|
||||||
name: string,
|
name: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn AddMatch(rule: string) { }
|
||||||
|
|
||||||
|
fn RemoveMatch(rule: string) { }
|
||||||
|
|
|
||||||
|
|
@ -5,3 +5,4 @@ fn GetSession(
|
||||||
}
|
}
|
||||||
|
|
||||||
prop BootLoaderEntries = array(string)
|
prop BootLoaderEntries = array(string)
|
||||||
|
prop ScheduledShutdown = struct(string, u64)
|
||||||
|
|
|
||||||
|
|
@ -8,3 +8,16 @@ fn TakeDevice(major: u32, minor: u32) {
|
||||||
|
|
||||||
fn PauseDeviceComplete(major: u32, minor: u32) { }
|
fn PauseDeviceComplete(major: u32, minor: u32) { }
|
||||||
|
|
||||||
|
prop Seat = struct(string, object_path)
|
||||||
|
|
||||||
|
sig PauseDevice {
|
||||||
|
major: u32,
|
||||||
|
minor: u32,
|
||||||
|
ty: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
sig ResumeDevice {
|
||||||
|
major: u32,
|
||||||
|
minor: u32,
|
||||||
|
fd: fd,
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue