1use crate::state::State;
2use serde::{Deserialize, Serialize};
3
4use super::Handle;
5
6#[derive(Serialize, Deserialize, Debug, Clone)]
7pub struct Viewport {
8 pub id: usize,
9 pub output: String,
10 pub tag: String,
11 pub h: u32,
12 pub w: u32,
13 pub x: i32,
14 pub y: i32,
15 pub layout: String,
16}
17
18#[derive(Serialize, Deserialize, Debug, Clone)]
19pub struct ManagerState {
20 pub window_title: Option<String>,
21 pub desktop_names: Vec<String>,
22 pub viewports: Vec<Viewport>,
23 pub active_desktop: Vec<String>,
24 pub working_tags: Vec<String>,
25 pub urgent_tags: Vec<String>,
26}
27
28#[allow(clippy::struct_excessive_bools)]
29#[derive(Serialize, Deserialize, Debug, Clone)]
30pub struct TagsForWorkspace {
31 pub name: String,
32 pub index: usize,
33 pub mine: bool,
34 pub visible: bool,
35 pub focused: bool,
36 pub urgent: bool,
37 pub busy: bool,
38}
39#[derive(Serialize, Deserialize, Debug, Clone)]
40pub struct DisplayWorkspace {
41 pub id: usize,
42 pub output: String,
43 pub h: u32,
44 pub w: u32,
45 pub x: i32,
46 pub y: i32,
47 pub layout: String,
48 pub index: usize,
49 pub tags: Vec<TagsForWorkspace>,
50}
51#[derive(Serialize, Deserialize, Debug, Clone)]
52pub struct DisplayState {
53 pub window_title: String,
54 pub workspaces: Vec<DisplayWorkspace>,
55}
56
57impl From<ManagerState> for DisplayState {
58 fn from(m: ManagerState) -> Self {
59 let visible: Vec<String> = m.viewports.iter().map(|vp| vp.tag.clone()).collect();
60 let workspaces = m
61 .viewports
62 .iter()
63 .enumerate()
64 .map(|(i, vp)| {
65 viewport_into_display_workspace(
66 &m.desktop_names,
67 &m.active_desktop,
68 &visible,
69 &m.working_tags,
70 &m.urgent_tags,
71 vp,
72 i,
73 )
74 })
75 .collect();
76 Self {
77 workspaces,
78 window_title: m.window_title.unwrap_or_default(),
79 }
80 }
81}
82
83fn viewport_into_display_workspace(
84 all_tags: &[String],
85 focused: &[String],
86 visible: &[String],
87 working_tags: &[String],
88 urgent_tags: &[String],
89 viewport: &Viewport,
90 ws_index: usize,
91) -> DisplayWorkspace {
92 let tags: Vec<TagsForWorkspace> = all_tags
93 .iter()
94 .enumerate()
95 .map(|(index, t)| TagsForWorkspace {
96 name: t.clone(),
97 index,
98 mine: viewport.tag == *t,
99 visible: visible.contains(t),
100 focused: focused.contains(t),
101 urgent: urgent_tags.contains(t),
102 busy: working_tags.contains(t),
103 })
104 .collect();
105 DisplayWorkspace {
106 id: viewport.id,
107 output: viewport.output.clone(),
108 tags,
109 h: viewport.h,
110 w: viewport.w,
111 x: viewport.x,
112 y: viewport.y,
113 index: ws_index,
114 layout: viewport.layout.clone(),
115 }
116}
117
118impl<H: Handle> From<&State<H>> for ManagerState {
119 fn from(state: &State<H>) -> Self {
120 let mut viewports: Vec<Viewport> = vec![];
121 let working_tags = state
123 .tags
124 .all()
125 .iter()
126 .filter(|tag| {
127 state
128 .windows
129 .iter()
130 .any(|w| w.has_tag(&tag.id) && w.is_managed())
131 })
132 .map(|t| t.label.clone())
133 .collect();
134 let urgent_tags = state
135 .tags
136 .all()
137 .iter()
138 .filter(|tag| state.windows.iter().any(|w| w.has_tag(&tag.id) && w.urgent))
139 .map(|t| t.label.clone())
140 .collect();
141 for ws in &state.workspaces {
142 let tag_label = ws
143 .tag
144 .map(|tag_id| state.tags.get(tag_id).map(|tag| tag.label.clone()))
145 .unwrap()
146 .unwrap();
147
148 let layout_name: String = ws
149 .tag
150 .and_then(|tagid| state.layout_manager.layout_maybe(ws.id, tagid))
151 .map_or_else(|| String::from("N/A"), |layout| layout.name.clone());
152
153 let output = state
154 .screens
155 .iter()
156 .find(|s| s.id == Some(ws.id))
157 .map_or_else(
158 || String::from("Not found (unreachable)"),
159 |s| s.output.clone(),
160 );
161
162 viewports.push(Viewport {
163 id: ws.id,
164 output,
165 tag: tag_label,
166 x: ws.xyhw.x(),
167 y: ws.xyhw.y(),
168 h: ws.xyhw.h() as u32,
169 w: ws.xyhw.w() as u32,
170 layout: layout_name,
171 });
172 }
173 let active_desktop = match state.focus_manager.workspace(&state.workspaces) {
174 Some(ws) => ws
175 .tag
176 .iter()
177 .map(|&tag_id| state.tags.get(tag_id).unwrap().label.clone())
178 .collect(),
179 None => vec![], };
181 let window_title = match state.focus_manager.window(&state.windows) {
182 Some(win) => win.name.clone(),
183 None => None,
184 };
185 Self {
186 window_title,
187 desktop_names: state
188 .tags
189 .normal()
190 .iter()
191 .map(|t| t.label.clone())
192 .collect(),
193 viewports,
194 active_desktop,
195 urgent_tags,
196 working_tags,
197 }
198 }
199}