1
0
Fork 0
forked from wry/wry

autocommit 2022-03-22 23:24:17 CET

This commit is contained in:
Julian Orth 2022-03-22 23:24:17 +01:00
parent 18806a38fb
commit 2ff60ff817
36 changed files with 4934 additions and 237 deletions

View file

@ -9,6 +9,7 @@ mod enums;
mod tokens;
mod wire;
mod wire_dbus;
mod wire_xcon;
fn open(s: &str) -> io::Result<BufWriter<File>> {
let mut path = PathBuf::from(env::var("OUT_DIR").unwrap());
@ -25,6 +26,7 @@ fn open(s: &str) -> io::Result<BufWriter<File>> {
fn main() -> anyhow::Result<()> {
wire::main()?;
wire_dbus::main()?;
wire_xcon::main()?;
enums::main()?;
println!("cargo:rerun-if-changed=build/build.rs");

View file

@ -1,5 +1,5 @@
use anyhow::{bail, Context, Result};
use bstr::{BStr, ByteSlice};
use bstr::{BStr, BString, ByteSlice};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum TreeDelim {
@ -27,7 +27,9 @@ impl TreeDelim {
pub enum Symbol {
Comma,
Colon,
Semicolon,
Equals,
At,
}
impl Symbol {
@ -36,17 +38,19 @@ impl Symbol {
Symbol::Comma => "','",
Symbol::Colon => "':'",
Symbol::Equals => "'='",
Symbol::At => "'@'",
Symbol::Semicolon => "';'",
}
}
}
#[derive(Debug)]
#[derive(Debug, Eq, PartialEq)]
pub struct Token<'a> {
pub line: u32,
pub kind: TokenKind<'a>,
}
#[derive(Debug)]
#[derive(Debug, Eq, PartialEq)]
pub enum TokenKind<'a> {
Ident(&'a BStr),
Num(u32),
@ -55,6 +59,7 @@ pub enum TokenKind<'a> {
body: Vec<Token<'a>>,
},
Symbol(Symbol),
String(BString),
}
impl TokenKind<'_> {
@ -67,6 +72,7 @@ impl TokenKind<'_> {
TreeDelim::Brace => "'{'-tree",
},
TokenKind::Symbol(s) => s.name(),
TokenKind::String(_) => "string",
}
}
}
@ -153,7 +159,9 @@ impl<'a> Tokenizer<'a> {
}
b',' => TokenKind::Symbol(Symbol::Comma),
b'=' => TokenKind::Symbol(Symbol::Equals),
b'@' => TokenKind::Symbol(Symbol::At),
b':' => TokenKind::Symbol(Symbol::Colon),
b';' => TokenKind::Symbol(Symbol::Semicolon),
b'(' => self.tokenize_tree(TreeDelim::Paren)?,
b'{' => self.tokenize_tree(TreeDelim::Brace)?,
c @ (b')' | b'}') => {
@ -162,6 +170,37 @@ impl<'a> Tokenizer<'a> {
}
return Ok(false);
}
b'"' => {
let mut res = vec![];
let mut escaped = false;
while !c.eof() {
let char = c.s[c.pos];
if char == b'\\' {
escaped = true;
} else if escaped {
escaped = false;
if matches!(char, b'"' | b'\\') {
res.push(char);
} else {
bail!(
"Unexpected escape sequence '\\{}' in line {}",
char,
self.line
);
}
} else if char == b'"' {
break;
} else {
res.push(char);
}
c.pos += 1;
}
if c.eof() {
bail!("Unterminated string in line {}", self.line);
}
c.pos += 1;
TokenKind::String(res.into())
}
_ => bail!("Unexpected byte {:?} in line {}", b as char, self.line),
};
self.res.push(Token { line, kind });

View file

@ -747,7 +747,13 @@ pub fn main() -> Result<()> {
println!("cargo:rerun-if-changed=wire-dbus");
let mut f = open("wire_dbus.rs")?;
for (_, child) in collect_interfaces()?.children {
let mut children: Vec<_> = collect_interfaces()?
.children
.into_iter()
.map(|v| v.1)
.collect();
children.sort_by(|c1, c2| c1.name.cmp(&c2.name));
for child in children {
write_element(&mut f, child, "")?;
}
Ok(())

1630
build/wire_xcon.rs Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,10 +1,16 @@
use jay_config::embedded::grab_input_device;
use jay_config::keyboard::mods::{Modifiers, ALT, CTRL, SHIFT};
use jay_config::keyboard::syms::{SYM_Super_L, SYM_b, SYM_comma, SYM_d, SYM_f, SYM_h, SYM_j, SYM_k, SYM_l, SYM_p, SYM_period, SYM_q, SYM_r, SYM_t, SYM_v, SYM_y, SYM_F1, SYM_F9, SYM_F12, SYM_F11, SYM_F10, SYM_F8, SYM_F7, SYM_F6, SYM_F5, SYM_F4, SYM_F3, SYM_F2};
use jay_config::keyboard::syms::{
SYM_Super_L, SYM_b, SYM_comma, SYM_d, SYM_f, SYM_h, SYM_j, SYM_k, SYM_l, SYM_p, SYM_period,
SYM_q, SYM_r, SYM_t, SYM_v, SYM_y, SYM_F1, SYM_F10, SYM_F11, SYM_F12, SYM_F2, SYM_F3, SYM_F4,
SYM_F5, SYM_F6, SYM_F7, SYM_F8, SYM_F9,
};
use jay_config::theme::{get_title_height, set_title_color, set_title_height, Color};
use jay_config::Axis::{Horizontal, Vertical};
use jay_config::Direction::{Down, Left, Right, Up};
use jay_config::{config, create_seat, input_devices, on_new_input_device, quit, Command, Seat, switch_to_vt};
use jay_config::{
config, create_seat, input_devices, on_new_input_device, quit, switch_to_vt, Command, Seat,
};
use rand::Rng;
const MOD: Modifiers = ALT;

View file

@ -28,8 +28,9 @@ pub enum Phase {
EventHandling,
Layout,
PostLayout,
Present,
}
const NUM_PHASES: usize = 3;
const NUM_PHASES: usize = 4;
pub struct AsyncEngine {
wheel: Rc<Wheel>,

View file

@ -237,7 +237,7 @@ impl InputDevice for MetalInputDevice {
}
fn grab(&self, _grab: bool) {
log::warn!("Metal backend does not support grabbing devices");
// nothing
}
}

View file

@ -1,2 +1,3 @@
pub mod metal;
pub mod xorg;
pub mod xorgng;

968
src/backends/xorgng.rs Normal file
View file

@ -0,0 +1,968 @@
use crate::async_engine::SpawnedFuture;
use crate::backend::{
Backend, BackendEvent, InputDevice, InputDeviceId, InputEvent, KeyState, Output, OutputId,
ScrollAxis,
};
use crate::drm::drm::{Drm, DrmError};
use crate::drm::gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING};
use crate::drm::{ModifiedFormat, INVALID_MODIFIER};
use crate::fixed::Fixed;
use crate::format::XRGB8888;
use crate::render::{Framebuffer, RenderContext, RenderError};
use crate::utils::clonecell::CloneCell;
use crate::utils::copyhashmap::CopyHashMap;
use crate::wire_xcon::{
ChangeProperty, ChangeWindowAttributes, ConfigureNotify, CreateCursor, CreatePixmap,
CreateWindow, CreateWindowValues, DestroyNotify, Dri3Open, Dri3PixmapFromBuffer,
Dri3QueryVersion, Extension, FreePixmap, MapWindow, PresentCompleteNotify, PresentIdleNotify,
PresentPixmap, PresentQueryVersion, PresentSelectInput, XiButtonPress, XiButtonRelease,
XiDeviceInfo, XiEnter, XiEventMask, XiGetDeviceButtonMapping, XiGrabDevice, XiHierarchy,
XiKeyPress, XiKeyRelease, XiMotion, XiQueryDevice, XiQueryVersion, XiSelectEvents,
XiUngrabDevice, XkbPerClientFlags, XkbUseExtension,
};
use crate::xcon::consts::{
ATOM_STRING, ATOM_WM_CLASS, EVENT_MASK_EXPOSURE, EVENT_MASK_STRUCTURE_NOTIFY,
EVENT_MASK_VISIBILITY_CHANGE, GRAB_MODE_ASYNC, GRAB_STATUS_SUCCESS, INPUT_DEVICE_ALL,
INPUT_DEVICE_ALL_MASTER, INPUT_DEVICE_TYPE_MASTER_KEYBOARD, INPUT_HIERARCHY_MASK_MASTER_ADDED,
INPUT_HIERARCHY_MASK_MASTER_REMOVED, PRESENT_EVENT_MASK_COMPLETE_NOTIFY,
PRESENT_EVENT_MASK_IDLE_NOTIFY, PROP_MODE_REPLACE, WINDOW_CLASS_INPUT_OUTPUT,
XI_EVENT_MASK_BUTTON_PRESS, XI_EVENT_MASK_BUTTON_RELEASE, XI_EVENT_MASK_ENTER,
XI_EVENT_MASK_FOCUS_IN, XI_EVENT_MASK_FOCUS_OUT, XI_EVENT_MASK_HIERARCHY,
XI_EVENT_MASK_KEY_PRESS, XI_EVENT_MASK_KEY_RELEASE, XI_EVENT_MASK_LEAVE, XI_EVENT_MASK_MOTION,
XI_EVENT_MASK_TOUCH_BEGIN, XI_EVENT_MASK_TOUCH_END, XI_EVENT_MASK_TOUCH_UPDATE,
XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
};
use crate::xcon::{Event, XEvent, Xcon, XconError};
use crate::{AsyncQueue, ErrorFmt, NumCell, Phase, State};
use std::borrow::Cow;
use std::cell::{Cell, RefCell};
use std::collections::VecDeque;
use std::rc::Rc;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum XorgngBackendError {
#[error("Could not connect to the X server")]
CannotConnect(#[source] XconError),
#[error("Could not enable XInput")]
EnableXinput(#[source] XconError),
#[error("Could not enable Present")]
EnablePresent(#[source] XconError),
#[error("Could not enable XKB")]
EnableXkb(#[source] XconError),
#[error("Could not enable DRI3")]
EnableDri3(#[source] XconError),
#[error("DriOpen returned an error")]
DriOpen(#[source] XconError),
#[error("Could not create a pixmap")]
CreatePixmap(#[source] XconError),
#[error("Could not create a cursor")]
CreateCursor(#[source] XconError),
#[error("Could not select XInput hierarchy events")]
SelectHierarchyEvents(#[source] XconError),
#[error("The drm subsystem returned an error")]
DrmError(#[from] DrmError),
#[error("The gbm subsystem returned an error")]
GbmError(#[from] GbmError),
#[error("Could not import a dma-buf")]
ImportBuffer(#[source] XconError),
#[error("Could not create an EGL context")]
CreateEgl(#[source] RenderError),
#[error("Could not create a framebuffer from a dma-buf")]
CreateFramebuffer(#[source] RenderError),
#[error("Could not select input events")]
CannotSelectInputEvents(#[source] XconError),
#[error("Could not select present events")]
CannotSelectPresentEvents(#[source] XconError),
#[error("libloading returned an error")]
Libloading(#[from] libloading::Error),
#[error("An unspecified X error occurred")]
XconError(#[from] XconError),
#[error("Could not create a window")]
CreateWindow(#[source] XconError),
#[error("Could not set WM_CLASS")]
WmClass(#[source] XconError),
#[error("Could not select window events")]
WindowEvents(#[source] XconError),
#[error("Could not map a window")]
MapWindow(#[source] XconError),
#[error("Could not query device")]
QueryDevice(#[source] XconError),
}
pub struct XorgngBackend {
_data: Rc<XorgngBackendData>,
_events: SpawnedFuture<()>,
_present: SpawnedFuture<()>,
_grab: SpawnedFuture<()>,
}
impl Backend for XorgngBackend {
fn switch_to(&self, _vtnr: u32) {
log::error!("Xorg backend cannot switch vts");
}
}
pub struct XorgngBackendData {
state: Rc<State>,
c: Rc<Xcon>,
outputs: CopyHashMap<u32, Rc<XorgOutput>>,
seats: CopyHashMap<u16, Rc<XorgSeat>>,
mouse_seats: CopyHashMap<u16, Rc<XorgSeat>>,
ctx: Rc<RenderContext>,
gbm: GbmDevice,
cursor: u32,
root: u32,
scheduled_present: AsyncQueue<Rc<XorgOutput>>,
grab_requests: AsyncQueue<(Rc<XorgSeat>, bool)>,
}
impl XorgngBackend {
pub async fn run(state: &Rc<State>) -> Result<Rc<Self>, XorgngBackendError> {
let c = match Xcon::connect(state.eng.clone()).await {
Ok(c) => c,
Err(e) => return Err(XorgngBackendError::CannotConnect(e)),
};
if let Err(e) = c
.call(&XiQueryVersion {
major_version: 2,
minor_version: 2,
})
.await
{
return Err(XorgngBackendError::EnableXinput(e));
}
if let Err(e) = c
.call(&Dri3QueryVersion {
major_version: 1,
minor_version: 0,
})
.await
{
return Err(XorgngBackendError::EnableDri3(e));
}
if let Err(e) = c
.call(&PresentQueryVersion {
major_version: 1,
minor_version: 0,
})
.await
{
return Err(XorgngBackendError::EnablePresent(e));
}
if let Err(e) = c
.call(&XkbUseExtension {
wanted_major: 1,
wanted_minor: 0,
})
.await
{
return Err(XorgngBackendError::EnableXkb(e));
}
let root = c.setup().screens[0].root;
let drm = {
let res = c
.call(&Dri3Open {
drawable: root,
provider: 0,
})
.await;
match res {
Ok(r) => Drm::reopen(r.get().device_fd.raw(), false)?,
Err(e) => return Err(XorgngBackendError::DriOpen(e)),
}
};
let gbm = GbmDevice::new(&drm)?;
let ctx = match RenderContext::from_drm_device(&drm) {
Ok(r) => Rc::new(r),
Err(e) => return Err(XorgngBackendError::CreateEgl(e)),
};
let cursor = {
let cp = CreatePixmap {
depth: 1,
pid: c.generate_id()?,
drawable: root,
width: 1,
height: 1,
};
if let Err(e) = c.call(&cp).await {
return Err(XorgngBackendError::CreatePixmap(e));
}
let cc = CreateCursor {
cid: c.generate_id()?,
source: cp.pid,
mask: 0,
fore_red: 0,
fore_green: 0,
fore_blue: 0,
back_red: 0,
back_green: 0,
back_blue: 0,
x: 0,
y: 0,
};
if let Err(e) = c.call(&cc).await {
return Err(XorgngBackendError::CreateCursor(e));
}
cc.cid
};
{
let se = XiSelectEvents {
window: c.setup().screens[0].root,
masks: Cow::Borrowed(&[XiEventMask {
deviceid: INPUT_DEVICE_ALL,
mask: &[XI_EVENT_MASK_HIERARCHY],
}]),
};
if let Err(e) = c.call(&se).await {
return Err(XorgngBackendError::SelectHierarchyEvents(e));
}
}
let data = Rc::new(XorgngBackendData {
state: state.clone(),
c,
outputs: Default::default(),
seats: Default::default(),
mouse_seats: Default::default(),
ctx: ctx.clone(),
gbm,
cursor,
root,
scheduled_present: Default::default(),
grab_requests: Default::default()
});
data.add_output().await?;
data.query_devices(INPUT_DEVICE_ALL_MASTER).await?;
let slf = Rc::new(Self {
_events: state.eng.spawn(data.clone().event_handler()),
_grab: state.eng.spawn(data.clone().grab_handler()),
_present: state
.eng
.spawn2(Phase::Present, data.clone().present_handler()),
_data: data,
});
state.set_render_ctx(&ctx);
state.backend.set(Some(slf.clone()));
Ok(slf)
}
}
impl XorgngBackendData {
async fn event_handler(self: Rc<Self>) {
loop {
let event = self.c.event().await;
if let Err(e) = self.handle_event(&event).await {
log::error!("Fatal error: Could not handle an event from the X server: {}", ErrorFmt(e));
self.state.el.stop();
return;
}
}
}
async fn present_handler(self: Rc<Self>) {
loop {
let output = self.scheduled_present.pop().await;
self.present(&output).await;
}
}
async fn grab_handler(self: Rc<Self>) {
loop {
let (dev, grab) = self.grab_requests.pop().await;
self.handle_grab_request(&dev, grab).await;
}
}
async fn handle_grab_request(&self, dev: &XorgSeat, grab: bool) {
if grab {
let xg = XiGrabDevice {
window: self.root,
time: 0,
cursor: 0,
deviceid: dev.kb,
mode: GRAB_MODE_ASYNC,
paired_device_mode: GRAB_MODE_ASYNC,
owner_events: 1,
mask: &[],
};
let res = match self.c.call(&xg).await {
Ok(r) => r,
Err(e) => {
log::error!("Could not grab device {}: {}", dev.kb, ErrorFmt(e));
return;
}
};
let res = res.get();
if res.status != GRAB_STATUS_SUCCESS {
log::error!("Could not grab device {}: status = {}", dev.kb, res.status);
}
} else {
let ug = XiUngrabDevice {
time: 0,
deviceid: dev.kb,
};
if let Err(e) = self.c.call(&ug).await {
log::error!("Could not ungrab device {}: {}", dev.kb, ErrorFmt(e));
}
}
}
async fn create_images(
&self,
window: u32,
width: i32,
height: i32,
) -> Result<[XorgImage; 2], XorgngBackendError> {
let format = ModifiedFormat {
format: XRGB8888,
modifier: INVALID_MODIFIER,
};
let mut images = [None, None];
for i in 0..2 {
let bo = self
.gbm
.create_bo(width, height, &format, GBM_BO_USE_RENDERING)?;
let dma = bo.dma();
assert!(dma.planes.len() == 1);
let plane = dma.planes.first().unwrap();
let size = plane.stride * dma.height as u32;
let fb = match self.ctx.dmabuf_fb(dma) {
Ok(f) => f,
Err(e) => return Err(XorgngBackendError::CreateFramebuffer(e)),
};
let pixmap = {
let pfb = Dri3PixmapFromBuffer {
pixmap: self.c.generate_id()?,
drawable: window,
size,
width: dma.width as _,
height: dma.height as _,
stride: plane.stride as _,
depth: 24,
bpp: 32,
pixmap_fd: plane.fd.clone(),
};
if let Err(e) = self.c.call(&pfb).await {
return Err(XorgngBackendError::ImportBuffer(e));
}
pfb.pixmap
};
images[i] = Some(XorgImage {
pixmap: Cell::new(pixmap),
fb: CloneCell::new(fb),
idle: Cell::new(true),
render_on_idle: Cell::new(false),
last_serial: Cell::new(0),
});
}
Ok([images[0].take().unwrap(), images[1].take().unwrap()])
}
async fn add_output(self: &Rc<Self>) -> Result<(), XorgngBackendError> {
const WIDTH: i32 = 800;
const HEIGHT: i32 = 600;
let window_id = {
let cw = CreateWindow {
depth: 0,
wid: self.c.generate_id()?,
parent: self.root,
x: 0,
y: 0,
width: WIDTH as _,
height: HEIGHT as _,
border_width: 0,
class: WINDOW_CLASS_INPUT_OUTPUT,
visual: 0,
values: Default::default(),
};
if let Err(e) = self.c.call(&cw).await {
return Err(XorgngBackendError::CreateWindow(e));
}
cw.wid
};
let images = self.create_images(window_id, WIDTH, HEIGHT).await?;
let output = Rc::new(XorgOutput {
id: self.state.output_ids.next(),
_backend: self.clone(),
window: window_id,
removed: Cell::new(false),
width: Cell::new(0),
height: Cell::new(0),
serial: Default::default(),
next_msc: Cell::new(0),
next_image: Default::default(),
cb: CloneCell::new(None),
images,
});
{
let class = "jay\0jay\0";
let cp = ChangeProperty {
mode: PROP_MODE_REPLACE,
window: window_id,
property: ATOM_WM_CLASS,
ty: ATOM_STRING,
format: 8,
data: class.as_bytes(),
};
if let Err(e) = self.c.call(&cp).await {
return Err(XorgngBackendError::WmClass(e));
};
}
{
let cwa = ChangeWindowAttributes {
window: window_id,
values: CreateWindowValues {
event_mask: Some(
EVENT_MASK_EXPOSURE
| EVENT_MASK_STRUCTURE_NOTIFY
| EVENT_MASK_VISIBILITY_CHANGE,
),
cursor: Some(self.cursor),
..Default::default()
},
};
if let Err(e) = self.c.call(&cwa).await {
return Err(XorgngBackendError::WindowEvents(e));
}
}
if let Err(e) = self.c.call(&MapWindow { window: window_id }).await {
return Err(XorgngBackendError::MapWindow(e));
}
{
let mask = 0
| XI_EVENT_MASK_MOTION
| XI_EVENT_MASK_BUTTON_PRESS
| XI_EVENT_MASK_BUTTON_RELEASE
| XI_EVENT_MASK_KEY_PRESS
| XI_EVENT_MASK_KEY_RELEASE
| XI_EVENT_MASK_ENTER
| XI_EVENT_MASK_LEAVE
| XI_EVENT_MASK_FOCUS_IN
| XI_EVENT_MASK_FOCUS_OUT
| XI_EVENT_MASK_TOUCH_BEGIN
| XI_EVENT_MASK_TOUCH_UPDATE
| XI_EVENT_MASK_TOUCH_END;
let mask = [XiEventMask {
deviceid: INPUT_DEVICE_ALL_MASTER,
mask: &[mask],
}];
let xs = XiSelectEvents {
window: window_id,
masks: Cow::Borrowed(&mask[..]),
};
if let Err(e) = self.c.call(&xs).await {
return Err(XorgngBackendError::CannotSelectInputEvents(e));
}
}
{
let mask = 0 | PRESENT_EVENT_MASK_IDLE_NOTIFY | PRESENT_EVENT_MASK_COMPLETE_NOTIFY;
let si = PresentSelectInput {
eid: self.c.generate_id()?,
window: window_id,
event_mask: mask,
};
if let Err(e) = self.c.call(&si).await {
return Err(XorgngBackendError::CannotSelectPresentEvents(e));
}
}
self.outputs.set(window_id, output.clone());
self.state
.backend_events
.push(BackendEvent::NewOutput(output.clone()));
self.present(&output).await;
Ok(())
}
async fn query_devices(self: &Rc<Self>, deviceid: u16) -> Result<(), XorgngBackendError> {
let reply = match self.c.call(&XiQueryDevice { deviceid }).await {
Ok(r) => r,
Err(e) => return Err(XorgngBackendError::QueryDevice(e)),
};
for dev in reply.get().infos.iter() {
self.handle_input_device(dev).await;
}
Ok(())
}
async fn handle_input_device(self: &Rc<Self>, info: &XiDeviceInfo<'_>) {
if info.ty != INPUT_DEVICE_TYPE_MASTER_KEYBOARD {
return;
}
self.mouse_seats.remove(&info.attachment);
if let Some(kb) = self.seats.remove(&info.deviceid) {
kb.removed.set(true);
kb.kb_changed();
kb.mouse_changed();
}
let pcf = XkbPerClientFlags {
device_spec: info.deviceid,
change: XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
value: XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
ctrls_to_change: 0,
auto_ctrls: 0,
auto_ctrls_values: 0,
};
if let Err(e) = self.c.call(&pcf).await {
log::warn!(
"Could not make auto repeat detectable for keyboard {}: {}",
info.deviceid,
ErrorFmt(e),
);
}
let seat = Rc::new(XorgSeat {
kb_id: self.state.input_device_ids.next(),
mouse_id: self.state.input_device_ids.next(),
backend: self.clone(),
kb: info.deviceid,
mouse: info.attachment,
removed: Cell::new(false),
kb_cb: Default::default(),
mouse_cb: Default::default(),
kb_events: RefCell::new(Default::default()),
mouse_events: RefCell::new(Default::default()),
button_map: Default::default(),
});
seat.update_button_map().await;
self.seats.set(info.deviceid, seat.clone());
self.mouse_seats.set(info.attachment, seat.clone());
self.state
.backend_events
.push(BackendEvent::NewInputDevice(Rc::new(XorgSeatMouse(
seat.clone(),
))));
self.state
.backend_events
.push(BackendEvent::NewInputDevice(Rc::new(XorgSeatKeyboard(
seat.clone(),
))));
}
async fn handle_event(self: &Rc<Self>, event: &Event) -> Result<(), XorgngBackendError> {
match event.ext() {
Some(ext) => self.handle_ext_event(ext, event).await,
_ => self.handle_core_event(event).await,
}
}
async fn handle_ext_event(
self: &Rc<Self>,
ext: Extension,
event: &Event,
) -> Result<(), XorgngBackendError> {
match ext {
Extension::Present => self.handle_present_event(event),
Extension::XInputExtension => self.handle_input_event(event).await,
_ => Ok(()),
}
}
async fn handle_core_event(self: &Rc<Self>, event: &Event) -> Result<(), XorgngBackendError> {
match event.code() {
ConfigureNotify::OPCODE => self.handle_configure(event).await,
DestroyNotify::OPCODE => self.handle_destroy(event),
_ => Ok(()),
}
}
fn handle_present_event(self: &Rc<Self>, event: &Event) -> Result<(), XorgngBackendError> {
match event.code() {
PresentCompleteNotify::OPCODE => self.handle_present_complete(event)?,
PresentIdleNotify::OPCODE => self.handle_present_idle(event)?,
_ => {}
}
Ok(())
}
fn handle_present_complete(self: &Rc<Self>, event: &Event) -> Result<(), XorgngBackendError> {
let event: PresentCompleteNotify = event.parse()?;
let window = event.window;
let output = match self.outputs.get(&window) {
Some(o) => o,
_ => return Ok(()),
};
output.next_msc.set(event.msc + 1);
let image = &output.images[output.next_image.get() % output.images.len()];
if image.idle.get() {
self.schedule_present(&output);
} else {
image.render_on_idle.set(true);
}
Ok(())
}
fn handle_present_idle(self: &Rc<Self>, event: &Event) -> Result<(), XorgngBackendError> {
let event: PresentIdleNotify = event.parse()?;
let output = match self.outputs.get(&event.window) {
Some(o) => o,
_ => return Ok(()),
};
for image in &output.images {
if image.last_serial.get() == event.serial {
image.idle.set(true);
if image.render_on_idle.replace(false) {
self.schedule_present(&output);
}
}
}
Ok(())
}
fn schedule_present(&self, output: &Rc<XorgOutput>) {
self.scheduled_present.push(output.clone());
}
async fn present(&self, output: &Rc<XorgOutput>) {
if output.removed.get() {
return;
}
let image = &output.images[output.next_image.fetch_add(1) % output.images.len()];
let serial = output.serial.fetch_add(1);
if let Some(node) = self.state.root.outputs.get(&output.id) {
let fb = image.fb.get();
fb.render(&*node, &self.state, Some(node.position.get()));
}
let pp = PresentPixmap {
window: output.window,
pixmap: image.pixmap.get(),
serial,
valid: 0,
update: 0,
x_off: 0,
y_off: 0,
target_crtc: 0,
wait_fence: 0,
idle_fence: 0,
options: 0,
target_msc: output.next_msc.get(),
divisor: 1,
remainder: 0,
notifies: Default::default(),
};
if let Err(e) = self.c.call(&pp).await {
log::error!("Could not present image: {:?}", e);
return;
}
image.idle.set(false);
image.last_serial.set(serial);
}
async fn handle_input_event(self: &Rc<Self>, event: &Event) -> Result<(), XorgngBackendError> {
match event.code() {
XiMotion::OPCODE => self.handle_input_motion(event),
XiEnter::OPCODE => self.handle_input_enter(event),
XiButtonPress::OPCODE => self.handle_input_button_press(event, KeyState::Pressed),
XiButtonRelease::OPCODE => self.handle_input_button_press(event, KeyState::Released),
XiKeyPress::OPCODE => self.handle_input_key_press(event, KeyState::Pressed),
XiKeyRelease::OPCODE => self.handle_input_key_press(event, KeyState::Released),
XiHierarchy::OPCODE => self.handle_input_hierarchy(event).await,
_ => Ok(()),
}
}
fn handle_input_button_press(
self: &Rc<Self>,
event: &Event,
state: KeyState,
) -> Result<(), XorgngBackendError> {
let event: XiButtonPress = event.parse()?;
if let Some(seat) = self.mouse_seats.get(&event.deviceid) {
let button = event.detail;
// let button = seat.button_map.get(&event.detail).unwrap_or(event.detail);
if matches!(button, 4..=7) {
if state == KeyState::Pressed {
let (axis, val) = match button {
4 => (ScrollAxis::Vertical, -15),
5 => (ScrollAxis::Vertical, 15),
6 => (ScrollAxis::Horizontal, -15),
7 => (ScrollAxis::Horizontal, 15),
_ => unreachable!(),
};
seat.mouse_event(InputEvent::Scroll(val, axis));
}
} else {
const BTN_LEFT: u32 = 0x110;
const BTN_RIGHT: u32 = 0x111;
const BTN_MIDDLE: u32 = 0x112;
const BTN_SIDE: u32 = 0x113;
let button = match button {
0 => return Ok(()),
1 => BTN_LEFT,
2 => BTN_MIDDLE,
3 => BTN_RIGHT,
n => BTN_SIDE + n - 8,
};
seat.mouse_event(InputEvent::Button(button, state));
}
}
Ok(())
}
fn handle_input_key_press(
self: &Rc<Self>,
event: &Event,
state: KeyState,
) -> Result<(), XorgngBackendError> {
let event: XiKeyPress = event.parse()?;
if let Some(seat) = self.seats.get(&event.deviceid) {
seat.kb_event(InputEvent::Key(event.detail - 8, state));
}
Ok(())
}
async fn handle_input_hierarchy(
self: &Rc<Self>,
event: &Event,
) -> Result<(), XorgngBackendError> {
let event: XiHierarchy = event.parse()?;
for info in event.infos.iter() {
if info.flags & INPUT_HIERARCHY_MASK_MASTER_ADDED != 0 {
if let Err(e) = self.query_devices(info.deviceid).await {
log::error!("Could not query device {}: {:#}", info.deviceid, e);
}
} else if info.flags & INPUT_HIERARCHY_MASK_MASTER_REMOVED != 0 {
self.mouse_seats.remove(&info.attachment);
if let Some(seat) = self.seats.remove(&info.deviceid) {
seat.removed.set(true);
seat.kb_changed();
seat.mouse_changed();
}
}
}
Ok(())
}
fn handle_input_enter(&self, event: &Event) -> Result<(), XorgngBackendError> {
let event: XiEnter = event.parse()?;
if let (Some(win), Some(seat)) = (
self.outputs.get(&event.event),
self.mouse_seats.get(&event.deviceid),
) {
seat.mouse_event(InputEvent::OutputPosition(
win.id,
Fixed::from_1616(event.event_x),
Fixed::from_1616(event.event_y),
));
}
Ok(())
}
fn handle_input_motion(&self, event: &Event) -> Result<(), XorgngBackendError> {
let event: XiMotion = event.parse()?;
let (win, seat) = match (
self.outputs.get(&event.event),
self.mouse_seats.get(&event.deviceid),
) {
(Some(a), Some(b)) => (a, b),
_ => return Ok(()),
};
seat.mouse_event(InputEvent::OutputPosition(
win.id,
Fixed::from_1616(event.event_x),
Fixed::from_1616(event.event_y),
));
Ok(())
}
fn handle_destroy(&self, event: &Event) -> Result<(), XorgngBackendError> {
self.state.el.stop();
let event: DestroyNotify = event.parse()?;
let output = match self.outputs.remove(&event.event) {
Some(o) => o,
_ => return Ok(()),
};
output.removed.set(true);
output.changed();
Ok(())
}
async fn handle_configure(&self, event: &Event) -> Result<(), XorgngBackendError> {
let event: ConfigureNotify = event.parse()?;
let output = match self.outputs.get(&event.event) {
Some(o) => o,
_ => return Ok(()),
};
let width = event.width as i32;
let height = event.height as i32;
let mut changed = false;
changed |= output.width.replace(width) != width;
changed |= output.height.replace(height) != height;
if changed {
let images = self.create_images(output.window, width, height).await?;
for (new, old) in images.iter().zip(output.images.iter()) {
let _ = self.c.call(&FreePixmap {
pixmap: old.pixmap.get(),
});
old.fb.set(new.fb.get());
old.pixmap.set(new.pixmap.get());
}
output.changed();
}
Ok(())
}
}
struct XorgOutput {
id: OutputId,
_backend: Rc<XorgngBackendData>,
window: u32,
removed: Cell<bool>,
width: Cell<i32>,
height: Cell<i32>,
serial: NumCell<u32>,
next_msc: Cell<u64>,
next_image: NumCell<usize>,
images: [XorgImage; 2],
cb: CloneCell<Option<Rc<dyn Fn()>>>,
}
struct XorgImage {
pixmap: Cell<u32>,
fb: CloneCell<Rc<Framebuffer>>,
idle: Cell<bool>,
render_on_idle: Cell<bool>,
last_serial: Cell<u32>,
}
impl XorgOutput {
fn changed(&self) {
if let Some(cb) = self.cb.get() {
cb();
}
}
}
impl Output for XorgOutput {
fn id(&self) -> OutputId {
self.id
}
fn removed(&self) -> bool {
self.removed.get()
}
fn width(&self) -> i32 {
self.width.get()
}
fn height(&self) -> i32 {
self.height.get()
}
fn on_change(&self, cb: Rc<dyn Fn()>) {
self.cb.set(Some(cb));
}
}
struct XorgSeat {
kb_id: InputDeviceId,
mouse_id: InputDeviceId,
backend: Rc<XorgngBackendData>,
kb: u16,
mouse: u16,
removed: Cell<bool>,
kb_cb: CloneCell<Option<Rc<dyn Fn()>>>,
mouse_cb: CloneCell<Option<Rc<dyn Fn()>>>,
kb_events: RefCell<VecDeque<InputEvent>>,
mouse_events: RefCell<VecDeque<InputEvent>>,
button_map: CopyHashMap<u32, u32>,
}
struct XorgSeatKeyboard(Rc<XorgSeat>);
struct XorgSeatMouse(Rc<XorgSeat>);
impl XorgSeat {
fn kb_changed(&self) {
if let Some(cb) = self.kb_cb.get() {
cb();
}
}
fn mouse_changed(&self) {
if let Some(cb) = self.mouse_cb.get() {
cb();
}
}
fn mouse_event(&self, event: InputEvent) {
self.mouse_events.borrow_mut().push_back(event);
self.mouse_changed();
}
fn kb_event(&self, event: InputEvent) {
self.kb_events.borrow_mut().push_back(event);
self.kb_changed();
}
async fn update_button_map(&self) {
self.button_map.clear();
let gdbm = XiGetDeviceButtonMapping {
device_id: self.mouse as _,
};
let reply = match self.backend.c.call(&gdbm).await {
Ok(r) => r,
Err(e) => {
log::error!(
"Could not get Xinput button map of device {}: {}",
self.mouse,
ErrorFmt(e),
);
return;
}
};
for (i, map) in reply.get().map.iter().copied().enumerate().rev() {
self.button_map.set(map as u32, i as u32 + 1);
}
}
}
impl InputDevice for XorgSeatKeyboard {
fn id(&self) -> InputDeviceId {
self.0.kb_id
}
fn removed(&self) -> bool {
self.0.removed.get()
}
fn event(&self) -> Option<InputEvent> {
self.0.kb_events.borrow_mut().pop_front()
}
fn on_change(&self, cb: Rc<dyn Fn()>) {
self.0.kb_cb.set(Some(cb));
}
fn grab(&self, grab: bool) {
self.0.backend.grab_requests.push((self.0.clone(), grab));
}
}
impl InputDevice for XorgSeatMouse {
fn id(&self) -> InputDeviceId {
self.0.mouse_id
}
fn removed(&self) -> bool {
self.0.removed.get()
}
fn event(&self) -> Option<InputEvent> {
self.0.mouse_events.borrow_mut().pop_front()
}
fn on_change(&self, cb: Rc<dyn Fn()>) {
self.0.mouse_cb.set(Some(cb));
}
fn grab(&self, _grab: bool) {
log::error!("Cannot grab xorg mouse");
}
}

View file

@ -1,10 +1,10 @@
use crate::async_engine::{AsyncFd, SpawnedFuture};
use crate::dbus::property::GetReply;
use crate::dbus::types::{ObjectPath, Signature, Variant};
use crate::utils::bufio::{BufIo, BufIoError};
use crate::utils::copyhashmap::CopyHashMap;
use crate::utils::stack::Stack;
use crate::utils::vecstorage::VecStorage;
use crate::{AsyncEngine, AsyncError, AsyncQueue, CloneCell, NumCell, RunToplevel};
use crate::{AsyncEngine, AsyncError, CloneCell, NumCell, RunToplevel};
use ahash::AHashMap;
use std::borrow::Cow;
use std::cell::{Cell, RefCell};
@ -50,8 +50,6 @@ impl Display for CallError {
pub enum DbusError {
#[error("Encountered an unknown type in a signature")]
UnknownType,
#[error("BUS closed the connection")]
Closed,
#[error("Function call reply does not contain a reply serial")]
NoReplySerial,
#[error("Signal message contains no interface or member or path")]
@ -108,6 +106,10 @@ pub enum DbusError {
InvalidSignatureType,
#[error("The signal already has a handler")]
AlreadyHandled,
#[error(transparent)]
BufIoError(#[from] BufIoError),
#[error(transparent)]
DbusError(Rc<DbusError>),
}
efrom!(DbusError, AsyncError);
@ -145,11 +147,10 @@ unsafe trait ReplyHandler {
pub struct DbusSocket {
bus_name: &'static str,
fd: AsyncFd,
bufio: Rc<BufIo>,
eng: Rc<AsyncEngine>,
next_serial: NumCell<u32>,
bufs: Stack<Vec<u8>>,
unique_name: CloneCell<Rc<String>>,
outgoing: AsyncQueue<DbusMessage>,
reply_handlers: CopyHashMap<u32, Box<dyn ReplyHandler>>,
incoming: Cell<Option<SpawnedFuture<()>>>,
outgoing_: Cell<Option<SpawnedFuture<()>>>,
@ -237,11 +238,6 @@ impl Drop for DbusHolder {
}
}
struct DbusMessage {
fds: Vec<Rc<OwnedFd>>,
buf: Vec<u8>,
}
#[derive(Clone, Debug)]
pub enum DynamicType {
U8,
@ -354,7 +350,7 @@ impl<T: Message<'static>> Reply<T> {
impl<T: Message<'static>> Drop for Reply<T> {
fn drop(&mut self) {
self.socket.bufs.push(mem::take(&mut self.buf));
self.socket.bufio.add_buf(mem::take(&mut self.buf));
}
}

View file

@ -1,5 +1,6 @@
use crate::dbus::auth::handle_auth;
use crate::dbus::{DbusError, DbusHolder, DbusSocket};
use crate::utils::bufio::BufIo;
use crate::{org, AsyncEngine, ErrorFmt, NumCell, RunToplevel};
use std::cell::Cell;
use std::rc::Rc;
@ -46,14 +47,14 @@ fn connect(
if let Err(e) = uapi::connect(socket.raw(), &sadr) {
return Err(DbusError::Connect(e.into()));
}
let fd = eng.fd(&Rc::new(socket))?;
let socket = Rc::new(DbusSocket {
bus_name: name,
fd: eng.fd(&Rc::new(socket))?,
fd: fd.clone(),
bufio: Rc::new(BufIo::new(fd)),
eng: eng.clone(),
next_serial: NumCell::new(1),
bufs: Default::default(),
unique_name: Default::default(),
outgoing: Default::default(),
reply_handlers: Default::default(),
incoming: Default::default(),
outgoing_: Default::default(),

View file

@ -5,35 +5,24 @@ use super::{
use crate::dbus::{
CallError, DbusError, DbusSocket, Headers, Parser, MSG_ERROR, MSG_METHOD_RETURN, MSG_SIGNAL,
};
use crate::utils::bufio::BufIoIncoming;
use crate::utils::ptr_ext::{MutPtrExt, PtrExt};
use crate::ErrorFmt;
use std::cell::UnsafeCell;
use std::collections::VecDeque;
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::rc::Rc;
use uapi::{c, Errno, MaybeUninitSliceExt, MsghdrMut, OwnedFd};
pub async fn handle_incoming(socket: Rc<DbusSocket>) {
let mut incoming = Incoming {
incoming: socket.bufio.incoming(),
socket,
buf: Box::new([MaybeUninit::uninit(); 4096]),
buf_start: 0,
buf_end: 0,
fds: Default::default(),
cmsg: Box::new([MaybeUninit::uninit(); 256]),
};
incoming.run().await;
}
pub struct Incoming {
socket: Rc<DbusSocket>,
buf: Box<[MaybeUninit<u8>; 4096]>,
buf_start: usize,
buf_end: usize,
fds: VecDeque<Rc<OwnedFd>>,
cmsg: Box<[MaybeUninit<u8>; 256]>,
incoming: BufIoIncoming,
}
impl Incoming {
@ -55,11 +44,12 @@ impl Incoming {
}
async fn handle_msg(&mut self) -> Result<(), DbusError> {
let msg_buf_data = UnsafeCell::new(self.socket.bufs.pop().unwrap_or_default());
let msg_buf_data = UnsafeCell::new(self.socket.bufio.buf());
let msg_buf = unsafe { msg_buf_data.get().deref_mut() };
msg_buf.clear();
const FIXED_HEADER_SIZE: usize = 16;
self.fill_msg_buf(FIXED_HEADER_SIZE, msg_buf).await?;
self.incoming
.fill_msg_buf(FIXED_HEADER_SIZE, msg_buf)
.await?;
let endianess = msg_buf[0];
if (endianess == b'l') != cfg!(target_endian = "little") {
return Err(DbusError::InvalidEndianess);
@ -75,16 +65,18 @@ impl Incoming {
let [body_len, _serial, headers_len] = fields2;
let dyn_header_len = headers_len + (headers_len.wrapping_neg() & 7);
let remaining = dyn_header_len + body_len;
self.fill_msg_buf(remaining as usize, msg_buf).await?;
self.incoming
.fill_msg_buf(remaining as usize, msg_buf)
.await?;
drop(msg_buf);
let msg_buf = unsafe { msg_buf_data.get().deref().deref() };
let headers = &msg_buf[FIXED_HEADER_SIZE..FIXED_HEADER_SIZE + headers_len as usize];
let headers = self.parse_headers(headers)?;
let unix_fds = headers.unix_fds.unwrap_or(0) as usize;
if self.fds.len() < unix_fds {
if self.incoming.fds.len() < unix_fds {
return Err(DbusError::TooFewFds);
}
let fds: Vec<_> = self.fds.drain(..unix_fds).collect();
let fds: Vec<_> = self.incoming.fds.drain(..unix_fds).collect();
let mut parser = Parser {
buf: &msg_buf,
pos: FIXED_HEADER_SIZE + dyn_header_len as usize,
@ -172,7 +164,7 @@ impl Incoming {
}
let msg_buf = msg_buf_data.into_inner();
if msg_buf.capacity() > 0 {
self.socket.bufs.push(msg_buf);
self.socket.bufio.add_buf(msg_buf);
}
Ok(())
}
@ -199,54 +191,4 @@ impl Incoming {
}
Ok(headers)
}
async fn fill_msg_buf(&mut self, mut n: usize, buf: &mut Vec<u8>) -> Result<(), DbusError> {
while n > 0 {
if self.buf_start == self.buf_end {
while let Err(e) = self.recvmsg() {
if e.0 != c::EAGAIN {
return Err(DbusError::ReadError(e.into()));
}
self.socket.fd.readable().await?;
}
if self.buf_start == self.buf_end {
return Err(DbusError::Closed);
}
}
let read = n.min(self.buf_end - self.buf_start);
let buf_start = self.buf_start % self.buf.len();
unsafe {
buf.extend_from_slice(
self.buf[buf_start..buf_start + read].slice_assume_init_ref(),
);
}
n -= read;
self.buf_start += read;
}
Ok(())
}
fn recvmsg(&mut self) -> Result<(), Errno> {
self.buf_start = 0;
self.buf_end = 0;
let mut iov = [&mut self.buf[..]];
let mut hdr = MsghdrMut {
iov: &mut iov[..],
control: Some(&mut self.cmsg[..]),
name: uapi::sockaddr_none_mut(),
flags: 0,
};
let (ivec, _, mut cmsg) =
uapi::recvmsg(self.socket.fd.raw(), &mut hdr, c::MSG_CMSG_CLOEXEC)?;
self.buf_end += ivec.len();
while cmsg.len() > 0 {
let (_, hdr, body) = uapi::cmsg_read(&mut cmsg)?;
if hdr.cmsg_level == c::SOL_SOCKET && hdr.cmsg_type == c::SCM_RIGHTS {
for fd in uapi::pod_iter(body)? {
self.fds.push_back(Rc::new(OwnedFd::new(fd)));
}
}
}
Ok(())
}
}

View file

@ -1,118 +1,10 @@
use crate::dbus::{DbusMessage, DbusSocket};
use crate::utils::vec_ext::{UninitVecExt, VecExt};
use crate::utils::vecstorage::VecStorage;
use crate::dbus::DbusSocket;
use crate::ErrorFmt;
use std::collections::VecDeque;
use std::mem;
use std::mem::MaybeUninit;
use std::ptr::NonNull;
use std::rc::Rc;
use uapi::{c, Errno, Msghdr};
pub async fn handle_outgoing(socket: Rc<DbusSocket>) {
let mut outgoing = Outgoing {
socket,
msgs: Default::default(),
cmsg: vec![],
fds: vec![],
iovecs: Default::default(),
};
outgoing.run().await
}
struct DbusMessageOffset {
msg: DbusMessage,
offset: usize,
}
struct Outgoing {
socket: Rc<DbusSocket>,
msgs: VecDeque<DbusMessageOffset>,
cmsg: Vec<MaybeUninit<u8>>,
fds: Vec<c::c_int>,
iovecs: VecStorage<NonNull<[u8]>>,
}
impl Outgoing {
async fn run(&mut self) {
loop {
self.socket.outgoing.non_empty().await;
while let Err(e) = self.try_flush() {
if e != Errno(c::EAGAIN) {
log::error!(
"{}: Could not send a message to the bus: {}",
self.socket.bus_name,
ErrorFmt(e)
);
self.socket.kill();
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)
);
self.socket.kill();
return;
}
}
}
}
fn try_flush(&mut self) -> Result<(), Errno> {
loop {
while let Some(msg) = self.socket.outgoing.try_pop() {
self.msgs.push_back(DbusMessageOffset { msg, offset: 0 });
}
if self.msgs.is_empty() {
return Ok(());
}
let mut iovecs = self.iovecs.take_as();
let mut fds = &[][..];
for msg in &mut self.msgs {
if msg.msg.fds.len() > 0 {
if fds.len() > 0 || iovecs.len() > 0 {
break;
}
fds = &msg.msg.fds;
}
iovecs.push(&msg.msg.buf[msg.offset..]);
}
self.cmsg.clear();
if fds.len() > 0 {
self.fds.clear();
self.fds.extend(fds.iter().map(|f| f.raw()));
let cmsg_space = uapi::cmsg_space(fds.len() * mem::size_of::<c::c_int>());
self.cmsg.reserve(cmsg_space);
let (_, mut spare) = self.cmsg.split_at_spare_mut_bytes_ext();
let hdr = c::cmsghdr {
cmsg_len: 0,
cmsg_level: c::SOL_SOCKET,
cmsg_type: c::SCM_RIGHTS,
};
let len = uapi::cmsg_write(&mut spare, hdr, &self.fds).unwrap();
self.cmsg.set_len_safe(len);
}
let msg = Msghdr {
iov: &iovecs[..],
control: Some(&self.cmsg[..]),
name: uapi::sockaddr_none_ref(),
};
let mut n = uapi::sendmsg(self.socket.fd.raw(), &msg, c::MSG_DONTWAIT)?;
drop(iovecs);
self.msgs[0].msg.fds.clear();
while n > 0 {
let len = self.msgs[0].msg.buf.len() - self.msgs[0].offset;
if n < len {
self.msgs[0].offset += n;
break;
}
n -= len;
let msg = self.msgs.pop_front().unwrap();
self.socket.bufs.push(msg.msg.buf);
}
}
}
if let Err(e) = socket.bufio.clone().outgoing().await {
log::error!("{}: {}", socket.bus_name, ErrorFmt(e));
}
socket.kill();
}

View file

@ -1,12 +1,13 @@
use crate::dbus::property::Get;
use crate::dbus::types::{ObjectPath, Signature, Variant};
use crate::dbus::{
AsyncProperty, AsyncReply, AsyncReplySlot, DbusError, DbusMessage, DbusSocket, DbusType,
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,
MSG_METHOD_CALL, NO_REPLY_EXPECTED,
AsyncProperty, AsyncReply, AsyncReplySlot, DbusError, DbusSocket, DbusType, 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, MSG_METHOD_CALL,
NO_REPLY_EXPECTED,
};
use crate::utils::bufio::BufIoMessage;
use crate::{org, ErrorFmt};
use std::cell::Cell;
use std::collections::hash_map::Entry;
@ -243,7 +244,7 @@ impl DbusSocket {
msg: &T,
) -> u32 {
let (msg, serial) = self.format_call(path, destination, flags, msg);
self.outgoing.push(msg);
self.bufio.send(msg);
serial
}
@ -253,12 +254,11 @@ impl DbusSocket {
destination: &str,
flags: u8,
msg: &T,
) -> (DbusMessage, u32) {
) -> (BufIoMessage, u32) {
let num_fds = msg.num_fds();
let mut fds = Vec::with_capacity(num_fds as _);
let serial = self.serial();
let mut buf = self.bufs.pop().unwrap_or_default();
buf.clear();
let mut buf = self.bufio.buf();
let mut fmt = Formatter::new(&mut fds, &mut buf);
self.format_header(
&mut fmt,
@ -276,7 +276,7 @@ impl DbusSocket {
msg.marshal(&mut fmt);
let body_len = (buf.len() - body_start) as u32;
buf[4..8].copy_from_slice(uapi::as_bytes(&body_len));
(DbusMessage { fds, buf }, serial)
(BufIoMessage { fds, buf }, serial)
}
fn format_header(
@ -345,13 +345,22 @@ where
) -> Result<(), DbusError> {
let msg = <T::Generic<'a> as Message>::unmarshal(parser)?;
(self.0)(Ok(&msg));
socket.bufs.push(buf);
socket.bufio.add_buf(buf);
Ok(())
}
}
struct AsyncReplyHandler<T: Message<'static>>(Rc<AsyncReplySlot<T>>);
impl<T: Message<'static>> AsyncReplyHandler<T> {
fn complete(self: Box<Self>, res: Result<Reply<T>, DbusError>) {
self.0.data.set(Some(res));
if let Some(waker) = self.0.waker.take() {
waker.wake();
}
}
}
unsafe impl<T> ReplyHandler for AsyncReplyHandler<T>
where
T: Message<'static>,
@ -376,16 +385,21 @@ where
) -> Result<(), DbusError> {
let msg = <T::Generic<'static> as Message<'static>>::unmarshal(unsafe {
mem::transmute::<&mut Parser<'a>, &mut Parser<'static>>(parser)
})?;
});
let msg = match msg {
Ok(msg) => msg,
Err(e) => {
let e = Rc::new(e);
self.complete(Err(DbusError::DbusError(e.clone())));
return Err(DbusError::DbusError(e.clone()));
}
};
let reply = Reply {
socket: socket.clone(),
buf,
t: msg,
};
self.0.data.set(Some(Ok(reply)));
if let Some(waker) = self.0.waker.take() {
waker.wake();
}
self.complete(Ok(reply));
Ok(())
}
}

View file

@ -151,10 +151,10 @@ impl EventLoop {
fn run_(&self) -> Result<(), EventLoopError> {
self.check_destroyed()?;
let mut buf = [c::epoll_event { events: 0, u64: 0 }; 16];
while !self.destroyed.get() {
'outer: while !self.destroyed.get() {
while let Some(id) = self.scheduled.borrow_mut().pop_front() {
if self.destroyed.get() {
break;
break 'outer;
}
if let Some(entry) = self.entries.get(&id) {
if let Err(e) = entry.dispatcher.clone().dispatch(0) {
@ -162,6 +162,9 @@ impl EventLoop {
}
}
}
if self.destroyed.get() {
break 'outer;
}
let num = match uapi::epoll_wait(self.epoll.raw(), &mut buf, -1) {
Ok(n) => n,
Err(Errno(c::EINTR)) => continue,
@ -169,7 +172,7 @@ impl EventLoop {
};
for event in &buf[..num] {
if self.destroyed.get() {
break;
break 'outer;
}
let id = event.u64;
let entry = match self.entries.get(&id) {

View file

@ -1,10 +1,10 @@
use crate::dbus::{DbusError, DbusSocket, SignalHandler};
use crate::org::freedesktop::login1::seat::SwitchToReply;
use crate::org::freedesktop::login1::session::{PauseDevice, ResumeDevice, TakeDeviceReply};
use crate::{org, FALSE};
use std::rc::Rc;
use thiserror::Error;
use uapi::c;
use crate::org::freedesktop::login1::seat::SwitchToReply;
const LOGIND_NAME: &str = "org.freedesktop.login1";
const MANAGER_PATH: &str = "/org/freedesktop/login1";
@ -53,7 +53,7 @@ impl Session {
.get_async::<org::freedesktop::login1::session::Seat>(LOGIND_NAME, &session_path)
.await;
match seat {
Ok(s) => s.get().1.0.to_string(),
Ok(s) => s.get().1 .0.to_string(),
Err(e) => return Err(LogindError::GetSeatName(e)),
}
};
@ -126,7 +126,8 @@ impl Session {
}
pub fn switch_to<F>(&self, vtnr: u32, f: F)
where F: FnOnce(Result<&SwitchToReply, DbusError>) + 'static
where
F: FnOnce(Result<&SwitchToReply, DbusError>) + 'static,
{
self.socket.call(
LOGIND_NAME,

View file

@ -17,7 +17,6 @@
use crate::acceptor::AcceptorError;
use crate::async_engine::{AsyncError, Phase};
use crate::backends::metal;
use crate::backends::xorg::{XorgBackend, XorgBackendError};
use crate::client::Clients;
use crate::clientmem::ClientMemError;
use crate::dbus::{Dbus, FALSE};
@ -97,6 +96,8 @@ mod utils;
mod wheel;
mod wire;
mod wire_dbus;
mod wire_xcon;
mod xcon;
mod xkbcommon;
mod xwayland;
@ -127,8 +128,6 @@ enum MainError {
WheelError(#[from] WheelError),
#[error("The async subsystem caused an error")]
AsyncError(#[from] AsyncError),
#[error("The xorg backend caused an error")]
XorgBackendError(#[from] XorgBackendError),
#[error("The render backend caused an error")]
RenderError(#[from] RenderError),
#[error("The ol' forker caused an error")]

View file

@ -1,5 +1,7 @@
use crate::async_engine::{AsyncEngine, SpawnedFuture};
use crate::backend::{Backend, BackendEvent, InputDevice, InputDeviceId, InputDeviceIds, OutputId, OutputIds};
use crate::backend::{
Backend, BackendEvent, InputDevice, InputDeviceId, InputDeviceIds, OutputId, OutputIds,
};
use crate::client::{Client, Clients};
use crate::config::ConfigProxy;
use crate::cursor::ServerCursors;

View file

@ -1,12 +1,19 @@
use crate::{metal, ErrorFmt, State, XorgBackend};
use crate::{metal, ErrorFmt, State};
use std::future::pending;
use std::rc::Rc;
use crate::backends::xorgng::XorgngBackend;
pub async fn start_backend(state: Rc<State>) {
log::info!("Trying to start X backend");
let e = match XorgBackend::new(&state) {
Ok(b) => {
state.backend.set(Some(b));
// let e = match XorgBackend::new(&state) {
// Ok(b) => {
// state.backend.set(Some(b));
// pending().await
// }
// Err(e) => e,
// };
let e = match XorgngBackend::run(&state).await {
Ok(_) => {
pending().await
},
Err(e) => e,

241
src/utils/bufio.rs Normal file
View file

@ -0,0 +1,241 @@
use crate::async_engine::AsyncFd;
use crate::utils::oserror::OsError;
use crate::utils::stack::Stack;
use crate::utils::vec_ext::{UninitVecExt, VecExt};
use crate::utils::vecstorage::VecStorage;
use crate::{AsyncError, AsyncQueue};
use std::collections::VecDeque;
use std::mem;
use std::mem::MaybeUninit;
use std::ptr::NonNull;
use std::rc::Rc;
use thiserror::Error;
use uapi::{c, Errno, MaybeUninitSliceExt, Msghdr, MsghdrMut, OwnedFd};
#[derive(Debug, Error)]
pub enum BufIoError {
#[error("Could not write to the socket")]
FlushError(#[source] OsError),
#[error("Could not read from the socket")]
ReadError(#[source] OsError),
#[error("Cannot wait for fd to become writable")]
Writable(#[source] AsyncError),
#[error("Cannot wait for fd to become readable")]
Readable(#[source] AsyncError),
#[error("The socket is closed")]
Closed,
}
pub struct BufIoMessage {
pub fds: Vec<Rc<OwnedFd>>,
pub buf: Vec<u8>,
}
struct MessageOffset {
msg: BufIoMessage,
offset: usize,
}
pub struct BufIo {
fd: AsyncFd,
bufs: Stack<Vec<u8>>,
outgoing: AsyncQueue<BufIoMessage>,
}
pub struct BufIoIncoming {
bufio: Rc<BufIo>,
buf: Box<[MaybeUninit<u8>; 4096]>,
buf_start: usize,
buf_end: usize,
pub fds: VecDeque<Rc<OwnedFd>>,
cmsg: Box<[MaybeUninit<u8>; 256]>,
}
struct Outgoing {
bufio: Rc<BufIo>,
msgs: VecDeque<MessageOffset>,
cmsg: Vec<MaybeUninit<u8>>,
fds: Vec<c::c_int>,
iovecs: VecStorage<NonNull<[u8]>>,
}
impl BufIo {
pub fn new(fd: AsyncFd) -> Self {
Self {
fd,
bufs: Default::default(),
outgoing: Default::default(),
}
}
pub fn shutdown(&self) {
let _ = uapi::shutdown(self.fd.raw(), c::SHUT_RDWR);
}
pub fn buf(&self) -> Vec<u8> {
let mut buf = self.bufs.pop().unwrap_or_default();
buf.clear();
buf
}
pub fn add_buf(&self, buf: Vec<u8>) {
self.bufs.push(buf);
}
pub fn send(&self, msg: BufIoMessage) {
self.outgoing.push(msg);
}
pub async fn outgoing(self: Rc<Self>) -> Result<(), BufIoError> {
let mut outgoing = Outgoing {
bufio: self,
msgs: Default::default(),
cmsg: vec![],
fds: vec![],
iovecs: Default::default(),
};
outgoing.run().await
}
pub fn incoming(self: &Rc<Self>) -> BufIoIncoming {
BufIoIncoming {
bufio: self.clone(),
buf: Box::new([MaybeUninit::uninit(); 4096]),
buf_start: 0,
buf_end: 0,
fds: Default::default(),
cmsg: Box::new([MaybeUninit::uninit(); 256]),
}
}
}
impl BufIoIncoming {
pub async fn fill_msg_buf(
&mut self,
mut n: usize,
buf: &mut Vec<u8>,
) -> Result<(), BufIoError> {
while n > 0 {
if self.buf_start == self.buf_end {
while let Err(e) = self.recvmsg() {
if e.0 != c::EAGAIN {
return Err(BufIoError::ReadError(e.into()));
}
if let Err(e) = self.bufio.fd.readable().await {
return Err(BufIoError::Readable(e));
}
}
if self.buf_start == self.buf_end {
return Err(BufIoError::Closed);
}
}
let read = n.min(self.buf_end - self.buf_start);
let buf_start = self.buf_start % self.buf.len();
unsafe {
buf.extend_from_slice(
self.buf[buf_start..buf_start + read].slice_assume_init_ref(),
);
}
n -= read;
self.buf_start += read;
}
Ok(())
}
fn recvmsg(&mut self) -> Result<(), Errno> {
self.buf_start = 0;
self.buf_end = 0;
let mut iov = [&mut self.buf[..]];
let mut hdr = MsghdrMut {
iov: &mut iov[..],
control: Some(&mut self.cmsg[..]),
name: uapi::sockaddr_none_mut(),
flags: 0,
};
let (ivec, _, mut cmsg) =
uapi::recvmsg(self.bufio.fd.raw(), &mut hdr, c::MSG_CMSG_CLOEXEC)?;
self.buf_end += ivec.len();
while cmsg.len() > 0 {
let (_, hdr, body) = uapi::cmsg_read(&mut cmsg)?;
if hdr.cmsg_level == c::SOL_SOCKET && hdr.cmsg_type == c::SCM_RIGHTS {
for fd in uapi::pod_iter(body)? {
self.fds.push_back(Rc::new(OwnedFd::new(fd)));
}
}
}
Ok(())
}
}
impl Outgoing {
async fn run(&mut self) -> Result<(), BufIoError> {
loop {
self.bufio.outgoing.non_empty().await;
while let Err(e) = self.try_flush() {
if e != Errno(c::EAGAIN) {
return Err(BufIoError::FlushError(e.into()));
}
if let Err(e) = self.bufio.fd.writable().await {
return Err(BufIoError::Writable(e));
}
}
}
}
fn try_flush(&mut self) -> Result<(), Errno> {
loop {
while let Some(msg) = self.bufio.outgoing.try_pop() {
self.msgs.push_back(MessageOffset { msg, offset: 0 });
}
if self.msgs.is_empty() {
return Ok(());
}
let mut iovecs = self.iovecs.take_as();
let mut fds = &[][..];
for msg in &mut self.msgs {
if msg.msg.fds.len() > 0 {
if fds.len() > 0 || iovecs.len() > 0 {
break;
}
fds = &msg.msg.fds;
}
iovecs.push(&msg.msg.buf[msg.offset..]);
}
self.cmsg.clear();
if fds.len() > 0 {
self.fds.clear();
self.fds.extend(fds.iter().map(|f| f.raw()));
let cmsg_space = uapi::cmsg_space(fds.len() * mem::size_of::<c::c_int>());
self.cmsg.reserve(cmsg_space);
let (_, mut spare) = self.cmsg.split_at_spare_mut_bytes_ext();
let hdr = c::cmsghdr {
cmsg_len: 0,
cmsg_level: c::SOL_SOCKET,
cmsg_type: c::SCM_RIGHTS,
};
let len = uapi::cmsg_write(&mut spare, hdr, &self.fds[..]).unwrap();
self.cmsg.set_len_safe(len);
}
let msg = Msghdr {
iov: &iovecs[..],
control: Some(&self.cmsg[..]),
name: uapi::sockaddr_none_ref(),
};
let mut n = uapi::sendmsg(self.bufio.fd.raw(), &msg, c::MSG_DONTWAIT)?;
drop(iovecs);
self.msgs[0].msg.fds.clear();
while n > 0 {
let len = self.msgs[0].msg.buf.len() - self.msgs[0].offset;
if n < len {
self.msgs[0].offset += n;
break;
}
n -= len;
let msg = self.msgs.pop_front().unwrap();
self.bufio.bufs.push(msg.msg.buf);
}
}
}
}

View file

@ -3,7 +3,7 @@ use crate::utils::ptr_ext::{MutPtrExt, PtrExt};
use std::cell::UnsafeCell;
use std::fmt::{Debug, Formatter};
use std::mem;
use std::rc::Rc;
use std::rc::{Rc, Weak};
pub struct CloneCell<T: UnsafeCellCloneSafe> {
data: UnsafeCell<T>,
@ -60,6 +60,7 @@ pub unsafe trait UnsafeCellCloneSafe: Clone {}
unsafe impl<T: UnsafeCellCloneSafe> UnsafeCellCloneSafe for Option<T> {}
unsafe impl<T: ?Sized> UnsafeCellCloneSafe for Rc<T> {}
unsafe impl<T: ?Sized> UnsafeCellCloneSafe for Weak<T> {}
unsafe impl<T> UnsafeCellCloneSafe for NodeRef<T> {}

View file

@ -3,6 +3,7 @@ pub mod asyncevent;
pub mod bitfield;
pub mod bitflags;
pub mod buffd;
pub mod bufio;
pub mod clonecell;
pub mod copyhashmap;
pub mod debug_fn;

9
src/wire_xcon.rs Normal file
View file

@ -0,0 +1,9 @@
#![allow(unused_imports, unused_variables, dead_code, unused_assignments)]
use crate::xcon::{Formatter, Message, Parser, Request, XEvent, XconError};
use bstr::BStr;
use std::borrow::Cow;
use std::rc::Rc;
use uapi::OwnedFd;
include!(concat!(env!("OUT_DIR"), "/wire_xcon.rs"));

590
src/xcon.rs Normal file
View file

@ -0,0 +1,590 @@
use crate::async_engine::SpawnedFuture;
use crate::utils::bufio::{BufIo, BufIoError, BufIoMessage};
use crate::utils::oserror::OsError;
use crate::wire_xcon::{
Extension, GetInputFocus, ListExtensions, QueryExtension, Setup, EXTENSIONS,
};
pub use crate::xcon::formatter::Formatter;
use crate::xcon::incoming::handle_incoming;
use crate::xcon::outgoing::handle_outgoing;
pub use crate::xcon::parser::Parser;
pub use crate::xcon::wire_type::{Message, Request, XEvent};
use crate::xcon::xauthority::{XAuthority, LOCAL, MIT_MAGIC_COOKIE};
use crate::{AsyncEngine, AsyncError, AsyncQueue, CloneCell, ErrorFmt, NumCell, Phase};
use ahash::AHashMap;
use bstr::{BString, ByteSlice};
use std::any::TypeId;
use std::cell::{Cell, RefCell};
use std::collections::VecDeque;
use std::future::Future;
use std::io::Write;
use std::mem::MaybeUninit;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::rc::{Rc, Weak};
use std::task::{Context, Poll, Waker};
use std::{mem, ptr};
use thiserror::Error;
use uapi::{c, OwnedFd};
pub mod consts;
mod formatter;
mod incoming;
mod outgoing;
mod parser;
mod wire_type;
mod xauthority;
#[derive(Debug, Error)]
pub enum XconError {
#[error("Unexpected EOF")]
UnexpectedEof,
#[error("Buffer slice is not properly aligned")]
UnalignedSlice,
#[error("Neither XAUTHORITY nor HOME is set")]
HomeNotSet,
#[error("Could not read Xauthority file")]
ReadXAuthority(#[source] std::io::Error),
#[error("Display field in Xauthority could not be parsed")]
InvalidAuthorityDisplay,
#[error("The DISPLAY is not set")]
DisplayNotSet,
#[error("DISPLAY contains an invalid value")]
InvalidDisplayFormat,
#[error("Could not create a unix socket")]
CreateSocket(#[source] OsError),
#[error("Could not connect to Xserver")]
ConnectSocket(#[source] OsError),
#[error("Could not retrive the hostname")]
Hostname(#[source] OsError),
#[error("Server did not send enough fds")]
NotEnoughFds,
#[error("Server rejected our connection attempt: {0}")]
Connect(BString),
#[error("Server requires additional authentication: {0}")]
Authenticate(BString),
#[error(transparent)]
AsyncError(#[from] AsyncError),
#[error(transparent)]
BufIoError(#[from] BufIoError),
#[error("The server did not send a reply to a request")]
MissingReply,
#[error("The server did not send fds with a reply")]
MissingFds,
#[error("The server sent a message with an excessive size")]
ExcessiveMessageSize,
#[error(transparent)]
XconError(Rc<XconError>),
#[error("The server does not support the `{0}` extension")]
ExtensionUnavailable(&'static str),
#[error("The server returned error {0}")]
CoreError(u8),
#[error("The extension `{}` returned error {1}", .0.name())]
ExtensionError(Extension, u8),
#[error("The connection to the server has already been closed")]
Dead,
#[error("Could not query the `{0}` extension")]
QueryExtension(BString, #[source] Box<XconError>),
#[error("All available xids have been used")]
XidExhausted,
#[error("Enum contains an unknown variant")]
UnknownEnumVariant,
}
#[derive(Debug)]
struct ExtensionIdRange {
name: BString,
extension: Option<Extension>,
first: u8,
}
#[derive(Default, Debug)]
struct ExtensionData {
opcodes: [Option<u8>; EXTENSIONS.len()],
ext_by_opcode: AHashMap<u8, Extension>,
events: Vec<ExtensionIdRange>,
errors: Vec<ExtensionIdRange>,
}
pub struct Xcon {
data: Rc<XconData>,
outgoing: Cell<Option<SpawnedFuture<()>>>,
incoming: Cell<Option<SpawnedFuture<()>>>,
setup: Reply<Setup<'static>>,
extensions: Rc<ExtensionData>,
xid_next: Cell<u32>,
xid_inc: u32,
xid_max: u32,
}
struct XconData {
bufio: Rc<BufIo>,
next_serial: NumCell<u64>,
last_recv_serial: Cell<u64>,
reply_handlers: RefCell<VecDeque<Box<dyn ReplyHandler>>>,
dead: Cell<bool>,
need_sync: Cell<bool>,
extensions: CloneCell<Option<Rc<ExtensionData>>>,
xorg: CloneCell<Weak<Xcon>>,
events: AsyncQueue<Event>,
}
pub struct Reply<T: Message<'static>> {
bufio: Rc<BufIo>,
buf: Vec<u8>,
t: T::Generic<'static>,
}
pub struct Event {
bufio: Rc<BufIo>,
ext: Option<Extension>,
code: u16,
buf: Vec<u8>,
}
impl Deref for Event {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.buf
}
}
impl Event {
pub fn ext(&self) -> Option<Extension> {
self.ext
}
pub fn code(&self) -> u16 {
self.code
}
pub fn parse<'a, M: Message<'a>>(&'a self) -> Result<M, XconError> {
let mut parser = Parser::new(&self.buf, vec![]);
M::deserialize(&mut parser)
}
}
impl Drop for Event {
fn drop(&mut self) {
self.bufio.add_buf(mem::take(&mut self.buf));
}
}
impl<T: Message<'static>> Reply<T> {
pub fn get<'a>(&'a self) -> &'a T::Generic<'a> {
unsafe { mem::transmute(&self.t) }
}
}
impl<T: Message<'static>> Drop for Reply<T> {
fn drop(&mut self) {
if self.buf.capacity() > 0 {
self.bufio.add_buf(mem::take(&mut self.buf));
}
}
}
unsafe trait ReplyHandler {
fn has_fds(&self) -> bool;
fn serial(&self) -> u64;
fn handle_result(
self: Box<Self>,
bufio: &Rc<BufIo>,
parser: &mut Parser<'static>,
buf: Vec<u8>,
) -> Result<(), XconError>;
fn handle_noreply(self: Box<Self>, bufio: &Rc<BufIo>) -> Result<(), XconError>;
fn handle_error(self: Box<Self>, error: XconError);
}
struct AsyncReplyHandler<T: Message<'static>> {
serial: u64,
slot: Weak<AsyncReplySlot<T>>,
}
impl<T: Message<'static>> AsyncReplyHandler<T> {
fn done(self: Box<Self>, res: Result<Reply<T>, XconError>) {
if let Some(slot) = self.slot.upgrade() {
slot.data.set(Some(res));
if let Some(waker) = slot.waker.take() {
waker.wake();
}
}
}
}
unsafe impl<T: Message<'static>> ReplyHandler for AsyncReplyHandler<T> {
fn has_fds(&self) -> bool {
T::HAS_FDS
}
fn serial(&self) -> u64 {
self.serial
}
fn handle_result(
self: Box<Self>,
bufio: &Rc<BufIo>,
parser: &mut Parser<'static>,
buf: Vec<u8>,
) -> Result<(), XconError> {
let msg = <T::Generic<'static> as Message<'static>>::deserialize(parser);
let msg = match msg {
Ok(m) => m,
Err(e) => {
let e = Rc::new(e);
self.done(Err(XconError::XconError(e.clone())));
return Err(XconError::XconError(e));
}
};
let reply = Reply {
bufio: bufio.clone(),
buf,
t: msg,
};
self.done(Ok(reply));
Ok(())
}
fn handle_noreply(self: Box<Self>, bufio: &Rc<BufIo>) -> Result<(), XconError> {
if TypeId::of::<T::Generic<'static>>() == TypeId::of::<()>() {
let reply = Reply {
bufio: bufio.clone(),
buf: vec![],
t: unsafe { ptr::read(&() as *const () as *const T::Generic<'static>) },
};
self.done(Ok(reply));
Ok(())
} else {
self.done(Err(XconError::MissingReply));
Err(XconError::MissingReply)
}
}
fn handle_error(self: Box<Self>, error: XconError) {
self.done(Err(error))
}
}
struct AsyncReplySlot<T: Message<'static>> {
data: Cell<Option<Result<Reply<T>, XconError>>>,
waker: Cell<Option<Waker>>,
}
pub struct AsyncReply<T: Message<'static>> {
slot: Rc<AsyncReplySlot<T>>,
xorg: Rc<XconData>,
}
impl<T: Message<'static>> Future for AsyncReply<T> {
type Output = Result<Reply<T>, XconError>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Some(d) = self.slot.data.take() {
Poll::Ready(d)
} else {
self.slot.waker.set(Some(cx.waker().clone()));
self.xorg.send_sync();
Poll::Pending
}
}
}
impl Xcon {
pub fn setup(&self) -> &Setup {
self.setup.get()
}
pub async fn event(&self) -> Event {
self.data.events.pop().await
}
pub fn generate_id(&self) -> Result<u32, XconError> {
if self.xid_next.get() == self.xid_max {
return Err(XconError::XidExhausted);
}
let id = self.xid_next.get();
self.xid_next.set(id + self.xid_inc);
Ok(id)
}
pub async fn connect(eng: Rc<AsyncEngine>) -> Result<Rc<Self>, XconError> {
let authority = match XAuthority::load() {
Ok(a) => a,
Err(e) => {
log::warn!(
"Could not parse Xauthority file. Proceeding without authorization: {}",
ErrorFmt(e)
);
vec![]
}
};
let display = parse_display()?;
let mut addr = c::sockaddr_un {
sun_family: c::AF_UNIX as _,
..uapi::pod_zeroed()
};
{
let mut path = uapi::as_bytes_mut(&mut addr.sun_path[..]);
let _ = write!(path, "/tmp/.X11-unix/X{}", display);
}
let fd = match uapi::socket(
c::AF_UNIX,
c::SOCK_STREAM | c::SOCK_CLOEXEC | c::SOCK_NONBLOCK,
0,
) {
Ok(fd) => Rc::new(fd),
Err(e) => return Err(XconError::CreateSocket(e.into())),
};
if let Err(e) = uapi::connect(fd.raw(), &addr) {
return Err(XconError::ConnectSocket(e.into()));
}
let mut hnbuf = [MaybeUninit::<u8>::uninit(); 256];
let hn = match uapi::gethostname(&mut hnbuf[..]) {
Ok(hn) => hn.to_bytes(),
Err(e) => return Err(XconError::Hostname(e.into())),
};
let (auth_method, auth_value) = 'auth: {
for auth in &authority {
if auth.display == display
&& auth.family == LOCAL
&& auth.host == hn
&& auth.method == MIT_MAGIC_COOKIE
{
break 'auth (&auth.method[..], &auth.value[..]);
}
}
(&[], &[])
};
Self::connect_to_fd(&eng, &fd, auth_method, auth_value).await
}
pub async fn connect_to_fd(
eng: &Rc<AsyncEngine>,
fd: &Rc<OwnedFd>,
auth_method: &[u8],
auth_value: &[u8],
) -> Result<Rc<Self>, XconError> {
let fd = eng.fd(fd)?;
let data = Rc::new(XconData {
bufio: Rc::new(BufIo::new(fd)),
next_serial: NumCell::new(1),
last_recv_serial: Cell::new(0),
reply_handlers: Default::default(),
dead: Cell::new(false),
need_sync: Cell::new(false),
extensions: Default::default(),
xorg: CloneCell::new(Weak::new()),
events: Default::default(),
});
let outgoing = eng.spawn2(Phase::PostLayout, handle_outgoing(data.clone()));
let mut buf = data.bufio.buf();
let mut fds = vec![];
{
let mut formatter = Formatter::new(&mut fds, &mut buf, 0);
#[cfg(target_endian = "little")]
const ENDIAN: u8 = b'l';
#[cfg(target_endian = "big")]
const ENDIAN: u8 = b'B';
formatter.write_packed(&ENDIAN);
formatter.pad(1);
formatter.write_packed(&11u16);
formatter.write_packed(&0u16);
formatter.write_packed(&(auth_method.len() as u16));
formatter.write_packed(&(auth_value.len() as u16));
formatter.pad(2);
formatter.write_packed(auth_method.as_bytes());
formatter.align(4);
formatter.write_packed(auth_value.as_bytes());
formatter.align(4);
}
data.bufio.send(BufIoMessage { fds, buf });
let mut incoming = data.bufio.incoming();
let mut buf = data.bufio.buf();
incoming.fill_msg_buf(8, &mut buf).await?;
let len = u16::from_ne_bytes([buf[6], buf[7]]) as usize * 4;
incoming.fill_msg_buf(len, &mut buf).await?;
let mut parser = Parser::new(&buf, vec![]);
let res: u8 = buf[0];
if res == 0 {
parser.pad(1)?;
let reason_len: u8 = parser.read_pod()?;
parser.pad(6)?;
let reason = parser.read_string(reason_len as usize)?;
return Err(XconError::Connect(reason.to_owned()));
}
if res == 2 {
parser.pad(6)?;
let reason_len: u16 = parser.read_pod()?;
let reason = parser.read_string(reason_len as usize * 4)?;
return Err(XconError::Authenticate(reason.to_owned()));
}
let setup = Setup::deserialize(&mut parser)?;
let incoming = eng.spawn(handle_incoming(data.clone(), incoming));
let slf = Rc::new(Self {
extensions: data.fetch_extension_data().await?,
outgoing: Cell::new(Some(outgoing)),
incoming: Cell::new(Some(incoming)),
xid_next: Cell::new(setup.resource_id_base),
xid_inc: 1 << setup.resource_id_mask.trailing_zeros(),
xid_max: setup.resource_id_mask | setup.resource_id_base,
setup: Reply {
bufio: data.bufio.clone(),
t: unsafe { mem::transmute(setup) },
buf,
},
data,
});
slf.data.xorg.set(Rc::downgrade(&slf));
Ok(slf)
}
pub fn call<'a, T: Request<'a>>(self: &Rc<Self>, t: &T) -> AsyncReply<T::Reply> {
self.data.call(t, &self.extensions)
}
}
impl XconData {
fn kill(&self) {
self.bufio.shutdown();
self.dead.set(true);
let handlers = mem::take(self.reply_handlers.borrow_mut().deref_mut());
for handler in handlers {
handler.handle_error(XconError::Dead);
}
if let Some(xorg) = self.xorg.get().upgrade() {
xorg.outgoing.take();
xorg.incoming.take();
}
}
fn call<'a, T: Request<'a>>(
self: &Rc<Self>,
t: &T,
extensions: &ExtensionData,
) -> AsyncReply<T::Reply> {
if self.dead.get() {
return AsyncReply {
slot: Rc::new(AsyncReplySlot {
data: Cell::new(Some(Err(XconError::Dead))),
waker: Cell::new(None),
}),
xorg: self.clone(),
};
}
let opcode = match T::EXTENSION {
None => 0,
Some(idx) => match extensions.opcodes[idx] {
Some(o) => o,
_ => {
return AsyncReply {
slot: Rc::new(AsyncReplySlot {
data: Cell::new(Some(Err(XconError::ExtensionUnavailable(
EXTENSIONS[idx].name(),
)))),
waker: Cell::new(None),
}),
xorg: self.clone(),
}
}
},
};
let mut fds = vec![];
let mut buf = self.bufio.buf();
let mut formatter = Formatter::new(&mut fds, &mut buf, opcode);
t.serialize(&mut formatter);
formatter.write_request_length();
self.bufio.send(BufIoMessage { fds, buf });
let slot = Rc::new(AsyncReplySlot {
data: Cell::new(None),
waker: Cell::new(None),
});
let handler = Box::new(AsyncReplyHandler {
serial: self.next_serial.fetch_add(1),
slot: Rc::downgrade(&slot),
});
self.reply_handlers.borrow_mut().push_back(handler);
self.need_sync.set(T::IS_VOID);
AsyncReply {
slot,
xorg: self.clone(),
}
}
fn send_sync(&self) {
if !self.need_sync.replace(false) {
return;
}
let mut fds = vec![];
let mut buf = self.bufio.buf();
let mut formatter = Formatter::new(&mut fds, &mut buf, 0);
GetInputFocus {}.serialize(&mut formatter);
formatter.write_request_length();
self.bufio.send(BufIoMessage { fds, buf });
self.next_serial.fetch_add(1);
}
async fn fetch_extension_data(self: &Rc<Self>) -> Result<Rc<ExtensionData>, XconError> {
let mut ext_by_name = AHashMap::new();
for e in EXTENSIONS.iter().copied() {
ext_by_name.insert(e.name().as_bytes().as_bstr(), e);
}
let mut ed = ExtensionData::default();
let extensions = self.call(&ListExtensions {}, &ed).await?;
let mut pending = vec![];
for name in extensions.get().names.iter() {
pending.push((name.val, self.call(&QueryExtension { name: name.val }, &ed)));
}
for (name, data) in pending {
let data = match data.await {
Ok(d) => d,
Err(e) => return Err(XconError::QueryExtension(name.to_owned(), Box::new(e))),
};
let data = data.get();
if data.present != 0 {
let e = ext_by_name.get(name).copied();
if data.first_event > 0 {
ed.events.push(ExtensionIdRange {
name: name.to_owned(),
extension: e,
first: data.first_event,
});
}
if data.first_error > 0 {
ed.errors.push(ExtensionIdRange {
name: name.to_owned(),
extension: e,
first: data.first_error,
});
}
if let Some(e) = e {
ed.opcodes[e as usize] = Some(data.major_opcode);
ed.ext_by_opcode.insert(data.major_opcode, e);
}
}
}
ed.events.sort_by_key(|e| e.first);
ed.errors.sort_by_key(|e| e.first);
let ed = Rc::new(ed);
self.extensions.set(Some(ed.clone()));
Ok(ed)
}
}
fn parse_display() -> Result<u32, XconError> {
let display = match std::env::var("DISPLAY") {
Ok(d) => d,
_ => return Err(XconError::DisplayNotSet),
};
let num = match display.strip_prefix(":") {
Some(p) => p,
_ => return Err(XconError::InvalidDisplayFormat),
};
let num = match num.parse() {
Ok(v) => v,
_ => return Err(XconError::InvalidDisplayFormat),
};
Ok(num)
}

103
src/xcon/consts.rs Normal file
View file

@ -0,0 +1,103 @@
#![allow(dead_code)]
pub const XGE_EVENT: u8 = 35;
pub const INPUT_DEVICE_ALL: u16 = 0;
pub const INPUT_DEVICE_ALL_MASTER: u16 = 1;
pub const WINDOW_CLASS_INPUT_OUTPUT: u16 = 1;
pub const PROP_MODE_REPLACE: u8 = 0;
pub const ATOM_WM_CLASS: u32 = 67;
pub const ATOM_STRING: u32 = 31;
pub const EVENT_MASK_NO_EVENT: u32 = 0;
pub const EVENT_MASK_KEY_PRESS: u32 = 1;
pub const EVENT_MASK_KEY_RELEASE: u32 = 2;
pub const EVENT_MASK_BUTTON_PRESS: u32 = 4;
pub const EVENT_MASK_BUTTON_RELEASE: u32 = 8;
pub const EVENT_MASK_ENTER_WINDOW: u32 = 16;
pub const EVENT_MASK_LEAVE_WINDOW: u32 = 32;
pub const EVENT_MASK_POINTER_MOTION: u32 = 64;
pub const EVENT_MASK_POINTER_MOTION_HINT: u32 = 128;
pub const EVENT_MASK_BUTTON_1_MOTION: u32 = 256;
pub const EVENT_MASK_BUTTON_2_MOTION: u32 = 512;
pub const EVENT_MASK_BUTTON_3_MOTION: u32 = 1024;
pub const EVENT_MASK_BUTTON_4_MOTION: u32 = 2048;
pub const EVENT_MASK_BUTTON_5_MOTION: u32 = 4096;
pub const EVENT_MASK_BUTTON_MOTION: u32 = 8192;
pub const EVENT_MASK_KEYMAP_STATE: u32 = 16384;
pub const EVENT_MASK_EXPOSURE: u32 = 32768;
pub const EVENT_MASK_VISIBILITY_CHANGE: u32 = 65536;
pub const EVENT_MASK_STRUCTURE_NOTIFY: u32 = 131072;
pub const EVENT_MASK_RESIZE_REDIRECT: u32 = 262144;
pub const EVENT_MASK_SUBSTRUCTURE_NOTIFY: u32 = 524288;
pub const EVENT_MASK_SUBSTRUCTURE_REDIRECT: u32 = 1048576;
pub const EVENT_MASK_FOCUS_CHANGE: u32 = 2097152;
pub const EVENT_MASK_PROPERTY_CHANGE: u32 = 4194304;
pub const EVENT_MASK_COLOR_MAP_CHANGE: u32 = 8388608;
pub const EVENT_MASK_OWNER_GRAB_BUTTON: u32 = 16777216;
pub const XI_EVENT_MASK_DEVICE_CHANGED: u32 = 2;
pub const XI_EVENT_MASK_KEY_PRESS: u32 = 4;
pub const XI_EVENT_MASK_KEY_RELEASE: u32 = 8;
pub const XI_EVENT_MASK_BUTTON_PRESS: u32 = 16;
pub const XI_EVENT_MASK_BUTTON_RELEASE: u32 = 32;
pub const XI_EVENT_MASK_MOTION: u32 = 64;
pub const XI_EVENT_MASK_ENTER: u32 = 128;
pub const XI_EVENT_MASK_LEAVE: u32 = 256;
pub const XI_EVENT_MASK_FOCUS_IN: u32 = 512;
pub const XI_EVENT_MASK_FOCUS_OUT: u32 = 1024;
pub const XI_EVENT_MASK_HIERARCHY: u32 = 2048;
pub const XI_EVENT_MASK_PROPERTY: u32 = 4096;
pub const XI_EVENT_MASK_RAW_KEY_PRESS: u32 = 8192;
pub const XI_EVENT_MASK_RAW_KEY_RELEASE: u32 = 16384;
pub const XI_EVENT_MASK_RAW_BUTTON_PRESS: u32 = 32768;
pub const XI_EVENT_MASK_RAW_BUTTON_RELEASE: u32 = 65536;
pub const XI_EVENT_MASK_RAW_MOTION: u32 = 131072;
pub const XI_EVENT_MASK_TOUCH_BEGIN: u32 = 262144;
pub const XI_EVENT_MASK_TOUCH_UPDATE: u32 = 524288;
pub const XI_EVENT_MASK_TOUCH_END: u32 = 1048576;
pub const XI_EVENT_MASK_TOUCH_OWNERSHIP: u32 = 2097152;
pub const XI_EVENT_MASK_RAW_TOUCH_BEGIN: u32 = 4194304;
pub const XI_EVENT_MASK_RAW_TOUCH_UPDATE: u32 = 8388608;
pub const XI_EVENT_MASK_RAW_TOUCH_END: u32 = 16777216;
pub const XI_EVENT_MASK_BARRIER_HIT: u32 = 33554432;
pub const XI_EVENT_MASK_BARRIER_LEAVE: u32 = 67108864;
pub const PRESENT_EVENT_MASK_NO_EVENT: u32 = 0;
pub const PRESENT_EVENT_MASK_CONFIGURE_NOTIFY: u32 = 1;
pub const PRESENT_EVENT_MASK_COMPLETE_NOTIFY: u32 = 2;
pub const PRESENT_EVENT_MASK_IDLE_NOTIFY: u32 = 4;
pub const PRESENT_EVENT_MASK_REDIRECT_NOTIFY: u32 = 8;
pub const INPUT_DEVICE_TYPE_MASTER_POINTER: u16 = 1;
pub const INPUT_DEVICE_TYPE_MASTER_KEYBOARD: u16 = 2;
pub const INPUT_DEVICE_TYPE_SLAVE_POINTER: u16 = 3;
pub const INPUT_DEVICE_TYPE_SLAVE_KEYBOARD: u16 = 4;
pub const INPUT_DEVICE_TYPE_FLOATING_SLAVE: u16 = 5;
pub const XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT: u32 = 1;
pub const XKB_PER_CLIENT_FLAG_GRABS_USE_XKB_STATE: u32 = 2;
pub const XKB_PER_CLIENT_FLAG_AUTO_RESET_CONTROLS: u32 = 4;
pub const XKB_PER_CLIENT_FLAG_LOOKUP_STATE_WHEN_GRABBED: u32 = 8;
pub const XKB_PER_CLIENT_FLAG_SEND_EVENT_USES_XKB_STATE: u32 = 16;
pub const INPUT_HIERARCHY_MASK_MASTER_ADDED: u32 = 1;
pub const INPUT_HIERARCHY_MASK_MASTER_REMOVED: u32 = 2;
pub const INPUT_HIERARCHY_MASK_SLAVE_ADDED: u32 = 4;
pub const INPUT_HIERARCHY_MASK_SLAVE_REMOVED: u32 = 8;
pub const INPUT_HIERARCHY_MASK_SLAVE_ATTACHED: u32 = 16;
pub const INPUT_HIERARCHY_MASK_SLAVE_DETACHED: u32 = 32;
pub const INPUT_HIERARCHY_MASK_DEVICE_ENABLED: u32 = 64;
pub const INPUT_HIERARCHY_MASK_DEVICE_DISABLED: u32 = 128;
pub const GRAB_MODE_SYNC: u8 = 0;
pub const GRAB_MODE_ASYNC: u8 = 1;
pub const GRAB_STATUS_SUCCESS: u8 = 0;
pub const GRAB_STATUS_ALREADY_GRABBED: u8 = 1;
pub const GRAB_STATUS_INVALID_TIME: u8 = 2;
pub const GRAB_STATUS_NOT_VIEWABLE: u8 = 3;
pub const GRAB_STATUS_FROZEN: u8 = 4;

62
src/xcon/formatter.rs Normal file
View file

@ -0,0 +1,62 @@
use crate::xcon::Message;
use std::rc::Rc;
use uapi::{AssertPacked, OwnedFd, Packed};
pub struct Formatter<'a> {
fds: &'a mut Vec<Rc<OwnedFd>>,
buf: &'a mut Vec<u8>,
ext_opcode: u8,
}
impl<'a> Formatter<'a> {
pub fn new(fds: &'a mut Vec<Rc<OwnedFd>>, buf: &'a mut Vec<u8>, ext_opcode: u8) -> Self {
Self {
fds,
buf,
ext_opcode,
}
}
pub fn ext_opcode(&self) -> u8 {
self.ext_opcode
}
pub fn pad(&mut self, pad: usize) {
static BUF: [u8; 8] = [0; 8];
self.buf.extend_from_slice(&BUF[..pad]);
}
pub fn align(&mut self, alignment: usize) {
static BUF: [u8; 8] = [0; 8];
let len = self.buf.len().wrapping_neg() & (alignment - 1);
self.buf.extend_from_slice(&BUF[..len]);
}
pub fn write_packed<T: Packed + ?Sized>(&mut self, t: &T) {
self.buf.extend_from_slice(uapi::as_bytes(t));
}
pub fn write_list<'b, T: Message<'b>>(&mut self, t: &[T]) {
if T::IS_POD {
self.buf
.extend_from_slice(uapi::as_bytes(unsafe { AssertPacked::new(t) }));
} else {
for t in t {
t.serialize(self);
}
}
}
pub fn write_bytes(&mut self, b: &[u8]) {
self.buf.extend_from_slice(b);
}
pub fn write_request_length(&mut self) {
let len: u16 = (self.buf.len() / 4) as u16;
self.buf[2..4].copy_from_slice(&len.to_ne_bytes());
}
pub fn add_fd(&mut self, fd: &Rc<OwnedFd>) {
self.fds.push(fd.clone());
}
}

222
src/xcon/incoming.rs Normal file
View file

@ -0,0 +1,222 @@
use crate::utils::bufio::BufIoIncoming;
use crate::xcon::consts::XGE_EVENT;
use crate::xcon::{Event, ExtensionData, ExtensionIdRange, Parser, XconData, XconError};
use crate::ErrorFmt;
use std::mem;
use std::rc::Rc;
pub(super) async fn handle_incoming(xorg: Rc<XconData>, incoming: BufIoIncoming) {
let mut incoming = Incoming {
incoming,
socket: xorg,
ed: None,
};
incoming.run().await;
}
pub struct Incoming {
socket: Rc<XconData>,
incoming: BufIoIncoming,
ed: Option<Rc<ExtensionData>>,
}
impl Incoming {
async fn run(&mut self) {
loop {
if self.socket.dead.get() {
return;
}
if let Err(e) = self.handle_msg().await {
log::error!("Could not process an incoming message: {}", ErrorFmt(e));
self.socket.kill();
return;
}
}
}
async fn handle_msg(&mut self) -> Result<(), XconError> {
const MAX_LENGTH_UNITS: usize = 0x4000 / 4;
const MIN_MSG_SIZE: usize = 32;
let mut msg_buf = self.socket.bufio.buf();
self.incoming
.fill_msg_buf(MIN_MSG_SIZE, &mut msg_buf)
.await?;
let mut serial = 0;
const KEYMAP_NOTIFY: u8 = 11;
let mut reply_handlers = self.socket.reply_handlers.borrow_mut();
if msg_buf[0] & 0x7f != KEYMAP_NOTIFY {
let serial_16 = u16::from_ne_bytes([msg_buf[2], msg_buf[3]]);
serial = (self.socket.last_recv_serial.get() & !0xffff) | (serial_16 as u64);
if serial < self.socket.last_recv_serial.get() {
serial += 0x10000;
}
self.socket.last_recv_serial.set(serial);
while let Some(first) = reply_handlers.front() {
if first.serial() < serial {
let handler = reply_handlers.pop_front().unwrap();
drop(reply_handlers);
handler.handle_noreply(&self.socket.bufio)?;
reply_handlers = self.socket.reply_handlers.borrow_mut();
} else {
break;
}
}
}
if self.ed.is_none() {
self.ed = self.socket.extensions.get();
}
match msg_buf[0] & 0x7f {
0 => 'handle_error: {
let code = msg_buf[1];
let (ext, code) = if code < 128 {
(None, code)
} else if let Some(ed) = &self.ed {
let r = match find_range(&ed.errors, code) {
Some(r) => r,
_ => {
log::error!("Received an out of bounds error code {}", code);
break 'handle_error;
}
};
match r.extension {
Some(e) => (Some(e), code - r.first),
None => {
log::warn!(
"Received an error from an unconfigured extension: `{}`",
r.name
);
break 'handle_error;
}
}
} else {
log::error!("Received an extension error before extension have been fetched");
break 'handle_error;
};
let e = match ext {
Some(e) => XconError::ExtensionError(e, code),
_ => XconError::CoreError(code),
};
if let Some(first) = reply_handlers.front() {
if first.serial() == serial {
let handler = reply_handlers.pop_front().unwrap();
drop(reply_handlers);
handler.handle_error(e);
break 'handle_error;
}
}
log::error!(
"Received an error with no corresponding handler: {}",
ErrorFmt(e)
);
}
1 => {
if let Some(first) = reply_handlers.front() {
if first.serial() == serial {
let handler = reply_handlers.pop_front().unwrap();
drop(reply_handlers);
let mut fds = vec![];
if handler.has_fds() {
let num_fds = msg_buf[1] as usize;
if self.incoming.fds.len() < num_fds {
return Err(XconError::MissingFds);
}
fds.extend(self.incoming.fds.drain(..num_fds));
}
let length =
u32::from_ne_bytes([msg_buf[4], msg_buf[5], msg_buf[6], msg_buf[7]])
as usize;
if length > MAX_LENGTH_UNITS {
return Err(XconError::ExcessiveMessageSize);
}
let length = length * 4;
self.incoming.fill_msg_buf(length, &mut msg_buf).await?;
let mut parser = unsafe {
let msg_buf = mem::transmute::<&[u8], &'static [u8]>(&msg_buf[..]);
Parser::new(msg_buf, fds)
};
handler.handle_result(
&self.socket.bufio,
&mut parser,
mem::take(&mut msg_buf),
)?;
}
}
}
ev => 'handle_event: {
let (ext, code) = if ev == XGE_EVENT {
let length =
u32::from_ne_bytes([msg_buf[4], msg_buf[5], msg_buf[6], msg_buf[7]])
as usize;
if length > MAX_LENGTH_UNITS {
return Err(XconError::ExcessiveMessageSize);
}
let length = length * 4;
self.incoming.fill_msg_buf(length, &mut msg_buf).await?;
let opcode = msg_buf[1];
let ext = match &self.ed {
Some(ed) => ed.ext_by_opcode.get(&opcode),
_ => {
log::error!("Received an XGE event before extension have been fetched");
break 'handle_event;
}
};
let ext = match ext {
Some(ext) => *ext,
_ => {
log::warn!(
"Received an event from an unconfigured extension: `{}`",
opcode
);
break 'handle_event;
}
};
let code = u16::from_ne_bytes([msg_buf[8], msg_buf[9]]);
(Some(ext), code)
} else if ev < 64 {
(None, ev as u16)
} else if let Some(ed) = &self.ed {
let r = match find_range(&ed.events, ev) {
Some(r) => r,
_ => {
log::error!("Received an out of bounds event {}", ev);
break 'handle_event;
}
};
match r.extension {
Some(e) => (Some(e), (ev - r.first) as u16),
None => {
log::warn!(
"Received an event from an unconfigured extension: `{}`",
r.name
);
break 'handle_event;
}
}
} else {
log::error!("Received an extension event before extension have been fetched");
break 'handle_event;
};
self.socket.events.push(Event {
bufio: self.socket.bufio.clone(),
ext,
code,
buf: mem::take(&mut msg_buf),
});
}
}
if msg_buf.capacity() > 0 {
self.socket.bufio.add_buf(msg_buf);
}
Ok(())
}
}
fn find_range(codes: &[ExtensionIdRange], code: u8) -> Option<&ExtensionIdRange> {
let idx = match codes.binary_search_by_key(&code, |v| v.first) {
Ok(v) => v,
Err(v) if v > 0 => v - 1,
_ => return None,
};
Some(&codes[idx])
}

10
src/xcon/outgoing.rs Normal file
View file

@ -0,0 +1,10 @@
use crate::xcon::XconData;
use crate::ErrorFmt;
use std::rc::Rc;
pub(super) async fn handle_outgoing(socket: Rc<XconData>) {
if let Err(e) = socket.bufio.clone().outgoing().await {
log::error!("{}", ErrorFmt(e));
}
socket.kill();
}

138
src/xcon/parser.rs Normal file
View file

@ -0,0 +1,138 @@
use crate::utils::ptr_ext::PtrExt;
use crate::xcon::wire_type::Message;
use crate::xcon::XconError;
use bstr::{BStr, ByteSlice};
use std::borrow::Cow;
use std::mem;
use std::rc::Rc;
use uapi::{OwnedFd, Pod};
pub struct Parser<'a> {
pos: usize,
buf: &'a [u8],
fds_pos: usize,
fds: Vec<Rc<OwnedFd>>,
}
impl<'a> Parser<'a> {
pub fn new(buf: &'a [u8], fds: Vec<Rc<OwnedFd>>) -> Self {
Self {
buf,
pos: 0,
fds,
fds_pos: 0,
}
}
pub fn eof(&self) -> bool {
self.pos == self.buf.len()
}
fn rem(&self) -> usize {
self.buf.len() - self.pos
}
pub fn unmarshal<T: Message<'a>>(&mut self) -> Result<T, XconError> {
T::deserialize(self)
}
pub fn pad(&mut self, new: usize) -> Result<(), XconError> {
if new > self.buf.len() - self.pos {
return Err(XconError::UnexpectedEof);
}
self.pos += new;
Ok(())
}
pub fn align(&mut self, n: usize) -> Result<(), XconError> {
let new = self.pos + (self.pos.wrapping_neg() & (n - 1));
if new > self.buf.len() {
return Err(XconError::UnexpectedEof);
}
self.pos = new;
Ok(())
}
pub fn read_fd(&mut self) -> Result<Rc<OwnedFd>, XconError> {
if self.fds_pos >= self.fds.len() {
return Err(XconError::NotEnoughFds);
}
self.fds_pos += 1;
Ok(self.fds[self.fds_pos - 1].clone())
}
pub fn read_pod<'b, T: Pod>(&mut self) -> Result<T, XconError> {
match uapi::pod_read_init(&self.buf[self.pos..]) {
Ok(v) => {
self.pos += mem::size_of::<T>();
Ok(v)
}
_ => Err(XconError::UnexpectedEof),
}
}
pub fn read_list_slice<T: Message<'a> + Pod>(
&mut self,
n: Option<usize>,
) -> Result<&'a [T], XconError> {
let n = match n {
Some(n) => n,
_ => self.rem() / mem::size_of::<T>(),
};
let len = mem::size_of::<T>() * n;
if len > self.rem() {
return Err(XconError::UnexpectedEof);
}
if self.buf[self.pos..].as_ptr() as usize & (mem::align_of::<T>() - 1) != 0 {
return Err(XconError::UnalignedSlice);
}
let res =
unsafe { std::slice::from_raw_parts(self.buf.as_ptr().add(self.pos) as *const T, n) };
self.pos += len;
Ok(res)
}
pub fn read_list<T: Message<'a> + Clone>(
&mut self,
n: Option<usize>,
) -> Result<Cow<'a, [T]>, XconError> {
let mut res = vec![];
if let Some(n) = n {
for _ in 0..n {
res.push(T::deserialize(self)?);
}
} else {
while !self.eof() {
res.push(T::deserialize(self)?);
}
}
Ok(res.into())
}
pub fn read_bytes<const N: usize>(&mut self) -> Result<&'a [u8; N], XconError> {
if N > self.rem() {
return Err(XconError::UnexpectedEof);
}
let res = unsafe { self.buf.as_ptr().add(self.pos).cast::<[u8; N]>().deref() };
self.pos += N;
Ok(res)
}
pub fn read_slice(&mut self, n: usize) -> Result<&'a [u8], XconError> {
if n > self.rem() {
return Err(XconError::UnexpectedEof);
}
let res = &self.buf[self.pos..self.pos + n];
self.pos += n;
Ok(res)
}
pub fn read_string(&mut self, n: usize) -> Result<&'a BStr, XconError> {
if n > self.rem() {
return Err(XconError::UnexpectedEof);
}
let res = &self.buf[self.pos..self.pos + n];
self.pos += n;
Ok(res.as_bstr())
}
}

118
src/xcon/wire_type.rs Normal file
View file

@ -0,0 +1,118 @@
use crate::xcon::formatter::Formatter;
use crate::xcon::parser::Parser;
use crate::xcon::XconError;
use bstr::{BStr, ByteSlice};
use std::borrow::Cow;
use std::rc::Rc;
use uapi::OwnedFd;
#[cold]
fn unimplemented() -> ! {
unimplemented!();
}
pub unsafe trait Message<'a>: Clone + 'a {
type Generic<'b>: Message<'b>;
const IS_POD: bool;
const HAS_FDS: bool;
fn serialize(&self, formatter: &mut Formatter) {
let _ = formatter;
unimplemented()
}
fn deserialize(parser: &mut Parser<'a>) -> Result<Self, XconError> {
let _ = parser;
unimplemented()
}
}
pub trait Request<'a>: Message<'a> {
type Reply: Message<'static>;
const EXTENSION: Option<usize>;
const IS_VOID: bool;
}
pub trait XEvent<'a>: Message<'a> {
const OPCODE: u16;
}
macro_rules! simple {
($ty:ty) => {
unsafe impl Message<'_> for $ty {
type Generic<'b> = $ty;
const IS_POD: bool = true;
const HAS_FDS: bool = false;
fn serialize(&self, formatter: &mut Formatter) {
formatter.write_packed(self);
}
fn deserialize(parser: &mut Parser<'_>) -> Result<Self, XconError> {
parser.read_pod()
}
}
};
}
simple!(u8);
simple!(i8);
simple!(u16);
simple!(i16);
simple!(u32);
simple!(i32);
simple!(u64);
simple!(i64);
unsafe impl<'a> Message<'a> for () {
type Generic<'b> = ();
const IS_POD: bool = false;
const HAS_FDS: bool = false;
}
unsafe impl<'a> Message<'a> for &'a BStr {
type Generic<'b> = &'b BStr;
const IS_POD: bool = true;
const HAS_FDS: bool = false;
fn serialize(&self, formatter: &mut Formatter) {
formatter.write_packed(self.as_bytes())
}
}
unsafe impl<'a, T: Message<'a>> Message<'a> for &'a [T] {
type Generic<'b> = &'b [T::Generic<'b>];
const IS_POD: bool = false;
const HAS_FDS: bool = false;
fn serialize(&self, formatter: &mut Formatter) {
formatter.write_list(self);
}
}
unsafe impl<'a, T> Message<'a> for Cow<'a, [T]>
where
T: Message<'a>,
{
type Generic<'b> = Cow<'b, [T::Generic<'b>]>;
const IS_POD: bool = false;
const HAS_FDS: bool = false;
fn serialize(&self, formatter: &mut Formatter) {
formatter.write_list(self);
}
}
unsafe impl<'a> Message<'a> for Rc<OwnedFd> {
type Generic<'b> = Rc<OwnedFd>;
const IS_POD: bool = false;
const HAS_FDS: bool = true;
fn serialize(&self, formatter: &mut Formatter) {
formatter.add_fd(self);
}
fn deserialize(parser: &mut Parser<'a>) -> Result<Self, XconError> {
parser.read_fd()
}
}

96
src/xcon/xauthority.rs Normal file
View file

@ -0,0 +1,96 @@
use crate::xcon::XconError;
use bstr::{BString, ByteSlice};
use std::fs::File;
use std::io::Read;
pub const LOCAL: u16 = 256;
pub const MIT_MAGIC_COOKIE: &[u8] = b"MIT-MAGIC-COOKIE-1";
#[derive(Debug)]
pub struct XAuthority {
pub family: u16,
pub host: BString,
pub display: u32,
pub method: BString,
pub value: BString,
}
impl XAuthority {
pub fn load() -> Result<Vec<XAuthority>, XconError> {
let path = 'path: {
if let Ok(p) = std::env::var("XAUTHORITY") {
break 'path p;
}
if let Ok(home) = std::env::var("HOME") {
break 'path format!("{home}/.Xauthority");
}
return Err(XconError::HomeNotSet);
};
let mut buf = vec![];
if let Err(e) = File::open(&path).and_then(|mut f| f.read_to_end(&mut buf)) {
return Err(XconError::ReadXAuthority(e));
}
Parser::parse(&buf)
}
}
struct Parser<'a> {
pos: usize,
buf: &'a [u8],
}
impl<'a> Parser<'a> {
fn parse(buf: &[u8]) -> Result<Vec<XAuthority>, XconError> {
let mut slf = Parser { pos: 0, buf };
let mut res = vec![];
while slf.rem() > 0 {
res.push(slf.parse_one()?);
}
Ok(res)
}
fn rem(&self) -> usize {
self.buf.len() - self.pos
}
fn parse_one(&mut self) -> Result<XAuthority, XconError> {
Ok(XAuthority {
family: self.read_u16()?,
host: self.read_string()?,
display: {
let s = self.read_string()?;
match s.to_str() {
Ok(s) => match s.parse() {
Ok(v) => v,
_ => return Err(XconError::InvalidAuthorityDisplay),
},
_ => return Err(XconError::InvalidAuthorityDisplay),
}
},
method: self.read_string()?,
value: self.read_string()?,
})
}
fn read_u16(&mut self) -> Result<u16, XconError> {
if self.rem() < 2 {
return Err(XconError::UnexpectedEof);
}
let bytes = [self.buf[self.pos], self.buf[self.pos + 1]];
self.pos += 2;
Ok(u16::from_be_bytes(bytes))
}
fn read_string(&mut self) -> Result<BString, XconError> {
let len = self.read_u16()? as usize;
if self.rem() < len {
log::info!("rem = {}; len = {}", self.rem(), len);
return Err(XconError::UnexpectedEof);
}
let res = self.buf[self.pos..self.pos + len].to_vec();
self.pos += len;
let res = res.into();
Ok(res)
}
}

31
wire-xcon/dri3.txt Normal file
View file

@ -0,0 +1,31 @@
ext "DRI3"
request Dri3QueryVersion = 0 (
major_version: u32,
minor_version: u32,
) {
@pad 1,
major_version: u32,
minor_version: u32,
}
request Dri3Open = 1 (
drawable: u32,
provider: u32,
) {
@pad 1,
device_fd: fd,
@pad 24,
}
request Dri3PixmapFromBuffer = 2 (
pixmap: u32,
drawable: u32,
size: u32,
width: u16,
height: u16,
stride: u16,
depth: u8,
bpp: u8,
pixmap_fd: fd,
);

59
wire-xcon/present.txt Normal file
View file

@ -0,0 +1,59 @@
ext "Present"
xge PresentCompleteNotify = 1 {
kind: u8,
mode: u8,
event: u32,
window: u32,
serial: u32,
ust: u64,
msc: u64,
}
struct PresentNotify {
window: u32,
serial: u32,
}
xge PresentIdleNotify = 2 {
@pad 2,
event: u32,
window: u32,
serial: u32,
pixmap: u32,
idle_fence: u32,
}
request PresentQueryVersion = 0 (
major_version: u32,
minor_version: u32,
) {
@pad 1,
major_version: u32,
minor_version: u32,
}
request PresentPixmap = 1 (
window: u32,
pixmap: u32,
serial: u32,
valid: u32,
update: u32,
x_off: i16,
y_off: i16,
target_crtc: u32,
wait_fence: u32,
idle_fence: u32,
options: u32,
@pad 4,
target_msc: u64,
divisor: u64,
remainder: u64,
notifies: list(PresentNotify),
);
request PresentSelectInput = 3 (
eid: u32,
window: u32,
event_mask: u32,
);

214
wire-xcon/xinput.txt Normal file
View file

@ -0,0 +1,214 @@
ext "XInputExtension"
struct XiModifierInfo {
base: u32,
latched: u32,
locked: u32,
effective: u32,
}
struct XiGroupInfo {
base: u8,
latched: u8,
locked: u8,
effective: u8,
}
xge XiKeyPress = 2 {
deviceid: u16,
time: u32,
detail: u32,
root: u32,
event: u32,
child: u32,
root_x: i32,
root_y: i32,
event_x: i32,
event_y: i32,
buttons_len: u16 = len(button_mask),
valuators_len: u16 = len(valuator_mask),
sourceid: u16,
@pad 2,
flags: u32,
mods: XiModifierInfo,
groups: XiGroupInfo,
button_mask: list(u32, field(buttons_len)),
valuator_mask: list(u32, field(valuators_len)),
axisvalues: list(u32, mul(sum(map(iter(field(valuator_mask)), popcount(it))), literal(2))),
}
eventcopy XiKeyRelease = 3 = XiKeyPress;
eventcopy XiButtonPress = 4 = XiKeyPress;
eventcopy XiButtonRelease = 5 = XiKeyPress;
eventcopy XiMotion = 6 = XiKeyPress;
xge XiEnter = 7 {
deviceid: u16,
time: u32,
sourceid: u16,
mode: u8,
detail: u8,
root: u32,
event: u32,
child: u32,
root_x: i32,
root_y: i32,
event_x: i32,
event_y: i32,
same_screen: u8,
focus: u8,
buttons_len: u16 = len(buttons),
buttons: list(u32, field(buttons_len)),
}
struct XiHierarchyInfo {
deviceid: u16,
attachment: u16,
ty: u8,
enabled: u8,
@pad 2,
flags: u32,
}
xge XiHierarchy = 11 {
deviceid: u16,
time: u32,
flags: u32,
num_infos: u16 = len(infos),
@pad 10,
infos: list(XiHierarchyInfo, field(num_infos)),
}
request XiQueryVersion = 47 (
major_version: u16,
minor_version: u16,
) {
@pad 1,
major_version: u16,
minor_version: u16,
@pad 20,
}
struct XiEventMask {
deviceid: u16,
mask_len: u16 = len(mask),
mask: list(u32, field(mask_len)),
}
request XiSelectEvents = 46 (
window: u32,
num_mask: u16 = len(masks),
@pad 2,
masks: list(XiEventMask, field(num_mask)),
);
struct XiDeviceClassKey {
num_keys: u16 = len(keys),
keys: list(u32, field(num_keys)),
}
struct XiDeviceClassButton {
num_buttons: u16 = len(labels),
state: list(u32, div(plus(field(num_buttons), literal(31)), literal(32))),
labels: list(u32, field(num_buttons)),
}
struct XiDeviceClassValuator {
number: u16,
label: u32,
min_int: i32,
min_frac: u32,
max_int: i32,
max_frac: u32,
value_int: i32,
value_frac: u32,
resolution: u32,
mode: u8,
@pad 3,
}
struct XiDeviceClassScroll {
number: u16,
scroll_type: u16,
@pad 2,
flags: u32,
increment_int: i32,
increment_frac: u32,
}
struct XiDeviceClassTouch {
mode: u8,
num_touches: u8,
}
enum XiDeviceClassType {
Key: XiDeviceClassKey = 0,
Button: XiDeviceClassButton = 1,
Valuator: XiDeviceClassValuator = 2,
Scroll: XiDeviceClassScroll = 3,
Touch: XiDeviceClassTouch = 8,
}
struct XiDeviceClass {
ty: u16 = variant(data),
len: u16,
sourceid: u16,
data: enum(XiDeviceClassType, field(ty)),
}
struct XiDeviceInfo {
deviceid: u16,
ty: u16,
attachment: u16,
num_classes: u16 = len(classes),
name_len: u16 = len(name),
enabled: u8,
@pad 1,
name: str(field(name_len)),
@align 4,
classes: list(XiDeviceClass, field(num_classes)),
}
request XiQueryDevice = 48 (
deviceid: u16,
@pad 2,
) {
@pad 1,
num_infos: u16 = len(infos),
@pad 22,
infos: list(XiDeviceInfo, field(num_infos)),
}
request XiGetDeviceButtonMapping = 28 (
device_id: u8,
@pad 3,
) {
xi_reply_type: u8,
map_size: u8 = len(map),
@pad 23,
map: list(u8, field(map_size)),
@align 4,
}
request XiGrabDevice = 51 (
window: u32,
time: u32,
cursor: u32,
deviceid: u16,
mode: u8,
paired_device_mode: u8,
owner_events: u8,
@pad 1,
mask_len: u16 = len(mask),
mask: list(u32, field(mask_len)),
) {
@pad 1,
status: u8,
@pad 23,
}
request XiUngrabDevice = 52 (
time: u32,
deviceid: u16,
@pad 2,
);

28
wire-xcon/xkb.txt Normal file
View file

@ -0,0 +1,28 @@
ext "XKEYBOARD"
request XkbUseExtension = 0 (
wanted_major: u16,
wanted_minor: u16,
) {
supported: u8,
server_major: u16,
server_minor: u16,
@pad 20,
}
request XkbPerClientFlags = 21 (
device_spec: u16,
@pad 2,
change: u32,
value: u32,
ctrls_to_change: u32,
auto_ctrls: u32,
auto_ctrls_values: u32,
) {
device_id: u8,
supported: u32,
value: u32,
auto_ctrls: u32,
auto_ctrls_values: u32,
@pad 8,
}

264
wire-xcon/xproto.txt Normal file
View file

@ -0,0 +1,264 @@
struct Format {
depth: u8,
bits_per_pixel: u8,
scanline_pad: u8,
@pad 5,
}
struct Visualtype {
visual_id: u32,
class: u8,
bits_per_rgb_value: u8,
colormap_entries: u16,
red_mask: u32,
green_mask: u32,
blue_mask: u32,
@pad 4,
}
struct Depth {
depth: u8,
@pad 1,
num_visualtypes: u16 = len(visuals),
@pad 4,
visuals: list(Visualtype, field(num_visualtypes)),
}
struct Screen {
root: u32,
default_colormap: u32,
white_pixel: u32,
black_pixel: u32,
input_mask: u32,
width: u16,
height: u16,
width_mm: u16,
height_mm: u16,
min_maps: u16,
max_maps: u16,
root_visual: u32,
backing_stores: u8,
save_unders: u8,
root_depth: u8,
number_of_depths: u8 = len(allowed_depths),
allowed_depths: list(Depth, field(number_of_depths)),
}
struct Setup {
success: u8 = literal(1),
@pad 1,
protocol_major: u16,
protocol_minor: u16,
additional_data: u16,
release_number: u32,
resource_id_base: u32,
resource_id_mask: u32,
motion_buffer_size: u32,
vendor_len: u16 = len(vendor),
max_request_length: u16,
number_of_screens: u8 = len(screens),
number_of_formats: u8 = len(formats),
image_byte_order: u8,
bitmap_format_bit_order: u8,
bitmap_format_scanline_unit: u8,
bitmap_format_scanline_pad: u8,
min_keycode: u8,
max_keycode: u8,
@pad 4,
vendor: str(field(vendor_len)),
@align 4,
formats: list(Format, field(number_of_formats)),
screens: list(Screen, field(number_of_screens)),
}
struct Str {
len: u8 = len(val),
val: str(field(len)),
}
request ListExtensions = 99 () {
names_len: u8 = len(names),
@pad 24,
names: list(Str, field(names_len)),
}
request GetInputFocus = 43 () {
revert_to: u8,
focus: u32,
}
request QueryExtension = 98 (
@pad 1,
name_len: u16 = len(name),
@pad 2,
name: str(field(name_len)),
@align 4,
) {
@pad 1,
present: u8,
major_opcode: u8,
first_event: u8,
first_error: u8,
}
bitmask CreateWindowValues {
background_pixmap: u32 = 0,
background_pixel: u32 = 1,
border_pixmap: u32 = 2,
border_pixel: u32 = 3,
bit_gravity: u32 = 4,
win_gravity: u32 = 5,
backing_store: u32 = 6,
backing_planes: u32 = 7,
backing_pixel: u32 = 8,
override_redirect: u32 = 9,
save_under: u32 = 10,
event_mask: u32 = 11,
do_not_propagate_mask: u32 = 12,
colormap: u32 = 13,
cursor: u32 = 14,
}
request CreateWindow = 1 (
depth: u8,
wid: u32,
parent: u32,
x: i16,
y: i16,
width: u16,
height: u16,
border_width: u16,
class: u16,
visual: u32,
value_mask: u32 = bitmask(values),
values: bitmask(CreateWindowValues, field(value_mask)),
);
request ChangeWindowAttributes = 2 (
@pad 1,
window: u32,
value_mask: u32 = bitmask(values),
values: bitmask(CreateWindowValues, field(value_mask)),
);
request DestroyWindow = 4 (
@pad 1,
window: u32,
);
request MapWindow = 8 (
@pad 1,
window: u32,
);
event DestroyNotify = 17 {
@pad 1,
event: u32,
window: u32,
}
event ConfigureNotify = 22 {
@pad 1,
event: u32,
window: u32,
above_sibling: u32,
x: i16,
y: i16,
width: u16,
height: u16,
border_width: u16,
override_redirect: u8,
@pad 1,
}
request CreatePixmap = 53 (
depth: u8,
pid: u32,
drawable: u32,
width: u16,
height: u16,
);
request FreePixmap = 54 (
@pad 1,
pixmap: u32,
);
bitmask GC {
function: u32 = 0,
plane_mask: u32 = 1,
foreground: u32 = 2,
background: u32 = 3,
line_width: u32 = 4,
line_style: u32 = 5,
cap_style: u32 = 6,
join_style: u32 = 7,
fill_style: u32 = 8,
fill_rule: u32 = 9,
tile: u32 = 10,
stipple: u32 = 11,
tile_stipple_x_origin: u32 = 12,
tile_stipple_y_origin: u32 = 13,
font: u32 = 14,
subwindow_mode: u32 = 15,
graphics_exposures: u32 = 16,
clip_x_origin: u32 = 17,
clip_y_origin: u32 = 18,
clip_mask: u32 = 19,
dash_offset: u32 = 20,
dashes: u32 = 21,
arc_mode: u32 = 22,
}
request CreateGC = 55 (
@pad 1,
cid: u32,
drawable: u32,
value_mask: u32 = bitmask(values),
values: bitmask(GC, field(value_mask)),
);
request FreeGC = 60 (
@pad 1,
gc: u32,
);
request PutImage = 72 (
format: u8,
drawable: u32,
gc: u32,
width: u16,
height: u16,
dst_x: i16,
dst_y: i16,
left_pad: u8,
depth: u8,
@pad 2,
data: list(u8),
);
request CreateCursor = 93 (
@pad 1,
cid: u32,
source: u32,
mask: u32,
fore_red: u16,
fore_green: u16,
fore_blue: u16,
back_red: u16,
back_green: u16,
back_blue: u16,
x: u16,
y: u16,
);
request ChangeProperty = 18 (
mode: u8,
window: u32,
property: u32,
ty: u32,
format: u8,
@pad 3,
data_len: u32 = div(mul(len(data), literal(8)), field(format)),
data: list(u8, mul(field(data_len), div(field(format), literal(8)))),
);