smithay_client_toolkit/
foreign_toplevel_list.rs1use crate::{dispatch2::Dispatch2, globals::GlobalData, registry::GlobalProxy};
2use std::sync::{Arc, Mutex};
3use wayland_client::{globals::GlobalList, Connection, Dispatch, Proxy, QueueHandle};
4use wayland_protocols::ext::foreign_toplevel_list::v1::client::{
5 ext_foreign_toplevel_handle_v1, ext_foreign_toplevel_list_v1,
6};
7
8#[derive(Clone, Debug, Default)]
10#[non_exhaustive]
11pub struct ForeignToplevelInfo {
12 pub title: String,
14 pub app_id: String,
16 pub identifier: String,
18}
19
20#[derive(Debug, Default)]
21struct ForeignToplevelInner {
22 current_info: Option<ForeignToplevelInfo>,
23 pending_info: ForeignToplevelInfo,
24}
25
26#[doc(hidden)]
27#[derive(Debug, Default, Clone)]
28pub struct ForeignToplevelData(Arc<Mutex<ForeignToplevelInner>>);
29
30#[derive(Debug)]
31pub struct ForeignToplevelList {
32 foreign_toplevel_list: GlobalProxy<ext_foreign_toplevel_list_v1::ExtForeignToplevelListV1>,
33 toplevels: Vec<ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1>,
34}
35
36impl ForeignToplevelList {
37 pub fn new<D>(globals: &GlobalList, qh: &QueueHandle<D>) -> Self
38 where
39 D: Dispatch<ext_foreign_toplevel_list_v1::ExtForeignToplevelListV1, GlobalData> + 'static,
40 {
41 let foreign_toplevel_list = GlobalProxy::from(globals.bind(qh, 1..=1, GlobalData));
42 Self { foreign_toplevel_list, toplevels: Vec::new() }
43 }
44
45 pub fn toplevels(&self) -> &[ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1] {
47 &self.toplevels
48 }
49
50 pub fn info(
55 &self,
56 toplevel: &ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
57 ) -> Option<ForeignToplevelInfo> {
58 toplevel.data::<ForeignToplevelData>()?.0.lock().unwrap().current_info.clone()
59 }
60
61 pub fn stop(&self) {
62 if let Ok(toplevel_list) = self.foreign_toplevel_list.get() {
63 toplevel_list.stop();
64 }
65 }
66}
67
68pub trait ForeignToplevelListHandler: Sized {
70 fn foreign_toplevel_list_state(&mut self) -> &mut ForeignToplevelList;
71
72 fn new_toplevel(
74 &mut self,
75 conn: &Connection,
76 qh: &QueueHandle<Self>,
77 toplevel_handle: ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
78 );
79
80 fn update_toplevel(
82 &mut self,
83 conn: &Connection,
84 qh: &QueueHandle<Self>,
85 toplevel_handle: ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
86 );
87
88 fn toplevel_closed(
90 &mut self,
91 conn: &Connection,
92 qh: &QueueHandle<Self>,
93 toplevel_handle: ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
94 );
95
96 fn finished(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>) {}
97}
98
99impl<D> Dispatch2<ext_foreign_toplevel_list_v1::ExtForeignToplevelListV1, D> for GlobalData
100where
101 D: Dispatch<ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1, ForeignToplevelData>
102 + ForeignToplevelListHandler
103 + 'static,
104{
105 fn event(
106 &self,
107 state: &mut D,
108 proxy: &ext_foreign_toplevel_list_v1::ExtForeignToplevelListV1,
109 event: ext_foreign_toplevel_list_v1::Event,
110 conn: &Connection,
111 qh: &QueueHandle<D>,
112 ) {
113 match event {
114 ext_foreign_toplevel_list_v1::Event::Toplevel { toplevel: _ } => {}
115 ext_foreign_toplevel_list_v1::Event::Finished => {
116 state.finished(conn, qh);
117 proxy.destroy();
118 }
119 _ => unreachable!(),
120 }
121 }
122
123 wayland_client::event_created_child!(D, ext_foreign_toplevel_list_v1::ExtForeignToplevelListV1, [
124 ext_foreign_toplevel_list_v1::EVT_TOPLEVEL_OPCODE => (ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1, Default::default())
125 ]);
126}
127
128impl<D> Dispatch2<ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1, D>
129 for ForeignToplevelData
130where
131 D: ForeignToplevelListHandler,
132{
133 fn event(
134 &self,
135 state: &mut D,
136 handle: &ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
137 event: ext_foreign_toplevel_handle_v1::Event,
138 conn: &Connection,
139 qh: &QueueHandle<D>,
140 ) {
141 match event {
142 ext_foreign_toplevel_handle_v1::Event::Closed => {
143 state.toplevel_closed(conn, qh, handle.clone());
144 let toplevels = &mut state.foreign_toplevel_list_state().toplevels;
145 if let Some(idx) = toplevels.iter().position(|x| x == handle) {
146 toplevels.remove(idx);
147 }
148 handle.destroy();
149 }
150 ext_foreign_toplevel_handle_v1::Event::Done => {
151 let mut inner = self.0.lock().unwrap();
152 let just_created = inner.current_info.is_none();
153 inner.current_info = Some(inner.pending_info.clone());
154 drop(inner);
155 if just_created {
156 state.foreign_toplevel_list_state().toplevels.push(handle.clone());
157 state.new_toplevel(conn, qh, handle.clone());
158 } else {
159 state.update_toplevel(conn, qh, handle.clone());
160 }
161 }
162 ext_foreign_toplevel_handle_v1::Event::Title { title } => {
163 self.0.lock().unwrap().pending_info.title = title;
164 }
165 ext_foreign_toplevel_handle_v1::Event::AppId { app_id } => {
166 self.0.lock().unwrap().pending_info.app_id = app_id;
167 }
168 ext_foreign_toplevel_handle_v1::Event::Identifier { identifier } => {
169 self.0.lock().unwrap().pending_info.identifier = identifier;
170 }
171 _ => unreachable!(),
172 }
173 }
174}