1
0
Fork 0
forked from wry/wry

autocommit 2022-03-23 14:35:09 CET

This commit is contained in:
Julian Orth 2022-03-23 14:35:09 +01:00
parent 6597a57ad5
commit 63be47a9fb
24 changed files with 703 additions and 722 deletions

View file

@ -1,2 +1,2 @@
pub mod metal;
pub mod xorgng;
pub mod x;

View file

@ -41,7 +41,7 @@ use std::rc::Rc;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum XorgngBackendError {
pub enum XBackendError {
#[error("Could not connect to the X server")]
CannotConnect(#[source] XconError),
#[error("Could not enable XInput")]
@ -90,38 +90,38 @@ pub enum XorgngBackendError {
QueryDevice(#[source] XconError),
}
pub struct XorgngBackend {
_data: Rc<XorgngBackendData>,
pub struct XBackend {
_data: Rc<XBackendData>,
_events: SpawnedFuture<()>,
_present: SpawnedFuture<()>,
_grab: SpawnedFuture<()>,
}
impl Backend for XorgngBackend {
impl Backend for XBackend {
fn switch_to(&self, _vtnr: u32) {
log::error!("Xorg backend cannot switch vts");
log::error!("X backend cannot switch vts");
}
}
pub struct XorgngBackendData {
struct XBackendData {
state: Rc<State>,
c: Rc<Xcon>,
outputs: CopyHashMap<u32, Rc<XorgOutput>>,
seats: CopyHashMap<u16, Rc<XorgSeat>>,
mouse_seats: CopyHashMap<u16, Rc<XorgSeat>>,
outputs: CopyHashMap<u32, Rc<XOutput>>,
seats: CopyHashMap<u16, Rc<XSeat>>,
mouse_seats: CopyHashMap<u16, Rc<XSeat>>,
ctx: Rc<RenderContext>,
gbm: GbmDevice,
cursor: u32,
root: u32,
scheduled_present: AsyncQueue<Rc<XorgOutput>>,
grab_requests: AsyncQueue<(Rc<XorgSeat>, bool)>,
scheduled_present: AsyncQueue<Rc<XOutput>>,
grab_requests: AsyncQueue<(Rc<XSeat>, bool)>,
}
impl XorgngBackend {
pub async fn run(state: &Rc<State>) -> Result<Rc<Self>, XorgngBackendError> {
impl XBackend {
pub async fn run(state: &Rc<State>) -> Result<Rc<Self>, XBackendError> {
let c = match Xcon::connect(state.eng.clone()).await {
Ok(c) => c,
Err(e) => return Err(XorgngBackendError::CannotConnect(e)),
Err(e) => return Err(XBackendError::CannotConnect(e)),
};
if let Err(e) = c
.call(&XiQueryVersion {
@ -130,7 +130,7 @@ impl XorgngBackend {
})
.await
{
return Err(XorgngBackendError::EnableXinput(e));
return Err(XBackendError::EnableXinput(e));
}
if let Err(e) = c
.call(&Dri3QueryVersion {
@ -139,7 +139,7 @@ impl XorgngBackend {
})
.await
{
return Err(XorgngBackendError::EnableDri3(e));
return Err(XBackendError::EnableDri3(e));
}
if let Err(e) = c
.call(&PresentQueryVersion {
@ -148,7 +148,7 @@ impl XorgngBackend {
})
.await
{
return Err(XorgngBackendError::EnablePresent(e));
return Err(XBackendError::EnablePresent(e));
}
if let Err(e) = c
.call(&XkbUseExtension {
@ -157,7 +157,7 @@ impl XorgngBackend {
})
.await
{
return Err(XorgngBackendError::EnableXkb(e));
return Err(XBackendError::EnableXkb(e));
}
let root = c.setup().screens[0].root;
let drm = {
@ -169,13 +169,13 @@ impl XorgngBackend {
.await;
match res {
Ok(r) => Drm::reopen(r.get().device_fd.raw(), false)?,
Err(e) => return Err(XorgngBackendError::DriOpen(e)),
Err(e) => return Err(XBackendError::DriOpen(e)),
}
};
let gbm = GbmDevice::new(&drm)?;
let ctx = match RenderContext::from_drm_device(&drm) {
Ok(r) => Rc::new(r),
Err(e) => return Err(XorgngBackendError::CreateEgl(e)),
Err(e) => return Err(XBackendError::CreateEgl(e)),
};
let cursor = {
let cp = CreatePixmap {
@ -186,7 +186,7 @@ impl XorgngBackend {
height: 1,
};
if let Err(e) = c.call(&cp).await {
return Err(XorgngBackendError::CreatePixmap(e));
return Err(XBackendError::CreatePixmap(e));
}
let cc = CreateCursor {
cid: c.generate_id()?,
@ -202,7 +202,7 @@ impl XorgngBackend {
y: 0,
};
if let Err(e) = c.call(&cc).await {
return Err(XorgngBackendError::CreateCursor(e));
return Err(XBackendError::CreateCursor(e));
}
c.call(&FreePixmap { pixmap: cp.pid });
cc.cid
@ -216,11 +216,11 @@ impl XorgngBackend {
}]),
};
if let Err(e) = c.call(&se).await {
return Err(XorgngBackendError::SelectHierarchyEvents(e));
return Err(XBackendError::SelectHierarchyEvents(e));
}
}
let data = Rc::new(XorgngBackendData {
let data = Rc::new(XBackendData {
state: state.clone(),
c,
outputs: Default::default(),
@ -252,7 +252,7 @@ impl XorgngBackend {
}
}
impl XorgngBackendData {
impl XBackendData {
async fn event_handler(self: Rc<Self>) {
loop {
let event = self.c.event().await;
@ -281,7 +281,7 @@ impl XorgngBackendData {
}
}
async fn handle_grab_request(&self, dev: &XorgSeat, grab: bool) {
async fn handle_grab_request(&self, dev: &XSeat, grab: bool) {
if grab {
let xg = XiGrabDevice {
window: self.root,
@ -320,7 +320,7 @@ impl XorgngBackendData {
window: u32,
width: i32,
height: i32,
) -> Result<[XorgImage; 2], XorgngBackendError> {
) -> Result<[XImage; 2], XBackendError> {
let format = ModifiedFormat {
format: XRGB8888,
modifier: INVALID_MODIFIER,
@ -336,7 +336,7 @@ impl XorgngBackendData {
let size = plane.stride * dma.height as u32;
let fb = match self.ctx.dmabuf_fb(dma) {
Ok(f) => f,
Err(e) => return Err(XorgngBackendError::CreateFramebuffer(e)),
Err(e) => return Err(XBackendError::CreateFramebuffer(e)),
};
let pixmap = {
let pfb = Dri3PixmapFromBuffer {
@ -351,11 +351,11 @@ impl XorgngBackendData {
pixmap_fd: plane.fd.clone(),
};
if let Err(e) = self.c.call(&pfb).await {
return Err(XorgngBackendError::ImportBuffer(e));
return Err(XBackendError::ImportBuffer(e));
}
pfb.pixmap
};
images[i] = Some(XorgImage {
images[i] = Some(XImage {
pixmap: Cell::new(pixmap),
fb: CloneCell::new(fb),
idle: Cell::new(true),
@ -366,7 +366,7 @@ impl XorgngBackendData {
Ok([images[0].take().unwrap(), images[1].take().unwrap()])
}
async fn add_output(self: &Rc<Self>) -> Result<(), XorgngBackendError> {
async fn add_output(self: &Rc<Self>) -> Result<(), XBackendError> {
const WIDTH: i32 = 800;
const HEIGHT: i32 = 600;
let window_id = {
@ -384,12 +384,12 @@ impl XorgngBackendData {
values: Default::default(),
};
if let Err(e) = self.c.call(&cw).await {
return Err(XorgngBackendError::CreateWindow(e));
return Err(XBackendError::CreateWindow(e));
}
cw.wid
};
let images = self.create_images(window_id, WIDTH, HEIGHT).await?;
let output = Rc::new(XorgOutput {
let output = Rc::new(XOutput {
id: self.state.output_ids.next(),
_backend: self.clone(),
window: window_id,
@ -413,7 +413,7 @@ impl XorgngBackendData {
data: class.as_bytes(),
};
if let Err(e) = self.c.call(&cp).await {
return Err(XorgngBackendError::WmClass(e));
return Err(XBackendError::WmClass(e));
};
}
{
@ -430,11 +430,11 @@ impl XorgngBackendData {
},
};
if let Err(e) = self.c.call(&cwa).await {
return Err(XorgngBackendError::WindowEvents(e));
return Err(XBackendError::WindowEvents(e));
}
}
if let Err(e) = self.c.call(&MapWindow { window: window_id }).await {
return Err(XorgngBackendError::MapWindow(e));
return Err(XBackendError::MapWindow(e));
}
{
let mask = 0
@ -459,7 +459,7 @@ impl XorgngBackendData {
masks: Cow::Borrowed(&mask[..]),
};
if let Err(e) = self.c.call(&xs).await {
return Err(XorgngBackendError::CannotSelectInputEvents(e));
return Err(XBackendError::CannotSelectInputEvents(e));
}
}
{
@ -470,7 +470,7 @@ impl XorgngBackendData {
event_mask: mask,
};
if let Err(e) = self.c.call(&si).await {
return Err(XorgngBackendError::CannotSelectPresentEvents(e));
return Err(XBackendError::CannotSelectPresentEvents(e));
}
}
self.outputs.set(window_id, output.clone());
@ -481,10 +481,10 @@ impl XorgngBackendData {
Ok(())
}
async fn query_devices(self: &Rc<Self>, deviceid: u16) -> Result<(), XorgngBackendError> {
async fn query_devices(self: &Rc<Self>, deviceid: u16) -> Result<(), XBackendError> {
let reply = match self.c.call(&XiQueryDevice { deviceid }).await {
Ok(r) => r,
Err(e) => return Err(XorgngBackendError::QueryDevice(e)),
Err(e) => return Err(XBackendError::QueryDevice(e)),
};
for dev in reply.get().infos.iter() {
self.handle_input_device(dev).await;
@ -517,7 +517,7 @@ impl XorgngBackendData {
ErrorFmt(e),
);
}
let seat = Rc::new(XorgSeat {
let seat = Rc::new(XSeat {
kb_id: self.state.input_device_ids.next(),
mouse_id: self.state.input_device_ids.next(),
backend: self.clone(),
@ -535,17 +535,17 @@ impl XorgngBackendData {
self.mouse_seats.set(info.attachment, seat.clone());
self.state
.backend_events
.push(BackendEvent::NewInputDevice(Rc::new(XorgSeatMouse(
.push(BackendEvent::NewInputDevice(Rc::new(XSeatMouse(
seat.clone(),
))));
self.state
.backend_events
.push(BackendEvent::NewInputDevice(Rc::new(XorgSeatKeyboard(
.push(BackendEvent::NewInputDevice(Rc::new(XSeatKeyboard(
seat.clone(),
))));
}
async fn handle_event(self: &Rc<Self>, event: &Event) -> Result<(), XorgngBackendError> {
async fn handle_event(self: &Rc<Self>, event: &Event) -> Result<(), XBackendError> {
match event.ext() {
Some(ext) => self.handle_ext_event(ext, event).await,
_ => self.handle_core_event(event).await,
@ -556,7 +556,7 @@ impl XorgngBackendData {
self: &Rc<Self>,
ext: Extension,
event: &Event,
) -> Result<(), XorgngBackendError> {
) -> Result<(), XBackendError> {
match ext {
Extension::Present => self.handle_present_event(event),
Extension::XInputExtension => self.handle_input_event(event).await,
@ -564,7 +564,7 @@ impl XorgngBackendData {
}
}
async fn handle_core_event(self: &Rc<Self>, event: &Event) -> Result<(), XorgngBackendError> {
async fn handle_core_event(self: &Rc<Self>, event: &Event) -> Result<(), XBackendError> {
match event.code() {
ConfigureNotify::OPCODE => self.handle_configure(event).await,
DestroyNotify::OPCODE => self.handle_destroy(event),
@ -572,7 +572,7 @@ impl XorgngBackendData {
}
}
fn handle_present_event(self: &Rc<Self>, event: &Event) -> Result<(), XorgngBackendError> {
fn handle_present_event(self: &Rc<Self>, event: &Event) -> Result<(), XBackendError> {
match event.code() {
PresentCompleteNotify::OPCODE => self.handle_present_complete(event)?,
PresentIdleNotify::OPCODE => self.handle_present_idle(event)?,
@ -581,7 +581,7 @@ impl XorgngBackendData {
Ok(())
}
fn handle_present_complete(self: &Rc<Self>, event: &Event) -> Result<(), XorgngBackendError> {
fn handle_present_complete(self: &Rc<Self>, event: &Event) -> Result<(), XBackendError> {
let event: PresentCompleteNotify = event.parse()?;
let window = event.window;
let output = match self.outputs.get(&window) {
@ -598,7 +598,7 @@ impl XorgngBackendData {
Ok(())
}
fn handle_present_idle(self: &Rc<Self>, event: &Event) -> Result<(), XorgngBackendError> {
fn handle_present_idle(self: &Rc<Self>, event: &Event) -> Result<(), XBackendError> {
let event: PresentIdleNotify = event.parse()?;
let output = match self.outputs.get(&event.window) {
Some(o) => o,
@ -615,11 +615,11 @@ impl XorgngBackendData {
Ok(())
}
fn schedule_present(&self, output: &Rc<XorgOutput>) {
fn schedule_present(&self, output: &Rc<XOutput>) {
self.scheduled_present.push(output.clone());
}
async fn present(&self, output: &Rc<XorgOutput>) {
async fn present(&self, output: &Rc<XOutput>) {
if output.removed.get() {
return;
}
@ -657,7 +657,7 @@ impl XorgngBackendData {
image.last_serial.set(serial);
}
async fn handle_input_event(self: &Rc<Self>, event: &Event) -> Result<(), XorgngBackendError> {
async fn handle_input_event(self: &Rc<Self>, event: &Event) -> Result<(), XBackendError> {
match event.code() {
XiMotion::OPCODE => self.handle_input_motion(event),
XiEnter::OPCODE => self.handle_input_enter(event),
@ -674,7 +674,7 @@ impl XorgngBackendData {
self: &Rc<Self>,
event: &Event,
state: KeyState,
) -> Result<(), XorgngBackendError> {
) -> Result<(), XBackendError> {
let event: XiButtonPress = event.parse()?;
if let Some(seat) = self.mouse_seats.get(&event.deviceid) {
let button = event.detail;
@ -712,7 +712,7 @@ impl XorgngBackendData {
self: &Rc<Self>,
event: &Event,
state: KeyState,
) -> Result<(), XorgngBackendError> {
) -> Result<(), XBackendError> {
let event: XiKeyPress = event.parse()?;
if let Some(seat) = self.seats.get(&event.deviceid) {
seat.kb_event(InputEvent::Key(event.detail - 8, state));
@ -720,15 +720,12 @@ impl XorgngBackendData {
Ok(())
}
async fn handle_input_hierarchy(
self: &Rc<Self>,
event: &Event,
) -> Result<(), XorgngBackendError> {
async fn handle_input_hierarchy(self: &Rc<Self>, event: &Event) -> Result<(), XBackendError> {
let event: XiHierarchy = event.parse()?;
for info in event.infos.iter() {
if info.flags & INPUT_HIERARCHY_MASK_MASTER_ADDED != 0 {
if let Err(e) = self.query_devices(info.deviceid).await {
log::error!("Could not query device {}: {:#}", info.deviceid, e);
log::error!("Could not query device {}: {}", info.deviceid, ErrorFmt(e));
}
} else if info.flags & INPUT_HIERARCHY_MASK_MASTER_REMOVED != 0 {
self.mouse_seats.remove(&info.attachment);
@ -742,7 +739,7 @@ impl XorgngBackendData {
Ok(())
}
fn handle_input_enter(&self, event: &Event) -> Result<(), XorgngBackendError> {
fn handle_input_enter(&self, event: &Event) -> Result<(), XBackendError> {
let event: XiEnter = event.parse()?;
if let (Some(win), Some(seat)) = (
self.outputs.get(&event.event),
@ -757,7 +754,7 @@ impl XorgngBackendData {
Ok(())
}
fn handle_input_motion(&self, event: &Event) -> Result<(), XorgngBackendError> {
fn handle_input_motion(&self, event: &Event) -> Result<(), XBackendError> {
let event: XiMotion = event.parse()?;
let (win, seat) = match (
self.outputs.get(&event.event),
@ -774,7 +771,7 @@ impl XorgngBackendData {
Ok(())
}
fn handle_destroy(&self, event: &Event) -> Result<(), XorgngBackendError> {
fn handle_destroy(&self, event: &Event) -> Result<(), XBackendError> {
self.state.el.stop();
let event: DestroyNotify = event.parse()?;
let output = match self.outputs.remove(&event.event) {
@ -786,7 +783,7 @@ impl XorgngBackendData {
Ok(())
}
async fn handle_configure(&self, event: &Event) -> Result<(), XorgngBackendError> {
async fn handle_configure(&self, event: &Event) -> Result<(), XBackendError> {
let event: ConfigureNotify = event.parse()?;
let output = match self.outputs.get(&event.event) {
Some(o) => o,
@ -812,9 +809,9 @@ impl XorgngBackendData {
}
}
struct XorgOutput {
struct XOutput {
id: OutputId,
_backend: Rc<XorgngBackendData>,
_backend: Rc<XBackendData>,
window: u32,
removed: Cell<bool>,
width: Cell<i32>,
@ -822,11 +819,11 @@ struct XorgOutput {
serial: NumCell<u32>,
next_msc: Cell<u64>,
next_image: NumCell<usize>,
images: [XorgImage; 2],
images: [XImage; 2],
cb: CloneCell<Option<Rc<dyn Fn()>>>,
}
struct XorgImage {
struct XImage {
pixmap: Cell<u32>,
fb: CloneCell<Rc<Framebuffer>>,
idle: Cell<bool>,
@ -834,7 +831,7 @@ struct XorgImage {
last_serial: Cell<u32>,
}
impl XorgOutput {
impl XOutput {
fn changed(&self) {
if let Some(cb) = self.cb.get() {
cb();
@ -842,7 +839,7 @@ impl XorgOutput {
}
}
impl Output for XorgOutput {
impl Output for XOutput {
fn id(&self) -> OutputId {
self.id
}
@ -864,10 +861,10 @@ impl Output for XorgOutput {
}
}
struct XorgSeat {
struct XSeat {
kb_id: InputDeviceId,
mouse_id: InputDeviceId,
backend: Rc<XorgngBackendData>,
backend: Rc<XBackendData>,
kb: u16,
mouse: u16,
removed: Cell<bool>,
@ -878,11 +875,11 @@ struct XorgSeat {
button_map: CopyHashMap<u32, u32>,
}
struct XorgSeatKeyboard(Rc<XorgSeat>);
struct XSeatKeyboard(Rc<XSeat>);
struct XorgSeatMouse(Rc<XorgSeat>);
struct XSeatMouse(Rc<XSeat>);
impl XorgSeat {
impl XSeat {
fn kb_changed(&self) {
if let Some(cb) = self.kb_cb.get() {
cb();
@ -927,7 +924,7 @@ impl XorgSeat {
}
}
impl InputDevice for XorgSeatKeyboard {
impl InputDevice for XSeatKeyboard {
fn id(&self) -> InputDeviceId {
self.0.kb_id
}
@ -949,7 +946,7 @@ impl InputDevice for XorgSeatKeyboard {
}
}
impl InputDevice for XorgSeatMouse {
impl InputDevice for XSeatMouse {
fn id(&self) -> InputDeviceId {
self.0.mouse_id
}

View file

@ -3,7 +3,7 @@ use crate::object::ObjectId;
use crate::utils::buffd::{BufFdIn, BufFdOut, MsgParser};
use crate::utils::vec_ext::VecExt;
use crate::{ErrorFmt, Phase};
use futures::{select, FutureExt};
use futures_util::{select, FutureExt};
use std::collections::VecDeque;
use std::mem;
use std::rc::Rc;

View file

@ -84,6 +84,7 @@ impl ServerCursors {
pub struct ServerCursorTemplate {
var: ServerCursorTemplateVariant,
pub xcursor: Vec<XCursorImage>,
}
enum ServerCursorTemplateVariant {
@ -100,18 +101,19 @@ impl ServerCursorTemplate {
ctx: &Rc<RenderContext>,
) -> Result<Self, CursorError> {
match open_cursor(name, theme, size, paths) {
Ok(c) => {
if c.len() == 1 {
let c = &c[0];
Ok(cs) => {
if cs.len() == 1 {
let c = &cs[0];
let cursor = CursorImage::from_bytes(
ctx, &c.pixels, 0, c.width, c.height, c.xhot, c.yhot,
)?;
Ok(ServerCursorTemplate {
var: ServerCursorTemplateVariant::Static(Rc::new(cursor)),
xcursor: cs,
})
} else {
let mut images = vec![];
for c in c {
for c in &cs {
let img = CursorImage::from_bytes(
ctx,
&c.pixels,
@ -125,6 +127,7 @@ impl ServerCursorTemplate {
}
Ok(ServerCursorTemplate {
var: ServerCursorTemplateVariant::Animated(Rc::new(images)),
xcursor: cs,
})
}
}
@ -134,6 +137,7 @@ impl ServerCursorTemplate {
let cursor = CursorImage::from_bytes(ctx, &empty, 0, 1, 1, 0, 0)?;
Ok(ServerCursorTemplate {
var: ServerCursorTemplateVariant::Static(Rc::new(cursor)),
xcursor: Default::default(),
})
}
}
@ -427,13 +431,13 @@ pub enum CursorError {
}
#[derive(Default, Clone)]
struct XCursorImage {
width: i32,
height: i32,
xhot: i32,
yhot: i32,
delay: u32,
pixels: Vec<Cell<u8>>,
pub struct XCursorImage {
pub width: i32,
pub height: i32,
pub xhot: i32,
pub yhot: i32,
pub delay: u32,
pub pixels: Vec<Cell<u8>>,
}
impl Debug for XCursorImage {

View file

@ -121,7 +121,7 @@ impl ForkerProxy {
waiter: Cell::new(None),
});
self.pending_pidfds.set(id, Rc::downgrade(&handoff));
futures::future::poll_fn(|ctx| {
futures_util::future::poll_fn(|ctx| {
if let Some(pidfd) = handoff.pidfd.take() {
Poll::Ready(pidfd)
} else {

View file

@ -11,17 +11,17 @@ use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode};
use crate::utils::linkedlist::LinkedNode;
use crate::utils::smallmap::SmallMap;
use crate::wire::WlSurfaceId;
use crate::wire_xcon::CreateNotify;
use crate::xwayland::XWaylandEvent;
use crate::{AsyncQueue, CloneCell, State};
use jay_config::Direction;
use std::cell::{Cell, RefCell};
use std::rc::Rc;
use thiserror::Error;
use x11rb::protocol::xproto::{CreateNotifyEvent, Window};
pub struct XwindowData {
pub state: Rc<State>,
pub window_id: Window,
pub window_id: u32,
pub override_redirect: bool,
pub extents: Cell<Rect>,
pub client: Rc<Client>,
@ -44,7 +44,7 @@ pub struct Xwindow {
}
impl XwindowData {
pub fn new(state: &Rc<State>, event: &CreateNotifyEvent, client: &Rc<Client>) -> Self {
pub fn new(state: &Rc<State>, event: &CreateNotify, client: &Rc<Client>) -> Self {
let extents = Rect::new_sized(
event.x as _,
event.y as _,
@ -56,7 +56,7 @@ impl XwindowData {
Self {
state: state.clone(),
window_id: event.window,
override_redirect: event.override_redirect,
override_redirect: event.override_redirect != 0,
extents: Cell::new(extents),
client: client.clone(),
surface_id: Cell::new(None),

View file

@ -360,3 +360,40 @@ macro_rules! assert_align_eq {
let _ = AssertEqAlign::<$t, $u>::VAL;
}};
}
macro_rules! atom_manager {
{
$name:ident;
$($field_name:ident,)*
} => {
#[allow(non_snake_case, dead_code)]
#[derive(Debug, Clone, Copy)]
struct $name {
$(
$field_name: u32,
)*
}
impl $name {
fn get(
conn: &std::rc::Rc<crate::xcon::Xcon>,
) -> impl std::future::Future<Output = Result<Self, crate::xcon::XconError>> {
#![allow(non_snake_case)]
use bstr::ByteSlice;
$(
let $field_name = conn.call(&InternAtom {
only_if_exists: 0,
name: stringify!($field_name).as_bytes().as_bstr(),
});
)*
async move {
Ok(Self {
$(
$field_name: $field_name.await?.get().atom,
)*
})
}
}
}
}
}

View file

@ -83,7 +83,6 @@ mod object;
mod pixman;
mod rect;
mod render;
mod servermem;
mod sighand;
mod state;
mod tasks;

View file

@ -9,11 +9,9 @@ use crate::render::gl::sys::GLint;
use crate::render::gl::texture::GlTexture;
use crate::render::renderer::framebuffer::Framebuffer;
use crate::render::renderer::image::Image;
use crate::render::renderer::RENDERDOC;
use crate::render::{RenderError, Texture};
use ahash::AHashMap;
use renderdoc::{RenderDoc, V100};
use std::cell::{Cell, RefCell};
use std::cell::Cell;
use std::ffi::CString;
use std::fmt::{Debug, Formatter};
use std::rc::Rc;
@ -42,8 +40,6 @@ pub struct RenderContext {
pub(super) render_node: Rc<CString>,
pub(super) renderdoc: Option<RefCell<RenderDoc<V100>>>,
pub(super) tex_prog: TexProg,
pub(super) tex_alpha_prog: TexProg,
@ -104,12 +100,6 @@ impl RenderContext {
fill_prog_pos: fill_prog.get_attrib_location(ustr!("pos")),
fill_prog_color: fill_prog.get_uniform_location(ustr!("color")),
fill_prog,
renderdoc: if RENDERDOC {
Some(RefCell::new(RenderDoc::new().unwrap()))
} else {
None
},
})
}

View file

@ -9,7 +9,6 @@ use crate::render::sys::{glBlendFunc, GL_ONE, GL_ONE_MINUS_SRC_ALPHA};
use crate::tree::Node;
use crate::State;
use std::fmt::{Debug, Formatter};
use std::ptr;
use std::rc::Rc;
pub struct Framebuffer {
@ -38,10 +37,6 @@ impl Framebuffer {
pub fn render(&self, node: &dyn Node, state: &State, cursor_rect: Option<Rect>) {
let _ = self.ctx.ctx.with_current(|| {
if let Some(rd) = &self.ctx.renderdoc {
rd.borrow_mut()
.start_frame_capture(ptr::null(), ptr::null());
}
unsafe {
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
glViewport(0, 0, self.gl.width, self.gl.height);
@ -79,9 +74,6 @@ impl Framebuffer {
}
}
}
if let Some(rd) = &self.ctx.renderdoc {
rd.borrow_mut().end_frame_capture(ptr::null(), ptr::null());
}
Ok(())
});
}

View file

@ -9,5 +9,3 @@ mod framebuffer;
mod image;
mod renderer;
mod texture;
pub const RENDERDOC: bool = false;

View file

@ -1,82 +0,0 @@
#![allow(dead_code)]
use std::cell::Cell;
use std::ptr;
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] crate::utils::oserror::OsError),
#[error("The provided size does not fit into off_t")]
SizeOverflow,
#[error("ftruncate failed")]
Ftruncate(#[source] crate::utils::oserror::OsError),
#[error("mmap failed")]
MmapFailed(#[source] crate::utils::oserror::OsError),
#[error("sealing failed")]
Seal(#[source] crate::utils::oserror::OsError),
}
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());
}
}
}

View file

@ -1,4 +1,4 @@
use crate::backends::xorgng::XorgngBackend;
use crate::backends::x::XBackend;
use crate::{metal, ErrorFmt, State};
use std::future::pending;
use std::rc::Rc;
@ -12,7 +12,7 @@ pub async fn start_backend(state: Rc<State>) {
// }
// Err(e) => e,
// };
let e = match XorgngBackend::run(&state).await {
let e = match XBackend::run(&state).await {
Ok(_) => pending().await,
Err(e) => e,
};

View file

@ -1,7 +1,7 @@
use crate::async_engine::{AsyncFd, Timeout};
use crate::utils::buffd::{BufFdError, BUF_SIZE, CMSG_BUF_SIZE};
use futures::future::Fuse;
use futures::{select, FutureExt};
use futures_util::future::Fuse;
use futures_util::{select, FutureExt};
use std::collections::VecDeque;
use std::mem::MaybeUninit;
use std::rc::Rc;

View file

@ -1,7 +1,6 @@
use parking_lot::{Condvar, Mutex};
use std::mem;
use std::rc::Rc;
use std::sync::Arc;
use std::sync::{Arc, Condvar, Mutex};
use uapi::OwnedFd;
pub struct FdCloser {
@ -18,15 +17,15 @@ impl FdCloser {
let slf2 = slf.clone();
std::thread::spawn(move || {
let mut fds = vec![];
let mut lock = slf2.fds.lock();
let mut lock = slf2.fds.lock().unwrap();
loop {
mem::swap(&mut *lock, &mut fds);
if fds.len() > 0 {
drop(lock);
fds.clear();
lock = slf2.fds.lock();
lock = slf2.fds.lock().unwrap();
} else {
slf2.cv.wait(&mut lock);
lock = slf2.cv.wait(lock).unwrap();
}
}
});
@ -36,7 +35,7 @@ impl FdCloser {
pub fn close(&self, fd: Rc<OwnedFd>) {
match Rc::try_unwrap(fd) {
Ok(fd) => {
self.fds.lock().push(fd);
self.fds.lock().unwrap().push(fd);
self.cv.notify_all();
}
Err(_e) => {

View file

@ -2,8 +2,10 @@ use crate::async_engine::SpawnedFuture;
use crate::utils::bufio::{BufIo, BufIoError, BufIoMessage};
use crate::utils::oserror::OsError;
use crate::wire_xcon::{
Extension, GetInputFocus, ListExtensions, QueryExtension, Setup, EXTENSIONS,
Extension, GetInputFocus, ListExtensions, QueryExtension, RenderQueryPictFormats, Setup,
EXTENSIONS,
};
use crate::xcon::consts::RENDER_PICT_TYPE_DIRECT;
pub use crate::xcon::formatter::Formatter;
use crate::xcon::incoming::handle_incoming;
use crate::xcon::outgoing::handle_outgoing;
@ -89,6 +91,10 @@ pub enum XconError {
XidExhausted,
#[error("Enum contains an unknown variant")]
UnknownEnumVariant,
#[error("Could not query the render pict formats")]
QueryPictFormats(#[source] Box<XconError>),
#[error("The server does not support the picture format for cursors")]
CursorFormatNotSupported,
}
#[derive(Debug)]
@ -444,6 +450,29 @@ impl Xcon {
pub fn call<'a, T: Request<'a>>(self: &Rc<Self>, t: &T) -> AsyncReply<T::Reply> {
self.data.call(t, &self.extensions)
}
pub async fn find_cursor_format(self: &Rc<Self>) -> Result<u32, XconError> {
let res = match self.call(&RenderQueryPictFormats {}).await {
Ok(r) => r,
Err(e) => return Err(XconError::QueryPictFormats(Box::new(e))),
};
for format in res.get().formats.iter() {
let valid = format.ty == RENDER_PICT_TYPE_DIRECT
&& format.depth == 32
&& format.direct.red_shift == 16
&& format.direct.red_mask == 0xff
&& format.direct.green_shift == 8
&& format.direct.green_mask == 0xff
&& format.direct.blue_shift == 0
&& format.direct.blue_mask == 0xff
&& format.direct.alpha_shift == 24
&& format.direct.alpha_mask == 0xff;
if valid {
return Ok(format.id);
}
}
Err(XconError::CursorFormatNotSupported)
}
}
impl XconData {

View file

@ -105,3 +105,9 @@ pub const GRAB_STATUS_FROZEN: u8 = 4;
pub const IMAGE_FORMAT_XY_BITMAP: u8 = 0;
pub const IMAGE_FORMAT_XY_PIXMAP: u8 = 1;
pub const IMAGE_FORMAT_Z_PIXMAP: u8 = 2;
pub const COMPOSITE_REDIRECT_AUTOMATIC: u8 = 0;
pub const COMPOSITE_REDIRECT_MANUAL: u8 = 1;
pub const RENDER_PICT_TYPE_INDEXED: u8 = 0;
pub const RENDER_PICT_TYPE_DIRECT: u8 = 1;

View file

@ -7,15 +7,16 @@ use crate::ifs::wl_surface::xwindow::Xwindow;
use crate::ifs::wl_surface::WlSurface;
use crate::utils::tri::Try;
use crate::wire::WlSurfaceId;
use crate::xcon::XconError;
use crate::xwayland::xsocket::allocate_socket;
use crate::xwayland::xwm::Wm;
use crate::{AsyncError, AsyncQueue, ErrorFmt, ForkerError, State};
use bstr::ByteSlice;
use std::error::Error;
use std::num::ParseIntError;
use std::rc::Rc;
use thiserror::Error;
use uapi::{c, pipe2, Errno, OwnedFd};
use crate::utils::oserror::OsError;
#[derive(Debug, Error)]
enum XWaylandError {
@ -38,43 +39,39 @@ enum XWaylandError {
#[error("The socket is already in use")]
AlreadyInUse,
#[error("Could not bind the socket to an address")]
BindFailed(#[source] crate::utils::oserror::OsError),
BindFailed(#[source] OsError),
#[error("All X displays in the range 0..1000 are already in use")]
AddressesInUse,
#[error("The async engine returned an error")]
AsyncError(#[from] AsyncError),
#[error("pipe(2) failed")]
Pipe(#[source] crate::utils::oserror::OsError),
#[error("dupfd(2) failed")]
Dupfd(#[source] crate::utils::oserror::OsError),
Pipe(#[source] OsError),
#[error("socketpair(2) failed")]
Socketpair(#[source] crate::utils::oserror::OsError),
Socketpair(#[source] OsError),
#[error("Could not start Xwayland")]
ExecFailed(#[source] ForkerError),
#[error("Could not load the atoms")]
LoadAtoms(#[source] Box<dyn Error>),
LoadAtoms(#[source] XconError),
#[error("Could not connect to Xwayland")]
Connect(#[source] Box<dyn Error>),
Connect(#[source] XconError),
#[error("Could not create a window manager")]
CreateWm(#[source] Box<Self>),
#[error("Could not select the root events")]
SelectRootEvents(#[source] Box<dyn Error>),
SelectRootEvents(#[source] XconError),
#[error("Could not create the WM window")]
CreateXWindow(#[source] Box<dyn Error>),
CreateXWindow(#[source] XconError),
#[error("Could not acquire a selection")]
SelectionOwner(#[source] Box<dyn Error>),
#[error("Could not load the resource database")]
ResourceDatabase(#[source] Box<dyn Error>),
#[error("Could not acquire a cursor handle")]
CursorHandle(#[source] Box<dyn Error>),
#[error("Could not load the default cursor")]
LoadCursor(#[source] Box<dyn Error>),
SelectionOwner(#[source] XconError),
#[error("Could not set the cursor of the root window")]
SetCursor(#[source] Box<dyn Error>),
SetCursor(#[source] XconError),
#[error("composite_redirect_subwindows failed")]
CompositeRedirectSubwindows(#[source] Box<dyn Error>),
CompositeRedirectSubwindows(#[source] XconError),
#[error("Could not spawn the Xwayland client")]
SpawnClient(#[source] ClientError),
#[error("Could not map a window")]
MapWindow(#[source] XconError),
#[error("An unspecified XconError occurred")]
XconError(#[from] XconError),
}
pub async fn manage(state: Rc<State>) {
@ -131,7 +128,7 @@ async fn run(
Ok(p) => p,
Err(e) => return Err(XWaylandError::Pipe(e.into())),
};
let wm = uapi::socketpair(c::AF_UNIX, c::SOCK_STREAM | c::SOCK_CLOEXEC, 0);
let wm = uapi::socketpair(c::AF_UNIX, c::SOCK_STREAM | c::SOCK_CLOEXEC | c::SOCK_NONBLOCK, 0);
let (wm1, wm2) = match wm {
Ok(w) => w,
Err(e) => return Err(XWaylandError::Socketpair(e.into())),
@ -169,7 +166,7 @@ async fn run(
Err(e) => return Err(XWaylandError::SpawnClient(e)),
};
state.eng.fd(&Rc::new(dfdread))?.readable().await?;
let wm = match Wm::get(state, client, wm1, queue.clone()) {
let wm = match Wm::get(state, client, wm1, queue.clone()).await {
Ok(w) => w,
Err(e) => return Err(XWaylandError::CreateWm(Box::new(e))),
};

View file

@ -1,116 +1,110 @@
use crate::async_engine::AsyncFd;
use crate::client::Client;
use crate::ifs::wl_surface::xwindow::{Xwindow, XwindowData};
use crate::ifs::wl_surface::WlSurface;
use crate::rect::Rect;
use crate::wire::WlSurfaceId;
use crate::wire_xcon::{
ChangeWindowAttributes, ClientMessage, CompositeRedirectSubwindows, ConfigureNotify,
ConfigureRequest, ConfigureWindow, ConfigureWindowValues, CreateGC, CreateNotify, CreatePixmap,
CreateWindow, CreateWindowValues, DestroyNotify, FreeGC, FreePixmap, InternAtom,
MapRequest, MapWindow, PutImage, RenderCreateCursor, RenderCreatePicture,
SetSelectionOwner,
};
use crate::xcon::consts::{
COMPOSITE_REDIRECT_MANUAL, EVENT_MASK_PROPERTY_CHANGE, EVENT_MASK_SUBSTRUCTURE_NOTIFY,
EVENT_MASK_SUBSTRUCTURE_REDIRECT, IMAGE_FORMAT_Z_PIXMAP,
WINDOW_CLASS_INPUT_OUTPUT,
};
use crate::xcon::{Event, XEvent, Xcon};
use crate::xwayland::{XWaylandError, XWaylandEvent};
use crate::{AsyncQueue, ErrorFmt, State};
use ahash::AHashMap;
use futures::FutureExt;
use std::error::Error;
use std::os::unix::io::FromRawFd;
use std::os::unix::net::UnixStream;
use futures_util::{FutureExt, select};
use std::mem;
use std::rc::Rc;
use uapi::OwnedFd;
use x11rb::atom_manager;
use x11rb::connection::Connection;
use x11rb::cursor::Handle;
use x11rb::errors::ConnectionError;
use x11rb::protocol::composite::{ConnectionExt as _, Redirect};
use x11rb::protocol::xproto::{
ChangeWindowAttributesAux, ClientMessageEvent, ConfigureNotifyEvent, ConfigureRequestEvent,
ConfigureWindowAux, ConnectionExt as _, CreateNotifyEvent, CreateWindowAux, DestroyNotifyEvent,
EventMask, MapRequestEvent, Window, WindowClass,
};
use x11rb::protocol::Event;
use x11rb::resource_manager::Database;
use x11rb::rust_connection::{DefaultStream, RustConnection};
atom_manager! {
pub Atoms: AtomsCookie {
WL_SURFACE_ID,
WM_DELETE_WINDOW,
WM_PROTOCOLS,
WM_HINTS,
WM_NORMAL_HINTS,
WM_SIZE_HINTS,
WM_WINDOW_ROLE,
MOTIF_WM_HINTS,
UTF8_STRING,
WM_S0,
NET_SUPPORTED,
NET_WM_CM_S0,
NET_WM_PID,
NET_WM_NAME,
NET_WM_STATE,
NET_WM_WINDOW_TYPE,
WM_TAKE_FOCUS,
WINDOW,
NET_ACTIVE_WINDOW,
NET_WM_MOVERESIZE,
NET_SUPPORTING_WM_CHECK,
NET_WM_STATE_FOCUSED,
NET_WM_STATE_MODAL,
NET_WM_STATE_FULLSCREEN,
NET_WM_STATE_MAXIMIZED_VERT,
NET_WM_STATE_MAXIMIZED_HORZ,
NET_WM_STATE_HIDDEN,
NET_WM_PING,
WM_CHANGE_STATE,
WM_STATE,
CLIPBOARD,
PRIMARY,
WL_SELECTION,
TARGETS,
CLIPBOARD_MANAGER,
INCR,
TEXT,
TIMESTAMP,
DELETE,
NET_STARTUP_ID,
NET_STARTUP_INFO,
NET_STARTUP_INFO_BEGIN,
NET_WM_WINDOW_TYPE_NORMAL,
NET_WM_WINDOW_TYPE_UTILITY,
NET_WM_WINDOW_TYPE_TOOLTIP,
NET_WM_WINDOW_TYPE_DND,
NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
NET_WM_WINDOW_TYPE_POPUP_MENU,
NET_WM_WINDOW_TYPE_COMBO,
NET_WM_WINDOW_TYPE_MENU,
NET_WM_WINDOW_TYPE_NOTIFICATION,
NET_WM_WINDOW_TYPE_SPLASH,
DND_SELECTION,
DND_AWARE,
DND_STATUS,
DND_POSITION,
DND_ENTER,
DND_LEAVE,
DND_DROP,
DND_FINISHED,
DND_PROXY,
DND_TYPE_LIST,
DND_ACTION_MOVE,
DND_ACTION_COPY,
DND_ACTION_ASK,
DND_ACTION_PRIVATE,
NET_CLIENT_LIST,
NET_CLIENT_LIST_STACKING,
}
}
Atoms;
type Res<T> = Result<T, Box<dyn Error>>;
WL_SURFACE_ID,
WM_DELETE_WINDOW,
WM_PROTOCOLS,
WM_HINTS,
WM_NORMAL_HINTS,
WM_SIZE_HINTS,
WM_WINDOW_ROLE,
MOTIF_WM_HINTS,
UTF8_STRING,
WM_S0,
NET_SUPPORTED,
NET_WM_CM_S0,
NET_WM_PID,
NET_WM_NAME,
NET_WM_STATE,
NET_WM_WINDOW_TYPE,
WM_TAKE_FOCUS,
WINDOW,
NET_ACTIVE_WINDOW,
NET_WM_MOVERESIZE,
NET_SUPPORTING_WM_CHECK,
NET_WM_STATE_FOCUSED,
NET_WM_STATE_MODAL,
NET_WM_STATE_FULLSCREEN,
NET_WM_STATE_MAXIMIZED_VERT,
NET_WM_STATE_MAXIMIZED_HORZ,
NET_WM_STATE_HIDDEN,
NET_WM_PING,
WM_CHANGE_STATE,
WM_STATE,
CLIPBOARD,
PRIMARY,
WL_SELECTION,
TARGETS,
CLIPBOARD_MANAGER,
INCR,
TEXT,
TIMESTAMP,
DELETE,
NET_STARTUP_ID,
NET_STARTUP_INFO,
NET_STARTUP_INFO_BEGIN,
NET_WM_WINDOW_TYPE_NORMAL,
NET_WM_WINDOW_TYPE_UTILITY,
NET_WM_WINDOW_TYPE_TOOLTIP,
NET_WM_WINDOW_TYPE_DND,
NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
NET_WM_WINDOW_TYPE_POPUP_MENU,
NET_WM_WINDOW_TYPE_COMBO,
NET_WM_WINDOW_TYPE_MENU,
NET_WM_WINDOW_TYPE_NOTIFICATION,
NET_WM_WINDOW_TYPE_SPLASH,
DND_SELECTION,
DND_AWARE,
DND_STATUS,
DND_POSITION,
DND_ENTER,
DND_LEAVE,
DND_DROP,
DND_FINISHED,
DND_PROXY,
DND_TYPE_LIST,
DND_ACTION_MOVE,
DND_ACTION_COPY,
DND_ACTION_ASK,
DND_ACTION_PRIVATE,
NET_CLIENT_LIST,
NET_CLIENT_LIST_STACKING,
}
pub struct Wm {
state: Rc<State>,
c: RustConnection,
c: Rc<Xcon>,
atoms: Atoms,
socket: AsyncFd,
_root: Window,
_xwin: Window,
_root: u32,
_xwin: u32,
client: Rc<Client>,
windows: AHashMap<Window, Rc<XwindowData>>,
windows: AHashMap<u32, Rc<XwindowData>>,
windows_by_surface_id: AHashMap<WlSurfaceId, Rc<XwindowData>>,
queue: Rc<AsyncQueue<XWaylandEvent>>,
}
@ -126,100 +120,167 @@ impl Drop for Wm {
}
impl Wm {
pub(super) fn get(
pub(super) async fn get(
state: &Rc<State>,
client: Rc<Client>,
socket: OwnedFd,
queue: Rc<AsyncQueue<XWaylandEvent>>,
) -> Result<Self, XWaylandError> {
let socket_dup = match uapi::fcntl_dupfd_cloexec(socket.raw(), 0) {
Ok(s) => state.eng.fd(&Rc::new(s))?,
Err(e) => return Err(XWaylandError::Dupfd(e.into())),
};
let c = try {
RustConnection::connect_to_stream(
DefaultStream::from_unix_stream(unsafe {
UnixStream::from_raw_fd(socket.unwrap())
})?,
0,
)?
};
let c: RustConnection = match c {
let c = match Xcon::connect_to_fd(&state.eng, &Rc::new(socket), &[], &[]).await {
Ok(c) => c,
Err(e) => return Err(XWaylandError::Connect(e)),
};
let atoms: Atoms = match try { Atoms::new(&c)?.reply()? } {
let atoms = match Atoms::get(&c).await {
Ok(a) => a,
Err(e) => return Err(XWaylandError::LoadAtoms(e)),
};
let root = c.setup().roots[0].root;
let root = c.setup().screens[0].root;
{
let cwa = ChangeWindowAttributesAux::new().event_mask(
EventMask::SUBSTRUCTURE_NOTIFY
| EventMask::SUBSTRUCTURE_REDIRECT
| EventMask::PROPERTY_CHANGE,
);
let res = try { c.change_window_attributes(root, &cwa)?.check()? };
if let Err(e) = res {
let events = 0
| EVENT_MASK_SUBSTRUCTURE_NOTIFY
| EVENT_MASK_SUBSTRUCTURE_REDIRECT
| EVENT_MASK_PROPERTY_CHANGE;
let cwa = ChangeWindowAttributes {
window: root,
values: CreateWindowValues {
event_mask: Some(events),
..Default::default()
},
};
if let Err(e) = c.call(&cwa).await {
return Err(XWaylandError::SelectRootEvents(e));
}
}
{
let res = try {
c.composite_redirect_subwindows(root, Redirect::MANUAL)?
.check()?
let crs = CompositeRedirectSubwindows {
window: root,
update: COMPOSITE_REDIRECT_MANUAL,
};
if let Err(e) = res {
if let Err(e) = c.call(&crs).await {
return Err(XWaylandError::CompositeRedirectSubwindows(e));
}
}
let xwin = c.generate_id().unwrap_or(0);
{
let res = try {
c.create_window(
0,
xwin,
root,
0,
0,
10,
10,
0,
WindowClass::INPUT_OUTPUT,
0,
&CreateWindowAux::new(),
)?
.check()?;
let xwin = {
let cw = CreateWindow {
depth: 0,
wid: c.generate_id()?,
parent: root,
x: 0,
y: 0,
width: 10,
height: 10,
border_width: 0,
class: WINDOW_CLASS_INPUT_OUTPUT,
visual: 0,
values: Default::default(),
};
if let Err(e) = res {
if let Err(e) = c.call(&cw).await {
return Err(XWaylandError::CreateXWindow(e));
}
}
cw.wid
};
{
let res = try {
c.set_selection_owner(xwin, atoms.WM_S0, 0u32)?.check()?;
let sso = SetSelectionOwner {
owner: xwin,
selection: atoms.WM_S0,
time: 0,
};
if let Err(e) = res {
if let Err(e) = c.call(&sso).await {
return Err(XWaylandError::SelectionOwner(e));
}
}
{
let rdb = match Database::new_from_default(&c) {
Ok(rdb) => rdb,
Err(e) => return Err(XWaylandError::ResourceDatabase(e.into())),
'set_root_cursor: {
let cursor_format = c.find_cursor_format().await?;
let cursors = match state.cursors.get() {
Some(g) => g,
_ => break 'set_root_cursor,
};
let handle: Res<Handle> = try { Handle::new(&c, 0, &rdb)?.reply()? };
let handle = match handle {
Ok(h) => h,
Err(e) => return Err(XWaylandError::CursorHandle(e)),
let first = match cursors.default.xcursor.first() {
Some(f) => f,
_ => break 'set_root_cursor,
};
let cursor = match handle.load_cursor(&c, "left_ptr") {
Ok(c) => c,
Err(e) => return Err(XWaylandError::LoadCursor(e.into())),
let pixmap = c.generate_id()?;
let gc = c.generate_id()?;
let picture = c.generate_id()?;
let cursor = c.generate_id()?;
let create_pixmap = c.call(&CreatePixmap {
depth: 32,
pid: pixmap,
drawable: root,
width: first.width as _,
height: first.height as _,
});
let create_gc = c.call(&CreateGC {
cid: gc,
drawable: pixmap,
values: Default::default(),
});
let put_image = c.call(&PutImage {
format: IMAGE_FORMAT_Z_PIXMAP,
drawable: pixmap,
gc,
width: first.width as _,
height: first.height as _,
dst_x: 0,
dst_y: 0,
left_pad: 0,
depth: 32,
data: unsafe { mem::transmute(&first.pixels[..]) },
});
c.call(&FreeGC { gc });
let create_picture = c.call(&RenderCreatePicture {
pid: picture,
drawable: pixmap,
format: cursor_format,
values: Default::default(),
});
c.call(&FreePixmap { pixmap });
let create_cursor = c.call(&RenderCreateCursor {
cid: cursor,
source: picture,
x: first.xhot as _,
y: first.yhot as _,
});
if let Err(e) = create_pixmap.await {
log::warn!(
"Could not create a pixmap for the root cursor: {}",
ErrorFmt(e)
);
break 'set_root_cursor;
}
if let Err(e) = create_gc.await {
log::warn!(
"Could not create a graphics context for the root cursor: {}",
ErrorFmt(e)
);
break 'set_root_cursor;
}
if let Err(e) = put_image.await {
log::warn!(
"Could not upload the image for the root cursor: {}",
ErrorFmt(e)
);
break 'set_root_cursor;
}
if let Err(e) = create_picture.await {
log::warn!(
"Could not create a picture for the root cursor: {}",
ErrorFmt(e)
);
break 'set_root_cursor;
}
if let Err(e) = create_cursor.await {
log::warn!("Could not create the root cursor: {}", ErrorFmt(e));
break 'set_root_cursor;
}
let cwa = ChangeWindowAttributes {
window: root,
values: CreateWindowValues {
cursor: Some(cursor),
..Default::default()
},
};
let cwa = ChangeWindowAttributesAux::new().cursor(cursor);
let res: Res<_> = try { c.change_window_attributes(root, &cwa)?.check()? };
if let Err(e) = res {
if let Err(e) = c.call(&cwa).await {
return Err(XWaylandError::SetCursor(e));
}
}
@ -227,7 +288,6 @@ impl Wm {
state: state.clone(),
c,
atoms,
socket: socket_dup,
_root: root,
_xwin: xwin,
client,
@ -239,52 +299,40 @@ impl Wm {
pub async fn run(mut self) {
loop {
while let Some(e) = self.queue.try_pop() {
self.handle_xwayland_event(e);
}
if let Err(e) = self.handle_events() {
log::error!("Connection failed: {}", ErrorFmt(e));
return;
}
futures::select! {
res = self.socket.readable().fuse() => {
if let Err(e) = res {
log::error!("Cannot wait for xwm fd to become readable: {}", ErrorFmt(e));
return;
}
}
_ = self.queue.non_empty().fuse() => { },
select! {
e = self.queue.pop().fuse() => self.handle_xwayland_event(e).await,
e = self.c.event().fuse() => self.handle_event(&e).await,
}
}
}
fn handle_xwayland_event(&mut self, e: XWaylandEvent) {
async fn handle_xwayland_event(&mut self, e: XWaylandEvent) {
match e {
XWaylandEvent::SurfaceCreated(event) => self.handle_xwayland_surface_created(event),
XWaylandEvent::Configure(event) => self.handle_xwayland_configure(event),
XWaylandEvent::Configure(event) => self.handle_xwayland_configure(event).await,
XWaylandEvent::SurfaceDestroyed(event) => self.handle_xwayland_surface_destroyed(event),
}
}
fn handle_xwayland_configure(&mut self, window: Rc<Xwindow>) {
self.send_configure(window);
async fn handle_xwayland_configure(&mut self, window: Rc<Xwindow>) {
self.send_configure(window).await;
}
fn send_configure(&mut self, window: Rc<Xwindow>) {
async fn send_configure(&mut self, window: Rc<Xwindow>) {
let extents = window.data.extents.get();
let cfg = ConfigureWindowAux::new()
.x(extents.x1())
.y(extents.y1())
.width(extents.width() as u32)
.height(extents.height() as u32)
.border_width(0);
let res: Res<()> = try {
self.c
.configure_window(window.data.window_id, &cfg)?
.check()?;
let cw = ConfigureWindow {
window: window.data.window_id,
values: ConfigureWindowValues {
x: Some(extents.x1()),
y: Some(extents.y1()),
width: Some(extents.width() as u32),
height: Some(extents.height() as u32),
border_width: Some(0),
..Default::default()
},
};
if let Err(e) = res {
log::error!("Could not configure window: {}", ErrorFmt(&*e));
if let Err(e) = self.c.call(&cw).await {
log::error!("Could not configure window: {}", ErrorFmt(e));
}
}
@ -319,30 +367,33 @@ impl Wm {
self.windows_by_surface_id.remove(&surface);
}
fn handle_events(&mut self) -> Result<(), ConnectionError> {
while let Some(e) = self.c.poll_for_event()? {
self.handle_event(e);
}
Ok(())
}
fn handle_event(&mut self, event: Event) {
log::info!("{:?}", event);
match event {
Event::MapRequest(event) => self.handle_map_request(event),
Event::ConfigureRequest(event) => self.handle_configure_request(event),
Event::ConfigureNotify(event) => self.handle_configure_notify(event),
Event::ClientMessage(event) => self.handle_client_message(event),
Event::CreateNotify(event) => self.handle_create_notify(event),
Event::DestroyNotify(event) => self.handle_destroy_notify(event),
_ => {}
async fn handle_event(&mut self, event: &Event) {
match event.ext() {
Some(_) => {}
_ => self.handle_core_event(&event).await,
}
}
fn handle_destroy_notify(&mut self, event: DestroyNotifyEvent) {
async fn handle_core_event(&mut self, event: &Event) {
let res = match event.code() {
MapRequest::OPCODE => self.handle_map_request(event).await,
ConfigureRequest::OPCODE => self.handle_configure_request(event).await,
ConfigureNotify::OPCODE => self.handle_configure_notify(event),
ClientMessage::OPCODE => self.handle_client_message(event),
CreateNotify::OPCODE => self.handle_create_notify(event),
DestroyNotify::OPCODE => self.handle_destroy_notify(event),
_ => Ok(()),
};
if let Err(e) = res {
log::warn!("Could not handle an event: {}", ErrorFmt(e));
}
}
fn handle_destroy_notify(&mut self, event: &Event) -> Result<(), XWaylandError> {
let event: DestroyNotify = event.parse()?;
let data = match self.windows.remove(&event.window) {
Some(w) => w,
_ => return,
_ => return Ok(()),
};
if let Some(sid) = data.surface_id.take() {
self.windows_by_surface_id.remove(&sid);
@ -350,30 +401,40 @@ impl Wm {
if let Some(window) = data.window.take() {
window.destroy();
}
Ok(())
}
fn handle_create_notify(&mut self, event: CreateNotifyEvent) {
fn handle_create_notify(&mut self, event: &Event) -> Result<(), XWaylandError> {
let event: CreateNotify = event.parse()?;
let data = Rc::new(XwindowData::new(&self.state, &event, &self.client));
self.windows.insert(event.window, data);
Ok(())
}
fn handle_client_message(&mut self, event: ClientMessageEvent) {
if event.type_ == self.atoms.WL_SURFACE_ID {
self.handle_wl_surface_id(event);
fn handle_client_message(&mut self, event: &Event) -> Result<(), XWaylandError> {
let event: ClientMessage = event.parse()?;
if event.ty == self.atoms.WL_SURFACE_ID {
self.handle_wl_surface_id(&event)?;
}
Ok(())
}
async fn handle_map_request(&mut self, event: &Event) -> Result<(), XWaylandError> {
let event: MapRequest = event.parse()?;
let mw = MapWindow {
window: event.window,
};
match self.c.call(&mw).await {
Ok(_) => Ok(()),
Err(e) => Err(XWaylandError::MapWindow(e)),
}
}
fn handle_map_request(&mut self, event: MapRequestEvent) {
let res: Res<_> = try { self.c.map_window(event.window)?.check()? };
if let Err(e) = res {
log::error!("Could not map window: {}", ErrorFmt(&*e));
}
}
fn handle_configure_notify(&mut self, event: ConfigureNotifyEvent) {
fn handle_configure_notify(&mut self, event: &Event) -> Result<(), XWaylandError> {
let event: ConfigureNotify = event.parse()?;
let data = match self.windows.get(&event.window) {
Some(d) => d,
_ => return,
_ => return Ok(()),
};
if data.override_redirect {
let extents = Rect::new_sized(
@ -388,33 +449,37 @@ impl Wm {
self.state.tree_changed();
}
}
Ok(())
}
fn handle_configure_request(&mut self, event: ConfigureRequestEvent) {
async fn handle_configure_request(&mut self, event: &Event) -> Result<(), XWaylandError> {
let event: ConfigureRequest = event.parse()?;
let data = match self.windows.get(&event.window) {
Some(d) => d,
_ => return,
_ => return Ok(()),
};
if let Some(w) = data.window.get() {
self.send_configure(w);
self.send_configure(w).await;
}
Ok(())
}
fn handle_wl_surface_id(&mut self, event: ClientMessageEvent) {
fn handle_wl_surface_id(&mut self, event: &ClientMessage) -> Result<(), XWaylandError> {
let data = match self.windows.get(&event.window) {
Some(d) => d.clone(),
_ => return,
_ => return Ok(()),
};
if data.surface_id.get().is_some() {
log::error!("Surface id is already set");
return;
return Ok(());
}
let [surface_id, ..] = event.data.as_data32();
let surface_id = event.data[0];
let surface_id = WlSurfaceId::from_raw(surface_id);
data.surface_id.set(Some(surface_id));
self.windows_by_surface_id.insert(surface_id, data.clone());
if let Ok(surface) = self.client.lookup(surface_id) {
self.create_window(&data, surface);
}
Ok(())
}
}