From 45a478eff0932b46de591380f045a8b8ff98bb25 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Tue, 29 Mar 2022 18:03:21 +0200 Subject: [PATCH] tiling: groundwork for resize grab --- src/shell/layout/tiling/grabs.rs | 83 +++++++++++++++++++ src/shell/layout/{tiling.rs => tiling/mod.rs} | 70 +++++++++++++++- 2 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 src/shell/layout/tiling/grabs.rs rename src/shell/layout/{tiling.rs => tiling/mod.rs} (85%) diff --git a/src/shell/layout/tiling/grabs.rs b/src/shell/layout/tiling/grabs.rs new file mode 100644 index 00000000..77ee7b37 --- /dev/null +++ b/src/shell/layout/tiling/grabs.rs @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-3.0-only +use super::{Data, Orientation, OutputInfo}; +use id_tree::{NodeId, Tree}; +use smithay::{ + desktop::layer_map_for_output, + reexports::wayland_server::protocol::{wl_pointer::ButtonState, wl_surface}, + utils::{Logical, Point}, + wayland::{ + output::Output, + seat::{AxisFrame, PointerGrab, PointerGrabStartData, PointerInnerHandle}, + Serial, + }, +}; +use std::cell::RefCell; + +pub struct ResizeForkGrab { + pub start_data: PointerGrabStartData, + pub node_id: NodeId, + pub initial_ratio: f64, + pub idx: u8, + pub output: Output, +} + +impl PointerGrab for ResizeForkGrab { + fn motion( + &mut self, + handle: &mut PointerInnerHandle<'_>, + location: Point, + _focus: Option<(wl_surface::WlSurface, Point)>, + serial: Serial, + time: u32, + ) { + // While the grab is active, no client has pointer focus + handle.motion(location, None, serial, time); + + let delta = location - self.start_data.location; + + let mut output_info = self + .output + .user_data() + .get::>() + .unwrap() + .borrow_mut(); + let tree = &mut output_info.trees.entry(self.idx).or_insert_with(Tree::new); + if let Some(&mut Data::Fork { + ref mut ratio, + ref orientation, + }) = tree.get_mut(&self.node_id).map(|x| x.data_mut()).ok() + { + let size = layer_map_for_output(&self.output).non_exclusive_zone().size; + let delta = match orientation { + Orientation::Vertical => delta.x / size.w as f64, + Orientation::Horizontal => delta.y / size.h as f64, + }; + *ratio = 0.9f64.min(0.1f64.max(self.initial_ratio + delta)); + } else { + handle.unset_grab(serial, time); + } + } + + fn button( + &mut self, + handle: &mut PointerInnerHandle<'_>, + button: u32, + state: ButtonState, + serial: Serial, + time: u32, + ) { + handle.button(button, state, serial, time); + if handle.current_pressed().is_empty() { + // No more buttons are pressed, release the grab. + handle.unset_grab(serial, time); + } + } + + fn axis(&mut self, handle: &mut PointerInnerHandle<'_>, details: AxisFrame) { + handle.axis(details) + } + + fn start_data(&self) -> &PointerGrabStartData { + &self.start_data + } +} diff --git a/src/shell/layout/tiling.rs b/src/shell/layout/tiling/mod.rs similarity index 85% rename from src/shell/layout/tiling.rs rename to src/shell/layout/tiling/mod.rs index bb6ab2fb..089cb86d 100644 --- a/src/shell/layout/tiling.rs +++ b/src/shell/layout/tiling/mod.rs @@ -4,12 +4,21 @@ use crate::shell::layout::{Layout, Orientation}; use id_tree::{InsertBehavior, MoveBehavior, Node, NodeId, NodeIdError, RemoveBehavior, Tree}; use smithay::{ desktop::{layer_map_for_output, Kind, Space, Window}, - reexports::wayland_protocols::xdg_shell::server::xdg_toplevel::State as XdgState, + reexports::wayland_protocols::xdg_shell::server::xdg_toplevel::{ + ResizeEdge, State as XdgState, + }, utils::Rectangle, - wayland::{output::Output, seat::Seat}, + wayland::{ + output::Output, + seat::{PointerGrabStartData, Seat}, + Serial, + }, }; use std::{cell::RefCell, collections::HashMap}; +mod grabs; +pub use self::grabs::*; + #[derive(Debug)] pub struct TilingLayout { idx: u8, @@ -190,6 +199,63 @@ impl Layout for TilingLayout { } } } + + fn resize_request( + &mut self, + _space: &mut Space, + window: &Window, + seat: &Seat, + serial: Serial, + start_data: PointerGrabStartData, + edges: ResizeEdge, + ) { + if let Some(pointer) = seat.get_pointer() { + if let Some(info) = window.user_data().get::>() { + let output = &info.borrow().output; + let mut output_info = output + .user_data() + .get::>() + .unwrap() + .borrow_mut(); + let tree = &mut output_info.trees.entry(self.idx).or_insert_with(Tree::new); + + let mut node_id = info.borrow().node.clone(); + while let Some(parent_id) = tree.get(&node_id).unwrap().parent().cloned() { + if let &Data::Fork { + ref orientation, + ref ratio, + } = tree.get(&parent_id).unwrap().data() + { + // found a fork + // which child are we? + let first = tree.children_ids(&parent_id).unwrap().next() == Some(&node_id); + match (first, orientation, edges) { + (true, Orientation::Horizontal, ResizeEdge::Bottom) + | (false, Orientation::Horizontal, ResizeEdge::Top) + | (true, Orientation::Vertical, ResizeEdge::Right) + | (false, Orientation::Vertical, ResizeEdge::Left) => { + let grab = ResizeForkGrab { + start_data, + node_id: parent_id, + initial_ratio: *ratio, + idx: self.idx, + output: output.clone(), + }; + + slog_scope::debug!("Tiling resize grabs"); + pointer.set_grab(grab, serial, 0); + return; + } + (x, y, z) => { + slog_scope::debug!("Nope: {:?}, {:?}, {:?}", x, y, z); + } + } + } + node_id = parent_id; + } + } + } + } } impl TilingLayout {