tiling: Properly handle resizing using a ptr device

This commit is contained in:
Victoria Brekenfeld 2023-07-11 16:33:23 +02:00
parent 92019b4286
commit b818a68a91
8 changed files with 371 additions and 252 deletions

View file

@ -37,6 +37,24 @@ use xcursor::{
static FALLBACK_CURSOR_DATA: &[u8] = include_bytes!("../../../resources/cursor.rgba"); 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)] #[derive(Debug, Clone)]
pub struct Cursor { pub struct Cursor {
icons: Vec<Image>, icons: Vec<Image>,
@ -44,17 +62,8 @@ pub struct Cursor {
} }
impl Cursor { impl Cursor {
pub fn load() -> Cursor { pub fn load(theme: &CursorTheme, shape: CursorShape, size: u32) -> Cursor {
let name = std::env::var("XCURSOR_THEME") let icons = load_icon(&theme, shape)
.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)
.map_err(|err| warn!(?err, "Unable to load xcursor, using fallback cursor")) .map_err(|err| warn!(?err, "Unable to load xcursor, using fallback cursor"))
.unwrap_or_else(|_| { .unwrap_or_else(|_| {
vec![Image { 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<Item = &Image> { fn nearest_images(size: u32, images: &[Image]) -> impl Iterator<Item = &Image> {
// Follow the nominal size of the cursor to choose the nearest // Follow the nominal size of the cursor to choose the nearest
let nearest_image = images let nearest_image = images
@ -120,8 +123,10 @@ enum Error {
Parse, Parse,
} }
fn load_icon(theme: &CursorTheme) -> Result<Vec<Image>, Error> { fn load_icon(theme: &CursorTheme, shape: CursorShape) -> Result<Vec<Image>, Error> {
let icon_path = theme.load_icon("default").ok_or(Error::NoDefaultCursor)?; 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_file = std::fs::File::open(&icon_path)?;
let mut cursor_data = Vec::new(); let mut cursor_data = Vec::new();
cursor_file.read_to_end(&mut cursor_data)?; cursor_file.read_to_end(&mut cursor_data)?;
@ -196,15 +201,50 @@ where
} }
pub struct CursorState { pub struct CursorState {
pub cursor: Cursor, current_cursor: RefCell<CursorShape>,
pub cursors: HashMap<CursorShape, Cursor>,
current_image: RefCell<Option<Image>>, current_image: RefCell<Option<Image>>,
image_cache: RefCell<HashMap<(TypeId, usize), Vec<(Image, Box<dyn Any + 'static>)>>>, image_cache: RefCell<HashMap<(TypeId, usize), Vec<(Image, Box<dyn Any + 'static>)>>>,
} }
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 { impl Default for CursorState {
fn default() -> CursorState { fn default() -> CursorState {
let (theme, size) = load_cursor_theme();
CursorState { 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), current_image: RefCell::new(None),
image_cache: RefCell::new(HashMap::new()), image_cache: RefCell::new(HashMap::new()),
} }
@ -247,12 +287,15 @@ where
let integer_scale = scale.x.max(scale.y).ceil() as u32; let integer_scale = scale.x.max(scale.y).ceil() as u32;
let seat_userdata = seat.user_data(); let seat_userdata = seat.user_data();
seat_userdata.insert_if_missing(CursorState::default);
let state = seat_userdata.get::<CursorState>().unwrap(); let state = seat_userdata.get::<CursorState>().unwrap();
let frame = state.cursor.get_image( let frame = state
integer_scale, .cursors
Into::<Duration>::into(time).as_millis() as u32, .get(&*state.current_cursor.borrow())
); .unwrap()
.get_image(
integer_scale,
Into::<Duration>::into(time).as_millis() as u32,
);
let mut cache = state.image_cache.borrow_mut(); let mut cache = state.image_cache.borrow_mut();
let pointer_images = cache let pointer_images = cache

View file

@ -13,7 +13,7 @@ use crate::{
}, // shell::grabs::SeatMoveGrabState }, // shell::grabs::SeatMoveGrabState
state::Common, state::Common,
utils::prelude::*, 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 calloop::{timer::Timer, RegistrationToken};
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::InputType; 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(Devices::default);
userdata.insert_if_missing(SupressedKeys::default); userdata.insert_if_missing(SupressedKeys::default);
userdata.insert_if_missing(SeatMoveGrabState::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(|| ActiveOutput(RefCell::new(output.clone())));
userdata.insert_if_missing(|| RefCell::new(CursorImageStatus::Default)); userdata.insert_if_missing(|| RefCell::new(CursorImageStatus::Default));
@ -664,10 +665,10 @@ impl State {
{ {
under = Some(layer.clone().into()); under = Some(layer.clone().into());
} }
} else if let Some((window, _)) = } else if let Some((target, _)) =
workspace.element_under(relative_pos) workspace.element_under(relative_pos)
{ {
under = Some(window.clone().into()); under = Some(target);
} else if let Some(layer) = layers } else if let Some(layer) = layers
.layer_under(WlrLayer::Bottom, pos) .layer_under(WlrLayer::Bottom, pos)
.or_else(|| layers.layer_under(WlrLayer::Background, pos)) .or_else(|| layers.layer_under(WlrLayer::Background, pos))
@ -685,8 +686,7 @@ impl State {
} }
}; };
} }
Common::set_focus(self, under.and_then(|target| target.try_into().ok()).as_ref(), seat, Some(serial));
Common::set_focus(self, under.as_ref(), seat, Some(serial));
} }
}; };
seat.get_pointer().unwrap().button( seat.get_pointer().unwrap().button(
@ -1347,9 +1347,9 @@ impl State {
{ {
return Some((or.clone().into(), or.geometry().loc)); 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(( return Some((
mapped.clone().into(), target,
loc + (global_pos - relative_pos).to_i32_round(), loc + (global_pos - relative_pos).to_i32_round(),
)); ));
} }

View file

@ -1,7 +1,7 @@
use std::sync::Weak; use std::sync::Weak;
use crate::{ use crate::{
shell::{element::CosmicMapped, CosmicSurface}, shell::{element::CosmicMapped, layout::tiling::ResizeForkTarget, CosmicSurface},
utils::prelude::*, utils::prelude::*,
wayland::handlers::xdg_shell::popup::get_popup_toplevel, wayland::handlers::xdg_shell::popup::get_popup_toplevel,
}; };
@ -28,6 +28,7 @@ pub enum PointerFocusTarget {
LayerSurface(LayerSurface), LayerSurface(LayerSurface),
Popup(PopupKind), Popup(PopupKind),
OverrideRedirect(X11Surface), OverrideRedirect(X11Surface),
ResizeFork(ResizeForkTarget),
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -39,6 +40,7 @@ pub enum KeyboardFocusTarget {
Popup(PopupKind), Popup(PopupKind),
} }
// TODO: This should be TryFrom, but PopupGrab needs to be able to convert. Fix this in smithay
impl From<KeyboardFocusTarget> for PointerFocusTarget { impl From<KeyboardFocusTarget> for PointerFocusTarget {
fn from(target: KeyboardFocusTarget) -> Self { fn from(target: KeyboardFocusTarget) -> Self {
match target { match target {
@ -51,6 +53,19 @@ impl From<KeyboardFocusTarget> for PointerFocusTarget {
} }
} }
impl TryFrom<PointerFocusTarget> for KeyboardFocusTarget {
type Error = ();
fn try_from(target: PointerFocusTarget) -> Result<Self, Self::Error> {
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 { impl KeyboardFocusTarget {
pub fn toplevel(&self) -> Option<WlSurface> { pub fn toplevel(&self) -> Option<WlSurface> {
match self { match self {
@ -85,6 +100,7 @@ impl IsAlive for PointerFocusTarget {
PointerFocusTarget::LayerSurface(l) => l.alive(), PointerFocusTarget::LayerSurface(l) => l.alive(),
PointerFocusTarget::Popup(p) => p.alive(), PointerFocusTarget::Popup(p) => p.alive(),
PointerFocusTarget::OverrideRedirect(s) => s.alive(), PointerFocusTarget::OverrideRedirect(s) => s.alive(),
PointerFocusTarget::ResizeFork(f) => f.alive(),
} }
} }
} }
@ -109,6 +125,7 @@ impl PointerTarget<State> for PointerFocusTarget {
PointerFocusTarget::LayerSurface(l) => PointerTarget::enter(l, seat, data, event), PointerFocusTarget::LayerSurface(l) => PointerTarget::enter(l, seat, data, event),
PointerFocusTarget::Popup(p) => PointerTarget::enter(p.wl_surface(), seat, data, event), PointerFocusTarget::Popup(p) => PointerTarget::enter(p.wl_surface(), seat, data, event),
PointerFocusTarget::OverrideRedirect(s) => PointerTarget::enter(s, 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<State>, data: &mut State, event: &MotionEvent) { fn motion(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
@ -120,6 +137,7 @@ impl PointerTarget<State> for PointerFocusTarget {
PointerTarget::motion(p.wl_surface(), seat, data, event) PointerTarget::motion(p.wl_surface(), seat, data, event)
} }
PointerFocusTarget::OverrideRedirect(s) => PointerTarget::motion(s, 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<State>, data: &mut State, event: &RelativeMotionEvent) { fn relative_motion(&self, seat: &Seat<State>, data: &mut State, event: &RelativeMotionEvent) {
@ -137,6 +155,9 @@ impl PointerTarget<State> for PointerFocusTarget {
PointerFocusTarget::OverrideRedirect(s) => { PointerFocusTarget::OverrideRedirect(s) => {
PointerTarget::relative_motion(s, seat, data, event) PointerTarget::relative_motion(s, seat, data, event)
} }
PointerFocusTarget::ResizeFork(f) => {
PointerTarget::relative_motion(f, seat, data, event)
}
} }
} }
fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) { fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) {
@ -148,6 +169,7 @@ impl PointerTarget<State> for PointerFocusTarget {
PointerTarget::button(p.wl_surface(), seat, data, event) PointerTarget::button(p.wl_surface(), seat, data, event)
} }
PointerFocusTarget::OverrideRedirect(s) => PointerTarget::button(s, 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<State>, data: &mut State, frame: AxisFrame) { fn axis(&self, seat: &Seat<State>, data: &mut State, frame: AxisFrame) {
@ -157,6 +179,7 @@ impl PointerTarget<State> for PointerFocusTarget {
PointerFocusTarget::LayerSurface(l) => PointerTarget::axis(l, seat, data, frame), PointerFocusTarget::LayerSurface(l) => PointerTarget::axis(l, seat, data, frame),
PointerFocusTarget::Popup(p) => PointerTarget::axis(p.wl_surface(), seat, data, frame), PointerFocusTarget::Popup(p) => PointerTarget::axis(p.wl_surface(), seat, data, frame),
PointerFocusTarget::OverrideRedirect(s) => PointerTarget::axis(s, 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<State>, data: &mut State, serial: Serial, time: u32) { fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) {
@ -172,6 +195,7 @@ impl PointerTarget<State> for PointerFocusTarget {
PointerFocusTarget::OverrideRedirect(s) => { PointerFocusTarget::OverrideRedirect(s) => {
PointerTarget::leave(s, seat, data, serial, time) 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) => { PointerFocusTarget::OverrideRedirect(s) => {
return s.wl_surface(); return s.wl_surface();
} }
PointerFocusTarget::ResizeFork(_) => {
return None;
}
}) })
} }
fn same_client_as(&self, object_id: &ObjectId) -> bool { 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::LayerSurface(l) => l.wl_surface().id().same_client_as(object_id),
PointerFocusTarget::Popup(p) => p.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::OverrideRedirect(s) => WaylandFocus::same_client_as(s, object_id),
PointerFocusTarget::ResizeFork(_) => false,
} }
} }
} }
@ -333,6 +361,12 @@ impl From<X11Surface> for PointerFocusTarget {
} }
} }
impl From<ResizeForkTarget> for PointerFocusTarget {
fn from(f: ResizeForkTarget) -> Self {
PointerFocusTarget::ResizeFork(f)
}
}
impl From<CosmicMapped> for KeyboardFocusTarget { impl From<CosmicMapped> for KeyboardFocusTarget {
fn from(w: CosmicMapped) -> Self { fn from(w: CosmicMapped) -> Self {
KeyboardFocusTarget::Element(w) KeyboardFocusTarget::Element(w)

View file

@ -1,52 +1,113 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use crate::{ use crate::{
backend::render::cursor::{CursorShape, CursorState},
shell::{focus::target::PointerFocusTarget, layout::Orientation}, shell::{focus::target::PointerFocusTarget, layout::Orientation},
utils::prelude::*, utils::prelude::*,
}; };
use id_tree::NodeId; use id_tree::NodeId;
use smithay::{ use smithay::{
input::pointer::{ backend::input::ButtonState,
AxisFrame, ButtonEvent, GrabStartData as PointerGrabStartData, MotionEvent, PointerGrab, input::{
PointerInnerHandle, RelativeMotionEvent, pointer::{
AxisFrame, ButtonEvent, Focus, GrabStartData as PointerGrabStartData, MotionEvent,
PointerGrab, PointerInnerHandle, PointerTarget, RelativeMotionEvent,
},
Seat,
}, },
output::{Output, WeakOutput}, output::WeakOutput,
utils::{Logical, Point}, 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<State> for ResizeForkTarget {
fn enter(&self, seat: &Seat<State>, _data: &mut State, _event: &MotionEvent) {
let user_data = seat.user_data();
let cursor_state = user_data.get::<CursorState>().unwrap();
cursor_state.set_shape(match self.orientation {
Orientation::Horizontal => CursorShape::RowResize,
Orientation::Vertical => CursorShape::ColResize,
});
}
fn leave(
&self,
seat: &Seat<State>,
_data: &mut State,
_serial: smithay::utils::Serial,
_time: u32,
) {
let user_data = seat.user_data();
let cursor_state = user_data.get::<CursorState>().unwrap();
cursor_state.set_shape(CursorShape::Default)
}
fn button(&self, seat: &Seat<State>, 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<State>, _data: &mut State, _event: &MotionEvent) {}
fn relative_motion(
&self,
_seat: &Seat<State>,
_data: &mut State,
_event: &RelativeMotionEvent,
) {
}
fn axis(&self, _seat: &Seat<State>, _data: &mut State, _frame: AxisFrame) {}
}
pub struct ResizeForkGrab { pub struct ResizeForkGrab {
start_data: PointerGrabStartData<State>, start_data: PointerGrabStartData<State>,
idx: usize, last_loc: Point<f64, Logical>,
initial_size_upleft: i32,
initial_size_downright: i32,
node: NodeId, node: NodeId,
output: WeakOutput, output: WeakOutput,
} left_up_idx: usize,
orientation: Orientation,
impl ResizeForkGrab {
pub fn new(
start_data: PointerGrabStartData<State>,
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(),
}
}
} }
impl PointerGrab<State> for ResizeForkGrab { impl PointerGrab<State> for ResizeForkGrab {
@ -60,131 +121,70 @@ impl PointerGrab<State> for ResizeForkGrab {
// While the grab is active, no client has pointer focus // While the grab is active, no client has pointer focus
handle.motion(data, None, event); 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() { if let Some(output) = self.output.upgrade() {
let tiling_layer = &mut data.common.shell.active_space_mut(&output).tiling_layer; let tiling_layer = &mut data.common.shell.active_space_mut(&output).tiling_layer;
if let Some(queue) = tiling_layer.queues.get_mut(&output) { if let Some(queue) = tiling_layer.queues.get_mut(&output) {
let tree = &mut queue.trees.back_mut().unwrap().0; let tree = &mut queue.trees.back_mut().unwrap().0;
if tree.get(&self.node).is_ok() { if tree.get(&self.node).is_ok() {
let orientation = tree.get(&self.node).unwrap().data().orientation(); let delta = match self.orientation {
let delta = match orientation {
Orientation::Vertical => delta.x, Orientation::Vertical => delta.x,
Orientation::Horizontal => delta.y, Orientation::Horizontal => delta.y,
} }
.round() as i32; .round() as i32;
let upleft_node_id = // check that we are still alive
match tree.children_ids(&self.node).unwrap().skip(self.idx).next() { let mut iter = tree
Some(elem) => elem,
None => {
return;
}
};
let downright_node_id = match tree
.children_ids(&self.node) .children_ids(&self.node)
.unwrap() .unwrap()
.skip(self.idx + 1) .skip(self.left_up_idx);
.next() let first_elem = iter.next();
{ let second_elem = iter.next();
Some(elem) => elem, if first_elem.is_none() || second_elem.is_none() {
None => { return handle.unset_grab(data, event.serial, event.time);
return;
}
}; };
let next_mapped = |mut node| loop { match tree.get_mut(&self.node).unwrap().data_mut() {
if let Some(node_id) = node { Data::Group {
match tree.get(&node_id).unwrap().data() { sizes, orientation, ..
Data::Group { orientation: o, .. } if o == &orientation => { } => {
node = tree.children_ids(&node_id).unwrap().last().cloned(); if sizes[self.left_up_idx] + sizes[self.left_up_idx + 1]
< match orientation {
Orientation::Vertical => 720,
Orientation::Horizontal => 480,
} }
_ => { {
break node_id; return;
}
}
} 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!(),
}; };
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 &[ _ => unreachable!(),
(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();
} }
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);
} }
} }
} }

View file

@ -10,7 +10,7 @@ use crate::{
CosmicMapped, CosmicMappedRenderElement, CosmicStack, CosmicWindow, CosmicMapped, CosmicMappedRenderElement, CosmicStack, CosmicWindow,
}, },
focus::{ focus::{
target::{KeyboardFocusTarget, WindowGroup}, target::{KeyboardFocusTarget, PointerFocusTarget, WindowGroup},
FocusDirection, FocusStackMut, FocusDirection, FocusStackMut,
}, },
grabs::ResizeEdge, grabs::ResizeEdge,
@ -34,7 +34,7 @@ use smithay::{
ImportAll, ImportMem, Renderer, ImportAll, ImportMem, Renderer,
}, },
desktop::{layer_map_for_output, space::SpaceElement, PopupKind}, desktop::{layer_map_for_output, space::SpaceElement, PopupKind},
input::{pointer::GrabStartData as PointerGrabStartData, Seat}, input::Seat,
output::Output, output::Output,
reexports::wayland_server::Client, reexports::wayland_server::Client,
utils::{IsAlive, Logical, Point, Rectangle, Scale}, utils::{IsAlive, Logical, Point, Rectangle, Scale},
@ -1389,60 +1389,6 @@ impl TilingLayout {
clients clients
} }
pub fn resize_request(
&self,
mapped: &CosmicMapped,
_seat: &Seat<State>,
start_data: PointerGrabStartData<State>,
edges: ResizeEdge,
) -> Option<ResizeForkGrab> {
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<Data>, mut node_id: NodeId) -> ResizeEdge { pub fn possible_resizes(tree: &Tree<Data>, mut node_id: NodeId) -> ResizeEdge {
let mut edges = ResizeEdge::empty(); let mut edges = ResizeEdge::empty();
@ -1535,6 +1481,15 @@ impl TilingLayout {
(other_idx, node_idx) (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]; let old_size = sizes[shrink_idx];
sizes[shrink_idx] = sizes[shrink_idx] =
(old_size - amount).max(if orientation == Orientation::Vertical { (old_size - amount).max(if orientation == Orientation::Vertical {
@ -1786,6 +1741,102 @@ impl TilingLayout {
None None
} }
pub fn element_under(
&self,
location: Point<f64, Logical>,
) -> Option<(PointerFocusTarget, Point<i32, Logical>)> {
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( pub fn mapped(
&self, &self,
) -> impl Iterator<Item = (&Output, &CosmicMapped, Rectangle<i32, Logical>)> { ) -> impl Iterator<Item = (&Output, &CosmicMapped, Rectangle<i32, Logical>)> {

View file

@ -51,7 +51,10 @@ use super::{
resize_indicator::ResizeIndicator, stack::CosmicStackRenderElement, resize_indicator::ResizeIndicator, stack::CosmicStackRenderElement,
window::CosmicWindowRenderElement, CosmicMapped, window::CosmicWindowRenderElement, CosmicMapped,
}, },
focus::{target::KeyboardFocusTarget, FocusStack, FocusStackMut}, focus::{
target::{KeyboardFocusTarget, PointerFocusTarget},
FocusStack, FocusStackMut,
},
grabs::{ResizeEdge, ResizeGrab}, grabs::{ResizeEdge, ResizeGrab},
CosmicMappedRenderElement, CosmicSurface, ResizeDirection, ResizeMode, CosmicMappedRenderElement, CosmicSurface, ResizeDirection, ResizeMode,
}; };
@ -200,23 +203,12 @@ impl Workspace {
pub fn element_under( pub fn element_under(
&self, &self,
location: Point<f64, Logical>, location: Point<f64, Logical>,
) -> Option<(&CosmicMapped, Point<i32, Logical>)> { ) -> Option<(PointerFocusTarget, Point<i32, Logical>)> {
self.floating_layer self.floating_layer
.space .space
.element_under(location) .element_under(location)
.or_else(|| { .map(|(mapped, p)| (mapped.clone().into(), p))
self.tiling_layer.mapped().find_map(|(_, mapped, geo)| { .or_else(|| self.tiling_layer.element_under(location))
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()
})
})
} }
pub fn element_geometry(&self, elem: &CosmicMapped) -> Option<Rectangle<i32, Logical>> { pub fn element_geometry(&self, elem: &CosmicMapped) -> Option<Rectangle<i32, Logical>> {
@ -335,10 +327,6 @@ impl Workspace {
self.floating_layer self.floating_layer
.resize_request(mapped, seat, start_data.clone(), edges) .resize_request(mapped, seat, start_data.clone(), edges)
.map(Into::into) .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 { } else {
None None
} }

View file

@ -1,7 +1,7 @@
use std::{cell::RefCell, sync::Mutex, time::Duration}; use std::{cell::RefCell, sync::Mutex, time::Duration};
use crate::{ use crate::{
backend::render::cursor::CursorState, backend::render::cursor::{CursorShape, CursorState},
input::{ActiveOutput, SeatId}, input::{ActiveOutput, SeatId},
}; };
use smithay::{ use smithay::{
@ -116,7 +116,9 @@ impl SeatExt for Seat<State> {
seat_userdata.insert_if_missing(CursorState::default); seat_userdata.insert_if_missing(CursorState::default);
let state = seat_userdata.get::<CursorState>().unwrap(); let state = seat_userdata.get::<CursorState>().unwrap();
let frame = state let frame = state
.cursor .cursors
.get(&CursorShape::Default)
.unwrap()
.get_image(1, Into::<Duration>::into(time).as_millis() as u32); .get_image(1, Into::<Duration>::into(time).as_millis() as u32);
Some(( Some((

View file

@ -1,7 +1,7 @@
use std::{ffi::OsString, os::unix::io::OwnedFd}; use std::{ffi::OsString, os::unix::io::OwnedFd};
use crate::{ use crate::{
backend::render::cursor::Cursor, backend::render::cursor::{load_cursor_theme, Cursor, CursorShape},
shell::{focus::target::KeyboardFocusTarget, CosmicSurface, Shell}, shell::{focus::target::KeyboardFocusTarget, CosmicSurface, Shell},
state::{Data, State}, state::{Data, State},
utils::prelude::*, 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); let image = cursor.get_image(1, 0);
if let Err(err) = wm.set_cursor( if let Err(err) = wm.set_cursor(
&image.pixels_rgba, &image.pixels_rgba,