smithay_client_toolkit/session_lock/
mod.rs1use crate::{compositor::Surface, error::GlobalError, globals::GlobalData, registry::GlobalProxy};
2use std::sync::{
3 atomic::{AtomicBool, Ordering},
4 Arc, Weak,
5};
6use wayland_client::{
7 globals::GlobalList,
8 protocol::{wl_output, wl_surface},
9 Connection, Dispatch, Proxy, QueueHandle,
10};
11use wayland_protocols::ext::session_lock::v1::client::{
12 ext_session_lock_manager_v1, ext_session_lock_surface_v1, ext_session_lock_v1,
13};
14
15mod dispatch;
16
17pub trait SessionLockHandler: Sized {
19 fn locked(&mut self, conn: &Connection, qh: &QueueHandle<Self>, session_lock: SessionLock);
21
22 fn finished(&mut self, conn: &Connection, qh: &QueueHandle<Self>, session_lock: SessionLock);
27
28 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)]
41pub struct SessionLockSurfaceConfigure {
42 pub new_size: (u32, u32),
43}
44
45#[derive(Debug)]
46struct SessionLockSurfaceInner {
47 surface: Surface,
48 session_lock_surface: ext_session_lock_surface_v1::ExtSessionLockSurfaceV1,
49}
50
51impl Drop for SessionLockSurfaceInner {
52 fn drop(&mut self) {
53 self.session_lock_surface.destroy();
54 }
55}
56
57#[must_use]
58#[derive(Debug, Clone)]
59pub struct SessionLockSurface(Arc<SessionLockSurfaceInner>);
60
61impl 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| 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)]
74pub struct SessionLockSurfaceData {
75 inner: Weak<SessionLockSurfaceInner>,
76}
77
78impl SessionLockSurfaceData {
79 pub fn session_lock_surface(&self) -> Option<SessionLockSurface> {
80 self.inner.upgrade().map(SessionLockSurface)
81 }
82}
83
84#[derive(Debug)]
85pub struct SessionLockInner {
86 session_lock: ext_session_lock_v1::ExtSessionLockV1,
87 locked: AtomicBool,
88}
89
90impl Drop for SessionLockInner {
91 fn drop(&mut self) {
92 self.session_lock.destroy();
96 }
97}
98
99#[derive(Debug, Clone)]
105pub struct SessionLock(Arc<SessionLockInner>);
106
107impl SessionLock {
108 pub fn from_ext_session_lock(surface: &ext_session_lock_v1::ExtSessionLockV1) -> Option<Self> {
109 surface.data::<SessionLockData>().and_then(|data| data.inner.upgrade()).map(Self)
110 }
111
112 pub fn is_locked(&self) -> bool {
113 self.0.locked.load(Ordering::SeqCst)
114 }
115
116 pub fn unlock(&self) {
117 if self.0.locked.load(Ordering::SeqCst) {
118 self.0.session_lock.unlock_and_destroy();
119 }
120 }
121}
122
123#[derive(Debug)]
124pub struct SessionLockData {
125 inner: Weak<SessionLockInner>,
126}
127
128impl SessionLock {
129 pub fn create_lock_surface<D>(
130 &self,
131 surface: impl Into<Surface>,
132 output: &wl_output::WlOutput,
133 qh: &QueueHandle<D>,
134 ) -> SessionLockSurface
135 where
136 D: Dispatch<ext_session_lock_surface_v1::ExtSessionLockSurfaceV1, SessionLockSurfaceData>
137 + 'static,
138 {
139 let freeze = qh.freeze();
142 let surface = surface.into();
143
144 let inner = Arc::new_cyclic(|weak| {
145 let session_lock_surface = self.0.session_lock.get_lock_surface(
146 surface.wl_surface(),
147 output,
148 qh,
149 SessionLockSurfaceData { inner: weak.clone() },
150 );
151
152 SessionLockSurfaceInner { surface, session_lock_surface }
153 });
154 drop(freeze);
155
156 SessionLockSurface(inner)
157 }
158}
159
160#[derive(Debug)]
162pub struct SessionLockState {
163 session_lock_manager: GlobalProxy<ext_session_lock_manager_v1::ExtSessionLockManagerV1>,
164}
165
166impl SessionLockState {
167 pub fn new<D>(globals: &GlobalList, qh: &QueueHandle<D>) -> Self
168 where
169 D: Dispatch<ext_session_lock_manager_v1::ExtSessionLockManagerV1, GlobalData> + 'static,
170 {
171 let session_lock_manager = GlobalProxy::from(globals.bind(qh, 1..=1, GlobalData));
172 Self { session_lock_manager }
173 }
174
175 pub fn lock<D>(&self, qh: &QueueHandle<D>) -> Result<SessionLock, GlobalError>
176 where
177 D: Dispatch<ext_session_lock_v1::ExtSessionLockV1, SessionLockData> + 'static,
178 {
179 let session_lock_manager = self.session_lock_manager.get()?;
180
181 let freeze = qh.freeze();
184
185 let inner = Arc::new_cyclic(|weak| {
186 let session_lock =
187 session_lock_manager.lock(qh, SessionLockData { inner: weak.clone() });
188
189 SessionLockInner { session_lock, locked: AtomicBool::new(false) }
190 });
191 drop(freeze);
192
193 Ok(SessionLock(inner))
194 }
195}
196
197#[macro_export]
198macro_rules! delegate_session_lock {
199 ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
200 $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty:
201 [
202 $crate::reexports::protocols::ext::session_lock::v1::client::ext_session_lock_manager_v1::ExtSessionLockManagerV1: $crate::globals::GlobalData
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_v1::ExtSessionLockV1: $crate::session_lock::SessionLockData
208 ] => $crate::session_lock::SessionLockState
209 );
210 $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty:
211 [
212 $crate::reexports::protocols::ext::session_lock::v1::client::ext_session_lock_surface_v1::ExtSessionLockSurfaceV1: $crate::session_lock::SessionLockSurfaceData
213 ] => $crate::session_lock::SessionLockState
214 );
215 };
216}