diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index 2998aff6..2397925e 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -22,6 +22,14 @@ pub mod zwlr_layer_surface_v1; pub mod zwp_idle_inhibitor_v1; pub mod zwp_input_popup_surface_v2; +mod node; +mod presentation; +mod request; + +pub use presentation::SyncobjRelease; + +use presentation::{FrameRequest, SurfaceRelease}; + use { crate::{ backend::{ButtonState, KeyState}, @@ -1008,167 +1016,6 @@ impl WlSurface { const MAX_DAMAGE: usize = 32; -impl WlSurfaceRequestHandler for WlSurface { - type Error = WlSurfaceError; - - fn destroy(&self, _req: Destroy, _slf: &Rc) -> Result<(), Self::Error> { - self.commit_timeline.clear(ClearReason::Destroy); - self.unset_dnd_icons(); - self.unset_cursors(); - self.ext.get().on_surface_destroy()?; - self.destroy_node(); - { - let mut children = self.children.borrow_mut(); - if let Some(children) = &mut *children { - for ss in children.subsurfaces.values() { - ss.surface.unset_ext(); - } - } - *children = None; - } - self.buffer.set(None); - self.reset_shm_textures(); - if let Some(xwayland_serial) = self.xwayland_serial.get() { - self.client - .surfaces_by_xwayland_serial - .remove(&xwayland_serial); - } - self.frame_requests.borrow_mut().clear(); - self.toplevel.set(None); - self.client.remove_obj(self)?; - self.idle_inhibitors.clear(); - self.constraints.take(); - self.destroyed.set(true); - Ok(()) - } - - fn attach(&self, req: Attach, _slf: &Rc) -> Result<(), Self::Error> { - let pending = &mut *self.pending.borrow_mut(); - if self.version >= OFFSET_SINCE { - if req.x != 0 || req.y != 0 { - return Err(WlSurfaceError::OffsetInAttach); - } - } else { - pending.offset = (req.x, req.y); - } - let buf = if req.buffer.is_some() { - Some(self.client.lookup(req.buffer)?) - } else { - None - }; - pending.buffer = Some(buf.map(|buf| AttachedBuffer { - send_release: false, - buf, - })); - Ok(()) - } - - fn damage(&self, req: Damage, _slf: &Rc) -> Result<(), Self::Error> { - self.do_damage(req.x, req.y, req.width, req.height, |p| { - &mut p.surface_damage - }) - } - - fn frame(&self, req: Frame, _slf: &Rc) -> Result<(), Self::Error> { - let cb = Rc::new(WlCallback::new(req.callback, &self.client)); - track!(self.client, cb); - self.client.add_client_obj(&cb)?; - self.pending - .borrow_mut() - .frame_request - .push(FrameRequest { now: 0, cb }); - Ok(()) - } - - fn set_opaque_region( - &self, - region: SetOpaqueRegion, - _slf: &Rc, - ) -> Result<(), Self::Error> { - let region = if region.region.is_some() { - Some(self.client.lookup(region.region)?.region()) - } else { - None - }; - self.pending.borrow_mut().opaque_region = Some(region); - Ok(()) - } - - fn set_input_region(&self, req: SetInputRegion, _slf: &Rc) -> Result<(), Self::Error> { - let region = if req.region.is_some() { - Some(self.client.lookup(req.region)?.region()) - } else { - None - }; - self.pending.borrow_mut().input_region = Some(region); - Ok(()) - } - - fn commit(&self, _req: Commit, slf: &Rc) -> Result<(), Self::Error> { - let ext = self.ext.get(); - let pending = &mut *self.pending.borrow_mut(); - if let Some(Some(buffer)) = &mut pending.buffer - && pending.release_point.is_none() - && pending.sync_file_release.is_none() - { - buffer.send_release = true; - } - if let Some(release) = &mut pending.release_point { - release.committed = true; - } - self.verify_syncobj_sync(pending)?; - if pending.surface_release.is_not_empty() && not_matches!(pending.buffer, Some(Some(_))) { - return Err(WlSurfaceError::SurfaceReleaseWithoutAttach); - } - if pending.sync_file_release.is_some() && not_matches!(pending.buffer, Some(Some(_))) { - return Err(WlSurfaceError::SyncFileReleaseWithoutAttach); - } - if ext.commit_requested(pending) == CommitAction::ContinueCommit { - self.commit_timeline.commit(slf, pending)?; - } - Ok(()) - } - - fn set_buffer_transform( - &self, - req: SetBufferTransform, - _slf: &Rc, - ) -> Result<(), Self::Error> { - let Some(tf) = Transform::from_wl(req.transform) else { - return Err(WlSurfaceError::UnknownBufferTransform(req.transform)); - }; - self.pending.borrow_mut().transform = Some(tf); - Ok(()) - } - - fn set_buffer_scale(&self, req: SetBufferScale, _slf: &Rc) -> Result<(), Self::Error> { - if req.scale < 1 { - return Err(WlSurfaceError::NonPositiveBufferScale); - } - self.pending.borrow_mut().scale = Some(req.scale); - Ok(()) - } - - fn damage_buffer(&self, req: DamageBuffer, _slf: &Rc) -> Result<(), Self::Error> { - self.do_damage(req.x, req.y, req.width, req.height, |p| { - &mut p.buffer_damage - }) - } - - fn offset(&self, req: Offset, _slf: &Rc) -> Result<(), Self::Error> { - self.pending.borrow_mut().offset = (req.x, req.y); - Ok(()) - } - - fn get_release(&self, req: GetRelease, _slf: &Rc) -> Result<(), Self::Error> { - let cb = Rc::new(WlCallback::new(req.callback, &self.client)); - track!(self.client, cb); - self.client.add_client_obj(&cb)?; - let release = SurfaceRelease { cb }; - self.pending.borrow_mut().surface_release.push(release); - Ok(()) - } -} impl WlSurface { fn apply_state(self: &Rc, pending: &mut PendingState) -> Result<(), WlSurfaceError> { @@ -1826,340 +1673,6 @@ impl Object for WlSurface { dedicated_add_obj!(WlSurface, WlSurfaceId, surfaces); tree_id!(SurfaceNodeId); -impl Node for WlSurface { - fn node_id(&self) -> NodeId { - self.node_id.into() - } - - fn node_seat_state(&self) -> &NodeSeatState { - &self.seat_state - } - - fn node_visit(self: Rc, visitor: &mut dyn NodeVisitor) { - visitor.visit_surface(&self); - } - - fn node_visit_children(&self, visitor: &mut dyn NodeVisitor) { - let children = self.children.borrow_mut(); - if let Some(c) = children.deref() { - for child in c.subsurfaces.values() { - visitor.visit_surface(&child.surface); - } - } - } - - fn node_visible(&self) -> bool { - self.visible.get() - } - - fn node_absolute_position(&self) -> Rect { - self.buffer_abs_pos.get() - } - - fn node_output(&self) -> Option> { - Some(self.output.get()) - } - - fn node_location(&self) -> Option { - Some(self.location.get()) - } - - fn node_layer(&self) -> NodeLayerLink { - self.ext.get().node_layer() - } - - fn node_active_changed(&self, active: bool) { - if let Some(tl) = self.toplevel.get() { - tl.tl_surface_active_changed(active); - } - } - - fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, bounds: Option<&Rect>) { - renderer.render_surface(self, x, y, bounds); - } - - fn node_client(&self) -> Option> { - Some(self.client.clone()) - } - - fn node_toplevel(self: Rc) -> Option> { - self.toplevel.get() - } - - fn node_tray_item(&self) -> Option { - self.ext.get().tray_item() - } - - fn node_make_visible(self: Rc) { - if let Some(tl) = self.toplevel.get() { - tl.node_make_visible(); - } - } - - fn node_on_key( - &self, - seat: &WlSeatGlobal, - time_usec: u64, - key: u32, - state: KeyState, - kb_state: &KeyboardState, - ) { - seat.key_surface(self, time_usec, key, state, kb_state); - } - - fn node_on_mods(&self, seat: &WlSeatGlobal, kb_state: &KeyboardState) { - seat.mods_surface(self, kb_state); - } - - fn node_on_touch_down( - self: Rc, - seat: &Rc, - time_usec: u64, - id: i32, - x: Fixed, - y: Fixed, - ) { - seat.touch_down_surface(&self, time_usec, id, x, y) - } - - fn node_on_touch_up(self: Rc, seat: &Rc, time_usec: u64, id: i32) { - seat.touch_up_surface(&self, time_usec, id) - } - - fn node_on_touch_motion( - self: Rc, - seat: &WlSeatGlobal, - time_usec: u64, - id: i32, - x: Fixed, - y: Fixed, - ) { - seat.touch_motion_surface(&self, time_usec, id, x, y) - } - - fn node_on_touch_frame(&self, seat: &WlSeatGlobal) { - seat.touch_frame_surface(&self) - } - - fn node_on_touch_cancel(&self, seat: &WlSeatGlobal) { - seat.touch_cancel_surface(&self) - } - - fn node_on_button( - self: Rc, - seat: &Rc, - time_usec: u64, - button: u32, - state: ButtonState, - serial: u64, - ) { - seat.button_surface(&self, time_usec, button, state, serial); - } - - fn node_on_axis_event(self: Rc, seat: &Rc, event: &PendingScroll) { - seat.scroll_surface(&self, event); - } - - fn node_on_focus(self: Rc, seat: &WlSeatGlobal) { - if let Some(xsurface) = self.ext.get().into_xsurface() - && let Some(window) = xsurface.xwindow.get() - { - self.client - .state - .xwayland - .queue - .push(XWaylandEvent::Activate(window.data.clone())); - } - seat.focus_surface(&self); - } - - fn node_on_unfocus(&self, seat: &WlSeatGlobal) { - seat.unfocus_surface(self); - } - - fn node_on_leave(&self, seat: &WlSeatGlobal) { - seat.leave_surface(self); - } - - fn node_on_pointer_enter(self: Rc, seat: &Rc, x: Fixed, y: Fixed) { - seat.enter_surface(&self, x, y) - } - - fn node_on_pointer_motion(self: Rc, seat: &Rc, x: Fixed, y: Fixed) { - seat.motion_surface(&self, x, y) - } - - fn node_on_pointer_relative_motion( - &self, - seat: &Rc, - time_usec: u64, - dx: Fixed, - dy: Fixed, - dx_unaccelerated: Fixed, - dy_unaccelerated: Fixed, - ) { - seat.relative_motion_surface(self, time_usec, dx, dy, dx_unaccelerated, dy_unaccelerated); - } - - fn node_on_dnd_drop(&self, dnd: &Dnd) { - dnd.seat.dnd_surface_drop(self, dnd); - } - - fn node_on_dnd_leave(&self, dnd: &Dnd) { - dnd.seat.dnd_surface_leave(self, dnd); - } - - fn node_on_dnd_enter(&self, dnd: &Dnd, x: Fixed, y: Fixed, serial: u64) { - dnd.seat.dnd_surface_enter(self, dnd, x, y, serial); - } - - fn node_on_dnd_motion(&self, dnd: &Dnd, time_usec: u64, x: Fixed, y: Fixed) { - dnd.seat.dnd_surface_motion(self, dnd, time_usec, x, y); - } - - fn node_on_swipe_begin(&self, seat: &Rc, time_usec: u64, finger_count: u32) { - seat.swipe_begin_surface(self, time_usec, finger_count) - } - - fn node_on_swipe_update(&self, seat: &Rc, time_usec: u64, dx: Fixed, dy: Fixed) { - seat.swipe_update_surface(self, time_usec, dx, dy) - } - - fn node_on_swipe_end(&self, seat: &Rc, time_usec: u64, cancelled: bool) { - seat.swipe_end_surface(self, time_usec, cancelled) - } - - fn node_on_pinch_begin(&self, seat: &Rc, time_usec: u64, finger_count: u32) { - seat.pinch_begin_surface(self, time_usec, finger_count) - } - - fn node_on_pinch_update( - &self, - seat: &Rc, - time_usec: u64, - dx: Fixed, - dy: Fixed, - scale: Fixed, - rotation: Fixed, - ) { - seat.pinch_update_surface(self, time_usec, dx, dy, scale, rotation) - } - - fn node_on_pinch_end(&self, seat: &Rc, time_usec: u64, cancelled: bool) { - seat.pinch_end_surface(self, time_usec, cancelled) - } - - fn node_on_hold_begin(&self, seat: &Rc, time_usec: u64, finger_count: u32) { - seat.hold_begin_surface(self, time_usec, finger_count) - } - - fn node_on_hold_end(&self, seat: &Rc, time_usec: u64, cancelled: bool) { - seat.hold_end_surface(self, time_usec, cancelled) - } - - fn node_on_tablet_pad_enter(&self, pad: &Rc) { - pad.surface_enter(self); - } - - fn node_on_tablet_pad_leave(&self, pad: &Rc) { - pad.surface_leave(self); - } - - fn node_on_tablet_pad_button( - &self, - pad: &Rc, - time_usec: u64, - button: u32, - state: PadButtonState, - ) { - pad.surface_button(self, time_usec, button, state); - } - - fn node_on_tablet_pad_mode_switch( - &self, - pad: &Rc, - group: &Rc, - time_usec: u64, - mode: u32, - ) { - pad.surface_mode_switch(self, group, time_usec, mode); - } - - fn node_on_tablet_pad_ring( - &self, - pad: &Rc, - ring: &Rc, - source: Option, - angle: Option, - time_usec: u64, - ) { - pad.surface_ring(self, ring, source, angle, time_usec); - } - - fn node_on_tablet_pad_strip( - &self, - pad: &Rc, - strip: &Rc, - source: Option, - position: Option, - time_usec: u64, - ) { - pad.surface_strip(self, strip, source, position, time_usec); - } - - fn node_on_tablet_pad_dial( - &self, - pad: &Rc, - dial: &Rc, - value120: i32, - time_usec: u64, - ) { - pad.surface_dial(self, dial, value120, time_usec); - } - - fn node_on_tablet_tool_leave(&self, tool: &Rc, time_usec: u64) { - tool.surface_leave(self, time_usec); - } - - fn node_on_tablet_tool_enter( - self: Rc, - tool: &Rc, - time_usec: u64, - x: Fixed, - y: Fixed, - ) { - tool.surface_enter(&self, time_usec, x, y); - } - - fn node_on_tablet_tool_button( - &self, - tool: &Rc, - time_usec: u64, - button: u32, - state: ToolButtonState, - ) { - tool.surface_button(self, time_usec, button, state); - } - - fn node_on_tablet_tool_apply_changes( - self: Rc, - tool: &Rc, - time_usec: u64, - changes: Option<&TabletToolChanges>, - x: Fixed, - y: Fixed, - ) { - tool.surface_apply_changes(&self, time_usec, changes, x, y); - } - - fn node_into_surface(self: Rc) -> Option> { - Some(self.clone()) - } - - fn node_is_xwayland_surface(&self) -> bool { - self.client.is_xwayland - } -} #[derive(Debug, Error)] pub enum WlSurfaceError { @@ -2212,144 +1725,3 @@ efrom!(WlSurfaceError, ClientError); efrom!(WlSurfaceError, XdgSurfaceError); efrom!(WlSurfaceError, ZwlrLayerSurfaceV1Error); efrom!(WlSurfaceError, CommitTimelineError); - -impl VblankListener for WlSurface { - fn after_vblank(self: Rc) { - if self.visible.get() { - let now = self.client.state.now_msec() as u32; - for mut fr in self.frame_requests.borrow_mut().drain(..) { - fr.now = now; - drop(fr); - } - } - if self.clear_fifo_on_vblank.take() { - self.commit_timeline.clear_fifo_barrier(); - } - self.vblank_listener.detach(); - } -} - -impl BeforeLatchListener for WlSurface { - fn before_latch(self: Rc, present: u64) -> BeforeLatchResult { - self.commit_timeline.before_latch(&self, present) - } -} - -impl LatchListener for WlSurface { - fn after_latch(self: Rc, _on: &OutputNode, tearing: bool) { - if self.visible.get() { - if self.latched_commit_version.get() < self.commit_version.get() { - let latched = &mut *self.latched_presentation_feedback.borrow_mut(); - latched.clear(); - latched.append(&mut self.presentation_feedback.borrow_mut()); - if latched.is_not_empty() { - self.presentation_listener - .attach(&self.output.get().presentation_event); - } - self.latched_commit_version.set(self.commit_version.get()); - } - } - if tearing && self.visible.get() { - if self.commit_timeline.has_fifo_barrier() { - self.vblank_listener.attach(&self.output.get().vblank_event); - self.clear_fifo_on_vblank.set(true); - } - } else { - self.commit_timeline.clear_fifo_barrier(); - } - self.latch_listener.detach(); - } -} - -impl PresentationListener for WlSurface { - fn presented( - self: Rc, - output: &OutputNode, - tv_sec: u64, - tv_nsec: u32, - refresh: u32, - seq: u64, - flags: u32, - vrr: bool, - ) { - let bindings = output.global.bindings.borrow(); - let bindings = bindings.get(&self.client.id); - for pf in self.latched_presentation_feedback.borrow_mut().drain(..) { - pf.presented(bindings, tv_sec, tv_nsec, refresh, seq, flags, vrr); - } - self.presentation_listener.detach(); - } -} - -pub struct FrameRequest { - now: u32, - cb: Rc, -} - -impl Drop for FrameRequest { - fn drop(&mut self) { - self.cb.send_done(self.now); - let _ = self.cb.client.remove_obj(&*self.cb); - } -} - -pub struct SyncobjRelease { - state: Rc, - committed: bool, - syncobj: Option>, - point: SyncobjPoint, -} - -impl SyncobjRelease { - fn signal(&mut self, syncs: Option<&SmallVec<[(BufferResvUser, FdSync); 1]>>) { - if !self.committed { - return; - } - let Some(syncobj) = self.syncobj.take() else { - return; - }; - let Some(ctx) = self.state.render_ctx.get() else { - log::error!("Cannot signal release point because there is no render context"); - return; - }; - let Some(ctx) = ctx.syncobj_ctx() else { - log::error!("Cannot signal release point because there is no syncobj context"); - return; - }; - if let Some(syncs) = syncs - && syncs.is_not_empty() - { - let res = ctx.import_sync_files( - &syncobj, - self.point, - syncs.iter().flat_map(|f| f.1.get_sync_file()), - ); - match res { - Ok(_) => return, - Err(e) => { - log::error!("Could not import sync files into syncobj: {}", ErrorFmt(e)); - } - } - } - if let Err(e) = ctx.signal(&syncobj, self.point) { - log::error!("Could not signal release point: {}", ErrorFmt(e)); - } - } -} - -impl Drop for SyncobjRelease { - fn drop(&mut self) { - self.signal(None); - } -} - -pub struct SurfaceRelease { - cb: Rc, -} - -impl Drop for SurfaceRelease { - fn drop(&mut self) { - self.cb.send_done(0); - let _ = self.cb.client.remove_obj(&*self.cb); - } -} diff --git a/src/ifs/wl_surface/node.rs b/src/ifs/wl_surface/node.rs new file mode 100644 index 00000000..d2650d7e --- /dev/null +++ b/src/ifs/wl_surface/node.rs @@ -0,0 +1,336 @@ +use super::*; + +impl Node for WlSurface { + fn node_id(&self) -> NodeId { + self.node_id.into() + } + + fn node_seat_state(&self) -> &NodeSeatState { + &self.seat_state + } + + fn node_visit(self: Rc, visitor: &mut dyn NodeVisitor) { + visitor.visit_surface(&self); + } + + fn node_visit_children(&self, visitor: &mut dyn NodeVisitor) { + let children = self.children.borrow_mut(); + if let Some(c) = children.deref() { + for child in c.subsurfaces.values() { + visitor.visit_surface(&child.surface); + } + } + } + + fn node_visible(&self) -> bool { + self.visible.get() + } + + fn node_absolute_position(&self) -> Rect { + self.buffer_abs_pos.get() + } + + fn node_output(&self) -> Option> { + Some(self.output.get()) + } + + fn node_location(&self) -> Option { + Some(self.location.get()) + } + + fn node_layer(&self) -> NodeLayerLink { + self.ext.get().node_layer() + } + + fn node_active_changed(&self, active: bool) { + if let Some(tl) = self.toplevel.get() { + tl.tl_surface_active_changed(active); + } + } + + fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, bounds: Option<&Rect>) { + renderer.render_surface(self, x, y, bounds); + } + + fn node_client(&self) -> Option> { + Some(self.client.clone()) + } + + fn node_toplevel(self: Rc) -> Option> { + self.toplevel.get() + } + + fn node_tray_item(&self) -> Option { + self.ext.get().tray_item() + } + + fn node_make_visible(self: Rc) { + if let Some(tl) = self.toplevel.get() { + tl.node_make_visible(); + } + } + + fn node_on_key( + &self, + seat: &WlSeatGlobal, + time_usec: u64, + key: u32, + state: KeyState, + kb_state: &KeyboardState, + ) { + seat.key_surface(self, time_usec, key, state, kb_state); + } + + fn node_on_mods(&self, seat: &WlSeatGlobal, kb_state: &KeyboardState) { + seat.mods_surface(self, kb_state); + } + + fn node_on_touch_down( + self: Rc, + seat: &Rc, + time_usec: u64, + id: i32, + x: Fixed, + y: Fixed, + ) { + seat.touch_down_surface(&self, time_usec, id, x, y) + } + + fn node_on_touch_up(self: Rc, seat: &Rc, time_usec: u64, id: i32) { + seat.touch_up_surface(&self, time_usec, id) + } + + fn node_on_touch_motion( + self: Rc, + seat: &WlSeatGlobal, + time_usec: u64, + id: i32, + x: Fixed, + y: Fixed, + ) { + seat.touch_motion_surface(&self, time_usec, id, x, y) + } + + fn node_on_touch_frame(&self, seat: &WlSeatGlobal) { + seat.touch_frame_surface(&self) + } + + fn node_on_touch_cancel(&self, seat: &WlSeatGlobal) { + seat.touch_cancel_surface(&self) + } + + fn node_on_button( + self: Rc, + seat: &Rc, + time_usec: u64, + button: u32, + state: ButtonState, + serial: u64, + ) { + seat.button_surface(&self, time_usec, button, state, serial); + } + + fn node_on_axis_event(self: Rc, seat: &Rc, event: &PendingScroll) { + seat.scroll_surface(&self, event); + } + + fn node_on_focus(self: Rc, seat: &WlSeatGlobal) { + if let Some(xsurface) = self.ext.get().into_xsurface() + && let Some(window) = xsurface.xwindow.get() + { + self.client + .state + .xwayland + .queue + .push(XWaylandEvent::Activate(window.data.clone())); + } + seat.focus_surface(&self); + } + + fn node_on_unfocus(&self, seat: &WlSeatGlobal) { + seat.unfocus_surface(self); + } + + fn node_on_leave(&self, seat: &WlSeatGlobal) { + seat.leave_surface(self); + } + + fn node_on_pointer_enter(self: Rc, seat: &Rc, x: Fixed, y: Fixed) { + seat.enter_surface(&self, x, y) + } + + fn node_on_pointer_motion(self: Rc, seat: &Rc, x: Fixed, y: Fixed) { + seat.motion_surface(&self, x, y) + } + + fn node_on_pointer_relative_motion( + &self, + seat: &Rc, + time_usec: u64, + dx: Fixed, + dy: Fixed, + dx_unaccelerated: Fixed, + dy_unaccelerated: Fixed, + ) { + seat.relative_motion_surface(self, time_usec, dx, dy, dx_unaccelerated, dy_unaccelerated); + } + + fn node_on_dnd_drop(&self, dnd: &Dnd) { + dnd.seat.dnd_surface_drop(self, dnd); + } + + fn node_on_dnd_leave(&self, dnd: &Dnd) { + dnd.seat.dnd_surface_leave(self, dnd); + } + + fn node_on_dnd_enter(&self, dnd: &Dnd, x: Fixed, y: Fixed, serial: u64) { + dnd.seat.dnd_surface_enter(self, dnd, x, y, serial); + } + + fn node_on_dnd_motion(&self, dnd: &Dnd, time_usec: u64, x: Fixed, y: Fixed) { + dnd.seat.dnd_surface_motion(self, dnd, time_usec, x, y); + } + + fn node_on_swipe_begin(&self, seat: &Rc, time_usec: u64, finger_count: u32) { + seat.swipe_begin_surface(self, time_usec, finger_count) + } + + fn node_on_swipe_update(&self, seat: &Rc, time_usec: u64, dx: Fixed, dy: Fixed) { + seat.swipe_update_surface(self, time_usec, dx, dy) + } + + fn node_on_swipe_end(&self, seat: &Rc, time_usec: u64, cancelled: bool) { + seat.swipe_end_surface(self, time_usec, cancelled) + } + + fn node_on_pinch_begin(&self, seat: &Rc, time_usec: u64, finger_count: u32) { + seat.pinch_begin_surface(self, time_usec, finger_count) + } + + fn node_on_pinch_update( + &self, + seat: &Rc, + time_usec: u64, + dx: Fixed, + dy: Fixed, + scale: Fixed, + rotation: Fixed, + ) { + seat.pinch_update_surface(self, time_usec, dx, dy, scale, rotation) + } + + fn node_on_pinch_end(&self, seat: &Rc, time_usec: u64, cancelled: bool) { + seat.pinch_end_surface(self, time_usec, cancelled) + } + + fn node_on_hold_begin(&self, seat: &Rc, time_usec: u64, finger_count: u32) { + seat.hold_begin_surface(self, time_usec, finger_count) + } + + fn node_on_hold_end(&self, seat: &Rc, time_usec: u64, cancelled: bool) { + seat.hold_end_surface(self, time_usec, cancelled) + } + + fn node_on_tablet_pad_enter(&self, pad: &Rc) { + pad.surface_enter(self); + } + + fn node_on_tablet_pad_leave(&self, pad: &Rc) { + pad.surface_leave(self); + } + + fn node_on_tablet_pad_button( + &self, + pad: &Rc, + time_usec: u64, + button: u32, + state: PadButtonState, + ) { + pad.surface_button(self, time_usec, button, state); + } + + fn node_on_tablet_pad_mode_switch( + &self, + pad: &Rc, + group: &Rc, + time_usec: u64, + mode: u32, + ) { + pad.surface_mode_switch(self, group, time_usec, mode); + } + + fn node_on_tablet_pad_ring( + &self, + pad: &Rc, + ring: &Rc, + source: Option, + angle: Option, + time_usec: u64, + ) { + pad.surface_ring(self, ring, source, angle, time_usec); + } + + fn node_on_tablet_pad_strip( + &self, + pad: &Rc, + strip: &Rc, + source: Option, + position: Option, + time_usec: u64, + ) { + pad.surface_strip(self, strip, source, position, time_usec); + } + + fn node_on_tablet_pad_dial( + &self, + pad: &Rc, + dial: &Rc, + value120: i32, + time_usec: u64, + ) { + pad.surface_dial(self, dial, value120, time_usec); + } + + fn node_on_tablet_tool_leave(&self, tool: &Rc, time_usec: u64) { + tool.surface_leave(self, time_usec); + } + + fn node_on_tablet_tool_enter( + self: Rc, + tool: &Rc, + time_usec: u64, + x: Fixed, + y: Fixed, + ) { + tool.surface_enter(&self, time_usec, x, y); + } + + fn node_on_tablet_tool_button( + &self, + tool: &Rc, + time_usec: u64, + button: u32, + state: ToolButtonState, + ) { + tool.surface_button(self, time_usec, button, state); + } + + fn node_on_tablet_tool_apply_changes( + self: Rc, + tool: &Rc, + time_usec: u64, + changes: Option<&TabletToolChanges>, + x: Fixed, + y: Fixed, + ) { + tool.surface_apply_changes(&self, time_usec, changes, x, y); + } + + fn node_into_surface(self: Rc) -> Option> { + Some(self.clone()) + } + + fn node_is_xwayland_surface(&self) -> bool { + self.client.is_xwayland + } +} diff --git a/src/ifs/wl_surface/presentation.rs b/src/ifs/wl_surface/presentation.rs new file mode 100644 index 00000000..363356df --- /dev/null +++ b/src/ifs/wl_surface/presentation.rs @@ -0,0 +1,142 @@ +use super::*; + +impl VblankListener for WlSurface { + fn after_vblank(self: Rc) { + if self.visible.get() { + let now = self.client.state.now_msec() as u32; + for mut fr in self.frame_requests.borrow_mut().drain(..) { + fr.now = now; + drop(fr); + } + } + if self.clear_fifo_on_vblank.take() { + self.commit_timeline.clear_fifo_barrier(); + } + self.vblank_listener.detach(); + } +} + +impl BeforeLatchListener for WlSurface { + fn before_latch(self: Rc, present: u64) -> BeforeLatchResult { + self.commit_timeline.before_latch(&self, present) + } +} + +impl LatchListener for WlSurface { + fn after_latch(self: Rc, _on: &OutputNode, tearing: bool) { + if self.visible.get() { + if self.latched_commit_version.get() < self.commit_version.get() { + let latched = &mut *self.latched_presentation_feedback.borrow_mut(); + latched.clear(); + latched.append(&mut self.presentation_feedback.borrow_mut()); + if latched.is_not_empty() { + self.presentation_listener + .attach(&self.output.get().presentation_event); + } + self.latched_commit_version.set(self.commit_version.get()); + } + } + if tearing && self.visible.get() { + if self.commit_timeline.has_fifo_barrier() { + self.vblank_listener.attach(&self.output.get().vblank_event); + self.clear_fifo_on_vblank.set(true); + } + } else { + self.commit_timeline.clear_fifo_barrier(); + } + self.latch_listener.detach(); + } +} + +impl PresentationListener for WlSurface { + fn presented( + self: Rc, + output: &OutputNode, + tv_sec: u64, + tv_nsec: u32, + refresh: u32, + seq: u64, + flags: u32, + vrr: bool, + ) { + let bindings = output.global.bindings.borrow(); + let bindings = bindings.get(&self.client.id); + for pf in self.latched_presentation_feedback.borrow_mut().drain(..) { + pf.presented(bindings, tv_sec, tv_nsec, refresh, seq, flags, vrr); + } + self.presentation_listener.detach(); + } +} + +pub(super) struct FrameRequest { + pub(super) now: u32, + pub(super) cb: Rc, +} + +impl Drop for FrameRequest { + fn drop(&mut self) { + self.cb.send_done(self.now); + let _ = self.cb.client.remove_obj(&*self.cb); + } +} + +pub struct SyncobjRelease { + pub(super) state: Rc, + pub(super) committed: bool, + pub(super) syncobj: Option>, + pub(super) point: SyncobjPoint, +} + +impl SyncobjRelease { + pub(super) fn signal(&mut self, syncs: Option<&SmallVec<[(BufferResvUser, FdSync); 1]>>) { + if !self.committed { + return; + } + let Some(syncobj) = self.syncobj.take() else { + return; + }; + let Some(ctx) = self.state.render_ctx.get() else { + log::error!("Cannot signal release point because there is no render context"); + return; + }; + let Some(ctx) = ctx.syncobj_ctx() else { + log::error!("Cannot signal release point because there is no syncobj context"); + return; + }; + if let Some(syncs) = syncs + && syncs.is_not_empty() + { + let res = ctx.import_sync_files( + &syncobj, + self.point, + syncs.iter().flat_map(|f| f.1.get_sync_file()), + ); + match res { + Ok(_) => return, + Err(e) => { + log::error!("Could not import sync files into syncobj: {}", ErrorFmt(e)); + } + } + } + if let Err(e) = ctx.signal(&syncobj, self.point) { + log::error!("Could not signal release point: {}", ErrorFmt(e)); + } + } +} + +impl Drop for SyncobjRelease { + fn drop(&mut self) { + self.signal(None); + } +} + +pub(super) struct SurfaceRelease { + pub(super) cb: Rc, +} + +impl Drop for SurfaceRelease { + fn drop(&mut self) { + self.cb.send_done(0); + let _ = self.cb.client.remove_obj(&*self.cb); + } +} diff --git a/src/ifs/wl_surface/request.rs b/src/ifs/wl_surface/request.rs new file mode 100644 index 00000000..a6466147 --- /dev/null +++ b/src/ifs/wl_surface/request.rs @@ -0,0 +1,163 @@ +use super::*; + +impl WlSurfaceRequestHandler for WlSurface { + type Error = WlSurfaceError; + + fn destroy(&self, _req: Destroy, _slf: &Rc) -> Result<(), Self::Error> { + self.commit_timeline.clear(ClearReason::Destroy); + self.unset_dnd_icons(); + self.unset_cursors(); + self.ext.get().on_surface_destroy()?; + self.destroy_node(); + { + let mut children = self.children.borrow_mut(); + if let Some(children) = &mut *children { + for ss in children.subsurfaces.values() { + ss.surface.unset_ext(); + } + } + *children = None; + } + self.buffer.set(None); + self.reset_shm_textures(); + if let Some(xwayland_serial) = self.xwayland_serial.get() { + self.client + .surfaces_by_xwayland_serial + .remove(&xwayland_serial); + } + self.frame_requests.borrow_mut().clear(); + self.toplevel.set(None); + self.client.remove_obj(self)?; + self.idle_inhibitors.clear(); + self.constraints.take(); + self.destroyed.set(true); + Ok(()) + } + + fn attach(&self, req: Attach, _slf: &Rc) -> Result<(), Self::Error> { + let pending = &mut *self.pending.borrow_mut(); + if self.version >= OFFSET_SINCE { + if req.x != 0 || req.y != 0 { + return Err(WlSurfaceError::OffsetInAttach); + } + } else { + pending.offset = (req.x, req.y); + } + let buf = if req.buffer.is_some() { + Some(self.client.lookup(req.buffer)?) + } else { + None + }; + pending.buffer = Some(buf.map(|buf| AttachedBuffer { + send_release: false, + buf, + })); + Ok(()) + } + + fn damage(&self, req: Damage, _slf: &Rc) -> Result<(), Self::Error> { + self.do_damage(req.x, req.y, req.width, req.height, |p| { + &mut p.surface_damage + }) + } + + fn frame(&self, req: Frame, _slf: &Rc) -> Result<(), Self::Error> { + let cb = Rc::new(WlCallback::new(req.callback, &self.client)); + track!(self.client, cb); + self.client.add_client_obj(&cb)?; + self.pending + .borrow_mut() + .frame_request + .push(FrameRequest { now: 0, cb }); + Ok(()) + } + + fn set_opaque_region( + &self, + region: SetOpaqueRegion, + _slf: &Rc, + ) -> Result<(), Self::Error> { + let region = if region.region.is_some() { + Some(self.client.lookup(region.region)?.region()) + } else { + None + }; + self.pending.borrow_mut().opaque_region = Some(region); + Ok(()) + } + + fn set_input_region(&self, req: SetInputRegion, _slf: &Rc) -> Result<(), Self::Error> { + let region = if req.region.is_some() { + Some(self.client.lookup(req.region)?.region()) + } else { + None + }; + self.pending.borrow_mut().input_region = Some(region); + Ok(()) + } + + fn commit(&self, _req: Commit, slf: &Rc) -> Result<(), Self::Error> { + let ext = self.ext.get(); + let pending = &mut *self.pending.borrow_mut(); + if let Some(Some(buffer)) = &mut pending.buffer + && pending.release_point.is_none() + && pending.sync_file_release.is_none() + { + buffer.send_release = true; + } + if let Some(release) = &mut pending.release_point { + release.committed = true; + } + self.verify_syncobj_sync(pending)?; + if pending.surface_release.is_not_empty() && not_matches!(pending.buffer, Some(Some(_))) { + return Err(WlSurfaceError::SurfaceReleaseWithoutAttach); + } + if pending.sync_file_release.is_some() && not_matches!(pending.buffer, Some(Some(_))) { + return Err(WlSurfaceError::SyncFileReleaseWithoutAttach); + } + if ext.commit_requested(pending) == CommitAction::ContinueCommit { + self.commit_timeline.commit(slf, pending)?; + } + Ok(()) + } + + fn set_buffer_transform( + &self, + req: SetBufferTransform, + _slf: &Rc, + ) -> Result<(), Self::Error> { + let Some(tf) = Transform::from_wl(req.transform) else { + return Err(WlSurfaceError::UnknownBufferTransform(req.transform)); + }; + self.pending.borrow_mut().transform = Some(tf); + Ok(()) + } + + fn set_buffer_scale(&self, req: SetBufferScale, _slf: &Rc) -> Result<(), Self::Error> { + if req.scale < 1 { + return Err(WlSurfaceError::NonPositiveBufferScale); + } + self.pending.borrow_mut().scale = Some(req.scale); + Ok(()) + } + + fn damage_buffer(&self, req: DamageBuffer, _slf: &Rc) -> Result<(), Self::Error> { + self.do_damage(req.x, req.y, req.width, req.height, |p| { + &mut p.buffer_damage + }) + } + + fn offset(&self, req: Offset, _slf: &Rc) -> Result<(), Self::Error> { + self.pending.borrow_mut().offset = (req.x, req.y); + Ok(()) + } + + fn get_release(&self, req: GetRelease, _slf: &Rc) -> Result<(), Self::Error> { + let cb = Rc::new(WlCallback::new(req.callback, &self.client)); + track!(self.client, cb); + self.client.add_client_obj(&cb)?; + let release = SurfaceRelease { cb }; + self.pending.borrow_mut().surface_release.push(release); + Ok(()) + } +}