1
0
Fork 0
forked from wry/wry

wl-surface: split interface handlers

This commit is contained in:
kossLAN 2026-05-29 20:42:15 -04:00
parent d36ec3b7d3
commit 054a3a919f
No known key found for this signature in database
4 changed files with 649 additions and 636 deletions

View file

@ -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<Self>) -> 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<Self>) -> 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<Self>) -> 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<Self>) -> 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<Self>,
) -> 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<Self>) -> 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<Self>) -> 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<Self>,
) -> 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<Self>) -> 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<Self>) -> 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<Self>) -> Result<(), Self::Error> {
self.pending.borrow_mut().offset = (req.x, req.y);
Ok(())
}
fn get_release(&self, req: GetRelease, _slf: &Rc<Self>) -> 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<Self>, 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<Self>, 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<Rc<OutputNode>> {
Some(self.output.get())
}
fn node_location(&self) -> Option<NodeLocation> {
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<Rc<Client>> {
Some(self.client.clone())
}
fn node_toplevel(self: Rc<Self>) -> Option<Rc<dyn ToplevelNode>> {
self.toplevel.get()
}
fn node_tray_item(&self) -> Option<TrayItemId> {
self.ext.get().tray_item()
}
fn node_make_visible(self: Rc<Self>) {
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<Self>,
seat: &Rc<WlSeatGlobal>,
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<Self>, seat: &Rc<WlSeatGlobal>, time_usec: u64, id: i32) {
seat.touch_up_surface(&self, time_usec, id)
}
fn node_on_touch_motion(
self: Rc<Self>,
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<Self>,
seat: &Rc<WlSeatGlobal>,
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<Self>, seat: &Rc<WlSeatGlobal>, event: &PendingScroll) {
seat.scroll_surface(&self, event);
}
fn node_on_focus(self: Rc<Self>, 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<Self>, seat: &Rc<WlSeatGlobal>, x: Fixed, y: Fixed) {
seat.enter_surface(&self, x, y)
}
fn node_on_pointer_motion(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, x: Fixed, y: Fixed) {
seat.motion_surface(&self, x, y)
}
fn node_on_pointer_relative_motion(
&self,
seat: &Rc<WlSeatGlobal>,
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<WlSeatGlobal>, time_usec: u64, finger_count: u32) {
seat.swipe_begin_surface(self, time_usec, finger_count)
}
fn node_on_swipe_update(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, dx: Fixed, dy: Fixed) {
seat.swipe_update_surface(self, time_usec, dx, dy)
}
fn node_on_swipe_end(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, cancelled: bool) {
seat.swipe_end_surface(self, time_usec, cancelled)
}
fn node_on_pinch_begin(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, finger_count: u32) {
seat.pinch_begin_surface(self, time_usec, finger_count)
}
fn node_on_pinch_update(
&self,
seat: &Rc<WlSeatGlobal>,
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<WlSeatGlobal>, time_usec: u64, cancelled: bool) {
seat.pinch_end_surface(self, time_usec, cancelled)
}
fn node_on_hold_begin(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, finger_count: u32) {
seat.hold_begin_surface(self, time_usec, finger_count)
}
fn node_on_hold_end(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, cancelled: bool) {
seat.hold_end_surface(self, time_usec, cancelled)
}
fn node_on_tablet_pad_enter(&self, pad: &Rc<TabletPad>) {
pad.surface_enter(self);
}
fn node_on_tablet_pad_leave(&self, pad: &Rc<TabletPad>) {
pad.surface_leave(self);
}
fn node_on_tablet_pad_button(
&self,
pad: &Rc<TabletPad>,
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<TabletPad>,
group: &Rc<TabletPadGroup>,
time_usec: u64,
mode: u32,
) {
pad.surface_mode_switch(self, group, time_usec, mode);
}
fn node_on_tablet_pad_ring(
&self,
pad: &Rc<TabletPad>,
ring: &Rc<TabletPadRing>,
source: Option<TabletRingEventSource>,
angle: Option<f64>,
time_usec: u64,
) {
pad.surface_ring(self, ring, source, angle, time_usec);
}
fn node_on_tablet_pad_strip(
&self,
pad: &Rc<TabletPad>,
strip: &Rc<TabletPadStrip>,
source: Option<TabletStripEventSource>,
position: Option<f64>,
time_usec: u64,
) {
pad.surface_strip(self, strip, source, position, time_usec);
}
fn node_on_tablet_pad_dial(
&self,
pad: &Rc<TabletPad>,
dial: &Rc<TabletPadDial>,
value120: i32,
time_usec: u64,
) {
pad.surface_dial(self, dial, value120, time_usec);
}
fn node_on_tablet_tool_leave(&self, tool: &Rc<TabletTool>, time_usec: u64) {
tool.surface_leave(self, time_usec);
}
fn node_on_tablet_tool_enter(
self: Rc<Self>,
tool: &Rc<TabletTool>,
time_usec: u64,
x: Fixed,
y: Fixed,
) {
tool.surface_enter(&self, time_usec, x, y);
}
fn node_on_tablet_tool_button(
&self,
tool: &Rc<TabletTool>,
time_usec: u64,
button: u32,
state: ToolButtonState,
) {
tool.surface_button(self, time_usec, button, state);
}
fn node_on_tablet_tool_apply_changes(
self: Rc<Self>,
tool: &Rc<TabletTool>,
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<Self>) -> Option<Rc<WlSurface>> {
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<Self>) {
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<Self>, present: u64) -> BeforeLatchResult {
self.commit_timeline.before_latch(&self, present)
}
}
impl LatchListener for WlSurface {
fn after_latch(self: Rc<Self>, _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<Self>,
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<WlCallback>,
}
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<State>,
committed: bool,
syncobj: Option<Rc<Syncobj>>,
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<WlCallback>,
}
impl Drop for SurfaceRelease {
fn drop(&mut self) {
self.cb.send_done(0);
let _ = self.cb.client.remove_obj(&*self.cb);
}
}

336
src/ifs/wl_surface/node.rs Normal file
View file

@ -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<Self>, 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<Rc<OutputNode>> {
Some(self.output.get())
}
fn node_location(&self) -> Option<NodeLocation> {
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<Rc<Client>> {
Some(self.client.clone())
}
fn node_toplevel(self: Rc<Self>) -> Option<Rc<dyn ToplevelNode>> {
self.toplevel.get()
}
fn node_tray_item(&self) -> Option<TrayItemId> {
self.ext.get().tray_item()
}
fn node_make_visible(self: Rc<Self>) {
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<Self>,
seat: &Rc<WlSeatGlobal>,
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<Self>, seat: &Rc<WlSeatGlobal>, time_usec: u64, id: i32) {
seat.touch_up_surface(&self, time_usec, id)
}
fn node_on_touch_motion(
self: Rc<Self>,
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<Self>,
seat: &Rc<WlSeatGlobal>,
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<Self>, seat: &Rc<WlSeatGlobal>, event: &PendingScroll) {
seat.scroll_surface(&self, event);
}
fn node_on_focus(self: Rc<Self>, 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<Self>, seat: &Rc<WlSeatGlobal>, x: Fixed, y: Fixed) {
seat.enter_surface(&self, x, y)
}
fn node_on_pointer_motion(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, x: Fixed, y: Fixed) {
seat.motion_surface(&self, x, y)
}
fn node_on_pointer_relative_motion(
&self,
seat: &Rc<WlSeatGlobal>,
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<WlSeatGlobal>, time_usec: u64, finger_count: u32) {
seat.swipe_begin_surface(self, time_usec, finger_count)
}
fn node_on_swipe_update(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, dx: Fixed, dy: Fixed) {
seat.swipe_update_surface(self, time_usec, dx, dy)
}
fn node_on_swipe_end(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, cancelled: bool) {
seat.swipe_end_surface(self, time_usec, cancelled)
}
fn node_on_pinch_begin(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, finger_count: u32) {
seat.pinch_begin_surface(self, time_usec, finger_count)
}
fn node_on_pinch_update(
&self,
seat: &Rc<WlSeatGlobal>,
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<WlSeatGlobal>, time_usec: u64, cancelled: bool) {
seat.pinch_end_surface(self, time_usec, cancelled)
}
fn node_on_hold_begin(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, finger_count: u32) {
seat.hold_begin_surface(self, time_usec, finger_count)
}
fn node_on_hold_end(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, cancelled: bool) {
seat.hold_end_surface(self, time_usec, cancelled)
}
fn node_on_tablet_pad_enter(&self, pad: &Rc<TabletPad>) {
pad.surface_enter(self);
}
fn node_on_tablet_pad_leave(&self, pad: &Rc<TabletPad>) {
pad.surface_leave(self);
}
fn node_on_tablet_pad_button(
&self,
pad: &Rc<TabletPad>,
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<TabletPad>,
group: &Rc<TabletPadGroup>,
time_usec: u64,
mode: u32,
) {
pad.surface_mode_switch(self, group, time_usec, mode);
}
fn node_on_tablet_pad_ring(
&self,
pad: &Rc<TabletPad>,
ring: &Rc<TabletPadRing>,
source: Option<TabletRingEventSource>,
angle: Option<f64>,
time_usec: u64,
) {
pad.surface_ring(self, ring, source, angle, time_usec);
}
fn node_on_tablet_pad_strip(
&self,
pad: &Rc<TabletPad>,
strip: &Rc<TabletPadStrip>,
source: Option<TabletStripEventSource>,
position: Option<f64>,
time_usec: u64,
) {
pad.surface_strip(self, strip, source, position, time_usec);
}
fn node_on_tablet_pad_dial(
&self,
pad: &Rc<TabletPad>,
dial: &Rc<TabletPadDial>,
value120: i32,
time_usec: u64,
) {
pad.surface_dial(self, dial, value120, time_usec);
}
fn node_on_tablet_tool_leave(&self, tool: &Rc<TabletTool>, time_usec: u64) {
tool.surface_leave(self, time_usec);
}
fn node_on_tablet_tool_enter(
self: Rc<Self>,
tool: &Rc<TabletTool>,
time_usec: u64,
x: Fixed,
y: Fixed,
) {
tool.surface_enter(&self, time_usec, x, y);
}
fn node_on_tablet_tool_button(
&self,
tool: &Rc<TabletTool>,
time_usec: u64,
button: u32,
state: ToolButtonState,
) {
tool.surface_button(self, time_usec, button, state);
}
fn node_on_tablet_tool_apply_changes(
self: Rc<Self>,
tool: &Rc<TabletTool>,
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<Self>) -> Option<Rc<WlSurface>> {
Some(self.clone())
}
fn node_is_xwayland_surface(&self) -> bool {
self.client.is_xwayland
}
}

View file

@ -0,0 +1,142 @@
use super::*;
impl VblankListener for WlSurface {
fn after_vblank(self: Rc<Self>) {
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<Self>, present: u64) -> BeforeLatchResult {
self.commit_timeline.before_latch(&self, present)
}
}
impl LatchListener for WlSurface {
fn after_latch(self: Rc<Self>, _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<Self>,
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<WlCallback>,
}
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<State>,
pub(super) committed: bool,
pub(super) syncobj: Option<Rc<Syncobj>>,
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<WlCallback>,
}
impl Drop for SurfaceRelease {
fn drop(&mut self) {
self.cb.send_done(0);
let _ = self.cb.client.remove_obj(&*self.cb);
}
}

View file

@ -0,0 +1,163 @@
use super::*;
impl WlSurfaceRequestHandler for WlSurface {
type Error = WlSurfaceError;
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> 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<Self>) -> 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<Self>) -> 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<Self>) -> 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<Self>,
) -> 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<Self>) -> 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<Self>) -> 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<Self>,
) -> 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<Self>) -> 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<Self>) -> 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<Self>) -> Result<(), Self::Error> {
self.pending.borrow_mut().offset = (req.x, req.y);
Ok(())
}
fn get_release(&self, req: GetRelease, _slf: &Rc<Self>) -> 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(())
}
}