1pub mod multi;
2pub mod raw;
3pub mod slot;
4
5use std::io;
6
7use wayland_client::{
8 globals::{BindError, GlobalList},
9 protocol::wl_shm,
10 Connection, Dispatch, QueueHandle, WEnum,
11};
12
13use crate::{
14 error::GlobalError,
15 globals::{GlobalData, ProvidesBoundGlobal},
16};
17
18pub trait ShmHandler {
19 fn shm_state(&mut self) -> &mut Shm;
20}
21
22#[derive(Debug)]
23pub struct Shm {
24 wl_shm: wl_shm::WlShm,
25 formats: Vec<wl_shm::Format>,
26}
27
28impl From<wl_shm::WlShm> for Shm {
29 fn from(wl_shm: wl_shm::WlShm) -> Self {
30 Self { wl_shm, formats: Vec::new() }
31 }
32}
33
34impl Shm {
35 pub fn bind<State>(globals: &GlobalList, qh: &QueueHandle<State>) -> Result<Shm, BindError>
36 where
37 State: Dispatch<wl_shm::WlShm, GlobalData, State> + ShmHandler + 'static,
38 {
39 let wl_shm: ! = globals.bind(qh, version:1..=1, udata:GlobalData)?;
40 // Compositors must advertise Argb8888 and Xrgb8888, so let's reserve space for those formats.
41 Ok(Shm { wl_shm, formats: Vec::with_capacity(2) })
42 }
43
44 pub fn wl_shm(&self) -> &wl_shm::WlShm {
45 &self.wl_shm
46 }
47
48 /// Returns the formats supported in memory pools.
49 pub fn formats(&self) -> &[wl_shm::Format] {
50 &self.formats[..]
51 }
52}
53
54impl ProvidesBoundGlobal<wl_shm::WlShm, 1> for Shm {
55 fn bound_global(&self) -> Result<wl_shm::WlShm, GlobalError> {
56 Ok(self.wl_shm.clone())
57 }
58}
59
60/// An error that may occur when creating a pool.
61#[derive(Debug, thiserror::Error)]
62pub enum CreatePoolError {
63 /// The wl_shm global is not bound.
64 #[error(transparent)]
65 Global(#[from] GlobalError),
66
67 /// Error while allocating the shared memory.
68 #[error(transparent)]
69 Create(#[from] io::Error),
70}
71
72/// Delegates the handling of [`wl_shm`] to some [`Shm`].
73///
74/// This macro requires two things, the type that will delegate to [`Shm`] and a closure specifying how
75/// to obtain the state object.
76///
77/// ```
78/// use smithay_client_toolkit::shm::{ShmHandler, Shm};
79/// use smithay_client_toolkit::delegate_shm;
80///
81/// struct ExampleApp {
82/// /// The state object that will be our delegate.
83/// shm: Shm,
84/// }
85///
86/// // Use the macro to delegate wl_shm to Shm.
87/// delegate_shm!(ExampleApp);
88///
89/// // You must implement the ShmHandler trait to provide a way to access the Shm from your data type.
90/// impl ShmHandler for ExampleApp {
91/// fn shm_state(&mut self) -> &mut Shm {
92/// &mut self.shm
93/// }
94/// }
95#[macro_export]
96macro_rules! delegate_shm {
97 ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
98 $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty:
99 [
100 $crate::reexports::client::protocol::wl_shm::WlShm: $crate::globals::GlobalData
101 ] => $crate::shm::Shm
102 );
103 };
104}
105
106impl<D> Dispatch<wl_shm::WlShm, GlobalData, D> for Shm
107where
108 D: Dispatch<wl_shm::WlShm, GlobalData> + ShmHandler,
109{
110 fn event(
111 state: &mut D,
112 _proxy: &wl_shm::WlShm,
113 event: wl_shm::Event,
114 _: &GlobalData,
115 _: &Connection,
116 _: &QueueHandle<D>,
117 ) {
118 match event {
119 wl_shm::Event::Format { format } => {
120 match format {
121 WEnum::Value(format) => {
122 state.shm_state().formats.push(format);
123 log::debug!(target: "sctk", "supported wl_shm format {:?}", format);
124 }
125
126 // Ignore formats we don't know about.
127 WEnum::Unknown(raw) => {
128 log::debug!(target: "sctk", "Unknown supported wl_shm format {:x}", raw);
129 }
130 };
131 }
132
133 _ => unreachable!(),
134 }
135 }
136}
137