diff --git a/Cargo.lock b/Cargo.lock index 36d1c769..681b1241 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -242,6 +242,7 @@ dependencies = [ "rand", "renderdoc", "repc", + "smallvec", "thiserror", "uapi", "xcb-dl", @@ -460,9 +461,9 @@ checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" [[package]] name = "smallvec" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "syn" diff --git a/Cargo.toml b/Cargo.toml index 6a2e862b..3fe7fef9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ isnt = "0.1.0" once_cell = "1.9.0" rand = "0.8.4" renderdoc = "0.10.1" +smallvec = { version = "1.8.0", features = ["const_generics", "const_new", "union"] } [build-dependencies] repc = "0.1.1" diff --git a/src/client/mod.rs b/src/client/mod.rs index 8627df4f..00b72ea6 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -352,6 +352,9 @@ impl Drop for ClientHolder { pub trait EventFormatter: Debug { fn format(self: Box, fmt: &mut MsgFormatter<'_>); fn obj(&self) -> &dyn Object; + fn should_log(&self) -> bool { + true + } } pub type DynEventFormatter = Box; @@ -522,6 +525,9 @@ impl Client { } pub fn log_event(&self, event: &dyn EventFormatter) { + if !event.should_log() { + return; + } let obj = event.obj(); log::trace!( "Client {} <= {}@{}.{:?}", @@ -579,7 +585,6 @@ simple_add_obj!(WlShmObj); simple_add_obj!(WlShmPool); simple_add_obj!(WlSubcompositorObj); simple_add_obj!(WlSubsurface); -simple_add_obj!(XdgToplevel); simple_add_obj!(XdgPopup); simple_add_obj!(WlOutputObj); simple_add_obj!(WlKeyboard); @@ -615,3 +620,4 @@ dedicated_add_obj!(XdgSurface, xdg_surfaces); dedicated_add_obj!(WlBuffer, buffers); dedicated_add_obj!(WlSeatObj, seats); dedicated_add_obj!(XdgPositioner, xdg_positioners); +dedicated_add_obj!(XdgToplevel, xdg_toplevel); diff --git a/src/client/objects.rs b/src/client/objects.rs index 438eae2e..2eabe45d 100644 --- a/src/client/objects.rs +++ b/src/client/objects.rs @@ -15,6 +15,8 @@ use ahash::AHashMap; use std::cell::{RefCell, RefMut}; use std::mem; use std::rc::Rc; +use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::{XdgToplevel, XdgToplevelId}; +use crate::tree::Node; pub struct Objects { pub display: CloneCell>>, @@ -22,6 +24,7 @@ pub struct Objects { registries: CopyHashMap>, pub surfaces: CopyHashMap>, pub xdg_surfaces: CopyHashMap>, + pub xdg_toplevel: CopyHashMap>, pub xdg_positioners: CopyHashMap>, pub regions: CopyHashMap>, pub buffers: CopyHashMap>, @@ -41,6 +44,7 @@ impl Objects { registries: Default::default(), surfaces: Default::default(), xdg_surfaces: Default::default(), + xdg_toplevel: Default::default(), xdg_positioners: Default::default(), regions: Default::default(), buffers: Default::default(), @@ -51,6 +55,13 @@ impl Objects { } pub fn destroy(&self) { + { + let mut toplevel = self.xdg_toplevel.lock(); + for obj in toplevel.values_mut() { + obj.destroy_node(true); + } + toplevel.clear(); + } { let mut registry = self.registry.lock(); for obj in registry.values_mut() { diff --git a/src/ifs/wl_seat/handling.rs b/src/ifs/wl_seat/handling.rs new file mode 100644 index 00000000..7288c0cd --- /dev/null +++ b/src/ifs/wl_seat/handling.rs @@ -0,0 +1,384 @@ +use std::ops::Deref; +use std::rc::Rc; +use crate::backend::{KeyState, OutputId, ScrollAxis, SeatEvent, SeatId}; +use crate::client::{ClientId, DynEventFormatter}; +use crate::fixed::Fixed; +use crate::ifs::wl_seat::{wl_pointer, WlSeatGlobal, WlSeatObj}; +use crate::ifs::wl_seat::wl_keyboard::WlKeyboard; +use crate::ifs::wl_seat::wl_pointer::{POINTER_FRAME_SINCE_VERSION, WlPointer}; +use crate::ifs::wl_surface::WlSurface; +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::tree::{FloatNode, FoundNode, Node}; +use crate::utils::smallmap::SmallMap; +use crate::xkbcommon::ModifierState; + +#[derive(Default)] +pub struct NodeSeatState { + pointer_foci: SmallMap, 1>, + kb_foci: SmallMap, 1>, +} + +impl NodeSeatState { + fn enter(&self, seat: &Rc) { + self.pointer_foci.insert(seat.seat.id(), seat.clone()); + } + + fn leave(&self, seat: &WlSeatGlobal) { + self.pointer_foci.remove(&seat.seat.id()); + } + + fn focus(&self, seat: &Rc) { + self.kb_foci.insert(seat.seat.id(), seat.clone()); + } + + fn unfocus(&self, seat: &WlSeatGlobal) { + self.kb_foci.remove(&seat.seat.id()); + } + + pub fn destroy_node(&self, node: &dyn Node) { + let node_id = node.id(); + while let Some((_, seat)) = self.pointer_foci.pop() { + let mut ps = seat.pointer_stack.borrow_mut(); + while let Some(last) = ps.pop() { + if last.id() == node_id { + break; + } + } + seat.state.tree_changed(); + } + while let Some((_, seat)) = self.kb_foci.pop() { + seat.keyboard_node.set(seat.state.root.clone()); + if let Some(tl) = seat.toplevel_focus_history.last() { + seat.focus_xdg_surface(&tl.xdg); + } + } + } +} + +impl WlSeatGlobal { + pub fn event(self: &Rc, event: SeatEvent) { + match event { + 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), + } + } + + fn output_position_event(self: &Rc, 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.set_new_position(x, y); + } + + fn motion_event(self: &Rc, dx: Fixed, dy: Fixed) { + let (x, y) = self.pos.get(); + self.set_new_position(x + dx, y + dy); + } + + fn button_event(self: &Rc, button: u32, state: KeyState) { + if state == KeyState::Released { + self.move_.set(false); + } + if let Some(node) = self.pointer_node() { + node.button(self, button, state); + } + } + + fn scroll_event(&self, delta: i32, axis: ScrollAxis) { + if let Some(node) = self.pointer_node() { + node.scroll(self, delta, axis); + } + } + + 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; + // } + // } + } +} + +impl WlSeatGlobal { + fn pointer_node(&self) -> Option> { + self.pointer_stack.borrow().last().cloned() + } + + 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 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())); + } + + fn focus_xdg_surface(self: &Rc, xdg: &Rc) { + self.focus_surface(&xdg.focus_surface(self)); + } + + fn focus_surface(self: &Rc, surface: &Rc) { + let old = self.keyboard_node.get(); + if old.id() == surface.node_id { + return; + } + old.unfocus(self); + old.seat_state().unfocus(self); + + surface.seat_state().focus(self); + surface.clone().focus(self); + self.keyboard_node.set(surface.clone()); + + let pressed_keys: Vec<_> = self.pressed_keys.borrow().iter().copied().collect(); + log::info!("enter"); + self.surface_kb_event(0, &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(0, &surface, |k| { + k.modifiers(0, mods_depressed, mods_latched, mods_locked, group) + }); + } + + fn for_each_seat(&self, ver: u32, client: ClientId, mut f: C) + where + C: FnMut(&Rc), + { + let bindings = self.bindings.borrow(); + if let Some(hm) = bindings.get(&client) { + for seat in hm.values() { + if seat.version >= ver { + f(seat); + } + } + } + } + + fn for_each_pointer(&self, ver: u32, client: ClientId, mut f: C) + where + C: FnMut(&Rc), + { + self.for_each_seat(ver, client, |seat| { + let pointers = seat.pointers.lock(); + for pointer in pointers.values() { + f(pointer); + } + }) + } + + fn for_each_kb(&self, ver: u32, client: ClientId, mut f: C) + where + C: FnMut(&Rc), + { + self.for_each_seat(ver, client, |seat| { + let keyboards = seat.keyboards.lock(); + for keyboard in keyboards.values() { + f(keyboard); + } + }) + } + + fn surface_pointer_frame(&self, surface: &WlSurface) { + self.surface_pointer_event(POINTER_FRAME_SINCE_VERSION, surface, |p| p.frame()); + } + + fn surface_pointer_event(&self, ver: u32, surface: &WlSurface, mut f: F) + where + F: FnMut(&Rc) -> DynEventFormatter, + { + let client = &surface.client; + self.for_each_pointer(ver, client.id, |p| { + client.event(f(p)); + }); + client.flush(); + } + + fn surface_kb_event(&self, ver: u32, surface: &WlSurface, mut f: F) + where + F: FnMut(&Rc) -> DynEventFormatter, + { + let client = &surface.client; + self.for_each_kb(ver, client.id, |p| { + client.event(f(p)); + }); + client.flush(); + } + + fn set_new_position(self: &Rc, x: Fixed, y: Fixed) { + self.pos.set((x, y)); + self.handle_new_position(true); + } + + pub fn tree_changed(self: &Rc) { + self.handle_new_position(false); + } + + fn handle_new_position(self: &Rc, changed: bool) { + let (x, y) = self.pos.get(); + let mut found_tree = self.found_tree.borrow_mut(); + 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 x_int = x.round_down(); + let y_int = y.round_down(); + found_tree.push(FoundNode { + node: self.state.root.clone(), + x: x_int, + y: y_int, + }); + self.state.root.find_tree_at(x_int, y_int, &mut found_tree); + let mut divergence = found_tree.len().min(stack.len()); + for (i, (found, stack)) in found_tree.iter().zip(stack.iter()).enumerate() { + if found.node.id() != stack.id() { + divergence = i; + break; + } + } + if (stack.len(), found_tree.len()) == (divergence, divergence) { + if changed { + if let Some(node) = found_tree.last() { + node.node.motion(self, x.apply_fract(node.x), y.apply_fract(node.y)); + } + } + } else { + for old in stack.drain(divergence..).rev() { + old.leave(self); + old.seat_state().leave(self); + } + for new in found_tree.drain(divergence..) { + new.node.seat_state().enter(self); + new.node.clone().enter(self, x.apply_fract(new.x), y.apply_fract(new.y)); + stack.push(new.node); + } + } + found_tree.clear(); + } +} + +// Button callbacks +impl WlSeatGlobal { + pub fn button_surface(self: &Rc, surface: &Rc, button: u32, state: KeyState) { + let (state, pressed) = match state { + KeyState::Released => (wl_pointer::RELEASED, false), + KeyState::Pressed => (wl_pointer::PRESSED, true), + }; + self.surface_pointer_event(0, surface, |p| p.button(0, 0, button, state)); + self.surface_pointer_frame(surface); + if pressed { + self.focus_surface(surface); + } + } +} + +// Scroll callbacks +impl WlSeatGlobal { + 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, + }; + self.surface_pointer_event(0, surface, |p| p.axis(0, axis, Fixed::from_int(delta))); + self.surface_pointer_frame(surface); + } +} + +// Motion callbacks +impl WlSeatGlobal { + pub fn motion_surface(&self, n: &WlSurface, x: Fixed, y: Fixed) { + self.surface_pointer_event(0, n, |p| p.motion(0, x, y)); + self.surface_pointer_frame(n); + } +} + +// Enter callbacks +impl WlSeatGlobal { + pub fn enter_toplevel(self: &Rc, n: &Rc) { + let node = self.toplevel_focus_history.add_last(n.clone()); + n.toplevel_history.insert(self.id(), node); + self.focus_xdg_surface(&n.xdg); + } + + pub fn enter_popup(self: &Rc, n: &Rc) { + self.focus_xdg_surface(&n.xdg); + } + + pub fn enter_surface(&self, n: &WlSurface, x: Fixed, y: Fixed) { + self.surface_pointer_event(0, n, |p| p.enter(0, n.id, x, y)); + self.surface_pointer_frame(n); + } +} + +// Leave callbacks +impl WlSeatGlobal { + pub fn leave_surface(&self, n: &WlSurface) { + self.surface_pointer_event(0, n, |p| p.leave(0, n.id)); + self.surface_pointer_frame(n); + } +} + +// Unfocus callbacks +impl WlSeatGlobal { + pub fn unfocus_surface(&self, surface: &WlSurface) { + self.surface_kb_event(0, surface, |k| k.leave(0, surface.id)) + } +} diff --git a/src/ifs/wl_seat/mod.rs b/src/ifs/wl_seat/mod.rs index f0f57514..9d52071c 100644 --- a/src/ifs/wl_seat/mod.rs +++ b/src/ifs/wl_seat/mod.rs @@ -2,34 +2,32 @@ mod types; pub mod wl_keyboard; pub mod wl_pointer; pub mod wl_touch; +mod handling; -use crate::backend::{KeyState, OutputId, ScrollAxis, Seat, SeatEvent}; +use crate::backend::{Seat, SeatId}; use crate::client::{Client, ClientId, DynEventFormatter}; use crate::fixed::Fixed; use crate::globals::{Global, GlobalName}; use crate::ifs::wl_seat::wl_keyboard::{WlKeyboard, WlKeyboardId, REPEAT_INFO_SINCE}; -use crate::ifs::wl_seat::wl_pointer::{WlPointer, WlPointerId, POINTER_FRAME_SINCE_VERSION}; +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::ifs::wl_surface::xdg_surface::xdg_toplevel::{XdgToplevel}; use crate::object::{Interface, Object, ObjectId}; -use crate::tree::{FloatNode, Node}; +use crate::tree::{FloatNode, FoundNode, Node}; use crate::utils::buffd::MsgParser; use crate::utils::clonecell::CloneCell; use crate::utils::copyhashmap::CopyHashMap; -use crate::utils::linkedlist::{LinkedList, LinkedNode}; -use crate::xkbcommon::{ModifierState, XkbContext, XkbState}; +use crate::utils::linkedlist::{LinkedList}; +use crate::xkbcommon::{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}; -use crate::ifs::wl_surface::xdg_surface::xdg_popup::XdgPopup; -use crate::ifs::wl_surface::xdg_surface::XdgSurface; +pub use handling::NodeSeatState; id!(WlSeatId); @@ -55,14 +53,14 @@ const BTN_LEFT: u32 = 0x110; pub struct WlSeatGlobal { name: GlobalName, state: Rc, - _seat: Rc, + seat: Rc, move_: Cell, move_start_pos: Cell<(Fixed, Fixed)>, extents_start_pos: Cell<(i32, i32)>, pos: Cell<(Fixed, Fixed)>, pointer_stack: RefCell>>, + found_tree: RefCell>, toplevel_focus_history: LinkedList>, - toplevel_focus_stash: RefCell>>>, keyboard_node: CloneCell>, pressed_keys: RefCell>, bindings: RefCell>>>, @@ -87,20 +85,20 @@ impl WlSeatGlobal { memfd.raw(), c::F_SEAL_SEAL | c::F_SEAL_GROW | c::F_SEAL_SHRINK | c::F_SEAL_WRITE, ) - .unwrap(); + .unwrap(); (state, Rc::new(memfd), (string.len() + 1) as _) }; Self { name, state: state.clone(), - _seat: seat.clone(), + seat: seat.clone(), move_: Cell::new(false), move_start_pos: Cell::new((Fixed(0), Fixed(0))), extents_start_pos: Cell::new((0, 0)), pos: Cell::new((Fixed(0), Fixed(0))), pointer_stack: RefCell::new(vec![]), + found_tree: 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(), @@ -110,321 +108,8 @@ impl WlSeatGlobal { } } - 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 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), - 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), - } - } - - 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(0, 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(0, &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(0, surface, |k| { - k.modifiers(0, mods_depressed, mods_latched, mods_locked, group) - }); - } - - pub fn unfocus_surface(&self, surface: &Rc) { - self.surface_kb_event(0, 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.focus_xdg_surface(&toplevel.xdg); - } - - fn focus_xdg_surface(&self, xdg: &Rc) { - self.keyboard_node.get().unfocus(self); - let focus_surface; - if let Some(ss) = xdg.focus_subsurface.get() { - focus_surface = ss.surface.clone(); - self.keyboard_node.set(ss); - } else { - focus_surface = 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.set_new_position(x, y); - } - - fn for_each_seat(&self, ver: u32, client: ClientId, mut f: C) - where - C: FnMut(&Rc), - { - let bindings = self.bindings.borrow(); - if let Some(hm) = bindings.get(&client) { - for seat in hm.values() { - if seat.version >= ver { - f(seat); - } - } - } - } - - fn for_each_pointer(&self, ver: u32, client: ClientId, mut f: C) - where - C: FnMut(&Rc), - { - self.for_each_seat(ver, client, |seat| { - let pointers = seat.pointers.lock(); - for pointer in pointers.values() { - f(pointer); - } - }) - } - - fn for_each_kb(&self, ver: u32, client: ClientId, mut f: C) - where - C: FnMut(&Rc), - { - self.for_each_seat(ver, client, |seat| { - let keyboards = seat.keyboards.lock(); - for keyboard in keyboards.values() { - f(keyboard); - } - }) - } - - fn surface_pointer_event(&self, ver: u32, surface: &WlSurface, mut f: F) - where - F: FnMut(&Rc) -> DynEventFormatter, - { - let client = &surface.client; - self.for_each_pointer(ver, client.id, |p| { - client.event(f(p)); - }); - client.flush(); - } - - fn surface_kb_event(&self, ver: u32, surface: &WlSurface, mut f: F) - where - F: FnMut(&Rc) -> DynEventFormatter, - { - let client = &surface.client; - self.for_each_kb(ver, client.id, |p| { - client.event(f(p)); - }); - client.flush(); - } - - fn set_new_position(&self, x: Fixed, y: Fixed) { - self.pos.set((x, y)); - self.handle_new_position(true); - } - - 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(); - 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); - } - } - } - - pub fn leave_surface(&self, n: &WlSurface) { - self.surface_pointer_event(0, n, |p| p.leave(0, n.id)); - } - - pub fn enter_toplevel(&self, n: &Rc) { - self.focus_toplevel(n); - } - - pub fn enter_popup(&self, n: &Rc) { - self.focus_xdg_surface(&n.xdg); - } - - pub fn enter_surface(&self, n: &WlSurface, x: Fixed, y: Fixed) { - self.surface_pointer_event(0, n, |p| p.enter(0, n.id, x, y)); - } - - pub fn motion_surface(&self, n: &WlSurface, x: Fixed, y: Fixed) { - self.surface_pointer_event(0, n, |p| p.motion(0, x, y)); - self.surface_pointer_event(POINTER_FRAME_SINCE_VERSION, 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 = match self.pointer_stack.borrow().last().cloned() { - Some(v) => v, - _ => return, - }; - let mut enter = false; - { - let kb_node = self.keyboard_node.get(); - if kb_node.id() != node.id() { - enter = true; - kb_node.unfocus(self); - self.keyboard_node.set(node.clone()); - } - } - node.clone().button(self, button, state); - if enter { - node.focus(self); - } - } - - 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, - }; - self.surface_pointer_event(0, surface, |p| p.axis(0, axis, Fixed::from_int(delta))); - self.surface_pointer_event(POINTER_FRAME_SINCE_VERSION, 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); - } - } - - 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; - // } - // } + pub fn id(&self) -> SeatId { + self.seat.id() } fn bind_( diff --git a/src/ifs/wl_surface/mod.rs b/src/ifs/wl_surface/mod.rs index 2e2f777b..4e4a5089 100644 --- a/src/ifs/wl_surface/mod.rs +++ b/src/ifs/wl_surface/mod.rs @@ -7,7 +7,7 @@ use crate::client::{Client, RequestParser}; use crate::fixed::Fixed; use crate::ifs::wl_buffer::WlBuffer; use crate::ifs::wl_callback::WlCallback; -use crate::ifs::wl_seat::WlSeatGlobal; +use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal}; use crate::ifs::wl_surface::wl_subsurface::WlSubsurface; use crate::object::{Interface, Object, ObjectId}; use crate::pixman::Region; @@ -23,6 +23,7 @@ use std::mem; use std::ops::{Deref, DerefMut}; use std::rc::Rc; pub use types::*; +use crate::ifs::wl_surface::xdg_surface::XdgSurface; const DESTROY: u32 = 0; const ATTACH: u32 = 1; @@ -54,8 +55,6 @@ pub enum SurfaceRole { None, Subsurface, XdgSurface, - XdgPopup, - XdgToplevel, } impl SurfaceRole { @@ -64,8 +63,6 @@ impl SurfaceRole { SurfaceRole::None => "none", SurfaceRole::Subsurface => "subsurface", SurfaceRole::XdgSurface => "xdg_surface", - SurfaceRole::XdgPopup => "xdg_popup", - SurfaceRole::XdgToplevel => "xdg_toplevel", } } } @@ -87,6 +84,8 @@ pub struct WlSurface { pub children: RefCell>>, ext: CloneCell>, pub frame_requests: RefCell>>, + seat_state: NodeSeatState, + xdg: CloneCell>>, } #[derive(Debug, Copy, Clone, Eq, PartialEq)] @@ -130,10 +129,6 @@ trait SurfaceExt { fn into_subsurface(self: Rc) -> Option> { None } - - fn into_node(self: Rc) -> Option> { - None - } } pub struct NoneSurfaceExt; @@ -183,16 +178,26 @@ impl WlSurface { children: Default::default(), ext: CloneCell::new(client.state.none_surface_ext.clone()), frame_requests: RefCell::new(vec![]), + seat_state: Default::default(), + xdg: Default::default(), } } + fn set_xdg_surface(&self, xdg: Option>) { + let ch = self.children.borrow(); + if let Some(ch) = &*ch { + for ss in ch.subsurfaces.values() { + ss.surface.set_xdg_surface(xdg.clone()); + } + } + self.xdg.set(xdg); + } + 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, @@ -258,6 +263,7 @@ impl WlSurface { fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.parse(parser)?; + self.destroy_node(true); if self.ext.get().is_some() { return Err(DestroyError::ReloObjectStillExists); } @@ -488,10 +494,12 @@ impl Object for WlSurface { } fn break_loops(&self) { + self.destroy_node(true); *self.children.borrow_mut() = None; self.unset_ext(); mem::take(self.frame_requests.borrow_mut().deref_mut()); self.buffer.set(None); + self.xdg.set(None); } } @@ -501,31 +509,58 @@ impl Node for WlSurface { self.node_id.into() } - fn enter(self: Rc, seat: &WlSeatGlobal, x: Fixed, y: Fixed) { - seat.enter_surface(&self, x, y) + fn seat_state(&self) -> &NodeSeatState { + &self.seat_state } - fn leave(&self, seat: &WlSeatGlobal) { - seat.leave_surface(self); + fn destroy_node(&self, _detach: bool) { + let children = self.children.borrow(); + if let Some(ch) = children.deref() { + for ss in ch.subsurfaces.values() { + ss.surface.destroy_node(false); + } + } + if let Some(xdg) = self.xdg.get() { + let mut remove = vec![]; + for (seat, s) in &xdg.focus_surface { + if s.id == self.id { + remove.push(seat); + } + } + for seat in remove { + xdg.focus_surface.remove(&seat); + } + } + self.seat_state.destroy_node(self); } - fn motion(&self, seat: &WlSeatGlobal, x: Fixed, y: Fixed) { - seat.motion_surface(self, x, y) + fn button(self: Rc, seat: &Rc, button: u32, state: KeyState) { + seat.button_surface(&self, button, state); } 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: &Rc) { + if let Some(xdg) = self.xdg.get() { + xdg.focus_surface.insert(seat.id(), self); + } } - fn focus(self: Rc, seat: &WlSeatGlobal) { - seat.focus_surface(&self); + fn unfocus(&self, seat: &WlSeatGlobal) { + seat.unfocus_surface(self); } - fn unfocus(self: Rc, seat: &WlSeatGlobal) { - seat.unfocus_surface(&self); + fn leave(&self, seat: &WlSeatGlobal) { + seat.leave_surface(self); + } + + fn enter(self: Rc, seat: &Rc, x: Fixed, y: Fixed) { + seat.enter_surface(&self, x, y) + } + + fn motion(&self, seat: &WlSeatGlobal, x: Fixed, y: Fixed) { + seat.motion_surface(self, x, y) } } diff --git a/src/ifs/wl_surface/types.rs b/src/ifs/wl_surface/types.rs index bd0880b6..0a2d76a3 100644 --- a/src/ifs/wl_surface/types.rs +++ b/src/ifs/wl_surface/types.rs @@ -1,11 +1,11 @@ use crate::client::{ClientError, RequestParser}; use crate::ifs::wl_callback::WlCallbackId; use crate::ifs::wl_region::WlRegionId; +use crate::ifs::wl_surface::xdg_surface::XdgSurfaceError; use crate::ifs::wl_surface::{SurfaceRole, WlSurfaceId}; use crate::utils::buffd::{MsgParser, MsgParserError}; use std::fmt::{Debug, Formatter}; use thiserror::Error; -use crate::ifs::wl_surface::xdg_surface::XdgSurfaceError; #[derive(Debug, Error)] pub enum WlSurfaceError { diff --git a/src/ifs/wl_surface/wl_subsurface/mod.rs b/src/ifs/wl_surface/wl_subsurface/mod.rs index 2d299ac2..8fead62b 100644 --- a/src/ifs/wl_surface/wl_subsurface/mod.rs +++ b/src/ifs/wl_surface/wl_subsurface/mod.rs @@ -1,12 +1,11 @@ mod types; -use crate::backend::{KeyState, ScrollAxis}; -use crate::fixed::Fixed; -use crate::ifs::wl_seat::WlSeatGlobal; -use crate::ifs::wl_surface::{CommitAction, CommitContext, StackElement, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError, WlSurfaceId}; +use crate::ifs::wl_surface::{ + CommitAction, CommitContext, StackElement, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError, + WlSurfaceId, +}; use crate::object::{Interface, Object, ObjectId}; use crate::rect::Rect; -use crate::tree::{Node, NodeId}; use crate::utils::buffd::MsgParser; use crate::utils::linkedlist::LinkedNode; use crate::NumCell; @@ -27,12 +26,10 @@ const BAD_SURFACE: u32 = 0; const MAX_SUBSURFACE_DEPTH: u32 = 100; -tree_id!(SubsurfaceNodeId); id!(WlSubsurfaceId); pub struct WlSubsurface { id: WlSubsurfaceId, - node_id: SubsurfaceNodeId, pub surface: Rc, pub(super) parent: Rc, pub position: Cell, @@ -87,7 +84,6 @@ 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()), @@ -312,42 +308,4 @@ impl SurfaceExt for WlSubsurface { 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/xdg_surface/mod.rs b/src/ifs/wl_surface/xdg_surface/mod.rs index e671e702..8b01cc01 100644 --- a/src/ifs/wl_surface/xdg_surface/mod.rs +++ b/src/ifs/wl_surface/xdg_surface/mod.rs @@ -5,20 +5,23 @@ pub mod xdg_toplevel; 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::{CommitAction, CommitContext, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError}; +use crate::ifs::wl_surface::{ + CommitAction, CommitContext, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError, +}; use crate::ifs::xdg_wm_base::XdgWmBaseObj; use crate::object::{Interface, Object, ObjectId}; use crate::rect::Rect; -use crate::tree::{FoundNode, Node}; +use crate::tree::{FindTreeResult, FoundNode, Node, WorkspaceNode}; use crate::utils::buffd::MsgParser; use crate::utils::clonecell::CloneCell; use crate::utils::copyhashmap::CopyHashMap; use crate::NumCell; use std::cell::Cell; -use std::ops::Deref; use std::rc::Rc; pub use types::*; -use crate::ifs::wl_surface::wl_subsurface::WlSubsurface; +use crate::backend::SeatId; +use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal}; +use crate::utils::smallmap::SmallMap; const DESTROY: u32 = 0; const GET_TOPLEVEL: u32 = 1; @@ -34,11 +37,29 @@ const ALREADY_CONSTRUCTED: u32 = 2; #[allow(dead_code)] const UNCONFIGURED_BUFFER: u32 = 3; +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum XdgSurfaceRole { + None, + XdgPopup, + XdgToplevel, +} + +impl XdgSurfaceRole { + fn name(self) -> &'static str { + match self { + XdgSurfaceRole::None => "none", + XdgSurfaceRole::XdgPopup => "xdg_popup", + XdgSurfaceRole::XdgToplevel => "xdg_toplevel", + } + } +} + id!(XdgSurfaceId); pub struct XdgSurface { id: XdgSurfaceId, base: Rc, + role: Cell, pub surface: Rc, requested_serial: NumCell, acked_serial: Cell>, @@ -48,7 +69,9 @@ pub struct XdgSurface { ext: CloneCell>>, popups: CopyHashMap>, pending: PendingXdgSurfaceData, - pub focus_subsurface: CloneCell>>, + pub(super) focus_surface: SmallMap, 1>, + seat_state: NodeSeatState, + pub workspace: CloneCell>>, } #[derive(Default)] @@ -79,6 +102,7 @@ impl XdgSurface { Self { id, base: wm_base.clone(), + role: Cell::new(XdgSurfaceRole::None), surface: surface.clone(), requested_serial: NumCell::new(0), acked_serial: Cell::new(None), @@ -88,7 +112,47 @@ impl XdgSurface { ext: Default::default(), popups: Default::default(), pending: Default::default(), - focus_subsurface: Default::default() + focus_surface: Default::default(), + seat_state: Default::default(), + workspace: Default::default(), + } + } + + fn set_workspace(&self, ws: &Rc) { + self.workspace.set(Some(ws.clone())); + let pu = self.popups.lock(); + for pu in pu.values() { + pu.xdg.set_workspace(ws); + } + } + + fn set_role(&self, role: XdgSurfaceRole) -> Result<(), XdgSurfaceError> { + use XdgSurfaceRole::*; + match (self.role.get(), role) { + (None, _) => {} + (old, new) if old == new => {} + (old, new) => { + return Err(XdgSurfaceError::IncompatibleRole { + id: self.id, + old, + new, + }) + } + } + self.role.set(role); + Ok(()) + } + + pub fn focus_surface(&self, seat: &WlSeatGlobal) -> Rc { + self.focus_surface.get(&seat.id()).unwrap_or_else(|| self.surface.clone()) + } + + fn destroy_node(&self) { + self.workspace.set(None); + self.surface.destroy_node(false); + let popups = self.popups.lock(); + for popup in popups.values() { + popup.destroy_node(true); } } @@ -114,6 +178,7 @@ impl XdgSurface { return Err(XdgSurfaceError::AlreadyAttached(self.surface.id)); } self.surface.ext.set(self.clone()); + self.surface.set_xdg_surface(Some(self.clone())); Ok(()) } @@ -128,6 +193,7 @@ impl XdgSurface { return Err(DestroyError::PopupsNotYetDestroyed); } } + self.surface.set_xdg_surface(None); self.surface.unset_ext(); self.base.surfaces.remove(&self.id); self.surface.client.remove_obj(self)?; @@ -136,7 +202,7 @@ impl XdgSurface { fn get_toplevel(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), GetToplevelError> { let req: GetToplevel = self.surface.client.parse(&**self, parser)?; - self.surface.set_role(SurfaceRole::XdgToplevel)?; + self.set_role(XdgSurfaceRole::XdgToplevel)?; if self.ext.get().is_some() { self.surface.client.protocol_error( &**self, @@ -156,7 +222,7 @@ impl XdgSurface { fn get_popup(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), GetPopupError> { let req: GetPopup = self.surface.client.parse(&**self, parser)?; - self.surface.set_role(SurfaceRole::XdgPopup)?; + self.set_role(XdgSurfaceRole::XdgPopup)?; let mut parent = None; if req.parent.is_some() { parent = Some(self.surface.client.get_xdg_surface(req.parent)?); @@ -230,24 +296,22 @@ impl XdgSurface { } } - fn find_child_at(&self, mut x: i32, mut y: i32) -> Option { + fn find_tree_at(&self, mut x: i32, mut y: i32, tree: &mut Vec) -> FindTreeResult { if let Some(geo) = self.geometry.get() { let (xt, yt) = geo.translate_inv(x, y); x = xt; y = yt; } match self.surface.find_surface_at(x, y) { - Some((node, x, y)) => Some(FoundNode { - node: if std::ptr::eq(node.deref(), self.surface.deref()) { - node - } else { - node.ext.get().into_node().unwrap() - }, - x, - y, - contained: true, - }), - _ => None, + Some((node, x, y)) => { + tree.push(FoundNode { + node, + x, + y, + }); + FindTreeResult::AcceptsInput + }, + _ => FindTreeResult::Other } } @@ -276,7 +340,7 @@ impl Object for XdgSurface { } fn break_loops(&self) { - self.focus_subsurface.set(None); + self.focus_surface.take(); } } @@ -311,11 +375,4 @@ impl SurfaceExt for XdgSurface { 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 d493203d..93337b67 100644 --- a/src/ifs/wl_surface/xdg_surface/types.rs +++ b/src/ifs/wl_surface/xdg_surface/types.rs @@ -1,7 +1,7 @@ use crate::client::{ClientError, EventFormatter, RequestParser}; use crate::ifs::wl_surface::xdg_surface::xdg_popup::{XdgPopupError, 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::xdg_surface::{XdgSurface, XdgSurfaceId, CONFIGURE, XdgSurfaceRole}; use crate::ifs::wl_surface::{WlSurfaceError, WlSurfaceId}; use crate::ifs::xdg_positioner::XdgPositionerId; use crate::object::Object; @@ -28,6 +28,12 @@ pub enum XdgSurfaceError { WlSurfaceError(Box), #[error(transparent)] XdgPopupError(#[from] XdgPopupError), + #[error("Surface {} cannot be assigned the role {} because it already has the role {}", .id, .new.name(), .old.name())] + IncompatibleRole { + id: XdgSurfaceId, + old: XdgSurfaceRole, + new: XdgSurfaceRole, + }, } efrom!(XdgSurfaceError, WlSurfaceError); @@ -55,10 +61,13 @@ pub enum GetToplevelError { AlreadyConstructed, #[error(transparent)] WlSurfaceError(Box), + #[error(transparent)] + XdgSurfaceError(Box), } efrom!(GetToplevelError, ParseFailed, MsgParserError); efrom!(GetToplevelError, ClientError); efrom!(GetToplevelError, WlSurfaceError); +efrom!(GetToplevelError, XdgSurfaceError); #[derive(Debug, Error)] pub enum GetPopupError { @@ -72,11 +81,14 @@ pub enum GetPopupError { WlSurfaceError(Box), #[error(transparent)] XdgPopupError(Box), + #[error(transparent)] + XdgSurfaceError(Box), } efrom!(GetPopupError, ParseFailed, MsgParserError); efrom!(GetPopupError, ClientError); efrom!(GetPopupError, XdgPopupError); efrom!(GetPopupError, WlSurfaceError); +efrom!(GetPopupError, XdgSurfaceError); #[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 bebdb673..f7deefde 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs @@ -1,21 +1,20 @@ mod types; +use crate::client::DynEventFormatter; +use crate::fixed::Fixed; +use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal}; use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceExt}; use crate::ifs::xdg_positioner::{XdgPositioned, XdgPositioner}; use crate::object::{Interface, Object, ObjectId}; use crate::rect::Rect; -use crate::tree::{FoundNode, Node, NodeId, StackedNode, WorkspaceNode}; +use crate::render::Renderer; +use crate::tree::{AbsoluteNode, FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode}; use crate::utils::buffd::MsgParser; use crate::utils::clonecell::CloneCell; +use crate::utils::linkedlist::LinkedNode; use std::cell::{Cell, RefCell}; use std::rc::Rc; pub use types::*; -use crate::client::DynEventFormatter; -use crate::fixed::Fixed; -use crate::ifs::wl_seat::WlSeatGlobal; -use crate::ifs::wl_surface::SurfaceExt; -use crate::render::Renderer; -use crate::utils::linkedlist::LinkedNode; const DESTROY: u32 = 0; const GRAB: u32 = 1; @@ -37,8 +36,8 @@ pub struct XdgPopup { pub xdg: Rc, pub(super) parent: CloneCell>>, relative_position: Cell, - display_link: RefCell>>, - workspace_link: RefCell>>, + display_link: RefCell>>>, + workspace_link: RefCell>>>, pos: RefCell, } @@ -83,9 +82,7 @@ impl XdgPopup { } fn popup_done(self: &Rc) -> DynEventFormatter { - Box::new(PopupDone { - obj: self.clone(), - }) + Box::new(PopupDone { obj: self.clone() }) } fn update_relative_position(&self, parent: &XdgSurface) -> Result<(), XdgPopupError> { @@ -102,12 +99,15 @@ impl XdgPopup { if let Some(parent) = self.parent.get() { let rel = self.relative_position.get(); let parent = parent.absolute_desired_extents.get(); - self.xdg.absolute_desired_extents.set(rel.move_(parent.x1(), parent.y1())); + self.xdg + .absolute_desired_extents + .set(rel.move_(parent.x1(), parent.y1())); } } fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.xdg.surface.client.parse(self, parser)?; + self.destroy_node(true); { if let Some(parent) = self.parent.take() { parent.popups.remove(&self.id); @@ -115,7 +115,6 @@ impl XdgPopup { } self.xdg.ext.set(None); self.xdg.surface.client.remove_obj(self)?; - self.clear(); *self.display_link.borrow_mut() = None; *self.workspace_link.borrow_mut() = None; Ok(()) @@ -128,15 +127,27 @@ impl XdgPopup { fn reposition(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), RepositionError> { let req: Reposition = self.xdg.surface.client.parse(&**self, parser)?; - *self.pos.borrow_mut() = self.xdg.surface.client.get_xdg_positioner(req.positioner)?.value(); + *self.pos.borrow_mut() = self + .xdg + .surface + .client + .get_xdg_positioner(req.positioner)? + .value(); if let Some(parent) = self.parent.get() { self.update_relative_position(&parent)?; let rel = self.relative_position.get(); self.xdg.surface.client.event(self.repositioned(req.token)); - self.xdg.surface.client.event(self.configure(rel.x1(), rel.y1(), rel.width(), rel.height())); + self.xdg.surface.client.event(self.configure( + rel.x1(), + rel.y1(), + rel.width(), + rel.height(), + )); self.xdg.send_configure(); let parent = parent.absolute_desired_extents.get(); - self.xdg.absolute_desired_extents.set(rel.move_(parent.x1(), parent.y1())); + self.xdg + .absolute_desired_extents + .set(rel.move_(parent.x1(), parent.y1())); } Ok(()) } @@ -154,6 +165,10 @@ impl XdgPopup { } Ok(()) } + + fn get_parent_workspace(&self) -> Option> { + self.parent.get()?.workspace.get() + } } handle_request!(XdgPopup); @@ -172,28 +187,44 @@ impl Object for XdgPopup { } fn break_loops(&self) { + self.destroy_node(true); self.parent.set(None); - self.clear(); *self.display_link.borrow_mut() = None; *self.workspace_link.borrow_mut() = None; } } +impl AbsoluteNode for XdgPopup { + fn into_node(self: Rc) -> Rc { + self + } + + fn absolute_position(&self) -> Rect { + self.xdg.absolute_desired_extents.get() + } +} + impl Node for XdgPopup { fn id(&self) -> NodeId { self.node_id.into() } - fn clear(&self) { + fn seat_state(&self) -> &NodeSeatState { + &self.xdg.seat_state + } + + fn destroy_node(&self, _detach: bool) { let _v = self.display_link.borrow_mut().take(); let _v = self.workspace_link.borrow_mut().take(); + self.xdg.destroy_node(); + self.xdg.seat_state.destroy_node(self); } - fn find_child_at(&self, x: i32, y: i32) -> Option { - self.xdg.find_child_at(x, y) + fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { + self.xdg.find_tree_at(x, y, tree) } - fn enter(self: Rc, seat: &WlSeatGlobal, _x: Fixed, _y: Fixed) { + fn enter(self: Rc, seat: &Rc, _x: Fixed, _y: Fixed) { seat.enter_popup(&self); } @@ -201,8 +232,8 @@ impl Node for XdgPopup { renderer.render_xdg_surface(&self.xdg, x, y) } - fn get_workspace(self: Rc) -> Option> { - self.parent.get()?.into_node()?.get_workspace() + fn set_workspace(self: Rc, ws: &Rc) { + self.xdg.set_workspace(ws); } } @@ -211,9 +242,16 @@ impl XdgSurfaceExt for XdgPopup { if let Some(parent) = self.parent.get() { self.update_relative_position(&parent)?; let rel = self.relative_position.get(); - self.xdg.surface.client.event(self.configure(rel.x1(), rel.y1(), rel.width(), rel.height())); + self.xdg.surface.client.event(self.configure( + rel.x1(), + rel.y1(), + rel.width(), + rel.height(), + )); let parent = parent.absolute_desired_extents.get(); - self.xdg.absolute_desired_extents.set(rel.move_(parent.x1(), parent.y1())); + self.xdg + .absolute_desired_extents + .set(rel.move_(parent.x1(), parent.y1())); } Ok(()) } @@ -221,22 +259,30 @@ impl XdgSurfaceExt for XdgPopup { fn post_commit(self: Rc) { let mut wl = self.workspace_link.borrow_mut(); let mut dl = self.display_link.borrow_mut(); - let ws = match self.clone().get_workspace() { + let ws = match self.get_parent_workspace() { Some(ws) => ws, - _ => return, + _ => { + log::info!("no ws"); + return; + }, }; let surface = &self.xdg.surface; let state = &surface.client.state; if surface.buffer.get().is_some() { if wl.is_none() { - *wl = Some(ws.stacked.add_last(StackedNode::Popup(self.clone()))); - *dl = Some(state.root.stacked.add_last(StackedNode::Popup(self.clone()))); + self.xdg.set_workspace(&ws); + *wl = Some(ws.stacked.add_last(self.clone())); + *dl = Some( + state + .root + .stacked + .add_last(self.clone()), + ); state.tree_changed(); } } else { if wl.take().is_some() { - *dl = None; - state.tree_changed(); + self.destroy_node(true); surface.client.event(self.popup_done()); } } diff --git a/src/ifs/wl_surface/xdg_surface/xdg_popup/types.rs b/src/ifs/wl_surface/xdg_surface/xdg_popup/types.rs index 498e0f6a..9bec4738 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_popup/types.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup/types.rs @@ -21,6 +21,7 @@ pub enum XdgPopupError { #[error("The `xdg_positioner` is incomplete")] Incomplete, #[error("The anchor rectangle of the `xdg_positioner` extends outside the parent")] + #[allow(dead_code)] AnchorRectOutside, } 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 2c7a3a0c..155be2cb 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs @@ -2,12 +2,12 @@ mod types; use crate::client::DynEventFormatter; use crate::fixed::Fixed; -use crate::ifs::wl_seat::WlSeatGlobal; +use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal}; use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceExt}; use crate::object::{Interface, Object, ObjectId}; use crate::rect::Rect; use crate::render::Renderer; -use crate::tree::{ContainerNode, StackedNode}; +use crate::tree::{ContainerNode, FindTreeResult}; use crate::tree::{FloatNode, FoundNode, Node, NodeId, ToplevelNodeId, WorkspaceNode}; use crate::utils::buffd::MsgParser; use crate::utils::clonecell::CloneCell; @@ -15,9 +15,11 @@ 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::*; +use crate::backend::SeatId; +use crate::utils::linkedlist::LinkedNode; +use crate::utils::smallmap::SmallMap; const DESTROY: u32 = 0; const SET_PARENT: u32 = 1; @@ -77,6 +79,7 @@ pub struct XdgToplevel { pub parent: CloneCell>>, pub children: RefCell>>, states: RefCell>, + pub toplevel_history: SmallMap>, 1>, } impl XdgToplevel { @@ -94,6 +97,7 @@ impl XdgToplevel { parent: Default::default(), children: RefCell::new(Default::default()), states: RefCell::new(states), + toplevel_history: Default::default(), } } @@ -115,6 +119,7 @@ impl XdgToplevel { fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.xdg.surface.client.parse(self, parser)?; + self.destroy_node(true); self.xdg.ext.set(None); if let Some(parent) = self.parent_node.take() { parent.remove_child(self); @@ -225,10 +230,11 @@ impl XdgToplevel { } fn map_child(self: &Rc, parent: &XdgToplevel) { - let workspace = match parent.get_workspace() { + let workspace = match parent.xdg.workspace.get() { Some(w) => w, _ => return self.map_tiled(), }; + self.xdg.set_workspace(&workspace); let output = workspace.output.get(); let output_rect = output.position.get(); let position = { @@ -255,14 +261,20 @@ impl XdgToplevel { workspace_link: Cell::new(None), workspace: CloneCell::new(workspace.clone()), child: CloneCell::new(Some(self.clone())), + seat_state: Default::default(), }); self.parent_node.set(Some(floater.clone())); - floater - .display_link - .set(Some(state.root.stacked.add_last(StackedNode::Float(floater.clone())))); - floater - .workspace_link - .set(Some(workspace.stacked.add_last(StackedNode::Float(floater.clone())))); + floater.display_link.set(Some( + state + .root + .stacked + .add_last(floater.clone()), + )); + floater.workspace_link.set(Some( + workspace + .stacked + .add_last(floater.clone()), + )); } fn map_tiled(self: &Rc) { @@ -291,7 +303,7 @@ impl XdgToplevel { self.parent_node.set(Some(container)); } else { let container = - Rc::new(ContainerNode::new(state, workspace.clone(), self.clone())); + Rc::new(ContainerNode::new(state, &workspace, workspace.clone(), self.clone())); workspace.set_container(&container); self.parent_node.set(Some(container)); }; @@ -300,13 +312,6 @@ impl XdgToplevel { } todo!("map_tiled"); } - - fn get_workspace(&self) -> Option> { - match self.parent_node.get() { - Some(node) => node.get_workspace(), - _ => None, - } - } } handle_request!(XdgToplevel); @@ -325,6 +330,7 @@ impl Object for XdgToplevel { } fn break_loops(&self) { + self.destroy_node(true); if let Some(parent) = self.parent_node.take() { parent.remove_child(self); } @@ -338,30 +344,40 @@ impl Node for XdgToplevel { self.node_id.into() } - fn clear(&self) { - self.parent_node.set(None); + fn seat_state(&self) -> &NodeSeatState { + &self.xdg.seat_state } - fn find_child_at(&self, x: i32, y: i32) -> Option { - self.xdg.find_child_at(x, y) + fn destroy_node(&self, detach: bool) { + if let Some(parent) = self.parent_node.take() { + if detach { + parent.remove_child(self); + } + } + self.toplevel_history.take(); + self.xdg.destroy_node(); + self.xdg.seat_state.destroy_node(self) + } + + fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { + self.xdg.find_tree_at(x, y, tree) + } + + fn enter(self: Rc, seat: &Rc, _x: Fixed, _y: Fixed) { + seat.enter_toplevel(&self); } fn render(&self, renderer: &mut Renderer, x: i32, y: i32) { renderer.render_xdg_surface(&self.xdg, 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_extents(self: Rc, rect: &Rect) { let de = self.xdg.absolute_desired_extents.replace(*rect); if de.width() != rect.width() || de.height() != rect.height() { - self.xdg.surface.client.event(self.configure(rect.width(), rect.height())); + self.xdg + .surface + .client + .event(self.configure(rect.width(), rect.height())); self.xdg.send_configure(); self.xdg.surface.client.flush(); } @@ -369,6 +385,10 @@ impl Node for XdgToplevel { self.xdg.update_popup_positions(); } } + + fn set_workspace(self: Rc, ws: &Rc) { + self.xdg.set_workspace(ws); + } } impl XdgSurfaceExt for XdgToplevel { diff --git a/src/main.rs b/src/main.rs index 6130a07f..b0ae5b40 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ clippy::redundant_clone )] +use std::cell::Cell; use crate::acceptor::AcceptorError; use crate::async_engine::AsyncError; use crate::backends::xorg::{XorgBackend, XorgBackendError}; @@ -142,6 +143,7 @@ fn main_() -> Result<(), MainError> { seat_queue: Default::default(), slow_clients: AsyncQueue::new(), none_surface_ext: Rc::new(NoneSurfaceExt), + tree_changed_sent: Cell::new(false), }); let _global_event_handler = engine.spawn(tasks::handle_backend_events(state.clone())); let _slow_client_handler = engine.spawn(tasks::handle_slow_clients(state.clone())); diff --git a/src/render/renderer/framebuffer.rs b/src/render/renderer/framebuffer.rs index bb01fafb..8323ca8b 100644 --- a/src/render/renderer/framebuffer.rs +++ b/src/render/renderer/framebuffer.rs @@ -27,8 +27,8 @@ impl Framebuffer { glClear(GL_COLOR_BUFFER_BIT); } let mut renderer = Renderer { - renderer: &self.ctx, - image: &self.gl, + ctx: &self.ctx, + fb: &self.gl, }; node.render(&mut renderer, 0, 0); if let Some(rd) = &self.ctx.renderdoc { diff --git a/src/render/renderer/renderer.rs b/src/render/renderer/renderer.rs index 027ef482..fa212152 100644 --- a/src/render/renderer/renderer.rs +++ b/src/render/renderer/renderer.rs @@ -1,4 +1,5 @@ use crate::ifs::wl_buffer::WlBuffer; +use crate::ifs::wl_surface::xdg_surface::XdgSurface; use crate::ifs::wl_surface::WlSurface; use crate::rect::Rect; use crate::render::gl::frame_buffer::{with_scissor, GlFrameBuffer}; @@ -9,11 +10,13 @@ use crate::render::gl::sys::{ GL_TEXTURE_MIN_FILTER, GL_TRIANGLES, GL_TRIANGLE_STRIP, }; use crate::render::renderer::context::RenderContext; -use crate::tree::{ContainerFocus, ContainerNode, ContainerSplit, FloatNode, OutputNode, WorkspaceNode, CONTAINER_BORDER, CONTAINER_TITLE_HEIGHT, StackedNode}; +use crate::tree::{ + ContainerFocus, ContainerNode, ContainerSplit, FloatNode, OutputNode, + WorkspaceNode, CONTAINER_BORDER, CONTAINER_TITLE_HEIGHT, +}; use std::ops::Deref; use std::rc::Rc; use std::slice; -use crate::ifs::wl_surface::xdg_surface::XdgSurface; const NON_COLOR: (f32, f32, f32) = (0.2, 0.2, 0.2); const CHILD_COLOR: (f32, f32, f32) = (0.8, 0.8, 0.8); @@ -28,8 +31,8 @@ fn focus_color(focus: ContainerFocus) -> (f32, f32, f32) { } pub struct Renderer<'a> { - pub(super) renderer: &'a RenderContext, - pub(super) image: &'a GlFrameBuffer, + pub(super) ctx: &'a RenderContext, + pub(super) fb: &'a GlFrameBuffer, } impl Renderer<'_> { @@ -44,25 +47,17 @@ impl Renderer<'_> { self.render_container(&node, x, y) } for stacked in workspace.stacked.iter() { - match &*stacked { - StackedNode::Float(f) => { - let pos = f.position.get(); - self.render_floating(f, pos.x1(), pos.y1()); - } - StackedNode::Popup(p) => { - let pos = p.xdg.absolute_desired_extents.get(); - self.render_xdg_surface(&p.xdg, pos.x1(), pos.y1()); - } - } + let pos = stacked.absolute_position(); + stacked.render(self, pos.x1(), pos.y1()); } } fn x_to_f(&self, x: i32) -> f32 { - 2.0 * (x as f32 / self.image.width as f32) - 1.0 + 2.0 * (x as f32 / self.fb.width as f32) - 1.0 } fn y_to_f(&self, y: i32) -> f32 { - 2.0 * (y as f32 / self.image.height as f32) - 1.0 + 2.0 * (y as f32 / self.fb.height as f32) - 1.0 } fn fill_boxes(&self, boxes: &[Rect], r: f32, g: f32, b: f32, a: f32) { @@ -84,19 +79,19 @@ impl Renderer<'_> { ]); } unsafe { - glUseProgram(self.renderer.fill_prog.prog); - glUniform4f(self.renderer.fill_prog_color, r, g, b, a); + glUseProgram(self.ctx.fill_prog.prog); + glUniform4f(self.ctx.fill_prog_color, r, g, b, a); glVertexAttribPointer( - self.renderer.fill_prog_pos as _, + self.ctx.fill_prog_pos as _, 2, GL_FLOAT, GL_FALSE, 0, pos.as_ptr() as _, ); - glEnableVertexAttribArray(self.renderer.fill_prog_pos as _); + glEnableVertexAttribArray(self.ctx.fill_prog_pos as _); glDrawArrays(GL_TRIANGLES, 0, (boxes.len() * 6) as _); - glDisableVertexAttribArray(self.renderer.fill_prog_pos as _); + glDisableVertexAttribArray(self.ctx.fill_prog_pos as _); } } @@ -224,21 +219,21 @@ impl Renderer<'_> { Some(t) => t, _ => return, }; - assert!(Rc::ptr_eq(&self.renderer.ctx, &texture.ctx.ctx)); + assert!(Rc::ptr_eq(&self.ctx.ctx, &texture.ctx.ctx)); unsafe { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture.gl.tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glUseProgram(self.renderer.tex_prog.prog); + glUseProgram(self.ctx.tex_prog.prog); - glUniform1i(self.renderer.tex_prog_tex, 0); + glUniform1i(self.ctx.tex_prog_tex, 0); let texcoord: [f32; 8] = [1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0]; - let f_width = self.image.width as f32; - let f_height = self.image.height as f32; + let f_width = self.fb.width as f32; + let f_height = self.fb.height as f32; let x1 = 2.0 * (x as f32 / f_width) - 1.0; let y1 = 2.0 * (y as f32 / f_height) - 1.0; @@ -253,7 +248,7 @@ impl Renderer<'_> { ]; glVertexAttribPointer( - self.renderer.tex_prog_texcoord as _, + self.ctx.tex_prog_texcoord as _, 2, GL_FLOAT, GL_FALSE, @@ -261,7 +256,7 @@ impl Renderer<'_> { texcoord.as_ptr() as _, ); glVertexAttribPointer( - self.renderer.tex_prog_pos as _, + self.ctx.tex_prog_pos as _, 2, GL_FLOAT, GL_FALSE, @@ -269,13 +264,13 @@ impl Renderer<'_> { pos.as_ptr() as _, ); - glEnableVertexAttribArray(self.renderer.tex_prog_texcoord as _); - glEnableVertexAttribArray(self.renderer.tex_prog_pos as _); + glEnableVertexAttribArray(self.ctx.tex_prog_texcoord as _); + glEnableVertexAttribArray(self.ctx.tex_prog_pos as _); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glDisableVertexAttribArray(self.renderer.tex_prog_texcoord as _); - glDisableVertexAttribArray(self.renderer.tex_prog_pos as _); + glDisableVertexAttribArray(self.ctx.tex_prog_texcoord as _); + glDisableVertexAttribArray(self.ctx.tex_prog_pos as _); glBindTexture(GL_TEXTURE_2D, 0); } diff --git a/src/state.rs b/src/state.rs index 2a655b71..3d3dc631 100644 --- a/src/state.rs +++ b/src/state.rs @@ -16,7 +16,7 @@ use crate::utils::numcell::NumCell; use crate::utils::queue::AsyncQueue; use crate::Wheel; use ahash::AHashMap; -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::rc::Rc; pub struct State { @@ -38,6 +38,7 @@ pub struct State { pub seat_queue: LinkedList>, pub slow_clients: AsyncQueue>, pub none_surface_ext: Rc, + pub tree_changed_sent: Cell, } pub struct SeatData { @@ -54,6 +55,9 @@ impl State { } pub fn tree_changed(&self) { + if self.tree_changed_sent.replace(true) { + return; + } let seats = self.seats.borrow(); for seat in seats.values() { seat.tree_changed.trigger(); diff --git a/src/tasks/output.rs b/src/tasks/output.rs index 949752fe..536c2267 100644 --- a/src/tasks/output.rs +++ b/src/tasks/output.rs @@ -1,12 +1,12 @@ use crate::backend::Output; use crate::ifs::wl_output::WlOutputGlobal; +use crate::rect::Rect; 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; -use crate::rect::Rect; pub struct OutputHandler { pub state: Rc, @@ -27,12 +27,14 @@ impl OutputHandler { workspaces: RefCell::new(vec![]), position: Cell::new(Default::default()), workspace: CloneCell::new(None), + seat_state: Default::default(), }); let workspace = Rc::new(WorkspaceNode { id: self.state.node_ids.next(), output: CloneCell::new(on.clone()), container: Default::default(), stacked: Default::default(), + seat_state: Default::default(), }); on.workspace.set(Some(workspace)); self.state.root.outputs.set(self.output.id(), on.clone()); @@ -51,7 +53,8 @@ impl OutputHandler { if new_width != width || new_height != height { width = new_width; height = new_height; - on.clone().change_extents(&Rect::new_sized(0, 0, new_width, new_height).unwrap()); + on.clone() + .change_extents(&Rect::new_sized(0, 0, new_width, new_height).unwrap()); } global.update_properties(); ae.triggered().await; diff --git a/src/tasks/seat.rs b/src/tasks/seat.rs index def2de42..262e5b86 100644 --- a/src/tasks/seat.rs +++ b/src/tasks/seat.rs @@ -22,7 +22,7 @@ impl SeatHandler { let _tree_changed = self .state .eng - .spawn(tree_changed(global.clone(), self.tree_changed.clone())); + .spawn(tree_changed(self.state.clone(), global.clone(), self.tree_changed.clone())); let mut _node = self.state.seat_queue.add_last(global.clone()); self.state.add_global(&global); loop { @@ -44,9 +44,10 @@ impl SeatHandler { } } -async fn tree_changed(global: Rc, tree_changed: Rc) { +async fn tree_changed(state: Rc, global: Rc, tree_changed: Rc) { loop { tree_changed.triggered().await; + state.tree_changed_sent.set(false); global.tree_changed(); } } diff --git a/src/tree/container.rs b/src/tree/container.rs index b5f66e67..f6ff8cdd 100644 --- a/src/tree/container.rs +++ b/src/tree/container.rs @@ -1,12 +1,13 @@ use crate::rect::Rect; use crate::render::Renderer; -use crate::tree::{FoundNode, Node, NodeId, WorkspaceNode}; +use crate::tree::{FindTreeResult, 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; +use crate::ifs::wl_seat::{NodeSeatState}; #[allow(dead_code)] #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -44,6 +45,8 @@ pub struct ContainerNode { num_children: NumCell, pub children: LinkedList, child_nodes: RefCell>>, + seat_state: NodeSeatState, + workspace: CloneCell>, } pub struct ContainerChild { @@ -72,7 +75,8 @@ impl ContainerChild { } impl ContainerNode { - pub fn new(state: &State, parent: Rc, child: Rc) -> Self { + pub fn new(state: &State, workspace: &Rc, parent: Rc, child: Rc) -> Self { + child.clone().set_workspace(workspace); let children = LinkedList::new(); let mut child_nodes = AHashMap::new(); child_nodes.insert( @@ -101,6 +105,8 @@ impl ContainerNode { num_children: NumCell::new(1), children, child_nodes: RefCell::new(child_nodes), + seat_state: Default::default(), + workspace: CloneCell::new(workspace.clone()), } } @@ -149,6 +155,7 @@ impl ContainerNode { }), ); } + new.clone().set_workspace(&self.workspace.get()); let num_children = self.num_children.fetch_add(1) + 1; self.update_content_size(); let new_child_factor = 1.0 / num_children as f64; @@ -264,40 +271,46 @@ impl Node for ContainerNode { self.id.into() } - fn clear(&self) { - let mut cn = self.child_nodes.borrow_mut(); - for (_, n) in cn.drain() { - n.node.clear(); - } + fn seat_state(&self) -> &NodeSeatState { + &self.seat_state } - fn find_child_at(&self, x: i32, y: i32) -> Option { + fn destroy_node(&self, detach: bool) { + if detach { + self.parent.get().remove_child(self); + } + let mut cn = self.child_nodes.borrow_mut(); + for (_, n) in cn.drain() { + n.node.destroy_node(false); + } + self.seat_state.destroy_node(self); + } + + fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { + let mut recurse = |content: Rect, child: NodeRef| { + if content.contains(x, y) { + let (x, y) = content.translate(x, y); + tree.push( + FoundNode { + node: child.node.clone(), + x, + y, + } + ); + child.node.find_tree_at(x, y, tree); + } + }; 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), - }); + recurse(self.mono_content.get(), child); + } else { + for child in self.children.iter() { + if child.body.get().contains(x, y) { + recurse(child.content.get(), child); + break; + } } } - None + FindTreeResult::AcceptsInput } fn remove_child(&self, child: &dyn Node) { @@ -347,10 +360,6 @@ impl Node for ContainerNode { Some(self) } - fn get_workspace(self: Rc) -> Option> { - self.parent.get().get_workspace() - } - fn change_extents(self: Rc, rect: &Rect) { self.abs_x1.set(rect.x1()); self.abs_y1.set(rect.y1()); @@ -367,4 +376,11 @@ impl Node for ContainerNode { } } } + + fn set_workspace(self: Rc, ws: &Rc) { + for child in self.children.iter() { + child.node.clone().set_workspace(ws); + } + self.workspace.set(ws.clone()); + } } diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 7840985b..c380774a 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -1,6 +1,6 @@ use crate::backend::{KeyState, Output, OutputId, ScrollAxis}; use crate::fixed::Fixed; -use crate::ifs::wl_seat::WlSeatGlobal; +use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal}; use crate::rect::Rect; use crate::render::Renderer; use crate::utils::clonecell::CloneCell; @@ -10,9 +10,9 @@ use crate::NumCell; pub use container::*; use std::cell::{Cell, RefCell}; use std::fmt::Display; +use std::ops::Deref; use std::rc::Rc; pub use workspace::*; -use crate::ifs::wl_surface::xdg_surface::xdg_popup::XdgPopup; mod container; mod workspace; @@ -51,14 +51,23 @@ impl Display for NodeId { } } +pub enum FindTreeResult { + AcceptsInput, + Other, +} + +pub trait AbsoluteNode: Node { + fn into_node(self: Rc) -> Rc; + + fn absolute_position(&self) -> Rect; +} + pub trait Node { fn id(&self) -> NodeId; + fn seat_state(&self) -> &NodeSeatState; + fn destroy_node(&self, detach: bool); - fn clear(&self) { - // nothing - } - - fn button(self: Rc, seat: &WlSeatGlobal, button: u32, state: KeyState) { + fn button(self: Rc, seat: &Rc, button: u32, state: KeyState) { let _ = seat; let _ = button; let _ = state; @@ -70,18 +79,19 @@ pub trait Node { let _ = axis; } - fn focus(self: Rc, seat: &WlSeatGlobal) { + fn focus(self: Rc, seat: &Rc) { let _ = seat; } - fn unfocus(self: Rc, seat: &WlSeatGlobal) { + fn unfocus(&self, seat: &WlSeatGlobal) { let _ = seat; } - fn find_child_at(&self, x: i32, y: i32) -> Option { + fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { let _ = x; let _ = y; - None + let _ = tree; + FindTreeResult::Other } fn remove_child(&self, child: &dyn Node) { @@ -96,7 +106,7 @@ pub trait Node { let _ = seat; } - fn enter(self: Rc, seat: &WlSeatGlobal, x: Fixed, y: Fixed) { + fn enter(self: Rc, seat: &Rc, x: Fixed, y: Fixed) { let _ = seat; let _ = x; let _ = y; @@ -126,33 +136,28 @@ pub trait Node { false } - fn get_workspace(self: Rc) -> Option> { - None - } - fn change_extents(self: Rc, rect: &Rect) { let _ = rect; } + + fn set_workspace(self: Rc, ws: &Rc) { + let _ = ws; + } } pub struct FoundNode { pub node: Rc, pub x: i32, pub y: i32, - pub contained: bool, } tree_id!(ToplevelNodeId); -pub enum StackedNode { - Float(Rc), - Popup(Rc), -} - pub struct DisplayNode { pub id: NodeId, pub outputs: CopyHashMap>, - pub stacked: LinkedList, + pub stacked: LinkedList>, + pub seat_state: NodeSeatState, } impl DisplayNode { @@ -161,6 +166,7 @@ impl DisplayNode { id, outputs: Default::default(), stacked: Default::default(), + seat_state: Default::default(), } } } @@ -170,35 +176,57 @@ impl Node for DisplayNode { self.id } - fn clear(&self) { - let mut outputs = self.outputs.lock(); - for output in outputs.values() { - output.clear(); - } - outputs.clear(); - for floater in self.stacked.iter() { - match &*floater { - StackedNode::Float(f) => f.clear(), - StackedNode::Popup(p) => p.clear(), - } - } + fn seat_state(&self) -> &NodeSeatState { + &self.seat_state } - fn find_child_at(&self, x: i32, y: i32) -> Option { + fn destroy_node(&self, _detach: bool) { + let mut outputs = self.outputs.lock(); + for output in outputs.values() { + output.destroy_node(false); + } + outputs.clear(); + for stacked in self.stacked.iter() { + stacked.destroy_node(false); + } + self.seat_state.destroy_node(self); + } + + fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { + for stacked in self.stacked.iter() { + let ext = stacked.absolute_position(); + if !ext.contains(x, y) { + continue; + } + let (x, y) = ext.translate(x, y); + let idx = tree.len(); + tree.push(FoundNode { + node: stacked.deref().clone().into_node(), + x, + y, + }); + match stacked.find_tree_at(x, y, tree) { + FindTreeResult::AcceptsInput => return FindTreeResult::AcceptsInput, + FindTreeResult::Other => { + tree.drain(idx..); + } + } + } 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 { + tree.push(FoundNode { node: output.clone(), x, y, - contained: true, }); + output.find_tree_at(x, y, tree); + break; } } - None + FindTreeResult::AcceptsInput } } @@ -210,6 +238,7 @@ pub struct OutputNode { pub backend: Rc, pub workspaces: RefCell>>, pub workspace: CloneCell>>, + pub seat_state: NodeSeatState, } impl Node for OutputNode { @@ -217,34 +246,41 @@ impl Node for OutputNode { self.id.into() } - fn clear(&self) { + fn seat_state(&self) -> &NodeSeatState { + &self.seat_state + } + + fn destroy_node(&self, detach: bool) { + if detach { + self.display.remove_child(self); + } let mut workspaces = self.workspaces.borrow_mut(); for workspace in workspaces.drain(..) { - workspace.clear(); + workspace.destroy_node(false); } + self.seat_state.destroy_node(self); } - fn find_child_at(&self, x: i32, y: i32) -> Option { + fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { if let Some(ws) = self.workspace.get() { - Some(FoundNode { - node: ws, + tree.push(FoundNode { + node: ws.clone(), x, y, - contained: true, - }) - } else { - None + }); + ws.find_tree_at(x, y, tree); } - } - - fn render(&self, renderer: &mut Renderer, x: i32, y: i32) { - renderer.render_output(self, x, y); + FindTreeResult::AcceptsInput } fn remove_child(&self, _child: &dyn Node) { self.workspace.set(None); } + fn render(&self, renderer: &mut Renderer, x: i32, y: i32) { + renderer.render_output(self, x, y); + } + fn change_extents(self: Rc, rect: &Rect) { self.position.set(*rect); if let Some(c) = self.workspace.get() { @@ -259,10 +295,21 @@ pub struct FloatNode { pub visible: Cell, pub position: Cell, pub display: Rc, - pub display_link: Cell>>, - pub workspace_link: Cell>>, + pub display_link: Cell>>>, + pub workspace_link: Cell>>>, pub workspace: CloneCell>, pub child: CloneCell>>, + pub seat_state: NodeSeatState, +} + +impl AbsoluteNode for FloatNode { + fn into_node(self: Rc) -> Rc { + self + } + + fn absolute_position(&self) -> Rect { + self.position.get() + } } impl Node for FloatNode { @@ -270,12 +317,30 @@ impl Node for FloatNode { self.id.into() } - fn clear(&self) { - self.child.set(None); + fn seat_state(&self) -> &NodeSeatState { + &self.seat_state } - fn find_child_at(&self, x: i32, y: i32) -> Option { - self.child.get().and_then(|c| c.find_child_at(x, y)) + fn destroy_node(&self, _detach: bool) { + let _v = self.display_link.take(); + let _v = self.workspace_link.take(); + if let Some(child) = self.child.get() { + child.destroy_node(false); + } + self.seat_state.destroy_node(self); + } + + fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { + let child = match self.child.get() { + Some(c) => c, + _ => return FindTreeResult::Other, + }; + tree.push(FoundNode { + node: child.clone(), + x, + y, + }); + child.find_tree_at(x, y, tree) } fn remove_child(&self, _child: &dyn Node) { @@ -284,6 +349,12 @@ impl Node for FloatNode { self.workspace_link.set(None); } + 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()); + } + fn render(&self, renderer: &mut Renderer, x: i32, y: i32) { renderer.render_floating(self, x, y) } @@ -296,19 +367,17 @@ impl Node for FloatNode { 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()); - } - fn change_extents(self: Rc, rect: &Rect) { if let Some(child) = self.child.get() { child.change_extents(rect); } } + + fn set_workspace(self: Rc, ws: &Rc) { + if let Some(c) = self.child.get() { + c.set_workspace(ws); + } + self.workspace_link.set(Some(ws.stacked.add_last(self.clone()))); + self.workspace.set(ws.clone()); + } } diff --git a/src/tree/workspace.rs b/src/tree/workspace.rs index 65e9761f..24ce2fd6 100644 --- a/src/tree/workspace.rs +++ b/src/tree/workspace.rs @@ -1,11 +1,11 @@ -use std::ops::Deref; +use crate::rect::Rect; use crate::render::Renderer; use crate::tree::container::ContainerNode; -use crate::tree::{FoundNode, Node, NodeId, OutputNode, StackedNode}; +use crate::tree::{AbsoluteNode, FindTreeResult, FoundNode, Node, NodeId, OutputNode}; use crate::utils::clonecell::CloneCell; use crate::utils::linkedlist::LinkedList; use std::rc::Rc; -use crate::rect::Rect; +use crate::ifs::wl_seat::NodeSeatState; tree_id!(WorkspaceNodeId); @@ -13,15 +13,15 @@ pub struct WorkspaceNode { pub id: WorkspaceNodeId, pub output: CloneCell>, pub container: CloneCell>>, - pub stacked: LinkedList, + pub stacked: LinkedList>, + pub seat_state: NodeSeatState, } impl WorkspaceNode { - pub fn set_container(&self, container: &Rc) { + pub fn set_container(self: &Rc, container: &Rc) { let output = self.output.get().position.get(); - container - .clone() - .change_extents(&output); + container.clone().change_extents(&output); + container.clone().set_workspace(self); self.container.set(Some(container.clone())); } } @@ -31,48 +31,40 @@ impl Node for WorkspaceNode { self.id.into() } - fn clear(&self) { - if let Some(child) = self.container.take() { - child.clear(); - } + fn seat_state(&self) -> &NodeSeatState { + &self.seat_state } - fn find_child_at(&self, x: i32, y: i32) -> Option { - for stacked in self.stacked.rev_iter() { - let (pos, node) = match stacked.deref() { - StackedNode::Float(f) => (f.position.get(), &**f as &dyn Node), - StackedNode::Popup(p) => (p.xdg.absolute_desired_extents.get(), &**p as &dyn Node), - }; - if pos.contains(x, y) { - let (x, y) = pos.translate(x, y); - if let Some(n) = node.find_child_at(x, y) { - return Some(n); - } - } + fn destroy_node(&self, detach: bool) { + if detach { + self.output.get().remove_child(self); } - match self.container.get() { - Some(node) => Some(FoundNode { - node, + if let Some(container) = self.container.take() { + container.destroy_node(false); + } + self.seat_state.destroy_node(self); + } + + fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { + if let Some(n) = self.container.get() { + tree.push(FoundNode { + node: n.clone(), x, y, - contained: true, - }), - _ => None, + }); + n.find_tree_at(x, y, tree); } - } - - fn render(&self, renderer: &mut Renderer, x: i32, y: i32) { - renderer.render_workspace(self, x, y); - } - - fn get_workspace(self: Rc) -> Option> { - Some(self) + FindTreeResult::AcceptsInput } fn remove_child(&self, _child: &dyn Node) { self.container.set(None); } + fn render(&self, renderer: &mut Renderer, x: i32, y: i32) { + renderer.render_workspace(self, x, y); + } + fn change_extents(self: Rc, rect: &Rect) { if let Some(c) = self.container.get() { c.change_extents(rect); diff --git a/src/utils/copyhashmap.rs b/src/utils/copyhashmap.rs index e376ff68..73213bfa 100644 --- a/src/utils/copyhashmap.rs +++ b/src/utils/copyhashmap.rs @@ -45,6 +45,6 @@ impl CopyHashMap { } pub fn is_empty(&self) -> bool { - self.map.borrow().is_empty() + self.map.borrow_mut().is_empty() } } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 974e54f3..67e2f562 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -10,4 +10,5 @@ pub mod numcell; pub mod oneshot; pub mod ptr_ext; pub mod queue; +pub mod smallmap; pub mod vec_ext; diff --git a/src/utils/smallmap.rs b/src/utils/smallmap.rs new file mode 100644 index 00000000..7d5f2339 --- /dev/null +++ b/src/utils/smallmap.rs @@ -0,0 +1,109 @@ +use crate::utils::clonecell::UnsafeCellCloneSafe; +use crate::utils::ptr_ext::{MutPtrExt, PtrExt}; +use smallvec::SmallVec; +use std::cell::UnsafeCell; +use std::mem; + +pub struct SmallMap { + m: UnsafeCell>, +} + +impl Default for SmallMap { + fn default() -> Self { + Self { + m: Default::default() + } + } +} + +impl SmallMap { + pub fn new() -> Self { + Self { + m: UnsafeCell::new(SmallVec::new_const()), + } + } + + pub fn insert(&self, k: K, v: V) -> Option { + unsafe { + let m = self.m.get().deref_mut(); + for (ek, ev) in &mut *m { + if ek == &k { + return Some(mem::replace(ev, v)); + } + } + m.push((k, v)); + None + } + } + + pub fn remove(&self, k: &K) -> Option { + unsafe { + let m = self.m.get().deref_mut(); + for (idx, (ek, _)) in m.iter_mut().enumerate() { + if ek == k { + return Some(m.swap_remove(idx).1); + } + } + None + } + } + + pub fn take(&self) -> SmallVec<[(K, V); N]> { + unsafe { + mem::take(self.m.get().deref_mut()) + } + } + + pub fn pop(&self) -> Option<(K, V)> { + unsafe { + self.m.get().deref_mut().pop() + } + } +} + +impl SmallMap { + pub fn get(&self, k: &K) -> Option { + unsafe { + let m = self.m.get().deref(); + for (ek, ev) in m { + if ek == k { + return Some(ev.clone()); + } + } + None + } + } +} + +impl<'a, K: Copy, V: UnsafeCellCloneSafe, const N: usize> IntoIterator for &'a SmallMap { + type Item = (K, V); + type IntoIter = SmallMapIter<'a, K, V, N>; + + fn into_iter(self) -> Self::IntoIter { + SmallMapIter { + pos: 0, + map: self, + } + } +} + +pub struct SmallMapIter<'a, K, V, const N: usize> { + pos: usize, + map: &'a SmallMap, +} + +impl<'a, K: Copy, V: UnsafeCellCloneSafe, const N: usize> Iterator for SmallMapIter<'a, K, V, N> { + type Item = (K, V); + + fn next(&mut self) -> Option { + unsafe { + let v = self.map.m.get().deref(); + if self.pos >= v.len() { + return None; + } + let (k, v) = &v[self.pos]; + self.pos += 1; + Some((*k, v.clone())) + } + } +}