diff --git a/src/backend/render/cursor.rs b/src/backend/render/cursor.rs index c6f0db74..41c412a8 100644 --- a/src/backend/render/cursor.rs +++ b/src/backend/render/cursor.rs @@ -37,6 +37,24 @@ use xcursor::{ static FALLBACK_CURSOR_DATA: &[u8] = include_bytes!("../../../resources/cursor.rgba"); +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum CursorShape { + Default, + ColResize, + RowResize, +} + +impl ToString for CursorShape { + fn to_string(&self) -> String { + match self { + CursorShape::Default => "default", + CursorShape::ColResize => "col-resize", + CursorShape::RowResize => "row-resize", + } + .to_string() + } +} + #[derive(Debug, Clone)] pub struct Cursor { icons: Vec, @@ -44,17 +62,8 @@ pub struct Cursor { } impl Cursor { - pub fn load() -> Cursor { - let name = std::env::var("XCURSOR_THEME") - .ok() - .unwrap_or_else(|| "default".into()); - let size = std::env::var("XCURSOR_SIZE") - .ok() - .and_then(|s| s.parse().ok()) - .unwrap_or(24); - - let theme = CursorTheme::load(&name); - let icons = load_icon(&theme) + pub fn load(theme: &CursorTheme, shape: CursorShape, size: u32) -> Cursor { + let icons = load_icon(&theme, shape) .map_err(|err| warn!(?err, "Unable to load xcursor, using fallback cursor")) .unwrap_or_else(|_| { vec![Image { @@ -78,12 +87,6 @@ impl Cursor { } } -impl Default for Cursor { - fn default() -> Cursor { - Cursor::load() - } -} - fn nearest_images(size: u32, images: &[Image]) -> impl Iterator { // Follow the nominal size of the cursor to choose the nearest let nearest_image = images @@ -120,8 +123,10 @@ enum Error { Parse, } -fn load_icon(theme: &CursorTheme) -> Result, Error> { - let icon_path = theme.load_icon("default").ok_or(Error::NoDefaultCursor)?; +fn load_icon(theme: &CursorTheme, shape: CursorShape) -> Result, Error> { + let icon_path = theme + .load_icon(&shape.to_string()) + .ok_or(Error::NoDefaultCursor)?; let mut cursor_file = std::fs::File::open(&icon_path)?; let mut cursor_data = Vec::new(); cursor_file.read_to_end(&mut cursor_data)?; @@ -196,15 +201,50 @@ where } pub struct CursorState { - pub cursor: Cursor, + current_cursor: RefCell, + pub cursors: HashMap, current_image: RefCell>, image_cache: RefCell)>>>, } +impl CursorState { + pub fn set_shape(&self, shape: CursorShape) { + *self.current_cursor.borrow_mut() = shape; + } +} + +pub fn load_cursor_theme() -> (CursorTheme, u32) { + let name = std::env::var("XCURSOR_THEME") + .ok() + .unwrap_or_else(|| "default".into()); + let size = std::env::var("XCURSOR_SIZE") + .ok() + .and_then(|s| s.parse().ok()) + .unwrap_or(24); + (CursorTheme::load(&name), size) +} + impl Default for CursorState { fn default() -> CursorState { + let (theme, size) = load_cursor_theme(); CursorState { - cursor: Cursor::default(), + current_cursor: RefCell::new(CursorShape::Default), + cursors: { + let mut map = HashMap::new(); + map.insert( + CursorShape::Default, + Cursor::load(&theme, CursorShape::Default, size), + ); + map.insert( + CursorShape::ColResize, + Cursor::load(&theme, CursorShape::ColResize, size), + ); + map.insert( + CursorShape::RowResize, + Cursor::load(&theme, CursorShape::RowResize, size), + ); + map + }, current_image: RefCell::new(None), image_cache: RefCell::new(HashMap::new()), } @@ -247,12 +287,15 @@ where let integer_scale = scale.x.max(scale.y).ceil() as u32; let seat_userdata = seat.user_data(); - seat_userdata.insert_if_missing(CursorState::default); let state = seat_userdata.get::().unwrap(); - let frame = state.cursor.get_image( - integer_scale, - Into::::into(time).as_millis() as u32, - ); + let frame = state + .cursors + .get(&*state.current_cursor.borrow()) + .unwrap() + .get_image( + integer_scale, + Into::::into(time).as_millis() as u32, + ); let mut cache = state.image_cache.borrow_mut(); let pointer_images = cache diff --git a/src/input/mod.rs b/src/input/mod.rs index 8108805d..49b5ff41 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -13,7 +13,7 @@ use crate::{ }, // shell::grabs::SeatMoveGrabState state::Common, utils::prelude::*, - wayland::{handlers::screencopy::ScreencopySessions, protocols::screencopy::Session}, + wayland::{handlers::screencopy::ScreencopySessions, protocols::screencopy::Session}, backend::render::cursor::CursorState, }; use calloop::{timer::Timer, RegistrationToken}; use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::InputType; @@ -141,6 +141,7 @@ pub fn add_seat( userdata.insert_if_missing(Devices::default); userdata.insert_if_missing(SupressedKeys::default); userdata.insert_if_missing(SeatMoveGrabState::default); + userdata.insert_if_missing(CursorState::default); userdata.insert_if_missing(|| ActiveOutput(RefCell::new(output.clone()))); userdata.insert_if_missing(|| RefCell::new(CursorImageStatus::Default)); @@ -664,10 +665,10 @@ impl State { { under = Some(layer.clone().into()); } - } else if let Some((window, _)) = + } else if let Some((target, _)) = workspace.element_under(relative_pos) { - under = Some(window.clone().into()); + under = Some(target); } else if let Some(layer) = layers .layer_under(WlrLayer::Bottom, pos) .or_else(|| layers.layer_under(WlrLayer::Background, pos)) @@ -685,8 +686,7 @@ impl State { } }; } - - Common::set_focus(self, under.as_ref(), seat, Some(serial)); + Common::set_focus(self, under.and_then(|target| target.try_into().ok()).as_ref(), seat, Some(serial)); } }; seat.get_pointer().unwrap().button( @@ -1347,9 +1347,9 @@ impl State { { return Some((or.clone().into(), or.geometry().loc)); } - if let Some((mapped, loc)) = workspace.element_under(relative_pos) { + if let Some((target, loc)) = workspace.element_under(relative_pos) { return Some(( - mapped.clone().into(), + target, loc + (global_pos - relative_pos).to_i32_round(), )); } diff --git a/src/shell/focus/target.rs b/src/shell/focus/target.rs index 953f38a8..26efabe7 100644 --- a/src/shell/focus/target.rs +++ b/src/shell/focus/target.rs @@ -1,7 +1,7 @@ use std::sync::Weak; use crate::{ - shell::{element::CosmicMapped, CosmicSurface}, + shell::{element::CosmicMapped, layout::tiling::ResizeForkTarget, CosmicSurface}, utils::prelude::*, wayland::handlers::xdg_shell::popup::get_popup_toplevel, }; @@ -28,6 +28,7 @@ pub enum PointerFocusTarget { LayerSurface(LayerSurface), Popup(PopupKind), OverrideRedirect(X11Surface), + ResizeFork(ResizeForkTarget), } #[derive(Debug, Clone, PartialEq)] @@ -39,6 +40,7 @@ pub enum KeyboardFocusTarget { Popup(PopupKind), } +// TODO: This should be TryFrom, but PopupGrab needs to be able to convert. Fix this in smithay impl From for PointerFocusTarget { fn from(target: KeyboardFocusTarget) -> Self { match target { @@ -51,6 +53,19 @@ impl From for PointerFocusTarget { } } +impl TryFrom for KeyboardFocusTarget { + type Error = (); + fn try_from(target: PointerFocusTarget) -> Result { + match target { + PointerFocusTarget::Element(mapped) => Ok(KeyboardFocusTarget::Element(mapped)), + PointerFocusTarget::Fullscreen(surf) => Ok(KeyboardFocusTarget::Fullscreen(surf)), + PointerFocusTarget::LayerSurface(layer) => Ok(KeyboardFocusTarget::LayerSurface(layer)), + PointerFocusTarget::Popup(popup) => Ok(KeyboardFocusTarget::Popup(popup)), + _ => Err(()), + } + } +} + impl KeyboardFocusTarget { pub fn toplevel(&self) -> Option { match self { @@ -85,6 +100,7 @@ impl IsAlive for PointerFocusTarget { PointerFocusTarget::LayerSurface(l) => l.alive(), PointerFocusTarget::Popup(p) => p.alive(), PointerFocusTarget::OverrideRedirect(s) => s.alive(), + PointerFocusTarget::ResizeFork(f) => f.alive(), } } } @@ -109,6 +125,7 @@ impl PointerTarget for PointerFocusTarget { PointerFocusTarget::LayerSurface(l) => PointerTarget::enter(l, seat, data, event), PointerFocusTarget::Popup(p) => PointerTarget::enter(p.wl_surface(), seat, data, event), PointerFocusTarget::OverrideRedirect(s) => PointerTarget::enter(s, seat, data, event), + PointerFocusTarget::ResizeFork(f) => PointerTarget::enter(f, seat, data, event), } } fn motion(&self, seat: &Seat, data: &mut State, event: &MotionEvent) { @@ -120,6 +137,7 @@ impl PointerTarget for PointerFocusTarget { PointerTarget::motion(p.wl_surface(), seat, data, event) } PointerFocusTarget::OverrideRedirect(s) => PointerTarget::motion(s, seat, data, event), + PointerFocusTarget::ResizeFork(f) => PointerTarget::motion(f, seat, data, event), } } fn relative_motion(&self, seat: &Seat, data: &mut State, event: &RelativeMotionEvent) { @@ -137,6 +155,9 @@ impl PointerTarget for PointerFocusTarget { PointerFocusTarget::OverrideRedirect(s) => { PointerTarget::relative_motion(s, seat, data, event) } + PointerFocusTarget::ResizeFork(f) => { + PointerTarget::relative_motion(f, seat, data, event) + } } } fn button(&self, seat: &Seat, data: &mut State, event: &ButtonEvent) { @@ -148,6 +169,7 @@ impl PointerTarget for PointerFocusTarget { PointerTarget::button(p.wl_surface(), seat, data, event) } PointerFocusTarget::OverrideRedirect(s) => PointerTarget::button(s, seat, data, event), + PointerFocusTarget::ResizeFork(f) => PointerTarget::button(f, seat, data, event), } } fn axis(&self, seat: &Seat, data: &mut State, frame: AxisFrame) { @@ -157,6 +179,7 @@ impl PointerTarget for PointerFocusTarget { PointerFocusTarget::LayerSurface(l) => PointerTarget::axis(l, seat, data, frame), PointerFocusTarget::Popup(p) => PointerTarget::axis(p.wl_surface(), seat, data, frame), PointerFocusTarget::OverrideRedirect(s) => PointerTarget::axis(s, seat, data, frame), + PointerFocusTarget::ResizeFork(f) => PointerTarget::axis(f, seat, data, frame), } } fn leave(&self, seat: &Seat, data: &mut State, serial: Serial, time: u32) { @@ -172,6 +195,7 @@ impl PointerTarget for PointerFocusTarget { PointerFocusTarget::OverrideRedirect(s) => { PointerTarget::leave(s, seat, data, serial, time) } + PointerFocusTarget::ResizeFork(f) => PointerTarget::leave(f, seat, data, serial, time), } } } @@ -290,6 +314,9 @@ impl WaylandFocus for PointerFocusTarget { PointerFocusTarget::OverrideRedirect(s) => { return s.wl_surface(); } + PointerFocusTarget::ResizeFork(_) => { + return None; + } }) } fn same_client_as(&self, object_id: &ObjectId) -> bool { @@ -299,6 +326,7 @@ impl WaylandFocus for PointerFocusTarget { PointerFocusTarget::LayerSurface(l) => l.wl_surface().id().same_client_as(object_id), PointerFocusTarget::Popup(p) => p.wl_surface().id().same_client_as(object_id), PointerFocusTarget::OverrideRedirect(s) => WaylandFocus::same_client_as(s, object_id), + PointerFocusTarget::ResizeFork(_) => false, } } } @@ -333,6 +361,12 @@ impl From for PointerFocusTarget { } } +impl From for PointerFocusTarget { + fn from(f: ResizeForkTarget) -> Self { + PointerFocusTarget::ResizeFork(f) + } +} + impl From for KeyboardFocusTarget { fn from(w: CosmicMapped) -> Self { KeyboardFocusTarget::Element(w) diff --git a/src/shell/layout/tiling/grabs.rs b/src/shell/layout/tiling/grabs.rs index 46e9cc70..a897f65d 100644 --- a/src/shell/layout/tiling/grabs.rs +++ b/src/shell/layout/tiling/grabs.rs @@ -1,52 +1,113 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::{ + backend::render::cursor::{CursorShape, CursorState}, shell::{focus::target::PointerFocusTarget, layout::Orientation}, utils::prelude::*, }; use id_tree::NodeId; use smithay::{ - input::pointer::{ - AxisFrame, ButtonEvent, GrabStartData as PointerGrabStartData, MotionEvent, PointerGrab, - PointerInnerHandle, RelativeMotionEvent, + backend::input::ButtonState, + input::{ + pointer::{ + AxisFrame, ButtonEvent, Focus, GrabStartData as PointerGrabStartData, MotionEvent, + PointerGrab, PointerInnerHandle, PointerTarget, RelativeMotionEvent, + }, + Seat, }, - output::{Output, WeakOutput}, - utils::{Logical, Point}, + output::WeakOutput, + utils::{IsAlive, Logical, Point}, }; -use super::Data; +use super::{Data, TilingLayout}; + +#[derive(Debug, Clone, PartialEq)] +pub struct ResizeForkTarget { + pub node: NodeId, + pub output: WeakOutput, + pub left_up_idx: usize, + pub orientation: Orientation, +} + +impl IsAlive for ResizeForkTarget { + fn alive(&self) -> bool { + self.output.upgrade().is_some() + } +} + +impl PointerTarget for ResizeForkTarget { + fn enter(&self, seat: &Seat, _data: &mut State, _event: &MotionEvent) { + let user_data = seat.user_data(); + let cursor_state = user_data.get::().unwrap(); + cursor_state.set_shape(match self.orientation { + Orientation::Horizontal => CursorShape::RowResize, + Orientation::Vertical => CursorShape::ColResize, + }); + } + + fn leave( + &self, + seat: &Seat, + _data: &mut State, + _serial: smithay::utils::Serial, + _time: u32, + ) { + let user_data = seat.user_data(); + let cursor_state = user_data.get::().unwrap(); + cursor_state.set_shape(CursorShape::Default) + } + + fn button(&self, seat: &Seat, data: &mut State, event: &ButtonEvent) { + if event.button == 0x110 && event.state == ButtonState::Pressed { + let seat = seat.clone(); + let node = self.node.clone(); + let output = self.output.clone(); + let left_up_idx = self.left_up_idx; + let orientation = self.orientation; + let serial = event.serial; + let button = event.button; + data.common.event_loop_handle.insert_idle(move |data| { + let pointer = seat.get_pointer().unwrap(); + let location = pointer.current_location(); + pointer.set_grab( + &mut data.state, + ResizeForkGrab { + start_data: PointerGrabStartData { + focus: None, + button, + location, + }, + last_loc: location, + node, + output, + left_up_idx, + orientation, + }, + serial, + Focus::Clear, + ) + }); + } + } + + fn motion(&self, _seat: &Seat, _data: &mut State, _event: &MotionEvent) {} + fn relative_motion( + &self, + _seat: &Seat, + _data: &mut State, + _event: &RelativeMotionEvent, + ) { + } + fn axis(&self, _seat: &Seat, _data: &mut State, _frame: AxisFrame) {} +} pub struct ResizeForkGrab { start_data: PointerGrabStartData, - idx: usize, - initial_size_upleft: i32, - initial_size_downright: i32, + last_loc: Point, node: NodeId, output: WeakOutput, -} - -impl ResizeForkGrab { - pub fn new( - start_data: PointerGrabStartData, - node: NodeId, - output: &Output, - data: &Data, - idx: usize, - ) -> ResizeForkGrab { - let sizes = match data { - Data::Group { ref sizes, .. } => sizes, - _ => panic!("Resizing without a group?!?"), - }; - - ResizeForkGrab { - start_data, - idx, - initial_size_upleft: sizes.iter().take(idx + 1).sum(), - initial_size_downright: sizes.iter().skip(idx + 1).sum(), - node, - output: output.downgrade(), - } - } + left_up_idx: usize, + orientation: Orientation, } impl PointerGrab for ResizeForkGrab { @@ -60,131 +121,70 @@ impl PointerGrab for ResizeForkGrab { // While the grab is active, no client has pointer focus handle.motion(data, None, event); - let delta = event.location - self.start_data.location; + let delta = event.location - self.last_loc; if let Some(output) = self.output.upgrade() { let tiling_layer = &mut data.common.shell.active_space_mut(&output).tiling_layer; if let Some(queue) = tiling_layer.queues.get_mut(&output) { let tree = &mut queue.trees.back_mut().unwrap().0; if tree.get(&self.node).is_ok() { - let orientation = tree.get(&self.node).unwrap().data().orientation(); - let delta = match orientation { + let delta = match self.orientation { Orientation::Vertical => delta.x, Orientation::Horizontal => delta.y, } .round() as i32; - let upleft_node_id = - match tree.children_ids(&self.node).unwrap().skip(self.idx).next() { - Some(elem) => elem, - None => { - return; - } - }; - let downright_node_id = match tree + // check that we are still alive + let mut iter = tree .children_ids(&self.node) .unwrap() - .skip(self.idx + 1) - .next() - { - Some(elem) => elem, - None => { - return; - } + .skip(self.left_up_idx); + let first_elem = iter.next(); + let second_elem = iter.next(); + if first_elem.is_none() || second_elem.is_none() { + return handle.unset_grab(data, event.serial, event.time); }; - let next_mapped = |mut node| loop { - if let Some(node_id) = node { - match tree.get(&node_id).unwrap().data() { - Data::Group { orientation: o, .. } if o == &orientation => { - node = tree.children_ids(&node_id).unwrap().last().cloned(); + match tree.get_mut(&self.node).unwrap().data_mut() { + Data::Group { + sizes, orientation, .. + } => { + if sizes[self.left_up_idx] + sizes[self.left_up_idx + 1] + < match orientation { + Orientation::Vertical => 720, + Orientation::Horizontal => 480, } - _ => { - break node_id; - } - } - } else { - unreachable!() - } - }; - let upleft_mapped_id = next_mapped(Some(upleft_node_id.clone())); - let downright_mapped_id = next_mapped(Some(downright_node_id.clone())); - - let new_upleft_size = self.initial_size_upleft + delta; - let new_downright_size = self.initial_size_downright - delta; - let new_upleft_mapped_size = match orientation { - Orientation::Horizontal => { - tree.get(&upleft_mapped_id) - .unwrap() - .data() - .geometry() - .size - .h - } - Orientation::Vertical => { - tree.get(&upleft_mapped_id) - .unwrap() - .data() - .geometry() - .size - .w - } - } + delta; - let new_downright_mapped_size = match orientation { - Orientation::Horizontal => { - tree.get(&downright_mapped_id) - .unwrap() - .data() - .geometry() - .size - .h - } - Orientation::Vertical => { - tree.get(&downright_mapped_id) - .unwrap() - .data() - .geometry() - .size - .w - } - } - delta; - - if new_upleft_mapped_size > 100 && new_downright_mapped_size > 100 { - // lets update - { - let node = tree.get_mut(&self.node).unwrap(); - let data = node.data_mut(); - match data { - Data::Group { sizes, .. } => { - sizes[self.idx] = new_upleft_size; - sizes[self.idx + 1] = new_downright_size; - } - _ => unreachable!(), + { + return; }; + + let old_size = sizes[self.left_up_idx]; + sizes[self.left_up_idx] = (old_size + delta).max( + if self.orientation == Orientation::Vertical { + 360 + } else { + 240 + }, + ); + let diff = old_size - sizes[self.left_up_idx]; + let next_size = sizes[self.left_up_idx + 1] + diff; + sizes[self.left_up_idx + 1] = + next_size.max(if self.orientation == Orientation::Vertical { + 360 + } else { + 240 + }); + let next_diff = next_size - sizes[self.left_up_idx + 1]; + sizes[self.left_up_idx] += next_diff; } - for (mapped_id, mapped_size) in &[ - (upleft_mapped_id, new_upleft_mapped_size), - (downright_mapped_id, new_downright_mapped_size), - ] { - let parent = tree.get(mapped_id).unwrap().parent().cloned().unwrap(); - if parent != self.node { - let idx = tree - .children_ids(&parent) - .unwrap() - .position(|id| id == mapped_id) - .unwrap(); - let node = tree.get_mut(&parent).unwrap(); - let data = node.data_mut(); - match data { - Data::Group { sizes, .. } => { - sizes[idx] = *mapped_size; - } - _ => unreachable!(), - }; - } - } - return tiling_layer.refresh(); + _ => unreachable!(), } + + self.last_loc = event.location; + let blocker = TilingLayout::update_positions(&output, tree, tiling_layer.gaps); + tiling_layer.pending_blockers.extend(blocker); + } else { + handle.unset_grab(data, event.serial, event.time); } } } diff --git a/src/shell/layout/tiling/mod.rs b/src/shell/layout/tiling/mod.rs index f9d95a13..bd0133b3 100644 --- a/src/shell/layout/tiling/mod.rs +++ b/src/shell/layout/tiling/mod.rs @@ -10,7 +10,7 @@ use crate::{ CosmicMapped, CosmicMappedRenderElement, CosmicStack, CosmicWindow, }, focus::{ - target::{KeyboardFocusTarget, WindowGroup}, + target::{KeyboardFocusTarget, PointerFocusTarget, WindowGroup}, FocusDirection, FocusStackMut, }, grabs::ResizeEdge, @@ -34,7 +34,7 @@ use smithay::{ ImportAll, ImportMem, Renderer, }, desktop::{layer_map_for_output, space::SpaceElement, PopupKind}, - input::{pointer::GrabStartData as PointerGrabStartData, Seat}, + input::Seat, output::Output, reexports::wayland_server::Client, utils::{IsAlive, Logical, Point, Rectangle, Scale}, @@ -1389,60 +1389,6 @@ impl TilingLayout { clients } - pub fn resize_request( - &self, - mapped: &CosmicMapped, - _seat: &Seat, - start_data: PointerGrabStartData, - edges: ResizeEdge, - ) -> Option { - let (output, mut node_id) = self.queues.iter().find_map(|(output, queue)| { - let tree = &queue.trees.back().unwrap().0; - let root_id = tree.root_node_id()?; - tree.traverse_pre_order_ids(root_id) - .unwrap() - .find(|id| tree.get(id).unwrap().data().is_mapped(Some(mapped))) - .map(|id| (&output.output, id)) - })?; - - let queue = self.queues.get(output).unwrap(); - let tree = &queue.trees.back().unwrap().0; - while let Some(group_id) = tree.get(&node_id).unwrap().parent() { - let orientation = tree.get(group_id).unwrap().data().orientation(); - if !((orientation == Orientation::Vertical - && (edges.contains(ResizeEdge::LEFT) || edges.contains(ResizeEdge::RIGHT))) - || (orientation == Orientation::Horizontal - && (edges.contains(ResizeEdge::TOP) || edges.contains(ResizeEdge::BOTTOM)))) - { - node_id = group_id.clone(); - continue; - } - - let node_idx = tree - .children_ids(group_id) - .unwrap() - .position(|id| id == &node_id) - .unwrap(); - let idx = match edges { - x if x.intersects(ResizeEdge::TOP_LEFT) => node_idx.checked_sub(1)?, - _ => node_idx, - }; - if idx > tree.get(&group_id).unwrap().data().len() { - return None; - } - - return Some(ResizeForkGrab::new( - start_data, - group_id.clone(), - output, - tree.get(&group_id).unwrap().data(), - idx, - )); - } - - None - } - pub fn possible_resizes(tree: &Tree, mut node_id: NodeId) -> ResizeEdge { let mut edges = ResizeEdge::empty(); @@ -1535,6 +1481,15 @@ impl TilingLayout { (other_idx, node_idx) }; + if sizes[shrink_idx] + sizes[grow_idx] + < match orientation { + Orientation::Vertical => 720, + Orientation::Horizontal => 480, + } + { + return true; + }; + let old_size = sizes[shrink_idx]; sizes[shrink_idx] = (old_size - amount).max(if orientation == Orientation::Vertical { @@ -1786,6 +1741,102 @@ impl TilingLayout { None } + pub fn element_under( + &self, + location: Point, + ) -> Option<(PointerFocusTarget, Point)> { + self.queues.iter().find_map(|(output_data, queue)| { + let tree = &queue.trees.back().unwrap().0; + let root = tree.root_node_id()?; + let location = (location - output_data.location.to_f64()).to_i32_round(); + + let mut result = None; + let mut lookup = Some(root.clone()); + while let Some(node) = lookup { + let data = tree.get(&node).unwrap().data(); + if data.geometry().contains(location) { + result = Some(node.clone()); + } + + lookup = None; + if result.is_some() && data.is_group() { + for child_id in tree.children_ids(&node).unwrap() { + if tree + .get(child_id) + .unwrap() + .data() + .geometry() + .contains(location) + { + lookup = Some(child_id.clone()); + break; + } + } + } + } + + match result.map(|id| (id.clone(), tree.get(&id).unwrap().data().clone())) { + Some(( + _, + Data::Mapped { + mapped, + last_geometry, + }, + )) => { + let test_point = location.to_f64() - last_geometry.loc.to_f64() + + mapped.geometry().loc.to_f64(); + mapped.is_in_input_region(&test_point).then(|| { + ( + mapped.clone().into(), + last_geometry.loc - output_data.location - mapped.geometry().loc, + ) + }) + } + Some(( + id, + Data::Group { + orientation, + last_geometry, + .. + }, + )) => { + let idx = tree + .children(&id) + .unwrap() + .position(|node| { + let data = node.data(); + match orientation { + Orientation::Vertical => location.x < data.geometry().loc.x, + Orientation::Horizontal => location.y < data.geometry().loc.y, + } + }) + .and_then(|x| x.checked_sub(1))?; + Some(( + ResizeForkTarget { + node: id.clone(), + output: output_data.output.downgrade(), + left_up_idx: idx, + orientation, + } + .into(), + last_geometry.loc - output_data.location + + tree + .children(&id) + .unwrap() + .skip(idx) + .next() + .map(|node| { + let geo = node.data().geometry(); + geo.loc + geo.size + }) + .unwrap(), + )) + } + _ => None, + } + }) + } + pub fn mapped( &self, ) -> impl Iterator)> { diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index 00a436f6..65aefa2b 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -51,7 +51,10 @@ use super::{ resize_indicator::ResizeIndicator, stack::CosmicStackRenderElement, window::CosmicWindowRenderElement, CosmicMapped, }, - focus::{target::KeyboardFocusTarget, FocusStack, FocusStackMut}, + focus::{ + target::{KeyboardFocusTarget, PointerFocusTarget}, + FocusStack, FocusStackMut, + }, grabs::{ResizeEdge, ResizeGrab}, CosmicMappedRenderElement, CosmicSurface, ResizeDirection, ResizeMode, }; @@ -200,23 +203,12 @@ impl Workspace { pub fn element_under( &self, location: Point, - ) -> Option<(&CosmicMapped, Point)> { + ) -> Option<(PointerFocusTarget, Point)> { self.floating_layer .space .element_under(location) - .or_else(|| { - self.tiling_layer.mapped().find_map(|(_, mapped, geo)| { - geo.contains(location.to_i32_round()) - .then(|| { - let test_point = - location - geo.loc.to_f64() + mapped.geometry().loc.to_f64(); - mapped - .is_in_input_region(&test_point) - .then_some((mapped, geo.loc - mapped.geometry().loc)) - }) - .flatten() - }) - }) + .map(|(mapped, p)| (mapped.clone().into(), p)) + .or_else(|| self.tiling_layer.element_under(location)) } pub fn element_geometry(&self, elem: &CosmicMapped) -> Option> { @@ -335,10 +327,6 @@ impl Workspace { self.floating_layer .resize_request(mapped, seat, start_data.clone(), edges) .map(Into::into) - } else if self.tiling_layer.mapped().any(|(_, m, _)| m == mapped) { - self.tiling_layer - .resize_request(mapped, seat, start_data, edges) - .map(Into::into) } else { None } diff --git a/src/utils/prelude.rs b/src/utils/prelude.rs index 57348025..e4cac742 100644 --- a/src/utils/prelude.rs +++ b/src/utils/prelude.rs @@ -1,7 +1,7 @@ use std::{cell::RefCell, sync::Mutex, time::Duration}; use crate::{ - backend::render::cursor::CursorState, + backend::render::cursor::{CursorShape, CursorState}, input::{ActiveOutput, SeatId}, }; use smithay::{ @@ -116,7 +116,9 @@ impl SeatExt for Seat { seat_userdata.insert_if_missing(CursorState::default); let state = seat_userdata.get::().unwrap(); let frame = state - .cursor + .cursors + .get(&CursorShape::Default) + .unwrap() .get_image(1, Into::::into(time).as_millis() as u32); Some(( diff --git a/src/xwayland.rs b/src/xwayland.rs index d6b802b8..7285b6eb 100644 --- a/src/xwayland.rs +++ b/src/xwayland.rs @@ -1,7 +1,7 @@ use std::{ffi::OsString, os::unix::io::OwnedFd}; use crate::{ - backend::render::cursor::Cursor, + backend::render::cursor::{load_cursor_theme, Cursor, CursorShape}, shell::{focus::target::KeyboardFocusTarget, CosmicSurface, Shell}, state::{Data, State}, utils::prelude::*, @@ -67,7 +67,8 @@ impl State { } }; - let cursor = Cursor::load(); + let (theme, size) = load_cursor_theme(); + let cursor = Cursor::load(&theme, CursorShape::Default, size); let image = cursor.get_image(1, 0); if let Err(err) = wm.set_cursor( &image.pixels_rgba,