iced: Track last seat/serial for grabs

This commit is contained in:
Victoria Brekenfeld 2025-02-13 21:07:15 +01:00 committed by Victoria Brekenfeld
parent 6fd1a48e60
commit df9441804d
3 changed files with 66 additions and 46 deletions

View file

@ -102,7 +102,6 @@ pub struct CosmicStackInternal {
reenter: Arc<AtomicBool>,
potential_drag: Arc<Mutex<Option<usize>>>,
override_alive: Arc<AtomicBool>,
last_seat: Arc<Mutex<Option<(Seat<State>, Serial)>>>,
geometry: Arc<Mutex<Option<Rectangle<i32, Global>>>>,
mask: Arc<Mutex<Option<tiny_skia::Mask>>>,
}
@ -155,7 +154,6 @@ impl CosmicStack {
reenter: Arc::new(AtomicBool::new(false)),
potential_drag: Arc::new(Mutex::new(None)),
override_alive: Arc::new(AtomicBool::new(true)),
last_seat: Arc::new(Mutex::new(None)),
geometry: Arc::new(Mutex::new(None)),
mask: Arc::new(Mutex::new(None)),
},
@ -768,10 +766,11 @@ impl Program for CosmicStackInternal {
&mut self,
message: Self::Message,
loop_handle: &LoopHandle<'static, crate::state::State>,
last_seat: Option<&(Seat<State>, Serial)>,
) -> Task<Self::Message> {
match message {
Message::DragStart => {
if let Some((seat, serial)) = self.last_seat.lock().unwrap().clone() {
if let Some((seat, serial)) = last_seat.cloned() {
let active = self.active.load(Ordering::SeqCst);
if let Some(surface) = self.windows.lock().unwrap()[active]
.wl_surface()
@ -831,7 +830,7 @@ impl Program for CosmicStackInternal {
self.scroll_to_focus.store(false, Ordering::SeqCst);
}
Message::Menu => {
if let Some((seat, serial)) = self.last_seat.lock().unwrap().clone() {
if let Some((seat, serial)) = last_seat.cloned() {
let active = self.active.load(Ordering::SeqCst);
if let Some(surface) = self.windows.lock().unwrap()[active]
.wl_surface()
@ -886,7 +885,7 @@ impl Program for CosmicStackInternal {
}
}
Message::TabMenu(idx) => {
if let Some((seat, serial)) = self.last_seat.lock().unwrap().clone() {
if let Some((seat, serial)) = last_seat.cloned() {
if let Some(surface) = self.windows.lock().unwrap()[idx]
.wl_surface()
.map(Cow::into_owned)
@ -1338,12 +1337,7 @@ impl PointerTarget<State> for CosmicStack {
fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) {
match self.0.with_program(|p| p.current_focus()) {
Some(Focus::Header) => {
self.0.with_program(|p| {
*p.last_seat.lock().unwrap() = Some((seat.clone(), event.serial));
});
PointerTarget::button(&self.0, seat, data, event)
}
Some(Focus::Header) => PointerTarget::button(&self.0, seat, data, event),
Some(x) => {
let serial = event.serial;
let seat = seat.clone();
@ -1523,7 +1517,6 @@ impl TouchTarget<State> for CosmicStack {
fn down(&self, seat: &Seat<State>, data: &mut State, event: &DownEvent, seq: Serial) {
let mut event = event.clone();
let active_window_geo = self.0.with_program(|p| {
*p.last_seat.lock().unwrap() = Some((seat.clone(), event.serial));
p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)].geometry()
});
event.location -= active_window_geo.loc.to_f64();

View file

@ -77,7 +77,6 @@ pub struct CosmicWindowInternal {
activated: Arc<AtomicBool>,
/// TODO: This needs to be per seat
pointer_entered: Arc<AtomicU8>,
last_seat: Arc<Mutex<Option<(Seat<State>, Serial)>>>,
last_title: Arc<Mutex<String>>,
}
@ -88,7 +87,6 @@ impl fmt::Debug for CosmicWindowInternal {
.field("activated", &self.activated.load(Ordering::SeqCst))
.field("pointer_entered", &self.pointer_entered)
// skip seat to avoid loop
.field("last_seat", &"...")
.finish()
}
}
@ -189,7 +187,6 @@ impl CosmicWindow {
window,
activated: Arc::new(AtomicBool::new(false)),
pointer_entered: Arc::new(AtomicU8::new(0)),
last_seat: Arc::new(Mutex::new(None)),
last_title: Arc::new(Mutex::new(last_title)),
},
(width, SSD_HEIGHT),
@ -427,10 +424,11 @@ impl Program for CosmicWindowInternal {
&mut self,
message: Self::Message,
loop_handle: &LoopHandle<'static, crate::state::State>,
last_seat: Option<&(Seat<State>, Serial)>,
) -> Task<Self::Message> {
match message {
Message::DragStart => {
if let Some((seat, serial)) = self.last_seat.lock().unwrap().clone() {
if let Some((seat, serial)) = last_seat.cloned() {
if let Some(surface) = self.window.wl_surface().map(Cow::into_owned) {
loop_handle.insert_idle(move |state| {
let res = state.common.shell.write().unwrap().move_request(
@ -480,7 +478,7 @@ impl Program for CosmicWindowInternal {
}
Message::Close => self.window.close(),
Message::Menu => {
if let Some((seat, serial)) = self.last_seat.lock().unwrap().clone() {
if let Some((seat, serial)) = last_seat.cloned() {
if let Some(surface) = self.window.wl_surface().map(Cow::into_owned) {
loop_handle.insert_idle(move |state| {
let shell = state.common.shell.read().unwrap();
@ -731,12 +729,7 @@ impl PointerTarget<State> for CosmicWindow {
fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) {
match self.0.with_program(|p| p.current_focus()) {
Some(Focus::Header) => {
self.0.with_program(|p| {
*p.last_seat.lock().unwrap() = Some((seat.clone(), event.serial));
});
PointerTarget::button(&self.0, seat, data, event)
}
Some(Focus::Header) => PointerTarget::button(&self.0, seat, data, event),
Some(x) => {
let serial = event.serial;
let seat = seat.clone();
@ -871,7 +864,6 @@ impl TouchTarget<State> for CosmicWindow {
let mut event = event.clone();
self.0.with_program(|p| {
event.location -= p.window.geometry().loc.to_f64();
*p.last_seat.lock().unwrap() = Some((seat.clone(), event.serial));
});
TouchTarget::down(&self.0, seat, data, &event, seq)
}

View file

@ -107,8 +107,9 @@ pub trait Program {
&mut self,
message: Self::Message,
loop_handle: &LoopHandle<'static, crate::state::State>,
last_seat: Option<&(Seat<crate::state::State>, Serial)>,
) -> Task<Self::Message> {
let _ = (message, loop_handle);
let _ = (message, loop_handle, last_seat);
Task::none()
}
fn view(&self) -> cosmic::Element<'_, Self::Message>;
@ -128,18 +129,24 @@ pub trait Program {
}
}
struct ProgramWrapper<P: Program>(P, LoopHandle<'static, crate::state::State>);
struct ProgramWrapper<P: Program> {
program: P,
evlh: LoopHandle<'static, crate::state::State>,
last_seat: Arc<Mutex<Option<(Seat<crate::state::State>, Serial)>>>,
}
impl<P: Program> IcedProgram for ProgramWrapper<P> {
type Message = <P as Program>::Message;
type Renderer = cosmic::Renderer;
type Theme = cosmic::Theme;
fn update(&mut self, message: Self::Message) -> Task<Self::Message> {
self.0.update(message, &self.1)
let last_seat = self.last_seat.lock().unwrap();
self.program.update(message, &self.evlh, last_seat.as_ref())
}
fn view(&self) -> cosmic::Element<'_, Self::Message> {
self.0.view()
self.program.view()
}
}
@ -151,6 +158,7 @@ pub(crate) struct IcedElementInternal<P: Program + Send + 'static> {
// state
size: Size<i32, Logical>,
last_seat: Arc<Mutex<Option<(Seat<crate::state::State>, Serial)>>>,
cursor_pos: Option<Point<f64, Logical>>,
touch_map: HashMap<Finger, IcedPoint>,
@ -185,7 +193,11 @@ impl<P: Program + Send + Clone + 'static> Clone for IcedElementInternal<P> {
let mut debug = Debug::new();
let state = State::new(
ID.clone(),
ProgramWrapper(self.state.program().0.clone(), handle.clone()),
ProgramWrapper {
program: self.state.program().program.clone(),
evlh: handle.clone(),
last_seat: self.last_seat.clone(),
},
IcedSize::new(self.size.w as f32, self.size.h as f32),
&mut renderer,
&mut debug,
@ -196,6 +208,7 @@ impl<P: Program + Send + Clone + 'static> Clone for IcedElementInternal<P> {
buffers: self.buffers.clone(),
pending_update: self.pending_update.clone(),
size: self.size.clone(),
last_seat: self.last_seat.clone(),
cursor_pos: self.cursor_pos.clone(),
touch_map: self.touch_map.clone(),
theme: self.theme.clone(),
@ -243,12 +256,17 @@ impl<P: Program + Send + 'static> IcedElement<P> {
theme: cosmic::Theme,
) -> IcedElement<P> {
let size = size.into();
let last_seat = Arc::new(Mutex::new(None));
let mut renderer = cosmic::Renderer::new(cosmic::font::default(), Pixels(16.0));
let mut debug = Debug::new();
let state = State::new(
ID.clone(),
ProgramWrapper(program, handle.clone()),
ProgramWrapper {
program,
evlh: handle.clone(),
last_seat: last_seat.clone(),
},
IcedSize::new(size.w as f32, size.h as f32),
&mut renderer,
&mut debug,
@ -268,6 +286,7 @@ impl<P: Program + Send + 'static> IcedElement<P> {
pending_update: None,
size,
cursor_pos: None,
last_seat,
touch_map: HashMap::new(),
theme,
renderer,
@ -285,12 +304,12 @@ impl<P: Program + Send + 'static> IcedElement<P> {
pub fn with_program<R>(&self, func: impl FnOnce(&P) -> R) -> R {
let internal = self.0.lock().unwrap();
func(&internal.state.program().0)
func(&internal.state.program().program)
}
pub fn minimum_size(&self) -> Size<i32, Logical> {
let internal = self.0.lock().unwrap();
let element = internal.state.program().0.view();
let element = internal.state.program().program.view();
let node = element
.as_widget()
.layout(
@ -349,6 +368,14 @@ impl<P: Program + Send + 'static> IcedElement<P> {
}
internal.update(true);
}
pub fn current_size(&self) -> Size<i32, Logical> {
self.0.lock().unwrap().size
}
pub fn queue_message(&self, msg: P::Message) {
self.0.lock().unwrap().state.queue_message(msg);
}
}
impl<P: Program + Send + 'static + Clone> IcedElement<P> {
@ -411,7 +438,7 @@ impl<P: Program + Send + 'static> IcedElementInternal<P> {
impl<P: Program + Send + 'static> PointerTarget<crate::state::State> for IcedElement<P> {
fn enter(
&self,
_seat: &Seat<crate::state::State>,
seat: &Seat<crate::state::State>,
_data: &mut crate::state::State,
event: &MotionEvent,
) {
@ -425,12 +452,13 @@ impl<P: Program + Send + 'static> PointerTarget<crate::state::State> for IcedEle
.queue_event(Event::Mouse(MouseEvent::CursorMoved { position }));
// TODO: Update iced widgets to handle touch using event position, not cursor_pos
internal.cursor_pos = Some(event.location);
*internal.last_seat.lock().unwrap() = Some((seat.clone(), event.serial));
let _ = internal.update(true);
}
fn motion(
&self,
_seat: &Seat<crate::state::State>,
seat: &Seat<crate::state::State>,
_data: &mut crate::state::State,
event: &MotionEvent,
) {
@ -440,6 +468,7 @@ impl<P: Program + Send + 'static> PointerTarget<crate::state::State> for IcedEle
.state
.queue_event(Event::Mouse(MouseEvent::CursorMoved { position }));
internal.cursor_pos = Some(event.location);
*internal.last_seat.lock().unwrap() = Some((seat.clone(), event.serial));
let _ = internal.update(true);
}
@ -453,7 +482,7 @@ impl<P: Program + Send + 'static> PointerTarget<crate::state::State> for IcedEle
fn button(
&self,
_seat: &Seat<crate::state::State>,
seat: &Seat<crate::state::State>,
_data: &mut crate::state::State,
event: &ButtonEvent,
) {
@ -468,6 +497,7 @@ impl<P: Program + Send + 'static> PointerTarget<crate::state::State> for IcedEle
ButtonState::Pressed => MouseEvent::ButtonPressed(button),
ButtonState::Released => MouseEvent::ButtonReleased(button),
}));
*internal.last_seat.lock().unwrap() = Some((seat.clone(), event.serial));
let _ = internal.update(true);
}
@ -573,10 +603,10 @@ impl<P: Program + Send + 'static> PointerTarget<crate::state::State> for IcedEle
impl<P: Program + Send + 'static> TouchTarget<crate::state::State> for IcedElement<P> {
fn down(
&self,
_seat: &Seat<crate::state::State>,
seat: &Seat<crate::state::State>,
_data: &mut crate::state::State,
event: &DownEvent,
_seq: Serial,
seq: Serial,
) {
let mut internal = self.0.lock().unwrap();
let id = Finger(i32::from(event.slot) as u64);
@ -586,19 +616,21 @@ impl<P: Program + Send + 'static> TouchTarget<crate::state::State> for IcedEleme
.queue_event(Event::Touch(TouchEvent::FingerPressed { id, position }));
internal.touch_map.insert(id, position);
internal.cursor_pos = Some(event.location);
*internal.last_seat.lock().unwrap() = Some((seat.clone(), seq));
let _ = internal.update(true);
}
fn up(
&self,
_seat: &Seat<crate::state::State>,
seat: &Seat<crate::state::State>,
_data: &mut crate::state::State,
event: &UpEvent,
_seq: Serial,
seq: Serial,
) {
let mut internal = self.0.lock().unwrap();
let id = Finger(i32::from(event.slot) as u64);
if let Some(position) = internal.touch_map.remove(&id) {
*internal.last_seat.lock().unwrap() = Some((seat.clone(), seq));
internal
.state
.queue_event(Event::Touch(TouchEvent::FingerLifted { id, position }));
@ -608,14 +640,15 @@ impl<P: Program + Send + 'static> TouchTarget<crate::state::State> for IcedEleme
fn motion(
&self,
_seat: &Seat<crate::state::State>,
seat: &Seat<crate::state::State>,
_data: &mut crate::state::State,
event: &TouchMotionEvent,
_seq: Serial,
seq: Serial,
) {
let mut internal = self.0.lock().unwrap();
let id = Finger(i32::from(event.slot) as u64);
let position = IcedPoint::new(event.location.x as f32, event.location.y as f32);
*internal.last_seat.lock().unwrap() = Some((seat.clone(), seq));
internal
.state
.queue_event(Event::Touch(TouchEvent::FingerMoved { id, position }));
@ -872,7 +905,7 @@ where
tiny_skia::PixmapMut::from_bytes(buf, size.w as u32, size.h as u32)
.expect("Failed to create pixel map");
let background_color = state_ref.program().0.background_color(theme);
let background_color = state_ref.program().program.background_color(theme);
let bounds = IcedSize::new(size.w as u32, size.h as u32);
let viewport = Viewport::with_physical_size(bounds, scale.x);
let scale_x = scale.x as f32;
@ -934,10 +967,12 @@ where
)
})
.collect::<Vec<_>>();
state_ref
.program()
.0
.foreground(&mut pixels, &damage, scale.x as f32, theme);
state_ref.program().program.foreground(
&mut pixels,
&damage,
scale.x as f32,
theme,
);
Result::<_, ()>::Ok(damage)
});