|
| 1 | +use super::manager::ToplevelManagerState; |
| 2 | +use super::{Buffer, BufferRequest}; |
| 3 | +use crate::clients::wayland::ToplevelHandle; |
| 4 | +use crate::lock; |
| 5 | +use color_eyre::Result; |
| 6 | +use std::sync::{Arc, Mutex}; |
| 7 | +use tracing::{error, warn}; |
| 8 | +use wayland_client::{Connection, Dispatch, QueueHandle, WEnum}; |
| 9 | +use wayland_protocols_hyprland::toplevel_export::v1::client::hyprland_toplevel_export_frame_v1::{ |
| 10 | + Event, Flags, HyprlandToplevelExportFrameV1, |
| 11 | +}; |
| 12 | + |
| 13 | +pub trait ToplevelFrameDataExt: Send + Sync { |
| 14 | + fn buffer_request(&self) -> BufferRequest; |
| 15 | + fn set_buffer_request(&self, buffer: BufferRequest); |
| 16 | + |
| 17 | + fn handle(&self) -> Option<&ToplevelHandle>; |
| 18 | + |
| 19 | + fn copied_first_frame(&self) -> bool; |
| 20 | + fn set_copied_first_frame(&self); |
| 21 | +} |
| 22 | + |
| 23 | +impl ToplevelFrameDataExt for ToplevelFrameData { |
| 24 | + fn buffer_request(&self) -> BufferRequest { |
| 25 | + let inner = lock!(self.inner); |
| 26 | + inner.buffer_request |
| 27 | + } |
| 28 | + |
| 29 | + fn set_buffer_request(&self, request: BufferRequest) { |
| 30 | + lock!(self.inner).buffer_request = request; |
| 31 | + } |
| 32 | + |
| 33 | + fn handle(&self) -> Option<&ToplevelHandle> { |
| 34 | + self.handle.as_ref() |
| 35 | + } |
| 36 | + |
| 37 | + fn copied_first_frame(&self) -> bool { |
| 38 | + lock!(self.inner).copied_first_frame |
| 39 | + } |
| 40 | + |
| 41 | + fn set_copied_first_frame(&self) { |
| 42 | + lock!(self.inner).copied_first_frame = true; |
| 43 | + } |
| 44 | +} |
| 45 | + |
| 46 | +#[derive(Default, Debug)] |
| 47 | +pub struct ToplevelFrameData { |
| 48 | + pub handle: Option<ToplevelHandle>, |
| 49 | + pub inner: Arc<Mutex<ToplevelFrameDataInner>>, |
| 50 | +} |
| 51 | + |
| 52 | +impl ToplevelFrameData {} |
| 53 | + |
| 54 | +#[derive(Debug, Default)] |
| 55 | +pub struct ToplevelFrameDataInner { |
| 56 | + buffer_request: BufferRequest, |
| 57 | + copied_first_frame: bool, |
| 58 | +} |
| 59 | + |
| 60 | +pub trait ToplevelFrameHandler: Sized { |
| 61 | + /// Requests a new DMA-BUF is created for the provided parameters. |
| 62 | + fn dma_buffer(&mut self, request: BufferRequest, handle_id: usize) -> Result<Buffer>; |
| 63 | + |
| 64 | + /// Provides the buffer once ready. |
| 65 | + /// This includes the copied contents. |
| 66 | + fn buffer_ready(&mut self, handle: &ToplevelHandle); |
| 67 | +} |
| 68 | + |
| 69 | +impl<D, U> Dispatch<HyprlandToplevelExportFrameV1, U, D> for ToplevelManagerState |
| 70 | +where |
| 71 | + D: Dispatch<HyprlandToplevelExportFrameV1, U> + ToplevelFrameHandler, |
| 72 | + U: ToplevelFrameDataExt, |
| 73 | +{ |
| 74 | + fn event( |
| 75 | + state: &mut D, |
| 76 | + proxy: &HyprlandToplevelExportFrameV1, |
| 77 | + event: Event, |
| 78 | + data: &U, |
| 79 | + _conn: &Connection, |
| 80 | + _qhandle: &QueueHandle<D>, |
| 81 | + ) { |
| 82 | + match event { |
| 83 | + Event::LinuxDmabuf { |
| 84 | + format, |
| 85 | + width, |
| 86 | + height, |
| 87 | + } => { |
| 88 | + data.set_buffer_request(BufferRequest { format, width, height }) |
| 89 | + }, |
| 90 | + Event::BufferDone => { |
| 91 | + let Some(handle_id) = data.handle().and_then(|h| h.info()).map(|i| i.id) else { |
| 92 | + error!("Missing handle"); |
| 93 | + return; |
| 94 | + }; |
| 95 | + |
| 96 | + match state.dma_buffer(data.buffer_request(), handle_id) { |
| 97 | + Ok(buffer) => { |
| 98 | + proxy.copy(&buffer.wl_buffer, !data.copied_first_frame() as i32); |
| 99 | + }, |
| 100 | + Err(err) => { error!("failed to fetch buffer: {err:?}"); proxy.destroy() }, |
| 101 | + } |
| 102 | + } |
| 103 | + Event::Flags { flags } => match flags { |
| 104 | + WEnum::Value(flags) => { |
| 105 | + if flags.contains(Flags::YInvert) { |
| 106 | + error!("Received unhandled YInvert transform flag"); |
| 107 | + } |
| 108 | + } |
| 109 | + WEnum::Unknown(_) => { |
| 110 | + error!("Received unknown flags for toplevel frame"); |
| 111 | + } |
| 112 | + }, |
| 113 | + Event::Ready { .. } => { |
| 114 | + let handle = data.handle().unwrap(); |
| 115 | + state.buffer_ready(handle); |
| 116 | + data.set_copied_first_frame(); |
| 117 | + |
| 118 | + proxy.destroy(); |
| 119 | + } |
| 120 | + Event::Failed => { |
| 121 | + error!("Failed to capture frame"); |
| 122 | + proxy.destroy(); |
| 123 | + } |
| 124 | + Event::Buffer { .. /* shm ignored in favour of dmabuf */ } | Event::Damage { .. } => {} |
| 125 | + _ => warn!("Received unhandled toplevel frame event: {:?}", event), |
| 126 | + } |
| 127 | + } |
| 128 | +} |
0 commit comments