autocommit 2022-01-06 19:08:32 CET
This commit is contained in:
parent
cbbc41a463
commit
4a939477a2
51 changed files with 3438 additions and 207 deletions
79
Cargo.lock
generated
79
Cargo.lock
generated
|
|
@ -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",
|
||||
]
|
||||
|
|
|
|||
11
Cargo.toml
11
Cargo.toml
|
|
@ -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
82
build.rs
Normal 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
19
c/bridge.c
Normal 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);
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
30
src/backend.rs
Normal 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
1
src/backends/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
pub mod xorg;
|
||||
787
src/backends/xorg/mod.rs
Normal file
787
src/backends/xorg/mod.rs
Normal 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
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
35
src/fixed.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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', ' ', ' '),
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
136
src/ifs/wl_output/types.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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
35
src/ifs/wl_seat/types.rs
Normal 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()")
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ impl WlSubsurface {
|
|||
}
|
||||
}
|
||||
self.surface.client.remove_obj(self).await?;
|
||||
self.parent.calculate_extents();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ id!(XdgToplevelId);
|
|||
|
||||
pub struct XdgToplevel {
|
||||
id: XdgToplevelId,
|
||||
surface: Rc<XdgSurface>,
|
||||
pub surface: Rc<XdgSurface>,
|
||||
version: u32,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
32
src/main.rs
32
src/main.rs
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
192
src/pixman/consts.rs
Normal 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
291
src/pixman/mod.rs
Normal 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
93
src/servermem.rs
Normal 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))
|
||||
}
|
||||
}
|
||||
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
|||
15
src/state.rs
15
src/state.rs
|
|
@ -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
138
src/tasks.rs
Normal 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
171
src/tree.rs
Normal 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
41
src/utils/asyncevent.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
pub mod asyncevent;
|
||||
pub mod buffd;
|
||||
pub mod copyhashmap;
|
||||
pub mod linkedlist;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
96
src/wheel.rs
96
src/wheel.rs
|
|
@ -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
43
src/xkbcommon/consts.rs
Normal 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
249
src/xkbcommon/mod.rs
Normal 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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue