1 | use crate::{compositor::Surface, error::GlobalError, globals::GlobalData, registry::GlobalProxy}; |
2 | use std::sync::{ |
3 | atomic::{AtomicBool, Ordering}, |
4 | Arc, Weak, |
5 | }; |
6 | use wayland_client::{ |
7 | globals::GlobalList, |
8 | protocol::{wl_output, wl_surface}, |
9 | Connection, Dispatch, Proxy, QueueHandle, |
10 | }; |
11 | use wayland_protocols::ext::session_lock::v1::client::{ |
12 | ext_session_lock_manager_v1, ext_session_lock_surface_v1, ext_session_lock_v1, |
13 | }; |
14 | |
15 | mod dispatch; |
16 | |
17 | /// Handler trait for session lock protocol. |
18 | pub trait SessionLockHandler: Sized { |
19 | /// The session lock is active, and the client may create lock surfaces. |
20 | fn locked(&mut self, conn: &Connection, qh: &QueueHandle<Self>, session_lock: SessionLock); |
21 | |
22 | /// Session lock is not active and should be destroyed. |
23 | /// |
24 | /// This may be sent immediately if the compositor denys the requires to create a lock, |
25 | /// or may be sent some time after `lock`. |
26 | fn finished(&mut self, conn: &Connection, qh: &QueueHandle<Self>, session_lock: SessionLock); |
27 | |
28 | /// Compositor has requested size for surface. |
29 | fn configure( |
30 | &mut self, |
31 | conn: &Connection, |
32 | qh: &QueueHandle<Self>, |
33 | surface: SessionLockSurface, |
34 | configure: SessionLockSurfaceConfigure, |
35 | serial: u32, |
36 | ); |
37 | } |
38 | |
39 | #[non_exhaustive ] |
40 | #[derive (Debug, Clone)] |
41 | pub struct SessionLockSurfaceConfigure { |
42 | pub new_size: (u32, u32), |
43 | } |
44 | |
45 | #[derive (Debug)] |
46 | struct SessionLockSurfaceInner { |
47 | surface: Surface, |
48 | session_lock_surface: ext_session_lock_surface_v1::ExtSessionLockSurfaceV1, |
49 | } |
50 | |
51 | impl Drop for SessionLockSurfaceInner { |
52 | fn drop(&mut self) { |
53 | self.session_lock_surface.destroy(); |
54 | } |
55 | } |
56 | |
57 | #[must_use ] |
58 | #[derive (Debug, Clone)] |
59 | pub struct SessionLockSurface(Arc<SessionLockSurfaceInner>); |
60 | |
61 | impl SessionLockSurface { |
62 | pub fn from_ext_session_lock_surface( |
63 | surface: &ext_session_lock_surface_v1::ExtSessionLockSurfaceV1, |
64 | ) -> Option<Self> { |
65 | surface.data::<SessionLockSurfaceData>().and_then(|data: &SessionLockSurfaceData| data.inner.upgrade()).map(Self) |
66 | } |
67 | |
68 | pub fn wl_surface(&self) -> &wl_surface::WlSurface { |
69 | self.0.surface.wl_surface() |
70 | } |
71 | } |
72 | |
73 | #[derive (Debug)] |
74 | pub struct SessionLockSurfaceData { |
75 | inner: Weak<SessionLockSurfaceInner>, |
76 | } |
77 | |
78 | impl SessionLockSurfaceData { |
79 | pub fn session_lock_surface(&self) -> Option<SessionLockSurface> { |
80 | self.inner.upgrade().map(SessionLockSurface) |
81 | } |
82 | } |
83 | |
84 | #[derive (Debug)] |
85 | pub struct SessionLockInner { |
86 | session_lock: ext_session_lock_v1::ExtSessionLockV1, |
87 | locked: AtomicBool, |
88 | } |
89 | |
90 | impl Drop for SessionLockInner { |
91 | fn drop(&mut self) { |
92 | if self.locked.load(order:Ordering::SeqCst) { |
93 | self.session_lock.unlock_and_destroy(); |
94 | } else { |
95 | self.session_lock.destroy(); |
96 | } |
97 | } |
98 | } |
99 | |
100 | /// A session lock |
101 | /// |
102 | /// The lock is destroyed on drop, which must be done after `locked` or `finished` |
103 | /// is received. |
104 | #[must_use ] |
105 | #[derive (Debug, Clone)] |
106 | pub struct SessionLock(Arc<SessionLockInner>); |
107 | |
108 | impl SessionLock { |
109 | pub fn from_ext_session_lock(surface: &ext_session_lock_v1::ExtSessionLockV1) -> Option<Self> { |
110 | surface.data::<SessionLockData>().and_then(|data: &SessionLockData| data.inner.upgrade()).map(Self) |
111 | } |
112 | |
113 | pub fn is_locked(&self) -> bool { |
114 | self.0.locked.load(order:Ordering::SeqCst) |
115 | } |
116 | } |
117 | |
118 | #[derive (Debug)] |
119 | pub struct SessionLockData { |
120 | inner: Weak<SessionLockInner>, |
121 | } |
122 | |
123 | impl SessionLock { |
124 | pub fn create_lock_surface<D>( |
125 | &self, |
126 | surface: impl Into<Surface>, |
127 | output: &wl_output::WlOutput, |
128 | qh: &QueueHandle<D>, |
129 | ) -> SessionLockSurface |
130 | where |
131 | D: Dispatch<ext_session_lock_surface_v1::ExtSessionLockSurfaceV1, SessionLockSurfaceData> |
132 | + 'static, |
133 | { |
134 | // Freeze the queue during the creation of the Arc to avoid a race between events on the |
135 | // new objects being processed and the Weak in the SessionLockSurfaceData becoming usable. |
136 | let freeze = qh.freeze(); |
137 | let surface = surface.into(); |
138 | |
139 | let inner = Arc::new_cyclic(|weak| { |
140 | let session_lock_surface = self.0.session_lock.get_lock_surface( |
141 | surface.wl_surface(), |
142 | output, |
143 | qh, |
144 | SessionLockSurfaceData { inner: weak.clone() }, |
145 | ); |
146 | |
147 | SessionLockSurfaceInner { surface, session_lock_surface } |
148 | }); |
149 | drop(freeze); |
150 | |
151 | SessionLockSurface(inner) |
152 | } |
153 | } |
154 | |
155 | /// A handler for [`ext_session_lock_manager_v1::ExtSessionLockManagerV1`] |
156 | #[derive (Debug)] |
157 | pub struct SessionLockState { |
158 | session_lock_manager: GlobalProxy<ext_session_lock_manager_v1::ExtSessionLockManagerV1>, |
159 | } |
160 | |
161 | impl SessionLockState { |
162 | pub fn new<D>(globals: &GlobalList, qh: &QueueHandle<D>) -> Self |
163 | where |
164 | D: Dispatch<ext_session_lock_manager_v1::ExtSessionLockManagerV1, GlobalData> + 'static, |
165 | { |
166 | let session_lock_manager = GlobalProxy::from(globals.bind(qh, 1..=1, GlobalData)); |
167 | Self { session_lock_manager } |
168 | } |
169 | |
170 | pub fn lock<D>(&self, qh: &QueueHandle<D>) -> Result<SessionLock, GlobalError> |
171 | where |
172 | D: Dispatch<ext_session_lock_v1::ExtSessionLockV1, SessionLockData> + 'static, |
173 | { |
174 | let session_lock_manager = self.session_lock_manager.get()?; |
175 | |
176 | // Freeze the queue during the creation of the Arc to avoid a race between events on the |
177 | // new objects being processed and the Weak in the SessionLockData becoming usable. |
178 | let freeze = qh.freeze(); |
179 | |
180 | let inner = Arc::new_cyclic(|weak| { |
181 | let session_lock = |
182 | session_lock_manager.lock(qh, SessionLockData { inner: weak.clone() }); |
183 | |
184 | SessionLockInner { session_lock, locked: AtomicBool::new(false) } |
185 | }); |
186 | drop(freeze); |
187 | |
188 | Ok(SessionLock(inner)) |
189 | } |
190 | } |
191 | |
192 | #[macro_export ] |
193 | macro_rules! delegate_session_lock { |
194 | ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => { |
195 | $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: |
196 | [ |
197 | $crate::reexports::protocols::ext::session_lock::v1::client::ext_session_lock_manager_v1::ExtSessionLockManagerV1: $crate::globals::GlobalData |
198 | ] => $crate::session_lock::SessionLockState |
199 | ); |
200 | $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: |
201 | [ |
202 | $crate::reexports::protocols::ext::session_lock::v1::client::ext_session_lock_v1::ExtSessionLockV1: $crate::session_lock::SessionLockData |
203 | ] => $crate::session_lock::SessionLockState |
204 | ); |
205 | $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: |
206 | [ |
207 | $crate::reexports::protocols::ext::session_lock::v1::client::ext_session_lock_surface_v1::ExtSessionLockSurfaceV1: $crate::session_lock::SessionLockSurfaceData |
208 | ] => $crate::session_lock::SessionLockState |
209 | ); |
210 | }; |
211 | } |
212 | |