1use std::fmt::Display;
2
3use crate::themes::ThemeInfo;
4use crate::messages::{ WindowMessageResponse, WindowManagerRequest, KeyPress, WindowMessage, Direction, ShortcutType, InfoType };
5use crate::window_manager_types::{ KeyChar, DrawInstructions, WindowLikeType };
6use crate::framebuffer_types::Dimensions;
7use crate::utils::get_rest_of_split;
8
9fn array_to_string<T: Display>(array: &[T]) -> String {
18 let mut output = String::new();
19 for item in array {
20 output += &format!("{}{}", if output == String::new() {
21 ""
22 } else {
23 "\x1F"
24 }, item);
25 }
26 output
27}
28
29fn option_to_string<T: Display>(option: &Option<T>) -> String {
30 if let Some(value) = option {
31 format!("S{}", value)
32 } else {
33 "N".to_string()
34 }
35}
36
37fn get_color(serialized: &str) -> Result<[u8; 3], ()> {
38 let rgb = serialized.split("\x1F");
39 let mut color = [0; 3];
40 let mut c_i = 0;
41 for c in rgb {
44 if c_i == 3 {
45 return Err(());
46 }
47 if let Ok(c) = c.parse() {
48 color[c_i] = c;
49 } else {
50 return Err(());
51 }
52 c_i += 1;
53 }
54 Ok(color)
55}
56
57fn get_two_array(serialized: &str) -> Result<[usize; 2], ()> {
58 let mut arg = serialized.split("\x1F");
59 let mut a = [0; 2];
60 for i in 0..2 {
61 if let Some(n) = arg.next() {
62 if let Ok(n) = n.parse() {
63 a[i] = n;
64 continue
65 }
66 }
67 return Err(());
68 }
69 return Ok(a);
70}
71
72pub trait Serializable {
73 fn serialize(&self) -> String;
74 fn deserialize(serialized: &str) -> Result<Self, ()> where Self: Sized;
75}
76
77impl Serializable for ThemeInfo {
80 fn serialize(&self) -> String {
81 format!("{}:{}:{}:{}:{}:{}:{}:{}:{}", array_to_string(&self.top), array_to_string(&self.background), array_to_string(&self.border_left_top), array_to_string(&self.border_right_bottom), array_to_string(&self.text), array_to_string(&self.top_text), array_to_string(&self.alt_background), array_to_string(&self.alt_text), array_to_string(&self.alt_secondary))
82 }
83 fn deserialize(serialized: &str) -> Result<Self, ()> {
84 let serialized = if serialized.ends_with("\n") { &serialized[..serialized.len() - 1] } else { serialized };
86 let mut theme_info: ThemeInfo = Default::default();
87 let arrays = serialized.split(":");
88 let mut a_i = 0;
89 for a in arrays {
91 if a_i == 9 {
92 return Err(());
93 }
94 let color = get_color(a)?;
95 match a_i {
96 0 => {
97 theme_info.top = color;
98 },
99 1 => {
100 theme_info.background = color;
101 },
102 2 => {
103 theme_info.border_left_top = color;
104 },
105 3 => {
106 theme_info.border_right_bottom = color;
107 },
108 4 => {
109 theme_info.text = color;
110 },
111 5 => {
112 theme_info.top_text = color;
113 },
114 6 => {
115 theme_info.alt_background = color;
116 },
117 7 => {
118 theme_info.alt_text = color;
119 },
120 8 => {
121 theme_info.alt_secondary = color;
122 },
123 _ => {},
124 };
125 if a_i == 8 {
126 return Ok(theme_info);
127 }
128 a_i += 1;
129 }
130 Err(())
131 }
132}
133
134#[test]
135fn theme_info_serialize_deserialize() {
136 use crate::themes::{ Themes, get_theme_info };
137 let theme_info = get_theme_info(&Default::default()).unwrap();
138 let serialized = theme_info.serialize();
139 assert!(serialized == ThemeInfo::deserialize(&serialized).unwrap().serialize());
140}
141
142impl Serializable for WindowMessageResponse {
143 fn serialize(&self) -> String {
144 match self {
145 WindowMessageResponse::JustRedraw => "JustRedraw".to_string(),
146 WindowMessageResponse::DoNothing => "DoNothing".to_string(),
147 WindowMessageResponse::Request(req) => {
148 let req = match req {
149 WindowManagerRequest::OpenWindow(name) => format!("OpenWindow/{}", name),
150 WindowManagerRequest::ClipboardCopy(name) => format!("ClipboardCopy/{}", name),
151 WindowManagerRequest::CloseStartMenu => "CloseStartMenu".to_string(),
152 WindowManagerRequest::Unlock => "Unlock".to_string(),
153 WindowManagerRequest::Lock => "Lock".to_string(),
154 WindowManagerRequest::DoKeyChar(kc) => format!("DoKeyChar/{}", match kc {
155 KeyChar::Press(c) => format!("Press/{}", c),
156 KeyChar::Alt(c) => format!("Alt/{}", c),
157 KeyChar::Ctrl(c) => format!("Ctrl/{}", c),
158 }),
159 };
160 format!("Request/{}", req)
161 },
162 }
163 }
164 fn deserialize(serialized: &str) -> Result<Self, ()> {
165 let serialized = if serialized.ends_with("\n") { &serialized[..serialized.len() - 1] } else { serialized };
167 let mut parts = serialized.split("/");
168 match parts.next().unwrap_or("Invalid") {
169 "JustRedraw" => Ok(WindowMessageResponse::JustRedraw),
170 "DoNothing" => Ok(WindowMessageResponse::DoNothing),
171 "Request" => {
172 let req = match parts.next().unwrap_or("Invalid") {
173 "OpenWindow" => Some(WindowManagerRequest::OpenWindow(get_rest_of_split(&mut parts, Some("/")))),
175 "ClipboardCopy" => Some(WindowManagerRequest::ClipboardCopy(get_rest_of_split(&mut parts, Some("/")))),
176 "CloseStartMenu" => Some(WindowManagerRequest::CloseStartMenu),
177 "Unlock" => Some(WindowManagerRequest::Unlock),
178 "Lock" => Some(WindowManagerRequest::Lock),
179 "DoKeyChar" => Some(WindowManagerRequest::DoKeyChar(
180 match parts.next().unwrap_or("Invalid") {
181 "Press" => KeyChar::Press(parts.next().unwrap_or("?").chars().next().unwrap()),
182 "Alt" => KeyChar::Alt(parts.next().unwrap_or("?").chars().next().unwrap()),
183 "Ctrl" => KeyChar::Ctrl(parts.next().unwrap_or("?").chars().next().unwrap()),
184 _ => KeyChar::Press('?'), }
186 )),
187 _ => None, };
189 if let Some(req) = req {
190 Ok(WindowMessageResponse::Request(req))
191 } else {
192 Err(())
193 }
194 },
195 _ => Err(()),
196 }
197 }
198}
199
200#[test]
201fn window_message_response_serialize_deserialize() {
202 let resp = WindowMessageResponse::JustRedraw;
203 let serialized = resp.serialize();
204 assert!(resp == WindowMessageResponse::deserialize(&serialized).unwrap());
205 let resp = WindowMessageResponse::Request(WindowManagerRequest::OpenWindow("a".to_string()));
206 let serialized = resp.serialize();
207 assert!(resp == WindowMessageResponse::deserialize(&serialized).unwrap());
208 let resp = WindowMessageResponse::Request(WindowManagerRequest::Unlock);
209 let serialized = resp.serialize();
210 assert!(resp == WindowMessageResponse::deserialize(&serialized).unwrap());
211 let resp = WindowMessageResponse::Request(WindowManagerRequest::DoKeyChar(KeyChar::Alt('e')));
212 let serialized = resp.serialize();
213 assert!(resp == WindowMessageResponse::deserialize(&serialized).unwrap());
214}
215
216impl Serializable for DrawInstructions {
217 fn serialize(&self) -> String {
218 match self {
219 DrawInstructions::Rect(p, d, c) => format!("Rect/{}\x1E{}\x1E{}", array_to_string(p), array_to_string(d), array_to_string(c)),
221 DrawInstructions::Text(p, vs, s, c1, c2, ou1, ou2) => format!("Text/{}\x1E{}\x1E{}\x1E{}\x1E{}\x1E{}\x1E{}", array_to_string(p), array_to_string(&vs), s, array_to_string(c1), array_to_string(c2), option_to_string(ou1), option_to_string(ou2)),
222 DrawInstructions::Gradient(p, d, c1, c2, u) => format!("Gradient/{}\x1E{}\x1E{}\x1E{}\x1E{}", array_to_string(p), array_to_string(d), array_to_string(c1), array_to_string(c2), u),
223 DrawInstructions::Bmp(p, s, b) => format!("Bmp/{}\x1E{}\x1E{}", array_to_string(p), s, b),
224 DrawInstructions::Circle(p, u, c) => format!("Circle/{}\x1E{}\x1E{}", array_to_string(p), u, array_to_string(c)),
225 }
226 }
227 fn deserialize(serialized: &str) -> Result<Self, ()> {
228 let mut parts = serialized.split("/");
230 match parts.next().unwrap_or("Invalid") {
231 "Rect" => {
232 let rest = get_rest_of_split(&mut parts, Some("/"));
233 let mut args = rest.split("\x1E");
234 let arg = args.next();
235 if arg.is_none() {
236 return Err(());
237 }
238 let p = get_two_array(arg.unwrap())?;
239 let arg = args.next();
240 if arg.is_none() {
241 return Err(());
242 }
243 let d = get_two_array(arg.unwrap())?;
244 let arg = args.next();
245 if arg.is_none() {
246 return Err(());
247 }
248 let c = get_color(arg.unwrap())?;
249 Ok(DrawInstructions::Rect(p, d, c))
250 },
251 "Text" => {
252 let rest = get_rest_of_split(&mut parts, Some("/"));
253 let mut args = rest.split("\x1E");
255 let arg = args.next();
256 if arg.is_none() {
257 return Err(());
258 }
259 let p = get_two_array(arg.unwrap())?;
260 let arg = args.next();
261 if arg.is_none() {
262 return Err(());
263 }
264 let mut vs = Vec::new();
265 for s in arg.unwrap().split("\x1F") {
266 vs.push(s.to_string());
267 }
268 let arg = args.next();
269 if arg.is_none() {
270 return Err(());
271 }
272 let s = arg.unwrap();
273 let arg = args.next();
274 if arg.is_none() {
275 return Err(());
276 }
277 let c1 = get_color(arg.unwrap())?;
278 let arg = args.next();
279 if arg.is_none() {
280 return Err(());
281 }
282 let c2 = get_color(arg.unwrap())?;
283 let arg = args.next();
284 if arg.is_none() {
285 return Err(());
286 }
287 let arg = arg.unwrap();
288 let o1 = match arg {
289 "N" => None,
290 _ => {
291 if arg.len() > 1 {
292 if let Ok(n) = arg[1..].parse() {
293 Some(n)
294 } else {
295 None
296 }
297 } else {
298 None
299 }
300 },
301 };
302 let arg = args.next();
303 if arg.is_none() {
304 return Err(());
305 }
306 let arg = arg.unwrap();
307 let o2 = match arg {
308 "N" => None,
309 _ => {
310 if arg.len() > 1 {
311 if let Ok(n) = arg[1..].parse() {
312 Some(n)
313 } else {
314 None
315 }
316 } else {
317 None
318 }
319 },
320 };
321 Ok(DrawInstructions::Text(p, vs, s.to_string(), c1, c2, o1, o2))
322 },
323 "Gradient" => {
324 let rest = get_rest_of_split(&mut parts, Some("/"));
325 let mut args = rest.split("\x1E");
327 let arg = args.next();
328 if arg.is_none() {
329 return Err(());
330 }
331 let p = get_two_array(arg.unwrap())?;
332 let arg = args.next();
333 if arg.is_none() {
334 return Err(());
335 }
336 let d = get_two_array(arg.unwrap())?;
337 let arg = args.next();
338 if arg.is_none() {
339 return Err(());
340 }
341 let c1 = get_color(arg.unwrap())?;
342 let arg = args.next();
343 if arg.is_none() {
344 return Err(());
345 }
346 let c2 = get_color(arg.unwrap())?;
347 let arg = args.next();
348 if arg.is_none() {
349 return Err(());
350 }
351 let u = arg.unwrap().parse();
352 if u.is_err() {
353 return Err(());
354 }
355 Ok(DrawInstructions::Gradient(p, d, c1, c2, u.unwrap()))
356 },
357 "Bmp" => {
358 let rest = get_rest_of_split(&mut parts, Some("/"));
359 let mut args = rest.split("\x1E");
361 let arg = args.next();
362 if arg.is_none() {
363 return Err(());
364 }
365 let p = get_two_array(arg.unwrap())?;
366 let arg = args.next();
367 if arg.is_none() {
368 return Err(());
369 }
370 let s = arg.unwrap();
371 let arg = args.next();
372 if arg.is_none() {
373 return Err(());
374 }
375 let arg = arg.unwrap();
376 if arg != "true" && arg != "false" {
377 return Err(());
378 }
379 let b = arg == "true";
380 Ok(DrawInstructions::Bmp(p, s.to_string(), b))
381 },
382 "Circle" => {
383 let rest = get_rest_of_split(&mut parts, Some("/"));
384 let mut args = rest.split("\x1E");
386 let arg = args.next();
387 if arg.is_none() {
388 return Err(());
389 }
390 let p = get_two_array(arg.unwrap())?;
391 let arg = args.next();
392 if arg.is_none() {
393 return Err(());
394 }
395 let u = arg.unwrap().parse();
396 if u.is_err() {
397 return Err(());
398 }
399 let arg = args.next();
400 if arg.is_none() {
401 return Err(());
402 }
403 let c = get_color(arg.unwrap())?;
404 Ok(DrawInstructions::Circle(p, u.unwrap(), c))
405 },
406 _ => Err(()),
407 }
408 }
409}
410
411pub type DrawInstructionsVec = Vec<DrawInstructions>;
412
413impl Serializable for DrawInstructionsVec {
414 fn serialize(&self) -> String {
415 let collected: Vec<_> = self.into_iter().map(|ins| ins.serialize()).collect();
416 collected.join("\x1D")
417 }
418 fn deserialize(serialized: &str) -> Result<Self, ()> {
419 let serialized = if serialized.ends_with("\n") { &serialized[..serialized.len() - 1] } else { serialized };
421 let mut instructions = Vec::new();
422 for ser_ins in serialized.split("\x1D") {
423 if let Ok(ser_ins) = DrawInstructions::deserialize(ser_ins) {
424 instructions.push(ser_ins);
425 } else {
426 return Err(());
427 }
428 }
429 Ok(instructions)
430 }
431}
432
433#[test]
434fn draw_instructions_serialize_deserialize() {
435 use std::vec;
436 let instructions = vec![
437 DrawInstructions::Rect([15, 24], [100, 320], [255, 0, 128]),
438 DrawInstructions::Text([0, 158], vec!["nimbus-roman".to_string(), "shippori-mincho".to_string()], "Test test 1234 testing\nmictest / mictest is this thing\non?".to_string(), [12, 36, 108], [128, 128, 128], Some(1), None),
439 DrawInstructions::Gradient([0, 500], [750, 125], [255, 255, 255], [0, 0, 0], 12),
440 DrawInstructions::Text([123, 999], vec!["nimbus-romono".to_string()], "print!(\"{}\", variable_name);".to_string(), [12, 36, 108], [128, 128, 128], Some(44), Some(200)),
441 DrawInstructions::Bmp([55, 98], "mingde".to_string(), true),
442 DrawInstructions::Bmp([55, 98], "wooooo".to_string(), false),
443 DrawInstructions::Circle([0, 1], 19, [128, 128, 128]),
444 ];
445 let serialized = instructions.serialize();
446 assert!(serialized == DrawInstructionsVec::deserialize(&serialized).unwrap().serialize());
447 let instructions = vec![
448 DrawInstructions::Rect([0, 0], [410, 410], [0, 0, 0]),
449 DrawInstructions::Text([4, 4], vec!["nimbus-romono".to_string()], "Mingde Terminal".to_string(), [255, 255, 255], [0, 0, 0], Some(0), Some(10)),
450 DrawInstructions::Text([4, 34], vec!["nimbus-romono".to_string()], "$ a".to_string(), [255, 255, 255], [0, 0, 0], Some(0), Some(10)),
451 ];
452 let serialized = instructions.serialize() + "\n";
453 assert!(serialized[..serialized.len() - 1] == DrawInstructionsVec::deserialize(&serialized).unwrap().serialize());
454}
455
456impl Serializable for WindowLikeType {
457 fn serialize(&self) -> String {
458 match self {
459 WindowLikeType::LockScreen => "LockScreen".to_string(),
460 WindowLikeType::Window => "Window".to_string(),
461 WindowLikeType::DesktopBackground => "DesktopBackground".to_string(),
462 WindowLikeType::Taskbar => "Taskbar".to_string(),
463 WindowLikeType::StartMenu => "StartMenu".to_string(),
464 WindowLikeType::WorkspaceIndicator => "WorkspaceIndicator".to_string(),
465 WindowLikeType::OnscreenKeyboard => "OnscreenKeyboard".to_string(),
466 }
467 }
468 fn deserialize(serialized: &str) -> Result<Self, ()> {
469 let serialized = if serialized.ends_with("\n") { &serialized[..serialized.len() - 1] } else { serialized };
470 match serialized {
471 "LockScreen" => Ok(WindowLikeType::LockScreen),
472 "Window" => Ok(WindowLikeType::Window),
473 "DesktopBackground" => Ok(WindowLikeType::DesktopBackground),
474 "Taskbar" => Ok(WindowLikeType::Taskbar),
475 "StartMenu" => Ok(WindowLikeType::StartMenu),
476 "WorkspaceIndicator" => Ok(WindowLikeType::WorkspaceIndicator),
477 "OnscreenKeyboard" => Ok(WindowLikeType::OnscreenKeyboard),
478 _ => Err(()),
479 }
480 }
481}
482
483#[test]
484fn window_like_type_serialize_deserialize() {
485 let wl_type = WindowLikeType::Window;
486 let serialized = wl_type.serialize();
487 assert!(serialized == WindowLikeType::deserialize(&serialized).unwrap().serialize());
488}
489
490impl Serializable for Dimensions {
491 fn serialize(&self) -> String {
492 array_to_string(self)
493 }
494 fn deserialize(serialized: &str) -> Result<Self, ()> {
495 let serialized = if serialized.ends_with("\n") { &serialized[..serialized.len() - 1] } else { serialized };
497 let d = get_two_array(serialized)?;
498 Ok(d)
499 }
500}
501
502impl Serializable for WindowMessage {
503 fn serialize(&self) -> String {
504 match self {
505 WindowMessage::Init(d) => format!("Init/{}", array_to_string(d)),
506 WindowMessage::KeyPress(kp) => format!("KeyPress/{}", kp.key),
507 WindowMessage::CtrlKeyPress(kp) => format!("CtrlKeyPress/{}", kp.key),
508 WindowMessage::Shortcut(st) => format!("Shortcut/{}", match st {
509 ShortcutType::StartMenu => "StartMenu".to_string(),
510 ShortcutType::SwitchWorkspace(u) => format!("SwitchWorkspace/{}", u),
511 ShortcutType::MoveWindowToWorkspace(u) => format!("MoveWindowToWorkspace/{}", u),
512 ShortcutType::FocusPrevWindow => "FocusPrevWindow".to_string(),
513 ShortcutType::FocusNextWindow => "FocusNextWindow".to_string(),
514 ShortcutType::QuitWindow => "QuitWindow".to_string(),
515 ShortcutType::MoveWindow(d) => format!("MoveWindow/{}", match d {
516 Direction::Left => "Left",
517 Direction::Down => "Down",
518 Direction::Up => "Up",
519 Direction::Right => "Right",
520 }),
521 ShortcutType::MoveWindowToEdge(d) => format!("MoveWindowToEdge/{}", match d {
522 Direction::Left => "Left",
523 Direction::Down => "Down",
524 Direction::Up => "Up",
525 Direction::Right => "Right",
526 }),
527 ShortcutType::ChangeWindowSize(d) => format!("ChangeWindowSize/{}", match d {
528 Direction::Left => "Left",
529 Direction::Down => "Down",
530 Direction::Up => "Up",
531 Direction::Right => "Right",
532 }),
533 ShortcutType::CenterWindow => "CenterWindow".to_string(),
534 ShortcutType::FullscreenWindow => "FullscreenWindow".to_string(),
535 ShortcutType::HalfWidthWindow => "HalfWidthWindow".to_string(),
536 ShortcutType::ClipboardCopy => "ClipboardCopy".to_string(),
537 ShortcutType::ClipboardPaste(s) => format!("ClipboardPaste/{}", s),
538 }),
539 WindowMessage::Info(i) => format!("Info/{}", match i {
540 InfoType::WindowsInWorkspace(wv, u) => {
541 let mut wv_string = String::new();
542 for w in wv {
543 wv_string += &format!("{}\x1F{}\x1F", w.0, w.1);
544 }
545 wv_string = wv_string[..wv_string.len() - 1].to_string();
546 format!("WindowsInWorkspace/{}\x1E{}", wv_string, u)
547 },
548 }),
549 WindowMessage::Focus => "Focus".to_string(),
550 WindowMessage::Unfocus => "Unfocus".to_string(),
551 WindowMessage::FocusClick => "FocusClick".to_string(),
552 WindowMessage::ChangeDimensions(d) => format!("ChangeDimensions/{}", array_to_string(d)),
553 WindowMessage::Touch(u1, u2) => format!("Touch/{}\x1E{}", u1, u2),
554 }
555 }
556 fn deserialize(serialized: &str) -> Result<Self, ()> {
557 let serialized = if serialized.ends_with("\n") { &serialized[..serialized.len() - 1] } else { serialized };
558 let mut parts = serialized.split("/");
559 match parts.next().unwrap_or("Invalid") {
560 "Init" => {
561 let arg = parts.next();
562 if arg.is_none() {
563 return Err(());
564 }
565 let d = get_two_array(arg.unwrap())?;
566 Ok(WindowMessage::Init(d))
567 },
568 "KeyPress" => {
569 let charg = get_rest_of_split(&mut parts, Some("/")).chars().next();
570 if let Some(charg) = charg {
571 Ok(WindowMessage::KeyPress(KeyPress { key: charg }))
572 } else {
573 Err(())
574 }
575 },
576 "CtrlKeyPress" => {
577 let charg = get_rest_of_split(&mut parts, Some("/")).chars().next();
578 if let Some(charg) = charg {
579 Ok(WindowMessage::CtrlKeyPress(KeyPress { key: charg }))
580 } else {
581 Err(())
582 }
583 },
584 "Shortcut" => {
585 let arg = parts.next();
586 if arg.is_none() {
587 return Err(());
588 }
589 let arg = arg.unwrap();
590 let shortcut = match arg {
591 "StartMenu" => Some(ShortcutType::StartMenu),
592 "SwitchWorkspace" | "MoveWindowToWorkspace" => {
593 let narg = parts.next();
594 if narg.is_none() {
595 None
596 } else {
597 let narg = narg.unwrap();
598 if let Ok(n) = narg.parse() {
599 if arg == "SwitchWorkspace" {
600 Some(ShortcutType::SwitchWorkspace(n))
601 } else {
602 Some(ShortcutType::MoveWindowToWorkspace(n))
603 }
604 } else {
605 None
606 }
607 }
608 },
609 "FocusPrevWindow" => Some(ShortcutType::FocusPrevWindow),
610 "FocusNextWindow" => Some(ShortcutType::FocusNextWindow),
611 "QuitWindow" => Some(ShortcutType::QuitWindow),
612 "MoveWindow" | "MoveWindowToEdge" | "ChangeWindowSize" => {
613 let darg = parts.next();
614 if let Some(darg) = darg {
615 let direction = match darg {
616 "Left" => Some(Direction::Left),
617 "Up" => Some(Direction::Up),
618 "Down" => Some(Direction::Down),
619 "Right" => Some(Direction::Right),
620 _ => None,
621 };
622 if let Some(direction) = direction {
623 if arg == "MoveWindow" {
624 Some(ShortcutType::MoveWindow(direction))
625 } else if arg == "MoveWindowToEdge" {
626 Some(ShortcutType::MoveWindowToEdge(direction))
627 } else {
628 Some(ShortcutType::ChangeWindowSize(direction))
629 }
630 } else {
631 None
632 }
633 } else {
634 None
635 }
636 },
637 "CenterWindow" => Some(ShortcutType::CenterWindow),
638 "FullscreenWindow" => Some(ShortcutType::FullscreenWindow),
639 "HalfWidthWindow" => Some(ShortcutType::HalfWidthWindow),
640 "ClipboardCopy" => Some(ShortcutType::ClipboardCopy),
641 "ClipboardPaste" => Some(ShortcutType::ClipboardPaste(get_rest_of_split(&mut parts, Some("/")))),
642 _ => None,
643 };
644 if let Some(shortcut) = shortcut {
645 Ok(WindowMessage::Shortcut(shortcut))
646 } else {
647 Err(())
648 }
649 },
650 "Info" => {
651 if parts.next().is_none() {
653 return Err(());
654 }
655 let arg = parts.next();
656 if arg.is_none() {
657 return Err(());
658 }
659 let mut parts2 = arg.unwrap().split("\x1E");
660 let arg2 = parts2.next();
661 if arg2.is_none() {
662 return Err(());
663 }
664 let mut w_tuple: (usize, String) = Default::default();
665 let mut w_vec = Vec::new();
666 let mut i = 0;
667 for a in arg2.unwrap().split("\x1F") {
668 if i % 2 == 0 {
669 if let Ok(n) = a.parse() {
670 w_tuple.0 = n;
671 }
672 } else {
673 w_tuple.1 = a.to_string();
674 w_vec.push(w_tuple.clone());
675 }
676 i += 1;
677 }
678 let arg2 = parts2.next();
679 if arg2.is_none() {
680 return Err(());
681 }
682 if let Ok(n) = arg2.unwrap().parse() {
683 return Ok(WindowMessage::Info(InfoType::WindowsInWorkspace(w_vec, n)));
684 } else {
685 return Err(());
686 }
687 },
688 "Focus" => Ok(WindowMessage::Focus),
689 "Unfocus" => Ok(WindowMessage::Unfocus),
690 "FocusClick" => Ok(WindowMessage::FocusClick),
691 "ChangeDimensions" => {
692 let arg = parts.next();
693 if arg.is_none() {
694 return Err(());
695 }
696 let d = get_two_array(arg.unwrap())?;
697 Ok(WindowMessage::ChangeDimensions(d))
698 },
699 "Touch" => {
700 let arg = parts.next();
701 if arg.is_none() {
702 return Err(());
703 }
704 let mut parts2 = arg.unwrap().split("\x1E");
705 let arg2 = parts2.next();
706 if arg2.is_none() {
707 return Err(());
708 }
709 let u1 = arg2.unwrap().parse();
710 let arg2 = parts2.next();
711 if u1.is_err() || arg2.is_none() {
712 return Err(());
713 }
714 let u2 = arg2.unwrap().parse();
715 if u2.is_err() {
716 return Err(());
717 }
718 Ok(WindowMessage::Touch(u1.unwrap(), u2.unwrap()))
719 },
720 _ => Err(()),
721 }
722 }
723}
724
725#[test]
726fn window_message_serialize_deserialize() {
727 for wm in [
728 WindowMessage::Init([1000, 1001]),
729 WindowMessage::KeyPress(KeyPress { key: 'a' }),
730 WindowMessage::KeyPress(KeyPress { key: '/' }),
731 WindowMessage::KeyPress(KeyPress { key: '𐘂' }),
732 WindowMessage::CtrlKeyPress(KeyPress { key: ';' }),
733 WindowMessage::Shortcut(ShortcutType::StartMenu),
734 WindowMessage::Shortcut(ShortcutType::MoveWindowToWorkspace(7)),
735 WindowMessage::Shortcut(ShortcutType::ClipboardPaste("105/20 Azumanga".to_string())),
736 WindowMessage::Info(InfoType::WindowsInWorkspace(vec![(1, "Terminal".to_string()), (2, "Minesweeper".to_string()), (12, "Test Test".to_string())], 5)),
737 WindowMessage::Focus,
738 WindowMessage::Unfocus,
739 WindowMessage::FocusClick,
740 WindowMessage::ChangeDimensions([999, 250]),
741 WindowMessage::Touch(12, 247),
742 ] {
743 let serialized = wm.serialize();
744 assert!(serialized == WindowMessage::deserialize(&serialized).unwrap().serialize());
745 }
746}
747