diff --git a/src/ifs/wl_seat/handling.rs b/src/ifs/wl_seat/handling.rs index 8f13c085..55a8fb73 100644 --- a/src/ifs/wl_seat/handling.rs +++ b/src/ifs/wl_seat/handling.rs @@ -294,13 +294,28 @@ impl WlSeatGlobal { self.handle_new_position(false); } - fn handle_new_position(self: &Rc, changed: bool) { + fn handle_new_position(self: &Rc, pos_changed: bool) { let (x, y) = self.pos.get(); - if changed { + if pos_changed { if let Some(cursor) = self.cursor.get() { cursor.set_position(x.round_down(), y.round_down()); } } + 'handle_grab: { + let grab_node = { + let grabber = self.grabber.borrow_mut(); + match grabber.as_ref() { + Some(n) => n.node.clone(), + None => break 'handle_grab, + } + }; + if pos_changed { + let pos = grab_node.absolute_position(); + let (x_int, y_int) = pos.translate(x.round_down(), y.round_down()); + grab_node.motion(self, x.apply_fract(x_int), y.apply_fract(y_int)); + } + return; + } let mut found_tree = self.found_tree.borrow_mut(); let mut stack = self.pointer_stack.borrow_mut(); // if self.move_.get() { @@ -332,7 +347,7 @@ impl WlSeatGlobal { } } if (stack.len(), found_tree.len()) == (divergence, divergence) { - if changed { + if pos_changed { if let Some(node) = found_tree.last() { node.node .motion(self, x.apply_fract(node.x), y.apply_fract(node.y)); diff --git a/src/ifs/wl_seat/mod.rs b/src/ifs/wl_seat/mod.rs index 1e37c1da..0fdea4c8 100644 --- a/src/ifs/wl_seat/mod.rs +++ b/src/ifs/wl_seat/mod.rs @@ -50,11 +50,25 @@ const TOUCH: u32 = 4; #[allow(dead_code)] const MISSING_CAPABILITY: u32 = 0; -#[allow(dead_code)] -const BTN_LEFT: u32 = 0x110; +pub const BTN_LEFT: u32 = 0x110; pub const SEAT_NAME_SINCE: u32 = 2; +pub struct PointerGrab { + seat: Rc, +} + +pub struct PointerGrabber { + node: Rc, +} + +impl Drop for PointerGrab { + fn drop(&mut self) { + *self.seat.grabber.borrow_mut() = None; + self.seat.tree_changed(); + } +} + pub struct WlSeatGlobal { name: GlobalName, state: Rc, @@ -76,6 +90,7 @@ pub struct WlSeatGlobal { layout_size: u32, cursor: CloneCell>>, serial: NumCell, + grabber: RefCell>, } impl WlSeatGlobal { @@ -118,9 +133,23 @@ impl WlSeatGlobal { layout_size, cursor: Default::default(), serial: Default::default(), + grabber: RefCell::new(None), } } + pub fn grab_pointer(self: &Rc, node: Rc) -> Option { + let mut grabber = self.grabber.borrow_mut(); + if grabber.is_some() { + return None; + } + *grabber = Some(PointerGrabber { + node, + }); + Some(PointerGrab { + seat: self.clone(), + }) + } + pub fn set_known_cursor(&self, cursor: KnownCursor) { let cursors = match self.state.cursors.get() { Some(c) => c, 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 90a9d010..94a35dd6 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs @@ -8,7 +8,7 @@ use crate::ifs::xdg_positioner::{XdgPositioned, XdgPositioner, CA}; use crate::object::{Interface, Object, ObjectId}; use crate::rect::Rect; use crate::render::Renderer; -use crate::tree::{AbsoluteNode, FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode}; +use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode}; use crate::utils::buffd::MsgParser; use crate::utils::clonecell::CloneCell; use crate::utils::linkedlist::LinkedNode; @@ -37,8 +37,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, } @@ -268,16 +268,6 @@ impl Object for XdgPopup { } } -impl AbsoluteNode for XdgPopup { - fn into_node(self: Rc) -> Rc { - self - } - - fn absolute_position(&self) -> (Rect, bool) { - (self.xdg.absolute_desired_extents.get(), false) - } -} - impl Node for XdgPopup { fn id(&self) -> NodeId { self.node_id.into() @@ -294,6 +284,14 @@ impl Node for XdgPopup { self.xdg.seat_state.destroy_node(self); } + fn absolute_position(&self) -> Rect { + self.xdg.absolute_desired_extents.get() + } + + fn absolute_position_constrains_input(&self) -> bool { + false + } + fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { self.xdg.find_tree_at(x, y, tree) } 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 89da70e4..1e5e1ff4 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs @@ -1,6 +1,6 @@ mod types; -use crate::backend::SeatId; +use crate::backend::{SeatId}; use crate::client::{ClientId, DynEventFormatter}; use crate::fixed::Fixed; use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal}; @@ -388,6 +388,10 @@ impl Node for XdgToplevel { self.xdg.seat_state.destroy_node(self) } + fn absolute_position(&self) -> Rect { + self.xdg.absolute_desired_extents.get() + } + fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { self.xdg.find_tree_at(x, y, tree) } @@ -405,12 +409,14 @@ impl Node for XdgToplevel { } fn change_extents(self: Rc, rect: &Rect) { + let nw = rect.width(); + let nh = rect.height(); let de = self.xdg.absolute_desired_extents.replace(*rect); - if de.width() != rect.width() || de.height() != rect.height() { + if de.width() != nw || de.height() != nh { self.xdg .surface .client - .event(self.configure(rect.width(), rect.height())); + .event(self.configure(nw.max(1), nh.max(1))); self.xdg.send_configure(); self.xdg.surface.client.flush(); } diff --git a/src/main.rs b/src/main.rs index f6cd7dbe..4b859c92 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,7 @@ #![feature( - generic_associated_types, - type_alias_impl_trait, - never_type, c_variadic, - thread_local + thread_local, + label_break_value, )] #![allow( clippy::len_zero, diff --git a/src/rect.rs b/src/rect.rs index fb721f54..667bcb18 100644 --- a/src/rect.rs +++ b/src/rect.rs @@ -97,6 +97,7 @@ impl Rect { self.x1 <= x && self.y1 <= y && self.x2 > x && self.y2 > y } + #[allow(dead_code)] pub fn contains_rect(&self, rect: &Self) -> bool { self.x1 <= rect.x1 && self.y1 <= rect.x1 && rect.x2 <= self.x2 && rect.y2 <= self.y2 } diff --git a/src/render/renderer/renderer.rs b/src/render/renderer/renderer.rs index d1d97484..ed4ec68c 100644 --- a/src/render/renderer/renderer.rs +++ b/src/render/renderer/renderer.rs @@ -50,7 +50,7 @@ impl Renderer<'_> { self.render_container(&node, x, y) } for stacked in workspace.stacked.iter() { - let (pos, _) = stacked.absolute_position(); + let pos = stacked.absolute_position(); stacked.render(self, pos.x1(), pos.y1()); } } diff --git a/src/tree/container.rs b/src/tree/container.rs index 6a79956f..ce0c2d58 100644 --- a/src/tree/container.rs +++ b/src/tree/container.rs @@ -1,4 +1,4 @@ -use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal}; +use crate::ifs::wl_seat::{BTN_LEFT, NodeSeatState, PointerGrab, WlSeatGlobal}; use crate::rect::Rect; use crate::render::Renderer; use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode}; @@ -8,8 +8,9 @@ use crate::{NumCell, State}; use ahash::AHashMap; use std::cell::{Cell, RefCell}; use std::mem; +use std::ops::DerefMut; use std::rc::Rc; -use crate::backend::SeatId; +use crate::backend::{KeyState, SeatId}; use crate::cursor::KnownCursor; use crate::fixed::Fixed; @@ -67,6 +68,7 @@ struct SeatState { target: bool, x: i32, y: i32, + op: Option, } impl ContainerChild { @@ -109,7 +111,7 @@ impl ContainerNode { Self { id: state.node_ids.next(), parent: CloneCell::new(parent), - split: Cell::new(ContainerSplit::Vertical), + split: Cell::new(ContainerSplit::Horizontal), mono_child: CloneCell::new(None), mono_body: Cell::new(Default::default()), mono_content: Cell::new(Default::default()), @@ -290,9 +292,40 @@ impl ContainerNode { target: false, x, y, + op: None, }); seat_state.x = x; seat_state.y = y; + if let Some(op) = &seat_state.op { + match op.kind { + SeatOpKind::Move => { + // todo + } + SeatOpKind::Resize { dist_left, dist_right } => { + let prev = op.child.prev(); + let prev_body = prev.body.get(); + let child_body = op.child.body.get(); + match self.split.get() { + ContainerSplit::Horizontal => { + let cw = self.content_width.get(); + if prev_body.x1() + dist_left > x || x + dist_right > child_body.x2() { + return; + } + let prev_factor = (x - prev_body.x1() - dist_left) as f64 / cw as f64; + let child_factor = (child_body.x2() - x - dist_right) as f64 / cw as f64; + let sum_factors = 1.0 - prev.factor.get() - op.child.factor.get() + prev_factor + child_factor; + prev.factor.set(prev_factor); + op.child.factor.set(child_factor); + self.apply_factors(sum_factors); + } + ContainerSplit::Vertical => { + // todo + } + } + } + } + return; + } let new_cursor = if self.mono_child.get().is_some() { KnownCursor::Default } else if self.split.get() == ContainerSplit::Horizontal { @@ -322,6 +355,21 @@ impl ContainerNode { } } +struct SeatOp { + _grab: PointerGrab, + child: NodeRef, + kind: SeatOpKind, +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +enum SeatOpKind { + Move, + Resize { + dist_left: i32, + dist_right: i32, + } +} + impl Node for ContainerNode { fn id(&self) -> NodeId { self.id.into() @@ -335,6 +383,7 @@ impl Node for ContainerNode { if detach { self.parent.get().remove_child(self); } + mem::take(self.seats.borrow_mut().deref_mut()); let mut cn = self.child_nodes.borrow_mut(); for (_, n) in cn.drain() { n.node.destroy_node(false); @@ -342,6 +391,89 @@ impl Node for ContainerNode { self.seat_state.destroy_node(self); } + fn absolute_position(&self) -> Rect { + Rect::new_sized(self.abs_x1.get(), self.abs_y1.get(), self.width.get(), self.height.get()).unwrap() + } + + fn button(self: Rc, seat: &Rc, button: u32, state: KeyState) { + if button != BTN_LEFT { + return; + } + let mut seat_datas = self.seats.borrow_mut(); + let seat_data = match seat_datas.get_mut(&seat.id()) { + Some(s) => s, + _ => return, + }; + if seat_data.op.is_none() { + if state != KeyState::Pressed { + return; + } + let (kind, child) = 'res: { + if self.mono_child.get().is_some() { + let width_per_child = self.width.get() / self.num_children.get() as i32; + let mut width_per_child_rem = self.width.get() % self.num_children.get() as i32; + let mut pos = 0; + for child in self.children.iter() { + pos += width_per_child; + if width_per_child_rem > 0 { + pos += 1; + width_per_child_rem -= 1; + } + if pos > seat_data.x { + break 'res (SeatOpKind::Move, child); + } + } + } else if self.split.get() == ContainerSplit::Horizontal { + for child in self.children.iter() { + let body = child.body.get(); + if seat_data.x < body.x2() { + let op = if seat_data.x < body.x1() { + SeatOpKind::Resize { + dist_left: seat_data.x - child.prev().body.get().x2(), + dist_right: body.x1() - seat_data.x, + } + } else { + SeatOpKind::Move + }; + break 'res (op, child); + } + } + } else { + for child in self.children.iter() { + let body = child.body.get(); + if seat_data.x < body.y1() { + let op = if seat_data.x < body.y1() - CONTAINER_TITLE_HEIGHT { + SeatOpKind::Resize { + dist_left: seat_data.y - child.prev().body.get().y2(), + dist_right: body.y1() - seat_data.x, + } + } else { + SeatOpKind::Move + }; + break 'res (op, child); + } + } + }; + return; + }; + let grab = match seat.grab_pointer(self.clone()) { + None => return, + Some(g) => g, + }; + seat_data.op = Some(SeatOp { + _grab: grab, + child, + kind, + }) + } else if state == KeyState::Released { + let op = seat_data.op.take().unwrap(); + drop(seat_datas); + if op.kind == SeatOpKind::Move { + // todo + } + } + } + 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) { @@ -405,6 +537,10 @@ impl Node for ContainerNode { } } + fn enter(self: Rc, seat: &Rc, x: Fixed, y: Fixed) { + self.pointer_move(seat, x.round_down(), y.round_down()); + } + fn pointer_untarget(&self, seat: &Rc) { let mut seats = self.seats.borrow_mut(); if let Some(seat_state) = seats.get_mut(&seat.id()) { @@ -424,10 +560,6 @@ impl Node for ContainerNode { self.pointer_move(seat, x.round_down(), y.round_down()); } - fn enter(self: Rc, seat: &Rc, x: Fixed, y: Fixed) { - self.pointer_move(seat, x.round_down(), y.round_down()); - } - fn render(&self, renderer: &mut Renderer, x: i32, y: i32) { renderer.render_container(self, x, y); } diff --git a/src/tree/mod.rs b/src/tree/mod.rs index d37b2b1a..fb8ecc5f 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -60,17 +60,19 @@ pub enum FindTreeResult { Other, } -pub trait AbsoluteNode: Node { - fn into_node(self: Rc) -> Rc; - - fn absolute_position(&self) -> (Rect, bool); -} - pub trait Node { fn id(&self) -> NodeId; fn seat_state(&self) -> &NodeSeatState; fn destroy_node(&self, detach: bool); + fn absolute_position(&self) -> Rect { + Rect::new_empty(0, 0) + } + + fn absolute_position_constrains_input(&self) -> bool { + true + } + fn active_changed(&self, active: bool) { let _ = active; } @@ -183,7 +185,7 @@ tree_id!(ToplevelNodeId); pub struct DisplayNode { pub id: NodeId, pub outputs: CopyHashMap>, - pub stacked: LinkedList>, + pub stacked: LinkedList>, pub seat_state: NodeSeatState, } @@ -221,15 +223,15 @@ impl Node for DisplayNode { fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { for stacked in self.stacked.rev_iter() { - let (ext, constrain) = stacked.absolute_position(); - if constrain && !ext.contains(x, y) { + let ext = stacked.absolute_position(); + if stacked.absolute_position_constrains_input() && !ext.contains(x, y) { // TODO: make constrain always true continue; } let (x, y) = ext.translate(x, y); let idx = tree.len(); tree.push(FoundNode { - node: stacked.deref().clone().into_node(), + node: stacked.deref().clone(), x, y, }); @@ -295,6 +297,10 @@ impl Node for OutputNode { self.seat_state.destroy_node(self); } + fn absolute_position(&self) -> Rect { + self.position.get() + } + fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { if let Some(ws) = self.workspace.get() { tree.push(FoundNode { @@ -333,23 +339,13 @@ 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, bool) { - (self.position.get(), true) - } -} - impl Node for FloatNode { fn id(&self) -> NodeId { self.id.into() @@ -368,6 +364,10 @@ impl Node for FloatNode { self.seat_state.destroy_node(self); } + fn absolute_position(&self) -> Rect { + self.position.get() + } + fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { let child = match self.child.get() { Some(c) => c, diff --git a/src/tree/workspace.rs b/src/tree/workspace.rs index 94840a02..93515874 100644 --- a/src/tree/workspace.rs +++ b/src/tree/workspace.rs @@ -2,7 +2,7 @@ use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal}; use crate::rect::Rect; use crate::render::Renderer; use crate::tree::container::ContainerNode; -use crate::tree::{AbsoluteNode, FindTreeResult, FoundNode, Node, NodeId, OutputNode}; +use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, OutputNode}; use crate::utils::clonecell::CloneCell; use crate::utils::linkedlist::LinkedList; use std::rc::Rc; @@ -14,7 +14,7 @@ pub struct WorkspaceNode { pub id: WorkspaceNodeId, pub output: CloneCell>, pub container: CloneCell>>, - pub stacked: LinkedList>, + pub stacked: LinkedList>, pub seat_state: NodeSeatState, } @@ -46,6 +46,10 @@ impl Node for WorkspaceNode { self.seat_state.destroy_node(self); } + fn absolute_position(&self) -> Rect { + self.output.get().position.get() + } + fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { if let Some(n) = self.container.get() { tree.push(FoundNode { diff --git a/src/utils/linkedlist.rs b/src/utils/linkedlist.rs index db404c60..7b42eb9c 100644 --- a/src/utils/linkedlist.rs +++ b/src/utils/linkedlist.rs @@ -196,6 +196,29 @@ impl NodeRef { pub fn append(&self, t: T) -> LinkedNode { unsafe { append(self.data, t) } } + + pub fn prev(&self) -> NodeRef { + unsafe { + let data = self.data.as_ref(); + let other = data.prev.get(); + other.as_ref().rc.fetch_add(1); + NodeRef { + data: other, + } + } + } + + #[allow(dead_code)] + pub fn next(&self) -> NodeRef { + unsafe { + let data = self.data.as_ref(); + let other = data.next.get(); + other.as_ref().rc.fetch_add(1); + NodeRef { + data: other, + } + } + } } struct NodeData { diff --git a/todo.md b/todo.md new file mode 100644 index 00000000..de6ced09 --- /dev/null +++ b/todo.md @@ -0,0 +1,16 @@ +- Container resizing +- Container moving (mouse) +- Container moving (kb) +- Float toggle +- Toplevel splitting +- Shortcuts +- Config +- Workspaces +- Float moving +- Highlighting active +- dnd +- clipboard +- primary selection +- presentation time +- viewporter +- session lock