From 6597a57ad569a450c06b0d6f2f65b86e64e59eca Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Wed, 23 Mar 2022 00:14:22 +0100 Subject: [PATCH] autocommit 2022-03-23 00:14:22 CET --- Cargo.lock | 29 - Cargo.toml | 2 - src/backends/mod.rs | 1 - src/backends/xorg.rs | 1170 ------------------------------------ src/backends/xorgng.rs | 10 +- src/tasks/start_backend.rs | 6 +- src/xcon/consts.rs | 4 + wire-xcon/xproto.txt | 1 + 8 files changed, 14 insertions(+), 1209 deletions(-) delete mode 100644 src/backends/xorg.rs diff --git a/Cargo.lock b/Cargo.lock index 7613f24a..7572daac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -444,8 +444,6 @@ dependencies = [ "thiserror", "uapi", "x11rb", - "xcb-dl", - "xcb-dl-util", ] [[package]] @@ -1110,30 +1108,3 @@ dependencies = [ "winapi", "winapi-wsapoll", ] - -[[package]] -name = "xcb-dl" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ce37e57249f12cbdf43844a3c9b3162f528ec27a1dc1dd7c6f46826063f51e8" -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", -] diff --git a/Cargo.toml b/Cargo.toml index 1da1020a..d721878d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,8 +23,6 @@ futures = "0.3.19" 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", "xcb_dri3", "xcb_present", "xcb_render"]} libloading = "0.7.2" bstr = "0.2.17" isnt = "0.1.0" diff --git a/src/backends/mod.rs b/src/backends/mod.rs index a175399c..4ce3a7ce 100644 --- a/src/backends/mod.rs +++ b/src/backends/mod.rs @@ -1,3 +1,2 @@ pub mod metal; -pub mod xorg; pub mod xorgng; diff --git a/src/backends/xorg.rs b/src/backends/xorg.rs deleted file mode 100644 index d94bf66a..00000000 --- a/src/backends/xorg.rs +++ /dev/null @@ -1,1170 +0,0 @@ -use crate::backend::{ - Backend, BackendEvent, InputDevice, InputDeviceId, InputEvent, KeyState, Output, OutputId, - ScrollAxis, -}; -use crate::drm::drm::{Drm, DrmError}; -use crate::drm::gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING}; -use crate::drm::{ModifiedFormat, INVALID_MODIFIER}; -use crate::event_loop::{EventLoopDispatcher, EventLoopId}; -use crate::fixed::Fixed; -use crate::format::XRGB8888; -use crate::render::{Framebuffer, RenderContext, RenderError}; -use crate::servermem::ServerMemError; -use crate::utils::clonecell::CloneCell; -use crate::utils::copyhashmap::CopyHashMap; -use crate::utils::ptr_ext::PtrExt; -use crate::wheel::{WheelDispatcher, WheelId}; -use crate::{ErrorFmt, EventLoopError, NumCell, State, WheelError}; -use isnt::std_1::primitive::IsntConstPtrExt; -use rand::Rng; -use std::cell::{Cell, RefCell}; -use std::collections::VecDeque; -use std::error::Error; -use std::rc::Rc; -use std::{ptr, slice}; -use thiserror::Error; -use uapi::{c, OwnedFd}; -use xcb_dl::{ffi, Xcb, XcbDri3, XcbPresent, XcbRender, XcbXinput, XcbXkb}; -use xcb_dl_util::cursor::{XcbCursorContext, XcbCursorImage}; -use xcb_dl_util::error::{XcbConnectionError, XcbError, XcbErrorParser}; -use xcb_dl_util::xcb_box::XcbBox; - -#[derive(Debug, Error)] -pub enum XorgBackendError { - #[error("Could not connect to the X server")] - CannotConnect(#[source] XcbConnectionError), - #[error("The xcb connection is in an error state")] - ErrorEvent, - #[error("The drm subsystem returned an error")] - DrmError(#[from] DrmError), - #[error("The gbm subsystem returned an error")] - GbmError(#[from] GbmError), - #[error("Could not import a dma-buf")] - ImportBuffer(#[source] XcbError), - #[error("Could not create an EGL context")] - CreateEgl(#[source] RenderError), - #[error("Could not create a framebuffer from a dma-buf")] - CreateFramebuffer(#[source] RenderError), - #[error("Could not select input events")] - CannotSelectInputEvents(#[source] XcbError), - #[error("Could not select present events")] - CannotSelectPresentEvents(#[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), - #[error("The timer wheel caused an error")] - WheelError(#[source] Box), - #[error("Could not allocate and map image memory")] - ServerMemError(#[source] Box), - #[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), -} -efrom!(XorgBackendError, EventLoopError); -efrom!(XorgBackendError, ServerMemError); -efrom!(XorgBackendError, WheelError); - -struct XcbCon { - xcb: Box, - input: Box, - dri: Box, - present: Box, - render: Box, - input_opcode: u8, - present_opcode: u8, - xkb: Box, - screen: ffi::xcb_screen_t, - c: *mut ffi::xcb_connection_t, - errors: XcbErrorParser, -} - -impl XcbCon { - fn new() -> Result { - unsafe { - let xcb = Box::new(Xcb::load_loose()?); - let input = Box::new(XcbXinput::load_loose()?); - let xkb = Box::new(XcbXkb::load_loose()?); - let dri = Box::new(XcbDri3::load_loose()?); - let present = Box::new(XcbPresent::load_loose()?); - let render = Box::new(XcbRender::load_loose()?); - - let c = xcb.xcb_connect(ptr::null(), ptr::null_mut()); - match xcb.xcb_connection_has_error(c) { - 0 => {} - n => return Err(XorgBackendError::CannotConnect(n.into())), - } - let errors = XcbErrorParser::new(&xcb, c); - - let mut con = Self { - screen: *xcb.xcb_setup_roots_iterator(xcb.xcb_get_setup(c)).data, - xcb, - input, - dri, - present, - render, - input_opcode: 0, - present_opcode: 0, - xkb, - c, - errors, - }; - - con.errors.check_connection(&con.xcb)?; - - let mut err = ptr::null_mut(); - - 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.dri.xcb_dri3_query_version_reply( - c, - con.dri.xcb_dri3_query_version(c, 1, 0), - &mut err, - ); - con.errors.check(&con.xcb, res, err)?; - - let res = con.present.xcb_present_query_version_reply( - c, - con.present.xcb_present_query_version(c, 1, 0), - &mut err, - ); - con.errors.check(&con.xcb, res, err)?; - - let res = con.render.xcb_render_query_version_reply( - c, - con.render.xcb_render_query_version(c, 0, 8), - &mut err, - ); - con.errors.check(&con.xcb, res, err)?; - - let present_ex = con - .xcb - .xcb_get_extension_data(con.c, con.present.xcb_present_id()); - assert!(present_ex.is_not_null()); - con.present_opcode = present_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( - &self, - reply: *mut T, - err: *mut ffi::xcb_generic_error_t, - ) -> Result, 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, - con: XcbCon, - outputs: CopyHashMap>, - seats: CopyHashMap>, - mouse_seats: CopyHashMap>, - ctx: Rc, - gbm: GbmDevice, - cursor: ffi::xcb_cursor_t, - r: Cell, - g: Cell, - b: Cell, -} - -impl Backend for XorgBackend { - fn switch_to(&self, _vtnr: u32) { - log::error!("Xorg backend cannot switch vts"); - } -} - -fn get_drm(con: &XcbCon) -> Result { - unsafe { - let mut err = ptr::null_mut(); - let res = con.dri.xcb_dri3_open_reply( - con.c, - con.dri.xcb_dri3_open(con.c, con.screen.root, 0), - &mut err, - ); - let mut res = con.check(res, err)?; - assert!(res.nfd == 1); - let fd = *con.dri.xcb_dri3_open_reply_fds(con.c, &mut *res); - let fd = OwnedFd::new(fd); - Ok(Drm::reopen(fd.raw(), false)?) - } -} - -impl XorgBackend { - pub fn new(state: &Rc) -> Result, XorgBackendError> { - unsafe { - let con = XcbCon::new()?; - - let drm = get_drm(&con)?; - let gbm = GbmDevice::new(&drm)?; - let ctx = match RenderContext::from_drm_device(&drm) { - Ok(r) => Rc::new(r), - Err(e) => return Err(XorgBackendError::CreateEgl(e)), - }; - - let fd = con.xcb.xcb_get_file_descriptor(con.c); - - let wheel_id = state.wheel.id(); - - let cursor = { - let ctx = XcbCursorContext::new(&con.xcb, &con.render, con.c); - let image = XcbCursorImage { - width: 1, - height: 1, - xhot: 0, - yhot: 0, - delay: 0, - pixels: vec![0], - ..Default::default() - }; - let cursor = ctx.create_cursor(&con.xcb, &con.render, slice::from_ref(&image)); - match cursor { - Ok(c) => c, - Err(e) => { - log::error!("Could not create empty cursor: {}", e); - 0 - } - } - }; - - let slf = Rc::new(Self { - id: state.el.id(), - wheel_id, - state: state.clone(), - con, - outputs: Default::default(), - seats: Default::default(), - mouse_seats: Default::default(), - ctx: ctx.clone(), - gbm, - cursor, - r: Cell::new(0.0), - g: Cell::new(0.0), - b: Cell::new(0.0), - }); - - { - 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.wheel.periodic(wheel_id, 1000_000, 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()?; - - state.set_render_ctx(&ctx); - - Ok(slf) - } - } - - fn create_images( - &self, - window: ffi::xcb_window_t, - width: i32, - height: i32, - ) -> Result<[XorgImage; 2], XorgBackendError> { - let format = ModifiedFormat { - format: XRGB8888, - modifier: INVALID_MODIFIER, - }; - let mut images = [None, None]; - for i in 0..2 { - let bo = self - .gbm - .create_bo(width, height, &format, GBM_BO_USE_RENDERING)?; - let dma = bo.dma(); - assert!(dma.planes.len() == 1); - let plane = dma.planes.first().unwrap(); - let size = plane.stride * dma.height as u32; - let fd = uapi::fcntl_dupfd_cloexec(plane.fd.raw(), 0).unwrap(); - let fb = match self.ctx.dmabuf_fb(dma) { - Ok(f) => f, - Err(e) => return Err(XorgBackendError::CreateFramebuffer(e)), - }; - let pixmap = unsafe { - let pixmap = self.con.xcb.xcb_generate_id(self.con.c); - let cookie = self.con.dri.xcb_dri3_pixmap_from_buffer_checked( - self.con.c, - pixmap, - window, - size, - dma.width as _, - dma.height as _, - plane.stride as _, - 24, - 32, - fd.unwrap(), - ); - if let Err(e) = self.con.check_cookie(cookie) { - return Err(XorgBackendError::ImportBuffer(e)); - } - pixmap - }; - images[i] = Some(XorgImage { - pixmap: Cell::new(pixmap), - fb: CloneCell::new(fb), - idle: Cell::new(true), - render_on_idle: Cell::new(false), - last_serial: Cell::new(0), - }); - } - Ok([images[0].take().unwrap(), images[1].take().unwrap()]) - } - - fn add_output(self: &Rc) -> 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); - const WIDTH: i32 = 800; - const HEIGHT: i32 = 600; - { - let cookie = con.xcb.xcb_create_window_checked( - con.c, - 0, - window_id, - screen.root, - 0, - 0, - WIDTH as _, - HEIGHT as _, - 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 images = self.create_images(window_id, WIDTH, HEIGHT).unwrap(); - let output = Rc::new(XorgOutput { - id: self.state.output_ids.next(), - backend: self.clone(), - window: window_id, - removed: Cell::new(false), - width: Cell::new(0), - height: Cell::new(0), - serial: Default::default(), - next_msc: Cell::new(0), - next_image: Default::default(), - cb: CloneCell::new(None), - images, - }); - { - let class = "jay\0jay\0"; - let 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 args = [event_mask, self.cursor]; - let cookie = con.xcb.xcb_change_window_attributes_checked( - con.c, - window_id, - ffi::XCB_CW_EVENT_MASK | ffi::XCB_CW_CURSOR, - args.as_ptr() 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 = 0 - | 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)); - } - } - { - let mask = 0 - | ffi::XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY - | ffi::XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY; - let cookie = con.present.xcb_present_select_input_checked( - con.c, - con.xcb.xcb_generate_id(con.c), - window_id, - mask, - ); - if let Err(e) = con.check_cookie(cookie) { - return Err(XorgBackendError::CannotSelectPresentEvents(e)); - } - } - self.outputs.set(window_id, output.clone()); - self.state - .backend_events - .push(BackendEvent::NewOutput(output.clone())); - self.present(&output); - } - Ok(()) - } - - fn query_devices( - self: &Rc, - 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, info: &ffi::xcb_input_xi_device_info_t) { - if info.type_ != ffi::XCB_INPUT_DEVICE_TYPE_MASTER_KEYBOARD as u16 { - 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.kb_changed(); - kb.mouse_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 seat = Rc::new(XorgSeat { - kb_id: self.state.input_device_ids.next(), - mouse_id: self.state.input_device_ids.next(), - backend: self.clone(), - kb: info.deviceid, - mouse: info.attachment, - removed: Cell::new(false), - kb_cb: Default::default(), - mouse_cb: Default::default(), - kb_events: RefCell::new(Default::default()), - mouse_events: RefCell::new(Default::default()), - button_map: Default::default(), - }); - seat.update_button_map(); - self.seats.set(info.deviceid, seat.clone()); - self.mouse_seats.set(info.attachment, seat.clone()); - self.state - .backend_events - .push(BackendEvent::NewInputDevice(Rc::new(XorgSeatMouse( - seat.clone(), - )))); - self.state - .backend_events - .push(BackendEvent::NewInputDevice(Rc::new(XorgSeatKeyboard( - seat.clone(), - )))); - } - } - - fn handle_events(self: &Rc) -> 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, - 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, - 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)?; - } else if event.extension == self.con.present_opcode { - self.handle_present_event(event)?; - } - Ok(()) - } - - fn handle_present_event( - self: &Rc, - event: &ffi::xcb_ge_generic_event_t, - ) -> Result<(), XorgBackendError> { - match event.event_type { - ffi::XCB_PRESENT_COMPLETE_NOTIFY => self.handle_present_complete(event)?, - ffi::XCB_PRESENT_IDLE_NOTIFY => self.handle_present_idle(event)?, - _ => {} - } - Ok(()) - } - - fn handle_present_complete( - self: &Rc, - event: &ffi::xcb_ge_generic_event_t, - ) -> Result<(), XorgBackendError> { - let event = unsafe { - (event as *const _ as *const ffi::xcb_present_complete_notify_event_t).deref() - }; - let window = event.window; - let output = match self.outputs.get(&window) { - Some(o) => o, - _ => return Ok(()), - }; - output.next_msc.set(event.msc + 1); - let image = &output.images[output.next_image.get() % output.images.len()]; - if image.idle.get() { - self.present(&output); - } else { - image.render_on_idle.set(true); - } - Ok(()) - } - - fn handle_present_idle( - self: &Rc, - event: &ffi::xcb_ge_generic_event_t, - ) -> Result<(), XorgBackendError> { - let event = - unsafe { (event as *const _ as *const ffi::xcb_present_idle_notify_event_t).deref() }; - let output = match self.outputs.get(&event.window) { - Some(o) => o, - _ => return Ok(()), - }; - for image in &output.images { - if image.last_serial.get() == event.serial { - image.idle.set(true); - if image.render_on_idle.replace(false) { - self.present(&output); - } - } - } - Ok(()) - } - - fn present(&self, output: &Rc) { - // { - // let clients = self.state.clients.clients.borrow(); - // for client in clients.values() { - // let s = client.data.objects.surfaces.lock(); - // for s in s.values() { - // let mut fr = s.frame_requests.borrow_mut(); - // for cb in fr.drain(..) { - // s.client.dispatch_frame_requests.push(cb); - // } - // } - // } - // return; - // } - - let image = &output.images[output.next_image.fetch_add(1) % output.images.len()]; - let serial = output.serial.fetch_add(1); - - if let Some(node) = self.state.root.outputs.get(&output.id) { - let fb = image.fb.get(); - fb.render(&*node, &self.state, Some(node.position.get())); - } - - unsafe { - let cookie = self.con.present.xcb_present_pixmap_checked( - self.con.c, - output.window, - image.pixmap.get(), - serial, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - output.next_msc.get(), - 1, - 0, - 0, - ptr::null(), - ); - if let Err(e) = self.con.check_cookie(cookie) { - log::error!("Could not present image: {:?}", e); - return; - } - } - image.idle.set(false); - image.last_serial.set(serial); - } - - fn handle_input_event( - self: &Rc, - 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_ENTER => self.handle_input_enter(event)?, - ffi::XCB_INPUT_BUTTON_PRESS => { - self.handle_input_button_press(event, KeyState::Pressed)? - } - ffi::XCB_INPUT_BUTTON_RELEASE => { - self.handle_input_button_press(event, KeyState::Released)? - } - ffi::XCB_INPUT_KEY_PRESS => self.handle_input_key_press(event, KeyState::Pressed)?, - ffi::XCB_INPUT_KEY_RELEASE => self.handle_input_key_press(event, KeyState::Released)?, - ffi::XCB_INPUT_HIERARCHY => self.handle_input_hierarchy(event)?, - _ => {} - } - Ok(()) - } - - fn handle_input_button_press( - self: &Rc, - event: &ffi::xcb_ge_generic_event_t, - state: KeyState, - ) -> Result<(), XorgBackendError> { - let event = - unsafe { (event as *const _ as *const ffi::xcb_input_button_press_event_t).deref() }; - if let Some(seat) = self.mouse_seats.get(&event.deviceid) { - let button = event.detail; - // let button = seat.button_map.get(&event.detail).unwrap_or(event.detail); - if matches!(button, 4..=7) { - if state == KeyState::Pressed { - let (axis, val) = match button { - 4 => (ScrollAxis::Vertical, -15), - 5 => (ScrollAxis::Vertical, 15), - 6 => (ScrollAxis::Horizontal, -15), - 7 => (ScrollAxis::Horizontal, 15), - _ => unreachable!(), - }; - seat.mouse_event(InputEvent::Scroll(val, axis)); - } - } else { - const BTN_LEFT: u32 = 0x110; - const BTN_RIGHT: u32 = 0x111; - const BTN_MIDDLE: u32 = 0x112; - const BTN_SIDE: u32 = 0x113; - let button = match button { - 0 => return Ok(()), - 1 => BTN_LEFT, - 2 => BTN_MIDDLE, - 3 => BTN_RIGHT, - n => BTN_SIDE + n - 8, - }; - seat.mouse_event(InputEvent::Button(button, state)); - } - } - Ok(()) - } - - fn handle_input_key_press( - self: &Rc, - event: &ffi::xcb_ge_generic_event_t, - state: KeyState, - ) -> Result<(), XorgBackendError> { - if state == KeyState::Pressed { - let mut rng = rand::thread_rng(); - self.r.set(rng.gen_range(0.0..1.0)); - self.g.set(rng.gen_range(0.0..1.0)); - self.b.set(rng.gen_range(0.0..1.0)); - } - let event = - unsafe { (event as *const _ as *const ffi::xcb_input_key_press_event_t).deref() }; - if let Some(seat) = self.seats.get(&event.deviceid) { - seat.kb_event(InputEvent::Key(event.detail - 8, state)); - } - Ok(()) - } - - fn handle_input_hierarchy( - self: &Rc, - 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 { - if let Err(e) = self.query_devices(info.deviceid) { - log::error!("Could not query device {}: {:#}", info.deviceid, e); - } - } 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.kb_changed(); - seat.mouse_changed(); - } - } - } - Ok(()) - } - - fn handle_input_enter( - &self, - event: &ffi::xcb_ge_generic_event_t, - ) -> Result<(), XorgBackendError> { - let event = unsafe { (event as *const _ as *const ffi::xcb_input_enter_event_t).deref() }; - if let (Some(win), Some(seat)) = ( - self.outputs.get(&event.event), - self.mouse_seats.get(&event.deviceid), - ) { - seat.mouse_event(InputEvent::OutputPosition( - win.id, - Fixed::from_1616(event.event_x), - Fixed::from_1616(event.event_y), - )); - } - Ok(()) - } - - fn handle_input_motion( - &self, - event: &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, seat) = match ( - self.outputs.get(&event.event), - self.mouse_seats.get(&event.deviceid), - ) { - (Some(a), Some(b)) => (a, b), - _ => return Ok(()), - }; - seat.mouse_event(InputEvent::OutputPosition( - win.id, - Fixed::from_1616(event.event_x), - Fixed::from_1616(event.event_y), - )); - Ok(()) - } - - fn handle_destroy(&self, event: &ffi::xcb_generic_event_t) -> Result<(), XorgBackendError> { - self.state.el.stop(); - 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.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 i32; - let height = event.height as i32; - let mut changed = false; - changed |= output.width.replace(width) != width; - changed |= output.height.replace(height) != height; - if changed { - unsafe { - let images = self.create_images(output.window, width, height).unwrap(); - for (new, old) in images.iter().zip(output.images.iter()) { - self.con.xcb.xcb_free_pixmap(self.con.c, old.pixmap.get()); - old.fb.set(new.fb.get()); - old.pixmap.set(new.pixmap.get()); - } - } - output.changed(); - } - Ok(()) - } -} - -impl EventLoopDispatcher for XorgBackend { - fn dispatch(self: Rc, events: i32) -> Result<(), Box> { - 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) -> Result<(), Box> { - 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, - window: ffi::xcb_window_t, - removed: Cell, - width: Cell, - height: Cell, - serial: NumCell, - next_msc: Cell, - next_image: NumCell, - images: [XorgImage; 2], - cb: CloneCell>>, -} - -struct XorgImage { - pixmap: Cell, - fb: CloneCell>, - idle: Cell, - render_on_idle: Cell, - last_serial: Cell, -} - -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.get() { - cb(); - } - } -} - -impl Output for XorgOutput { - fn id(&self) -> OutputId { - self.id - } - - fn removed(&self) -> bool { - self.removed.get() - } - - fn width(&self) -> i32 { - self.width.get() - } - - fn height(&self) -> i32 { - self.height.get() - } - - fn on_change(&self, cb: Rc) { - self.cb.set(Some(cb)); - } -} - -struct XorgSeat { - kb_id: InputDeviceId, - mouse_id: InputDeviceId, - backend: Rc, - kb: ffi::xcb_input_device_id_t, - mouse: ffi::xcb_input_device_id_t, - removed: Cell, - kb_cb: CloneCell>>, - mouse_cb: CloneCell>>, - kb_events: RefCell>, - mouse_events: RefCell>, - button_map: CopyHashMap, -} - -struct XorgSeatKeyboard(Rc); - -struct XorgSeatMouse(Rc); - -impl XorgSeat { - fn kb_changed(&self) { - if let Some(cb) = self.kb_cb.get() { - cb(); - } - } - - fn mouse_changed(&self) { - if let Some(cb) = self.mouse_cb.get() { - cb(); - } - } - - fn mouse_event(&self, event: InputEvent) { - self.mouse_events.borrow_mut().push_back(event); - self.mouse_changed(); - } - - fn kb_event(&self, event: InputEvent) { - self.kb_events.borrow_mut().push_back(event); - self.kb_changed(); - } - - fn update_button_map(&self) { - self.button_map.clear(); - unsafe { - let con = &self.backend.con; - let mut err = ptr::null_mut(); - let reply = con.input.xcb_input_get_device_button_mapping_reply( - con.c, - con.input - .xcb_input_get_device_button_mapping(con.c, self.mouse as _), - &mut err, - ); - let reply = match con.check(reply, err) { - Ok(r) => r, - Err(e) => { - log::error!( - "Could not get Xinput button map of device {}: {:#}", - self.mouse, - e - ); - return; - } - }; - let map = std::slice::from_raw_parts( - con.input.xcb_input_get_device_button_mapping_map(&*reply), - reply.map_size as _, - ); - for (i, map) in map.iter().copied().enumerate().rev() { - self.button_map.set(map as u32, i as u32 + 1); - } - } - } -} - -impl InputDevice for XorgSeatKeyboard { - fn id(&self) -> InputDeviceId { - self.0.kb_id - } - - fn removed(&self) -> bool { - self.0.removed.get() - } - - fn event(&self) -> Option { - self.0.kb_events.borrow_mut().pop_front() - } - - fn on_change(&self, cb: Rc) { - self.0.kb_cb.set(Some(cb)); - } - - fn grab(&self, grab: bool) { - unsafe { - let con = &self.0.backend.con; - let mut err = ptr::null_mut(); - if grab { - let res = con.input.xcb_input_xi_grab_device( - con.c, - con.screen.root, - 0, - 0, - self.0.kb, - ffi::XCB_GRAB_MODE_ASYNC as _, - ffi::XCB_GRAB_MODE_ASYNC as _, - 1, - 0, - ptr::null(), - ); - let res = con - .input - .xcb_input_xi_grab_device_reply(con.c, res, &mut err); - let res = match con.check(res, err) { - Ok(r) => r, - Err(e) => { - log::error!("Could not grab device {}: {}", self.0.kb, ErrorFmt(e)); - return; - } - }; - if res.status != ffi::XCB_GRAB_STATUS_SUCCESS as _ { - log::error!( - "Could not grab device {}: status = {}", - self.0.kb, - res.status - ); - } - } else { - let cookie = con - .input - .xcb_input_xi_ungrab_device_checked(con.c, 0, self.0.kb); - if let Err(e) = con.check_cookie(cookie) { - log::error!("Could not ungrab device {}: {}", self.0.kb, ErrorFmt(e)); - } - } - } - } -} - -impl InputDevice for XorgSeatMouse { - fn id(&self) -> InputDeviceId { - self.0.mouse_id - } - - fn removed(&self) -> bool { - self.0.removed.get() - } - - fn event(&self) -> Option { - self.0.mouse_events.borrow_mut().pop_front() - } - - fn on_change(&self, cb: Rc) { - self.0.mouse_cb.set(Some(cb)); - } - - fn grab(&self, _grab: bool) { - log::error!("Cannot grab xorg mouse"); - } -} diff --git a/src/backends/xorgng.rs b/src/backends/xorgng.rs index c3a3c6a3..8e64892f 100644 --- a/src/backends/xorgng.rs +++ b/src/backends/xorgng.rs @@ -191,7 +191,7 @@ impl XorgngBackend { let cc = CreateCursor { cid: c.generate_id()?, source: cp.pid, - mask: 0, + mask: cp.pid, fore_red: 0, fore_green: 0, fore_blue: 0, @@ -204,6 +204,7 @@ impl XorgngBackend { if let Err(e) = c.call(&cc).await { return Err(XorgngBackendError::CreateCursor(e)); } + c.call(&FreePixmap { pixmap: cp.pid }); cc.cid }; { @@ -230,7 +231,7 @@ impl XorgngBackend { cursor, root, scheduled_present: Default::default(), - grab_requests: Default::default() + grab_requests: Default::default(), }); data.add_output().await?; data.query_devices(INPUT_DEVICE_ALL_MASTER).await?; @@ -256,7 +257,10 @@ impl XorgngBackendData { loop { let event = self.c.event().await; if let Err(e) = self.handle_event(&event).await { - log::error!("Fatal error: Could not handle an event from the X server: {}", ErrorFmt(e)); + log::error!( + "Fatal error: Could not handle an event from the X server: {}", + ErrorFmt(e) + ); self.state.el.stop(); return; } diff --git a/src/tasks/start_backend.rs b/src/tasks/start_backend.rs index b0d701f7..e0f44ff3 100644 --- a/src/tasks/start_backend.rs +++ b/src/tasks/start_backend.rs @@ -1,7 +1,7 @@ +use crate::backends::xorgng::XorgngBackend; use crate::{metal, ErrorFmt, State}; use std::future::pending; use std::rc::Rc; -use crate::backends::xorgng::XorgngBackend; pub async fn start_backend(state: Rc) { log::info!("Trying to start X backend"); @@ -13,9 +13,7 @@ pub async fn start_backend(state: Rc) { // Err(e) => e, // }; let e = match XorgngBackend::run(&state).await { - Ok(_) => { - pending().await - }, + Ok(_) => pending().await, Err(e) => e, }; log::warn!("Could not start X backend: {}", ErrorFmt(e)); diff --git a/src/xcon/consts.rs b/src/xcon/consts.rs index e80b9f52..2f730bb6 100644 --- a/src/xcon/consts.rs +++ b/src/xcon/consts.rs @@ -101,3 +101,7 @@ pub const GRAB_STATUS_ALREADY_GRABBED: u8 = 1; pub const GRAB_STATUS_INVALID_TIME: u8 = 2; pub const GRAB_STATUS_NOT_VIEWABLE: u8 = 3; pub const GRAB_STATUS_FROZEN: u8 = 4; + +pub const IMAGE_FORMAT_XY_BITMAP: u8 = 0; +pub const IMAGE_FORMAT_XY_PIXMAP: u8 = 1; +pub const IMAGE_FORMAT_Z_PIXMAP: u8 = 2; diff --git a/wire-xcon/xproto.txt b/wire-xcon/xproto.txt index 39edb829..00ae99c5 100644 --- a/wire-xcon/xproto.txt +++ b/wire-xcon/xproto.txt @@ -235,6 +235,7 @@ request PutImage = 72 ( depth: u8, @pad 2, data: list(u8), + @align 4, ); request CreateCursor = 93 (