tiling: Properly handle resizing using a ptr device
This commit is contained in:
parent
92019b4286
commit
b818a68a91
8 changed files with 371 additions and 252 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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>)> {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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((
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue