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

View file

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

View file

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