From c340df0d08d9990c35708a8c62bb12fcaad8935f Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Tue, 25 Jan 2022 16:45:44 +0100 Subject: [PATCH] autocommit 2022-01-25 16:45:44 CET --- Cargo.toml | 2 +- build.rs | 1 + src/async_engine.rs | 2 +- src/backend.rs | 4 +- src/backends/xorg/mod.rs | 208 +++---- src/client/mod.rs | 113 ++-- src/client/objects.rs | 6 +- src/client/tasks.rs | 18 +- src/globals.rs | 87 +-- src/ifs/wl_buffer/mod.rs | 33 +- src/ifs/wl_callback/mod.rs | 2 +- src/ifs/wl_compositor/mod.rs | 14 +- src/ifs/wl_data_device/mod.rs | 18 +- src/ifs/wl_data_device_manager/mod.rs | 17 +- src/ifs/wl_data_offer/mod.rs | 26 +- src/ifs/wl_data_source/mod.rs | 18 +- src/ifs/wl_display/mod.rs | 19 +- src/ifs/wl_output/mod.rs | 63 +- src/ifs/wl_region/mod.rs | 18 +- src/ifs/wl_registry/mod.rs | 8 +- src/ifs/wl_seat/mod.rs | 425 +++++++------ src/ifs/wl_seat/wl_keyboard/mod.rs | 12 +- src/ifs/wl_seat/wl_pointer/mod.rs | 14 +- src/ifs/wl_seat/wl_touch/mod.rs | 13 +- src/ifs/wl_shm/mod.rs | 24 +- src/ifs/wl_shm_pool/mod.rs | 24 +- src/ifs/wl_subcompositor/mod.rs | 16 +- src/ifs/wl_surface/mod.rs | 560 +++++++++--------- src/ifs/wl_surface/types.rs | 13 + src/ifs/wl_surface/wl_subsurface/mod.rs | 302 ++++++---- src/ifs/wl_surface/wl_subsurface/types.rs | 7 +- src/ifs/wl_surface/xdg_surface/mod.rs | 291 +++++---- src/ifs/wl_surface/xdg_surface/types.rs | 17 +- .../wl_surface/xdg_surface/xdg_popup/mod.rs | 47 +- .../xdg_surface/xdg_toplevel/mod.rs | 345 +++++++++-- src/ifs/xdg_positioner/mod.rs | 46 +- src/ifs/xdg_wm_base/mod.rs | 24 +- src/macros.rs | 68 ++- src/main.rs | 9 +- src/object.rs | 8 +- src/pixman/mod.rs | 74 ++- src/rect.rs | 115 ++++ src/render/mod.rs | 28 + src/render/pixman.rs | 203 +++++++ src/render/util.rs | 0 src/state.rs | 27 +- src/tasks.rs | 141 ----- src/tasks/backend.rs | 55 ++ src/tasks/mod.rs | 19 + src/tasks/output.rs | 66 +++ src/tasks/seat.rs | 52 ++ src/tasks/slow_clients.rs | 15 + src/tree.rs | 222 ------- src/tree/container.rs | 347 +++++++++++ src/tree/mod.rs | 299 ++++++++++ src/tree/workspace.rs | 67 +++ src/utils/clonecell.rs | 3 + src/utils/linkedlist.rs | 113 +++- src/utils/numcell.rs | 7 +- 59 files changed, 3085 insertions(+), 1710 deletions(-) create mode 100644 src/rect.rs create mode 100644 src/render/mod.rs create mode 100644 src/render/pixman.rs create mode 100644 src/render/util.rs delete mode 100644 src/tasks.rs create mode 100644 src/tasks/backend.rs create mode 100644 src/tasks/mod.rs create mode 100644 src/tasks/output.rs create mode 100644 src/tasks/seat.rs create mode 100644 src/tasks/slow_clients.rs delete mode 100644 src/tree.rs create mode 100644 src/tree/container.rs create mode 100644 src/tree/mod.rs create mode 100644 src/tree/workspace.rs diff --git a/Cargo.toml b/Cargo.toml index ad750985..3d6b242b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ 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-dl-util = { version = "0.2.0", features = ["xcb_shm", "xcb_xinput", "xcb_xkb", "xcb_dri3", "xcb_present"]} libloading = "0.7.2" bstr = "0.2.17" isnt = "0.1.0" diff --git a/build.rs b/build.rs index 1035b01d..d1ee26be 100644 --- a/build.rs +++ b/build.rs @@ -53,6 +53,7 @@ fn get_enum_ty(variants: Vec) -> anyhow::Result { fn write_ty(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, "#[allow(dead_code)]")?; writeln!(f, "pub type {} = u{};", ty, size)?; Ok(()) } diff --git a/src/async_engine.rs b/src/async_engine.rs index 4eb7a6c7..d3c01fc2 100644 --- a/src/async_engine.rs +++ b/src/async_engine.rs @@ -480,7 +480,7 @@ mod queue { } pub fn iteration(&self) -> u64 { - self.iteration.load() + self.iteration.get() } } } diff --git a/src/backend.rs b/src/backend.rs index e5fb9901..36170db6 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -7,8 +7,8 @@ linear_ids!(SeatIds, SeatId); pub trait Output { fn id(&self) -> OutputId; fn removed(&self) -> bool; - fn width(&self) -> u32; - fn height(&self) -> u32; + fn width(&self) -> i32; + fn height(&self) -> i32; fn on_change(&self, cb: Rc); } diff --git a/src/backends/xorg/mod.rs b/src/backends/xorg/mod.rs index 9828dca3..852fbbe0 100644 --- a/src/backends/xorg/mod.rs +++ b/src/backends/xorg/mod.rs @@ -3,11 +3,11 @@ use crate::backend::{ }; use crate::event_loop::{EventLoopDispatcher, EventLoopId}; use crate::fixed::Fixed; -use crate::ifs::wl_buffer::WlBuffer; -use crate::ifs::wl_surface::WlSurface; use crate::pixman::{Image, PixmanError}; +use crate::render::pixman::PixmanRenderer; +use crate::render::Renderer; use crate::servermem::{ServerMem, ServerMemError}; -use crate::tree::{Node, NodeKind, ToplevelNode}; +use crate::tree::Node; use crate::utils::clonecell::CloneCell; use crate::utils::copyhashmap::CopyHashMap; use crate::utils::ptr_ext::PtrExt; @@ -22,7 +22,7 @@ use std::ptr; use std::rc::Rc; use thiserror::Error; use uapi::c; -use xcb_dl::{ffi, Xcb, XcbShm, XcbXinput, XcbXkb}; +use xcb_dl::{ffi, Xcb, XcbDri3, XcbPresent, XcbShm, XcbXinput, XcbXkb}; use xcb_dl_util::error::{XcbError, XcbErrorParser}; use xcb_dl_util::xcb_box::XcbBox; @@ -32,6 +32,8 @@ pub enum XorgBackendError { ErrorEvent, #[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")] @@ -66,7 +68,10 @@ struct XcbCon { xcb: Box, shm: Box, input: Box, + dri: Box, + present: Box, input_opcode: u8, + present_opcode: u8, xkb: Box, c: *mut ffi::xcb_connection_t, errors: XcbErrorParser, @@ -79,6 +84,7 @@ impl XcbCon { let shm = Box::new(XcbShm::load_loose()?); let input = Box::new(XcbXinput::load_loose()?); let xkb = Box::new(XcbXkb::load_loose()?); + let dri = Box::new(XcbDri3::load_loose()?); let c = xcb.xcb_connect(ptr::null(), ptr::null_mut()); let errors = XcbErrorParser::new(&xcb, c); @@ -87,7 +93,9 @@ impl XcbCon { xcb, shm, input, + dri, input_opcode: 0, + present_opcode: 0, xkb, c, errors, @@ -115,6 +123,26 @@ impl XcbCon { 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 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), @@ -286,7 +314,8 @@ impl XorgBackend { } } { - let mask = ffi::XCB_INPUT_XI_EVENT_MASK_MOTION + 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 @@ -309,6 +338,20 @@ impl XorgBackend { 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 @@ -382,7 +425,6 @@ impl XorgBackend { cb: CloneCell::new(None), events: RefCell::new(Default::default()), button_map: Default::default(), - last_position: Cell::new((0, 0)), }); seat.update_button_map(); self.seats.set(info.deviceid, seat.clone()); @@ -428,10 +470,39 @@ impl XorgBackend { 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 output = match self.outputs.get(&event.window) { + Some(o) => o, + _ => return Ok(()), + }; + output.next_msc.set(event.msc + 1); + Ok(()) + } + fn handle_input_event( self: &Rc, event: &ffi::xcb_ge_generic_event_t, @@ -541,7 +612,6 @@ impl XorgBackend { self.outputs.get(&event.event), self.mouse_seats.get(&event.deviceid), ) { - seat.last_position.set((event.event_x, event.event_y)); seat.event(SeatEvent::OutputPosition( win.id, Fixed::from_1616(event.event_x), @@ -556,17 +626,15 @@ impl XorgBackend { 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 seat = match self.mouse_seats.get(&event.deviceid) { - Some(s) => s, + let (win, seat) = match (self.outputs.get(&event.event), self.mouse_seats.get(&event.deviceid)) { + (Some(a), Some(b)) => (a, b), _ => return Ok(()), }; - let pos = (event.event_x, event.event_y); - let last_pos = seat.last_position.replace(pos); - if pos != last_pos { - let dx = Fixed::from_1616(pos.0 - last_pos.0); - let dy = Fixed::from_1616(pos.1 - last_pos.1); - seat.event(SeatEvent::Motion(dx, dy)); - } + seat.event(SeatEvent::OutputPosition( + win.id, + Fixed::from_1616(event.event_x), + Fixed::from_1616(event.event_y), + )); Ok(()) } @@ -593,8 +661,8 @@ impl XorgBackend { 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; + changed |= output.width.replace(width as i32) != width as i32; + changed |= output.height.replace(height as i32) != height as i32; if changed { let shm = Rc::new(ServerMem::new((width * height * 4) as usize)?); let fd = shm.fd(); @@ -639,83 +707,6 @@ impl XorgBackend { Ok(()) } - fn render_node(&self, image: &Image>, node: Rc) { - match node.into_kind() { - NodeKind::Display(_) => {} - NodeKind::Output(_) => {} - NodeKind::Toplevel(tl) => self.render_toplevel(image, &tl), - NodeKind::Container(_) => {} - } - } - - fn render_toplevel(&self, image: &Image>, tl: &Rc) { - let surface = &tl.surface.surface.surface; - let node_extents = tl.common.extents.get(); - let surface_extents = tl.surface.surface.surface.effective_extents.get(); - self.render_surface( - image, - surface, - node_extents.x - surface_extents.x1, - node_extents.y - surface_extents.y1, - ); - let _ = image.fill_insert_border( - 255, - 0, - 0, - 255, - node_extents.x, - node_extents.y, - node_extents.x + node_extents.width as i32, - node_extents.y + node_extents.height as i32, - 2, - ); - } - - fn render_surface( - &self, - image: &Image>, - surface: &Rc, - 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); - } - } - } - if let Some(buffer) = surface.buffer.get() { - 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>, buffer: &Rc, x: i32, y: i32) { - if let Err(e) = image.add_image(&buffer.image, x, y) { - let client = &buffer.client; - log::error!("Could not access client {} memory: {:#}", client.id, e); - if let Ok(d) = client.display() { - client.fatal_event( - d.implementation_error(format!("Could not access memory: {:#}", e)), - ); - } else { - self.state.clients.kill(client.id); - } - } - } - fn render(&self) -> Result<(), XorgBackendError> { let outputs = self.outputs.lock(); for output in outputs.values() { @@ -729,8 +720,15 @@ impl XorgBackend { Some(n) => n, _ => continue, }; - for floating in node.floating.iter() { - self.render_node(image, floating.clone()); + let pos = node.position.get(); + let mut renderer = PixmanRenderer::new(image); + renderer.render_output(&node); + for floating in self.state.root.floaters.iter() { + let fpos = floating.position.get(); + if floating.visible.get() && fpos.intersects(&pos) { + let (x, y) = pos.translate(fpos.x1(), fpos.x2()); + floating.render(&mut renderer, x, y); + } } unsafe { let cookie = @@ -774,12 +772,19 @@ struct XorgOutput { backend: Rc, window: ffi::xcb_window_t, removed: Cell, - width: Cell, - height: Cell, + width: Cell, + height: Cell, + next_msc: Cell, + next_image: Cell, + // images: [XorgImage; 2], image: RefCell>>>, cb: CloneCell>>, } +struct XorgImage { + +} + impl Drop for XorgOutput { fn drop(&mut self) { unsafe { @@ -806,11 +811,11 @@ impl Output for XorgOutput { self.removed.get() } - fn width(&self) -> u32 { + fn width(&self) -> i32 { self.width.get() } - fn height(&self) -> u32 { + fn height(&self) -> i32 { self.height.get() } @@ -828,7 +833,6 @@ struct XorgSeat { cb: CloneCell>>, events: RefCell>, button_map: CopyHashMap, - last_position: Cell<(ffi::xcb_input_fp1616_t, ffi::xcb_input_fp1616_t)>, } impl XorgSeat { diff --git a/src/client/mod.rs b/src/client/mod.rs index 9171d532..f4c18934 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -35,7 +35,6 @@ use crate::ErrorFmt; use ahash::AHashMap; use std::cell::{Cell, RefCell, RefMut}; use std::fmt::{Debug, Display, Formatter}; -use std::future::Future; use std::mem; use std::rc::Rc; use thiserror::Error; @@ -60,8 +59,6 @@ pub enum ClientError { MessageSizeTooSmall, #[error("The size of the message is not a multiple of 4")] UnalignedMessage, - #[error("The outgoing buffer overflowed")] - OutBufferOverflow, #[error("The requested client {0} does not exist")] ClientDoesNotExist(ClientId), #[error("There is no wl_region with id {0}")] @@ -204,6 +201,7 @@ impl Clients { ClientId(self.next_client_id.fetch_add(1)) } + #[allow(dead_code)] pub fn get(&self, id: ClientId) -> Result, ClientError> { let clients = self.clients.borrow(); match clients.get(&id) { @@ -239,6 +237,7 @@ impl Clients { let data = Rc::new(Client { id, state: global.clone(), + checking_queue_size: Cell::new(false), socket: global.eng.fd(&Rc::new(socket))?, objects: Objects::new(), events: AsyncQueue::new(), @@ -332,6 +331,7 @@ pub enum WlEvent { pub struct Client { pub id: ClientId, pub state: Rc, + checking_queue_size: Cell, socket: AsyncFd, pub objects: Objects, events: AsyncQueue, @@ -401,39 +401,33 @@ impl Client { self.state.clients.shutdown(self.id); } - pub fn event_locked(&self, event: Box) -> bool { - self.events.push(WlEvent::Event(event)); - self.events.size() > MAX_PENDING_EVENTS + pub fn event(self: &Rc, event: Box) { + self.event2(WlEvent::Event(event)); } - pub async fn event(&self, event: Box) -> Result<(), ClientError> { - self.event2(WlEvent::Event(event)).await + pub fn flush(self: &Rc) { + self.event2(WlEvent::Flush); } - pub async fn flush(&self) -> Result<(), ClientError> { - self.event2(WlEvent::Flush).await - } - - async fn event2(&self, event: WlEvent) -> Result<(), ClientError> { + pub fn event2(self: &Rc, event: WlEvent) { self.events.push(event); - self.check_queue_size().await + if self.events.size() > MAX_PENDING_EVENTS { + if !self.checking_queue_size.replace(true) { + self.state.slow_clients.push(self.clone()); + } + } } - 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> { + pub async fn check_queue_size(&self) { if self.events.size() > MAX_PENDING_EVENTS { self.state.eng.yield_now().await; if self.events.size() > MAX_PENDING_EVENTS { log::error!("Client {} is too slow at fetching events", self.id.0); self.state.clients.kill(self.id); - return Err(ClientError::OutBufferOverflow); + return; } } - Ok(()) + self.checking_queue_size.set(false); } pub fn get_buffer(&self, id: WlBufferId) -> Result, ClientError> { @@ -471,22 +465,6 @@ impl Client { } } - fn simple_add_obj(&self, obj: &Rc, client: bool) -> Result<(), ClientError> { - if client { - self.objects.add_client_object(obj.clone()) - } else { - self.objects.add_server_object(obj.clone()); - Ok(()) - } - } - - fn simple_remove_obj<'a>( - &'a self, - id: ObjectId, - ) -> impl Future> + 'a { - self.objects.remove_obj(self, id) - } - pub fn lock_registries(&self) -> RefMut>> { self.objects.registries() } @@ -501,36 +479,44 @@ impl Client { event, ); } -} -pub trait AddObj { - type RemoveObj<'a>: Future> + 'a; - - fn add_client_obj(&self, obj: &Rc) -> Result<(), ClientError> { + pub fn add_client_obj(&self, obj: &Rc) -> Result<(), ClientError> { self.add_obj(obj, true) } - fn add_server_obj(&self, obj: &Rc) { + #[allow(dead_code)] + pub fn add_server_obj(&self, obj: &Rc) { self.add_obj(obj, false).expect("add_server_obj failed") } - fn add_obj(&self, obj: &Rc, client: bool) -> Result<(), ClientError>; + fn add_obj(&self, obj: &Rc, client: bool) -> Result<(), ClientError> { + if client { + self.objects.add_client_object(obj.clone())?; + } else { + self.objects.add_server_object(obj.clone()); + } + obj.clone().add(self); + Ok(()) + } - fn remove_obj<'a>(&'a self, obj: &'a T) -> Self::RemoveObj<'a>; + pub fn remove_obj(self: &Rc, obj: &T) -> Result<(), ClientError> { + obj.remove(self); + self.objects.remove_obj(self, obj.id()) + } +} + +pub trait WaylandObject: Object { + fn add(self: Rc, client: &Client) { + let _ = client; + } + fn remove(&self, client: &Client) { + let _ = client; + } } macro_rules! simple_add_obj { ($ty:ty) => { - impl AddObj<$ty> for Client { - type RemoveObj<'a> = impl Future> + 'a; - - fn add_obj(&self, obj: &Rc<$ty>, client: bool) -> Result<(), ClientError> { - self.simple_add_obj(obj, client) - } - fn remove_obj<'a>(&'a self, obj: &'a $ty) -> Self::RemoveObj<'a> { - self.simple_remove_obj(obj.id()) - } - } + impl WaylandObject for $ty {} }; } @@ -555,17 +541,12 @@ simple_add_obj!(WlDataSource); macro_rules! dedicated_add_obj { ($ty:ty, $field:ident) => { - impl AddObj<$ty> for Client { - type RemoveObj<'a> = impl Future> + 'a; - - fn add_obj(&self, obj: &Rc<$ty>, client: bool) -> Result<(), ClientError> { - self.simple_add_obj(obj, client)?; - self.objects.$field.set(obj.id().into(), obj.clone()); - Ok(()) + impl WaylandObject for $ty { + fn add(self: Rc, client: &Client) { + client.objects.$field.set(self.id().into(), self); } - fn remove_obj<'a>(&'a self, obj: &'a $ty) -> Self::RemoveObj<'a> { - self.objects.$field.remove(&obj.id().into()); - self.simple_remove_obj(obj.id()) + fn remove(&self, client: &Client) { + client.objects.$field.remove(&self.id().into()); } } }; diff --git a/src/client/objects.rs b/src/client/objects.rs index 3eb0bc5a..452d356c 100644 --- a/src/client/objects.rs +++ b/src/client/objects.rs @@ -114,7 +114,7 @@ impl Objects { Ok(()) } - pub async fn remove_obj(&self, client_data: &Client, id: ObjectId) -> Result<(), ClientError> { + pub fn remove_obj(&self, client_data: &Rc, id: ObjectId) -> Result<(), ClientError> { let _obj = match self.registry.remove(&id) { Some(o) => o, _ => return Err(ClientError::UnknownId), @@ -129,9 +129,7 @@ impl Objects { } ids[pos] |= 1 << seg_offset; } - client_data - .event(client_data.display()?.delete_id(id)) - .await?; + client_data.event(client_data.display()?.delete_id(id)); Ok(()) } diff --git a/src/client/tasks.rs b/src/client/tasks.rs index e8650a0f..656cb5cd 100644 --- a/src/client/tasks.rs +++ b/src/client/tasks.rs @@ -1,4 +1,4 @@ -use crate::client::{AddObj, Client, ClientError, WlEvent}; +use crate::client::{Client, ClientError, WlEvent}; use crate::object::ObjectId; use crate::utils::buffd::{BufFdIn, BufFdOut, MsgFormatter, MsgParser}; use crate::utils::oneshot::OneshotRx; @@ -38,11 +38,8 @@ async fn dispatch_fr(data: Rc) { 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: {}", ErrorFmt(e)); - return; - } - if let Err(e) = data.remove_obj(&*fr).await { + data.event(fr.done()); + if let Err(e) = data.remove_obj(&*fr) { log::error!("Could not remove frame object: {}", ErrorFmt(e)); return; } @@ -51,10 +48,7 @@ async fn dispatch_fr(data: Rc) { _ => break, }; } - if let Err(e) = data.event2(WlEvent::Flush).await { - log::error!("Could not dispatch frame event: {}", ErrorFmt(e)); - return; - } + data.flush(); } } @@ -97,10 +91,10 @@ async fn receive(data: Rc) { } // log::trace!("{:x?}", data_buf); let parser = MsgParser::new(&mut buf, &data_buf[..]); - if let Err(e) = obj.handle_request(request, parser).await { + if let Err(e) = obj.handle_request(request, parser) { return Err(ClientError::RequestError(Box::new(e))); } - data.event2(WlEvent::Flush).await?; + data.flush(); } }; let res: Result<(), ClientError> = recv.await; diff --git a/src/globals.rs b/src/globals.rs index 3df09bc3..a1349d2a 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -1,4 +1,4 @@ -use crate::client::{Client, ClientError, DynEventFormatter, WlEvent}; +use crate::client::{Client, DynEventFormatter}; use crate::ifs::wl_compositor::WlCompositorError; use crate::ifs::wl_data_device_manager::WlDataDeviceManagerError; use crate::ifs::wl_output::{WlOutputError, WlOutputGlobal}; @@ -13,10 +13,7 @@ use crate::{ NumCell, State, WlCompositorGlobal, WlDataDeviceManagerGlobal, WlShmGlobal, WlSubcompositorGlobal, XdgWmBaseGlobal, }; -use ahash::AHashSet; use std::fmt::{Display, Formatter}; -use std::future::Future; -use std::pin::Pin; use std::rc::Rc; use thiserror::Error; @@ -24,8 +21,6 @@ use thiserror::Error; pub enum GlobalError { #[error("The requested global {0} does not exist")] GlobalDoesNotExist(GlobalName), - #[error("An error occurred while trying to send all globals via a new registry")] - SendAllError(#[source] Box), #[error("An error occurred in a wl_compositor")] WlCompositorError(#[source] Box), #[error("An error occurred in a wl_shm")] @@ -81,7 +76,7 @@ pub trait GlobalBind { client: &'a Rc, id: ObjectId, version: u32, - ) -> Pin> + 'a>>; + ) -> Result<(), GlobalError>; } pub trait Global: GlobalBind { @@ -123,61 +118,44 @@ impl Globals { self.registry.set(global.name(), global.clone()); } - async fn insert<'a>(&'a self, state: &'a State, global: Rc) { + fn insert(&self, state: &State, global: Rc) { self.insert_no_broadcast_(&global); - self.broadcast(state, |r| r.global(&global)).await; + self.broadcast(state, |r| r.global(&global)); } pub fn get(&self, name: GlobalName) -> Result, GlobalError> { self.take(name, false) } - pub async fn remove(&self, state: &State, name: GlobalName) -> Result<(), GlobalError> { + pub fn remove(&self, state: &State, name: GlobalName) -> Result<(), GlobalError> { let _global = self.take(name, true)?; - self.broadcast(state, |r| r.global_remove(name)).await; + self.broadcast(state, |r| r.global_remove(name)); Ok(()) } - pub async fn notify_all( - &self, - client: &Client, - registry: &Rc, - ) -> Result<(), GlobalError> { + pub fn notify_all(&self, client: &Rc, registry: &Rc) { let globals = self.registry.lock(); macro_rules! emit { ($singleton:expr) => { for global in globals.values() { if global.singleton() == $singleton { - if let Err(e) = client.event(registry.global(global)).await { - return Err(GlobalError::SendAllError(Box::new(e))); - } + client.event(registry.global(global)); } } }; } emit!(true); emit!(false); - Ok(()) } - async fn broadcast) -> DynEventFormatter>(&self, state: &State, f: F) { - let mut clients_to_check = AHashSet::new(); + fn broadcast) -> DynEventFormatter>(&self, state: &State, f: F) { state.clients.broadcast(|c| { let registries = c.lock_registries(); for registry in registries.values() { - if c.event_locked(f(registry)) { - clients_to_check.insert(c.id); - } - } - if c.event2_locked(WlEvent::Flush) { - clients_to_check.insert(c.id); + c.event(f(registry)); } + c.flush(); }); - for client in clients_to_check.drain() { - if let Ok(c) = state.clients.get(client) { - let _ = c.check_queue_size().await; - } - } } fn take(&self, name: GlobalName, remove: bool) -> Result, GlobalError> { @@ -202,27 +180,17 @@ impl Globals { } pub trait AddGlobal { - type RemoveGlobal<'a>: Future> + 'a; - type AddGlobal<'a>: Future + 'a; - - fn add_global<'a>(&'a self, state: &'a State, global: &'a Rc) -> Self::AddGlobal<'a>; + fn add_global(&self, state: &State, global: &Rc); fn add_global_no_broadcast(&self, global: &Rc); - fn remove_global<'a>(&'a self, state: &'a State, global: &'a T) -> Self::RemoveGlobal<'a>; + fn remove_global(&self, state: &State, global: &T) -> Result<(), GlobalError>; } macro_rules! simple_add_global { ($ty:ty) => { impl AddGlobal<$ty> for Globals { - type RemoveGlobal<'a> = impl Future> + 'a; - type AddGlobal<'a> = impl Future + 'a; - - fn add_global<'a>( - &'a self, - state: &'a State, - global: &'a Rc<$ty>, - ) -> Self::AddGlobal<'a> { + fn add_global(&self, state: &State, global: &Rc<$ty>) { self.insert(state, global.clone()) } @@ -230,11 +198,7 @@ macro_rules! simple_add_global { self.insert_no_broadcast(global.clone()); } - fn remove_global<'a>( - &'a self, - state: &'a State, - global: &'a $ty, - ) -> Self::RemoveGlobal<'a> { + fn remove_global(&self, state: &State, global: &$ty) -> Result<(), GlobalError> { self.remove(state, global.name()) } } @@ -251,18 +215,9 @@ simple_add_global!(WlDataDeviceManagerGlobal); macro_rules! dedicated_add_global { ($ty:ty, $field:ident) => { impl AddGlobal<$ty> for Globals { - type RemoveGlobal<'a> = impl Future> + 'a; - type AddGlobal<'a> = impl Future + 'a; - - fn add_global<'a>( - &'a self, - state: &'a State, - global: &'a Rc<$ty>, - ) -> Self::AddGlobal<'a> { - async move { - self.insert(state, global.clone()).await; - self.$field.set(global.name(), global.clone()); - } + fn add_global(&self, state: &State, global: &Rc<$ty>) { + self.insert(state, global.clone()); + self.$field.set(global.name(), global.clone()); } fn add_global_no_broadcast(&self, global: &Rc<$ty>) { @@ -270,11 +225,7 @@ macro_rules! dedicated_add_global { self.$field.set(global.name(), global.clone()); } - fn remove_global<'a>( - &'a self, - state: &'a State, - global: &'a $ty, - ) -> Self::RemoveGlobal<'a> { + fn remove_global(&self, state: &State, global: &$ty) -> Result<(), GlobalError> { self.$field.remove(&global.name()); self.remove(state, global.name()) } diff --git a/src/ifs/wl_buffer/mod.rs b/src/ifs/wl_buffer/mod.rs index 9f991f78..0821016c 100644 --- a/src/ifs/wl_buffer/mod.rs +++ b/src/ifs/wl_buffer/mod.rs @@ -1,11 +1,12 @@ mod types; -use crate::client::{AddObj, Client, DynEventFormatter}; +use crate::client::{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::rect::Rect; use crate::utils::buffd::MsgParser; use crate::utils::copyhashmap::CopyHashMap; use std::rc::Rc; @@ -21,9 +22,8 @@ pub struct WlBuffer { id: WlBufferId, pub client: Rc, _offset: usize, - pub width: u32, - pub height: u32, - _stride: u32, + pub rect: Rect, + _stride: i32, _format: &'static Format, pub image: Rc>, pub(super) surfaces: CopyHashMap>, @@ -35,9 +35,9 @@ impl WlBuffer { id: WlBufferId, client: &Rc, offset: usize, - width: u32, - height: u32, - stride: u32, + width: i32, + height: i32, + stride: i32, format: &'static Format, mem: &Rc, ) -> Result { @@ -51,13 +51,18 @@ impl WlBuffer { if (stride as u64) < min_row_size { return Err(WlBufferError::StrideTooSmall); } - let image = pixman::Image::new(mem, format.pixman, width, height, stride)?; + let image = pixman::Image::new( + mem, + format.pixman, + width as u32, + height as u32, + stride as u32, + )?; Ok(Self { id, client: client.clone(), _offset: offset, - width, - height, + rect: Rect::new_sized(0, 0, width, height).unwrap(), _stride: stride, _format: format, image: Rc::new(image), @@ -65,7 +70,7 @@ impl WlBuffer { }) } - async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.client.parse(self, parser)?; { let surfaces = self.surfaces.lock(); @@ -73,17 +78,17 @@ impl WlBuffer { surface.buffer.set(None); } } - self.client.remove_obj(self).await?; + self.client.remove_obj(self)?; Ok(()) } - async fn handle_request_( + fn handle_request_( &self, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), WlBufferError> { match request { - DESTROY => self.destroy(parser).await?, + DESTROY => self.destroy(parser)?, _ => unreachable!(), } Ok(()) diff --git a/src/ifs/wl_callback/mod.rs b/src/ifs/wl_callback/mod.rs index c00bdfd4..aa336641 100644 --- a/src/ifs/wl_callback/mod.rs +++ b/src/ifs/wl_callback/mod.rs @@ -23,7 +23,7 @@ impl WlCallback { Box::new(Done { obj: self.clone() }) } - async fn handle_request_( + fn handle_request_( &self, _request: u32, _parser: MsgParser<'_, '_>, diff --git a/src/ifs/wl_compositor/mod.rs b/src/ifs/wl_compositor/mod.rs index 533ffa22..78543af8 100644 --- a/src/ifs/wl_compositor/mod.rs +++ b/src/ifs/wl_compositor/mod.rs @@ -1,6 +1,6 @@ mod types; -use crate::client::{AddObj, Client}; +use crate::client::Client; use crate::globals::{Global, GlobalName}; use crate::ifs::wl_region::WlRegion; use crate::ifs::wl_surface::WlSurface; @@ -29,7 +29,7 @@ impl WlCompositorGlobal { Self { name } } - async fn bind_( + fn bind_( self: Rc, id: WlCompositorId, client: &Rc, @@ -46,28 +46,28 @@ impl WlCompositorGlobal { } impl WlCompositorObj { - async fn create_surface(&self, parser: MsgParser<'_, '_>) -> Result<(), CreateSurfaceError> { + fn create_surface(&self, parser: MsgParser<'_, '_>) -> Result<(), CreateSurfaceError> { let surface: CreateSurface = self.client.parse(self, parser)?; let surface = Rc::new(WlSurface::new(surface.id, &self.client)); self.client.add_client_obj(&surface)?; Ok(()) } - async fn create_region(&self, parser: MsgParser<'_, '_>) -> Result<(), CreateRegionError> { + fn create_region(&self, parser: MsgParser<'_, '_>) -> Result<(), CreateRegionError> { let region: CreateRegion = self.client.parse(self, parser)?; let region = Rc::new(WlRegion::new(region.id, &self.client)); self.client.add_client_obj(®ion)?; Ok(()) } - async fn handle_request_( + fn handle_request_( &self, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), WlCompositorError> { match request { - CREATE_SURFACE => self.create_surface(parser).await?, - CREATE_REGION => self.create_region(parser).await?, + CREATE_SURFACE => self.create_surface(parser)?, + CREATE_REGION => self.create_region(parser)?, _ => unreachable!(), } Ok(()) diff --git a/src/ifs/wl_data_device/mod.rs b/src/ifs/wl_data_device/mod.rs index f11b8f63..c37f428b 100644 --- a/src/ifs/wl_data_device/mod.rs +++ b/src/ifs/wl_data_device/mod.rs @@ -1,6 +1,6 @@ mod types; -use crate::client::{AddObj, Client}; +use crate::client::Client; use crate::object::{Interface, Object, ObjectId}; use crate::utils::buffd::MsgParser; use std::rc::Rc; @@ -35,31 +35,31 @@ impl WlDataDevice { } } - async fn start_drag(&self, parser: MsgParser<'_, '_>) -> Result<(), StartDragError> { + fn start_drag(&self, parser: MsgParser<'_, '_>) -> Result<(), StartDragError> { let _req: StartDrag = self.client.parse(self, parser)?; Ok(()) } - async fn set_selection(&self, parser: MsgParser<'_, '_>) -> Result<(), SetSelectionError> { + fn set_selection(&self, parser: MsgParser<'_, '_>) -> Result<(), SetSelectionError> { let _req: SetSelection = self.client.parse(self, parser)?; Ok(()) } - async fn release(&self, parser: MsgParser<'_, '_>) -> Result<(), ReleaseError> { + fn release(&self, parser: MsgParser<'_, '_>) -> Result<(), ReleaseError> { let _req: Release = self.client.parse(self, parser)?; - self.client.remove_obj(self).await?; + self.client.remove_obj(self)?; Ok(()) } - async fn handle_request_( + fn handle_request_( self: &Rc, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), WlDataDeviceError> { match request { - START_DRAG => self.start_drag(parser).await?, - SET_SELECTION => self.set_selection(parser).await?, - RELEASE => self.release(parser).await?, + START_DRAG => self.start_drag(parser)?, + SET_SELECTION => self.set_selection(parser)?, + RELEASE => self.release(parser)?, _ => unreachable!(), } Ok(()) diff --git a/src/ifs/wl_data_device_manager/mod.rs b/src/ifs/wl_data_device_manager/mod.rs index 1cb59c74..2211bf4b 100644 --- a/src/ifs/wl_data_device_manager/mod.rs +++ b/src/ifs/wl_data_device_manager/mod.rs @@ -1,6 +1,6 @@ mod types; -use crate::client::{AddObj, Client}; +use crate::client::Client; use crate::globals::{Global, GlobalName}; use crate::ifs::wl_data_device::WlDataDevice; use crate::ifs::wl_data_source::WlDataSource; @@ -37,7 +37,7 @@ impl WlDataDeviceManagerGlobal { Self { name } } - async fn bind_( + fn bind_( self: Rc, id: WlDataDeviceManagerId, client: &Rc, @@ -53,31 +53,28 @@ impl WlDataDeviceManagerGlobal { } impl WlDataDeviceManagerObj { - async fn create_data_source( - &self, - parser: MsgParser<'_, '_>, - ) -> Result<(), CreateDataSourceError> { + fn create_data_source(&self, parser: MsgParser<'_, '_>) -> Result<(), CreateDataSourceError> { let req: CreateDataSource = self.client.parse(self, parser)?; let res = Rc::new(WlDataSource::new(req.id, &self.client)); self.client.add_client_obj(&res)?; Ok(()) } - async fn get_data_device(&self, parser: MsgParser<'_, '_>) -> Result<(), GetDataDeviceError> { + fn get_data_device(&self, parser: MsgParser<'_, '_>) -> Result<(), GetDataDeviceError> { let req: GetDataDevice = self.client.parse(self, parser)?; let res = Rc::new(WlDataDevice::new(req.id, &self.client)); self.client.add_client_obj(&res)?; Ok(()) } - async fn handle_request_( + fn handle_request_( self: &Rc, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), WlDataDeviceManagerError> { match request { - CREATE_DATA_SOURCE => self.create_data_source(parser).await?, - GET_DATA_DEVICE => self.get_data_device(parser).await?, + CREATE_DATA_SOURCE => self.create_data_source(parser)?, + GET_DATA_DEVICE => self.get_data_device(parser)?, _ => unreachable!(), } Ok(()) diff --git a/src/ifs/wl_data_offer/mod.rs b/src/ifs/wl_data_offer/mod.rs index 7d127557..87c368e0 100644 --- a/src/ifs/wl_data_offer/mod.rs +++ b/src/ifs/wl_data_offer/mod.rs @@ -1,6 +1,6 @@ mod types; -use crate::client::{AddObj, Client}; +use crate::client::Client; use crate::object::{Interface, Object, ObjectId}; use crate::utils::buffd::MsgParser; use std::rc::Rc; @@ -33,43 +33,43 @@ pub struct WlDataOffer { } impl WlDataOffer { - async fn accept(&self, parser: MsgParser<'_, '_>) -> Result<(), AcceptError> { + fn accept(&self, parser: MsgParser<'_, '_>) -> Result<(), AcceptError> { let _req: Accept = self.client.parse(self, parser)?; Ok(()) } - async fn receive(&self, parser: MsgParser<'_, '_>) -> Result<(), ReceiveError> { + fn receive(&self, parser: MsgParser<'_, '_>) -> Result<(), ReceiveError> { let _req: Receive = self.client.parse(self, parser)?; Ok(()) } - async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.client.parse(self, parser)?; - self.client.remove_obj(self).await?; + self.client.remove_obj(self)?; Ok(()) } - async fn finish(&self, parser: MsgParser<'_, '_>) -> Result<(), FinishError> { + fn finish(&self, parser: MsgParser<'_, '_>) -> Result<(), FinishError> { let _req: Finish = self.client.parse(self, parser)?; Ok(()) } - async fn set_actions(&self, parser: MsgParser<'_, '_>) -> Result<(), SetActionsError> { + fn set_actions(&self, parser: MsgParser<'_, '_>) -> Result<(), SetActionsError> { let _req: SetActions = self.client.parse(self, parser)?; Ok(()) } - async fn handle_request_( + fn handle_request_( self: &Rc, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), WlDataOfferError> { match request { - ACCEPT => self.accept(parser).await?, - RECEIVE => self.receive(parser).await?, - DESTROY => self.destroy(parser).await?, - FINISH => self.finish(parser).await?, - SET_ACTIONS => self.set_actions(parser).await?, + ACCEPT => self.accept(parser)?, + RECEIVE => self.receive(parser)?, + DESTROY => self.destroy(parser)?, + FINISH => self.finish(parser)?, + SET_ACTIONS => self.set_actions(parser)?, _ => unreachable!(), } Ok(()) diff --git a/src/ifs/wl_data_source/mod.rs b/src/ifs/wl_data_source/mod.rs index a914d22a..17b44231 100644 --- a/src/ifs/wl_data_source/mod.rs +++ b/src/ifs/wl_data_source/mod.rs @@ -1,6 +1,6 @@ mod types; -use crate::client::{AddObj, Client}; +use crate::client::Client; use crate::object::{Interface, Object, ObjectId}; use crate::utils::buffd::MsgParser; use std::rc::Rc; @@ -37,31 +37,31 @@ impl WlDataSource { } } - async fn offer(&self, parser: MsgParser<'_, '_>) -> Result<(), OfferError> { + fn offer(&self, parser: MsgParser<'_, '_>) -> Result<(), OfferError> { let _req: Offer = self.client.parse(self, parser)?; Ok(()) } - async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.client.parse(self, parser)?; - self.client.remove_obj(self).await?; + self.client.remove_obj(self)?; Ok(()) } - async fn set_actions(&self, parser: MsgParser<'_, '_>) -> Result<(), SetActionsError> { + fn set_actions(&self, parser: MsgParser<'_, '_>) -> Result<(), SetActionsError> { let _req: SetActions = self.client.parse(self, parser)?; Ok(()) } - async fn handle_request_( + fn handle_request_( self: &Rc, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), WlDataSourceError> { match request { - OFFER => self.offer(parser).await?, - DESTROY => self.destroy(parser).await?, - SET_ACTIONS => self.set_actions(parser).await?, + OFFER => self.offer(parser)?, + DESTROY => self.destroy(parser)?, + SET_ACTIONS => self.set_actions(parser)?, _ => unreachable!(), } Ok(()) diff --git a/src/ifs/wl_display/mod.rs b/src/ifs/wl_display/mod.rs index 4f58d989..bb0bb65b 100644 --- a/src/ifs/wl_display/mod.rs +++ b/src/ifs/wl_display/mod.rs @@ -1,6 +1,6 @@ mod types; -use crate::client::{AddObj, Client, DynEventFormatter}; +use crate::client::{Client, DynEventFormatter}; use crate::ifs::wl_callback::WlCallback; use crate::ifs::wl_registry::WlRegistry; use crate::object::{Interface, Object, ObjectId, WL_DISPLAY_ID}; @@ -31,37 +31,36 @@ impl WlDisplay { } } - async fn handle_request_( + fn handle_request_( &self, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), WlDisplayError> { match request { - SYNC => self.sync(parser).await?, - GET_REGISTRY => self.get_registry(parser).await?, + SYNC => self.sync(parser)?, + GET_REGISTRY => self.get_registry(parser)?, _ => unreachable!(), } Ok(()) } - async fn sync(&self, parser: MsgParser<'_, '_>) -> Result<(), SyncError> { + fn sync(&self, parser: MsgParser<'_, '_>) -> Result<(), SyncError> { let sync: Sync = self.client.parse(self, parser)?; let cb = Rc::new(WlCallback::new(sync.callback)); self.client.add_client_obj(&cb)?; - self.client.event(cb.done()).await?; - self.client.remove_obj(&*cb).await?; + self.client.event(cb.done()); + self.client.remove_obj(&*cb)?; Ok(()) } - async fn get_registry(&self, parser: MsgParser<'_, '_>) -> Result<(), GetRegistryError> { + fn get_registry(&self, parser: MsgParser<'_, '_>) -> Result<(), GetRegistryError> { let gr: GetRegistry = self.client.parse(self, parser)?; let registry = Rc::new(WlRegistry::new(gr.registry, &self.client)); self.client.add_client_obj(®istry)?; self.client .state .globals - .notify_all(&self.client, ®istry) - .await?; + .notify_all(&self.client, ®istry); Ok(()) } diff --git a/src/ifs/wl_output/mod.rs b/src/ifs/wl_output/mod.rs index 8df11623..def23383 100644 --- a/src/ifs/wl_output/mod.rs +++ b/src/ifs/wl_output/mod.rs @@ -1,12 +1,11 @@ mod types; use crate::backend::Output; -use crate::client::{AddObj, Client, ClientId, DynEventFormatter, WlEvent}; +use crate::client::{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; @@ -58,8 +57,8 @@ pub struct WlOutputGlobal { output: Rc, pub x: Cell, pub y: Cell, - width: Cell, - height: Cell, + width: Cell, + height: Cell, bindings: CopyHashMap<(ClientId, WlOutputId), Rc>, } @@ -76,7 +75,7 @@ impl WlOutputGlobal { } } - pub async fn update_properties(&self) { + pub fn update_properties(&self) { let width = self.output.width(); let height = self.output.height(); @@ -85,34 +84,26 @@ impl WlOutputGlobal { 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()); - } - } + 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 { + binding.client.event2(event); } } - for client in clients.values() { - let _ = client.check_queue_size().await; - } } } - async fn bind_( + fn bind_( self: Rc, id: WlOutputId, client: &Rc, @@ -126,13 +117,13 @@ impl WlOutputGlobal { }); 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.geometry()); + client.event(obj.mode()); if obj.send_scale() { - client.event(obj.scale()).await?; + client.event(obj.scale()); } if obj.send_done() { - client.event(obj.done()).await?; + client.event(obj.done()); } Ok(()) } @@ -213,20 +204,20 @@ impl WlOutputObj { Box::new(Done { obj: self.clone() }) } - async fn release(&self, parser: MsgParser<'_, '_>) -> Result<(), ReleaseError> { + 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?; + self.client.remove_obj(self)?; Ok(()) } - async fn handle_request_( + fn handle_request_( &self, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), WlOutputError> { match request { - RELEASE => self.release(parser).await?, + RELEASE => self.release(parser)?, _ => unreachable!(), } Ok(()) diff --git a/src/ifs/wl_region/mod.rs b/src/ifs/wl_region/mod.rs index 090f3c45..c382b5b6 100644 --- a/src/ifs/wl_region/mod.rs +++ b/src/ifs/wl_region/mod.rs @@ -1,6 +1,6 @@ mod types; -use crate::client::{AddObj, Client}; +use crate::client::Client; use crate::object::{Interface, Object, ObjectId}; use crate::pixman::Region; use crate::utils::buffd::MsgParser; @@ -33,13 +33,13 @@ impl WlRegion { self.rect.borrow().clone() } - async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _destroy: Destroy = self.client.parse(self, parser)?; - self.client.remove_obj(self).await?; + self.client.remove_obj(self)?; Ok(()) } - async fn add(&self, parser: MsgParser<'_, '_>) -> Result<(), AddError> { + fn add(&self, parser: MsgParser<'_, '_>) -> Result<(), AddError> { let add: Add = self.client.parse(self, parser)?; if add.width < 0 || add.height < 0 { return Err(AddError::NegativeExtents); @@ -49,7 +49,7 @@ impl WlRegion { Ok(()) } - async fn subtract(&self, parser: MsgParser<'_, '_>) -> Result<(), SubtractError> { + fn subtract(&self, parser: MsgParser<'_, '_>) -> Result<(), SubtractError> { let subtract: Subtract = self.client.parse(self, parser)?; if subtract.width < 0 || subtract.height < 0 { return Err(SubtractError::NegativeExtents); @@ -64,15 +64,15 @@ impl WlRegion { Ok(()) } - async fn handle_request_( + fn handle_request_( &self, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), WlRegionError> { match request { - DESTROY => self.destroy(parser).await?, - ADD => self.add(parser).await?, - SUBTRACT => self.subtract(parser).await?, + DESTROY => self.destroy(parser)?, + ADD => self.add(parser)?, + SUBTRACT => self.subtract(parser)?, _ => unreachable!(), } Ok(()) diff --git a/src/ifs/wl_registry/mod.rs b/src/ifs/wl_registry/mod.rs index 32e642f9..aee24a1d 100644 --- a/src/ifs/wl_registry/mod.rs +++ b/src/ifs/wl_registry/mod.rs @@ -41,7 +41,7 @@ impl WlRegistry { }) } - async fn bind(&self, parser: MsgParser<'_, '_>) -> Result<(), BindError> { + fn bind(&self, parser: MsgParser<'_, '_>) -> Result<(), BindError> { let bind: Bind = self.client.parse(self, parser)?; let global = self.client.state.globals.get(bind.name)?; if global.interface().name() != bind.interface { @@ -59,17 +59,17 @@ impl WlRegistry { actual: bind.version, })); } - global.bind(&self.client, bind.id, bind.version).await?; + global.bind(&self.client, bind.id, bind.version)?; Ok(()) } - async fn handle_request_( + fn handle_request_( &self, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), WlRegistryError> { match request { - BIND => self.bind(parser).await?, + BIND => self.bind(parser)?, _ => unreachable!(), } Ok(()) diff --git a/src/ifs/wl_seat/mod.rs b/src/ifs/wl_seat/mod.rs index fd2f9d92..a55b708f 100644 --- a/src/ifs/wl_seat/mod.rs +++ b/src/ifs/wl_seat/mod.rs @@ -4,23 +4,27 @@ pub mod wl_pointer; pub mod wl_touch; use crate::backend::{KeyState, OutputId, ScrollAxis, Seat, SeatEvent}; -use crate::client::{AddObj, Client, ClientId, DynEventFormatter}; +use crate::client::{Client, ClientId, DynEventFormatter}; use crate::fixed::Fixed; use crate::globals::{Global, GlobalName}; use crate::ifs::wl_seat::wl_keyboard::{WlKeyboard, WlKeyboardId}; use crate::ifs::wl_seat::wl_pointer::{WlPointer, WlPointerId}; use crate::ifs::wl_seat::wl_touch::WlTouch; +use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::{XdgToplevel, XdgToplevelId}; +use crate::ifs::wl_surface::WlSurface; use crate::object::{Interface, Object, ObjectId}; -use crate::tree::{Node, NodeBase, NodeKind, ToplevelNode}; +use crate::tree::{FloatNode, Node}; use crate::utils::buffd::MsgParser; use crate::utils::clonecell::CloneCell; use crate::utils::copyhashmap::CopyHashMap; -use crate::xkbcommon::{ModifierState, XkbContext, XkbState, XKB_KEY_DOWN, XKB_KEY_UP}; +use crate::utils::linkedlist::{LinkedList, LinkedNode}; +use crate::xkbcommon::{ModifierState, XkbContext, XkbState}; use crate::State; use ahash::{AHashMap, AHashSet}; use bstr::ByteSlice; use std::cell::{Cell, RefCell}; use std::io::Write; +use std::ops::Deref; use std::rc::Rc; pub use types::*; use uapi::{c, OwnedFd}; @@ -43,6 +47,7 @@ const TOUCH: u32 = 4; #[allow(dead_code)] const MISSING_CAPABILITY: u32 = 0; +#[allow(dead_code)] const BTN_LEFT: u32 = 0x110; pub struct WlSeatGlobal { @@ -53,7 +58,9 @@ pub struct WlSeatGlobal { move_start_pos: Cell<(Fixed, Fixed)>, extents_start_pos: Cell<(i32, i32)>, pos: Cell<(Fixed, Fixed)>, - cursor_node: CloneCell>, + pointer_stack: RefCell>>, + toplevel_focus_history: LinkedList>, + toplevel_focus_stash: RefCell>>>, keyboard_node: CloneCell>, pressed_keys: RefCell>, bindings: RefCell>>>, @@ -89,7 +96,9 @@ impl WlSeatGlobal { move_start_pos: Cell::new((Fixed(0), Fixed(0))), extents_start_pos: Cell::new((0, 0)), pos: Cell::new((Fixed(0), Fixed(0))), - cursor_node: CloneCell::new(state.root.clone()), + pointer_stack: RefCell::new(vec![]), + toplevel_focus_history: Default::default(), + toplevel_focus_stash: RefCell::new(Default::default()), keyboard_node: CloneCell::new(state.root.clone()), pressed_keys: RefCell::new(Default::default()), bindings: Default::default(), @@ -99,34 +108,87 @@ impl WlSeatGlobal { } } - pub fn move_(&self, node: &Rc) { - let cursor = self.cursor_node.get(); - if cursor.id() == node.id() { - self.move_.set(true); - self.move_start_pos.set(self.pos.get()); - let ex = node.common.extents.get(); - self.extents_start_pos.set((ex.x, ex.y)); + pub fn last_tiled_keyboard_toplevel(&self) -> Option> { + for tl in self.toplevel_focus_history.rev_iter() { + if !tl.parent_is_float() { + return Some(tl.deref().clone()); + } } + None } - pub async fn event(&self, event: SeatEvent) { + pub fn move_(&self, node: &Rc) { + self.move_.set(true); + self.move_start_pos.set(self.pos.get()); + let ex = node.position.get(); + self.extents_start_pos.set((ex.x1(), ex.y1())); + } + + pub fn event(&self, event: SeatEvent) { match event { - SeatEvent::OutputPosition(o, x, y) => self.output_position_event(o, x, y).await, - SeatEvent::Motion(dx, dy) => self.motion_event(dx, dy).await, - SeatEvent::Button(b, s) => self.button_event(b, s).await, - SeatEvent::Scroll(d, a) => self.scroll_event(d, a).await, - SeatEvent::Key(k, s) => self.key_event(k, s).await, + SeatEvent::OutputPosition(o, x, y) => self.output_position_event(o, x, y), + SeatEvent::Motion(dx, dy) => self.motion_event(dx, dy), + SeatEvent::Button(b, s) => self.button_event(b, s), + SeatEvent::Scroll(d, a) => self.scroll_event(d, a), + SeatEvent::Key(k, s) => self.key_event(k, s), } } - async fn output_position_event(&self, output: OutputId, mut x: Fixed, mut y: Fixed) { + pub fn button_surface(&self, surface: &Rc, button: u32, state: KeyState) { + let state = match state { + KeyState::Released => wl_pointer::RELEASED, + KeyState::Pressed => wl_pointer::PRESSED, + }; + self.surface_pointer_event(surface, |p| p.button(0, 0, button, state)); + } + + pub fn focus_surface(&self, surface: &Rc) { + let pressed_keys: Vec<_> = self.pressed_keys.borrow().iter().copied().collect(); + self.surface_kb_event(&surface, |k| { + k.enter(0, surface.id, pressed_keys.clone()) + }); + let ModifierState { + mods_depressed, + mods_latched, + mods_locked, + group, + } = self.kb_state.borrow().mods(); + self.surface_kb_event(surface, |k| { + k.modifiers(0, mods_depressed, mods_latched, mods_locked, group) + }); + } + + pub fn unfocus_surface(&self, surface: &Rc) { + self.surface_kb_event(surface, |k| { + k.leave(0, surface.id) + }) + } + + fn focus_toplevel(&self, toplevel: &Rc) { + let node = self.toplevel_focus_history.add_last(toplevel.clone()); + self.toplevel_focus_stash + .borrow_mut() + .insert(toplevel.id, node); + self.keyboard_node.get().unfocus(self); + let focus_surface; + if let Some(ss) = toplevel.focus_subsurface.get() { + focus_surface = ss.surface.clone(); + self.keyboard_node.set(ss); + } else { + focus_surface = toplevel.xdg.surface.clone(); + self.keyboard_node.set(focus_surface.clone()); + } + self.focus_surface(&focus_surface); + } + + fn output_position_event(&self, output: OutputId, mut x: Fixed, mut y: Fixed) { let output = match self.state.outputs.get(&output) { Some(o) => o, _ => return, }; x += Fixed::from_int(output.x.get()); y += Fixed::from_int(output.y.get()); - self.handle_new_position(x, y).await; + self.set_new_position(x, y); } fn for_each_seat(&self, client: ClientId, mut f: C) @@ -165,175 +227,197 @@ impl WlSeatGlobal { }) } - async fn tl_pointer_event(&self, tl: &ToplevelNode, mut f: F) + fn surface_pointer_event(&self, surface: &WlSurface, mut f: F) where F: FnMut(&Rc) -> DynEventFormatter, { - let client = &tl.surface.surface.surface.client; + let client = &surface.client; self.for_each_pointer(client.id, |p| { - client.event_locked(f(p)); + client.event(f(p)); }); - let _ = client.flush().await; + client.flush(); } - async fn tl_kb_event(&self, tl: &ToplevelNode, mut f: F) + fn surface_kb_event(&self, surface: &WlSurface, mut f: F) where F: FnMut(&Rc) -> DynEventFormatter, { - let client = &tl.surface.surface.surface.client; + let client = &surface.client; self.for_each_kb(client.id, |p| { - client.event_locked(f(p)); + client.event(f(p)); }); - let _ = client.flush().await; + client.flush(); } - async fn handle_new_position(&self, x: Fixed, y: Fixed) { + fn set_new_position(&self, x: Fixed, y: Fixed) { self.pos.set((x, y)); - let cur_node = self.cursor_node.get(); - if self.move_.get() { - if let NodeKind::Toplevel(tn) = cur_node.into_kind() { - let (move_start_x, move_start_y) = self.move_start_pos.get(); - let (move_start_ex, move_start_ey) = self.extents_start_pos.get(); - let mut ex = tn.common.extents.get(); - ex.x = (x - move_start_x).round_down() + move_start_ex; - ex.y = (y - move_start_y).round_down() + move_start_ey; - tn.common.extents.set(ex); - } - return; - } - let x_int = x.round_down(); - let y_int = y.round_down(); - let (node_dyn, x_int, y_int) = self.state.root.clone().find_node_at(x_int, y_int); - let mut x = x.apply_fract(x_int); - let mut y = x.apply_fract(y_int); - let node = node_dyn.clone().into_kind(); - let mut enter = false; - if node_dyn.id() != cur_node.id() { - if let NodeKind::Toplevel(tl) = cur_node.into_kind() { - self.tl_pointer_event(&tl, |p| p.leave(0, tl.surface.surface.surface.id)) - .await; - } - enter = true; - self.cursor_node.set(node_dyn); - } - if let NodeKind::Toplevel(tl) = &node { - let ee = tl.surface.surface.surface.effective_extents.get(); - // log::trace!("{} {}", Fixed::from_int(ee.x1), Fixed::from_int(ee.y1)); - x += Fixed::from_int(ee.x1); - y += Fixed::from_int(ee.y1); - if enter { - self.tl_pointer_event(tl, |p| p.enter(0, tl.surface.surface.surface.id, x, y)) - .await; - } - self.tl_pointer_event(tl, |p| p.motion(0, x, y)).await; - self.tl_pointer_event(tl, |p| p.frame()).await; - } + self.handle_new_position(true); } - async fn motion_event(&self, dx: Fixed, dy: Fixed) { + pub fn tree_changed(&self) { + log::info!("tree changed"); + self.handle_new_position(false); + } + + pub fn handle_new_position(&self, changed: bool) { let (x, y) = self.pos.get(); - self.handle_new_position(x + dx, y + dy).await; + let mut stack = self.pointer_stack.borrow_mut(); + // if self.move_.get() { + // for node in stack.iter().rev() { + // if let NodeKind::Toplevel(tn) = node.clone().into_kind() { + // let (move_start_x, move_start_y) = self.move_start_pos.get(); + // let (move_start_ex, move_start_ey) = self.extents_start_pos.get(); + // let mut ex = tn.common.extents.get(); + // ex.x = (x - move_start_x).round_down() + move_start_ex; + // ex.y = (y - move_start_y).round_down() + move_start_ey; + // tn.common.extents.set(ex); + // } + // } + // return; + // } + let mut x_int = x.round_down(); + let mut y_int = y.round_down(); + let mut node = Some(self.state.root.clone() as Rc); + let divergence = 'outer: loop { + for i in 0..stack.len() { + match node.take() { + None => break 'outer i, + Some(n) if n.id() != stack[i].id() => { + node = Some(n); + break 'outer i; + } + Some(n) => { + if let Some(found) = n.find_child_at(x_int.into(), y_int.into()) { + node = Some(found.node); + x_int = found.x.into(); + y_int = found.y.into(); + } + } + } + } + break stack.len(); + }; + if divergence == stack.len() && node.is_none() { + if changed { + if let Some(node) = stack.last() { + node.motion(self, x.apply_fract(x_int), y.apply_fract(y_int)); + } + } + } else { + for node in stack.drain(divergence..).rev() { + node.leave(self); + } + while let Some(n) = node.take() { + n.clone() + .enter(self, x.apply_fract(x_int), y.apply_fract(y_int)); + if let Some(found) = n.find_child_at(x_int.into(), y_int.into()) { + node = Some(found.node); + x_int = found.x.into(); + y_int = found.y.into(); + } + stack.push(n); + } + } } - async fn button_event(&self, button: u32, state: KeyState) { + pub fn leave_surface(&self, n: &WlSurface) { + self.surface_pointer_event(n, |p| p.leave(0, n.id)); + } + + pub fn enter_toplevel(&self, n: &Rc) { + self.focus_toplevel(n); + } + + pub fn enter_surface(&self, n: &WlSurface, x: Fixed, y: Fixed) { + self.surface_pointer_event(n, |p| p.enter(0, n.id, x, y)); + } + + pub fn motion_surface(&self, n: &WlSurface, x: Fixed, y: Fixed) { + self.surface_pointer_event(n, |p| p.motion(0, x, y)); + self.surface_pointer_event(n, |p| p.frame()); + } + + fn motion_event(&self, dx: Fixed, dy: Fixed) { + let (x, y) = self.pos.get(); + self.set_new_position(x + dx, y + dy); + } + + fn button_event(&self, button: u32, state: KeyState) { if state == KeyState::Released { self.move_.set(false); } - let node = self.cursor_node.get(); + let node = match self.pointer_stack.borrow().last().cloned() { + Some(v) => v, + _ => return, + }; let mut enter = false; - if button == BTN_LEFT { + { let kb_node = self.keyboard_node.get(); if kb_node.id() != node.id() { enter = true; - if let NodeKind::Toplevel(tl) = kb_node.clone().into_kind() { - self.tl_kb_event(&tl, |k| k.leave(0, tl.surface.surface.surface.id)) - .await; - } + kb_node.unfocus(self); self.keyboard_node.set(node.clone()); } } - if let NodeKind::Toplevel(node) = node.into_kind() { - let state = match state { - KeyState::Released => wl_pointer::RELEASED, - KeyState::Pressed => wl_pointer::PRESSED, - }; - self.tl_pointer_event(&node, |p| p.button(0, 0, button, state)) - .await; - if enter { - self.tl_kb_event(&node, |k| { - k.enter( - 0, - node.surface.surface.surface.id, - self.pressed_keys.borrow().iter().cloned().collect(), - ) - }) - .await; - let ModifierState { - mods_depressed, - mods_latched, - mods_locked, - group, - } = self.kb_state.borrow().mods(); - self.tl_kb_event(&node, |k| { - k.modifiers(0, mods_depressed, mods_latched, mods_locked, group) - }) - .await; - } + node.clone().button(self, button, state); + if enter { + node.focus(self); } } - async fn scroll_event(&self, delta: i32, axis: ScrollAxis) { - let node = self.cursor_node.get().into_kind(); - if let NodeKind::Toplevel(node) = node { - let axis = match axis { - ScrollAxis::Horizontal => wl_pointer::HORIZONTAL_SCROLL, - ScrollAxis::Vertical => wl_pointer::VERTICAL_SCROLL, - }; - self.tl_pointer_event(&node, |p| p.axis(0, axis, Fixed::from_int(delta))) - .await; - self.tl_pointer_event(&node, |p| p.frame()) - .await; - } - } - - async fn key_event(&self, key: u32, state: KeyState) { - let (state, xkb_dir) = { - let mut pk = self.pressed_keys.borrow_mut(); - match state { - KeyState::Released => { - if !pk.remove(&key) { - return; - } - (wl_keyboard::RELEASED, XKB_KEY_UP) - } - KeyState::Pressed => { - if !pk.insert(key) { - return; - } - (wl_keyboard::PRESSED, XKB_KEY_DOWN) - } - } + pub fn scroll_surface(&self, surface: &WlSurface, delta: i32, axis: ScrollAxis) { + let axis = match axis { + ScrollAxis::Horizontal => wl_pointer::HORIZONTAL_SCROLL, + ScrollAxis::Vertical => wl_pointer::VERTICAL_SCROLL, }; - let mods = self.kb_state.borrow_mut().update(key, xkb_dir); - let node = self.keyboard_node.get().into_kind(); - if let NodeKind::Toplevel(node) = node { - self.tl_kb_event(&node, |k| k.key(0, 0, key, state)).await; - if let Some(mods) = mods { - self.tl_kb_event(&node, |k| { - k.modifiers( - 0, - mods.mods_depressed, - mods.mods_latched, - mods.mods_locked, - mods.group, - ) - }) - .await; - } + self.surface_pointer_event(surface, |p| p.axis(0, axis, Fixed::from_int(delta))); + self.surface_pointer_event(surface, |p| p.frame()); + } + + fn scroll_event(&self, delta: i32, axis: ScrollAxis) { + if let Some(node) = self.pointer_stack.borrow().last().cloned() { + node.scroll(self, delta, axis); } } - async fn bind_( + fn key_event(&self, _key: u32, _state: KeyState) { + // let (state, xkb_dir) = { + // let mut pk = self.pressed_keys.borrow_mut(); + // match state { + // KeyState::Released => { + // if !pk.remove(&key) { + // return; + // } + // (wl_keyboard::RELEASED, XKB_KEY_UP) + // } + // KeyState::Pressed => { + // if !pk.insert(key) { + // return; + // } + // (wl_keyboard::PRESSED, XKB_KEY_DOWN) + // } + // } + // }; + // let mods = self.kb_state.borrow_mut().update(key, xkb_dir); + // let node = self.keyboard_node.get().into_kind(); + // if let NodeKind::Toplevel(node) = node { + // self.tl_kb_event(&node, |k| k.key(0, 0, key, state)).await; + // if let Some(mods) = mods { + // self.tl_kb_event(&node, |k| { + // k.modifiers( + // 0, + // mods.mods_depressed, + // mods.mods_latched, + // mods.mods_locked, + // mods.group, + // ) + // }) + // .await; + // } + // } + } + + fn bind_( self: Rc, id: WlSeatId, client: &Rc, @@ -348,7 +432,7 @@ impl WlSeatGlobal { version, }); client.add_client_obj(&obj)?; - client.event(obj.capabilities()).await?; + client.event(obj.capabilities()); { let mut bindings = self.bindings.borrow_mut(); let bindings = bindings.entry(client.id).or_insert_with(Default::default); @@ -399,14 +483,11 @@ impl WlSeatObj { }) } - pub fn move_(&self, node: &Rc) { + pub fn move_(&self, node: &Rc) { self.global.move_(node); } - async fn get_pointer( - self: &Rc, - parser: MsgParser<'_, '_>, - ) -> Result<(), GetPointerError> { + fn get_pointer(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), GetPointerError> { let req: GetPointer = self.client.parse(&**self, parser)?; let p = Rc::new(WlPointer::new(req.id, self)); self.client.add_client_obj(&p)?; @@ -414,31 +495,25 @@ impl WlSeatObj { Ok(()) } - async fn get_keyboard( - self: &Rc, - parser: MsgParser<'_, '_>, - ) -> Result<(), GetKeyboardError> { + fn get_keyboard(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), GetKeyboardError> { let req: GetKeyboard = self.client.parse(&**self, parser)?; let p = Rc::new(WlKeyboard::new(req.id, self)); self.client.add_client_obj(&p)?; self.keyboards.set(req.id, p.clone()); self.client - .event(p.keymap(wl_keyboard::XKB_V1, p.keymap_fd()?, self.global.layout_size)) - .await?; - self.client - .event(p.repeat_info(25, 250)) - .await?; + .event(p.keymap(wl_keyboard::XKB_V1, p.keymap_fd()?, self.global.layout_size)); + self.client.event(p.repeat_info(25, 250)); Ok(()) } - async fn get_touch(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), GetTouchError> { + fn get_touch(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), GetTouchError> { let req: GetTouch = self.client.parse(&**self, parser)?; let p = Rc::new(WlTouch::new(req.id, self)); self.client.add_client_obj(&p)?; Ok(()) } - async fn release(&self, parser: MsgParser<'_, '_>) -> Result<(), ReleaseError> { + fn release(&self, parser: MsgParser<'_, '_>) -> Result<(), ReleaseError> { let _req: Release = self.client.parse(self, parser)?; { let mut bindings = self.global.bindings.borrow_mut(); @@ -446,20 +521,20 @@ impl WlSeatObj { hm.remove(&self.id); } } - self.client.remove_obj(self).await?; + self.client.remove_obj(self)?; Ok(()) } - async fn handle_request_( + fn handle_request_( self: &Rc, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), WlSeatError> { match request { - GET_POINTER => self.get_pointer(parser).await?, - GET_KEYBOARD => self.get_keyboard(parser).await?, - GET_TOUCH => self.get_touch(parser).await?, - RELEASE => self.release(parser).await?, + GET_POINTER => self.get_pointer(parser)?, + GET_KEYBOARD => self.get_keyboard(parser)?, + GET_TOUCH => self.get_touch(parser)?, + RELEASE => self.release(parser)?, _ => unreachable!(), } Ok(()) diff --git a/src/ifs/wl_seat/wl_keyboard/mod.rs b/src/ifs/wl_seat/wl_keyboard/mod.rs index ebab27b6..90decc17 100644 --- a/src/ifs/wl_seat/wl_keyboard/mod.rs +++ b/src/ifs/wl_seat/wl_keyboard/mod.rs @@ -1,6 +1,6 @@ mod types; -use crate::client::{AddObj, DynEventFormatter}; +use crate::client::DynEventFormatter; use crate::ifs::wl_seat::WlSeatObj; use crate::ifs::wl_surface::WlSurfaceId; use crate::object::{Interface, Object, ObjectId}; @@ -22,7 +22,9 @@ const REPEAT_INFO: u32 = 5; const NO_KEYMAP: u32 = 0; pub(super) const XKB_V1: u32 = 1; +#[allow(dead_code)] pub(super) const RELEASED: u32 = 0; +#[allow(dead_code)] pub(super) const PRESSED: u32 = 1; id!(WlKeyboardId); @@ -142,20 +144,20 @@ impl WlKeyboard { }) } - async fn release(&self, parser: MsgParser<'_, '_>) -> Result<(), ReleaseError> { + fn release(&self, parser: MsgParser<'_, '_>) -> Result<(), ReleaseError> { let _req: Release = self.seat.client.parse(self, parser)?; self.seat.keyboards.remove(&self.id); - self.seat.client.remove_obj(self).await?; + self.seat.client.remove_obj(self)?; Ok(()) } - async fn handle_request_( + fn handle_request_( &self, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), WlKeyboardError> { match request { - RELEASE => self.release(parser).await?, + RELEASE => self.release(parser)?, _ => unreachable!(), } Ok(()) diff --git a/src/ifs/wl_seat/wl_pointer/mod.rs b/src/ifs/wl_seat/wl_pointer/mod.rs index d1651cc5..a1301da7 100644 --- a/src/ifs/wl_seat/wl_pointer/mod.rs +++ b/src/ifs/wl_seat/wl_pointer/mod.rs @@ -1,6 +1,6 @@ mod types; -use crate::client::{AddObj, DynEventFormatter}; +use crate::client::DynEventFormatter; use crate::fixed::Fixed; use crate::ifs::wl_seat::WlSeatObj; use crate::ifs::wl_surface::WlSurfaceId; @@ -144,26 +144,26 @@ impl WlPointer { }) } - async fn set_cursor(&self, parser: MsgParser<'_, '_>) -> Result<(), SetCursorError> { + fn set_cursor(&self, parser: MsgParser<'_, '_>) -> Result<(), SetCursorError> { let _req: SetCursor = self.seat.client.parse(self, parser)?; Ok(()) } - async fn release(&self, parser: MsgParser<'_, '_>) -> Result<(), ReleaseError> { + fn release(&self, parser: MsgParser<'_, '_>) -> Result<(), ReleaseError> { let _req: Release = self.seat.client.parse(self, parser)?; self.seat.pointers.remove(&self.id); - self.seat.client.remove_obj(self).await?; + self.seat.client.remove_obj(self)?; Ok(()) } - async fn handle_request_( + fn handle_request_( &self, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), WlPointerError> { match request { - SET_CURSOR => self.set_cursor(parser).await?, - RELEASE => self.release(parser).await?, + SET_CURSOR => self.set_cursor(parser)?, + RELEASE => self.release(parser)?, _ => unreachable!(), } Ok(()) diff --git a/src/ifs/wl_seat/wl_touch/mod.rs b/src/ifs/wl_seat/wl_touch/mod.rs index ed10934e..0673a9b3 100644 --- a/src/ifs/wl_seat/wl_touch/mod.rs +++ b/src/ifs/wl_seat/wl_touch/mod.rs @@ -1,6 +1,5 @@ mod types; -use crate::client::AddObj; use crate::ifs::wl_seat::WlSeatObj; use crate::object::{Interface, Object, ObjectId}; use crate::utils::buffd::MsgParser; @@ -39,19 +38,15 @@ impl WlTouch { } } - async fn release(&self, parser: MsgParser<'_, '_>) -> Result<(), ReleaseError> { + fn release(&self, parser: MsgParser<'_, '_>) -> Result<(), ReleaseError> { let _req: Release = self.seat.client.parse(self, parser)?; - self.seat.client.remove_obj(self).await?; + self.seat.client.remove_obj(self)?; Ok(()) } - async fn handle_request_( - &self, - request: u32, - parser: MsgParser<'_, '_>, - ) -> Result<(), WlTouchError> { + fn handle_request_(&self, request: u32, parser: MsgParser<'_, '_>) -> Result<(), WlTouchError> { match request { - RELEASE => self.release(parser).await?, + RELEASE => self.release(parser)?, _ => unreachable!(), } Ok(()) diff --git a/src/ifs/wl_shm/mod.rs b/src/ifs/wl_shm/mod.rs index f4a9661a..80b646f9 100644 --- a/src/ifs/wl_shm/mod.rs +++ b/src/ifs/wl_shm/mod.rs @@ -1,6 +1,6 @@ mod types; -use crate::client::{AddObj, Client}; +use crate::client::Client; use crate::globals::{Global, GlobalName}; use crate::ifs::wl_shm_pool::WlShmPool; use crate::object::{Interface, Object, ObjectId}; @@ -29,7 +29,7 @@ impl WlShmGlobal { Self { name } } - async fn bind_( + fn bind_( self: Rc, id: WlShmId, client: &Rc, @@ -42,19 +42,17 @@ impl WlShmGlobal { }); client.add_client_obj(&obj)?; for &format in client.state.formats.values() { - client - .event(Box::new(FormatE { - obj: obj.clone(), - format, - })) - .await?; + client.event(Box::new(FormatE { + obj: obj.clone(), + format, + })); } Ok(()) } } impl WlShmObj { - async fn create_pool(&self, parser: MsgParser<'_, '_>) -> Result<(), CreatePoolError> { + fn create_pool(&self, parser: MsgParser<'_, '_>) -> Result<(), CreatePoolError> { let create: CreatePool = self.client.parse(self, parser)?; if create.size < 0 { return Err(CreatePoolError::NegativeSize); @@ -69,13 +67,9 @@ impl WlShmObj { Ok(()) } - async fn handle_request_( - &self, - request: u32, - parser: MsgParser<'_, '_>, - ) -> Result<(), WlShmError> { + fn handle_request_(&self, request: u32, parser: MsgParser<'_, '_>) -> Result<(), WlShmError> { match request { - CREATE_POOL => self.create_pool(parser).await?, + CREATE_POOL => self.create_pool(parser)?, _ => unreachable!(), } Ok(()) diff --git a/src/ifs/wl_shm_pool/mod.rs b/src/ifs/wl_shm_pool/mod.rs index 83d33b80..caa94f17 100644 --- a/src/ifs/wl_shm_pool/mod.rs +++ b/src/ifs/wl_shm_pool/mod.rs @@ -1,6 +1,6 @@ mod types; -use crate::client::{AddObj, Client}; +use crate::client::Client; use crate::clientmem::ClientMem; use crate::ifs::wl_buffer::WlBuffer; use crate::object::{Interface, Object, ObjectId}; @@ -38,7 +38,7 @@ impl WlShmPool { }) } - async fn create_buffer(&self, parser: MsgParser<'_, '_>) -> Result<(), CreateBufferError> { + fn create_buffer(&self, parser: MsgParser<'_, '_>) -> Result<(), CreateBufferError> { let req: CreateBuffer = self.client.parse(self, parser)?; let format = match self.client.state.formats.get(&req.format) { Some(f) => *f, @@ -51,9 +51,9 @@ impl WlShmPool { req.id, &self.client, req.offset as usize, - req.width as u32, - req.height as u32, - req.stride as u32, + req.width, + req.height, + req.stride, format, &self.mem.get(), )?); @@ -61,13 +61,13 @@ impl WlShmPool { Ok(()) } - async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.client.parse(self, parser)?; - self.client.remove_obj(self).await?; + self.client.remove_obj(self)?; Ok(()) } - async fn resize(&self, parser: MsgParser<'_, '_>) -> Result<(), ResizeError> { + fn resize(&self, parser: MsgParser<'_, '_>) -> Result<(), ResizeError> { let req: Resize = self.client.parse(self, parser)?; if req.size < 0 { return Err(ResizeError::NegativeSize); @@ -80,15 +80,15 @@ impl WlShmPool { Ok(()) } - async fn handle_request_( + fn handle_request_( &self, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), WlShmPoolError> { match request { - CREATE_BUFFER => self.create_buffer(parser).await?, - DESTROY => self.destroy(parser).await?, - RESIZE => self.resize(parser).await?, + CREATE_BUFFER => self.create_buffer(parser)?, + DESTROY => self.destroy(parser)?, + RESIZE => self.resize(parser)?, _ => unreachable!(), } Ok(()) diff --git a/src/ifs/wl_subcompositor/mod.rs b/src/ifs/wl_subcompositor/mod.rs index 975f2643..7e2e94ab 100644 --- a/src/ifs/wl_subcompositor/mod.rs +++ b/src/ifs/wl_subcompositor/mod.rs @@ -1,6 +1,6 @@ mod types; -use crate::client::{AddObj, Client}; +use crate::client::Client; use crate::globals::{Global, GlobalName}; use crate::ifs::wl_surface::wl_subsurface::WlSubsurface; use crate::object::{Interface, Object, ObjectId}; @@ -30,7 +30,7 @@ impl WlSubcompositorGlobal { Self { name } } - async fn bind_( + fn bind_( self: Rc, id: WlSubcompositorId, client: &Rc, @@ -46,13 +46,13 @@ impl WlSubcompositorGlobal { } impl WlSubcompositorObj { - async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.client.parse(self, parser)?; - self.client.remove_obj(self).await?; + self.client.remove_obj(self)?; Ok(()) } - async fn get_subsurface(&self, parser: MsgParser<'_, '_>) -> Result<(), GetSubsurfaceError> { + fn get_subsurface(&self, parser: MsgParser<'_, '_>) -> Result<(), GetSubsurfaceError> { let req: GetSubsurface = self.client.parse(self, parser)?; let surface = self.client.get_surface(req.surface)?; let parent = self.client.get_surface(req.parent)?; @@ -62,14 +62,14 @@ impl WlSubcompositorObj { Ok(()) } - async fn handle_request_( + fn handle_request_( self: &Rc, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), WlSubcompositorError> { match request { - DESTROY => self.destroy(parser).await?, - GET_SUBSURFACE => self.get_subsurface(parser).await?, + DESTROY => self.destroy(parser)?, + GET_SUBSURFACE => self.get_subsurface(parser)?, _ => unreachable!(), } Ok(()) diff --git a/src/ifs/wl_surface/mod.rs b/src/ifs/wl_surface/mod.rs index 9d07cb8a..5036a6f9 100644 --- a/src/ifs/wl_surface/mod.rs +++ b/src/ifs/wl_surface/mod.rs @@ -2,26 +2,27 @@ mod types; pub mod wl_subsurface; pub mod xdg_surface; -use crate::client::{AddObj, Client, RequestParser}; +use crate::client::{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::rect::Rect; +use crate::tree::{Node, NodeId}; use crate::utils::buffd::{MsgParser, MsgParserError}; use crate::utils::clonecell::CloneCell; -use crate::utils::copyhashmap::CopyHashMap; -use crate::utils::linkedlist::{LinkedList, Node as LinkNode}; +use crate::utils::linkedlist::LinkedList; +use crate::NumCell; use ahash::AHashMap; use std::cell::{Cell, RefCell}; use std::mem; use std::ops::{Deref, DerefMut}; use std::rc::Rc; pub use types::*; +use crate::backend::{KeyState, ScrollAxis}; +use crate::fixed::Fixed; +use crate::ifs::wl_seat::WlSeatGlobal; const DESTROY: u32 = 0; const ATTACH: u32 = 1; @@ -53,6 +54,8 @@ pub enum SurfaceRole { None, Subsurface, XdgSurface, + XdgPopup, + XdgToplevel, } impl SurfaceRole { @@ -61,213 +64,189 @@ impl SurfaceRole { SurfaceRole::None => "none", SurfaceRole::Subsurface => "subsurface", SurfaceRole::XdgSurface => "xdg_surface", + SurfaceRole::XdgPopup => "xdg_popup", + SurfaceRole::XdgToplevel => "xdg_toplevel", } } } pub struct WlSurface { pub id: WlSurfaceId, + pub node_id: SurfaceNodeId, pub client: Rc, role: Cell, pending: PendingState, input_region: Cell>, opaque_region: Cell>, - pub extents: Cell, - pub effective_extents: Cell, + pub extents: Cell, + pub need_extents_update: Cell, + pub effective_extents: Cell, pub buffer: CloneCell>>, + pub buf_x: NumCell, + pub buf_y: NumCell, pub children: RefCell>>, - role_data: RefCell, + ext: CloneCell>, pub frame_requests: RefCell>>, } -#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)] -pub struct SurfaceExtents { - pub x1: i32, - pub y1: i32, - pub x2: i32, - pub y2: i32, +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +enum CommitContext { + RootCommit, + ChildCommit, } -enum RoleData { - None, - Subsurface(Box), - XdgSurface(Box), +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +enum CommitAction { + ContinueCommit, + AbortCommit, } -impl RoleData { +trait SurfaceExt { + fn pre_commit(self: Rc, ctx: CommitContext) -> CommitAction { + let _ = ctx; + CommitAction::ContinueCommit + } + + fn post_commit(&self) { + // nothing + } + fn is_some(&self) -> bool { - !matches!(self, RoleData::None) + true + } + + fn update_subsurface_parent_extents(&self) { + // nothing + } + + fn subsurface_parent(&self) -> Option> { + None + } + + fn extents_changed(&self) { + // nothing + } + + fn into_subsurface(self: Rc) -> Option> { + None + } + + fn into_node(self: Rc) -> Option> { + None + } +} + +pub struct NoneSurfaceExt; + +impl SurfaceExt for NoneSurfaceExt { + fn is_some(&self) -> bool { + false } } #[derive(Default)] struct PendingState { + buffer: Cell)>>>, opaque_region: Cell>, input_region: Cell>, frame_request: RefCell>>, } -struct XdgSurfaceData { - xdg_surface: Rc, - requested_serial: u32, - acked_serial: Option, - role: XdgSurfaceRole, - extents: Option, - role_data: XdgSurfaceRoleData, - popups: CopyHashMap>, - pending: PendingXdgSurfaceData, -} - -#[derive(Default)] -struct PendingXdgSurfaceData { - extents: Cell>, -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -enum XdgSurfaceRole { - None, - Popup, - Toplevel, -} - -impl XdgSurfaceRole { - fn is_compatible(self, role: XdgSurfaceRole) -> bool { - self == XdgSurfaceRole::None || self == role - } -} - -enum XdgSurfaceRoleData { - None, - Popup(XdgPopupData), - Toplevel(XdgToplevelData), -} - -impl XdgSurfaceRoleData { - fn is_some(&self) -> bool { - !matches!(self, XdgSurfaceRoleData::None) - } -} - -struct XdgPopupData { - _popup: Rc, - parent: Option>, -} - -struct XdgToplevelData { - toplevel: Rc, - node: Option, -} - -struct ToplevelNodeHolder { - node: Rc, -} - -impl Drop for ToplevelNodeHolder { - fn drop(&mut self) { - mem::take(&mut *self.node.common.floating_outputs.borrow_mut()); - } -} - -struct SubsurfaceData { - subsurface: Rc, - x: i32, - y: i32, - sync_requested: bool, - sync_ancestor: bool, - node: LinkNode, - depth: u32, - pending: PendingSubsurfaceData, -} - -#[derive(Default)] -struct PendingSubsurfaceData { - node: Option>, - position: Option<(i32, i32)>, -} - #[derive(Default)] pub struct ParentData { - subsurfaces: AHashMap>, + subsurfaces: AHashMap>, pub below: LinkedList, pub above: LinkedList, } pub struct StackElement { - pending: Cell, - pub surface: Rc, + pub pending: Cell, + pub sub_surface: Rc, } impl WlSurface { pub fn new(id: WlSurfaceId, client: &Rc) -> Self { Self { id, + node_id: client.state.node_ids.next(), client: client.clone(), role: Cell::new(SurfaceRole::None), pending: Default::default(), input_region: Cell::new(None), opaque_region: Cell::new(None), extents: Default::default(), + need_extents_update: Cell::new(false), effective_extents: Default::default(), buffer: CloneCell::new(None), + buf_x: Default::default(), + buf_y: Default::default(), children: Default::default(), - role_data: RefCell::new(RoleData::None), + ext: CloneCell::new(client.state.none_surface_ext.clone()), 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 set_role(&self, role: SurfaceRole) -> Result<(), WlSurfaceError> { + use SurfaceRole::*; + match (self.role.get(), role) { + (None, _) => {} + (old, new) if old == new => {} + (XdgSurface, XdgPopup) => {} + (XdgSurface, XdgToplevel) => {} + (old, new) => { + return Err(WlSurfaceError::IncompatibleRole { + id: self.id, + old, + new, + }) + } } + self.role.set(role); + Ok(()) + } + + fn unset_ext(&self) { + self.ext.set(self.client.state.none_surface_ext.clone()); } fn calculate_extents(&self) { - { - let mut extents = SurfaceExtents::default(); - if let Some(b) = self.buffer.get() { - 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 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); - } + let old_extents = self.extents.get(); + let mut extents = Rect::new_empty(0, 0); + if let Some(b) = self.buffer.get() { + extents = b.rect; + } + let children = self.children.borrow(); + if let Some(children) = &*children { + for ss in children.subsurfaces.values() { + let ce = ss.surface.extents.get(); + if !ce.is_empty() { + let cp = ss.position.get(); + let ce = ce.move_(cp.x1(), cp.y1()); + extents = if extents.is_empty() { + ce + } else { + extents.union(ce) + }; } } - 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(); + self.extents.set(extents); + self.need_extents_update.set(false); + if old_extents != extents { + self.ext.get().extents_changed() + } } pub fn get_root(self: &Rc) -> Rc { let mut root = self.clone(); loop { - let tmp = root; - let data = tmp.role_data.borrow(); - match &*data { - RoleData::Subsurface(d) => root = d.subsurface.parent.clone(), - _ => { - drop(data); - return tmp; - } + if let Some(parent) = root.ext.get().subsurface_parent() { + root = parent; + continue; } + break; } + root } fn parse<'a, T: RequestParser<'a>>( @@ -277,16 +256,16 @@ impl WlSurface { self.client.parse(self, parser) } - async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.parse(parser)?; - if self.role_data.borrow().is_some() { + if self.ext.get().is_some() { return Err(DestroyError::ReloObjectStillExists); } { let mut children = self.children.borrow_mut(); if let Some(children) = &mut *children { - for surface in children.subsurfaces.values() { - *surface.role_data.borrow_mut() = RoleData::None; + for ss in children.subsurfaces.values() { + ss.surface.unset_ext(); } } *children = None; @@ -297,62 +276,27 @@ impl WlSurface { buffer.surfaces.remove(&self.id); } } - self.client.remove_obj(self).await?; + self.client.remove_obj(self)?; Ok(()) } - async fn attach(&self, parser: MsgParser<'_, '_>) -> Result<(), AttachError> { + fn attach(&self, parser: MsgParser<'_, '_>) -> Result<(), AttachError> { let req: Attach = self.parse(parser)?; - { - if let Some(buffer) = self.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() { - self.buffer.set(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.add_last(node.clone()); - node.common - .floating_outputs - .borrow_mut() - .insert(output.id(), link); - } - } - } - } - } else { - self.buffer.set(None); - if let RoleData::XdgSurface(xdg) = &mut *rd { - if let XdgSurfaceRoleData::Toplevel(td) = &mut xdg.role_data { - td.node = None; - } - } - } - } + let buf = if req.buffer.is_some() { + Some((req.x, req.y, self.client.get_buffer(req.buffer)?)) + } else { + None + }; + self.pending.buffer.set(Some(buf)); Ok(()) } - async fn damage(&self, parser: MsgParser<'_, '_>) -> Result<(), DamageError> { + fn damage(&self, parser: MsgParser<'_, '_>) -> Result<(), DamageError> { let _req: Damage = self.parse(parser)?; Ok(()) } - async fn frame(&self, parser: MsgParser<'_, '_>) -> Result<(), FrameError> { + 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)?; @@ -360,49 +304,57 @@ impl WlSurface { Ok(()) } - async fn set_opaque_region( - &self, - parser: MsgParser<'_, '_>, - ) -> Result<(), SetOpaqueRegionError> { + fn set_opaque_region(&self, parser: MsgParser<'_, '_>) -> Result<(), SetOpaqueRegionError> { let region: SetOpaqueRegion = self.parse(parser)?; let region = self.client.get_region(region.region)?; self.pending.opaque_region.set(Some(region.region())); Ok(()) } - async fn set_input_region(&self, parser: MsgParser<'_, '_>) -> Result<(), SetInputRegionError> { + fn set_input_region(&self, parser: MsgParser<'_, '_>) -> Result<(), SetInputRegionError> { let req: SetInputRegion = self.parse(parser)?; let region = self.client.get_region(req.region)?; self.pending.input_region.set(Some(region.region())); Ok(()) } - fn do_commit(&self) { - let mut xdg_extents = None; - let mut td_node = None; + fn do_commit(&self, ctx: CommitContext) { + let ext = self.ext.get(); + if ext.clone().pre_commit(ctx) == CommitAction::AbortCommit { + return; + } { - 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; - } + let children = self.children.borrow(); + if let Some(children) = children.deref() { + for child in children.subsurfaces.values() { + child.surface.do_commit(CommitContext::ChildCommit); } - RoleData::XdgSurface(xdg) => { - if let Some(extents) = xdg.pending.extents.take() { - xdg.extents = Some(extents); - } - xdg_extents = xdg.extents; - if let XdgSurfaceRoleData::Toplevel(tl) = &xdg.role_data { - td_node = tl.node.as_ref().map(|n| n.node.clone()); - } + } + } + if let Some(buffer_change) = self.pending.buffer.take() { + let mut old_size = None; + let mut new_size = None; + log::info!("changing buffer"); + if let Some(buffer) = self.buffer.take() { + log::info!("releasing buffer {}", buffer.id()); + old_size = Some(buffer.rect); + self.client.event(buffer.release()); + buffer.surfaces.remove(&self.id); + } + if let Some((dx, dy, buffer)) = buffer_change { + new_size = Some(buffer.rect); + self.buffer.set(Some(buffer)); + self.buf_x.fetch_add(dx); + self.buf_y.fetch_add(dy); + if (dx, dy) != (0, 0) { + self.need_extents_update.set(true); } + } else { + self.buf_x.set(0); + self.buf_y.set(0); + } + if old_size != new_size { + self.need_extents_update.set(true); } } { @@ -417,71 +369,19 @@ impl WlSurface { 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 { + if self.need_extents_update.get() { self.calculate_extents(); } - let mut effective_extents = self.extents.get(); - if let Some(extents) = xdg_extents { - effective_extents.x1 = effective_extents.x1.max(extents.x1); - effective_extents.y1 = effective_extents.y1.max(extents.y1); - effective_extents.x2 = effective_extents.x2.min(extents.x2); - effective_extents.y2 = effective_extents.y2.min(extents.y2); - if effective_extents.x1 > effective_extents.x2 { - effective_extents.x1 = 0; - effective_extents.x2 = 0; - } - if effective_extents.y1 > effective_extents.y2 { - effective_extents.y1 = 0; - effective_extents.y2 = 0; - } - } - if let Some(node) = td_node { - let mut td_extents = node.common.extents.get(); - td_extents.width = (effective_extents.x2 - effective_extents.x1) as u32; - td_extents.height = (effective_extents.y2 - effective_extents.y1) as u32; - node.common.extents.set(td_extents); - } - self.effective_extents.set(effective_extents); + ext.post_commit(); } - async fn commit(&self, parser: MsgParser<'_, '_>) -> Result<(), CommitError> { + fn commit(&self, parser: MsgParser<'_, '_>) -> Result<(), CommitError> { 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(); + self.do_commit(CommitContext::RootCommit); Ok(()) } - async fn set_buffer_transform( + fn set_buffer_transform( &self, parser: MsgParser<'_, '_>, ) -> Result<(), SetBufferTransformError> { @@ -489,36 +389,79 @@ impl WlSurface { Ok(()) } - async fn set_buffer_scale(&self, parser: MsgParser<'_, '_>) -> Result<(), SetBufferScaleError> { + fn set_buffer_scale(&self, parser: MsgParser<'_, '_>) -> Result<(), SetBufferScaleError> { let _req: SetBufferScale = self.parse(parser)?; Ok(()) } - async fn damage_buffer(&self, parser: MsgParser<'_, '_>) -> Result<(), DamageBufferError> { + fn damage_buffer(&self, parser: MsgParser<'_, '_>) -> Result<(), DamageBufferError> { let _req: DamageBuffer = self.parse(parser)?; Ok(()) } - async fn handle_request_( + fn handle_request_( &self, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), WlSurfaceError> { match request { - DESTROY => self.destroy(parser).await?, - ATTACH => self.attach(parser).await?, - DAMAGE => self.damage(parser).await?, - FRAME => self.frame(parser).await?, - SET_OPAQUE_REGION => self.set_opaque_region(parser).await?, - SET_INPUT_REGION => self.set_input_region(parser).await?, - COMMIT => self.commit(parser).await?, - SET_BUFFER_TRANSFORM => self.set_buffer_transform(parser).await?, - SET_BUFFER_SCALE => self.set_buffer_scale(parser).await?, - DAMAGE_BUFFER => self.damage_buffer(parser).await?, + DESTROY => self.destroy(parser)?, + ATTACH => self.attach(parser)?, + DAMAGE => self.damage(parser)?, + FRAME => self.frame(parser)?, + SET_OPAQUE_REGION => self.set_opaque_region(parser)?, + SET_INPUT_REGION => self.set_input_region(parser)?, + COMMIT => self.commit(parser)?, + SET_BUFFER_TRANSFORM => self.set_buffer_transform(parser)?, + SET_BUFFER_SCALE => self.set_buffer_scale(parser)?, + DAMAGE_BUFFER => self.damage_buffer(parser)?, _ => unreachable!(), } Ok(()) } + + fn find_surface_at(self: &Rc, x: i32, y: i32) -> Option<(Rc, i32, i32)> { + let buffer = match self.buffer.get() { + Some(b) => b, + _ => return None, + }; + let children = self.children.borrow(); + let children = match children.deref() { + Some(c) => c, + _ => { + return if buffer.rect.contains(x, y) { + Some((self.clone(), x, y)) + } else { + None + }; + } + }; + let ss = |c: &LinkedList| { + for child in c.rev_iter() { + if child.pending.get() { + continue; + } + let pos = child.sub_surface.position.get(); + if pos.contains(x, y) { + let (x, y) = pos.translate(x, y); + if let Some(res) = child.sub_surface.surface.find_surface_at(x, y) { + return Some(res); + } + } + } + None + }; + if let Some(res) = ss(&children.above) { + return Some(res); + } + if buffer.rect.contains(x, y) { + return Some((self.clone(), x, y)); + } + if let Some(res) = ss(&children.below) { + return Some(res); + } + None + } } handle_request!(WlSurface); @@ -538,8 +481,43 @@ impl Object for WlSurface { fn break_loops(&self) { *self.children.borrow_mut() = None; - *self.role_data.borrow_mut() = RoleData::None; + self.unset_ext(); mem::take(self.frame_requests.borrow_mut().deref_mut()); self.buffer.set(None); } } + +tree_id!(SurfaceNodeId); +impl Node for WlSurface { + fn id(&self) -> NodeId { + self.node_id.into() + } + + fn enter(self: Rc, seat: &WlSeatGlobal, x: Fixed, y: Fixed) { + seat.enter_surface(&self, x, y) + } + + fn leave(&self, seat: &WlSeatGlobal) { + seat.leave_surface(self); + } + + fn motion(&self, seat: &WlSeatGlobal, x: Fixed, y: Fixed) { + seat.motion_surface(self, x, y) + } + + fn scroll(&self, seat: &WlSeatGlobal, delta: i32, axis: ScrollAxis) { + seat.scroll_surface(self, delta, axis); + } + + fn button(self: Rc, seat: &WlSeatGlobal, button: u32, state: KeyState) { + seat.button_surface(&self, button, state); + } + + fn focus(self: Rc, seat: &WlSeatGlobal) { + seat.focus_surface(&self); + } + + fn unfocus(self: Rc, seat: &WlSeatGlobal) { + seat.unfocus_surface(&self); + } +} diff --git a/src/ifs/wl_surface/types.rs b/src/ifs/wl_surface/types.rs index 4bcf4be9..2a31d732 100644 --- a/src/ifs/wl_surface/types.rs +++ b/src/ifs/wl_surface/types.rs @@ -1,12 +1,15 @@ use crate::client::{ClientError, RequestParser}; use crate::ifs::wl_callback::WlCallbackId; use crate::ifs::wl_region::WlRegionId; +use crate::ifs::wl_surface::{SurfaceRole, WlSurfaceId}; use crate::utils::buffd::{MsgParser, MsgParserError}; use std::fmt::{Debug, Formatter}; use thiserror::Error; #[derive(Debug, Error)] pub enum WlSurfaceError { + #[error(transparent)] + ClientError(Box), #[error("Could not process `destroy` request")] DestroyError(#[source] Box), #[error("Could not process `attach` request")] @@ -27,7 +30,14 @@ pub enum WlSurfaceError { SetBufferScaleError(#[source] Box), #[error("Could not process `damage_buffer` request")] DamageBufferError(#[source] Box), + #[error("Surface {} cannot be assigned the role {} because it already has the role {}", .id, .new.name(), .old.name())] + IncompatibleRole { + id: WlSurfaceId, + old: SurfaceRole, + new: SurfaceRole, + }, } +efrom!(WlSurfaceError, ClientError, ClientError); efrom!(WlSurfaceError, DestroyError, DestroyError); efrom!(WlSurfaceError, AttachError, AttachError); efrom!(WlSurfaceError, DamageError, DamageError); @@ -104,11 +114,14 @@ efrom!(SetInputRegionError, ClientError, ClientError); #[derive(Debug, Error)] pub enum CommitError { + #[error(transparent)] + WlSurfaceError(Box), #[error("Parsing failed")] ParseFailed(#[source] Box), #[error(transparent)] ClientError(Box), } +efrom!(CommitError, WlSurfaceError, WlSurfaceError); efrom!(CommitError, ParseFailed, MsgParserError); efrom!(CommitError, ClientError, ClientError); diff --git a/src/ifs/wl_surface/wl_subsurface/mod.rs b/src/ifs/wl_surface/wl_subsurface/mod.rs index 89c2d280..09038660 100644 --- a/src/ifs/wl_surface/wl_subsurface/mod.rs +++ b/src/ifs/wl_surface/wl_subsurface/mod.rs @@ -1,14 +1,21 @@ mod types; -use crate::client::AddObj; use crate::ifs::wl_surface::{ - RoleData, StackElement, SubsurfaceData, SurfaceRole, WlSurface, WlSurfaceId, + CommitAction, CommitContext, StackElement, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceId, }; use crate::object::{Interface, Object, ObjectId}; +use crate::rect::Rect; +use crate::tree::{Node, NodeId}; use crate::utils::buffd::MsgParser; -use std::cell::Cell; +use crate::utils::linkedlist::LinkedNode; +use crate::NumCell; +use std::cell::{Cell, RefCell}; +use std::ops::Deref; use std::rc::Rc; pub use types::*; +use crate::backend::{KeyState, ScrollAxis}; +use crate::fixed::Fixed; +use crate::ifs::wl_seat::WlSeatGlobal; const DESTROY: u32 = 0; const SET_POSITION: u32 = 1; @@ -22,49 +29,57 @@ const BAD_SURFACE: u32 = 0; const MAX_SUBSURFACE_DEPTH: u32 = 100; +tree_id!(SubsurfaceNodeId); id!(WlSubsurfaceId); pub struct WlSubsurface { id: WlSubsurfaceId, - surface: Rc, + node_id: SubsurfaceNodeId, + pub surface: Rc, pub(super) parent: Rc, + pub position: Cell, + sync_requested: Cell, + sync_ancestor: Cell, + node: RefCell>>, + depth: NumCell, + pending: PendingSubsurfaceData, } -fn update_children_sync(surface: &Rc, sync: bool) { - let children = surface.children.borrow(); +#[derive(Default)] +struct PendingSubsurfaceData { + node: RefCell>>, + position: Cell>, +} + +fn update_children_sync(surface: &WlSubsurface, sync: bool) { + let children = surface.surface.children.borrow(); if let Some(children) = &*children { for child in children.subsurfaces.values() { - let mut data = child.role_data.borrow_mut(); - if let RoleData::Subsurface(data) = &mut *data { - let was_sync = data.sync_ancestor || data.sync_requested; - data.sync_ancestor = sync; - let is_sync = data.sync_ancestor || data.sync_requested; - if was_sync != is_sync { - update_children_sync(child, sync); - } + let was_sync = child.sync(); + child.sync_ancestor.set(sync); + let is_sync = child.sync(); + if was_sync != is_sync { + update_children_sync(child, sync); } } } } fn update_children_attach( - surface: &Rc, - sync: bool, + surface: &WlSubsurface, + mut sync: bool, depth: u32, ) -> Result<(), WlSubsurfaceError> { - let children = surface.children.borrow(); + let children = surface.surface.children.borrow(); if let Some(children) = &*children { for child in children.subsurfaces.values() { - let mut data = child.role_data.borrow_mut(); - if let RoleData::Subsurface(data) = &mut *data { - data.depth = depth + 1; - if data.depth > MAX_SUBSURFACE_DEPTH { - return Err(WlSubsurfaceError::MaxDepthExceeded); - } - data.sync_ancestor = sync; - let sync = data.sync_ancestor || data.sync_requested; - update_children_attach(child, sync, depth + 1)?; + child.depth.set(depth + 1); + if depth + 1 > MAX_SUBSURFACE_DEPTH { + return Err(WlSubsurfaceError::MaxDepthExceeded); } + child.sync_ancestor.set(sync); + sync |= child.sync_requested.get(); + update_children_attach(child, sync, depth + 1)?; } } Ok(()) @@ -74,8 +89,15 @@ impl WlSubsurface { pub fn new(id: WlSubsurfaceId, surface: &Rc, parent: &Rc) -> Self { Self { id, + node_id: surface.client.state.node_ids.next(), surface: surface.clone(), parent: parent.clone(), + position: Cell::new(Default::default()), + sync_requested: Cell::new(false), + sync_ancestor: Cell::new(false), + node: RefCell::new(None), + depth: NumCell::new(0), + pending: Default::default(), } } @@ -83,13 +105,8 @@ impl WlSubsurface { if self.surface.id == self.parent.id { return Err(WlSubsurfaceError::OwnParent(self.surface.id)); } - let old_ty = self.surface.role.get(); - if !matches!(old_ty, SurfaceRole::None | SurfaceRole::Subsurface) { - return Err(WlSubsurfaceError::IncompatibleType(self.surface.id, old_ty)); - } - self.surface.role.set(SurfaceRole::Subsurface); - let mut data = self.surface.role_data.borrow_mut(); - if matches!(*data, RoleData::Subsurface(_)) { + self.surface.set_role(SurfaceRole::Subsurface)?; + if self.surface.ext.get().is_some() { return Err(WlSubsurfaceError::AlreadyAttached(self.surface.id)); } if self.surface.id == self.parent.get_root().id { @@ -98,10 +115,9 @@ impl WlSubsurface { let mut sync_ancestor = false; let mut depth = 1; { - let data = self.parent.role_data.borrow(); - if let RoleData::Subsurface(data) = &*data { - sync_ancestor = data.sync_requested || data.sync_ancestor; - depth = data.depth + 1; + if let Some(ss) = self.parent.ext.get().into_subsurface() { + sync_ancestor = ss.sync(); + depth = ss.depth.get() + 1; if depth >= MAX_SUBSURFACE_DEPTH { return Err(WlSubsurfaceError::MaxDepthExceeded); } @@ -110,138 +126,136 @@ impl WlSubsurface { let node = { let mut data = self.parent.children.borrow_mut(); let data = data.get_or_insert_with(Default::default); - data.subsurfaces - .insert(self.surface.id, self.surface.clone()); + data.subsurfaces.insert(self.surface.id, self.clone()); data.above.add_first(StackElement { pending: Cell::new(true), - surface: self.surface.clone(), + sub_surface: self.clone(), }) }; - *data = RoleData::Subsurface(Box::new(SubsurfaceData { - subsurface: self.clone(), - x: 0, - y: 0, - sync_requested: false, - sync_ancestor, - depth, - node, - pending: Default::default(), - })); - update_children_attach(&self.surface, sync_ancestor, depth)?; - + *self.pending.node.borrow_mut() = Some(node); + self.sync_ancestor.set(sync_ancestor); + self.depth.set(depth); + self.surface.ext.set(self.clone()); + update_children_attach(&self, sync_ancestor, depth)?; Ok(()) } - async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.surface.client.parse(self, parser)?; - *self.surface.role_data.borrow_mut() = RoleData::None; + self.surface.unset_ext(); + *self.node.borrow_mut() = None; { let mut children = self.parent.children.borrow_mut(); if let Some(children) = &mut *children { children.subsurfaces.remove(&self.surface.id); } } - self.surface.client.remove_obj(self).await?; - self.parent.calculate_extents(); - Ok(()) - } - - async fn set_position(&self, parser: MsgParser<'_, '_>) -> Result<(), SetPositionError> { - let req: SetPosition = self.surface.client.parse(self, parser)?; - let mut data = self.surface.role_data.borrow_mut(); - if let RoleData::Subsurface(data) = &mut *data { - data.pending.position = Some((req.x, req.y)); + if !self.surface.extents.get().is_empty() { + let mut parent_opt = Some(self.parent.clone()); + while let Some(parent) = parent_opt.take() { + if !parent.need_extents_update.get() { + break; + } + parent.calculate_extents(); + parent_opt = parent.ext.get().subsurface_parent(); + } } + self.surface.client.remove_obj(self)?; Ok(()) } - fn place(&self, sibling: WlSurfaceId, above: bool) -> Result<(), PlacementError> { + fn set_position(&self, parser: MsgParser<'_, '_>) -> Result<(), SetPositionError> { + let req: SetPosition = self.surface.client.parse(self, parser)?; + self.pending.position.set(Some((req.x, req.y))); + Ok(()) + } + + fn place(self: &Rc, sibling: WlSurfaceId, above: bool) -> Result<(), PlacementError> { if sibling == self.surface.id { return Err(PlacementError::AboveSelf(sibling)); } - let mut data = self.surface.role_data.borrow_mut(); let pdata = self.parent.children.borrow(); - if let (RoleData::Subsurface(data), Some(pdata)) = (&mut *data, &*pdata) { + if let Some(pdata) = &*pdata { let element = StackElement { pending: Cell::new(true), - surface: self.surface.clone(), + sub_surface: self.clone(), }; - if sibling == self.parent.id { - let node = match above { + let node = if sibling == self.parent.id { + match above { true => pdata.above.add_first(element), _ => pdata.below.add_last(element), - }; - data.pending.node = Some(node); + } } else { let sibling = match pdata.subsurfaces.get(&sibling) { Some(s) => s, _ => return Err(PlacementError::NotASibling(sibling, self.surface.id)), }; - let sdata = sibling.role_data.borrow(); - if let RoleData::Subsurface(p) = &*sdata { - let node = match &p.pending.node { - Some(n) => n, - _ => &p.node, - }; - let node = match above { - true => node.append(element), - _ => node.prepend(element), - }; - data.pending.node = Some(node); + let node = match sibling.pending.node.borrow().deref() { + Some(n) => n.to_ref(), + _ => match sibling.node.borrow().deref() { + Some(n) => n.to_ref(), + _ => return Ok(()), + }, + }; + match above { + true => node.append(element), + _ => node.prepend(element), } - } + }; + self.pending.node.borrow_mut().replace(node); } Ok(()) } - async fn place_above(&self, parser: MsgParser<'_, '_>) -> Result<(), PlaceAboveError> { - let req: PlaceAbove = self.surface.client.parse(self, parser)?; + fn place_above(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), PlaceAboveError> { + let req: PlaceAbove = self.surface.client.parse(self.deref(), parser)?; self.place(req.sibling, true)?; Ok(()) } - async fn place_below(&self, parser: MsgParser<'_, '_>) -> Result<(), PlaceBelowError> { - let req: PlaceBelow = self.surface.client.parse(self, parser)?; + fn place_below(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), PlaceBelowError> { + let req: PlaceBelow = self.surface.client.parse(self.deref(), parser)?; self.place(req.sibling, false)?; Ok(()) } + pub fn sync(&self) -> bool { + self.sync_requested.get() || self.sync_ancestor.get() + } + fn update_sync(&self, sync: bool) { - let mut data = self.surface.role_data.borrow_mut(); - if let RoleData::Subsurface(data) = &mut *data { - let was_sync = data.sync_requested || data.sync_ancestor; - data.sync_requested = sync; - let is_sync = data.sync_requested || data.sync_ancestor; - if was_sync != is_sync { - update_children_sync(&self.surface, is_sync); - } + let was_sync = self.sync(); + self.sync_requested.set(sync); + let is_sync = self.sync(); + if was_sync != is_sync { + update_children_sync(self, is_sync); } } - async fn set_sync(&self, parser: MsgParser<'_, '_>) -> Result<(), SetSyncError> { + fn set_sync(&self, parser: MsgParser<'_, '_>) -> Result<(), SetSyncError> { let _req: SetSync = self.surface.client.parse(self, parser)?; self.update_sync(true); Ok(()) } - async fn set_desync(&self, parser: MsgParser<'_, '_>) -> Result<(), SetDesyncError> { + fn set_desync(&self, parser: MsgParser<'_, '_>) -> Result<(), SetDesyncError> { let _req: SetDesync = self.surface.client.parse(self, parser)?; self.update_sync(false); Ok(()) } - async fn handle_request_( - &self, + fn handle_request_( + self: &Rc, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), WlSubsurfaceError> { match request { - DESTROY => self.destroy(parser).await?, - SET_POSITION => self.set_position(parser).await?, - PLACE_ABOVE => self.place_above(parser).await?, - PLACE_BELOW => self.place_below(parser).await?, - SET_SYNC => self.set_sync(parser).await?, - SET_DESYNC => self.set_desync(parser).await?, + DESTROY => self.destroy(parser)?, + SET_POSITION => self.set_position(parser)?, + PLACE_ABOVE => self.place_above(parser)?, + PLACE_BELOW => self.place_below(parser)?, + SET_SYNC => self.set_sync(parser)?, + SET_DESYNC => self.set_desync(parser)?, _ => unreachable!(), } Ok(()) @@ -263,3 +277,79 @@ impl Object for WlSubsurface { SET_DESYNC + 1 } } + +impl SurfaceExt for WlSubsurface { + fn pre_commit(self: Rc, ctx: CommitContext) -> CommitAction { + if ctx == CommitContext::RootCommit && self.sync() { + log::info!("Aborting commit due to sync"); + return CommitAction::AbortCommit; + } + CommitAction::ContinueCommit + } + + fn post_commit(&self) { + if let Some(v) = self.pending.node.take() { + log::info!("post commit"); + v.pending.set(false); + self.node.borrow_mut().replace(v); + } + if let Some((x, y)) = self.pending.position.take() { + if let Some(buffer) = self.surface.buffer.get() { + self.position.set(buffer.rect.move_(x, y)); + self.parent.need_extents_update.set(true); + } else { + self.position.set(Rect::new_empty(x, y)); + } + } + } + + fn subsurface_parent(&self) -> Option> { + Some(self.parent.clone()) + } + + fn extents_changed(&self) { + self.parent.need_extents_update.set(true); + } + + fn into_subsurface(self: Rc) -> Option> { + Some(self) + } + + fn into_node(self: Rc) -> Option> { + Some(self) + } +} + +impl Node for WlSubsurface { + fn id(&self) -> NodeId { + self.node_id.into() + } + + fn enter(self: Rc, seat: &WlSeatGlobal, x: Fixed, y: Fixed) { + seat.enter_surface(&self.surface, x, y) + } + + fn leave(&self, seat: &WlSeatGlobal) { + seat.leave_surface(&self.surface); + } + + fn motion(&self, seat: &WlSeatGlobal, x: Fixed, y: Fixed) { + seat.motion_surface(&self.surface, x, y) + } + + fn button(self: Rc, seat: &WlSeatGlobal, button: u32, state: KeyState) { + seat.button_surface(&self.surface, button, state); + } + + fn scroll(&self, seat: &WlSeatGlobal, delta: i32, axis: ScrollAxis) { + seat.scroll_surface(&self.surface, delta, axis); + } + + fn focus(self: Rc, seat: &WlSeatGlobal) { + seat.focus_surface(&self.surface); + } + + fn unfocus(self: Rc, seat: &WlSeatGlobal) { + seat.unfocus_surface(&self.surface) + } +} diff --git a/src/ifs/wl_surface/wl_subsurface/types.rs b/src/ifs/wl_surface/wl_subsurface/types.rs index 932824a5..fb33c7b5 100644 --- a/src/ifs/wl_surface/wl_subsurface/types.rs +++ b/src/ifs/wl_surface/wl_subsurface/types.rs @@ -1,5 +1,5 @@ use crate::client::{ClientError, RequestParser}; -use crate::ifs::wl_surface::{SurfaceRole, WlSurfaceId}; +use crate::ifs::wl_surface::{WlSurfaceError, WlSurfaceId}; use crate::utils::buffd::{MsgParser, MsgParserError}; use std::fmt::{Debug, Formatter}; use thiserror::Error; @@ -18,8 +18,6 @@ pub enum WlSubsurfaceError { SetSync(#[from] SetSyncError), #[error("Could not process `set_desync` request")] SetDesync(#[from] SetDesyncError), - #[error("Surface {0} cannot be assigned the role `Subsurface` because it already has the role `{1:?}`")] - IncompatibleType(WlSurfaceId, SurfaceRole), #[error("Surface {0} already has an attached `wl_subsurface`")] AlreadyAttached(WlSurfaceId), #[error("Surface {0} cannot be made its own parent")] @@ -28,7 +26,10 @@ pub enum WlSubsurfaceError { Ancestor(WlSurfaceId, WlSurfaceId), #[error("Subsurfaces cannot be nested deeper than 100 levels")] MaxDepthExceeded, + #[error(transparent)] + WlSurfaceError(Box), } +efrom!(WlSubsurfaceError, WlSurfaceError, WlSurfaceError); #[derive(Debug, Error)] pub enum DestroyError { diff --git a/src/ifs/wl_surface/xdg_surface/mod.rs b/src/ifs/wl_surface/xdg_surface/mod.rs index 09141e76..79acef79 100644 --- a/src/ifs/wl_surface/xdg_surface/mod.rs +++ b/src/ifs/wl_surface/xdg_surface/mod.rs @@ -2,17 +2,19 @@ mod types; pub mod xdg_popup; pub mod xdg_toplevel; -use crate::client::{AddObj, DynEventFormatter}; -use crate::ifs::wl_surface::xdg_surface::xdg_popup::XdgPopup; +use crate::client::DynEventFormatter; +use crate::ifs::wl_surface::xdg_surface::xdg_popup::{XdgPopup, XdgPopupId}; use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel; -use crate::ifs::wl_surface::{ - RoleData, SurfaceExtents, SurfaceRole, WlSurface, XdgPopupData, XdgSurfaceData, XdgSurfaceRole, - XdgSurfaceRoleData, XdgToplevelData, -}; +use crate::ifs::wl_surface::{CommitAction, CommitContext, SurfaceExt, SurfaceRole, WlSurface}; use crate::ifs::xdg_wm_base::XdgWmBaseObj; use crate::object::{Interface, Object, ObjectId}; +use crate::rect::Rect; +use crate::tree::Node; use crate::utils::buffd::MsgParser; -use std::ops::DerefMut; +use crate::utils::clonecell::CloneCell; +use crate::utils::copyhashmap::CopyHashMap; +use crate::NumCell; +use std::cell::Cell; use std::rc::Rc; pub use types::*; @@ -36,6 +38,32 @@ pub struct XdgSurface { id: XdgSurfaceId, base: Rc, pub surface: Rc, + requested_serial: NumCell, + acked_serial: Cell>, + geometry: Cell>, + extents: Cell, + ext: CloneCell>>, + popups: CopyHashMap>, + pending: PendingXdgSurfaceData, +} + +#[derive(Default)] +struct PendingXdgSurfaceData { + geometry: Cell>, +} + +trait XdgSurfaceExt { + fn post_commit(self: Rc) { + // nothing + } + + fn into_node(self: Rc) -> Option> { + None + } + + fn extents_changed(&self) { + // nothing + } } impl XdgSurface { @@ -44,9 +72,25 @@ impl XdgSurface { id, base: wm_base.clone(), surface: surface.clone(), + requested_serial: NumCell::new(0), + acked_serial: Cell::new(None), + geometry: Cell::new(None), + extents: Cell::new(Default::default()), + ext: Default::default(), + popups: Default::default(), + pending: Default::default(), } } + pub fn geometry(&self) -> Option { + self.geometry.get() + } + + pub fn send_configure(self: &Rc) { + let serial = self.requested_serial.fetch_add(1) + 1; + self.surface.client.event(self.configure(serial)); + } + pub fn configure(self: &Rc, serial: u32) -> DynEventFormatter { Box::new(Configure { obj: self.clone(), @@ -55,171 +99,125 @@ impl XdgSurface { } pub fn install(self: &Rc) -> Result<(), XdgSurfaceError> { - let old_role = self.surface.role.get(); - if !matches!(old_role, SurfaceRole::None | SurfaceRole::XdgSurface) { - return Err(XdgSurfaceError::IncompatibleRole(self.surface.id, old_role)); - } - self.surface.role.set(SurfaceRole::XdgSurface); - let mut data = self.surface.role_data.borrow_mut(); - if data.is_some() { + self.surface.set_role(SurfaceRole::XdgSurface)?; + if self.surface.ext.get().is_some() { return Err(XdgSurfaceError::AlreadyAttached(self.surface.id)); } - *data = RoleData::XdgSurface(Box::new(XdgSurfaceData { - xdg_surface: self.clone(), - requested_serial: 0, - acked_serial: None, - role: XdgSurfaceRole::None, - extents: None, - role_data: XdgSurfaceRoleData::None, - popups: Default::default(), - pending: Default::default(), - })); + self.surface.ext.set(self.clone()); Ok(()) } - async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.surface.client.parse(self, parser)?; + if self.ext.get().is_some() { + return Err(DestroyError::RoleNotYetDestroyed(self.id)); + } { - let mut data = self.surface.role_data.borrow_mut(); - if let RoleData::XdgSurface(rd) = &*data { - if rd.role_data.is_some() { - return Err(DestroyError::RoleNotYetDestroyed(self.id)); - } - let children = rd.popups.lock(); - for child in children.values() { - let mut data = child.surface.surface.role_data.borrow_mut(); - if let RoleData::XdgSurface(xdg) = &mut *data { - if let XdgSurfaceRoleData::Popup(p) = &mut xdg.role_data { - p.parent = None; - } - } - } + let children = self.popups.lock(); + for child in children.values() { + child.parent.set(None); } - *data = RoleData::None; } + self.surface.unset_ext(); self.base.surfaces.remove(&self.id); - self.surface.client.remove_obj(self).await?; + self.surface.client.remove_obj(self)?; Ok(()) } - async fn get_toplevel( - self: &Rc, - parser: MsgParser<'_, '_>, - ) -> Result<(), GetToplevelError> { + fn get_toplevel(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), GetToplevelError> { let req: GetToplevel = self.surface.client.parse(&**self, parser)?; - let mut data = self.surface.role_data.borrow_mut(); - if let RoleData::XdgSurface(data) = &mut *data { - if !data.role.is_compatible(XdgSurfaceRole::Toplevel) { - return Err(GetToplevelError::IncompatibleRole); - } - if data.role_data.is_some() { - self.surface.client.protocol_error( - &**self, - ALREADY_CONSTRUCTED, - format!( - "wl_surface {} already has an assigned xdg_toplevel", - self.surface.id - ), - ); - return Err(GetToplevelError::AlreadyConstructed); - } - data.role = XdgSurfaceRole::Toplevel; - let toplevel = Rc::new(XdgToplevel::new(req.id, self)); - self.surface.client.add_client_obj(&toplevel)?; - data.role_data = XdgSurfaceRoleData::Toplevel(XdgToplevelData { - toplevel, - node: None, - }); + self.surface.set_role(SurfaceRole::XdgToplevel)?; + if self.ext.get().is_some() { + self.surface.client.protocol_error( + &**self, + ALREADY_CONSTRUCTED, + format!( + "wl_surface {} already has an assigned xdg_toplevel", + self.surface.id + ), + ); + return Err(GetToplevelError::AlreadyConstructed); } + let toplevel = Rc::new(XdgToplevel::new(req.id, self)); + self.surface.client.add_client_obj(&toplevel)?; + self.ext.set(Some(toplevel)); Ok(()) } - async fn get_popup(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), GetPopupError> { + fn get_popup(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), GetPopupError> { let req: GetPopup = self.surface.client.parse(&**self, parser)?; - let mut data = self.surface.role_data.borrow_mut(); - if let RoleData::XdgSurface(data) = &mut *data { - let mut parent = None; - if req.parent.is_some() { - parent = Some(self.surface.client.get_xdg_surface(req.parent)?); - } - if !data.role.is_compatible(XdgSurfaceRole::Popup) { - return Err(GetPopupError::IncompatibleRole); - } - if data.role_data.is_some() { - self.surface.client.protocol_error( - &**self, - ALREADY_CONSTRUCTED, - format!( - "wl_surface {} already has an assigned xdg_popup", - self.surface.id - ), - ); - return Err(GetPopupError::AlreadyConstructed); - } - data.role = XdgSurfaceRole::Popup; - let popup = Rc::new(XdgPopup::new(req.id, self)); - self.surface.client.add_client_obj(&popup)?; - if let Some(parent) = &parent { - let mut data = parent.surface.role_data.borrow_mut(); - if let RoleData::XdgSurface(xdg) = &mut *data { - xdg.popups.set(self.surface.id, popup.clone()); - } - } - data.role_data = XdgSurfaceRoleData::Popup(XdgPopupData { - _popup: popup, - parent, - }); + self.surface.set_role(SurfaceRole::XdgPopup)?; + let mut parent = None; + if req.parent.is_some() { + parent = Some(self.surface.client.get_xdg_surface(req.parent)?); } + if self.ext.get().is_some() { + self.surface.client.protocol_error( + &**self, + ALREADY_CONSTRUCTED, + format!( + "wl_surface {} already has an assigned xdg_popup", + self.surface.id + ), + ); + return Err(GetPopupError::AlreadyConstructed); + } + let popup = Rc::new(XdgPopup::new(req.id, self, parent.as_ref())); + self.surface.client.add_client_obj(&popup)?; + if let Some(parent) = &parent { + parent.popups.set(req.id, popup.clone()); + } + self.ext.set(Some(popup)); Ok(()) } - async fn set_window_geometry( - &self, - parser: MsgParser<'_, '_>, - ) -> Result<(), SetWindowGeometryError> { + fn set_window_geometry(&self, parser: MsgParser<'_, '_>) -> Result<(), SetWindowGeometryError> { let req: SetWindowGeometry = self.surface.client.parse(self, parser)?; if req.height <= 0 || req.width <= 0 { return Err(SetWindowGeometryError::NonPositiveWidthHeight); } - let mut rd = self.surface.role_data.borrow_mut(); - if let RoleData::XdgSurface(xdg) = rd.deref_mut() { - let extents = SurfaceExtents { - x1: req.x, - y1: req.y, - x2: req.x + req.width, - y2: req.y + req.height, - }; - xdg.pending.extents.set(Some(extents)); - } + let extents = Rect::new_sized(req.x, req.y, req.width, req.height).unwrap(); + self.pending.geometry.set(Some(extents)); Ok(()) } - async fn ack_configure(&self, parser: MsgParser<'_, '_>) -> Result<(), AckConfigureError> { + fn ack_configure(&self, parser: MsgParser<'_, '_>) -> Result<(), AckConfigureError> { 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); - } + if self.requested_serial.get() == req.serial { + self.acked_serial.set(Some(req.serial)); } Ok(()) } - async fn handle_request_( + fn handle_request_( self: &Rc, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), XdgSurfaceError> { match request { - DESTROY => self.destroy(parser).await?, - GET_TOPLEVEL => self.get_toplevel(parser).await?, - GET_POPUP => self.get_popup(parser).await?, - SET_WINDOW_GEOMETRY => self.set_window_geometry(parser).await?, - ACK_CONFIGURE => self.ack_configure(parser).await?, + DESTROY => self.destroy(parser)?, + GET_TOPLEVEL => self.get_toplevel(parser)?, + GET_POPUP => self.get_popup(parser)?, + SET_WINDOW_GEOMETRY => self.set_window_geometry(parser)?, + ACK_CONFIGURE => self.ack_configure(parser)?, _ => unreachable!(), } Ok(()) } + + fn update_extents(&self) { + let old_extents = self.extents.get(); + let mut new_extents = self.surface.extents.get(); + if let Some(geometry) = self.geometry.get() { + new_extents = new_extents.intersect(geometry); + } + self.extents.set(new_extents); + if old_extents != new_extents { + if let Some(ext) = self.ext.get() { + ext.extents_changed(); + } + } + } } handle_request!(XdgSurface); @@ -237,3 +235,40 @@ impl Object for XdgSurface { ACK_CONFIGURE + 1 } } + +impl SurfaceExt for XdgSurface { + fn pre_commit(self: Rc, _ctx: CommitContext) -> CommitAction { + { + let ase = self.acked_serial.get(); + let rse = self.requested_serial.get(); + if ase != Some(rse) { + if ase.is_none() { + self.surface.client.event(self.configure(rse)); + } + // return CommitAction::AbortCommit; + } + } + if let Some(geometry) = self.pending.geometry.take() { + self.geometry.set(Some(geometry)); + self.update_extents(); + } + CommitAction::ContinueCommit + } + + fn post_commit(&self) { + if let Some(ext) = self.ext.get() { + ext.post_commit(); + } + } + + fn extents_changed(&self) { + self.update_extents(); + } + + fn into_node(self: Rc) -> Option> { + match self.ext.get() { + Some(e) => e.into_node(), + _ => None, + } + } +} diff --git a/src/ifs/wl_surface/xdg_surface/types.rs b/src/ifs/wl_surface/xdg_surface/types.rs index 163d3914..f221ebb0 100644 --- a/src/ifs/wl_surface/xdg_surface/types.rs +++ b/src/ifs/wl_surface/xdg_surface/types.rs @@ -2,7 +2,7 @@ use crate::client::{ClientError, EventFormatter, RequestParser}; use crate::ifs::wl_surface::xdg_surface::xdg_popup::XdgPopupId; use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevelId; use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceId, CONFIGURE}; -use crate::ifs::wl_surface::{SurfaceRole, WlSurfaceId}; +use crate::ifs::wl_surface::{WlSurfaceError, WlSurfaceId}; use crate::ifs::xdg_positioner::XdgPositionerId; use crate::object::Object; use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError}; @@ -22,11 +22,12 @@ pub enum XdgSurfaceError { SetWindowGeometryError(#[from] SetWindowGeometryError), #[error("Could not process `ack_configure` request")] AckConfigureError(#[from] AckConfigureError), - #[error("Surface {0} cannot be turned into a xdg_surface because it already has the role {}", .1.name())] - IncompatibleRole(WlSurfaceId, SurfaceRole), #[error("Surface {0} cannot be turned into a xdg_surface because it already has an attached xdg_surface")] AlreadyAttached(WlSurfaceId), + #[error(transparent)] + WlSurfaceError(Box), } +efrom!(XdgSurfaceError, WlSurfaceError, WlSurfaceError); #[derive(Debug, Error)] pub enum DestroyError { @@ -46,13 +47,14 @@ pub enum GetToplevelError { ParseFailed(#[source] Box), #[error(transparent)] ClientError(Box), - #[error("The surface already has a different role")] - IncompatibleRole, #[error("The surface already has an assigned xdg_toplevel")] AlreadyConstructed, + #[error(transparent)] + WlSurfaceError(Box), } efrom!(GetToplevelError, ParseFailed, MsgParserError); efrom!(GetToplevelError, ClientError, ClientError); +efrom!(GetToplevelError, WlSurfaceError, WlSurfaceError); #[derive(Debug, Error)] pub enum GetPopupError { @@ -60,13 +62,14 @@ pub enum GetPopupError { ParseFailed(#[source] Box), #[error(transparent)] ClientError(Box), - #[error("The surface already has a different role")] - IncompatibleRole, #[error("The surface already has an assigned xdg_popup")] AlreadyConstructed, + #[error(transparent)] + WlSurfaceError(Box), } efrom!(GetPopupError, ParseFailed, MsgParserError); efrom!(GetPopupError, ClientError, ClientError); +efrom!(GetPopupError, WlSurfaceError, WlSurfaceError); #[derive(Debug, Error)] pub enum SetWindowGeometryError { diff --git a/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs b/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs index 63ed3ae6..efb6fa90 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs @@ -1,9 +1,10 @@ mod types; -use crate::ifs::wl_surface::xdg_surface::XdgSurface; -use crate::ifs::wl_surface::{RoleData, XdgSurfaceRoleData}; +use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceExt}; use crate::object::{Interface, Object, ObjectId}; +use crate::tree::{Node, NodeId}; use crate::utils::buffd::MsgParser; +use crate::utils::clonecell::CloneCell; use std::rc::Rc; pub use types::*; @@ -18,59 +19,55 @@ const REPOSITIONED: u32 = 2; #[allow(dead_code)] const INVALID_GRAB: u32 = 1; +tree_id!(PopupId); id!(XdgPopupId); pub struct XdgPopup { id: XdgPopupId, + node_id: PopupId, pub(in super::super) surface: Rc, + pub(super) parent: CloneCell>>, } impl XdgPopup { - pub fn new(id: XdgPopupId, surface: &Rc) -> Self { + pub fn new(id: XdgPopupId, surface: &Rc, parent: Option<&Rc>) -> Self { Self { id, + node_id: surface.surface.client.state.node_ids.next(), surface: surface.clone(), + parent: CloneCell::new(parent.cloned()), } } - async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.surface.surface.client.parse(self, parser)?; { - let mut rd = self.surface.surface.role_data.borrow_mut(); - if let RoleData::XdgSurface(xdg) = &mut *rd { - if let XdgSurfaceRoleData::Popup(p) = &xdg.role_data { - if let Some(p) = &p.parent { - let mut rd = p.surface.role_data.borrow_mut(); - if let RoleData::XdgSurface(xdg) = &mut *rd { - xdg.popups.remove(&self.surface.surface.id); - } - } - } - xdg.role_data = XdgSurfaceRoleData::None; + if let Some(parent) = self.parent.take() { + parent.popups.remove(&self.id); } } Ok(()) } - async fn grab(&self, parser: MsgParser<'_, '_>) -> Result<(), GrabError> { + fn grab(&self, parser: MsgParser<'_, '_>) -> Result<(), GrabError> { let _req: Grab = self.surface.surface.client.parse(self, parser)?; Ok(()) } - async fn reposition(&self, parser: MsgParser<'_, '_>) -> Result<(), RepositionError> { + fn reposition(&self, parser: MsgParser<'_, '_>) -> Result<(), RepositionError> { let _req: Reposition = self.surface.surface.client.parse(self, parser)?; Ok(()) } - async fn handle_request_( + fn handle_request_( &self, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), XdgPopupError> { match request { - DESTROY => self.destroy(parser).await?, - GRAB => self.grab(parser).await?, - REPOSITION => self.reposition(parser).await?, + DESTROY => self.destroy(parser)?, + GRAB => self.grab(parser)?, + REPOSITION => self.reposition(parser)?, _ => unreachable!(), } Ok(()) @@ -92,3 +89,11 @@ impl Object for XdgPopup { REPOSITION + 1 } } + +impl Node for XdgPopup { + fn id(&self) -> NodeId { + self.node_id.into() + } +} + +impl XdgSurfaceExt for XdgPopup {} diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs index 046370c7..b2c1954a 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs @@ -1,10 +1,21 @@ mod types; -use crate::ifs::wl_surface::xdg_surface::XdgSurface; -use crate::ifs::wl_surface::{RoleData, XdgSurfaceRoleData}; +use crate::client::DynEventFormatter; +use crate::fixed::Fixed; +use crate::ifs::wl_seat::WlSeatGlobal; +use crate::ifs::wl_surface::wl_subsurface::WlSubsurface; +use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceExt}; use crate::object::{Interface, Object, ObjectId}; +use crate::rect::Rect; +use crate::render::Renderer; +use crate::tree::ContainerNode; +use crate::tree::{FloatNode, FoundNode, Node, NodeId, ToplevelNodeId, WorkspaceNode}; use crate::utils::buffd::MsgParser; +use crate::utils::clonecell::CloneCell; +use ahash::{AHashMap, AHashSet}; use num_derive::FromPrimitive; +use std::cell::{Cell, RefCell}; +use std::mem; use std::ops::Deref; use std::rc::Rc; pub use types::*; @@ -60,130 +71,245 @@ const STATE_TILED_BOTTOM: u32 = 8; id!(XdgToplevelId); pub struct XdgToplevel { - id: XdgToplevelId, - pub surface: Rc, + pub id: XdgToplevelId, + pub xdg: Rc, + pub node_id: ToplevelNodeId, + pub parent_node: CloneCell>>, + pub parent: CloneCell>>, + pub children: RefCell>>, + pub focus_subsurface: CloneCell>>, + states: RefCell>, } impl XdgToplevel { pub fn new(id: XdgToplevelId, surface: &Rc) -> Self { + let mut states = AHashSet::new(); + states.insert(STATE_TILED_LEFT); + states.insert(STATE_TILED_RIGHT); + states.insert(STATE_TILED_TOP); + states.insert(STATE_TILED_BOTTOM); Self { id, - surface: surface.clone(), + xdg: surface.clone(), + node_id: surface.surface.client.state.node_ids.next(), + parent_node: Default::default(), + parent: Default::default(), + children: RefCell::new(Default::default()), + focus_subsurface: Default::default(), + states: RefCell::new(states), } } - async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { - let _req: Destroy = self.surface.surface.client.parse(self, parser)?; + pub fn parent_is_float(&self) -> bool { + if let Some(parent) = self.parent_node.get() { + return parent.is_float(); + } + false + } + + pub fn configure(self: &Rc, width: i32, height: i32) -> DynEventFormatter { + Box::new(Configure { + obj: self.clone(), + width, + height, + states: self.states.borrow().iter().copied().collect(), + }) + } + + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + let _req: Destroy = self.xdg.surface.client.parse(self, parser)?; + self.xdg.ext.set(None); + if let Some(parent) = self.parent_node.take() { + parent.remove_child(self); + } { - let mut rd = self.surface.surface.role_data.borrow_mut(); - if let RoleData::XdgSurface(rd) = &mut *rd { - rd.role_data = XdgSurfaceRoleData::None; + let mut children = self.children.borrow_mut(); + for (_, child) in children.drain() { + child.parent.set(self.parent.get()); } } Ok(()) } - async fn set_parent(&self, parser: MsgParser<'_, '_>) -> Result<(), SetParentError> { - let _req: SetParent = self.surface.surface.client.parse(self, parser)?; + fn set_parent(&self, parser: MsgParser<'_, '_>) -> Result<(), SetParentError> { + let _req: SetParent = self.xdg.surface.client.parse(self, parser)?; Ok(()) } - async fn set_title(&self, parser: MsgParser<'_, '_>) -> Result<(), SetTitleError> { - let _req: SetTitle = self.surface.surface.client.parse(self, parser)?; + fn set_title(&self, parser: MsgParser<'_, '_>) -> Result<(), SetTitleError> { + let _req: SetTitle = self.xdg.surface.client.parse(self, parser)?; Ok(()) } - async fn set_app_id(&self, parser: MsgParser<'_, '_>) -> Result<(), SetAppIdError> { - let _req: SetAppId = self.surface.surface.client.parse(self, parser)?; + fn set_app_id(&self, parser: MsgParser<'_, '_>) -> Result<(), SetAppIdError> { + let _req: SetAppId = self.xdg.surface.client.parse(self, parser)?; Ok(()) } - async fn show_window_menu(&self, parser: MsgParser<'_, '_>) -> Result<(), ShowWindowMenuError> { - let _req: ShowWindowMenu = self.surface.surface.client.parse(self, parser)?; + fn show_window_menu(&self, parser: MsgParser<'_, '_>) -> Result<(), ShowWindowMenuError> { + let _req: ShowWindowMenu = self.xdg.surface.client.parse(self, parser)?; Ok(()) } - async fn move_(&self, parser: MsgParser<'_, '_>) -> Result<(), MoveError> { - let req: Move = self.surface.surface.client.parse(self, parser)?; - let rd = self.surface.surface.role_data.borrow(); - if let RoleData::XdgSurface(xdg) = rd.deref() { - if let XdgSurfaceRoleData::Toplevel(tl) = &xdg.role_data { - if let Some(node) = tl.node.as_ref() { - let seat = self.surface.surface.client.get_wl_seat(req.seat)?; - seat.move_(&node.node); - } + fn move_(&self, parser: MsgParser<'_, '_>) -> Result<(), MoveError> { + let req: Move = self.xdg.surface.client.parse(self, parser)?; + let seat = self.xdg.surface.client.get_wl_seat(req.seat)?; + if let Some(parent) = self.parent_node.get() { + if let Some(float) = parent.into_float() { + seat.move_(&float); } } Ok(()) } - async fn resize(&self, parser: MsgParser<'_, '_>) -> Result<(), ResizeError> { - let _req: Resize = self.surface.surface.client.parse(self, parser)?; + fn resize(&self, parser: MsgParser<'_, '_>) -> Result<(), ResizeError> { + let _req: Resize = self.xdg.surface.client.parse(self, parser)?; Ok(()) } - async fn set_max_size(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMaxSizeError> { - let _req: SetMaxSize = self.surface.surface.client.parse(self, parser)?; + fn set_max_size(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMaxSizeError> { + let _req: SetMaxSize = self.xdg.surface.client.parse(self, parser)?; Ok(()) } - async fn set_min_size(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMinSizeError> { - let _req: SetMinSize = self.surface.surface.client.parse(self, parser)?; + fn set_min_size(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMinSizeError> { + let _req: SetMinSize = self.xdg.surface.client.parse(self, parser)?; Ok(()) } - async fn set_maximized(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMaximizedError> { - let _req: SetMaximized = self.surface.surface.client.parse(self, parser)?; + fn set_maximized(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMaximizedError> { + let _req: SetMaximized = self.xdg.surface.client.parse(self, parser)?; Ok(()) } - async fn unset_maximized(&self, parser: MsgParser<'_, '_>) -> Result<(), UnsetMaximizedError> { - let _req: UnsetMaximized = self.surface.surface.client.parse(self, parser)?; + fn unset_maximized(&self, parser: MsgParser<'_, '_>) -> Result<(), UnsetMaximizedError> { + let _req: UnsetMaximized = self.xdg.surface.client.parse(self, parser)?; Ok(()) } - async fn set_fullscreen(&self, parser: MsgParser<'_, '_>) -> Result<(), SetFullscreenError> { - let _req: SetFullscreen = self.surface.surface.client.parse(self, parser)?; + fn set_fullscreen(&self, parser: MsgParser<'_, '_>) -> Result<(), SetFullscreenError> { + let _req: SetFullscreen = self.xdg.surface.client.parse(self, parser)?; Ok(()) } - async fn unset_fullscreen( - &self, - parser: MsgParser<'_, '_>, - ) -> Result<(), UnsetFullscreenError> { - let _req: UnsetFullscreen = self.surface.surface.client.parse(self, parser)?; + fn unset_fullscreen(&self, parser: MsgParser<'_, '_>) -> Result<(), UnsetFullscreenError> { + let _req: UnsetFullscreen = self.xdg.surface.client.parse(self, parser)?; Ok(()) } - async fn set_minimized(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMinimizedError> { - let _req: SetMinimized = self.surface.surface.client.parse(self, parser)?; + fn set_minimized(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMinimizedError> { + let _req: SetMinimized = self.xdg.surface.client.parse(self, parser)?; Ok(()) } - async fn handle_request_( + fn handle_request_( &self, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), XdgToplevelError> { match request { - DESTROY => self.destroy(parser).await?, - SET_PARENT => self.set_parent(parser).await?, - SET_TITLE => self.set_title(parser).await?, - SET_APP_ID => self.set_app_id(parser).await?, - SHOW_WINDOW_MENU => self.show_window_menu(parser).await?, - MOVE => self.move_(parser).await?, - RESIZE => self.resize(parser).await?, - SET_MAX_SIZE => self.set_max_size(parser).await?, - SET_MIN_SIZE => self.set_min_size(parser).await?, - SET_MAXIMIZED => self.set_maximized(parser).await?, - UNSET_MAXIMIZED => self.unset_maximized(parser).await?, - SET_FULLSCREEN => self.set_fullscreen(parser).await?, - UNSET_FULLSCREEN => self.unset_fullscreen(parser).await?, - SET_MINIMIZED => self.set_minimized(parser).await?, + DESTROY => self.destroy(parser)?, + SET_PARENT => self.set_parent(parser)?, + SET_TITLE => self.set_title(parser)?, + SET_APP_ID => self.set_app_id(parser)?, + SHOW_WINDOW_MENU => self.show_window_menu(parser)?, + MOVE => self.move_(parser)?, + RESIZE => self.resize(parser)?, + SET_MAX_SIZE => self.set_max_size(parser)?, + SET_MIN_SIZE => self.set_min_size(parser)?, + SET_MAXIMIZED => self.set_maximized(parser)?, + UNSET_MAXIMIZED => self.unset_maximized(parser)?, + SET_FULLSCREEN => self.set_fullscreen(parser)?, + UNSET_FULLSCREEN => self.unset_fullscreen(parser)?, + SET_MINIMIZED => self.set_minimized(parser)?, _ => unreachable!(), } Ok(()) } + + fn map_child(self: &Rc, parent: &XdgToplevel) { + let workspace = match parent.get_workspace() { + Some(w) => w, + _ => return self.map_tiled(), + }; + let output = workspace.output.get(); + let output_rect = output.position.get(); + let position = { + let extents = self.xdg.extents.get().to_origin(); + let width = extents.width(); + let height = extents.height(); + let mut x1 = output_rect.x1(); + let mut y1 = output_rect.y1(); + if width < output_rect.width() { + x1 += (output_rect.width() - width) as i32 / 2; + } + if height < output_rect.height() { + y1 += (output_rect.height() - height) as i32 / 2; + } + Rect::new_sized(x1, y1, width, height).unwrap() + }; + let state = &self.xdg.surface.client.state; + let floater = Rc::new(FloatNode { + id: state.node_ids.next(), + visible: Cell::new(true), + position: Cell::new(position), + display: output.display.clone(), + display_link: Cell::new(None), + workspace_link: Cell::new(None), + workspace: CloneCell::new(workspace.clone()), + child: CloneCell::new(Some(self.clone())), + }); + self.parent_node.set(Some(floater.clone())); + floater + .display_link + .set(Some(state.root.floaters.add_last(floater.clone()))); + floater + .workspace_link + .set(Some(workspace.floaters.add_last(floater.clone()))); + } + + fn map_tiled(self: &Rc) { + log::info!("mapping tiled"); + let state = &self.xdg.surface.client.state; + let seat = state.seat_queue.last(); + if let Some(seat) = seat { + if let Some(prev) = seat.last_tiled_keyboard_toplevel() { + if let Some(container) = prev.parent_node.get() { + if let Some(container) = container.into_container() { + container.add_child_after(&*prev, self.clone()); + self.parent_node.set(Some(container)); + return; + } + } + } + } + let output = { + let outputs = state.root.outputs.lock(); + outputs.values().next().cloned() + }; + if let Some(output) = output { + if let Some(workspace) = output.workspace.get() { + if let Some(container) = workspace.container.get() { + container.append_child(self.clone()); + self.parent_node.set(Some(container)); + } else { + let container = + Rc::new(ContainerNode::new(state, workspace.clone(), self.clone())); + workspace.set_container(&container); + self.parent_node.set(Some(container)); + }; + return; + } + } + todo!("map_tiled"); + } + + fn get_workspace(&self) -> Option> { + match self.parent_node.get() { + Some(node) => node.get_workspace(), + _ => None, + } + } } handle_request!(XdgToplevel); @@ -200,4 +326,101 @@ impl Object for XdgToplevel { fn num_requests(&self) -> u32 { SET_MINIMIZED + 1 } + + fn break_loops(&self) { + if let Some(parent) = self.parent_node.take() { + parent.remove_child(self); + } + self.parent.set(None); + let _children = mem::take(&mut *self.children.borrow_mut()); + self.focus_subsurface.set(None); + } +} + +impl Node for XdgToplevel { + fn id(&self) -> NodeId { + self.node_id.into() + } + + fn clear(&self) { + self.parent_node.set(None); + } + + fn find_child_at(&self, mut x: i32, mut y: i32) -> Option { + if let Some(geo) = self.xdg.geometry.get() { + let (xt, yt) = geo.translate_inv(x, y); + x = xt; + y = yt; + } + match self.xdg.surface.find_surface_at(x, y) { + Some((node, x, y)) => Some(FoundNode { + node: if std::ptr::eq(node.deref(), self.xdg.surface.deref()) { + node + } else { + node.ext.get().into_node().unwrap() + }, + x, + y, + contained: true, + }), + _ => None, + } + } + + fn render(&self, renderer: &mut dyn Renderer, x: i32, y: i32) { + renderer.render_toplevel(self, x, y) + } + + fn get_workspace(self: Rc) -> Option> { + self.deref().get_workspace() + } + + fn enter(self: Rc, seat: &WlSeatGlobal, _x: Fixed, _y: Fixed) { + seat.enter_toplevel(&self); + } + + fn change_size(self: Rc, width: i32, height: i32) { + self.xdg.surface.client.event(self.configure(width, height)); + self.xdg.send_configure(); + self.xdg.surface.client.flush(); + } +} + +impl XdgSurfaceExt for XdgToplevel { + fn post_commit(self: Rc) { + let surface = &self.xdg.surface; + if let Some(parent) = self.parent_node.get() { + if surface.buffer.get().is_none() { + parent.remove_child(&*self); + { + let new_parent = self.parent.get(); + let mut children = self.children.borrow_mut(); + for (_, child) in children.drain() { + child.parent.set(new_parent.clone()); + } + } + surface.client.state.tree_changed(); + } + } else if surface.buffer.get().is_some() { + if let Some(parent) = self.parent.get() { + self.map_child(&parent); + } else { + self.map_tiled(); + } + self.extents_changed(); + surface.client.state.tree_changed(); + } + } + + fn extents_changed(&self) { + if let Some(parent) = self.parent_node.get() { + let extents = self.xdg.extents.get(); + parent.child_size_changed(self, extents.width(), extents.height()); + self.xdg.surface.client.state.tree_changed(); + } + } + + fn into_node(self: Rc) -> Option> { + Some(self) + } } diff --git a/src/ifs/xdg_positioner/mod.rs b/src/ifs/xdg_positioner/mod.rs index 2fb7c1a8..7bbc2382 100644 --- a/src/ifs/xdg_positioner/mod.rs +++ b/src/ifs/xdg_positioner/mod.rs @@ -1,6 +1,6 @@ mod types; -use crate::client::{AddObj, Client}; +use crate::client::Client; use crate::ifs::xdg_wm_base::XdgWmBaseObj; use crate::object::{Interface, Object, ObjectId}; use crate::utils::buffd::MsgParser; @@ -118,13 +118,13 @@ impl XdgPositioner { Box::new(*self.position.borrow()) } - async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.client.parse(self, parser)?; - self.client.remove_obj(self).await?; + self.client.remove_obj(self)?; Ok(()) } - async fn set_size(&self, parser: MsgParser<'_, '_>) -> Result<(), SetSizeError> { + fn set_size(&self, parser: MsgParser<'_, '_>) -> Result<(), SetSizeError> { let req: SetSize = self.client.parse(self, parser)?; if req.width <= 0 || req.height <= 0 { self.client.protocol_error( @@ -140,7 +140,7 @@ impl XdgPositioner { Ok(()) } - async fn set_anchor_rect(&self, parser: MsgParser<'_, '_>) -> Result<(), SetAnchorRectError> { + fn set_anchor_rect(&self, parser: MsgParser<'_, '_>) -> Result<(), SetAnchorRectError> { let req: SetAnchorRect = self.client.parse(self, parser)?; if req.width < 0 || req.height < 0 { self.client.protocol_error( @@ -158,7 +158,7 @@ impl XdgPositioner { Ok(()) } - async fn set_anchor(&self, parser: MsgParser<'_, '_>) -> Result<(), SetAnchorError> { + fn set_anchor(&self, parser: MsgParser<'_, '_>) -> Result<(), SetAnchorError> { let req: SetAnchor = self.client.parse(self, parser)?; let anchor = match Anchor::from_u32(req.anchor) { Some(a) => a, @@ -168,7 +168,7 @@ impl XdgPositioner { Ok(()) } - async fn set_gravity(&self, parser: MsgParser<'_, '_>) -> Result<(), SetGravityError> { + fn set_gravity(&self, parser: MsgParser<'_, '_>) -> Result<(), SetGravityError> { let req: SetGravity = self.client.parse(self, parser)?; let gravity = match Gravity::from_u32(req.gravity) { Some(a) => a, @@ -178,7 +178,7 @@ impl XdgPositioner { Ok(()) } - async fn set_constraint_adjustment( + fn set_constraint_adjustment( &self, parser: MsgParser<'_, '_>, ) -> Result<(), SetConstraintAdjustmentError> { @@ -195,7 +195,7 @@ impl XdgPositioner { Ok(()) } - async fn set_offset(&self, parser: MsgParser<'_, '_>) -> Result<(), SetOffsetError> { + fn set_offset(&self, parser: MsgParser<'_, '_>) -> Result<(), SetOffsetError> { let req: SetOffset = self.client.parse(self, parser)?; let mut position = self.position.borrow_mut(); position.off_x = req.x; @@ -203,13 +203,13 @@ impl XdgPositioner { Ok(()) } - async fn set_reactive(&self, parser: MsgParser<'_, '_>) -> Result<(), SetReactiveError> { + fn set_reactive(&self, parser: MsgParser<'_, '_>) -> Result<(), SetReactiveError> { let _req: SetReactive = self.client.parse(self, parser)?; self.position.borrow_mut().reactive = true; Ok(()) } - async fn set_parent_size(&self, parser: MsgParser<'_, '_>) -> Result<(), SetParentSizeError> { + fn set_parent_size(&self, parser: MsgParser<'_, '_>) -> Result<(), SetParentSizeError> { let req: SetParentSize = self.client.parse(self, parser)?; if req.parent_width < 0 || req.parent_height < 0 { self.client.protocol_error( @@ -225,7 +225,7 @@ impl XdgPositioner { Ok(()) } - async fn set_parent_configure( + fn set_parent_configure( &self, parser: MsgParser<'_, '_>, ) -> Result<(), SetParentConfigureError> { @@ -234,22 +234,22 @@ impl XdgPositioner { Ok(()) } - async fn handle_request_( + fn handle_request_( &self, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), XdgPositionerError> { match request { - DESTROY => self.destroy(parser).await?, - SET_SIZE => self.set_size(parser).await?, - SET_ANCHOR_RECT => self.set_anchor_rect(parser).await?, - SET_ANCHOR => self.set_anchor(parser).await?, - SET_GRAVITY => self.set_gravity(parser).await?, - SET_CONSTRAINT_ADJUSTMENT => self.set_constraint_adjustment(parser).await?, - SET_OFFSET => self.set_offset(parser).await?, - SET_REACTIVE => self.set_reactive(parser).await?, - SET_PARENT_SIZE => self.set_parent_size(parser).await?, - SET_PARENT_CONFIGURE => self.set_parent_configure(parser).await?, + DESTROY => self.destroy(parser)?, + SET_SIZE => self.set_size(parser)?, + SET_ANCHOR_RECT => self.set_anchor_rect(parser)?, + SET_ANCHOR => self.set_anchor(parser)?, + SET_GRAVITY => self.set_gravity(parser)?, + SET_CONSTRAINT_ADJUSTMENT => self.set_constraint_adjustment(parser)?, + SET_OFFSET => self.set_offset(parser)?, + SET_REACTIVE => self.set_reactive(parser)?, + SET_PARENT_SIZE => self.set_parent_size(parser)?, + SET_PARENT_CONFIGURE => self.set_parent_configure(parser)?, _ => unreachable!(), } Ok(()) diff --git a/src/ifs/xdg_wm_base/mod.rs b/src/ifs/xdg_wm_base/mod.rs index 6b1b7a1e..4fe08112 100644 --- a/src/ifs/xdg_wm_base/mod.rs +++ b/src/ifs/xdg_wm_base/mod.rs @@ -1,6 +1,6 @@ mod types; -use crate::client::{AddObj, Client}; +use crate::client::Client; use crate::globals::{Global, GlobalName}; use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceId}; use crate::ifs::xdg_positioner::XdgPositioner; @@ -47,7 +47,7 @@ impl XdgWmBaseGlobal { Self { name } } - async fn bind_( + fn bind_( self: Rc, id: XdgWmBaseId, client: &Rc, @@ -65,7 +65,7 @@ impl XdgWmBaseGlobal { } impl XdgWmBaseObj { - async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.client.parse(self, parser)?; if !self.surfaces.is_empty() { self.client.protocol_error( @@ -78,11 +78,11 @@ impl XdgWmBaseObj { ); return Err(DestroyError::DefunctSurfaces); } - self.client.remove_obj(self).await?; + self.client.remove_obj(self)?; Ok(()) } - async fn create_positioner( + fn create_positioner( self: &Rc, parser: MsgParser<'_, '_>, ) -> Result<(), CreatePositionerError> { @@ -92,7 +92,7 @@ impl XdgWmBaseObj { Ok(()) } - async fn get_xdg_surface( + fn get_xdg_surface( self: &Rc, parser: MsgParser<'_, '_>, ) -> Result<(), GetXdgSurfaceError> { @@ -105,21 +105,21 @@ impl XdgWmBaseObj { Ok(()) } - async fn pong(&self, parser: MsgParser<'_, '_>) -> Result<(), PongError> { + fn pong(&self, parser: MsgParser<'_, '_>) -> Result<(), PongError> { let _req: Pong = self.client.parse(self, parser)?; Ok(()) } - async fn handle_request_( + fn handle_request_( self: &Rc, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), XdgWmBaseError> { match request { - DESTROY => self.destroy(parser).await?, - CREATE_POSITIONER => self.create_positioner(parser).await?, - GET_XDG_SURFACE => self.get_xdg_surface(parser).await?, - PONG => self.pong(parser).await?, + DESTROY => self.destroy(parser)?, + CREATE_POSITIONER => self.create_positioner(parser)?, + GET_XDG_SURFACE => self.get_xdg_surface(parser)?, + PONG => self.pong(parser)?, _ => unreachable!(), } Ok(()) diff --git a/src/macros.rs b/src/macros.rs index f4031d47..46c3c6ba 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -11,17 +11,13 @@ macro_rules! efrom { macro_rules! handle_request { ($oname:ty) => { impl crate::object::ObjectHandleRequest for $oname { - fn handle_request<'a>( + fn handle_request( self: std::rc::Rc, request: u32, - parser: crate::utils::buffd::MsgParser<'a, 'a>, - ) -> std::pin::Pin< - Box> + 'a>, - > { - Box::pin(async move { - self.handle_request_(request, parser).await?; - Ok(()) - }) + parser: crate::utils::buffd::MsgParser<'_, '_>, + ) -> Result<(), crate::client::ClientError> { + self.handle_request_(request, parser)?; + Ok(()) } } }; @@ -35,13 +31,9 @@ macro_rules! bind { client: &'a std::rc::Rc, id: crate::object::ObjectId, version: u32, - ) -> std::pin::Pin< - Box> + 'a>, - > { - Box::pin(async move { - self.bind_(id.into(), client, version).await?; - Ok(()) - }) + ) -> Result<(), crate::globals::GlobalError> { + self.bind_(id.into(), client, version)?; + Ok(()) } } }; @@ -171,3 +163,47 @@ macro_rules! bitor { } }; } + +macro_rules! tree_id { + ($id:ident) => { + #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] + pub struct $id(u32); + + impl $id { + #[allow(dead_code)] + 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) + } + } + + impl From for $id { + fn from(v: crate::tree::NodeId) -> $id { + $id(v.0) + } + } + + impl From<$id> for crate::tree::NodeId { + fn from(v: $id) -> crate::tree::NodeId { + crate::tree::NodeId(v.0) + } + } + + impl PartialEq for $id { + fn eq(&self, other: &crate::tree::NodeId) -> bool { + self.0 == other.0 + } + } + + impl PartialEq<$id> for crate::tree::NodeId { + fn eq(&self, other: &$id) -> bool { + self.0 == other.0 + } + } + }; +} diff --git a/src/main.rs b/src/main.rs index 82324b16..4edf9ca5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,6 +23,7 @@ use crate::ifs::wl_compositor::WlCompositorGlobal; use crate::ifs::wl_data_device_manager::WlDataDeviceManagerGlobal; use crate::ifs::wl_shm::WlShmGlobal; use crate::ifs::wl_subcompositor::WlSubcompositorGlobal; +use crate::ifs::wl_surface::NoneSurfaceExt; use crate::ifs::xdg_wm_base::XdgWmBaseGlobal; use crate::sighand::SighandError; use crate::state::State; @@ -54,6 +55,8 @@ mod globals; mod ifs; mod object; mod pixman; +mod rect; +mod render; mod servermem; mod sighand; mod state; @@ -119,10 +122,14 @@ fn main_() -> Result<(), MainError> { backend_events: AsyncQueue::new(), output_handlers: Default::default(), seat_ids: Default::default(), - seat_handlers: Default::default(), + seats: Default::default(), outputs: Default::default(), + seat_queue: Default::default(), + slow_clients: AsyncQueue::new(), + none_surface_ext: Rc::new(NoneSurfaceExt), }); let _global_event_handler = engine.spawn(tasks::handle_backend_events(state.clone())); + let _slow_client_handler = engine.spawn(tasks::handle_slow_clients(state.clone())); Acceptor::install(&state)?; let _backend = XorgBackend::new(&state)?; el.run()?; diff --git a/src/object.rs b/src/object.rs index 917ae7fb..c2aed6bd 100644 --- a/src/object.rs +++ b/src/object.rs @@ -1,8 +1,6 @@ use crate::client::ClientError; use crate::utils::buffd::MsgParser; use std::fmt::{Display, Formatter}; -use std::future::Future; -use std::pin::Pin; use std::rc::Rc; pub const WL_DISPLAY_ID: ObjectId = ObjectId(1); @@ -27,11 +25,11 @@ impl Display for ObjectId { } pub trait ObjectHandleRequest { - fn handle_request<'a>( + fn handle_request( self: Rc, request: u32, - parser: MsgParser<'a, 'a>, - ) -> Pin> + 'a>>; + parser: MsgParser<'_, '_>, + ) -> Result<(), ClientError>; } pub trait Object: ObjectHandleRequest + 'static { diff --git a/src/pixman/mod.rs b/src/pixman/mod.rs index fe26cde7..a27c3348 100644 --- a/src/pixman/mod.rs +++ b/src/pixman/mod.rs @@ -2,6 +2,8 @@ mod consts; include!(concat!(env!("OUT_DIR"), "/pixman_tys.rs")); +use crate::rect::Rect; +use crate::render::Border; use crate::ClientMemError; pub use consts::*; use std::cell::Cell; @@ -24,6 +26,7 @@ extern "C" { 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_set_clip_region32(image: *mut PixmanImage, region: *const Region); fn pixman_image_create_bits_no_clear( format: PixmanFormat, width: c::c_int, @@ -99,7 +102,7 @@ impl Region { slf } - pub fn rect(x: i32, y: i32, width: u32, height: u32) -> Self { + pub fn rect(x: i32, y: i32, width: i32, height: i32) -> Self { let mut new = Region::new(); unsafe { pixman_region32_init_rect(&mut new, x as _, y as _, width as _, height as _); @@ -180,6 +183,7 @@ pub struct Image { width: u32, height: u32, memory: T, + clip: Cell>, } impl Image @@ -227,9 +231,27 @@ where width, height, memory, + clip: Cell::new(None), }) } + pub fn with_clip(&self, clip: Rect, f: F) { + let region = Region::rect(clip.x1(), clip.y1(), clip.width(), clip.height()); + unsafe { + pixman_image_set_clip_region32(self.data, ®ion); + } + let region = self.clip.replace(Some(region)); + f(); + unsafe { + let region = region + .as_ref() + .map(|p| p as *const _) + .unwrap_or(ptr::null()); + pixman_image_set_clip_region32(self.data, region); + } + self.clip.set(region); + } + pub fn fill(&self, r: u8, g: u8, b: u8, a: u8) -> Result<(), PixmanError> { self.fill_rect(r, g, b, a, 0, 0, self.width as _, self.height as _) } @@ -247,7 +269,12 @@ where y2: i32, ) -> Result<(), PixmanError> { self.memory.access(|_| { - let bx = Box32 { x1, y1, x2, y2 }; + let bx = Box32 { + x1: x1.max(0), + y1: y1.max(0), + x2: x2.min(self.width as i32), + y2: y2.min(self.height as i32), + }; let color = Color { red: (r as u16) << 8, green: (g as u16) << 8, @@ -262,7 +289,7 @@ where } #[allow(clippy::too_many_arguments)] - pub fn fill_insert_border( + pub fn fill_inner_border( &self, r: u8, g: u8, @@ -273,34 +300,27 @@ where x2: i32, y2: i32, width: i32, + borders: Border, ) -> Result<(), PixmanError> { self.memory.access(|_| { let mut bx = [ - Box32 { - x1, - y1, - x2, - y2: y1 + width, - }, - Box32 { - x1: x2 - width, - y1, - x2, - y2, - }, - Box32 { - x1, - y1, - x2: x1 + width, - y2, - }, - Box32 { - x1, - y1: y2 - width, - x2, - y2, - }, + Box32 { x1, y1, x2, y2: y1 }, + Box32 { x1: x2, y1, x2, y2 }, + Box32 { x1, y1, x2: x1, y2 }, + Box32 { x1, y1: y2, x2, y2 }, ]; + if borders.contains(Border::TOP) { + bx[0].y2 += width; + } + if borders.contains(Border::RIGHT) { + bx[1].x1 -= width; + } + if borders.contains(Border::LEFT) { + bx[2].x2 += width; + } + if borders.contains(Border::BOTTOM) { + bx[3].y1 -= width; + } for bx in &mut bx { bx.x1 = bx.x1.max(0).min(self.width as i32); bx.x2 = bx.x2.max(0).min(self.width as i32); diff --git a/src/rect.rs b/src/rect.rs new file mode 100644 index 00000000..b02a720e --- /dev/null +++ b/src/rect.rs @@ -0,0 +1,115 @@ +#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] +pub struct Rect { + x1: i32, + y1: i32, + x2: i32, + y2: i32, +} + +impl Rect { + pub fn new_empty(x: i32, y: i32) -> Self { + Self { + x1: x, + y1: y, + x2: x, + y2: y, + } + } + + pub fn new(x1: i32, y1: i32, x2: i32, y2: i32) -> Option { + if x2 < x1 || y2 < y1 { + return None; + } + Some(Self { x1, y1, x2, y2 }) + } + + pub fn new_sized(x1: i32, y1: i32, width: i32, height: i32) -> Option { + if width < 0 || height < 0 { + return None; + } + Self::new(x1, y1, x1 + width, y1 + height) + } + + pub fn union(&self, other: Self) -> Self { + Self { + x1: self.x1.min(other.x1), + y1: self.y1.min(other.y1), + x2: self.x2.max(other.x2), + y2: self.y2.max(other.y2), + } + } + + pub fn intersects(&self, other: &Self) -> bool { + let x1 = self.x1.max(other.x1); + let y1 = self.y1.max(other.y1); + let x2 = self.x2.min(other.x2); + let y2 = self.y2.min(other.y2); + x1 < x2 && y1 < y2 + } + + pub fn intersect(&self, other: Self) -> Self { + let x1 = self.x1.max(other.x1); + let y1 = self.y1.max(other.y1); + let x2 = self.x2.min(other.x2).max(x1); + let y2 = self.y2.min(other.y2).max(y1); + Self { x1, y1, x2, y2 } + } + + pub fn contains(&self, x: i32, y: i32) -> bool { + self.x1 <= x && self.y1 <= y && self.x2 > x && self.y2 > y + } + + pub fn is_empty(&self) -> bool { + self.x1 == self.x2 || self.y1 == self.y2 + } + + pub fn to_origin(&self) -> Self { + Self { + x1: 0, + y1: 0, + x2: self.x2 - self.x1, + y2: self.y2 - self.y1, + } + } + + pub fn move_(&self, dx: i32, dy: i32) -> Self { + Self { + x1: self.x1.saturating_add(dx), + y1: self.y1.saturating_add(dy), + x2: self.x2.saturating_add(dx), + y2: self.y2.saturating_add(dy), + } + } + + pub fn translate(&self, x: i32, y: i32) -> (i32, i32) { + (x.wrapping_sub(self.x1), y.wrapping_sub(self.y1)) + } + + pub fn translate_inv(&self, x: i32, y: i32) -> (i32, i32) { + (x.wrapping_add(self.x1), y.wrapping_add(self.y1)) + } + + pub fn x1(&self) -> i32 { + self.x1 + } + + pub fn x2(&self) -> i32 { + self.x2 + } + + pub fn y1(&self) -> i32 { + self.y1 + } + + pub fn y2(&self) -> i32 { + self.y2 + } + + pub fn width(&self) -> i32 { + self.x2 - self.x1 + } + + pub fn height(&self) -> i32 { + self.y2 - self.y1 + } +} diff --git a/src/render/mod.rs b/src/render/mod.rs new file mode 100644 index 00000000..64d51907 --- /dev/null +++ b/src/render/mod.rs @@ -0,0 +1,28 @@ +use crate::ifs::wl_buffer::WlBuffer; +use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel; +use crate::ifs::wl_surface::WlSurface; +use crate::tree::ContainerNode; +use crate::tree::{FloatNode, OutputNode, WorkspaceNode}; + +pub mod pixman; + +bitflags::bitflags! { + pub struct Border: u32 { + const NONE = 0b0000; + const LEFT = 0b0001; + const TOP = 0b0010; + const RIGHT = 0b0100; + const BOTTOM = 0b1000; + const ALL = 0b1111; + } +} + +pub trait Renderer { + fn render_output(&mut self, output: &OutputNode); + fn render_workspace(&mut self, workspace: &WorkspaceNode); + fn render_container(&mut self, container: &ContainerNode, x: i32, y: i32); + fn render_toplevel(&mut self, toplevel: &XdgToplevel, x: i32, y: i32); + fn render_surface(&mut self, surface: &WlSurface, x: i32, y: i32); + fn render_buffer(&mut self, buffer: &WlBuffer, x: i32, y: i32); + fn render_floating(&mut self, floating: &FloatNode, x: i32, y: i32); +} diff --git a/src/render/pixman.rs b/src/render/pixman.rs new file mode 100644 index 00000000..db170f73 --- /dev/null +++ b/src/render/pixman.rs @@ -0,0 +1,203 @@ +use crate::ifs::wl_buffer::WlBuffer; +use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel; +use crate::ifs::wl_surface::WlSurface; +use crate::pixman::Image; +use crate::render::{Border, Renderer}; +use crate::servermem::ServerMem; +use crate::tree::{ + ContainerFocus, ContainerNode, ContainerSplit, CONTAINER_BORDER, CONTAINER_TITLE_HEIGHT, +}; +use crate::tree::{FloatNode, OutputNode, WorkspaceNode}; +use std::ops::Deref; +use std::rc::Rc; + +pub struct PixmanRenderer<'a> { + image: &'a Image>, +} + +const NON_COLOR: (u8, u8, u8) = (100, 100, 100); +const CHILD_COLOR: (u8, u8, u8) = (200, 200, 200); +const YES_COLOR: (u8, u8, u8) = (0, 0, 255); + +fn focus_color(focus: ContainerFocus) -> (u8, u8, u8) { + match focus { + ContainerFocus::None => NON_COLOR, + ContainerFocus::Child => CHILD_COLOR, + ContainerFocus::Yes => YES_COLOR, + } +} + +impl<'a> PixmanRenderer<'a> { + pub fn new(image: &'a Image>) -> Self { + Self { image } + } +} + +impl Renderer for PixmanRenderer<'_> { + fn render_output(&mut self, output: &OutputNode) { + if let Some(ws) = output.workspace.get() { + self.render_workspace(&ws); + } + } + + fn render_workspace(&mut self, workspace: &WorkspaceNode) { + if let Some(node) = workspace.container.get() { + self.render_container(&node, 0, 0) + } + } + + fn render_container(&mut self, container: &ContainerNode, x: i32, y: i32) { + let cwidth = container.width.get(); + let cheight = container.height.get(); + let num_children = container.num_children(); + if let Some(child) = container.mono_child.get() { + let space_per_child = cwidth / num_children as i32; + let mut rem = cwidth % num_children as i32; + let mut pos = x; + for child in container.children.iter() { + let (r, g, b) = focus_color(child.focus.get()); + let mut width = space_per_child; + if rem > 0 { + rem -= 1; + width += 1; + } + let _ = self.image.fill_rect( + r, + g, + b, + 255, + pos, + y, + pos + width as i32, + y + CONTAINER_TITLE_HEIGHT as i32, + ); + pos += width as i32; + } + self.image.with_clip(container.mono_body.get(), || { + let content = container.mono_content.get(); + child + .node + .render(self, x + content.x1(), y + content.y1()); + }); + } else { + let split = container.split.get(); + for (i, child) in container.children.iter().enumerate() { + let body = child.body.get(); + if body.x1() >= cwidth || body.y1() >= cheight { + break; + } + let (r, g, b) = focus_color(child.focus.get()); + let _ = self.image.fill_rect( + r, + g, + b, + 255, + x + body.x1(), + y + body.y1() - CONTAINER_TITLE_HEIGHT, + x + body.x2(), + y + body.y1(), + ); + { + let mut x1 = x + body.x1(); + let mut x2 = x + body.x2(); + let mut y2 = y + body.y2(); + let mut border = Border::empty(); + if i < num_children { + if split == ContainerSplit::Horizontal { + border |= Border::RIGHT; + x2 += CONTAINER_BORDER; + } else if split == ContainerSplit::Vertical { + border |= Border::BOTTOM; + y2 += CONTAINER_BORDER; + } + } + if i > 0 && split == ContainerSplit::Horizontal { + border |= Border::LEFT; + x1 -= CONTAINER_BORDER; + } + let _ = self.image.fill_inner_border( + r, + g, + b, + 255, + x1, + y + body.y1() - CONTAINER_TITLE_HEIGHT, + x2, + y2, + CONTAINER_BORDER as i32, + border, + ); + } + self.image.with_clip(body, || { + let content = child.content.get(); + child.node.render(self, x + content.x1(), y + content.y1()); + self.image.fill_inner_border(0, 0, 255, 255, x + body.x1(), y + body.y1(), x + body.x1() + body.width(), y + body.y1() + body.height(), 2, Border::all()); + self.image.fill_inner_border(255, 0, 0, 255, x + content.x1(), y + content.y1(), x + content.x1() + content.width(), y + content.y1() + content.height(), 2, Border::all()); + }); + } + } + } + + fn render_toplevel(&mut self, tl: &XdgToplevel, mut x: i32, mut y: i32) { + let surface = &tl.xdg.surface; + if let Some(geo) = tl.xdg.geometry() { + let (xt, yt) = geo.translate(x, y); + x = xt; + y = yt; + } + self.render_surface(surface, x, y); + } + + fn render_surface(&mut self, surface: &WlSurface, x: i32, y: i32) { + let children = surface.children.borrow(); + let buffer = match surface.buffer.get() { + Some(b) => b, + _ => { + log::warn!("surface has no buffer attached"); + return + }, + }; + if let Some(children) = children.deref() { + macro_rules! render { + ($children:expr) => { + for child in $children.rev_iter() { + if child.pending.get() { + continue; + } + let pos = child.sub_surface.position.get(); + self.render_surface(&child.sub_surface.surface, x + pos.x1(), y + pos.y1()); + } + }; + } + render!(&children.above); + self.render_buffer(&buffer, x, y); + render!(&children.below); + } else { + self.render_buffer(&buffer, x, y); + } + let mut fr = surface.frame_requests.borrow_mut(); + for cb in fr.drain(..) { + surface.client.dispatch_frame_requests.push(cb); + } + } + + fn render_buffer(&mut self, buffer: &WlBuffer, x: i32, y: i32) { + if let Err(e) = self.image.add_image(&buffer.image, x, y) { + let client = &buffer.client; + log::error!("Could not access client {} memory: {:#}", client.id, e); + if let Ok(d) = client.display() { + client.fatal_event( + d.implementation_error(format!("Could not access memory: {:#}", e)), + ); + } else { + client.state.clients.kill(client.id); + } + } + } + + fn render_floating(&mut self, floating: &FloatNode, x: i32, y: i32) { + if let Some(child) = floating.child.get() { + child.render(self, x, y) + } + } +} diff --git a/src/render/util.rs b/src/render/util.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/state.rs b/src/state.rs index 79c1421c..884a0e74 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,12 +1,16 @@ use crate::async_engine::{AsyncEngine, SpawnedFuture}; use crate::backend::{BackendEvent, OutputId, OutputIds, SeatId, SeatIds}; -use crate::client::Clients; +use crate::client::{Client, Clients}; use crate::event_loop::EventLoop; use crate::format::Format; use crate::globals::{AddGlobal, Globals}; use crate::ifs::wl_output::WlOutputGlobal; +use crate::ifs::wl_seat::WlSeatGlobal; +use crate::ifs::wl_surface::NoneSurfaceExt; use crate::tree::{DisplayNode, NodeIds}; +use crate::utils::asyncevent::AsyncEvent; use crate::utils::copyhashmap::CopyHashMap; +use crate::utils::linkedlist::LinkedList; use crate::utils::numcell::NumCell; use crate::utils::queue::AsyncQueue; use crate::Wheel; @@ -28,15 +32,30 @@ pub struct State { pub root: Rc, pub backend_events: AsyncQueue, pub output_handlers: RefCell>>, - pub seat_handlers: RefCell>>, + pub seats: RefCell>, pub outputs: CopyHashMap>, + pub seat_queue: LinkedList>, + pub slow_clients: AsyncQueue>, + pub none_surface_ext: Rc, +} + +pub struct SeatData { + pub handler: SpawnedFuture<()>, + pub tree_changed: Rc, } impl State { - pub async fn add_global(&self, global: &Rc) + pub fn add_global(&self, global: &Rc) where Globals: AddGlobal, { - self.globals.add_global(self, global).await + self.globals.add_global(self, global) + } + + pub fn tree_changed(&self) { + let seats = self.seats.borrow(); + for seat in seats.values() { + seat.tree_changed.trigger(); + } } } diff --git a/src/tasks.rs b/src/tasks.rs deleted file mode 100644 index 284259d5..00000000 --- a/src/tasks.rs +++ /dev/null @@ -1,141 +0,0 @@ -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::utils::clonecell::CloneCell; -use crate::State; -use std::cell::{Cell, RefCell}; -use std::rc::Rc; - -pub async fn handle_backend_events(state: Rc) { - let mut beh = BackendEventHandler { state }; - beh.handle_events().await; -} - -struct BackendEventHandler { - state: Rc, -} - -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) { - 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) { - 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, - output: Rc, -} - -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: CloneCell::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.add_global(&global).await; - self.state.outputs.set(self.output.id(), global.clone()); - 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.outputs.remove(&self.output.id()); - let _ = self.state.globals.remove(&self.state, name).await; - self.state - .output_handlers - .borrow_mut() - .remove(&self.output.id()); - } -} - -struct SeatHandler { - state: Rc, - seat: Rc, -} - -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.state, &self.seat)); - self.state.add_global(&global).await; - loop { - if self.seat.removed() { - break; - } - while let Some(event) = self.seat.event() { - global.event(event).await; - } - ae.triggered().await; - } - let _ = self.state.globals.remove(&self.state, name).await; - self.state - .seat_handlers - .borrow_mut() - .remove(&self.seat.id()); - } -} diff --git a/src/tasks/backend.rs b/src/tasks/backend.rs new file mode 100644 index 00000000..d0b48542 --- /dev/null +++ b/src/tasks/backend.rs @@ -0,0 +1,55 @@ +use crate::backend::{BackendEvent, Output, Seat}; +use crate::state::SeatData; +use crate::tasks::output::OutputHandler; +use crate::tasks::seat::SeatHandler; +use crate::utils::asyncevent::AsyncEvent; +use crate::State; +use std::rc::Rc; + +pub struct BackendEventHandler { + pub state: Rc, +} + +impl BackendEventHandler { + pub async fn handle_events(&mut self) { + loop { + let event = self.state.backend_events.pop().await; + self.handle_event(event); + } + } + + fn handle_event(&mut self, event: BackendEvent) { + match event { + BackendEvent::NewOutput(output) => self.handle_new_output(output), + BackendEvent::NewSeat(seat) => self.handle_new_seat(seat), + } + } + + fn handle_new_output(&mut self, output: Rc) { + 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); + } + + fn handle_new_seat(&mut self, seat: Rc) { + let id = seat.id(); + let tree_changed = Rc::new(AsyncEvent::default()); + let oh = SeatHandler { + state: self.state.clone(), + seat, + tree_changed: tree_changed.clone(), + }; + let handler = self.state.eng.spawn(oh.handle()); + self.state.seats.borrow_mut().insert( + id, + SeatData { + handler, + tree_changed, + }, + ); + } +} diff --git a/src/tasks/mod.rs b/src/tasks/mod.rs new file mode 100644 index 00000000..5e1ffbb7 --- /dev/null +++ b/src/tasks/mod.rs @@ -0,0 +1,19 @@ +mod backend; +mod output; +mod seat; +mod slow_clients; + +use crate::tasks::backend::BackendEventHandler; +use crate::tasks::slow_clients::SlowClientHandler; +use crate::State; +use std::rc::Rc; + +pub async fn handle_backend_events(state: Rc) { + let mut beh = BackendEventHandler { state }; + beh.handle_events().await; +} + +pub async fn handle_slow_clients(state: Rc) { + let mut sch = SlowClientHandler { state }; + sch.handle_events().await; +} diff --git a/src/tasks/output.rs b/src/tasks/output.rs new file mode 100644 index 00000000..2fc0ecdd --- /dev/null +++ b/src/tasks/output.rs @@ -0,0 +1,66 @@ +use crate::backend::Output; +use crate::ifs::wl_output::WlOutputGlobal; +use crate::tree::{Node, OutputNode, WorkspaceNode}; +use crate::utils::asyncevent::AsyncEvent; +use crate::utils::clonecell::CloneCell; +use crate::State; +use std::cell::{Cell, RefCell}; +use std::rc::Rc; + +pub struct OutputHandler { + pub state: Rc, + pub output: Rc, +} + +impl OutputHandler { + pub 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 { + display: self.state.root.clone(), + id: self.state.node_ids.next(), + backend: self.output.clone(), + workspaces: RefCell::new(vec![]), + position: Cell::new(Default::default()), + workspace: CloneCell::new(None), + }); + let workspace = Rc::new(WorkspaceNode { + id: self.state.node_ids.next(), + output: CloneCell::new(on.clone()), + container: Default::default(), + floaters: Default::default(), + }); + on.workspace.set(Some(workspace)); + 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.add_global(&global); + self.state.outputs.set(self.output.id(), global.clone()); + let mut width = 0; + let mut height = 0; + loop { + if self.output.removed() { + break; + } + let new_width = self.output.width(); + let new_height = self.output.height(); + if new_width != width || new_height != height { + width = new_width; + height = new_height; + on.clone().change_size(width, height); + } + global.update_properties(); + ae.triggered().await; + } + self.state.outputs.remove(&self.output.id()); + let _ = self.state.globals.remove(&self.state, name); + self.state + .output_handlers + .borrow_mut() + .remove(&self.output.id()); + self.state.root.outputs.remove(&self.output.id()); + } +} diff --git a/src/tasks/seat.rs b/src/tasks/seat.rs new file mode 100644 index 00000000..def2de42 --- /dev/null +++ b/src/tasks/seat.rs @@ -0,0 +1,52 @@ +use crate::backend::Seat; +use crate::ifs::wl_seat::WlSeatGlobal; +use crate::utils::asyncevent::AsyncEvent; +use crate::State; +use std::rc::Rc; + +pub struct SeatHandler { + pub state: Rc, + pub seat: Rc, + pub tree_changed: Rc, +} + +impl SeatHandler { + pub 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.state, &self.seat)); + let _tree_changed = self + .state + .eng + .spawn(tree_changed(global.clone(), self.tree_changed.clone())); + let mut _node = self.state.seat_queue.add_last(global.clone()); + self.state.add_global(&global); + loop { + if self.seat.removed() { + break; + } + let mut any_events = false; + while let Some(event) = self.seat.event() { + global.event(event); + any_events = true; + } + if any_events { + _node = self.state.seat_queue.add_last(global.clone()); + } + ae.triggered().await; + } + let _ = self.state.globals.remove(&self.state, name); + self.state.seats.borrow_mut().remove(&self.seat.id()); + } +} + +async fn tree_changed(global: Rc, tree_changed: Rc) { + loop { + tree_changed.triggered().await; + global.tree_changed(); + } +} diff --git a/src/tasks/slow_clients.rs b/src/tasks/slow_clients.rs new file mode 100644 index 00000000..3831c193 --- /dev/null +++ b/src/tasks/slow_clients.rs @@ -0,0 +1,15 @@ +use crate::State; +use std::rc::Rc; + +pub struct SlowClientHandler { + pub state: Rc, +} + +impl SlowClientHandler { + pub async fn handle_events(&mut self) { + loop { + let client = self.state.slow_clients.pop().await; + client.check_queue_size().await; + } + } +} diff --git a/src/tree.rs b/src/tree.rs deleted file mode 100644 index 30f0ee55..00000000 --- a/src/tree.rs +++ /dev/null @@ -1,222 +0,0 @@ -use crate::backend::{Output, OutputId}; -use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel; -use crate::utils::clonecell::CloneCell; -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>; - fn extents(&self) -> NodeExtents; -} - -macro_rules! base { - ($name:ident) => { - impl NodeBase for $name { - fn id(&self) -> NodeId { - self.common.id - } - - fn parent(&self) -> Option> { - self.common.parent.clone() - } - - fn extents(&self) -> NodeExtents { - self.common.extents.get() - } - } - }; -} - -pub trait Node: NodeBase { - fn into_kind(self: Rc) -> NodeKind; - fn clear(&self); - fn find_node_at(self: Rc, x: i32, y: i32) -> (Rc, i32, i32); -} - -pub enum NodeKind { - Display(Rc), - Output(Rc), - Toplevel(Rc), - Container(Rc), -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] -pub struct NodeExtents { - pub x: i32, - pub y: i32, - pub width: u32, - pub height: u32, -} - -impl NodeExtents { - pub fn contains(&self, x: i32, y: i32) -> bool { - self.x <= x - && self.y <= y - && (x - self.x) as u32 <= self.width - && (y - self.y) as u32 <= self.height - } - - pub fn translate(&self, x: i32, y: i32) -> Option<(i32, i32)> { - if self.contains(x, y) { - Some((x - self.x, y - self.y)) - } else { - None - } - } -} - -pub struct NodeCommon { - pub extents: Cell, - pub id: NodeId, - pub parent: Option>, - pub floating_outputs: RefCell>>>, -} - -impl NodeCommon { - fn clear(&self) { - mem::take(&mut *self.floating_outputs.borrow_mut()); - } -} - -pub struct DisplayNode { - pub common: NodeCommon, - pub outputs: CopyHashMap>, -} - -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) -> 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(); - } - - fn find_node_at(self: Rc, x: i32, y: i32) -> (Rc, i32, i32) { - { - let outputs = self.outputs.lock(); - for output in outputs.values() { - if let Some((x, y)) = output.common.extents.get().translate(x, y) { - return output.clone().find_node_at(x, y); - } - } - } - (self, x, y) - } -} - -pub struct OutputNode { - pub common: NodeCommon, - pub backend: Rc, - pub child: CloneCell>>, - pub floating: LinkedList>, -} - -base!(OutputNode); - -impl Node for OutputNode { - fn into_kind(self: Rc) -> NodeKind { - NodeKind::Output(self) - } - - fn clear(&self) { - self.common.clear(); - for floating in self.floating.iter() { - floating.clear(); - } - if let Some(child) = self.child.take() { - child.clear(); - } - } - - fn find_node_at(self: Rc, x: i32, y: i32) -> (Rc, i32, i32) { - for f in self.floating.rev_iter() { - let e = f.extents(); - if let Some((x, y)) = e.translate(x, y) { - return f.clone().find_node_at(x, y); - } - } - (self, x, y) - } -} - -pub struct ToplevelNode { - pub common: NodeCommon, - pub surface: Rc, -} - -base!(ToplevelNode); - -impl Node for ToplevelNode { - fn into_kind(self: Rc) -> NodeKind { - NodeKind::Toplevel(self) - } - - fn clear(&self) { - self.common.clear(); - } - - fn find_node_at(self: Rc, x: i32, y: i32) -> (Rc, i32, i32) { - (self, x, y) - } -} - -#[allow(dead_code)] -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum ContainerSplit { - Horizontal, - Vertical, -} - -pub struct ContainerNode { - pub common: NodeCommon, - pub split: Cell, - pub children: LinkedList>, -} - -base!(ContainerNode); - -impl Node for ContainerNode { - fn into_kind(self: Rc) -> NodeKind { - NodeKind::Container(self) - } - - fn clear(&self) { - for child in self.children.iter() { - child.clear(); - } - } - - fn find_node_at(self: Rc, x: i32, y: i32) -> (Rc, i32, i32) { - (self, x, y) - // todo - } -} diff --git a/src/tree/container.rs b/src/tree/container.rs new file mode 100644 index 00000000..9dd1af8e --- /dev/null +++ b/src/tree/container.rs @@ -0,0 +1,347 @@ +use crate::rect::Rect; +use crate::render::{Border, Renderer}; +use crate::tree::{FoundNode, Node, NodeId, WorkspaceNode}; +use crate::utils::clonecell::CloneCell; +use crate::utils::linkedlist::{LinkedList, LinkedNode, NodeRef}; +use crate::{NumCell, State}; +use ahash::AHashMap; +use std::cell::{Cell, RefCell}; +use std::rc::Rc; + +#[allow(dead_code)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum ContainerSplit { + Horizontal, + Vertical, +} + +#[allow(dead_code)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum ContainerFocus { + None, + Child, + Yes, +} + +tree_id!(ContainerNodeId); + +pub const CONTAINER_TITLE_HEIGHT: i32 = 18; +pub const CONTAINER_BORDER: i32 = 2; + +pub struct ContainerNode { + pub id: ContainerNodeId, + pub parent: CloneCell>, + pub split: Cell, + pub mono_child: CloneCell>>, + pub mono_body: Cell, + pub mono_content: Cell, + pub width: Cell, + pub height: Cell, + pub content_width: Cell, + pub content_height: Cell, + pub borders: Cell, + num_children: NumCell, + pub children: LinkedList, + child_nodes: RefCell>>, +} + +pub struct ContainerChild { + pub node: Rc, + pub body: Cell, + pub content: Cell, + factor: Cell, + pub focus: Cell, +} + +impl ContainerChild { + fn position_content(&self) { + let mut content = self.content.get(); + let body = self.body.get(); + let width = content.width(); + let height = content.height(); + let x1 = body.x1() + (body.width() - width) / 2; + let y1 = body.y1() + (body.height() - height) / 2; + content = Rect::new_sized(x1, y1, width, height).unwrap(); + log::debug!("body: {:?}", body); + log::debug!("content: {:?}", content); + self.content.set(content); + } +} + +impl ContainerNode { + pub fn new(state: &State, parent: Rc, child: Rc) -> Self { + let children = LinkedList::new(); + let mut child_nodes = AHashMap::new(); + child_nodes.insert( + child.id(), + children.add_last(ContainerChild { + node: child, + body: Cell::new(Default::default()), + content: Cell::new(Default::default()), + factor: Cell::new(1.0), + focus: Cell::new(ContainerFocus::None), + }), + ); + Self { + id: state.node_ids.next(), + parent: CloneCell::new(parent), + split: Cell::new(ContainerSplit::Horizontal), + mono_child: CloneCell::new(None), + mono_body: Cell::new(Default::default()), + mono_content: Cell::new(Default::default()), + width: Cell::new(0), + height: Cell::new(0), + content_width: Cell::new(0), + content_height: Cell::new(0), + borders: Cell::new(Border::NONE), + num_children: NumCell::new(1), + children, + child_nodes: RefCell::new(child_nodes), + } + } + + pub fn num_children(&self) -> usize { + self.num_children.get() + } + + pub fn append_child(self: &Rc, new: Rc) { + if let Some(child) = self.children.last() { + self.add_child_after_(&child, new); + return; + } + log::error!("Tried to add a child to a container but container is empty"); + } + + pub fn add_child_after(self: &Rc, prev: &dyn Node, new: Rc) { + let node = self.child_nodes.borrow().get(&prev.id()).map(|n| n.to_ref()); + if let Some(node) = node { + self.add_child_after_(&node, new); + return; + } + log::error!( + "Tried to add a child to a container but the preceding node is not in the container" + ); + } + + fn add_child_after_(self: &Rc, prev: &NodeRef, new: Rc) { + { + let mut links = self.child_nodes.borrow_mut(); + if links.contains_key(&new.id()) { + log::error!("Tried to add a child to a container that already contains the child"); + return; + } + links.insert( + new.id(), + prev.append(ContainerChild { + node: new.clone(), + body: Default::default(), + content: Default::default(), + factor: Cell::new(0.0), + focus: Cell::new(ContainerFocus::None), + }), + ); + } + match self.split.get() { + ContainerSplit::Horizontal => { + let new_content_size = self.content_width.get().saturating_sub(CONTAINER_BORDER); + self.content_width.set(new_content_size); + } + ContainerSplit::Vertical => { + let new_content_size = self + .content_height + .get() + .saturating_sub(CONTAINER_BORDER + CONTAINER_TITLE_HEIGHT); + self.content_height.set(new_content_size); + } + } + let num_children = self.num_children.fetch_add(1) + 1; + let new_child_factor = 1.0 / num_children as f64; + let mut sum_factors = 0.0; + for child in self.children.iter() { + let factor = if Rc::ptr_eq(&child.node, &new) { + new_child_factor + } else { + child.factor.get() * (1.0 - new_child_factor) + }; + child.factor.set(factor); + sum_factors += factor; + } + self.apply_factors(sum_factors); + } + + fn apply_factors(&self, sum_factors: f64) { + let split = self.split.get(); + let (content_size, other_content_size) = match split { + ContainerSplit::Horizontal => (self.content_width.get(), self.content_height.get()), + ContainerSplit::Vertical => (self.content_height.get(), self.content_width.get()), + }; + let num_children = self.num_children.get(); + let mut pos = 0; + let mut remaining_content_size = content_size; + for child in self.children.iter() { + let factor = child.factor.get() / sum_factors; + child.factor.set(factor); + let mut body_size = (content_size as f64 * factor).round() as i32; + body_size = body_size.min(remaining_content_size); + remaining_content_size -= body_size; + let (x1, y1, width, height) = match split { + ContainerSplit::Horizontal => (pos, CONTAINER_TITLE_HEIGHT, body_size, other_content_size), + _ => (0, pos, other_content_size, body_size), + }; + let body = Rect::new_sized(x1, y1, width, height).unwrap(); + child.body.set(body); + pos += body_size + CONTAINER_BORDER; + if split == ContainerSplit::Vertical { + pos += body_size + CONTAINER_BORDER + CONTAINER_TITLE_HEIGHT; + } + } + if remaining_content_size > 0 { + let size_per = remaining_content_size / num_children as i32; + let mut rem = remaining_content_size % num_children as i32; + pos = 0; + for child in self.children.iter() { + let mut body = child.body.get(); + let mut add = size_per; + if rem > 0 { + rem -= 1; + add += 1; + } + let (x1, y1, width, height, size) = match split { + ContainerSplit::Horizontal => { + let width = body.width() + add; + (pos, CONTAINER_TITLE_HEIGHT, width, other_content_size, width) + } + _ => { + let height = body.height() + add; + (0, pos, other_content_size, height, height) + } + }; + body = Rect::new_sized(x1, y1, width, height).unwrap(); + child.body.set(body); + pos += size + CONTAINER_BORDER; + if split == ContainerSplit::Vertical { + pos += CONTAINER_TITLE_HEIGHT; + } + } + } + for child in self.children.iter() { + let body = child.body.get(); + child.node.clone().change_size(body.width(), body.height()); + child.position_content(); + } + } +} + +impl Node for ContainerNode { + fn id(&self) -> NodeId { + self.id.into() + } + + fn clear(&self) { + let mut cn = self.child_nodes.borrow_mut(); + for (_, n) in cn.drain() { + n.node.clear(); + } + } + + fn find_child_at(&self, x: i32, y: i32) -> Option { + if let Some(child) = self.mono_child.get() { + if self.mono_body.get().contains(x, y) { + let content = self.mono_content.get(); + let (x, y) = content.translate(x, y); + return Some(FoundNode { + node: child.node.clone(), + x, + y, + contained: content.contains(x, y), + }); + } + return None; + } + for child in self.children.iter() { + if child.body.get().contains(x, y) { + let content = child.content.get(); + let (x, y) = content.translate(x, y); + return Some(FoundNode { + node: child.node.clone(), + x, + y, + contained: content.contains(x, y), + }); + } + } + None + } + + fn remove_child(&self, child: &dyn Node) { + let node = match self.child_nodes.borrow_mut().remove(&child.id()) { + Some(c) => c.to_ref(), + None => return, + }; + let num_children = self.num_children.fetch_sub(1) - 1; + if num_children == 0 { + self.parent.get().remove_child(self); + return; + } + let rem = 1.0 - node.factor.get(); + let mut sum = 0.0; + if rem <= 0.0 { + let factor = 1.0 / num_children as f64; + for child in self.children.iter() { + child.factor.set(factor) + } + sum = 1.0; + } else { + for child in self.children.iter() { + let factor = child.factor.get() / rem; + child.factor.set(factor); + sum += factor; + } + } + self.apply_factors(sum); + } + + fn child_size_changed(&self, child: &dyn Node, width: i32, height: i32) { + log::info!("child size changed {}x{}", width, height); + let cn = self.child_nodes.borrow(); + if let Some(node) = cn.get(&child.id()) { + let rect = Rect::new(0, 0, width, height).unwrap(); + node.content.set(rect); + node.position_content(); + } + } + + fn render(&self, renderer: &mut dyn Renderer, x: i32, y: i32) { + renderer.render_container(self, x, y); + } + + fn into_container(self: Rc) -> Option> { + Some(self) + } + + fn get_workspace(self: Rc) -> Option> { + self.parent.get().get_workspace() + } + + fn change_size(self: Rc, width: i32, height: i32) { + self.width.set(width); + self.height.set(height); + let num_children = self.num_children.get(); + match self.split.get() { + ContainerSplit::Horizontal => { + self.content_width + .set(width.saturating_sub((num_children - 1) as i32 * CONTAINER_BORDER)); + self.content_height + .set(height.saturating_sub(CONTAINER_TITLE_HEIGHT)); + } + ContainerSplit::Vertical => { + self.content_width.set(width); + self.content_height.set(height.saturating_sub( + (num_children - 1) as i32 * CONTAINER_BORDER + + num_children as i32 * CONTAINER_TITLE_HEIGHT, + )); + } + } + self.apply_factors(1.0); + } +} diff --git a/src/tree/mod.rs b/src/tree/mod.rs new file mode 100644 index 00000000..b0005aba --- /dev/null +++ b/src/tree/mod.rs @@ -0,0 +1,299 @@ +use crate::backend::{KeyState, Output, OutputId, ScrollAxis}; +use crate::fixed::Fixed; +use crate::ifs::wl_seat::WlSeatGlobal; +use crate::rect::Rect; +use crate::render::Renderer; +use crate::utils::clonecell::CloneCell; +use crate::utils::copyhashmap::CopyHashMap; +use crate::utils::linkedlist::{LinkedList, LinkedNode}; +use crate::NumCell; +pub use container::*; +use std::cell::{Cell, RefCell}; +use std::fmt::Display; +use std::rc::Rc; +pub use workspace::*; + +mod container; +mod workspace; + +pub struct NodeIds { + next: NumCell, +} + +impl Default for NodeIds { + fn default() -> Self { + Self { + next: NumCell::new(1), + } + } +} + +impl NodeIds { + pub fn next>(&self) -> T { + NodeId(self.next.fetch_add(1)).into() + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct NodeId(pub u32); + +impl NodeId { + #[allow(dead_code)] + pub fn raw(&self) -> u32 { + self.0 + } +} + +impl Display for NodeId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Display::fmt(&self.0, f) + } +} + +pub trait Node { + fn id(&self) -> NodeId; + + fn clear(&self) { + // nothing + } + + fn button(self: Rc, seat: &WlSeatGlobal, button: u32, state: KeyState) { + let _ = seat; + let _ = button; + let _ = state; + } + + fn scroll(&self, seat: &WlSeatGlobal, delta: i32, axis: ScrollAxis) { + let _ = seat; + let _ = delta; + let _ = axis; + } + + fn focus(self: Rc, seat: &WlSeatGlobal) { + let _ = seat; + } + + fn unfocus(self: Rc, seat: &WlSeatGlobal) { + let _ = seat; + } + + fn find_child_at(&self, x: i32, y: i32) -> Option { + let _ = x; + let _ = y; + None + } + + fn remove_child(&self, child: &dyn Node) { + let _ = child; + } + + fn child_size_changed(&self, child: &dyn Node, width: i32, height: i32) { + let _ = (child, width, height); + } + + fn leave(&self, seat: &WlSeatGlobal) { + let _ = seat; + } + + fn enter(self: Rc, seat: &WlSeatGlobal, x: Fixed, y: Fixed) { + let _ = seat; + let _ = x; + let _ = y; + } + + fn motion(&self, seat: &WlSeatGlobal, x: Fixed, y: Fixed) { + let _ = seat; + let _ = x; + let _ = y; + } + + fn render(&self, renderer: &mut dyn Renderer, x: i32, y: i32) { + let _ = renderer; + let _ = x; + let _ = y; + } + + fn into_float(self: Rc) -> Option> { + None + } + + fn into_container(self: Rc) -> Option> { + None + } + + fn is_float(&self) -> bool { + false + } + + fn get_workspace(self: Rc) -> Option> { + None + } + + fn change_size(self: Rc, width: i32, height: i32) { + let _ = width; + let _ = height; + } +} + +pub struct FoundNode { + pub node: Rc, + pub x: i32, + pub y: i32, + pub contained: bool, +} + +tree_id!(ToplevelNodeId); + +pub struct DisplayNode { + pub id: NodeId, + pub outputs: CopyHashMap>, + pub floaters: LinkedList>, +} + +impl DisplayNode { + pub fn new(id: NodeId) -> Self { + Self { + id, + outputs: Default::default(), + floaters: Default::default(), + } + } +} + +impl Node for DisplayNode { + fn id(&self) -> NodeId { + self.id + } + + fn clear(&self) { + let mut outputs = self.outputs.lock(); + for output in outputs.values() { + output.clear(); + } + outputs.clear(); + for floater in self.floaters.iter() { + floater.clear(); + } + } + + fn find_child_at(&self, x: i32, y: i32) -> Option { + let outputs = self.outputs.lock(); + for output in outputs.values() { + let pos = output.position.get(); + if pos.contains(x, y) { + let (x, y) = pos.translate(x, y); + return Some(FoundNode { + node: output.clone(), + x, + y, + contained: true, + }); + } + } + None + } +} + +tree_id!(OutputNodeId); +pub struct OutputNode { + pub display: Rc, + pub id: OutputNodeId, + pub position: Cell, + pub backend: Rc, + pub workspaces: RefCell>>, + pub workspace: CloneCell>>, +} + +impl Node for OutputNode { + fn id(&self) -> NodeId { + self.id.into() + } + + fn clear(&self) { + let mut workspaces = self.workspaces.borrow_mut(); + for workspace in workspaces.drain(..) { + workspace.clear(); + } + } + + fn find_child_at(&self, x: i32, y: i32) -> Option { + if let Some(ws) = self.workspace.get() { + Some(FoundNode { + node: ws, + x, + y, + contained: true, + }) + } else { + None + } + } + + fn render(&self, renderer: &mut dyn Renderer, _x: i32, _y: i32) { + renderer.render_output(self); + } + + fn remove_child(&self, _child: &dyn Node) { + self.workspace.set(None); + } + + fn change_size(self: Rc, width: i32, height: i32) { + self.position.set(Rect::new_sized(0, 0, width, height).unwrap()); + if let Some(c) = self.workspace.get() { + c.change_size(width, height); + } + } +} + +tree_id!(FloatNodeId); +pub struct FloatNode { + pub id: FloatNodeId, + pub visible: Cell, + pub position: Cell, + pub display: Rc, + pub display_link: Cell>>>, + pub workspace_link: Cell>>>, + pub workspace: CloneCell>, + pub child: CloneCell>>, +} + +impl Node for FloatNode { + fn id(&self) -> NodeId { + self.id.into() + } + + fn clear(&self) { + self.child.set(None); + } + + fn find_child_at(&self, x: i32, y: i32) -> Option { + self.child.get().and_then(|c| c.find_child_at(x, y)) + } + + fn remove_child(&self, _child: &dyn Node) { + self.child.set(None); + self.display_link.set(None); + self.workspace_link.set(None); + } + + fn render(&self, renderer: &mut dyn Renderer, x: i32, y: i32) { + renderer.render_floating(self, x, y) + } + + fn into_float(self: Rc) -> Option> { + Some(self) + } + + fn is_float(&self) -> bool { + true + } + + fn get_workspace(self: Rc) -> Option> { + Some(self.workspace.get()) + } + + fn child_size_changed(&self, _child: &dyn Node, width: i32, height: i32) { + let pos = self.position.get(); + self.position.set(Rect::new_sized(pos.x1(), pos.x2(), width, height).unwrap()); + } +} diff --git a/src/tree/workspace.rs b/src/tree/workspace.rs new file mode 100644 index 00000000..63d29ae0 --- /dev/null +++ b/src/tree/workspace.rs @@ -0,0 +1,67 @@ +use crate::render::Renderer; +use crate::tree::container::ContainerNode; +use crate::tree::{FloatNode, FoundNode, Node, NodeId, OutputNode}; +use crate::utils::clonecell::CloneCell; +use crate::utils::linkedlist::LinkedList; +use std::rc::Rc; + +tree_id!(WorkspaceNodeId); + +pub struct WorkspaceNode { + pub id: WorkspaceNodeId, + pub output: CloneCell>, + pub container: CloneCell>>, + pub floaters: LinkedList>, +} + +impl WorkspaceNode { + pub fn set_container(&self, container: &Rc) { + let output = self.output.get().position.get(); + container + .clone() + .change_size(output.width(), output.height()); + self.container.set(Some(container.clone())); + } +} + +impl Node for WorkspaceNode { + fn id(&self) -> NodeId { + self.id.into() + } + + fn clear(&self) { + if let Some(child) = self.container.take() { + child.clear(); + } + } + + fn find_child_at(&self, x: i32, y: i32) -> Option { + match self.container.get() { + Some(node) => Some(FoundNode { + node, + x, + y, + contained: true, + }), + _ => None, + } + } + + fn render(&self, renderer: &mut dyn Renderer, _x: i32, _y: i32) { + renderer.render_workspace(self); + } + + fn get_workspace(self: Rc) -> Option> { + Some(self) + } + + fn remove_child(&self, _child: &dyn Node) { + self.container.set(None); + } + + fn change_size(self: Rc, width: i32, height: i32) { + if let Some(c) = self.container.get() { + c.change_size(width, height); + } + } +} diff --git a/src/utils/clonecell.rs b/src/utils/clonecell.rs index 4960265b..3ae23384 100644 --- a/src/utils/clonecell.rs +++ b/src/utils/clonecell.rs @@ -1,3 +1,4 @@ +use crate::utils::linkedlist::NodeRef; use crate::utils::ptr_ext::{MutPtrExt, PtrExt}; use std::cell::UnsafeCell; use std::mem; @@ -46,3 +47,5 @@ pub unsafe trait UnsafeCellCloneSafe: Clone {} unsafe impl UnsafeCellCloneSafe for Option {} unsafe impl UnsafeCellCloneSafe for Rc {} + +unsafe impl UnsafeCellCloneSafe for NodeRef {} diff --git a/src/utils/linkedlist.rs b/src/utils/linkedlist.rs index aff37072..a90db89a 100644 --- a/src/utils/linkedlist.rs +++ b/src/utils/linkedlist.rs @@ -6,7 +6,7 @@ use std::ops::Deref; use std::ptr::NonNull; pub struct LinkedList { - root: Node, + root: LinkedNode, } impl Default for LinkedList { @@ -27,18 +27,37 @@ impl LinkedList { node.deref().prev.set(NonNull::new_unchecked(node)); node.deref().next.set(NonNull::new_unchecked(node)); Self { - root: Node { + root: LinkedNode { data: NonNull::new_unchecked(node), }, } } } - pub fn add_last(&self, t: T) -> Node { + fn endpoint(&self, ep: NonNull>) -> Option> { + unsafe { + if ep != self.root.data { + ep.as_ref().rc.fetch_add(1); + Some(NodeRef { data: ep }) + } else { + None + } + } + } + + pub fn last(&self) -> Option> { + unsafe { self.endpoint(self.root.data.as_ref().prev.get()) } + } + + pub fn first(&self) -> Option> { + unsafe { self.endpoint(self.root.data.as_ref().next.get()) } + } + + pub fn add_last(&self, t: T) -> LinkedNode { self.root.prepend(t) } - pub fn add_first(&self, t: T) -> Node { + pub fn add_first(&self, t: T) -> LinkedNode { self.root.append(t) } @@ -127,11 +146,11 @@ impl Drop for RevLinkedListIter { } } -pub struct Node { +pub struct LinkedNode { data: NonNull>, } -impl Deref for Node { +impl Deref for LinkedNode { type Target = T; fn deref(&self) -> &Self::Target { @@ -159,6 +178,25 @@ impl Drop for NodeRef { } } +impl Clone for NodeRef { + fn clone(&self) -> Self { + unsafe { + self.data.as_ref().rc.fetch_add(1); + Self { data: self.data } + } + } +} + +impl NodeRef { + pub fn prepend(&self, t: T) -> LinkedNode { + unsafe { prepend(self.data, t) } + } + + pub fn append(&self, t: T) -> LinkedNode { + unsafe { append(self.data, t) } + } +} + struct NodeData { rc: NumCell, prev: Cell>>, @@ -172,7 +210,7 @@ unsafe fn dec_ref_count(slf: NonNull>, n: usize) { } } -impl Drop for Node { +impl Drop for LinkedNode { fn drop(&mut self) { unsafe { { @@ -185,34 +223,45 @@ impl Drop for Node { } } -impl Node { - pub fn prepend(&self, t: T) -> Node { - unsafe { - let data = self.data.as_ref(); - let node = NonNull::new_unchecked(Box::into_raw(Box::new(NodeData { - rc: NumCell::new(3), - prev: Cell::new(data.prev.get()), - next: Cell::new(self.data), - data: MaybeUninit::new(t), - }))); - data.prev.get().as_ref().next.set(node); - data.prev.set(node); - Node { data: node } - } +impl LinkedNode { + pub fn prepend(&self, t: T) -> LinkedNode { + unsafe { prepend(self.data, t) } } - pub fn append(&self, t: T) -> Node { + pub fn append(&self, t: T) -> LinkedNode { + unsafe { append(self.data, t) } + } + + pub fn to_ref(&self) -> NodeRef { unsafe { - let data = self.data.as_ref(); - let node = NonNull::new_unchecked(Box::into_raw(Box::new(NodeData { - rc: NumCell::new(3), - prev: Cell::new(self.data), - next: Cell::new(data.next.get()), - data: MaybeUninit::new(t), - }))); - data.next.get().as_ref().prev.set(node); - data.next.set(node); - Node { data: node } + self.data.as_ref().rc.fetch_add(1); + NodeRef { data: self.data } } } } + +unsafe fn prepend(data: NonNull>, t: T) -> LinkedNode { + let dref = data.as_ref(); + let node = NonNull::new_unchecked(Box::into_raw(Box::new(NodeData { + rc: NumCell::new(3), + prev: Cell::new(dref.prev.get()), + next: Cell::new(data), + data: MaybeUninit::new(t), + }))); + dref.prev.get().as_ref().next.set(node); + dref.prev.set(node); + LinkedNode { data: node } +} + +unsafe fn append(data: NonNull>, t: T) -> LinkedNode { + let dref = data.as_ref(); + let node = NonNull::new_unchecked(Box::into_raw(Box::new(NodeData { + rc: NumCell::new(3), + prev: Cell::new(data), + next: Cell::new(dref.next.get()), + data: MaybeUninit::new(t), + }))); + dref.next.get().as_ref().prev.set(node); + dref.next.set(node); + LinkedNode { data: node } +} diff --git a/src/utils/numcell.rs b/src/utils/numcell.rs index de8c0f1a..2a36a517 100644 --- a/src/utils/numcell.rs +++ b/src/utils/numcell.rs @@ -12,13 +12,18 @@ impl NumCell { Self { t: Cell::new(t) } } + #[inline(always)] + pub fn set(&self, n: T) { + let _ = self.t.replace(n); + } + #[inline(always)] pub fn replace(&self, n: T) -> T { self.t.replace(n) } #[inline(always)] - pub fn load(&self) -> T + pub fn get(&self) -> T where T: Copy, {