use std::{cell::RefCell, sync::Mutex, time::Duration}; use crate::{ backend::render::cursor::CursorState, input::{ActiveOutput, SeatId}, }; use smithay::{ desktop::utils::bbox_from_surface_tree, input::{ pointer::{CursorImageAttributes, CursorImageStatus}, Seat, }, output::Output, utils::{Buffer, IsAlive, Logical, Monotonic, Point, Rectangle, Time, Transform}, wayland::compositor::with_states, }; pub use crate::shell::{Shell, Workspace}; pub use crate::state::{Common, State}; pub use crate::wayland::handlers::xdg_shell::popup::update_reactive_popups; pub trait OutputExt { fn geometry(&self) -> Rectangle; } impl OutputExt for Output { fn geometry(&self) -> Rectangle { Rectangle::from_loc_and_size(self.current_location(), { Transform::from(self.current_transform()) .transform_size( self.current_mode() .map(|m| m.size) .unwrap_or_else(|| (0, 0).into()), ) .to_f64() .to_logical(self.current_scale().fractional_scale()) .to_i32_round() }) } } pub trait SeatExt { fn id(&self) -> usize; fn active_output(&self) -> Output; fn set_active_output(&self, output: &Output); fn cursor_geometry( &self, loc: impl Into>, time: Time, ) -> Option<(Rectangle, Point)>; } impl SeatExt for Seat { fn id(&self) -> usize { self.user_data().get::().unwrap().0 } fn active_output(&self) -> Output { self.user_data() .get::() .map(|x| x.0.borrow().clone()) .unwrap() } fn set_active_output(&self, output: &Output) { *self .user_data() .get::() .unwrap() .0 .borrow_mut() = output.clone(); } fn cursor_geometry( &self, loc: impl Into>, time: Time, ) -> Option<(Rectangle, Point)> { let location = loc.into().to_i32_round(); let cursor_status = self .user_data() .get::>() .map(|cell| { let mut cursor_status = cell.borrow_mut(); if let CursorImageStatus::Surface(ref surface) = *cursor_status { if !surface.alive() { *cursor_status = CursorImageStatus::Default; } } cursor_status.clone() }) .unwrap_or(CursorImageStatus::Default); match cursor_status { CursorImageStatus::Surface(surface) => { let hotspot = with_states(&surface, |states| { states .data_map .get::>() .unwrap() .lock() .unwrap() .hotspot }); let geo = bbox_from_surface_tree(&surface, (location.x, location.y)); let buffer_geo = Rectangle::from_loc_and_size( (geo.loc.x, geo.loc.y), geo.size.to_buffer(1, Transform::Normal), ); Some((buffer_geo, (hotspot.x, hotspot.y).into())) } CursorImageStatus::Default => { let seat_userdata = self.user_data(); seat_userdata.insert_if_missing(CursorState::default); let state = seat_userdata.get::().unwrap(); let frame = state .cursor .get_image(1, Into::::into(time).as_millis() as u32); Some(( Rectangle::from_loc_and_size( location, (frame.width as i32, frame.height as i32), ), (frame.xhot as i32, frame.yhot as i32).into(), )) } CursorImageStatus::Hidden => None, } } }