ltk/platform/wayland/
primary_selection.rsuse std::sync::mpsc;
use smithay_client_toolkit::data_device_manager::WritePipe;
use smithay_client_toolkit::primary_selection::PrimarySelectionManagerState;
use smithay_client_toolkit::primary_selection::device::{ PrimarySelectionDevice, PrimarySelectionDeviceData, PrimarySelectionDeviceHandler };
use smithay_client_toolkit::primary_selection::selection::{ PrimarySelectionSource, PrimarySelectionSourceHandler };
use smithay_client_toolkit::reexports::client::
{
protocol::wl_seat::WlSeat,
Connection, Proxy, QueueHandle,
};
use smithay_client_toolkit::reexports::protocols::wp::primary_selection::zv1::client::
{
zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1,
zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1,
};
use crate::app::App;
use crate::event_loop::AppData;
use super::WaylandPlatform;
use super::data_device::{ pick_text_mime, read_selection, write_selection, CLIPBOARD_MIMES };
pub( crate ) struct PrimarySelection
{
manager: Option<PrimarySelectionManagerState>,
device: Option<PrimarySelectionDevice>,
source: Option<PrimarySelectionSource>,
inbox_tx: mpsc::Sender<String>,
inbox_rx: mpsc::Receiver<String>,
reading: usize,
}
impl PrimarySelection
{
pub( crate ) fn new( manager: Option<PrimarySelectionManagerState> ) -> Self
{
let ( inbox_tx, inbox_rx ) = mpsc::channel();
Self { manager, device: None, source: None, inbox_tx, inbox_rx, reading: 0 }
}
pub( crate ) fn drain( &mut self ) -> Option<String>
{
let arrived: Vec<String> = self.inbox_rx.try_iter().collect();
self.reading = self.reading.saturating_sub( arrived.len() );
arrived.into_iter().last()
}
pub( crate ) fn pending( &self ) -> bool
{
self.reading > 0
}
}
pub( crate ) fn publish<A: App>( platform: &mut WaylandPlatform<A> )
{
let ( Some( manager ), Some( device ) ) = ( &platform.primary.manager, &platform.primary.device ) else { return };
let source = manager.create_selection_source( &platform.qh, CLIPBOARD_MIMES.iter().copied() );
source.set_selection( device, platform.last_input_serial );
platform.primary.source = Some( source );
}
impl<A: App> AppData<A>
{
pub( crate ) fn bind_primary_selection( &mut self, qh: &QueueHandle<Self>, seat: &WlSeat )
{
let primary = &mut self.platform.primary;
if primary.device.is_some() { return; }
let Some( manager ) = &primary.manager else { return };
primary.device = Some( manager.get_selection_device( qh, seat ) );
}
fn owns_primary( &self, source: &ZwpPrimarySelectionSourceV1 ) -> bool
{
self.platform.primary.source.as_ref().is_some_and( |own| own.inner() == source )
}
}
impl<A: App> PrimarySelectionDeviceHandler for AppData<A>
{
fn selection( &mut self, _conn: &Connection, _qh: &QueueHandle<Self>, device: &ZwpPrimarySelectionDeviceV1 )
{
let Some( offer ) = device.data::<PrimarySelectionDeviceData>().and_then( |data| data.selection_offer() ) else { return };
let Some( mime ) = offer.with_mime_types( pick_text_mime ) else { return };
let Ok( pipe ) = offer.receive( mime ) else { return };
read_selection( pipe, self.platform.primary.inbox_tx.clone() );
self.platform.primary.reading += 1;
}
}
impl<A: App> PrimarySelectionSourceHandler for AppData<A>
{
fn send_request( &mut self, _conn: &Connection, _qh: &QueueHandle<Self>, source: &ZwpPrimarySelectionSourceV1, _mime: String, pipe: WritePipe )
{
if self.owns_primary( source ) { write_selection( pipe, &self.primary_selection ); }
}
fn cancelled( &mut self, _conn: &Connection, _qh: &QueueHandle<Self>, source: &ZwpPrimarySelectionSourceV1 )
{
if self.owns_primary( source ) { self.platform.primary.source = None; }
}
}