1use std::{sync::Mutex};
2use slotmap::{new_key_type, SlotMap};
3use tokio::{sync::{mpsc::{Sender, Receiver}, oneshot}, io::unix::AsyncFd};
4use wayland_client::{EventQueue, protocol::{wl_seat::{WlSeat, self}, wl_registry::{WlRegistry, self}, wl_output::{WlOutput, self}}, globals::{self, GlobalListContents}, Connection, QueueHandle, Dispatch, event_created_child, Proxy};
5use wayland_protocols_wlr::foreign_toplevel::v1::client::{zwlr_foreign_toplevel_manager_v1::{ZwlrForeignToplevelManagerV1, self}, zwlr_foreign_toplevel_handle_v1::{ZwlrForeignToplevelHandleV1, self}};
6
7use super::errors::{ToplevelHandlerError, ToplevelHandlerErrorCodes};
8
9new_key_type! { pub struct ToplevelKey; }
10
11#[derive(Debug)]
12pub enum ToplevelMessage {
13 GetToplevels { reply_to: oneshot::Sender<Vec<ToplevelKey>> },
14 GetToplevelMeta { key: ToplevelKey, reply_to: oneshot::Sender<Option<ToplevelMeta>> },
15 Activate { key: ToplevelKey, reply_to: oneshot::Sender<Result<bool, ToplevelHandlerError>> },
16 SetFullscreen { key: ToplevelKey, reply_to: oneshot::Sender<Result<bool, ToplevelHandlerError>> },
17 SetMaximize { key: ToplevelKey, reply_to: oneshot::Sender<Result<bool, ToplevelHandlerError>> },
18 SetMinimize { key: ToplevelKey, reply_to: oneshot::Sender<Result<bool, ToplevelHandlerError>> },
19 UnsetFullscreen { key: ToplevelKey, reply_to: oneshot::Sender<Result<bool, ToplevelHandlerError>> },
20 UnsetMaximize { key: ToplevelKey, reply_to: oneshot::Sender<Result<bool, ToplevelHandlerError>> },
21 UnsetMinimize { key: ToplevelKey, reply_to: oneshot::Sender<Result<bool, ToplevelHandlerError>> },
22 Close { key: ToplevelKey, reply_to: oneshot::Sender<Result<bool, ToplevelHandlerError>> },
23}
24
25#[derive(Debug, Clone, PartialEq)]
26pub enum ToplevelWState {
27 Maximized = 0,
28 Minimized = 1,
29 Activated = 2,
30 Fullscreen = 3
31}
32
33fn map_state_to_wstate(state: Vec<u8>) -> Vec<ToplevelWState> {
34 let mut wstate: Vec<ToplevelWState> = vec![];
35 let mut state_iter = state
36 .chunks_exact(4)
37 .map(|b| u32::from_ne_bytes(b.try_into().unwrap()));
38
39 let is_maximized = state_iter.clone().any(|s| s == zwlr_foreign_toplevel_handle_v1::State::Maximized as u32);
40 let is_minimized = state_iter.clone().any(|s| s == zwlr_foreign_toplevel_handle_v1::State::Minimized as u32);
41 let is_activated = state_iter.clone().any(|s| s == zwlr_foreign_toplevel_handle_v1::State::Activated as u32);
42 let is_fullscreen = state_iter.clone().any(|s| s == zwlr_foreign_toplevel_handle_v1::State::Fullscreen as u32);
43
44 if is_maximized {
45 wstate.push(ToplevelWState::Maximized);
46 }
47
48 if is_minimized {
49 wstate.push(ToplevelWState::Minimized);
50 }
51
52 if is_activated {
53 wstate.push(ToplevelWState::Activated);
54 }
55
56 if is_fullscreen {
57 wstate.push(ToplevelWState::Fullscreen);
58 }
59
60 println!("base state {:?} {:?} {:?}", state, wstate, is_activated);
61
62 wstate
63}
64
65#[derive(Debug)]
66pub enum ToplevelEvent {
67 Created { key: ToplevelKey },
68 Title { key: ToplevelKey, title: String },
69 AppId { key: ToplevelKey, app_id: String },
70 Done { key: ToplevelKey, title: String, app_id: String, state: Option<Vec<ToplevelWState>> },
71 State { key: ToplevelKey, state: Vec<ToplevelWState> },
72 Closed { key: ToplevelKey },
73 OutputEnter { key: ToplevelKey, output: WlOutput },
74 OutputLeave { key: ToplevelKey, output: WlOutput },
75 Parent { key: ToplevelKey, parent: Option<ZwlrForeignToplevelHandleV1> },
76}
77
78#[derive(Debug, Clone)]
79pub struct Toplevel {
80 pub title: String,
81 pub app_id: String,
82 pub state: Option<Vec<ToplevelWState>>,
83 _handle: ZwlrForeignToplevelHandleV1,
84}
85
86#[derive(Debug, Clone)]
87pub struct ToplevelMeta {
88 app_id: String,
89 title: String,
90 state: Option<Vec<ToplevelWState>>,
91}
92
93impl Toplevel {
94 fn new(handle: ZwlrForeignToplevelHandleV1) -> Self {
95 Toplevel {
96 title: "".to_string(),
97 app_id: "".to_string(), state: None,
99 _handle: handle,
100 }
101 }
102}
103
104
105pub struct ToplevelState {
106 event_tx: Sender<ToplevelEvent>,
107 seat: Option<WlSeat>,
108 output: Option<WlOutput>,
109 toplevels: SlotMap<ToplevelKey, Toplevel>,
110}
111
112pub struct ToplevelHandler {
113 event_queue: EventQueue<ToplevelState>,
114 state: ToplevelState,
115}
116
117impl ToplevelHandler {
118 pub fn new(event_tx: Sender<ToplevelEvent>) -> Self {
119 let conn = wayland_client::Connection::connect_to_env()
120 .map_err(|_| "could not connect to wayland socket, try setting WAYLAND_DISPLAY.")
121 .unwrap();
122 let (globals, mut event_queue) = globals::registry_queue_init::<ToplevelState>(&conn).unwrap();
123 let qh = event_queue.handle();
124
125 let _toplevel_manager = globals
126 .bind::<ZwlrForeignToplevelManagerV1, _, _>(&qh, core::ops::RangeInclusive::new(3, 3), ())
127 .map_err(|_| "compositor does not implement foreign toplevel manager (v3).").unwrap();
128
129 let seat = globals
130 .bind::<WlSeat, _, _>(&qh, core::ops::RangeInclusive::new(1, 1), ())
131 .map_err(|_| "failed to retrieve the seat from global.")
132 .unwrap();
133 let output = globals
134 .bind::<WlOutput, _, _>(&qh, core::ops::RangeInclusive::new(1, 1), ())
135 .map_err(|_| "failed to retrieve the output from global.")
136 .unwrap();
137
138 let mut state = ToplevelState {
139 event_tx,
140 seat: Some(seat),
141 output: Some(output),
142 toplevels: SlotMap::with_key(),
143 };
144
145 event_queue.roundtrip(&mut state).unwrap();
146
147 ToplevelHandler {
148 event_queue,
149 state,
150 }
151 }
152
153 pub async fn run(&mut self, mut msg_rx: Receiver<ToplevelMessage>) {
154 let event_queue = &mut self.event_queue;
155 let mut toplevel_state = &mut self.state;
156
157 loop {
158 event_queue.dispatch_pending(&mut toplevel_state).unwrap();
160 let read_guard = event_queue.prepare_read().unwrap();
161 let fd = read_guard.connection_fd();
162 let async_fd = AsyncFd::new(fd).unwrap();
163
164 tokio::select! {
165 async_guard = async_fd.readable() => {
166 async_guard.unwrap().clear_ready();
167 std::mem::drop(async_fd);
170 let event = read_guard.read();
172 match event {
173 Ok(0) => {},
175 Ok(_) => {
177 event_queue.dispatch_pending(&mut toplevel_state).unwrap();
178 },
179 Err(_) => {}
181 }
183 },
184 msg = msg_rx.recv() => {
185 if msg.is_none() {
186 continue;
187 }
188 match msg.unwrap() {
189 ToplevelMessage::GetToplevels { reply_to } => {
190 let _ = reply_to.send(toplevel_state.toplevels.keys().collect());
191 },
192 ToplevelMessage::GetToplevelMeta { key, reply_to } => {
193 let toplevel_meta = match toplevel_state.toplevels.get(key) {
194 Some(t) => Some(ToplevelMeta {
195 app_id: t.app_id.clone(),
196 title: t.title.clone(),
197 state: t.state.clone(),
198 }),
199 None => None,
200 };
201 let _ = reply_to.send(toplevel_meta);
202 },
203 ToplevelMessage::Activate { key, reply_to } => {
204 let toplevel = toplevel_state.toplevels.get_mut(key);
205 let result = match toplevel {
206 Some(t) => {
207 if toplevel_state.seat.is_some() {
208 let seat = toplevel_state.seat.as_ref().unwrap();
209 t._handle.activate(&seat);
210 }
211 Ok(true)
212 },
213 None => {
214 Err(ToplevelHandlerError::new(
215 ToplevelHandlerErrorCodes::ToplevelNotFound,
216 format!("toplevel not found")
217 ))
218 },
219 };
220 let _ = reply_to.send(result);
221 },
222 ToplevelMessage::SetFullscreen { key, reply_to } => {
223 let toplevel = toplevel_state.toplevels.get_mut(key);
224 let output = toplevel_state.output.clone();
225 let result = match toplevel {
226 Some(t) => {
227 t._handle.set_fullscreen(output.as_ref());
228 Ok(true)
229 },
230 None => {
231 Err(ToplevelHandlerError::new(
232 ToplevelHandlerErrorCodes::ToplevelNotFound,
233 format!("toplevel not found")
234 ))
235 },
236 };
237 let _ = reply_to.send(result);
238 },
239 ToplevelMessage::SetMaximize { key, reply_to } => {
240 let toplevel = toplevel_state.toplevels.get_mut(key);
241 let result = match toplevel {
242 Some(t) => {
243 t._handle.set_maximized();
244 Ok(true)
245 },
246 None => {
247 Err(ToplevelHandlerError::new(
248 ToplevelHandlerErrorCodes::ToplevelNotFound,
249 format!("toplevel not found")
250 ))
251 },
252 };
253 let _ = reply_to.send(result);
254 },
255 ToplevelMessage::SetMinimize { key, reply_to } => {
256 let toplevel = toplevel_state.toplevels.get_mut(key);
257 let result = match toplevel {
258 Some(t) => {
259 t._handle.set_minimized();
260 Ok(true)
261 },
262 None => {
263 Err(ToplevelHandlerError::new(
264 ToplevelHandlerErrorCodes::ToplevelNotFound,
265 format!("toplevel not found")
266 ))
267 },
268 };
269 let _ = reply_to.send(result);
270 },
271 ToplevelMessage::UnsetFullscreen { key, reply_to } => {
272 let toplevel = toplevel_state.toplevels.get_mut(key);
273 let result = match toplevel {
274 Some(t) => {
275 t._handle.unset_fullscreen();
276 Ok(true)
277 },
278 None => {
279 Err(ToplevelHandlerError::new(
280 ToplevelHandlerErrorCodes::ToplevelNotFound,
281 format!("toplevel not found")
282 ))
283 },
284 };
285 let _ = reply_to.send(result);
286 },
287 ToplevelMessage::UnsetMaximize { key, reply_to } => {
288 let toplevel = toplevel_state.toplevels.get_mut(key);
289 let result = match toplevel {
290 Some(t) => {
291 t._handle.unset_maximized();
292 Ok(true)
293 },
294 None => {
295 Err(ToplevelHandlerError::new(
296 ToplevelHandlerErrorCodes::ToplevelNotFound,
297 format!("toplevel not found")
298 ))
299 },
300 };
301 let _ = reply_to.send(result);
302 },
303 ToplevelMessage::UnsetMinimize { key, reply_to } => {
304 let toplevel = toplevel_state.toplevels.get_mut(key);
305 let result = match toplevel {
306 Some(t) => {
307 t._handle.unset_minimized();
308 Ok(true)
309 },
310 None => {
311 Err(ToplevelHandlerError::new(
312 ToplevelHandlerErrorCodes::ToplevelNotFound,
313 format!("toplevel not found")
314 ))
315 },
316 };
317 let _ = reply_to.send(result);
318 },
319 ToplevelMessage::Close { key, reply_to } => {
320 let toplevel = toplevel_state.toplevels.get_mut(key);
321 let result = match toplevel {
322 Some(t) => {
323 t._handle.close();
324 Ok(true)
325 },
326 None => {
327 Err(ToplevelHandlerError::new(
328 ToplevelHandlerErrorCodes::ToplevelNotFound,
329 format!("toplevel not found")
330 ))
331 },
332 };
333 let _ = reply_to.send(result);
334 },
335 }
336 }
337 }
338
339 let _ = event_queue.flush().expect("wayland connection closed");
341 }
342 }
343}
344
345impl ToplevelState {
346 fn dispatch_event(&self, event: ToplevelEvent) {
347 let tx = self.event_tx.clone();
348 tokio::task::spawn(async move {
349 let _ = tx.send(event).await;
350 });
351 }
352}
353
354impl Dispatch<WlRegistry, GlobalListContents> for ToplevelState {
355 fn event(
356 _: &mut Self,
357 registry: &wl_registry::WlRegistry,
358 event: wl_registry::Event,
359 _: &GlobalListContents,
360 _: &Connection,
361 qh: &QueueHandle<ToplevelState>,
362 ) {
363 if let wl_registry::Event::Global {
364 name,
365 interface,
366 version,
367 } = event
368 {
369 if interface == "wl_seat" {
370 registry.bind::<WlSeat, (), ToplevelState>(name, version, qh, ());
371 }
372 }
373 }
374}
375
376impl Dispatch<WlSeat, ()> for ToplevelState {
377 fn event(
378 state: &mut Self,
379 seat: &WlSeat,
380 event: wl_seat::Event,
381 _: &(),
382 _: &Connection,
383 _: &QueueHandle<ToplevelState>,
384 ) {
385 if let wl_seat::Event::Name { .. } = event {
386 state.seat = Some(seat.to_owned());
387 }
388 }
389}
390
391impl Dispatch<WlOutput, ()> for ToplevelState {
392 fn event(
393 state: &mut Self,
394 output: &WlOutput,
395 event: wl_output::Event,
396 _: &(),
397 _: &Connection,
398 _: &QueueHandle<ToplevelState>,
399 ) {
400 if let wl_output::Event::Name { .. } = event {
401 state.output = Some(output.to_owned());
402 }
403 }
404}
405
406
407impl Dispatch<ZwlrForeignToplevelManagerV1, ()> for ToplevelState {
408 fn event(
409 state: &mut Self,
410 _: &ZwlrForeignToplevelManagerV1,
411 event: <ZwlrForeignToplevelManagerV1 as wayland_client::Proxy>::Event,
412 _: &(),
413 _: &Connection,
414 _: &QueueHandle<Self>,
415 ) {
416 match event {
417 zwlr_foreign_toplevel_manager_v1::Event::Toplevel { toplevel } => {
418 let toplevel_data = Toplevel::new(toplevel.clone());
419
420 let toplevel_key = state.toplevels.insert(toplevel_data);
422
423 let user_data: &Mutex<Option<ToplevelKey>> = toplevel.data().unwrap();
425 *user_data.lock().unwrap() = Some(toplevel_key);
426
427 state.dispatch_event(ToplevelEvent::Created { key: toplevel_key });
431 },
432 zwlr_foreign_toplevel_manager_v1::Event::Finished => {
433 }
435 _ => (),
436 }
437 }
438
439 event_created_child!(Self, ZwlrForeignToplevelHandleV1, [
440 zwlr_foreign_toplevel_manager_v1::EVT_TOPLEVEL_OPCODE => (ZwlrForeignToplevelHandleV1, Mutex::new(None))
441 ]);
442}
443
444impl Dispatch<ZwlrForeignToplevelHandleV1, Mutex<Option<ToplevelKey>>> for ToplevelState {
445 fn event(
446 state: &mut Self,
447 _: &ZwlrForeignToplevelHandleV1,
448 event: <ZwlrForeignToplevelHandleV1 as Proxy>::Event,
449 key: &Mutex<Option<ToplevelKey>>,
450 _: &Connection,
451 _: &QueueHandle<Self>,
452 ) {
453 match event {
454 zwlr_foreign_toplevel_handle_v1::Event::Title { title } => {
455 let toplevel_key = key.lock().unwrap().unwrap();
456
457 let toplevel = state
458 .toplevels
459 .get_mut(toplevel_key)
460 .unwrap();
461 toplevel.title = title.clone();
462
463 state.dispatch_event(ToplevelEvent::Title { key: toplevel_key, title });
464 },
465 zwlr_foreign_toplevel_handle_v1::Event::AppId { app_id } => {
466 let toplevel_key = key.lock().unwrap().unwrap();
467 let toplevel = state
468 .toplevels
469 .get_mut(toplevel_key)
470 .unwrap();
471 toplevel.app_id = app_id.clone();
472
473 state.dispatch_event(ToplevelEvent::AppId { key: toplevel_key, app_id });
474 },
475 zwlr_foreign_toplevel_handle_v1::Event::State { state: toplevel_state } => {
476 let toplevel_key = key.lock().unwrap().unwrap();
477 let toplevel = state
478 .toplevels
479 .get_mut(toplevel_key)
480 .unwrap();
481 let toplevel_state = map_state_to_wstate(toplevel_state);
482 toplevel.state = Some(toplevel_state.clone());
483
484 state.dispatch_event(ToplevelEvent::State { key: toplevel_key, state: toplevel_state.clone() });
485 },
486 zwlr_foreign_toplevel_handle_v1::Event::Done => {
487 let toplevel_key = key.lock().unwrap().unwrap();
488 let toplevel = state
489 .toplevels
490 .get_mut(toplevel_key)
491 .unwrap();
492 let title = toplevel.title.clone();
493 let app_id = toplevel.app_id.clone();
494 let toplevel_state = toplevel.state.clone();
495
496 state.dispatch_event(ToplevelEvent::Done { key: toplevel_key, title, app_id, state: toplevel_state });
497 },
498 zwlr_foreign_toplevel_handle_v1::Event::Closed => {
499 let toplevel_key = key.lock().unwrap().unwrap();
500 let toplevel = state
501 .toplevels
502 .get_mut(toplevel_key)
503 .unwrap();
504
505 state.toplevels.remove(toplevel_key);
507
508 state.dispatch_event(ToplevelEvent::Closed { key: toplevel_key });
509 },
510 zwlr_foreign_toplevel_handle_v1::Event::OutputEnter { output } => {
511 let toplevel_key = key.lock().unwrap().unwrap();
512 state.dispatch_event(ToplevelEvent::OutputEnter { key: toplevel_key, output });
513 },
514 zwlr_foreign_toplevel_handle_v1::Event::OutputLeave { output } => {
515 let toplevel_key = key.lock().unwrap().unwrap();
516 state.dispatch_event(ToplevelEvent::OutputLeave { key: toplevel_key, output });
517 },
518 zwlr_foreign_toplevel_handle_v1::Event::Parent { parent } => {
519 let toplevel_key = key.lock().unwrap().unwrap();
520 state.dispatch_event(ToplevelEvent::Parent { key: toplevel_key, parent });
521 },
522 _ => todo!(),
523 }
524 }
525}