1
0
Fork 0
forked from wry/wry

autocommit 2022-01-06 19:08:32 CET

This commit is contained in:
Julian Orth 2022-01-06 19:08:32 +01:00
parent cbbc41a463
commit 4a939477a2
51 changed files with 3438 additions and 207 deletions

79
Cargo.lock generated
View file

@ -51,6 +51,23 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bstr"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
dependencies = [
"lazy_static",
"memchr",
"regex-automata",
]
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.72"
@ -204,17 +221,27 @@ dependencies = [
"ahash",
"anyhow",
"bitflags",
"bstr",
"env_logger",
"futures",
"isnt",
"libloading",
"log",
"num-derive",
"num-traits",
"repc",
"thiserror",
"uapi",
"waker-fn",
"xcb-dl",
"xcb-dl-util",
]
[[package]]
name = "isnt"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a7558cc96ddcaf0b4144d7149984ace2899bb29d4ee2999979d429efc305200"
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -319,18 +346,45 @@ dependencies = [
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "repc"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd5497e1d1e81bb330f7a48f4093b01b95da3b5b7ac07e7cd9a17d4f5cfe98e6"
dependencies = [
"repc-impl",
]
[[package]]
name = "repc-impl"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e110b7d5a1335c2e801176c42a626a905c23eecdee104d9bdfbd6ea5f0b8368"
[[package]]
name = "slab"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
[[package]]
name = "smallvec"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
[[package]]
name = "syn"
version = "1.0.84"
@ -409,12 +463,6 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "waker-fn"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
@ -461,3 +509,20 @@ dependencies = [
"libc",
"libloading",
]
[[package]]
name = "xcb-dl-util"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac09222229087f380311b876bf8651de4cfe78cf793ef8702932a81385c0f400"
dependencies = [
"bitflags",
"bstr",
"byteorder",
"isnt",
"libc",
"log",
"smallvec",
"thiserror",
"xcb-dl",
]

View file

@ -3,8 +3,6 @@ name = "i4"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[profile.release]
panic = "abort"
@ -19,8 +17,15 @@ ahash = "0.7.6"
log = "0.4.14"
env_logger = "0.9.0"
futures = "0.3.19"
waker-fn = "1.1.0"
num-traits = "0.2.14"
num-derive = "0.3.3"
bitflags = "1.3.2"
xcb-dl = "0.2.0"
xcb-dl-util = { version = "0.2.0", features = ["xcb_shm", "xcb_xinput", "xcb_xkb"]}
libloading = "0.7.2"
bstr = "0.2.17"
isnt = "0.1.0"
[build-dependencies]
repc = "0.1.1"
anyhow = "1.0.52"

82
build.rs Normal file
View file

@ -0,0 +1,82 @@
use repc::layout::{Type, TypeVariant};
use std::fs::{File, OpenOptions};
use std::io::BufWriter;
use std::io::Write;
use std::path::PathBuf;
use std::{env, io};
#[allow(unused_macros)]
#[macro_use]
#[path = "src/macros.rs"]
mod macros;
#[path = "src/pixman/consts.rs"]
mod pixman;
#[path = "src/xkbcommon/consts.rs"]
mod xkbcommon;
fn open(s: &str) -> io::Result<BufWriter<File>> {
let mut path = PathBuf::from(env::var("OUT_DIR").unwrap());
path.push(s);
Ok(BufWriter::new(
OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(path)?,
))
}
fn get_target() -> repc::Target {
let rustc_target = env::var("TARGET").unwrap();
repc::TARGET_MAP
.iter()
.cloned()
.find(|t| t.0 == &rustc_target)
.unwrap()
.1
}
fn get_enum_ty(variants: Vec<i128>) -> anyhow::Result<u64> {
let target = get_target();
let ty = Type {
layout: (),
annotations: vec![],
variant: TypeVariant::Enum(variants),
};
let ty = repc::compute_layout(target, &ty)?;
assert!(ty.layout.pointer_alignment_bits <= ty.layout.size_bits);
Ok(ty.layout.size_bits)
}
fn write_ty<W: Write>(f: &mut W, vals: &[u32], ty: &str) -> anyhow::Result<()> {
let variants: Vec<_> = vals.iter().cloned().map(|v| v as i128).collect();
let size = get_enum_ty(variants)?;
writeln!(f, "pub type {} = u{};", ty, size)?;
Ok(())
}
fn main() -> anyhow::Result<()> {
let mut f = open("pixman_tys.rs")?;
write_ty(&mut f, pixman::FORMATS, "PixmanFormat")?;
write_ty(&mut f, pixman::OPS, "PixmanOp")?;
let mut f = open("xkbcommon_tys.rs")?;
write_ty(
&mut f,
xkbcommon::XKB_X11_SETUP_XKB_EXTENSION_FLAGS,
"xkb_x11_setup_xkb_extension_flags",
)?;
write_ty(&mut f, xkbcommon::XKB_LOG_LEVEL, "xkb_log_level")?;
write_ty(&mut f, xkbcommon::XKB_CONTEXT_FLAGS, "xkb_context_flags")?;
write_ty(
&mut f,
xkbcommon::XKB_KEYMAP_COMPILE_FLAGS,
"xkb_keymap_compile_flags",
)?;
write_ty(&mut f, xkbcommon::XKB_KEYMAP_FORMAT, "xkb_keymap_format")?;
println!("cargo:rerun-if-changed=build.rs");
Ok(())
}

19
c/bridge.c Normal file
View file

@ -0,0 +1,19 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <xkbcommon/xkbcommon.h>
extern void i4_xkbcommon_log_fn(enum xkb_log_level level, unsigned char *bytes, size_t len);
void i4_xkbcommon_log_fn_bridge(
struct xkb_context *context,
enum xkb_log_level level,
const char *format, va_list args)
{
char *buf;
int len = vasprintf(&buf, format, args);
if (len < 0) {
abort();
}
i4_xkbcommon_log_fn(level, (unsigned char *)buf, len);
}

View file

@ -104,7 +104,10 @@ impl Acceptor {
}
impl EventLoopDispatcher for Acceptor {
fn dispatch(&self, events: i32) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
fn dispatch(
self: Rc<Self>,
events: i32,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
if events & (c::EPOLLERR | c::EPOLLHUP) != 0 {
return Err(Box::new(AcceptorError::ErrorEvent));
}

View file

@ -435,7 +435,7 @@ mod queue {
}
impl EventLoopDispatcher for Dispatcher {
fn dispatch(&self, _events: i32) -> Result<(), Box<dyn Error + Send + Sync>> {
fn dispatch(self: Rc<Self>, _events: i32) -> Result<(), Box<dyn Error + Send + Sync>> {
loop {
self.queue.iteration.fetch_add(1);
let mut stash = self.stash.borrow_mut();
@ -549,7 +549,7 @@ mod fd {
}
impl EventLoopDispatcher for AsyncFdData {
fn dispatch(&self, events: i32) -> Result<(), Box<dyn Error + Send + Sync>> {
fn dispatch(self: Rc<Self>, events: i32) -> Result<(), Box<dyn Error + Send + Sync>> {
if events & (c::EPOLLERR | c::EPOLLHUP) != 0 {
self.erroneous.set(true);
if let Err(e) = self.el.remove(self.id) {

30
src/backend.rs Normal file
View file

@ -0,0 +1,30 @@
use std::rc::Rc;
use crate::fixed::Fixed;
linear_ids!(OutputIds, OutputId);
linear_ids!(SeatIds, SeatId);
pub trait Output {
fn id(&self) -> OutputId;
fn removed(&self) -> bool;
fn width(&self) -> u32;
fn height(&self) -> u32;
fn on_change(&self, cb: Rc<dyn Fn()>);
}
pub trait Seat {
fn id(&self) -> SeatId;
fn removed(&self) -> bool;
fn event(&self) -> Option<SeatEvent>;
fn on_change(&self, cb: Rc<dyn Fn()>);
}
pub enum BackendEvent {
NewOutput(Rc<dyn Output>),
NewSeat(Rc<dyn Seat>),
}
#[derive(Debug)]
pub enum SeatEvent {
Motion(OutputId, Fixed, Fixed),
}

1
src/backends/mod.rs Normal file
View file

@ -0,0 +1 @@
pub mod xorg;

787
src/backends/xorg/mod.rs Normal file
View file

@ -0,0 +1,787 @@
use crate::backend::{BackendEvent, Output, OutputId, Seat, SeatEvent, SeatId};
use crate::event_loop::{EventLoopDispatcher, EventLoopId};
use crate::ifs::wl_buffer::WlBuffer;
use crate::ifs::wl_surface::WlSurface;
use crate::pixman::{Image, PixmanError};
use crate::servermem::{ServerMem, ServerMemError};
use crate::tree::{Node, NodeKind, ToplevelNode};
use crate::utils::copyhashmap::CopyHashMap;
use crate::utils::ptr_ext::PtrExt;
use crate::wheel::{WheelDispatcher, WheelId};
use crate::xkbcommon::{
XkbCommonError, XkbCommonX11, XkbContext, XkbState, XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS,
};
use crate::{pixman, EventLoopError, State, WheelError};
use isnt::std_1::primitive::IsntConstPtrExt;
use std::cell::{Cell, RefCell};
use std::collections::VecDeque;
use std::error::Error;
use std::ops::Deref;
use std::ptr;
use std::rc::Rc;
use thiserror::Error;
use uapi::c;
use xcb_dl::{ffi, Xcb, XcbShm, XcbXinput, XcbXkb};
use xcb_dl_util::error::{XcbError, XcbErrorParser};
use xcb_dl_util::xcb_box::XcbBox;
use crate::fixed::Fixed;
#[derive(Debug, Error)]
pub enum XorgBackendError {
#[error("The xcb connection is in an error state")]
ErrorEvent,
#[error("Could not select input events")]
CannotSelectInputEvents(#[source] XcbError),
#[error("libloading returned an error")]
Libloading(#[from] libloading::Error),
#[error("xcb returned an error")]
XcbError(#[from] XcbError),
#[error("The event loop caused an error")]
EventLoopError(#[source] Box<EventLoopError>),
#[error("The timer wheel caused an error")]
WheelError(#[source] Box<WheelError>),
#[error("Could not allocate and map image memory")]
ServerMemError(#[source] Box<ServerMemError>),
#[error("Pixman returned an error")]
PixmanError(#[source] Box<PixmanError>),
#[error("dupfd failed")]
DupfdFailed(#[source] std::io::Error),
#[error("Could not create a window")]
CreateWindow(#[source] XcbError),
#[error("Could not set WM_CLASS")]
WmClass(#[source] XcbError),
#[error("Could not select window events")]
WindowEvents(#[source] XcbError),
#[error("Could not map a window")]
MapWindow(#[source] XcbError),
#[error("Could not query device")]
QueryDevice(#[source] XcbError),
#[error("xkbcommon error")]
XkbCommon(#[from] Box<XkbCommonError>),
}
efrom!(XorgBackendError, EventLoopError, EventLoopError);
efrom!(XorgBackendError, ServerMemError, ServerMemError);
efrom!(XorgBackendError, PixmanError, PixmanError);
efrom!(XorgBackendError, WheelError, WheelError);
efrom!(XorgBackendError, XkbCommon, XkbCommonError);
struct XcbCon {
xcb: Box<Xcb>,
shm: Box<XcbShm>,
input: Box<XcbXinput>,
input_opcode: u8,
xkb: Box<XcbXkb>,
c: *mut ffi::xcb_connection_t,
errors: XcbErrorParser,
}
impl XcbCon {
fn new() -> Result<Self, XorgBackendError> {
unsafe {
let xcb = Box::new(Xcb::load_loose()?);
let shm = Box::new(XcbShm::load_loose()?);
let input = Box::new(XcbXinput::load_loose()?);
let xkb = Box::new(XcbXkb::load_loose()?);
let c = xcb.xcb_connect(ptr::null(), ptr::null_mut());
let errors = XcbErrorParser::new(&xcb, c);
let mut con = Self {
xcb,
shm,
input,
input_opcode: 0,
xkb,
c,
errors,
};
con.errors.check_connection(&con.xcb)?;
let mut err = ptr::null_mut();
let res =
con.shm
.xcb_shm_query_version_reply(c, con.shm.xcb_shm_query_version(c), &mut err);
con.errors.check(&con.xcb, res, err)?;
let res = con.input.xcb_input_xi_query_version_reply(
c,
con.input.xcb_input_xi_query_version(c, 2, 2),
&mut err,
);
con.errors.check(&con.xcb, res, err)?;
let input_ex = con
.xcb
.xcb_get_extension_data(con.c, con.input.xcb_input_id());
assert!(input_ex.is_not_null());
con.input_opcode = input_ex.deref().major_opcode;
let res = con.xkb.xcb_xkb_use_extension_reply(
c,
con.xkb.xcb_xkb_use_extension(c, 1, 0),
&mut err,
);
con.errors.check(&con.xcb, res, err)?;
Ok(con)
}
}
fn check_cookie(&self, cookie: ffi::xcb_void_cookie_t) -> Result<(), XcbError> {
unsafe { self.errors.check_cookie(&self.xcb, cookie) }
}
fn check<T>(
&self,
reply: *mut T,
err: *mut ffi::xcb_generic_error_t,
) -> Result<XcbBox<T>, XcbError> {
unsafe { self.errors.check(&self.xcb, reply, err) }
}
fn screen(&self) -> &ffi::xcb_screen_t {
unsafe {
self.xcb
.xcb_setup_roots_iterator(self.xcb.xcb_get_setup(self.c))
.data
.deref()
}
}
}
impl Drop for XcbCon {
fn drop(&mut self) {
unsafe {
self.xcb.xcb_disconnect(self.c);
}
}
}
pub struct XorgBackend {
id: EventLoopId,
wheel_id: WheelId,
state: Rc<State>,
con: XcbCon,
xkbcommon: XkbContext,
xkbcommonx11: XkbCommonX11,
outputs: CopyHashMap<ffi::xcb_window_t, Rc<XorgOutput>>,
seats: CopyHashMap<ffi::xcb_input_device_id_t, Rc<XorgSeat>>,
mouse_seats: CopyHashMap<ffi::xcb_input_device_id_t, Rc<XorgSeat>>,
}
impl XorgBackend {
pub fn new(state: &Rc<State>) -> Result<Rc<Self>, XorgBackendError> {
unsafe {
let con = XcbCon::new()?;
let fd = con.xcb.xcb_get_file_descriptor(con.c);
let wheel_id = state.wheel.id();
let slf = Rc::new(Self {
id: state.el.id(),
wheel_id,
state: state.clone(),
con,
xkbcommon: XkbContext::new()?,
xkbcommonx11: XkbCommonX11::load()?,
outputs: Default::default(),
seats: Default::default(),
mouse_seats: Default::default(),
});
{
let cookie = xcb_dl_util::input::select_events_checked(
&slf.con.input,
slf.con.c,
slf.con.screen().root,
ffi::XCB_INPUT_DEVICE_ALL as _,
[ffi::XCB_INPUT_XI_EVENT_MASK_HIERARCHY],
);
if let Err(e) = slf.con.check_cookie(cookie) {
return Err(XorgBackendError::CannotSelectInputEvents(e));
}
}
state.wheel.periodic(wheel_id, 16_667, slf.clone())?;
state.el.insert(slf.id, Some(fd), c::EPOLLIN, slf.clone())?;
slf.add_output()?;
slf.query_devices(ffi::XCB_INPUT_DEVICE_ALL_MASTER as _)?;
slf.handle_events()?;
Ok(slf)
}
}
fn add_output(self: &Rc<Self>) -> Result<(), XorgBackendError> {
unsafe {
let con = &self.con;
let screen = con
.xcb
.xcb_setup_roots_iterator(con.xcb.xcb_get_setup(con.c))
.data
.deref();
let window_id = con.xcb.xcb_generate_id(con.c);
{
let cookie = con.xcb.xcb_create_window_checked(
con.c,
0,
window_id,
screen.root,
0,
0,
800,
600,
0,
ffi::XCB_WINDOW_CLASS_INPUT_OUTPUT as _,
0,
0,
ptr::null(),
);
if let Err(e) = con.check_cookie(cookie) {
return Err(XorgBackendError::CreateWindow(e));
}
}
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),
image: RefCell::new(None),
cb: RefCell::new(None),
});
{
let class = "i4\0i4\0";
let cookie = con.xcb.xcb_change_property_checked(
con.c,
ffi::XCB_PROP_MODE_REPLACE as _,
window_id,
ffi::XCB_ATOM_WM_CLASS,
ffi::XCB_ATOM_STRING,
8,
class.len() as _,
class.as_ptr() as _,
);
if let Err(e) = con.check_cookie(cookie) {
return Err(XorgBackendError::WmClass(e));
}
}
{
let event_mask = ffi::XCB_EVENT_MASK_EXPOSURE
| ffi::XCB_EVENT_MASK_STRUCTURE_NOTIFY
| ffi::XCB_EVENT_MASK_VISIBILITY_CHANGE;
let cookie = con.xcb.xcb_change_window_attributes_checked(
con.c,
window_id,
ffi::XCB_CW_EVENT_MASK,
&event_mask as *const _ as _,
);
if let Err(e) = con.check_cookie(cookie) {
return Err(XorgBackendError::WindowEvents(e));
}
}
{
let cookie = con.xcb.xcb_map_window_checked(con.c, window_id);
if let Err(e) = con.check_cookie(cookie) {
return Err(XorgBackendError::MapWindow(e));
}
}
{
let mask = ffi::XCB_INPUT_XI_EVENT_MASK_MOTION
| ffi::XCB_INPUT_XI_EVENT_MASK_BUTTON_PRESS
| ffi::XCB_INPUT_XI_EVENT_MASK_BUTTON_RELEASE
| ffi::XCB_INPUT_XI_EVENT_MASK_KEY_PRESS
| ffi::XCB_INPUT_XI_EVENT_MASK_KEY_RELEASE
| ffi::XCB_INPUT_XI_EVENT_MASK_ENTER
| ffi::XCB_INPUT_XI_EVENT_MASK_LEAVE
| ffi::XCB_INPUT_XI_EVENT_MASK_FOCUS_IN
| ffi::XCB_INPUT_XI_EVENT_MASK_FOCUS_OUT
| ffi::XCB_INPUT_XI_EVENT_MASK_TOUCH_BEGIN
| ffi::XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE
| ffi::XCB_INPUT_XI_EVENT_MASK_TOUCH_END;
let cookie = xcb_dl_util::input::select_events_checked(
&con.input,
con.c,
window_id,
ffi::XCB_INPUT_DEVICE_ALL_MASTER as _,
[mask],
);
if let Err(e) = con.check_cookie(cookie) {
return Err(XorgBackendError::CannotSelectInputEvents(e));
}
}
self.outputs.set(window_id, output.clone());
self.state
.backend_events
.push(BackendEvent::NewOutput(output.clone()));
}
Ok(())
}
fn query_devices(
self: &Rc<Self>,
device_id: ffi::xcb_input_device_id_t,
) -> Result<(), XorgBackendError> {
unsafe {
let con = &self.con;
let mut err = ptr::null_mut();
let reply = con.input.xcb_input_xi_query_device_reply(
con.c,
con.input.xcb_input_xi_query_device(con.c, device_id),
&mut err,
);
let reply = match con.check(reply, err) {
Ok(i) => i,
Err(e) => return Err(XorgBackendError::QueryDevice(e)),
};
let mut iter = con.input.xcb_input_xi_query_device_infos_iterator(&*reply);
while iter.rem > 0 {
self.handle_input_device(iter.data.deref());
con.input.xcb_input_xi_device_info_next(&mut iter);
}
}
Ok(())
}
fn handle_input_device(self: &Rc<Self>, info: &ffi::xcb_input_xi_device_info_t) {
if info.type_ != ffi::XCB_INPUT_DEVICE_TYPE_MASTER_KEYBOARD as _ {
return;
}
let con = &self.con;
self.mouse_seats.remove(&info.attachment);
if let Some(kb) = self.seats.remove(&info.deviceid) {
kb.removed.set(true);
kb.changed();
}
unsafe {
let mut err = ptr::null_mut();
let cookie = con.xkb.xcb_xkb_per_client_flags(
con.c,
info.deviceid,
ffi::XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
ffi::XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
0,
0,
0,
);
let reply = con
.xkb
.xcb_xkb_per_client_flags_reply(con.c, cookie, &mut err);
if let Err(e) = con.check(reply, err) {
log::warn!(
"Could not make auto repeat detectable for keyboard {}: {:#}",
info.deviceid,
e
);
}
let res: Result<_, XkbCommonError> = (|| {
let keymap = self.xkbcommonx11.keymap_from_device(
&self.xkbcommon,
con.c,
info.deviceid as _,
XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS,
)?;
let state =
self.xkbcommonx11
.state_from_device(&keymap, con.c, info.deviceid as _)?;
Ok(state)
})();
let state = match res {
Ok(c) => c,
Err(e) => {
log::error!(
"Could not create an xkb context for device {}: {:#}",
info.deviceid,
e
);
return;
}
};
let seat = Rc::new(XorgSeat {
id: self.state.seat_ids.next(),
backend: self.clone(),
kb: info.deviceid,
mouse: info.attachment,
removed: Cell::new(false),
cb: RefCell::new(None),
events: RefCell::new(Default::default()),
state,
});
self.seats.set(info.deviceid, seat.clone());
self.mouse_seats.set(info.attachment, seat.clone());
self.state
.backend_events
.push(BackendEvent::NewSeat(seat.clone()));
}
}
fn handle_events(self: &Rc<Self>) -> Result<(), XorgBackendError> {
unsafe {
loop {
let event = self.con.xcb.xcb_poll_for_event(self.con.c);
if event.is_null() {
self.con.errors.check_connection(&self.con.xcb)?;
return Ok(());
}
let event = XcbBox::new(event);
self.handle_event(&event)?;
}
}
}
fn handle_event(
self: &Rc<Self>,
event: &ffi::xcb_generic_event_t,
) -> Result<(), XorgBackendError> {
let event_type = event.response_type & 0x7f;
match event_type {
ffi::XCB_CONFIGURE_NOTIFY => self.handle_configure(event)?,
ffi::XCB_DESTROY_NOTIFY => self.handle_destroy(event)?,
ffi::XCB_GE_GENERIC => self.handle_generic(event)?,
_ => {}
}
Ok(())
}
fn handle_generic(
self: &Rc<Self>,
event: &ffi::xcb_generic_event_t,
) -> Result<(), XorgBackendError> {
let event = unsafe { (event as *const _ as *const ffi::xcb_ge_generic_event_t).deref() };
if event.extension == self.con.input_opcode {
self.handle_input_event(event)?;
}
Ok(())
}
fn handle_input_event(
self: &Rc<Self>,
event: &ffi::xcb_ge_generic_event_t,
) -> Result<(), XorgBackendError> {
match event.event_type {
ffi::XCB_INPUT_MOTION => self.handle_input_motion(event)?,
ffi::XCB_INPUT_HIERARCHY => self.handle_input_hierarchy(event)?,
_ => {}
}
Ok(())
}
fn handle_input_hierarchy(
self: &Rc<Self>,
event: &ffi::xcb_ge_generic_event_t,
) -> Result<(), XorgBackendError> {
let event =
unsafe { (event as *const _ as *const ffi::xcb_input_hierarchy_event_t).deref() };
let infos = unsafe {
std::slice::from_raw_parts(
self.con.input.xcb_input_hierarchy_infos(event),
event.num_infos as _,
)
};
for info in infos {
if info.flags & ffi::XCB_INPUT_HIERARCHY_MASK_MASTER_ADDED != 0 {
self.query_devices(info.deviceid);
} else if info.flags & ffi::XCB_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.changed();
}
}
}
Ok(())
}
fn handle_input_motion(
&self,
event: &ffi::xcb_ge_generic_event_t,
) -> Result<(), XorgBackendError> {
let event = unsafe { (event as *const _ as *const ffi::xcb_input_motion_event_t).deref() };
let win = match self.outputs.get(&event.event) {
Some(w) => w,
_ => return Ok(()),
};
let seat = match self.mouse_seats.get(&event.deviceid) {
Some(s) => s,
_ => return Ok(()),
};
seat.event(SeatEvent::Motion(
win.id,
Fixed::from_1616(event.event_x),
Fixed::from_1616(event.event_y),
));
Ok(())
}
fn handle_destroy(&self, event: &ffi::xcb_generic_event_t) -> Result<(), XorgBackendError> {
let event =
unsafe { (event as *const _ as *const ffi::xcb_destroy_notify_event_t).deref() };
let output = match self.outputs.remove(&event.event) {
Some(o) => o,
_ => return Ok(()),
};
output.removed.set(true);
*output.image.borrow_mut() = None;
output.changed();
Ok(())
}
fn handle_configure(&self, event: &ffi::xcb_generic_event_t) -> Result<(), XorgBackendError> {
let event =
unsafe { (event as *const _ as *const ffi::xcb_configure_notify_event_t).deref() };
let output = match self.outputs.get(&event.event) {
Some(o) => o,
_ => return Ok(()),
};
let width = event.width as u32;
let height = event.height as u32;
let mut changed = false;
changed |= output.width.replace(width) != width;
changed |= output.height.replace(height) != height;
if changed {
let shm = Rc::new(ServerMem::new((width * height * 4) as usize)?);
let fd = shm.fd();
let image = Image::new(shm, pixman::X8R8G8B8, width, height, width * 4)?;
*output.image.borrow_mut() = Some(image);
unsafe {
let fd = match uapi::fcntl_dupfd_cloexec(fd, 0) {
Ok(fd) => fd,
Err(e) => return Err(XorgBackendError::DupfdFailed(e.into())),
};
let shmseg = self.con.xcb.xcb_generate_id(self.con.c);
let cookie =
self.con
.shm
.xcb_shm_attach_fd_checked(self.con.c, shmseg, fd.unwrap(), 0);
self.con.check_cookie(cookie)?;
let pixmap = self.con.xcb.xcb_generate_id(self.con.c);
let cookie = self.con.shm.xcb_shm_create_pixmap(
self.con.c,
pixmap,
output.window,
width as _,
height as _,
24,
shmseg,
0,
);
self.con.check_cookie(cookie)?;
let cookie = self.con.xcb.xcb_change_window_attributes_checked(
self.con.c,
output.window,
ffi::XCB_CW_BACK_PIXMAP,
&pixmap as *const _ as _,
);
self.con.check_cookie(cookie)?;
self.con.xcb.xcb_free_pixmap(self.con.c, pixmap);
self.con.shm.xcb_shm_detach(self.con.c, shmseg);
}
output.changed();
self.render()?;
}
Ok(())
}
fn render_node(&self, image: &Image<Rc<ServerMem>>, node: Rc<dyn Node>) {
match node.into_kind() {
NodeKind::Display(_) => {}
NodeKind::Output(_) => {}
NodeKind::Toplevel(tl) => self.render_toplevel(image, &tl),
NodeKind::Container(_) => {}
}
}
fn render_toplevel(&self, image: &Image<Rc<ServerMem>>, tl: &Rc<ToplevelNode>) {
let surface = &tl.surface.surface.surface;
let extents = surface.extents.get();
self.render_surface(image, surface, -extents.x1, -extents.y1);
}
fn render_surface(
&self,
image: &Image<Rc<ServerMem>>,
surface: &Rc<WlSurface>,
x: i32,
y: i32,
) {
let children = surface.children.borrow();
if let Some(children) = &*children {
for child in children.below.iter() {
if let Some((sx, sy)) = child.surface.subsurface_position() {
self.render_surface(image, &child.surface, x + sx, y + sy);
}
}
}
let buffer = surface.buffer.borrow();
if let Some(buffer) = &*buffer {
self.render_buffer(image, buffer, x, y);
let mut fr = surface.frame_requests.borrow_mut();
for cb in fr.drain(..) {
surface.client.dispatch_frame_requests.push(cb);
}
}
if let Some(children) = &*children {
for child in children.above.iter() {
if let Some((sx, sy)) = child.surface.subsurface_position() {
self.render_surface(image, &child.surface, x + sx, y + sy);
}
}
}
}
fn render_buffer(&self, image: &Image<Rc<ServerMem>>, buffer: &Rc<WlBuffer>, x: i32, y: i32) {
image.add_image(&buffer.image, x, y);
}
fn render(&self) -> Result<(), XorgBackendError> {
let outputs = self.outputs.lock();
for output in outputs.values() {
let image = output.image.borrow();
let image = match image.deref() {
Some(i) => i,
None => continue,
};
image.fill(0, 0, 0, 255);
let node = match self.state.root.outputs.get(&output.id) {
Some(n) => n,
_ => continue,
};
for floating in node.floating.iter() {
self.render_node(image, floating.clone());
}
unsafe {
let cookie =
self.con
.xcb
.xcb_clear_area_checked(self.con.c, 0, output.window, 0, 0, 0, 0);
self.con.check_cookie(cookie)?;
}
}
Ok(())
}
}
impl EventLoopDispatcher for XorgBackend {
fn dispatch(self: Rc<Self>, events: i32) -> Result<(), Box<dyn Error + Send + Sync>> {
if events & (c::EPOLLERR | c::EPOLLHUP) != 0 {
return Err(Box::new(XorgBackendError::ErrorEvent));
}
self.handle_events()?;
Ok(())
}
}
impl WheelDispatcher for XorgBackend {
fn dispatch(self: Rc<Self>) -> Result<(), Box<dyn Error + Send + Sync>> {
self.render()?;
Ok(())
}
}
impl Drop for XorgBackend {
fn drop(&mut self) {
let _ = self.state.el.remove(self.id);
let _ = self.state.wheel.remove(self.wheel_id);
}
}
struct XorgOutput {
id: OutputId,
backend: Rc<XorgBackend>,
window: ffi::xcb_window_t,
removed: Cell<bool>,
width: Cell<u32>,
height: Cell<u32>,
image: RefCell<Option<Image<Rc<ServerMem>>>>,
cb: RefCell<Option<Rc<dyn Fn()>>>,
}
impl Drop for XorgOutput {
fn drop(&mut self) {
unsafe {
let con = &self.backend.con;
con.xcb.xcb_destroy_window(con.c, self.window);
}
}
}
impl XorgOutput {
fn changed(&self) {
if let Some(cb) = self.cb.borrow().clone() {
cb();
}
}
}
impl Output for XorgOutput {
fn id(&self) -> OutputId {
self.id
}
fn removed(&self) -> bool {
self.removed.get()
}
fn width(&self) -> u32 {
self.width.get()
}
fn height(&self) -> u32 {
self.height.get()
}
fn on_change(&self, cb: Rc<dyn Fn()>) {
*self.cb.borrow_mut() = Some(cb);
}
}
struct XorgSeat {
id: SeatId,
backend: Rc<XorgBackend>,
kb: ffi::xcb_input_device_id_t,
mouse: ffi::xcb_input_device_id_t,
removed: Cell<bool>,
cb: RefCell<Option<Rc<dyn Fn()>>>,
events: RefCell<VecDeque<SeatEvent>>,
state: XkbState,
}
impl XorgSeat {
fn changed(&self) {
if let Some(cb) = self.cb.borrow().clone() {
cb();
}
}
fn event(&self, event: SeatEvent) {
self.events.borrow_mut().push_back(event);
self.changed();
}
}
impl Seat for XorgSeat {
fn id(&self) -> SeatId {
self.id
}
fn removed(&self) -> bool {
self.removed.get()
}
fn event(&self) -> Option<SeatEvent> {
self.events.borrow_mut().pop_front()
}
fn on_change(&self, cb: Rc<dyn Fn()>) {
*self.cb.borrow_mut() = Some(cb);
}
}
fn fp1616_to_f64(i: ffi::xcb_input_fp1616_t) -> f64 {
i as f64 / (1 << 16) as f64
}

View file

@ -1,10 +1,13 @@
use crate::async_engine::{AsyncError, AsyncFd, SpawnedFuture};
use crate::client::objects::Objects;
use crate::ifs::wl_buffer::{WlBuffer, WlBufferError, WlBufferId};
use crate::ifs::wl_callback::WlCallback;
use crate::ifs::wl_compositor::{WlCompositorError, WlCompositorObj};
use crate::ifs::wl_display::{WlDisplay, WlDisplayError};
use crate::ifs::wl_output::{WlOutputError, WlOutputObj};
use crate::ifs::wl_region::{WlRegion, WlRegionError, WlRegionId};
use crate::ifs::wl_registry::{WlRegistry, WlRegistryError, WlRegistryId};
use crate::ifs::wl_seat::{WlSeatError, WlSeatObj};
use crate::ifs::wl_shm::{WlShmError, WlShmObj};
use crate::ifs::wl_shm_pool::{WlShmPool, WlShmPoolError};
use crate::ifs::wl_subcompositor::{WlSubcompositorError, WlSubcompositorObj};
@ -30,7 +33,6 @@ use std::mem;
use std::rc::Rc;
use thiserror::Error;
use uapi::OwnedFd;
use crate::ifs::wl_buffer::{WlBuffer, WlBufferError};
mod objects;
mod tasks;
@ -57,6 +59,8 @@ pub enum ClientError {
ClientDoesNotExist(ClientId),
#[error("There is no wl_region with id {0}")]
RegionDoesNotExist(WlRegionId),
#[error("There is no wl_buffer with id {0}")]
BufferDoesNotExist(WlBufferId),
#[error("There is no wl_surface with id {0}")]
SurfaceDoesNotExist(WlSurfaceId),
#[error("There is no xdg_surface with id {0}")]
@ -105,6 +109,10 @@ pub enum ClientError {
XdgWmBaseError(#[source] Box<XdgWmBaseError>),
#[error("An error occurred in a `wl_buffer`")]
WlBufferError(#[source] Box<WlBufferError>),
#[error("An error occurred in a `wl_output`")]
WlOutputError(#[source] Box<WlOutputError>),
#[error("An error occurred in a `wl_seat`")]
WlSeatError(#[source] Box<WlSeatError>),
#[error("Object {0} is not a display")]
NotADisplay(ObjectId),
}
@ -125,6 +133,8 @@ efrom!(ClientError, XdgWmBaseError, XdgWmBaseError);
efrom!(ClientError, XdgToplevelError, XdgToplevelError);
efrom!(ClientError, XdgPopupError, XdgPopupError);
efrom!(ClientError, WlBufferError, WlBufferError);
efrom!(ClientError, WlOutputError, WlOutputError);
efrom!(ClientError, WlSeatError, WlSeatError);
impl ClientError {
fn peer_closed(&self) -> bool {
@ -146,7 +156,7 @@ impl Display for ClientId {
pub struct Clients {
next_client_id: NumCell<u64>,
clients: RefCell<AHashMap<ClientId, ClientHolder>>,
pub clients: RefCell<AHashMap<ClientId, ClientHolder>>,
shutdown_clients: RefCell<AHashMap<ClientId, ClientHolder>>,
}
@ -186,6 +196,7 @@ impl Clients {
events: AsyncQueue::new(),
shutdown: Cell::new(Some(send)),
shutdown_sent: Cell::new(false),
dispatch_frame_requests: AsyncQueue::new(),
});
let display = Rc::new(WlDisplay::new(&data));
*data.objects.display.borrow_mut() = Some(display.clone());
@ -234,14 +245,16 @@ impl Drop for Clients {
}
}
struct ClientHolder {
data: Rc<Client>,
pub struct ClientHolder {
pub data: Rc<Client>,
_handler: SpawnedFuture<()>,
}
impl Drop for ClientHolder {
fn drop(&mut self) {
self.data.objects.destroy();
self.data.events.clear();
self.data.dispatch_frame_requests.clear();
}
}
@ -256,7 +269,7 @@ pub trait RequestParser<'a>: Debug + Sized {
fn parse(parser: &mut MsgParser<'_, 'a>) -> Result<Self, MsgParserError>;
}
enum WlEvent {
pub enum WlEvent {
Flush,
Shutdown,
Event(Box<dyn EventFormatter>),
@ -266,10 +279,11 @@ pub struct Client {
pub id: ClientId,
pub state: Rc<State>,
socket: AsyncFd,
objects: Objects,
pub objects: Objects,
events: AsyncQueue<WlEvent>,
shutdown: Cell<Option<OneshotTx<()>>>,
shutdown_sent: Cell<bool>,
pub dispatch_frame_requests: AsyncQueue<Rc<WlCallback>>,
}
const MAX_PENDING_EVENTS: usize = 100;
@ -342,11 +356,20 @@ impl Client {
self.event2(WlEvent::Event(event)).await
}
pub async fn flush(&self) -> Result<(), ClientError> {
self.event2(WlEvent::Flush).await
}
async fn event2(&self, event: WlEvent) -> Result<(), ClientError> {
self.events.push(event);
self.check_queue_size().await
}
pub fn event2_locked(&self, event: WlEvent) -> bool {
self.events.push(event);
self.events.size() > MAX_PENDING_EVENTS
}
pub async fn check_queue_size(&self) -> Result<(), ClientError> {
if self.events.size() > MAX_PENDING_EVENTS {
self.state.eng.yield_now().await;
@ -359,6 +382,13 @@ impl Client {
Ok(())
}
pub fn get_buffer(&self, id: WlBufferId) -> Result<Rc<WlBuffer>, ClientError> {
match self.objects.buffers.get(&id) {
Some(r) => Ok(r),
_ => Err(ClientError::BufferDoesNotExist(id)),
}
}
pub fn get_region(&self, id: WlRegionId) -> Result<Rc<WlRegion>, ClientError> {
match self.objects.regions.get(&id) {
Some(r) => Ok(r),
@ -453,7 +483,8 @@ simple_add_obj!(WlSubsurface);
simple_add_obj!(XdgPositioner);
simple_add_obj!(XdgToplevel);
simple_add_obj!(XdgPopup);
simple_add_obj!(WlBuffer);
simple_add_obj!(WlOutputObj);
simple_add_obj!(WlSeatObj);
macro_rules! dedicated_add_obj {
($ty:ty, $field:ident) => {
@ -477,3 +508,4 @@ dedicated_add_obj!(WlRegion, regions);
dedicated_add_obj!(WlSurface, surfaces);
dedicated_add_obj!(XdgWmBaseObj, xdg_wm_bases);
dedicated_add_obj!(XdgSurface, xdg_surfaces);
dedicated_add_obj!(WlBuffer, buffers);

View file

@ -1,4 +1,5 @@
use crate::client::{Client, ClientError};
use crate::ifs::wl_buffer::{WlBuffer, WlBufferId};
use crate::ifs::wl_display::WlDisplay;
use crate::ifs::wl_region::{WlRegion, WlRegionId};
use crate::ifs::wl_registry::{WlRegistry, WlRegistryId};
@ -19,6 +20,7 @@ pub struct Objects {
pub surfaces: CopyHashMap<WlSurfaceId, Rc<WlSurface>>,
pub xdg_surfaces: CopyHashMap<XdgSurfaceId, Rc<XdgSurface>>,
pub regions: CopyHashMap<WlRegionId, Rc<WlRegion>>,
pub buffers: CopyHashMap<WlBufferId, Rc<WlBuffer>>,
pub xdg_wm_bases: CopyHashMap<XdgWmBaseId, Rc<XdgWmBaseObj>>,
ids: RefCell<Vec<usize>>,
}
@ -35,6 +37,7 @@ impl Objects {
surfaces: Default::default(),
xdg_surfaces: Default::default(),
regions: Default::default(),
buffers: Default::default(),
xdg_wm_bases: Default::default(),
ids: RefCell::new(vec![]),
}
@ -54,6 +57,7 @@ impl Objects {
self.surfaces.clear();
self.xdg_wm_bases.clear();
self.xdg_surfaces.clear();
self.buffers.clear();
}
fn id<T>(&self, client_data: &Client) -> Result<T, ClientError>
@ -106,9 +110,10 @@ impl Objects {
}
pub async fn remove_obj(&self, client_data: &Client, id: ObjectId) -> Result<(), ClientError> {
if self.registry.remove(&id).is_none() {
return Err(ClientError::UnknownId);
}
let _obj = match self.registry.remove(&id) {
Some(o) => o,
_ => return Err(ClientError::UnknownId),
};
if id.raw() >= MIN_SERVER_ID {
let offset = (id.raw() - MIN_SERVER_ID) as usize;
let pos = offset / SEG_SIZE;

View file

@ -1,4 +1,4 @@
use crate::client::{Client, ClientError, WlEvent};
use crate::client::{AddObj, Client, ClientError, WlEvent};
use crate::object::ObjectId;
use crate::utils::buffd::{BufFdIn, BufFdOut, MsgFormatter, MsgParser};
use crate::utils::oneshot::OneshotRx;
@ -10,12 +10,15 @@ use std::rc::Rc;
pub async fn client(data: Rc<Client>, shutdown: OneshotRx<()>) {
let mut recv = data.state.eng.spawn(receive(data.clone())).fuse();
let mut dispatch_fr = data.state.eng.spawn(dispatch_fr(data.clone())).fuse();
let _send = data.state.eng.spawn(send(data.clone()));
select! {
_ = recv => { },
_ = dispatch_fr => { },
_ = shutdown.fuse() => { },
}
drop(recv);
drop(dispatch_fr);
if !data.shutdown_sent.get() {
data.events.push(WlEvent::Shutdown);
}
@ -25,12 +28,36 @@ pub async fn client(data: Rc<Client>, shutdown: OneshotRx<()>) {
log::error!("Could not shut down client {} within 5 seconds", data.id.0);
}
Err(e) => {
log::error!("Could not create a timeout: {:#}", e);
log::error!("Could not create a timeout: {:#}", anyhow!(e));
}
}
data.state.clients.kill(data.id);
}
async fn dispatch_fr(data: Rc<Client>) {
loop {
let mut fr = data.dispatch_frame_requests.pop().await;
loop {
if let Err(e) = data.event(fr.done()).await {
log::error!("Could not dispatch frame event: {:#}", anyhow!(e));
return;
}
if let Err(e) = data.remove_obj(&*fr).await {
log::error!("Could not remove frame object: {:#}", anyhow!(e));
return;
}
fr = match data.dispatch_frame_requests.try_pop() {
Some(f) => f,
_ => break,
};
}
if let Err(e) = data.event2(WlEvent::Flush).await {
log::error!("Could not dispatch frame event: {:#}", anyhow!(e));
return;
}
}
}
async fn receive(data: Rc<Client>) {
let display = data.display().unwrap();
let recv = async {

View file

@ -1,5 +1,7 @@
use crate::pixman::PixmanMemory;
use std::cell::{Cell, UnsafeCell};
use std::mem::MaybeUninit;
use std::rc::Rc;
use std::sync::atomic::{compiler_fence, Ordering};
use std::{mem, ptr};
use thiserror::Error;
@ -19,7 +21,13 @@ pub enum ClientMemError {
pub struct ClientMem {
failed: Cell<bool>,
sigbus_impossible: bool,
data: *mut [Cell<u8>],
data: *const [Cell<u8>],
}
#[derive(Clone)]
pub struct ClientMemOffset {
mem: Rc<ClientMem>,
data: *const [Cell<u8>],
}
impl ClientMem {
@ -53,32 +61,42 @@ impl ClientMem {
})
}
pub fn len(&self) -> usize {
unsafe { (*self.data).len() }
}
pub fn offset(self: &Rc<Self>, offset: usize) -> ClientMemOffset {
let mem = unsafe { &*self.data };
ClientMemOffset {
mem: self.clone(),
data: &mem[offset..],
}
}
}
impl ClientMemOffset {
pub fn access<T, F: FnOnce(&[Cell<u8>]) -> T>(&self, f: F) -> Result<T, ClientMemError> {
unsafe {
if self.sigbus_impossible {
return Ok(f(&mut *self.data));
if self.mem.sigbus_impossible {
return Ok(f(&*self.data));
}
MEM.with(|m| {
let mref = MemRef {
mem: self,
mem: &*self.mem,
outer: *m.get(),
};
*m.get() = &mref;
compiler_fence(Ordering::SeqCst);
let res = f(&mut *self.data);
let res = f(&*self.data);
*m.get() = mref.outer;
compiler_fence(Ordering::SeqCst);
match self.failed.get() {
match self.mem.failed.get() {
true => Err(ClientMemError::Sigbus),
_ => Ok(res),
}
})
}
}
pub fn len(&self) -> usize {
unsafe { (*self.data).len() }
}
}
impl Drop for ClientMem {
@ -147,3 +165,14 @@ pub fn init() -> Result<(), ClientMemError> {
}
}
}
unsafe impl PixmanMemory for ClientMemOffset {
type E = ClientMemError;
fn access<T, F>(&self, f: F) -> Result<T, Self::E>
where
F: FnOnce(&[Cell<u8>]) -> T,
{
ClientMemOffset::access(self, f)
}
}

View file

@ -30,7 +30,10 @@ pub enum EventLoopError {
pub struct EventLoopId(u64);
pub trait EventLoopDispatcher {
fn dispatch(&self, events: i32) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
fn dispatch(
self: Rc<Self>,
events: i32,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
}
#[derive(Clone)]
@ -155,7 +158,7 @@ impl EventLoop {
break;
}
if let Some(entry) = self.entries.get(&id) {
if let Err(e) = entry.dispatcher.dispatch(0) {
if let Err(e) = entry.dispatcher.clone().dispatch(0) {
return Err(EventLoopError::DispatcherError(e));
}
}
@ -180,7 +183,7 @@ impl EventLoop {
continue;
}
};
if let Err(e) = entry.dispatcher.dispatch(event.events as i32) {
if let Err(e) = entry.dispatcher.clone().dispatch(event.events as i32) {
return Err(EventLoopError::DispatcherError(e));
}
}

35
src/fixed.rs Normal file
View file

@ -0,0 +1,35 @@
use std::fmt::{Debug, Formatter};
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[repr(transparent)]
pub struct Fixed(pub i32);
impl Fixed {
pub fn from_1616(i: i32) -> Self {
Self(i >> 8)
}
}
impl From<f64> for Fixed {
fn from(v: f64) -> Self {
Self((v * 256.0) as i32)
}
}
impl From<Fixed> for f64 {
fn from(v: Fixed) -> Self {
v.0 as f64 / 256.0
}
}
impl From<Fixed> for i32 {
fn from(f: Fixed) -> Self {
f.0 >> 8
}
}
impl Debug for Fixed {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&f64::from(*self), f)
}
}

View file

@ -1,3 +1,4 @@
use crate::pixman;
use ahash::AHashMap;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
@ -5,6 +6,7 @@ pub struct Format {
pub id: u32,
pub name: &'static str,
pub bpp: u32,
pub pixman: pixman::Format,
}
pub fn formats() -> AHashMap<u32, &'static Format> {
@ -24,11 +26,13 @@ static FORMATS: &[Format] = &[
id: 0,
name: "argb8888",
bpp: 4,
pixman: pixman::A8R8G8B8,
},
Format {
id: 1,
name: "xrgb8888",
bpp: 4,
pixman: pixman::X8R8G8B8,
},
// Format {
// id: fourcc_code('C', '8', ' ', ' '),

View file

@ -1,6 +1,8 @@
use crate::client::{Client, ClientError, DynEventFormatter};
use crate::client::{Client, ClientError, DynEventFormatter, WlEvent};
use crate::ifs::wl_compositor::WlCompositorError;
use crate::ifs::wl_output::WlOutputError;
use crate::ifs::wl_registry::WlRegistry;
use crate::ifs::wl_seat::WlSeatError;
use crate::ifs::wl_shm::WlShmError;
use crate::ifs::wl_subcompositor::WlSubcompositorError;
use crate::ifs::xdg_wm_base::XdgWmBaseError;
@ -28,12 +30,18 @@ pub enum GlobalError {
WlSubcompositorError(#[source] Box<WlSubcompositorError>),
#[error("An error occurred in a xdg_wm_base")]
XdgWmBaseError(#[source] Box<XdgWmBaseError>),
#[error("An error occurred in a wl_output")]
WlOutputError(#[source] Box<WlOutputError>),
#[error("An error occurred in a wl_seat")]
WlSeatError(#[source] Box<WlSeatError>),
}
efrom!(GlobalError, WlCompositorError, WlCompositorError);
efrom!(GlobalError, WlShmError, WlShmError);
efrom!(GlobalError, WlSubcompositorError, WlSubcompositorError);
efrom!(GlobalError, XdgWmBaseError, XdgWmBaseError);
efrom!(GlobalError, WlOutputError, WlOutputError);
efrom!(GlobalError, WlSeatError, WlSeatError);
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct GlobalName(u32);
@ -68,6 +76,7 @@ pub trait Global: GlobalBind {
fn interface(&self) -> Interface;
fn version(&self) -> u32;
fn pre_remove(&self);
fn break_loops(&self) {}
}
pub struct Globals {
@ -142,6 +151,9 @@ impl Globals {
clients_to_check.insert(c.id);
}
}
if c.event2_locked(WlEvent::Flush) {
clients_to_check.insert(c.id);
}
});
for client in clients_to_check.drain() {
if let Ok(c) = state.clients.get(client) {

View file

@ -1,13 +1,15 @@
mod types;
use std::cell::RefCell;
use crate::client::{AddObj, Client};
use crate::clientmem::ClientMem;
use crate::client::{AddObj, Client, DynEventFormatter};
use crate::clientmem::{ClientMem, ClientMemOffset};
use crate::format::Format;
use crate::ifs::wl_surface::{WlSurface, WlSurfaceId};
use crate::object::{Interface, Object, ObjectId};
use crate::pixman;
use crate::utils::buffd::MsgParser;
use crate::utils::copyhashmap::CopyHashMap;
use std::rc::Rc;
pub use types::*;
use crate::utils::buffd::MsgParser;
const DESTROY: u32 = 0;
@ -19,11 +21,12 @@ pub struct WlBuffer {
id: WlBufferId,
client: Rc<Client>,
offset: usize,
width: u32,
height: u32,
pub width: u32,
pub height: u32,
stride: u32,
format: &'static Format,
mem: RefCell<Option<Rc<ClientMem>>>,
pub image: Rc<pixman::Image<ClientMemOffset>>,
pub(super) surfaces: CopyHashMap<WlSurfaceId, Rc<WlSurface>>,
}
impl WlBuffer {
@ -42,10 +45,12 @@ impl WlBuffer {
if required > mem.len() as u64 {
return Err(WlBufferError::OutOfBounds);
}
let mem = mem.offset(offset);
let min_row_size = width as u64 * format.bpp as u64;
if (stride as u64) < min_row_size {
return Err(WlBufferError::StrideTooSmall);
}
let image = pixman::Image::new(mem, format.pixman, width, height, stride)?;
Ok(Self {
id,
client: client.clone(),
@ -54,24 +59,38 @@ impl WlBuffer {
height,
stride,
format,
mem: RefCell::new(Some(mem.clone())),
image: Rc::new(image),
surfaces: Default::default(),
})
}
async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> {
let _req: Destroy = self.client.parse(self, parser)?;
*self.mem.borrow_mut() = None;
{
let surfaces = self.surfaces.lock();
for surface in surfaces.values() {
*surface.buffer.borrow_mut() = None;
}
}
self.client.remove_obj(self).await?;
Ok(())
}
async fn handle_request_(&self, request: u32, parser: MsgParser<'_, '_>) -> Result<(), WlBufferError> {
async fn handle_request_(
&self,
request: u32,
parser: MsgParser<'_, '_>,
) -> Result<(), WlBufferError> {
match request {
DESTROY => self.destroy(parser).await?,
_ => unreachable!(),
}
Ok(())
}
pub fn release(self: &Rc<Self>) -> DynEventFormatter {
Box::new(Release { obj: self.clone() })
}
}
handle_request!(WlBuffer);
@ -88,4 +107,8 @@ impl Object for WlBuffer {
fn num_requests(&self) -> u32 {
DESTROY + 1
}
fn break_loops(&self) {
self.surfaces.clear();
}
}

View file

@ -1,10 +1,11 @@
use crate::client::{ClientError, EventFormatter, RequestParser};
use crate::ifs::wl_buffer::{WlBuffer, RELEASE};
use crate::object::Object;
use crate::pixman::PixmanError;
use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError};
use std::fmt::{Debug, Formatter};
use std::rc::Rc;
use thiserror::Error;
use crate::client::{ClientError, EventFormatter, RequestParser};
use crate::ifs::wl_buffer::{RELEASE, WlBuffer};
use crate::object::Object;
use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError};
#[derive(Debug, Error)]
pub enum WlBufferError {
@ -14,7 +15,10 @@ pub enum WlBufferError {
StrideTooSmall,
#[error("Could not handle a `destroy` request")]
DestroyError(#[from] DestroyError),
#[error("Pixman returned an error")]
PixmanError(#[source] Box<PixmanError>),
}
efrom!(WlBufferError, PixmanError, PixmanError);
#[derive(Debug, Error)]
pub enum DestroyError {

View file

@ -1 +1,223 @@
mod types;
use crate::backend::Output;
use crate::client::{AddObj, Client, ClientId, DynEventFormatter, WlEvent};
use crate::globals::{Global, GlobalName};
use crate::object::{Interface, Object, ObjectId};
use crate::utils::buffd::MsgParser;
use crate::utils::copyhashmap::CopyHashMap;
use ahash::AHashMap;
use std::cell::Cell;
use std::iter;
use std::rc::Rc;
pub use types::*;
id!(WlOutputId);
const RELEASE: u32 = 0;
const GEOMETRY: u32 = 0;
const MODE: u32 = 1;
const DONE: u32 = 2;
const SCALE: u32 = 3;
const SP_UNKNOWN: i32 = 0;
const SP_NONE: i32 = 1;
const SP_HORIZONTAL_RGB: i32 = 2;
const SP_HORIZONTAL_BGR: i32 = 3;
const SP_VERTICAL_RGB: i32 = 4;
const SP_VERTICAL_BGR: i32 = 5;
const TF_NORMAL: i32 = 0;
const TF_90: i32 = 1;
const TF_180: i32 = 2;
const TF_270: i32 = 3;
const TF_FLIPPED: i32 = 4;
const TF_FLIPPED_90: i32 = 5;
const TF_FLIPPED_180: i32 = 6;
const TF_FLIPPED_270: i32 = 7;
const MODE_CURRENT: u32 = 1;
const MODE_PREFERRED: u32 = 2;
pub struct WlOutputGlobal {
name: GlobalName,
output: Rc<dyn Output>,
width: Cell<u32>,
height: Cell<u32>,
bindings: CopyHashMap<(ClientId, WlOutputId), Rc<WlOutputObj>>,
}
impl WlOutputGlobal {
pub fn new(name: GlobalName, output: &Rc<dyn Output>) -> Self {
Self {
name,
output: output.clone(),
width: Cell::new(output.width()),
height: Cell::new(output.height()),
bindings: Default::default(),
}
}
pub async fn update_properties(&self) {
let width = self.output.width();
let height = self.output.height();
let mut changed = false;
changed |= self.width.replace(width) != width;
changed |= self.height.replace(height) != height;
if changed {
let mut clients = AHashMap::new();
{
let bindings = self.bindings.lock();
for binding in bindings.values() {
let events = [
binding.geometry(),
binding.mode(),
binding.scale(),
binding.done(),
];
let events = events
.into_iter()
.map(|e| WlEvent::Event(e))
.chain(iter::once(WlEvent::Flush));
for event in events {
if binding.client.event2_locked(event) {
clients.insert(binding.client.id, binding.client.clone());
}
}
}
}
for client in clients.values() {
let _ = client.check_queue_size().await;
}
}
}
async fn bind_(
self: Rc<Self>,
id: WlOutputId,
client: &Rc<Client>,
version: u32,
) -> Result<(), WlOutputError> {
let obj = Rc::new(WlOutputObj {
global: self.clone(),
id,
client: client.clone(),
});
client.add_client_obj(&obj)?;
self.bindings.set((client.id, id), obj.clone());
client.event(obj.geometry()).await?;
client.event(obj.mode()).await?;
client.event(obj.scale()).await?;
client.event(obj.done()).await?;
Ok(())
}
}
bind!(WlOutputGlobal);
impl Global for WlOutputGlobal {
fn name(&self) -> GlobalName {
self.name
}
fn interface(&self) -> Interface {
Interface::WlOutput
}
fn version(&self) -> u32 {
3
}
fn pre_remove(&self) {
//
}
fn break_loops(&self) {
self.bindings.clear();
}
}
pub struct WlOutputObj {
global: Rc<WlOutputGlobal>,
id: WlOutputId,
client: Rc<Client>,
}
impl WlOutputObj {
fn geometry(self: &Rc<Self>) -> DynEventFormatter {
Box::new(Geometry {
obj: self.clone(),
x: 0,
y: 0,
physical_width: self.global.width.get() as _,
physical_height: self.global.height.get() as _,
subpixel: SP_UNKNOWN,
make: String::new(),
model: String::new(),
transform: TF_NORMAL,
})
}
fn mode(self: &Rc<Self>) -> DynEventFormatter {
Box::new(Mode {
obj: self.clone(),
flags: MODE_CURRENT,
width: self.global.width.get() as _,
height: self.global.height.get() as _,
refresh: 60_000_000,
})
}
fn scale(self: &Rc<Self>) -> DynEventFormatter {
Box::new(Scale {
obj: self.clone(),
factor: 1,
})
}
fn done(self: &Rc<Self>) -> DynEventFormatter {
Box::new(Done { obj: self.clone() })
}
async fn release(&self, parser: MsgParser<'_, '_>) -> Result<(), ReleaseError> {
let _req: Release = self.client.parse(self, parser)?;
self.global.bindings.remove(&(self.client.id, self.id));
self.client.remove_obj(self).await?;
Ok(())
}
async fn handle_request_(
&self,
request: u32,
parser: MsgParser<'_, '_>,
) -> Result<(), WlOutputError> {
match request {
RELEASE => self.release(parser).await?,
_ => unreachable!(),
}
Ok(())
}
}
handle_request!(WlOutputObj);
impl Object for WlOutputObj {
fn id(&self) -> ObjectId {
self.id.into()
}
fn interface(&self) -> Interface {
Interface::WlOutput
}
fn num_requests(&self) -> u32 {
RELEASE + 1
}
fn break_loops(&self) {
self.global.bindings.remove(&(self.client.id, self.id));
}
}

136
src/ifs/wl_output/types.rs Normal file
View file

@ -0,0 +1,136 @@
use crate::client::{ClientError, EventFormatter, RequestParser};
use crate::ifs::wl_output::{WlOutputObj, DONE, GEOMETRY, MODE, SCALE};
use crate::object::Object;
use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError};
use std::fmt::{Debug, Formatter};
use std::rc::Rc;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum WlOutputError {
#[error("Could not handle `release` request")]
ReleaseError(#[from] ReleaseError),
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(WlOutputError, ClientError, ClientError);
#[derive(Debug, Error)]
pub enum ReleaseError {
#[error("Parsing failed")]
ParseError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(ReleaseError, ClientError, ClientError);
efrom!(ReleaseError, ParseError, MsgParserError);
pub(super) struct Release;
impl RequestParser<'_> for Release {
fn parse(_parser: &mut MsgParser<'_, '_>) -> Result<Self, MsgParserError> {
Ok(Self)
}
}
impl Debug for Release {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "release()")
}
}
pub(super) struct Geometry {
pub obj: Rc<WlOutputObj>,
pub x: i32,
pub y: i32,
pub physical_width: i32,
pub physical_height: i32,
pub subpixel: i32,
pub make: String,
pub model: String,
pub transform: i32,
}
impl EventFormatter for Geometry {
fn format(self: Box<Self>, fmt: &mut MsgFormatter<'_>) {
fmt.header(self.obj.id, GEOMETRY)
.int(self.x)
.int(self.y)
.int(self.physical_width)
.int(self.physical_height)
.int(self.subpixel)
.string(&self.make)
.string(&self.model)
.int(self.transform);
}
fn obj(&self) -> &dyn Object {
&*self.obj
}
}
impl Debug for Geometry {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "geometry(x: {}, y: {}, physical_width: {}, physical_height: {}, subpixel: {}, make: {}, model: {}, transform: {})",
self.x, self.y, self.physical_width, self.physical_height, self.subpixel, self.make, self.model, self.transform)
}
}
pub(super) struct Mode {
pub obj: Rc<WlOutputObj>,
pub flags: u32,
pub width: i32,
pub height: i32,
pub refresh: i32,
}
impl EventFormatter for Mode {
fn format(self: Box<Self>, fmt: &mut MsgFormatter<'_>) {
fmt.header(self.obj.id, MODE)
.uint(self.flags)
.int(self.width)
.int(self.height)
.int(self.refresh);
}
fn obj(&self) -> &dyn Object {
&*self.obj
}
}
impl Debug for Mode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"mode(flags: 0x{:x}, width: {}, height: {}, refresh: {})",
self.flags, self.width, self.height, self.refresh
)
}
}
pub(super) struct Done {
pub obj: Rc<WlOutputObj>,
}
impl EventFormatter for Done {
fn format(self: Box<Self>, fmt: &mut MsgFormatter<'_>) {
fmt.header(self.obj.id, DONE);
}
fn obj(&self) -> &dyn Object {
&*self.obj
}
}
impl Debug for Done {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "done()")
}
}
pub(super) struct Scale {
pub obj: Rc<WlOutputObj>,
pub factor: i32,
}
impl EventFormatter for Scale {
fn format(self: Box<Self>, fmt: &mut MsgFormatter<'_>) {
fmt.header(self.obj.id, SCALE).int(self.factor);
}
fn obj(&self) -> &dyn Object {
&*self.obj
}
}
impl Debug for Scale {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "scale(factor: {})", self.factor)
}
}

View file

@ -3,6 +3,7 @@ use crate::globals::{Global, GlobalError, GlobalName};
use crate::ifs::wl_registry::{WlRegistry, GLOBAL, GLOBAL_REMOVE};
use crate::object::{Interface, Object, ObjectId};
use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError};
use bstr::BStr;
use std::fmt::{Debug, Formatter};
use std::rc::Rc;
use thiserror::Error;
@ -93,7 +94,7 @@ impl Debug for GlobalRemove {
pub(super) struct Bind<'a> {
pub name: GlobalName,
pub id: ObjectId,
pub interface: &'a str,
pub interface: &'a BStr,
pub version: u32,
}
impl<'a> RequestParser<'a> for Bind<'a> {

View file

@ -1 +1,121 @@
mod types;
use crate::backend::{Seat, SeatEvent};
use crate::client::{AddObj, Client, ClientId};
use crate::globals::{Global, GlobalName};
use crate::object::{Interface, Object, ObjectId};
use crate::utils::buffd::MsgParser;
use crate::utils::copyhashmap::CopyHashMap;
use std::rc::Rc;
pub use types::*;
id!(WlSeatId);
const RELEASE: u32 = 0;
pub struct WlSeatGlobal {
name: GlobalName,
seat: Rc<dyn Seat>,
bindings: CopyHashMap<(ClientId, WlSeatId), Rc<WlSeatObj>>,
}
impl WlSeatGlobal {
pub fn new(name: GlobalName, seat: &Rc<dyn Seat>) -> Self {
Self {
name,
seat: seat.clone(),
bindings: Default::default(),
}
}
pub async fn event(&self, event: SeatEvent) {
log::debug!("se: {:?}", event);
}
async fn bind_(
self: Rc<Self>,
id: WlSeatId,
client: &Rc<Client>,
version: u32,
) -> Result<(), WlSeatError> {
let obj = Rc::new(WlSeatObj {
global: self.clone(),
id,
client: client.clone(),
});
client.add_client_obj(&obj)?;
self.bindings.set((client.id, id), obj.clone());
Ok(())
}
}
bind!(WlSeatGlobal);
impl Global for WlSeatGlobal {
fn name(&self) -> GlobalName {
self.name
}
fn interface(&self) -> Interface {
Interface::WlSeat
}
fn version(&self) -> u32 {
3
}
fn pre_remove(&self) {
//
}
fn break_loops(&self) {
self.bindings.clear();
}
}
pub struct WlSeatObj {
global: Rc<WlSeatGlobal>,
id: WlSeatId,
client: Rc<Client>,
}
impl WlSeatObj {
async fn release(&self, parser: MsgParser<'_, '_>) -> Result<(), ReleaseError> {
let _req: Release = self.client.parse(self, parser)?;
self.global.bindings.remove(&(self.client.id, self.id));
self.client.remove_obj(self).await?;
Ok(())
}
async fn handle_request_(
&self,
request: u32,
parser: MsgParser<'_, '_>,
) -> Result<(), WlSeatError> {
match request {
RELEASE => self.release(parser).await?,
_ => unreachable!(),
}
Ok(())
}
}
handle_request!(WlSeatObj);
impl Object for WlSeatObj {
fn id(&self) -> ObjectId {
self.id.into()
}
fn interface(&self) -> Interface {
Interface::WlSeat
}
fn num_requests(&self) -> u32 {
RELEASE + 1
}
fn break_loops(&self) {
self.global.bindings.remove(&(self.client.id, self.id));
}
}

35
src/ifs/wl_seat/types.rs Normal file
View file

@ -0,0 +1,35 @@
use crate::client::{ClientError, RequestParser};
use crate::utils::buffd::{MsgParser, MsgParserError};
use std::fmt::{Debug, Formatter};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum WlSeatError {
#[error("Could not handle `release` request")]
ReleaseError(#[from] ReleaseError),
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(WlSeatError, ClientError, ClientError);
#[derive(Debug, Error)]
pub enum ReleaseError {
#[error("Parsing failed")]
ParseError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(ReleaseError, ClientError, ClientError);
efrom!(ReleaseError, ParseError, MsgParserError);
pub(super) struct Release;
impl RequestParser<'_> for Release {
fn parse(_parser: &mut MsgParser<'_, '_>) -> Result<Self, MsgParserError> {
Ok(Self)
}
}
impl Debug for Release {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "release()")
}
}

View file

@ -3,17 +3,22 @@ pub mod wl_subsurface;
pub mod xdg_surface;
use crate::client::{AddObj, Client, RequestParser};
use crate::ifs::wl_buffer::WlBuffer;
use crate::ifs::wl_callback::WlCallback;
use crate::ifs::wl_surface::wl_subsurface::WlSubsurface;
use crate::ifs::wl_surface::xdg_surface::xdg_popup::XdgPopup;
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel;
use crate::ifs::wl_surface::xdg_surface::XdgSurface;
use crate::object::{Interface, Object, ObjectId};
use crate::pixman::Region;
use crate::tree::{NodeBase, NodeCommon, ToplevelNode};
use crate::utils::buffd::{MsgParser, MsgParserError};
use crate::utils::copyhashmap::CopyHashMap;
use crate::utils::linkedlist::{LinkedList, Node};
use crate::utils::linkedlist::{LinkedList, Node as LinkNode};
use ahash::AHashMap;
use std::cell::{Cell, RefCell};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
pub use types::*;
@ -56,11 +61,24 @@ impl SurfaceRole {
pub struct WlSurface {
id: WlSurfaceId,
client: Rc<Client>,
pub client: Rc<Client>,
role: Cell<SurfaceRole>,
pending: PendingState,
children: RefCell<Option<Box<ParentData>>>,
input_region: Cell<Option<Region>>,
opaque_region: Cell<Option<Region>>,
pub extents: Cell<SurfaceExtents>,
pub buffer: RefCell<Option<Rc<WlBuffer>>>,
pub children: RefCell<Option<Box<ParentData>>>,
role_data: RefCell<RoleData>,
pub frame_requests: RefCell<Vec<Rc<WlCallback>>>,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
pub struct SurfaceExtents {
pub x1: i32,
pub y1: i32,
pub x2: i32,
pub y2: i32,
}
enum RoleData {
@ -79,11 +97,13 @@ impl RoleData {
struct PendingState {
opaque_region: Cell<Option<Region>>,
input_region: Cell<Option<Region>>,
frame_request: RefCell<Vec<Rc<WlCallback>>>,
}
struct XdgSurfaceData {
xdg_surface: Rc<XdgSurface>,
committed: bool,
requested_serial: u32,
acked_serial: Option<u32>,
role: XdgSurfaceRole,
role_data: XdgSurfaceRoleData,
popups: CopyHashMap<WlSurfaceId, Rc<XdgPopup>>,
@ -121,6 +141,17 @@ struct XdgPopupData {
struct XdgToplevelData {
toplevel: Rc<XdgToplevel>,
node: Option<ToplevelNodeHolder>,
}
struct ToplevelNodeHolder {
node: Rc<ToplevelNode>,
}
impl Drop for ToplevelNodeHolder {
fn drop(&mut self) {
mem::take(&mut *self.node.common.floating_outputs.borrow_mut());
}
}
struct SubsurfaceData {
@ -129,27 +160,27 @@ struct SubsurfaceData {
y: i32,
sync_requested: bool,
sync_ancestor: bool,
node: Node<StackElement>,
node: LinkNode<StackElement>,
depth: u32,
pending: PendingSubsurfaceData,
}
#[derive(Default)]
struct PendingSubsurfaceData {
node: Option<Node<StackElement>>,
node: Option<LinkNode<StackElement>>,
position: Option<(i32, i32)>,
}
#[derive(Default)]
struct ParentData {
pub struct ParentData {
subsurfaces: AHashMap<WlSurfaceId, Rc<WlSurface>>,
below: LinkedList<StackElement>,
above: LinkedList<StackElement>,
pub below: LinkedList<StackElement>,
pub above: LinkedList<StackElement>,
}
struct StackElement {
pub struct StackElement {
pending: Cell<bool>,
surface: Rc<WlSurface>,
pub surface: Rc<WlSurface>,
}
impl WlSurface {
@ -159,11 +190,60 @@ impl WlSurface {
client: client.clone(),
role: Cell::new(SurfaceRole::None),
pending: Default::default(),
input_region: Cell::new(None),
opaque_region: Cell::new(None),
extents: Default::default(),
buffer: RefCell::new(None),
children: Default::default(),
role_data: RefCell::new(RoleData::None),
frame_requests: RefCell::new(vec![]),
}
}
pub fn subsurface_position(&self) -> Option<(i32, i32)> {
let rd = self.role_data.borrow();
match rd.deref() {
RoleData::Subsurface(ss) => Some((ss.x, ss.y)),
_ => None,
}
}
fn calculate_extents(&self) {
{
let mut extents = SurfaceExtents::default();
if let Some(b) = self.buffer.borrow().deref() {
extents.x2 = b.width as i32;
extents.y2 = b.height as i32;
}
let children = self.children.borrow();
if let Some(children) = &*children {
for surface in children.subsurfaces.values() {
let rd = surface.role_data.borrow();
if let RoleData::Subsurface(ss) = &*rd {
let mut ss_extents = surface.extents.get();
extents.x1 = extents.x1.min(ss_extents.x1 + ss.x);
extents.y1 = extents.y1.min(ss_extents.y1 + ss.y);
extents.x2 = extents.x2.max(ss_extents.x2 + ss.x);
extents.y2 = extents.y2.max(ss_extents.y2 + ss.y);
}
}
}
self.extents.set(extents);
}
let parent = {
let rd = self.role_data.borrow();
match &*rd {
RoleData::Subsurface(ss) => ss.subsurface.parent.clone(),
_ => return,
}
};
parent.calculate_extents();
}
pub fn is_subsurface(&self) -> bool {
self.role.get() == SurfaceRole::Subsurface
}
pub fn get_root(self: &Rc<Self>) -> Rc<WlSurface> {
let mut root = self.clone();
loop {
@ -197,11 +277,13 @@ impl WlSurface {
}
*children = None;
}
let mut ss_parent = None;
{
let mut data = self.role_data.borrow_mut();
match &mut *data {
RoleData::None => {}
RoleData::Subsurface(ss) => {
ss_parent = Some(ss.subsurface.parent.clone());
let mut children = ss.subsurface.parent.children.borrow_mut();
if let Some(children) = &mut *children {
children.subsurfaces.remove(&self.id);
@ -229,12 +311,63 @@ impl WlSurface {
}
*data = RoleData::None;
}
{
let buffer = self.buffer.borrow();
if let Some(buffer) = &*buffer {
buffer.surfaces.remove(&self.id);
}
}
if let Some(parent) = ss_parent {
parent.calculate_extents();
}
self.client.remove_obj(self).await?;
Ok(())
}
async fn attach(&self, parser: MsgParser<'_, '_>) -> Result<(), AttachError> {
let req: Attach = self.parse(parser)?;
{
let mut buffer = self.buffer.borrow_mut();
if let Some(buffer) = buffer.take() {
self.client.event(buffer.release()).await?;
buffer.surfaces.remove(&self.id);
}
let mut rd = self.role_data.borrow_mut();
if req.buffer.is_some() {
*buffer = Some(self.client.get_buffer(req.buffer)?);
if let RoleData::XdgSurface(xdg) = &mut *rd {
if let XdgSurfaceRoleData::Toplevel(td) = &mut xdg.role_data {
if td.node.is_none() {
let outputs = self.client.state.root.outputs.lock();
if let Some(output) = outputs.values().next() {
let node = Rc::new(ToplevelNode {
common: NodeCommon {
extents: Cell::new(Default::default()),
id: self.client.state.node_ids.next(),
parent: Some(output.clone()),
floating_outputs: RefCell::new(Default::default()),
},
surface: td.toplevel.clone(),
});
td.node = Some(ToplevelNodeHolder { node: node.clone() });
let link = output.floating.append(node.clone());
node.common
.floating_outputs
.borrow_mut()
.insert(output.id(), link);
}
}
}
}
} else {
*buffer = None;
if let RoleData::XdgSurface(xdg) = &mut *rd {
if let XdgSurfaceRoleData::Toplevel(td) = &mut xdg.role_data {
td.node = None;
}
}
}
}
Ok(())
}
@ -245,6 +378,9 @@ impl WlSurface {
async fn frame(&self, parser: MsgParser<'_, '_>) -> Result<(), FrameError> {
let req: Frame = self.parse(parser)?;
let cb = Rc::new(WlCallback::new(req.callback));
self.client.add_client_obj(&cb)?;
self.pending.frame_request.borrow_mut().push(cb);
Ok(())
}
@ -265,8 +401,75 @@ impl WlSurface {
Ok(())
}
fn do_commit(&self) {
{
let mut rd = self.role_data.borrow_mut();
match &mut *rd {
RoleData::None => {}
RoleData::Subsurface(ss) => {
if let Some(v) = ss.pending.node.take() {
v.pending.set(false);
ss.node = v;
}
if let Some((x, y)) = ss.pending.position.take() {
ss.x = x;
ss.y = y;
}
}
RoleData::XdgSurface(xdg) => {}
}
}
{
let mut pfr = self.pending.frame_request.borrow_mut();
self.frame_requests.borrow_mut().extend(pfr.drain(..));
}
{
if let Some(region) = self.pending.input_region.take() {
self.input_region.set(Some(region));
}
if let Some(region) = self.pending.opaque_region.take() {
self.opaque_region.set(Some(region));
}
}
let mut committed_any_children = false;
{
let children = self.children.borrow();
if let Some(children) = children.deref() {
for child in children.subsurfaces.values() {
child.do_commit();
committed_any_children = true;
}
}
}
if !committed_any_children {
self.calculate_extents();
}
}
async fn commit(&self, parser: MsgParser<'_, '_>) -> Result<(), CommitError> {
let req: Commit = self.parse(parser)?;
let _req: Commit = self.parse(parser)?;
{
let rd = self.role_data.borrow();
match rd.deref() {
RoleData::Subsurface(ss) => {
if ss.sync_ancestor || ss.sync_requested {
return Ok(());
}
}
RoleData::XdgSurface(xdg) => {
if xdg.acked_serial != Some(xdg.requested_serial) {
if xdg.acked_serial.is_none() {
self.client
.event(xdg.xdg_surface.configure(xdg.requested_serial))
.await?;
}
return Ok(());
}
}
_ => {}
}
}
self.do_commit();
Ok(())
}
@ -328,5 +531,7 @@ impl Object for WlSurface {
fn break_loops(&self) {
*self.children.borrow_mut() = None;
*self.role_data.borrow_mut() = RoleData::None;
mem::take(self.frame_requests.borrow_mut().deref_mut());
*self.buffer.borrow_mut() = None;
}
}

View file

@ -57,8 +57,11 @@ efrom!(DestroyError, ClientError, ClientError);
pub enum AttachError {
#[error("Parsing failed")]
ParseFailed(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(AttachError, ParseFailed, MsgParserError);
efrom!(AttachError, ClientError, ClientError);
#[derive(Debug, Error)]
pub enum DamageError {
@ -71,8 +74,11 @@ efrom!(DamageError, ParseFailed, MsgParserError);
pub enum FrameError {
#[error("Parsing failed")]
ParseFailed(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(FrameError, ParseFailed, MsgParserError);
efrom!(FrameError, ClientError, ClientError);
#[derive(Debug, Error)]
pub enum SetOpaqueRegionError {
@ -98,8 +104,11 @@ efrom!(SetInputRegionError, ClientError, ClientError);
pub enum CommitError {
#[error("Parsing failed")]
ParseFailed(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(CommitError, ParseFailed, MsgParserError);
efrom!(CommitError, ClientError, ClientError);
#[derive(Debug, Error)]
pub enum SetBufferTransformError {

View file

@ -142,6 +142,7 @@ impl WlSubsurface {
}
}
self.surface.client.remove_obj(self).await?;
self.parent.calculate_extents();
Ok(())
}

View file

@ -2,7 +2,7 @@ mod types;
pub mod xdg_popup;
pub mod xdg_toplevel;
use crate::client::AddObj;
use crate::client::{AddObj, DynEventFormatter};
use crate::ifs::wl_surface::xdg_surface::xdg_popup::XdgPopup;
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel;
use crate::ifs::wl_surface::{
@ -12,6 +12,7 @@ use crate::ifs::wl_surface::{
use crate::ifs::xdg_wm_base::XdgWmBaseObj;
use crate::object::{Interface, Object, ObjectId};
use crate::utils::buffd::MsgParser;
use std::ops::DerefMut;
use std::rc::Rc;
pub use types::*;
@ -32,7 +33,7 @@ id!(XdgSurfaceId);
pub struct XdgSurface {
id: XdgSurfaceId,
wm_base: Rc<XdgWmBaseObj>,
pub(super) surface: Rc<WlSurface>,
pub surface: Rc<WlSurface>,
version: u32,
}
@ -51,6 +52,13 @@ impl XdgSurface {
}
}
pub fn configure(self: &Rc<Self>, serial: u32) -> DynEventFormatter {
Box::new(Configure {
obj: self.clone(),
serial,
})
}
pub fn install(self: &Rc<Self>) -> Result<(), XdgSurfaceError> {
let old_role = self.surface.role.get();
if !matches!(old_role, SurfaceRole::None | SurfaceRole::XdgSurface) {
@ -62,7 +70,8 @@ impl XdgSurface {
}
*data = RoleData::XdgSurface(Box::new(XdgSurfaceData {
xdg_surface: self.clone(),
committed: false,
requested_serial: 0,
acked_serial: None,
role: XdgSurfaceRole::None,
role_data: XdgSurfaceRoleData::None,
popups: Default::default(),
@ -119,7 +128,10 @@ impl XdgSurface {
data.role = XdgSurfaceRole::Toplevel;
let toplevel = Rc::new(XdgToplevel::new(req.id, self, self.version));
self.surface.client.add_client_obj(&toplevel)?;
data.role_data = XdgSurfaceRoleData::Toplevel(XdgToplevelData { toplevel });
data.role_data = XdgSurfaceRoleData::Toplevel(XdgToplevelData {
toplevel,
node: None,
});
}
Ok(())
}
@ -169,7 +181,13 @@ impl XdgSurface {
}
async fn ack_configure(&self, parser: MsgParser<'_, '_>) -> Result<(), AckConfigureError> {
let _req: AckConfigure = self.surface.client.parse(self, parser)?;
let req: AckConfigure = self.surface.client.parse(self, parser)?;
let mut rd = self.surface.role_data.borrow_mut();
if let RoleData::XdgSurface(xdg) = rd.deref_mut() {
if xdg.requested_serial == req.serial {
xdg.acked_serial = Some(xdg.requested_serial);
}
}
Ok(())
}

View file

@ -52,7 +52,7 @@ id!(XdgToplevelId);
pub struct XdgToplevel {
id: XdgToplevelId,
surface: Rc<XdgSurface>,
pub surface: Rc<XdgSurface>,
version: u32,
}

View file

@ -4,6 +4,7 @@ use crate::ifs::wl_seat::WlSeatId;
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::{XdgToplevel, XdgToplevelId, CLOSE};
use crate::object::Object;
use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError};
use bstr::BStr;
use std::fmt::{Debug, Formatter};
use std::rc::Rc;
use thiserror::Error;
@ -209,7 +210,7 @@ impl Debug for SetParent {
}
pub(super) struct SetTitle<'a> {
pub title: &'a str,
pub title: &'a BStr,
}
impl<'a> RequestParser<'a> for SetTitle<'a> {
fn parse(parser: &mut MsgParser<'_, 'a>) -> Result<Self, MsgParserError> {
@ -225,7 +226,7 @@ impl<'a> Debug for SetTitle<'a> {
}
pub(super) struct SetAppId<'a> {
pub app_id: &'a str,
pub app_id: &'a BStr,
}
impl<'a> RequestParser<'a> for SetAppId<'a> {
fn parse(parser: &mut MsgParser<'_, 'a>) -> Result<Self, MsgParserError> {

View file

@ -92,3 +92,71 @@ macro_rules! id {
}
};
}
macro_rules! linear_ids {
($ids:ident, $id:ident) => {
pub struct $ids {
next: crate::utils::numcell::NumCell<u32>,
}
impl Default for $ids {
fn default() -> Self {
Self {
next: crate::utils::numcell::NumCell::new(1),
}
}
}
impl $ids {
pub fn next(&self) -> $id {
$id(self.next.fetch_add(1))
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct $id(u32);
impl $id {
pub fn raw(&self) -> u32 {
self.0
}
}
impl std::fmt::Display for $id {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}
};
}
macro_rules! cenum {
($name:ident, $uc:ident; $($name2:ident = $val:expr,)*) => {
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct $name(pub(super) u32);
impl $name {
pub fn raw(self) -> u32 {
self.0
}
}
pub const $uc: &[u32] = &[$($val,)*];
$(
pub const $name2: $name = $name($val);
)*
}
}
macro_rules! bitor {
($name:ident) => {
impl std::ops::BitOr for $name {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
};
}

View file

@ -1,7 +1,13 @@
#![feature(generic_associated_types, type_alias_impl_trait)]
#![feature(
generic_associated_types,
type_alias_impl_trait,
never_type,
c_variadic
)]
use crate::acceptor::AcceptorError;
use crate::async_engine::AsyncError;
use crate::backends::xorg::{XorgBackend, XorgBackendError};
use crate::client::Clients;
use crate::clientmem::ClientMemError;
use crate::event_loop::EventLoopError;
@ -12,7 +18,9 @@ use crate::ifs::wl_subcompositor::WlSubcompositorGlobal;
use crate::ifs::xdg_wm_base::XdgWmBaseGlobal;
use crate::sighand::SighandError;
use crate::state::State;
use crate::tree::{DisplayNode, NodeIds};
use crate::utils::numcell::NumCell;
use crate::utils::queue::AsyncQueue;
use crate::wheel::WheelError;
use acceptor::Acceptor;
use anyhow::anyhow;
@ -27,6 +35,8 @@ use wheel::Wheel;
mod macros;
mod acceptor;
mod async_engine;
mod backend;
mod backends;
mod client;
mod clientmem;
mod event_loop;
@ -35,11 +45,16 @@ mod globals;
mod ifs;
mod object;
mod pixman;
mod servermem;
mod sighand;
mod state;
mod tasks;
mod time;
mod tree;
mod utils;
mod wheel;
mod xkbcommon;
mod fixed;
fn main() {
env_logger::builder()
@ -65,6 +80,8 @@ 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),
}
fn main_() -> Result<(), MainError> {
@ -78,15 +95,26 @@ fn main_() -> Result<(), MainError> {
globals.insert_no_broadcast(Rc::new(WlShmGlobal::new(globals.name())));
globals.insert_no_broadcast(Rc::new(WlSubcompositorGlobal::new(globals.name())));
globals.insert_no_broadcast(Rc::new(XdgWmBaseGlobal::new(globals.name())));
let node_ids = NodeIds::default();
let state = Rc::new(State {
eng: engine,
eng: engine.clone(),
el: el.clone(),
wheel,
clients: Clients::new(),
next_name: NumCell::new(1),
globals,
formats: format::formats(),
output_ids: Default::default(),
root: Rc::new(DisplayNode::new(node_ids.next())),
node_ids,
backend_events: AsyncQueue::new(),
output_handlers: Default::default(),
seat_ids: Default::default(),
seat_handlers: Default::default(),
});
let _global_event_handler = engine.spawn(tasks::handle_backend_events(state.clone()));
Acceptor::install(&state)?;
let _backend = XorgBackend::new(&state)?;
el.run()?;
Ok(())
}

View file

@ -48,6 +48,7 @@ pub enum Interface {
WlDisplay,
WlCallback,
WlCompositor,
WlOutput,
WlRegistry,
WlShm,
WlShmPool,
@ -61,6 +62,7 @@ pub enum Interface {
XdgToplevel,
WlRegion,
WlBuffer,
WlSeat,
}
impl Interface {
@ -82,6 +84,8 @@ impl Interface {
Interface::XdgPopup => "xdg_popup",
Interface::XdgToplevel => "xdg_toplevel",
Interface::WlBuffer => "wl_buffer",
Interface::WlOutput => "wl_output",
Interface::WlSeat => "wl_seat",
}
}
}

View file

@ -1,95 +0,0 @@
use std::ptr;
use uapi::c;
#[link(name = "pixman-1")]
extern "C" {
fn pixman_region32_init(region: *mut Region);
fn pixman_region32_init_rect(
region: *mut Region,
x: c::c_int,
y: c::c_int,
width: c::c_uint,
height: c::c_uint,
);
fn pixman_region32_fini(region: *mut Region);
fn pixman_region32_copy(dst: *mut Region, src: *const Region);
fn pixman_region32_union(dst: *mut Region, a: *const Region, b: *const Region);
fn pixman_region32_subtract(dst: *mut Region, a: *const Region, b: *const Region);
}
#[repr(C)]
#[derive(Copy, Clone, Default, Debug)]
pub struct Box32 {
x1: i32,
y1: i32,
x2: i32,
y2: i32,
}
#[repr(C)]
struct RegionData {
size: c::c_long,
num_rects: c::c_long,
// rects: [Box32; size],
}
#[repr(C)]
pub struct Region {
extents: Box32,
data: *mut RegionData,
}
impl Region {
pub fn new() -> Self {
let mut slf = Region {
extents: Default::default(),
data: ptr::null_mut(),
};
unsafe {
pixman_region32_init(&mut slf);
}
slf
}
pub fn rect(x: i32, y: i32, width: u32, height: u32) -> Self {
let mut new = Region::new();
unsafe {
pixman_region32_init_rect(&mut new, x as _, y as _, width as _, height as _);
}
new
}
pub fn add(&self, region: &Self) -> Self {
let mut new = Region::new();
unsafe {
pixman_region32_union(&mut new, self, region);
}
new
}
pub fn subtract(&self, region: &Self) -> Self {
let mut new = Region::new();
unsafe {
pixman_region32_subtract(&mut new, self, region);
}
new
}
}
impl Clone for Region {
fn clone(&self) -> Self {
let mut new = Region::new();
unsafe {
pixman_region32_copy(&mut new, self);
}
new
}
}
impl Drop for Region {
fn drop(&mut self) {
unsafe {
pixman_region32_fini(self);
}
}
}

192
src/pixman/consts.rs Normal file
View file

@ -0,0 +1,192 @@
#![allow(dead_code)]
pub const fn format(bpp: u32, ty: u32, a: u32, r: u32, g: u32, b: u32) -> u32 {
(bpp << 24) | (ty << 16) | (a << 12) | (r << 8) | (g << 4) | b
}
pub const fn format_byte(bpp: u32, ty: u32, a: u32, r: u32, g: u32, b: u32) -> u32 {
((bpp >> 3) << 24)
| (3 << 22)
| (ty << 16)
| ((a >> 3) << 12)
| ((r >> 3) << 8)
| ((g >> 3) << 4)
| (b >> 3)
}
pub const fn format_reshift(val: u32, ofs: u32, num: u32) -> u32 {
((val >> (ofs)) & ((1 << (num)) - 1)) << ((val >> 22) & 3)
}
pub const fn format_bpp(f: u32) -> u32 {
format_reshift(f, 24, 8)
}
pub const fn format_shift(f: u32) -> u32 {
(f >> 22) & 3
}
pub const fn format_type(f: u32) -> u32 {
(f >> 16) & 0x3f
}
pub const fn format_a(f: u32) -> u32 {
format_reshift(f, 12, 4)
}
pub const fn format_r(f: u32) -> u32 {
format_reshift(f, 8, 4)
}
pub const fn format_g(f: u32) -> u32 {
format_reshift(f, 4, 4)
}
pub const fn format_b(f: u32) -> u32 {
format_reshift(f, 0, 4)
}
pub const fn format_rgb(f: u32) -> u32 {
f & 0xfff
}
pub const fn format_vis(f: u32) -> u32 {
f & 0xffff
}
pub const fn format_depth(f: u32) -> u32 {
format_a(f) + format_r(f) + format_g(f) + format_b(f)
}
pub const TYPE_OTHER: u32 = 0;
pub const TYPE_A: u32 = 1;
pub const TYPE_ARGB: u32 = 2;
pub const TYPE_ABGR: u32 = 3;
pub const TYPE_COLOR: u32 = 4;
pub const TYPE_GRAY: u32 = 5;
pub const TYPE_YUY2: u32 = 6;
pub const TYPE_YV12: u32 = 7;
pub const TYPE_BGRA: u32 = 8;
pub const TYPE_RGBA: u32 = 9;
pub const TYPE_ARGB_SRGB: u32 = 10;
pub const TYPE_RGBA_FLOAT: u32 = 11;
pub const fn format_color(f: u32) -> bool {
format_type(f) == TYPE_ARGB
|| format_type(f) == TYPE_ABGR
|| format_type(f) == TYPE_BGRA
|| format_type(f) == TYPE_RGBA
|| format_type(f) == TYPE_RGBA_FLOAT
}
cenum! {
Format, FORMATS;
RGBA_FLOAT = format_byte(128, TYPE_RGBA_FLOAT, 32, 32, 32, 32),
RGB_FLOAT = format_byte(96, TYPE_RGBA_FLOAT, 0, 32, 32, 32),
A8R8G8B8 = format(32, TYPE_ARGB, 8, 8, 8, 8),
X8R8G8B8 = format(32, TYPE_ARGB, 0, 8, 8, 8),
A8B8G8R8 = format(32, TYPE_ABGR, 8, 8, 8, 8),
X8B8G8R8 = format(32, TYPE_ABGR, 0, 8, 8, 8),
B8G8R8A8 = format(32, TYPE_BGRA, 8, 8, 8, 8),
B8G8R8X8 = format(32, TYPE_BGRA, 0, 8, 8, 8),
R8G8B8A8 = format(32, TYPE_RGBA, 8, 8, 8, 8),
R8G8B8X8 = format(32, TYPE_RGBA, 0, 8, 8, 8),
X14R6G6B6 = format(32, TYPE_ARGB, 0, 6, 6, 6),
X2R10G10B10 = format(32, TYPE_ARGB, 0, 10, 10, 10),
A2R10G10B10 = format(32, TYPE_ARGB, 2, 10, 10, 10),
X2B10G10R10 = format(32, TYPE_ABGR, 0, 10, 10, 10),
A2B10G10R10 = format(32, TYPE_ABGR, 2, 10, 10, 10),
A8R8G8B8_SRGB = format(32, TYPE_ARGB_SRGB, 8, 8, 8, 8),
R8G8B8 = format(24, TYPE_ARGB, 0, 8, 8, 8),
B8G8R8 = format(24, TYPE_ABGR, 0, 8, 8, 8),
R5G6B5 = format(16, TYPE_ARGB, 0, 5, 6, 5),
B5G6R5 = format(16, TYPE_ABGR, 0, 5, 6, 5),
A1R5G5B5 = format(16, TYPE_ARGB, 1, 5, 5, 5),
X1R5G5B5 = format(16, TYPE_ARGB, 0, 5, 5, 5),
A1B5G5R5 = format(16, TYPE_ABGR, 1, 5, 5, 5),
X1B5G5R5 = format(16, TYPE_ABGR, 0, 5, 5, 5),
A4R4G4B4 = format(16, TYPE_ARGB, 4, 4, 4, 4),
X4R4G4B4 = format(16, TYPE_ARGB, 0, 4, 4, 4),
A4B4G4R4 = format(16, TYPE_ABGR, 4, 4, 4, 4),
X4B4G4R4 = format(16, TYPE_ABGR, 0, 4, 4, 4),
A8 = format(8, TYPE_A, 8, 0, 0, 0),
R3G3B2 = format(8, TYPE_ARGB, 0, 3, 3, 2),
B2G3R3 = format(8, TYPE_ABGR, 0, 3, 3, 2),
A2R2G2B2 = format(8, TYPE_ARGB, 2, 2, 2, 2),
A2B2G2R2 = format(8, TYPE_ABGR, 2, 2, 2, 2),
C8 = format(8, TYPE_COLOR, 0, 0, 0, 0),
G8 = format(8, TYPE_GRAY, 0, 0, 0, 0),
X4A4 = format(8, TYPE_A, 4, 0, 0, 0),
X4C4 = format(8, TYPE_COLOR, 0, 0, 0, 0),
X4G4 = format(8, TYPE_GRAY, 0, 0, 0, 0),
A4 = format(4, TYPE_A, 4, 0, 0, 0),
R1G2B1 = format(4, TYPE_ARGB, 0, 1, 2, 1),
B1G2R1 = format(4, TYPE_ABGR, 0, 1, 2, 1),
A1R1G1B1 = format(4, TYPE_ARGB, 1, 1, 1, 1),
A1B1G1R1 = format(4, TYPE_ABGR, 1, 1, 1, 1),
C4 = format(4, TYPE_COLOR, 0, 0, 0, 0),
G4 = format(4, TYPE_GRAY, 0, 0, 0, 0),
A1 = format(1, TYPE_A, 1, 0, 0, 0),
G1 = format(1, TYPE_GRAY, 0, 0, 0, 0),
YUY2 = format(16, TYPE_YUY2, 0, 0, 0, 0),
YV12 = format(12, TYPE_YV12, 0, 0, 0, 0),
}
cenum! {
Op, OPS;
OP_CLEAR = 0x00,
OP_SRC = 0x01,
OP_DST = 0x02,
OP_OVER = 0x03,
OP_OVER_REVERSE = 0x04,
OP_IN = 0x05,
OP_IN_REVERSE = 0x06,
OP_OUT = 0x07,
OP_OUT_REVERSE = 0x08,
OP_ATOP = 0x09,
OP_ATOP_REVERSE = 0x0a,
OP_XOR = 0x0b,
OP_ADD = 0x0c,
OP_SATURATE = 0x0d,
OP_DISJOINT_CLEAR = 0x10,
OP_DISJOINT_SRC = 0x11,
OP_DISJOINT_DST = 0x12,
OP_DISJOINT_OVER = 0x13,
OP_DISJOINT_OVER_REVERSE = 0x14,
OP_DISJOINT_IN = 0x15,
OP_DISJOINT_IN_REVERSE = 0x16,
OP_DISJOINT_OUT = 0x17,
OP_DISJOINT_OUT_REVERSE = 0x18,
OP_DISJOINT_ATOP = 0x19,
OP_DISJOINT_ATOP_REVERSE = 0x1a,
OP_DISJOINT_XOR = 0x1b,
OP_CONJOINT_CLEAR = 0x20,
OP_CONJOINT_SRC = 0x21,
OP_CONJOINT_DST = 0x22,
OP_CONJOINT_OVER = 0x23,
OP_CONJOINT_OVER_REVERSE = 0x24,
OP_CONJOINT_IN = 0x25,
OP_CONJOINT_IN_REVERSE = 0x26,
OP_CONJOINT_OUT = 0x27,
OP_CONJOINT_OUT_REVERSE = 0x28,
OP_CONJOINT_ATOP = 0x29,
OP_CONJOINT_ATOP_REVERSE = 0x2a,
OP_CONJOINT_XOR = 0x2b,
OP_MULTIPLY = 0x30,
OP_SCREEN = 0x31,
OP_OVERLAY = 0x32,
OP_DARKEN = 0x33,
OP_LIGHTEN = 0x34,
OP_COLOR_DODGE = 0x35,
OP_COLOR_BURN = 0x36,
OP_HARD_LIGHT = 0x37,
OP_SOFT_LIGHT = 0x38,
OP_DIFFERENCE = 0x39,
OP_EXCLUSION = 0x3a,
OP_HSL_HUE = 0x3b,
OP_HSL_SATURATION = 0x3c,
OP_HSL_COLOR = 0x3d,
OP_HSL_LUMINOSITY = 0x3e,
}

291
src/pixman/mod.rs Normal file
View file

@ -0,0 +1,291 @@
mod consts;
include!(concat!(env!("OUT_DIR"), "/pixman_tys.rs"));
use crate::ClientMemError;
pub use consts::*;
use std::cell::Cell;
use std::ptr;
use thiserror::Error;
use uapi::c;
#[link(name = "pixman-1")]
#[allow(improper_ctypes)]
extern "C" {
fn pixman_region32_init(region: *mut Region);
fn pixman_region32_init_rect(
region: *mut Region,
x: c::c_int,
y: c::c_int,
width: c::c_uint,
height: c::c_uint,
);
fn pixman_region32_fini(region: *mut Region);
fn pixman_region32_copy(dst: *mut Region, src: *const Region);
fn pixman_region32_union(dst: *mut Region, a: *const Region, b: *const Region);
fn pixman_region32_subtract(dst: *mut Region, a: *const Region, b: *const Region);
fn pixman_image_create_bits_no_clear(
format: PixmanFormat,
width: c::c_int,
height: c::c_int,
bits: *mut u32,
stride: c::c_int,
) -> *mut PixmanImage;
fn pixman_image_unref(image: *mut PixmanImage) -> c::c_int;
// fn pixman_image_ref(image: *mut PixmanImage) -> *mut PixmanImage;
fn pixman_image_fill_boxes(
op: PixmanOp,
dest: *mut PixmanImage,
color: *const Color,
nboxes: c::c_int,
boxes: *const Box32,
) -> c::c_int;
fn pixman_image_composite32(
op: PixmanOp,
src: *mut PixmanImage,
mask: *mut PixmanImage,
dest: *mut PixmanImage,
src_x: i32,
src_y: i32,
mask_x: i32,
mask_y: i32,
dest_x: i32,
dest_y: i32,
width: i32,
height: i32,
);
}
#[repr(C)]
#[derive(Copy, Clone, Default, Debug)]
pub struct Box32 {
pub x1: i32,
pub y1: i32,
pub x2: i32,
pub y2: i32,
}
#[repr(C)]
#[derive(Copy, Clone, Default, Debug)]
pub struct Color {
red: u16,
green: u16,
blue: u16,
alpha: u16,
}
#[repr(C)]
struct RegionData {
size: c::c_long,
num_rects: c::c_long,
// rects: [Box32; size],
}
#[repr(C)]
pub struct Region {
extents: Box32,
data: *mut RegionData,
}
impl Region {
pub fn new() -> Self {
let mut slf = Region {
extents: Default::default(),
data: ptr::null_mut(),
};
unsafe {
pixman_region32_init(&mut slf);
}
slf
}
pub fn rect(x: i32, y: i32, width: u32, height: u32) -> Self {
let mut new = Region::new();
unsafe {
pixman_region32_init_rect(&mut new, x as _, y as _, width as _, height as _);
}
new
}
pub fn add(&self, region: &Self) -> Self {
let mut new = Region::new();
unsafe {
pixman_region32_union(&mut new, self, region);
}
new
}
pub fn subtract(&self, region: &Self) -> Self {
let mut new = Region::new();
unsafe {
pixman_region32_subtract(&mut new, self, region);
}
new
}
}
impl Clone for Region {
fn clone(&self) -> Self {
let mut new = Region::new();
unsafe {
pixman_region32_copy(&mut new, self);
}
new
}
}
impl Drop for Region {
fn drop(&mut self) {
unsafe {
pixman_region32_fini(self);
}
}
}
pub unsafe trait PixmanMemory: Clone {
type E;
fn access<T, F>(&self, f: F) -> Result<T, Self::E>
where
F: FnOnce(&[Cell<u8>]) -> T;
}
#[derive(Debug, Error)]
pub enum PixmanError {
#[error("The image size values cannot be represented in c_int")]
SizeOverflow,
#[error("The pixman memory does not contain enough memory to hold the image")]
InsufficientMemory,
#[error("The stride does not contain enough bytes to contain a row")]
RowOverflow,
#[error("Pixman images must be aligned at a 4 byte boundary")]
UnalignedMemory,
#[error("Internal pixman error")]
Internal,
#[error(transparent)]
ClientMemError(Box<ClientMemError>),
}
efrom!(PixmanError, ClientMemError, ClientMemError);
impl From<!> for PixmanError {
fn from(_: !) -> Self {
unreachable!()
}
}
struct PixmanImage;
pub struct Image<T> {
data: *mut PixmanImage,
width: u32,
height: u32,
memory: T,
}
impl<T: PixmanMemory> Image<T>
where
PixmanError: From<<T as PixmanMemory>::E>,
{
pub fn new(
memory: T,
format: Format,
width: u32,
height: u32,
stride: u32,
) -> Result<Self, PixmanError> {
let data = memory.access(|m| {
if format_bpp(format.raw()) as u64 * width as u64 > stride as u64 * 8 {
return Err(PixmanError::RowOverflow);
}
if (m.len() as u64) < height as u64 * stride as u64 {
return Err(PixmanError::InsufficientMemory);
}
let (width, height, stride) =
match (width.try_into(), height.try_into(), stride.try_into()) {
(Ok(w), Ok(h), Ok(s)) => (w, h, s),
_ => return Err(PixmanError::SizeOverflow),
};
if m.as_ptr() as usize % 4 != 0 {
return Err(PixmanError::UnalignedMemory);
}
let data = unsafe {
pixman_image_create_bits_no_clear(
format.raw() as _,
width,
height,
m.as_ptr() as _,
stride,
)
};
if data.is_null() {
return Err(PixmanError::Internal);
}
Ok(data)
})??;
Ok(Self {
data,
width,
height,
memory,
})
}
pub fn fill(&self, r: u8, g: u8, b: u8, a: u8) -> Result<(), PixmanError> {
self.memory.access(|_| {
let bx = Box32 {
x1: 0,
y1: 0,
x2: self.width as _,
y2: self.height as _,
};
let color = Color {
red: (r as u16) << 8,
green: (g as u16) << 8,
blue: (b as u16) << 8,
alpha: (a as u16) << 8,
};
unsafe {
pixman_image_fill_boxes(OP_SRC.raw() as PixmanOp, self.data, &color, 1, &bx);
}
})?;
Ok(())
}
pub fn add_image<U>(&self, over: &Image<U>, x: i32, y: i32) -> Result<(), PixmanError>
where
U: PixmanMemory,
PixmanError: From<<U as PixmanMemory>::E>,
{
self.memory.access(|_| {
over.memory.access(|_| unsafe {
pixman_image_composite32(
OP_OVER.raw(),
over.data,
ptr::null_mut(),
self.data,
0,
0,
0,
0,
x,
y,
over.width as _,
over.height as _,
);
})
})??;
Ok(())
}
pub fn memory(&self) -> &T {
&self.memory
}
}
impl<T> Drop for Image<T> {
fn drop(&mut self) {
unsafe {
pixman_image_unref(self.data);
}
}
}

93
src/servermem.rs Normal file
View file

@ -0,0 +1,93 @@
use crate::pixman::PixmanMemory;
use std::cell::Cell;
use std::ptr;
use std::rc::Rc;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::Relaxed;
use thiserror::Error;
use uapi::{c, Errno, OwnedFd};
#[derive(Debug, Error)]
pub enum ServerMemError {
#[error("memfd_create failed")]
MemfdCreate(#[source] std::io::Error),
#[error("The provided size does not fit into off_t")]
SizeOverflow,
#[error("ftruncate failed")]
Ftruncate(#[source] std::io::Error),
#[error("mmap failed")]
MmapFailed(#[source] std::io::Error),
#[error("sealing failed")]
Seal(#[source] std::io::Error),
}
pub struct ServerMem {
fd: OwnedFd,
mem: *const [Cell<u8>],
}
static NEXT_ID: AtomicUsize = AtomicUsize::new(1);
impl ServerMem {
pub fn new(size: usize) -> Result<Self, ServerMemError> {
let name = format!("servermem-{}", NEXT_ID.fetch_add(1, Relaxed));
let fd = match uapi::memfd_create(name, c::MFD_CLOEXEC | c::MFD_ALLOW_SEALING) {
Ok(f) => f,
Err(e) => return Err(ServerMemError::MemfdCreate(e.into())),
};
let o_size = match size.try_into() {
Ok(s) => s,
_ => return Err(ServerMemError::SizeOverflow),
};
if let Err(e) = uapi::ftruncate(fd.raw(), o_size) {
return Err(ServerMemError::Ftruncate(e.into()));
}
if let Err(e) =
uapi::fcntl_add_seals(fd.raw(), c::F_SEAL_SHRINK | c::F_SEAL_GROW | c::F_SEAL_SEAL)
{
return Err(ServerMemError::Seal(e.into()));
}
let mem = unsafe {
let res = c::mmap64(
ptr::null_mut(),
size,
c::PROT_READ | c::PROT_WRITE,
c::MAP_SHARED,
fd.raw(),
0,
);
if res == c::MAP_FAILED {
return Err(ServerMemError::MmapFailed(Errno::default().into()));
}
std::slice::from_raw_parts(res as *mut Cell<u8>, size)
};
Ok(Self { fd, mem })
}
pub fn access<T, F: FnOnce(&[Cell<u8>]) -> T>(&self, f: F) -> T {
unsafe { f(&*self.mem) }
}
pub fn fd(&self) -> i32 {
self.fd.raw()
}
}
impl Drop for ServerMem {
fn drop(&mut self) {
unsafe {
c::munmap(self.mem as *const _ as _, (*self.mem).len());
}
}
}
unsafe impl PixmanMemory for Rc<ServerMem> {
type E = !;
fn access<T, F>(&self, f: F) -> Result<T, Self::E>
where
F: FnOnce(&[Cell<u8>]) -> T,
{
Ok(ServerMem::access(self, f))
}
}

View file

@ -22,6 +22,7 @@ pub enum SighandError {
pub fn install(el: &Rc<EventLoop>) -> Result<(), SighandError> {
let mut set: c::sigset_t = uapi::pod_zeroed();
uapi::sigaddset(&mut set, c::SIGINT).unwrap();
uapi::sigaddset(&mut set, c::SIGTERM).unwrap();
if let Err(e) = uapi::pthread_sigmask(c::SIG_BLOCK, Some(&set), None) {
return Err(SighandError::BlockFailed(e.into()));
}
@ -46,7 +47,7 @@ struct Sighand {
}
impl EventLoopDispatcher for Sighand {
fn dispatch(&self, events: i32) -> Result<(), Box<dyn Error + Send + Sync>> {
fn dispatch(self: Rc<Self>, events: i32) -> Result<(), Box<dyn Error + Send + Sync>> {
if events & (c::EPOLLERR | c::EPOLLHUP) != 0 {
return Err(Box::new(SighandError::ErrorEvent));
}
@ -59,10 +60,8 @@ impl EventLoopDispatcher for Sighand {
}
}
log::info!("Received signal {}", sigfd.ssi_signo);
if sigfd.ssi_signo == c::SIGINT as _ {
log::info!("Exiting");
self.el.stop();
}
log::info!("Exiting");
self.el.stop();
}
Ok(())
}

View file

@ -1,17 +1,30 @@
use crate::async_engine::AsyncEngine;
use crate::async_engine::{AsyncEngine, SpawnedFuture};
use crate::backend::{BackendEvent, OutputId, OutputIds, SeatId, SeatIds};
use crate::client::Clients;
use crate::event_loop::EventLoop;
use crate::format::Format;
use crate::globals::Globals;
use crate::tree::{DisplayNode, NodeIds};
use crate::utils::numcell::NumCell;
use crate::utils::queue::AsyncQueue;
use crate::Wheel;
use ahash::AHashMap;
use std::cell::RefCell;
use std::rc::Rc;
pub struct State {
pub eng: Rc<AsyncEngine>,
pub el: Rc<EventLoop>,
pub wheel: Rc<Wheel>,
pub clients: Clients,
pub next_name: NumCell<u32>,
pub globals: Globals,
pub formats: AHashMap<u32, &'static Format>,
pub output_ids: OutputIds,
pub seat_ids: SeatIds,
pub node_ids: NodeIds,
pub root: Rc<DisplayNode>,
pub backend_events: AsyncQueue<BackendEvent>,
pub output_handlers: RefCell<AHashMap<OutputId, SpawnedFuture<()>>>,
pub seat_handlers: RefCell<AHashMap<SeatId, SpawnedFuture<()>>>,
}

138
src/tasks.rs Normal file
View file

@ -0,0 +1,138 @@
use crate::backend::{BackendEvent, Output, Seat};
use crate::ifs::wl_output::WlOutputGlobal;
use crate::ifs::wl_seat::WlSeatGlobal;
use crate::tree::{NodeCommon, NodeExtents, OutputNode};
use crate::utils::asyncevent::AsyncEvent;
use crate::State;
use std::cell::{Cell, RefCell};
use std::rc::Rc;
pub async fn handle_backend_events(state: Rc<State>) {
let mut beh = BackendEventHandler { state };
beh.handle_events().await;
}
struct BackendEventHandler {
state: Rc<State>,
}
impl BackendEventHandler {
async fn handle_events(&mut self) {
loop {
let event = self.state.backend_events.pop().await;
self.handle_event(event).await;
}
}
async fn handle_event(&mut self, event: BackendEvent) {
match event {
BackendEvent::NewOutput(output) => self.handle_new_output(output).await,
BackendEvent::NewSeat(seat) => self.handle_new_seat(seat).await,
}
}
async fn handle_new_output(&mut self, output: Rc<dyn Output>) {
let id = output.id();
let oh = OutputHandler {
state: self.state.clone(),
output,
};
let future = self.state.eng.spawn(oh.handle());
self.state.output_handlers.borrow_mut().insert(id, future);
}
async fn handle_new_seat(&mut self, seat: Rc<dyn Seat>) {
let id = seat.id();
let oh = SeatHandler {
state: self.state.clone(),
seat,
};
let future = self.state.eng.spawn(oh.handle());
self.state.seat_handlers.borrow_mut().insert(id, future);
}
}
struct OutputHandler {
state: Rc<State>,
output: Rc<dyn Output>,
}
impl OutputHandler {
async fn handle(self) {
let ae = Rc::new(AsyncEvent::default());
{
let ae = ae.clone();
self.output.on_change(Rc::new(move || ae.trigger()));
}
let on = Rc::new(OutputNode {
common: NodeCommon {
extents: Cell::new(NodeExtents {
x: 0,
y: 0,
width: self.output.width(),
height: self.output.height(),
}),
id: self.state.node_ids.next(),
parent: Some(self.state.root.clone()),
floating_outputs: RefCell::new(Default::default()),
},
backend: self.output.clone(),
child: RefCell::new(None),
floating: Default::default(),
});
self.state.root.outputs.set(self.output.id(), on.clone());
let name = self.state.globals.name();
let global = Rc::new(WlOutputGlobal::new(name, &self.output));
self.state.globals.insert(&self.state, global.clone()).await;
loop {
if self.output.removed() {
break;
}
on.common.extents.set(NodeExtents {
x: 0,
y: 0,
width: self.output.width(),
height: self.output.height(),
});
global.update_properties().await;
ae.triggered().await;
}
self.state.globals.remove(&self.state, name).await;
self.state
.output_handlers
.borrow_mut()
.remove(&self.output.id());
}
}
struct SeatHandler {
state: Rc<State>,
seat: Rc<dyn Seat>,
}
impl SeatHandler {
async fn handle(self) {
let ae = Rc::new(AsyncEvent::default());
{
let ae = ae.clone();
self.seat.on_change(Rc::new(move || ae.trigger()));
}
let name = self.state.globals.name();
let global = Rc::new(WlSeatGlobal::new(name, &self.seat));
self.state.globals.insert(&self.state, global.clone()).await;
loop {
if self.seat.removed() {
break;
}
while let Some(event) = self.seat.event() {
global.event(event).await;
}
ae.triggered().await;
}
self.state.globals.remove(&self.state, name).await;
self.state
.seat_handlers
.borrow_mut()
.remove(&self.seat.id());
}
}

171
src/tree.rs Normal file
View file

@ -0,0 +1,171 @@
use crate::backend::{Output, OutputId};
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel;
use crate::utils::copyhashmap::CopyHashMap;
use crate::utils::linkedlist::{LinkedList, Node as LinkedNode};
use ahash::AHashMap;
use std::cell::{Cell, RefCell};
use std::mem;
use std::rc::Rc;
linear_ids!(NodeIds, NodeId);
pub trait NodeBase {
fn id(&self) -> NodeId;
fn parent(&self) -> Option<Rc<dyn Node>>;
fn extents(&self) -> NodeExtents;
}
macro_rules! base {
($name:ident) => {
impl NodeBase for $name {
fn id(&self) -> NodeId {
self.common.id
}
fn parent(&self) -> Option<Rc<dyn Node>> {
self.common.parent.clone()
}
fn extents(&self) -> NodeExtents {
self.common.extents.get()
}
}
};
}
pub trait Node: NodeBase {
fn into_kind(self: Rc<Self>) -> NodeKind;
fn clear(&self);
}
pub enum NodeKind {
Display(Rc<DisplayNode>),
Output(Rc<OutputNode>),
Toplevel(Rc<ToplevelNode>),
Container(Rc<ContainerNode>),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
pub struct NodeExtents {
pub x: i32,
pub y: i32,
pub width: u32,
pub height: u32,
}
pub struct NodeCommon {
pub extents: Cell<NodeExtents>,
pub id: NodeId,
pub parent: Option<Rc<dyn Node>>,
pub floating_outputs: RefCell<AHashMap<NodeId, LinkedNode<Rc<dyn Node>>>>,
}
impl NodeCommon {
fn clear(&self) {
mem::take(&mut *self.floating_outputs.borrow_mut());
}
}
pub struct DisplayNode {
pub common: NodeCommon,
pub outputs: CopyHashMap<OutputId, Rc<OutputNode>>,
}
impl DisplayNode {
pub fn new(id: NodeId) -> Self {
Self {
common: NodeCommon {
extents: Default::default(),
id,
parent: None,
floating_outputs: Default::default(),
},
outputs: Default::default(),
}
}
}
base!(DisplayNode);
impl Node for DisplayNode {
fn into_kind(self: Rc<Self>) -> NodeKind {
NodeKind::Display(self)
}
fn clear(&self) {
self.common.clear();
let mut outputs = self.outputs.lock();
for output in outputs.values() {
output.clear();
}
outputs.clear();
}
}
pub struct OutputNode {
pub common: NodeCommon,
pub backend: Rc<dyn Output>,
pub child: RefCell<Option<Rc<dyn Node>>>,
pub floating: LinkedList<Rc<dyn Node>>,
}
base!(OutputNode);
impl Node for OutputNode {
fn into_kind(self: Rc<Self>) -> NodeKind {
NodeKind::Output(self)
}
fn clear(&self) {
self.common.clear();
for floating in self.floating.iter() {
floating.clear();
}
if let Some(child) = self.child.borrow_mut().take() {
child.clear();
}
}
}
pub struct ToplevelNode {
pub common: NodeCommon,
pub surface: Rc<XdgToplevel>,
}
base!(ToplevelNode);
impl Node for ToplevelNode {
fn into_kind(self: Rc<Self>) -> NodeKind {
NodeKind::Toplevel(self)
}
fn clear(&self) {
self.common.clear();
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ContainerSplit {
Horizontal,
Vertical,
}
pub struct ContainerNode {
pub common: NodeCommon,
pub split: Cell<ContainerSplit>,
pub children: LinkedList<Rc<dyn Node>>,
}
base!(ContainerNode);
impl Node for ContainerNode {
fn into_kind(self: Rc<Self>) -> NodeKind {
NodeKind::Container(self)
}
fn clear(&self) {
for child in self.children.iter() {
child.clear();
}
}
}

41
src/utils/asyncevent.rs Normal file
View file

@ -0,0 +1,41 @@
use crate::NumCell;
use std::cell::Cell;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll, Waker};
#[derive(Default)]
pub struct AsyncEvent {
triggers: NumCell<u32>,
waker: Cell<Option<Waker>>,
}
impl AsyncEvent {
pub fn trigger(&self) {
self.triggers.fetch_add(1);
if let Some(waker) = self.waker.take() {
waker.wake();
}
}
pub fn triggered(&self) -> AsyncEventTriggered {
AsyncEventTriggered { ae: self }
}
}
pub struct AsyncEventTriggered<'a> {
ae: &'a AsyncEvent,
}
impl<'a> Future for AsyncEventTriggered<'a> {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.ae.triggers.replace(0) == 0 {
self.ae.waker.set(Some(cx.waker().clone()));
Poll::Pending
} else {
Poll::Ready(())
}
}
}

View file

@ -3,6 +3,7 @@ use crate::utils::buffd::buf_out::{BufFdOut, MsgFds};
use std::mem;
use std::mem::MaybeUninit;
use uapi::OwnedFd;
use crate::fixed::Fixed;
pub struct MsgFormatter<'a> {
buf: &'a mut BufFdOut,
@ -29,17 +30,17 @@ impl<'a> MsgFormatter<'a> {
self
}
pub fn fixed(&mut self, fixed: f64) -> &mut Self {
let int = (fixed * 256.0) as i32;
self.buf.write(uapi::as_maybe_uninit_bytes(&int));
pub fn fixed(&mut self, fixed: Fixed) -> &mut Self {
self.buf.write(uapi::as_maybe_uninit_bytes(&fixed));
self
}
pub fn string(&mut self, s: &str) -> &mut Self {
pub fn string<S: AsRef<[u8]> + ?Sized>(&mut self, s: &S) -> &mut Self {
let s = s.as_ref();
let len = s.len() + 1;
let cap = (len + 3) & !3;
self.uint(len as u32);
self.buf.write(uapi::as_maybe_uninit_bytes(s.as_bytes()));
self.buf.write(uapi::as_maybe_uninit_bytes(s));
let none = [MaybeUninit::new(0); 4];
self.buf.write(&none[..cap - len + 1]);
self

View file

@ -1,15 +1,15 @@
use crate::globals::GlobalName;
use crate::object::ObjectId;
use crate::utils::buffd::BufFdIn;
use bstr::{BStr, ByteSlice};
use thiserror::Error;
use uapi::OwnedFd;
use crate::fixed::Fixed;
#[derive(Debug, Error)]
pub enum MsgParserError {
#[error("The message ended unexpectedly")]
UnexpectedEof,
#[error("The message contained a non-utf8 string")]
NonUtf8,
#[error("The message contained a string of size 0")]
EmptyString,
#[error("Message is missing a required file descriptor")]
@ -57,11 +57,11 @@ impl<'a, 'b> MsgParser<'a, 'b> {
self.int().map(|i| GlobalName::from_raw(i as u32))
}
pub fn fixed(&mut self) -> Result<f64, MsgParserError> {
self.int().map(|i| i as f64 / 256.0)
pub fn fixed(&mut self) -> Result<Fixed, MsgParserError> {
self.int().map(|i| Fixed(i))
}
pub fn string(&mut self) -> Result<&'b str, MsgParserError> {
pub fn string(&mut self) -> Result<&'b BStr, MsgParserError> {
let len = self.uint()? as usize;
if len == 0 {
return Err(MsgParserError::EmptyString);
@ -71,10 +71,7 @@ impl<'a, 'b> MsgParser<'a, 'b> {
return Err(MsgParserError::UnexpectedEof);
}
let s = &self.data[self.pos..self.pos + len - 1];
let s = match std::str::from_utf8(s) {
Ok(s) => s,
_ => return Err(MsgParserError::NonUtf8),
};
let s = s.as_bstr();
self.pos += cap;
Ok(s)
}

View file

@ -1,3 +1,4 @@
pub mod asyncevent;
pub mod buffd;
pub mod copyhashmap;
pub mod linkedlist;

View file

@ -11,6 +11,10 @@ impl<T> NumCell<T> {
Self { t: Cell::new(t) }
}
pub fn replace(&self, n: T) -> T {
self.t.replace(n)
}
pub fn load(&self) -> T
where
T: Copy,

View file

@ -1,24 +1,24 @@
pub trait PtrExt<T> {
pub trait PtrExt<T: ?Sized> {
unsafe fn deref<'a>(self) -> &'a T;
}
pub trait MutPtrExt<T> {
pub trait MutPtrExt<T: ?Sized> {
unsafe fn deref_mut<'a>(self) -> &'a mut T;
}
impl<T> PtrExt<T> for *const T {
impl<T: ?Sized> PtrExt<T> for *const T {
unsafe fn deref<'a>(self) -> &'a T {
&*self
}
}
impl<T> PtrExt<T> for *mut T {
impl<T: ?Sized> PtrExt<T> for *mut T {
unsafe fn deref<'a>(self) -> &'a T {
&*self
}
}
impl<T> MutPtrExt<T> for *mut T {
impl<T: ?Sized> MutPtrExt<T> for *mut T {
unsafe fn deref_mut<'a>(self) -> &'a mut T {
&mut *self
}

View file

@ -1,6 +1,7 @@
use std::cell::RefCell;
use std::collections::VecDeque;
use std::future::Future;
use std::mem;
use std::pin::Pin;
use std::task::{Context, Poll, Waker};
@ -35,6 +36,10 @@ impl<T> AsyncQueue<T> {
pub fn size(&self) -> usize {
self.data.borrow().len()
}
pub fn clear(&self) {
mem::take(&mut *self.data.borrow_mut());
}
}
pub struct AsyncQueuePop<'a, T> {

View file

@ -1,10 +1,11 @@
use crate::event_loop::{EventLoop, EventLoopDispatcher, EventLoopError};
use crate::event_loop::{EventLoop, EventLoopDispatcher, EventLoopError, EventLoopId};
use crate::time::{Time, TimeError};
use crate::utils::copyhashmap::CopyHashMap;
use crate::utils::numcell::NumCell;
use std::cell::{Cell, RefCell};
use std::cmp::Reverse;
use std::collections::BinaryHeap;
use std::error::Error;
use std::rc::Rc;
use std::time::Duration;
use thiserror::Error;
@ -33,10 +34,10 @@ pub trait WheelDispatcher {
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
struct WheelEntry {
expiration: Time,
id: u64,
id: WheelId,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct WheelId(u64);
pub struct Wheel {
@ -45,8 +46,11 @@ pub struct Wheel {
next_id: NumCell<u64>,
start: Time,
current_expiration: Cell<Option<Time>>,
dispatchers: CopyHashMap<u64, Rc<dyn WheelDispatcher>>,
dispatchers: CopyHashMap<WheelId, Rc<dyn WheelDispatcher>>,
periodic_dispatchers: CopyHashMap<WheelId, Rc<PeriodicDispatcher>>,
expirations: RefCell<BinaryHeap<Reverse<WheelEntry>>>,
id: EventLoopId,
el: Rc<EventLoop>,
}
impl Wheel {
@ -63,7 +67,10 @@ impl Wheel {
start: Time::now()?,
current_expiration: Cell::new(None),
dispatchers: CopyHashMap::new(),
periodic_dispatchers: Default::default(),
expirations: RefCell::new(Default::default()),
id,
el: el.clone(),
});
let wrapper = Rc::new(WheelWrapper {
wheel: wheel.clone(),
@ -106,17 +113,56 @@ impl Wheel {
}
self.current_expiration.set(Some(expiration));
}
self.expirations.borrow_mut().push(Reverse(WheelEntry {
expiration,
id: id.0,
}));
self.dispatchers.set(id.0, dispatcher);
self.expirations
.borrow_mut()
.push(Reverse(WheelEntry { expiration, id }));
self.dispatchers.set(id, dispatcher);
Ok(())
}
pub fn periodic(
&self,
id: WheelId,
us: u64,
dispatcher: Rc<dyn WheelDispatcher>,
) -> Result<(), WheelError> {
self.check_destroyed()?;
let fd = match uapi::timerfd_create(c::CLOCK_MONOTONIC, c::TFD_CLOEXEC | c::TFD_NONBLOCK) {
Ok(fd) => fd,
Err(e) => return Err(WheelError::CreateFailed(e.into())),
};
let tv_sec = (us / 1_000_000) as _;
let tv_nsec = (us % 1_000_000 * 1_000) as _;
let res = uapi::timerfd_settime(
fd.raw(),
0,
&c::itimerspec {
it_interval: c::timespec { tv_sec, tv_nsec },
it_value: c::timespec { tv_sec, tv_nsec },
},
);
if let Err(e) = res {
return Err(WheelError::SetFailed(e.into()));
}
let el_id = self.el.id();
let pd = Rc::new(PeriodicDispatcher {
fd: fd,
id: el_id,
el: self.el.clone(),
dispatcher,
});
self.el
.insert(el_id, Some(pd.fd.raw()), c::EPOLLIN, pd.clone())?;
self.periodic_dispatchers.set(id, pd);
Ok(())
}
pub fn remove(&self, id: WheelId) {
// log::trace!("removing {:?} from wheel", id);
self.dispatchers.remove(&id.0);
self.dispatchers.remove(&id);
if let Some(d) = self.periodic_dispatchers.remove(&id) {
let _ = self.el.remove(d.id);
}
}
}
@ -125,7 +171,10 @@ struct WheelWrapper {
}
impl EventLoopDispatcher for WheelWrapper {
fn dispatch(&self, events: i32) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
fn dispatch(
self: Rc<Self>,
events: i32,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
if events & (c::EPOLLERR | c::EPOLLHUP) != 0 {
return Err(Box::new(WheelError::ErrorEvent));
}
@ -179,5 +228,30 @@ impl Drop for WheelWrapper {
fn drop(&mut self) {
self.wheel.destroyed.set(true);
self.wheel.dispatchers.clear();
let _ = self.wheel.el.remove(self.wheel.id);
}
}
struct PeriodicDispatcher {
fd: OwnedFd,
id: EventLoopId,
el: Rc<EventLoop>,
dispatcher: Rc<dyn WheelDispatcher>,
}
impl EventLoopDispatcher for PeriodicDispatcher {
fn dispatch(self: Rc<Self>, events: i32) -> Result<(), Box<dyn Error + Send + Sync>> {
if events & (c::EPOLLERR | c::EPOLLHUP) != 0 {
return Err(Box::new(WheelError::ErrorEvent));
}
let mut n = 0u64;
while uapi::read(self.fd.raw(), &mut n).is_ok() {}
self.dispatcher.clone().dispatch()
}
}
impl Drop for PeriodicDispatcher {
fn drop(&mut self) {
let _ = self.el.remove(self.id);
}
}

43
src/xkbcommon/consts.rs Normal file
View file

@ -0,0 +1,43 @@
#![allow(dead_code)]
cenum! {
XkbX11SetupXkbExtensionFlags, XKB_X11_SETUP_XKB_EXTENSION_FLAGS;
XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS = 0,
}
bitor!(XkbX11SetupXkbExtensionFlags);
cenum! {
XkbLogLevel, XKB_LOG_LEVEL;
XKB_LOG_LEVEL_CRITICAL = 10,
XKB_LOG_LEVEL_ERROR = 20,
XKB_LOG_LEVEL_WARNING = 30,
XKB_LOG_LEVEL_INFO = 40,
XKB_LOG_LEVEL_DEBUG = 50,
}
cenum! {
XkbContextFlags, XKB_CONTEXT_FLAGS;
XKB_CONTEXT_NO_FLAGS = 0,
XKB_CONTEXT_NO_DEFAULT_INCLUDES = 1 << 0,
XKB_CONTEXT_NO_ENVIRONMENT_NAMES = 1 << 1,
}
bitor!(XkbContextFlags);
cenum! {
XkbKeymapCompileFlags, XKB_KEYMAP_COMPILE_FLAGS;
XKB_KEYMAP_COMPILE_NO_FLAGS = 0,
}
bitor!(XkbKeymapCompileFlags);
cenum! {
XkbKeymapFormat, XKB_KEYMAP_FORMAT;
XKB_KEYMAP_FORMAT_TEXT_V1 = 1,
}

249
src/xkbcommon/mod.rs Normal file
View file

@ -0,0 +1,249 @@
#![allow(non_camel_case_types)]
mod consts;
include!(concat!(env!("OUT_DIR"), "/xkbcommon_tys.rs"));
use bstr::{BStr, ByteSlice};
pub use consts::*;
use std::ffi::{CStr, VaList};
use std::ops::Deref;
use std::ptr;
use crate::utils::ptr_ext::PtrExt;
use libloading::Library;
use thiserror::Error;
use uapi::c;
use xcb_dl::ffi::xcb_connection_t;
#[derive(Debug, Error)]
pub enum XkbCommonError {
#[error("xkbcommon-x11 could not be loaded")]
LoadXkbCommonX11(#[source] libloading::Error),
#[error("One of the xkbcommon-x11 symbols could not be loaded")]
LoadXkbCommonX11Sym(#[source] libloading::Error),
#[error("Could not create keymap from X11 device")]
CreateKeymapFromDevice,
#[error("Could not create state from X11 device")]
CreateStateFromDevice,
#[error("Could not create an xkbcommon context")]
CreateContext,
#[error("Could not convert the keymap to a string")]
AsStr,
}
struct xkb_context;
struct xkb_keymap;
struct xkb_state;
#[link(name = "xkbcommon")]
extern "C" {
fn xkb_context_new(flags: xkb_context_flags) -> *mut xkb_context;
fn xkb_context_unref(context: *mut xkb_context);
fn xkb_context_set_log_fn(
context: *mut xkb_context,
log_fn: unsafe extern "C" fn(
context: *mut xkb_context,
level: xkb_log_level,
format: *const c::c_char,
args: VaList,
),
);
fn xkb_keymap_get_as_string(
keymap: *mut xkb_keymap,
format: xkb_keymap_format,
) -> *mut c::c_char;
fn xkb_keymap_unref(keymap: *mut xkb_keymap);
fn xkb_state_unref(state: *mut xkb_state);
}
pub struct XkbContext {
context: *mut xkb_context,
}
impl XkbContext {
pub fn new() -> Result<Self, XkbCommonError> {
let res = unsafe { xkb_context_new(XKB_CONTEXT_NO_FLAGS.raw() as _) };
if res.is_null() {
return Err(XkbCommonError::CreateContext);
}
unsafe {
xkb_context_set_log_fn(res, xkbcommon_logger);
}
Ok(Self { context: res })
}
}
impl Drop for XkbContext {
fn drop(&mut self) {
unsafe {
xkb_context_unref(self.context);
}
}
}
pub struct XkbKeymap {
keymap: *mut xkb_keymap,
}
impl XkbKeymap {
pub fn as_str(&self) -> Result<XkbKeymapStr, XkbCommonError> {
let res =
unsafe { xkb_keymap_get_as_string(self.keymap, XKB_KEYMAP_FORMAT_TEXT_V1.raw() as _) };
if res.is_null() {
return Err(XkbCommonError::AsStr);
}
Ok(XkbKeymapStr {
s: unsafe { CStr::from_ptr(res).to_bytes().as_bstr() },
})
}
}
impl Drop for XkbKeymap {
fn drop(&mut self) {
unsafe {
xkb_keymap_unref(self.keymap);
}
}
}
pub struct XkbKeymapStr {
s: *const BStr,
}
impl Deref for XkbKeymapStr {
type Target = BStr;
fn deref(&self) -> &Self::Target {
unsafe { self.s.deref() }
}
}
impl Drop for XkbKeymapStr {
fn drop(&mut self) {
unsafe { c::free(self.s as _) }
}
}
pub struct XkbState {
state: *mut xkb_state,
}
impl Drop for XkbState {
fn drop(&mut self) {
unsafe {
xkb_state_unref(self.state);
}
}
}
pub struct XkbCommonX11 {
library: Library,
fns: XkbCommonX11Fns,
}
struct XkbCommonX11Fns {
xkb_x11_keymap_new_from_device: unsafe fn(
context: *mut xkb_context,
c: *mut xcb_connection_t,
device_id: i32,
flags: xkb_x11_setup_xkb_extension_flags,
) -> *mut xkb_keymap,
xkb_x11_state_new_from_device: unsafe fn(
keymap: *mut xkb_keymap,
c: *mut xcb_connection_t,
device_id: i32,
) -> *mut xkb_state,
}
impl XkbCommonX11 {
pub fn load() -> Result<Self, XkbCommonError> {
let library = unsafe {
match Library::new("libxkbcommon-x11.so") {
Ok(l) => l,
Err(e) => return Err(XkbCommonError::LoadXkbCommonX11(e)),
}
};
let fns = match get_xkbcommon_x11_fns(&library) {
Ok(f) => f,
Err(e) => return Err(XkbCommonError::LoadXkbCommonX11Sym(e)),
};
Ok(Self { library, fns })
}
pub unsafe fn keymap_from_device(
&self,
context: &XkbContext,
c: *mut xcb_connection_t,
device_id: i32,
flags: XkbX11SetupXkbExtensionFlags,
) -> Result<XkbKeymap, XkbCommonError> {
let res = (self.fns.xkb_x11_keymap_new_from_device)(
context.context,
c,
device_id,
flags.raw() as _,
);
if res.is_null() {
return Err(XkbCommonError::CreateKeymapFromDevice);
}
Ok(XkbKeymap { keymap: res })
}
pub unsafe fn state_from_device(
&self,
keymap: &XkbKeymap,
c: *mut xcb_connection_t,
device_id: i32,
) -> Result<XkbState, XkbCommonError> {
let res = (self.fns.xkb_x11_state_new_from_device)(keymap.keymap, c, device_id);
if res.is_null() {
return Err(XkbCommonError::CreateStateFromDevice);
}
Ok(XkbState { state: res })
}
}
fn get_xkbcommon_x11_fns(lib: &Library) -> Result<XkbCommonX11Fns, libloading::Error> {
macro_rules! syms {
($($sym:ident,)*) => {
Ok(XkbCommonX11Fns {
$(
$sym: std::mem::transmute(lib.get::<usize>(concat!(stringify!($sym), "\0").as_bytes())?.into_raw().into_raw()),
)*
})
}
}
unsafe {
syms! {
xkb_x11_keymap_new_from_device,
xkb_x11_state_new_from_device,
}
}
}
unsafe extern "C" fn xkbcommon_logger(
_ctx: *mut xkb_context,
level: xkb_log_level,
format: *const c::c_char,
args: VaList,
) {
extern "C" {
fn vasprintf(buf: *mut *mut c::c_char, fmt: *const c::c_char, args: VaList) -> c::c_int;
}
let mut buf = ptr::null_mut();
let res = vasprintf(&mut buf, format, args);
if res < 0 {
log::warn!("Could not vasprintf");
}
let buf = std::slice::from_raw_parts(buf as *const u8, res as usize);
let buf = buf.as_bstr();
let level = match XkbLogLevel(level) {
XKB_LOG_LEVEL_CRITICAL | XKB_LOG_LEVEL_ERROR => log::Level::Error,
XKB_LOG_LEVEL_WARNING => log::Level::Warn,
XKB_LOG_LEVEL_INFO => log::Level::Info,
XKB_LOG_LEVEL_DEBUG => log::Level::Debug,
_ => log::Level::Error,
};
log::log!(level, "xkbcommon: {}", buf);
}