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 {
20 let mut output = String::new();
21 for item in array {
22 output += &format!("{}{}", if output == String::new() {
23 ""
24 } else {
25 "\x1F"
26 }, item);
27 }
28 output
29}
30
31fn option_to_string<T: Display>(option: &Option<T>) -> String {
32 if let Some(value) = option {
33 format!("S{}", value)
34 } else {
35 "N".to_string()
36 }
37}
38
39fn get_color(serialized: &str) -> Result<[u8; 3], ()> {
40 let rgb = serialized.split("\x1F");
41 let mut color = [0; 3];
42 for (c_i, c) in rgb.enumerate() {
46 if c_i == 3 {
47 return Err(());
48 }
49 if let Ok(c) = c.parse() {
50 color[c_i] = c;
51 } else {
52 return Err(());
53 }
54 }
55 Ok(color)
56}
57
58fn get_two_array(serialized: &str) -> Result<[usize; 2], ()> {
59 let mut arg = serialized.split("\x1F");
60 let mut a = [0; 2];
61 for i in 0..2 {
62 if let Some(n) = arg.next() {
63 if let Ok(n) = n.parse() {
64 a[i] = n;
65 continue
66 }
67 }
68 return Err(());
69 }
70 Ok(a)
71}
72
73pub trait Serializable {
74 fn serialize(&self) -> String;
75 fn deserialize(serialized: &str) -> Result<Self, ()> where Self: Sized;
76}
77
78impl Serializable for ThemeInfo {
81 fn serialize(&self) -> String {
82 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))
83 }
84 fn deserialize(serialized: &str) -> Result<Self, ()> {
85 let serialized = if serialized.ends_with("\n") { &serialized[..serialized.len() - 1] } else { serialized };
87 let mut theme_info: ThemeInfo = Default::default();
88 let arrays = serialized.split(":");
89 for (a_i, a) in arrays.enumerate() {
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 }
129 Err(())
130 }
131}
132
133#[test]
134fn theme_info_serialize_deserialize() {
135 use crate::themes::get_theme_info;
136 let theme_info = get_theme_info(&Default::default()).unwrap();
137 let serialized = theme_info.serialize();
138 assert!(serialized == ThemeInfo::deserialize(&serialized).unwrap().serialize());
139}
140
141impl Serializable for WindowMessageResponse {
142 fn serialize(&self) -> String {
143 match self {
144 WindowMessageResponse::JustRedraw => "JustRedraw".to_string(),
145 WindowMessageResponse::DoNothing => "DoNothing".to_string(),
146 WindowMessageResponse::Request(req) => {
147 let req = match req {
148 WindowManagerRequest::OpenWindow(name) => format!("OpenWindow/{}", name),
149 WindowManagerRequest::ClipboardCopy(copy_string) => format!("ClipboardCopy/{}", copy_string.replace("\n", "𐘂")), WindowManagerRequest::CloseStartMenu => "CloseStartMenu".to_string(),
151 WindowManagerRequest::Unlock => "Unlock".to_string(),
152 WindowManagerRequest::Lock => "Lock".to_string(),
153 WindowManagerRequest::DoKeyChar(kc) => format!("DoKeyChar/{}", match kc {
154 KeyChar::Press(c) => format!("Press/{}", c),
155 KeyChar::Alt(c) => format!("Alt/{}", c),
156 KeyChar::Ctrl(c) => format!("Ctrl/{}", c),
157 }),
158 };
159 format!("Request/{}", req)
160 },
161 }
162 }
163 fn deserialize(serialized: &str) -> Result<Self, ()> {
164 let serialized = if serialized.ends_with("\n") { &serialized[..serialized.len() - 1] } else { serialized };
166 let mut parts = serialized.split("/");
167 match parts.next().unwrap_or("Invalid") {
168 "JustRedraw" => Ok(WindowMessageResponse::JustRedraw),
169 "DoNothing" => Ok(WindowMessageResponse::DoNothing),
170 "Request" => {
171 let req = match parts.next().unwrap_or("Invalid") {
172 "OpenWindow" => Some(WindowManagerRequest::OpenWindow(get_rest_of_split(&mut parts, Some("/")))),
174 "ClipboardCopy" => Some(WindowManagerRequest::ClipboardCopy(get_rest_of_split(&mut parts, Some("/")))),
175 "CloseStartMenu" => Some(WindowManagerRequest::CloseStartMenu),
176 "Unlock" => Some(WindowManagerRequest::Unlock),
177 "Lock" => Some(WindowManagerRequest::Lock),
178 "DoKeyChar" => Some(WindowManagerRequest::DoKeyChar(
179 match parts.next().unwrap_or("Invalid") {
180 "Press" => KeyChar::Press(parts.next().unwrap_or("?").chars().next().unwrap()),
181 "Alt" => KeyChar::Alt(parts.next().unwrap_or("?").chars().next().unwrap()),
182 "Ctrl" => KeyChar::Ctrl(parts.next().unwrap_or("?").chars().next().unwrap()),
183 _ => KeyChar::Press('?'), }
185 )),
186 _ => None, };
188 if let Some(req) = req {
189 Ok(WindowMessageResponse::Request(req))
190 } else {
191 Err(())
192 }
193 },
194 _ => Err(()),
195 }
196 }
197}
198
199#[test]
200fn window_message_response_serialize_deserialize() {
201 let resp = WindowMessageResponse::JustRedraw;
202 let serialized = resp.serialize();
203 assert!(resp == WindowMessageResponse::deserialize(&serialized).unwrap());
204 let resp = WindowMessageResponse::Request(WindowManagerRequest::OpenWindow("a".to_string()));
205 let serialized = resp.serialize();
206 assert!(resp == WindowMessageResponse::deserialize(&serialized).unwrap());
207 let resp = WindowMessageResponse::Request(WindowManagerRequest::Unlock);
208 let serialized = resp.serialize();
209 assert!(resp == WindowMessageResponse::deserialize(&serialized).unwrap());
210 let resp = WindowMessageResponse::Request(WindowManagerRequest::DoKeyChar(KeyChar::Alt('e')));
211 let serialized = resp.serialize();
212 assert!(resp == WindowMessageResponse::deserialize(&serialized).unwrap());
213}
214
215impl Serializable for DrawInstructions {
216 fn serialize(&self) -> String {
217 match self {
218 DrawInstructions::Rect(p, d, c) => format!("Rect/{}\x1E{}\x1E{}", array_to_string(p), array_to_string(d), array_to_string(c)),
220 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)),
221 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),
222 DrawInstructions::Bmp(p, s, b) => format!("Bmp/{}\x1E{}\x1E{}", array_to_string(p), s, b),
223 DrawInstructions::Circle(p, u, c) => format!("Circle/{}\x1E{}\x1E{}", array_to_string(p), u, array_to_string(c)),
224 DrawInstructions::Line(s, e, w, c) => format!("Line/{}\x1E{}\x1E{}\x1E{}", array_to_string(s), array_to_string(e), w, 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 "Line" => {
407 let rest = get_rest_of_split(&mut parts, Some("/"));
408 let mut args = rest.split("\x1E");
410 let arg = args.next();
411 if arg.is_none() {
412 return Err(());
413 }
414 let s = get_two_array(arg.unwrap())?;
415 let arg = args.next();
416 if arg.is_none() {
417 return Err(());
418 }
419 let e = get_two_array(arg.unwrap())?;
420 let arg = args.next();
421 if arg.is_none() {
422 return Err(());
423 }
424 let w = arg.unwrap().parse();
425 if w.is_err() {
426 return Err(());
427 }
428 let arg = args.next();
429 if arg.is_none() {
430 return Err(());
431 }
432 let c = get_color(arg.unwrap())?;
433 Ok(DrawInstructions::Line(s, e, w.unwrap(), c))
434 },
435 _ => Err(()),
436 }
437 }
438}
439
440pub type DrawInstructionsVec = Vec<DrawInstructions>;
441
442impl Serializable for DrawInstructionsVec {
443 fn serialize(&self) -> String {
444 if self.len() == 0 {
445 return "empty".to_string();
446 }
447 let collected: Vec<_> = self.into_iter().map(|ins| ins.serialize()).collect();
448 collected.join("\x1D")
449 }
450 fn deserialize(serialized: &str) -> Result<Self, ()> {
451 let serialized = if serialized.ends_with("\n") { &serialized[..serialized.len() - 1] } else { serialized };
453 if serialized == "empty" {
454 return Ok(Vec::new());
455 }
456 let mut instructions = Vec::new();
457 for ser_ins in serialized.split("\x1D") {
458 if let Ok(ser_ins) = DrawInstructions::deserialize(ser_ins) {
459 instructions.push(ser_ins);
460 } else {
461 return Err(());
462 }
463 }
464 Ok(instructions)
465 }
466}
467
468#[test]
469fn draw_instructions_serialize_deserialize() {
470 use std::vec;
471 let instructions = vec![
472 DrawInstructions::Rect([15, 24], [100, 320], [255, 0, 128]),
473 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),
474 DrawInstructions::Gradient([0, 500], [750, 125], [255, 255, 255], [0, 0, 0], 12),
475 DrawInstructions::Text([123, 999], vec!["nimbus-romono".to_string()], "print!(\"{}\", variable_name);".to_string(), [12, 36, 108], [128, 128, 128], Some(44), Some(200)),
476 DrawInstructions::Bmp([55, 98], "mingde".to_string(), true),
477 DrawInstructions::Bmp([55, 98], "wooooo".to_string(), false),
478 DrawInstructions::Circle([0, 1], 19, [128, 128, 128]),
479 ];
480 let serialized = instructions.serialize();
481 assert!(serialized == DrawInstructionsVec::deserialize(&serialized).unwrap().serialize());
482 let instructions = vec![
483 DrawInstructions::Rect([0, 0], [410, 410], [0, 0, 0]),
484 DrawInstructions::Text([4, 4], vec!["nimbus-romono".to_string()], "Mingde Terminal".to_string(), [255, 255, 255], [0, 0, 0], Some(0), Some(10)),
485 DrawInstructions::Text([4, 34], vec!["nimbus-romono".to_string()], "$ a".to_string(), [255, 255, 255], [0, 0, 0], Some(0), Some(10)),
486 ];
487 let serialized = instructions.serialize() + "\n";
488 assert!(serialized[..serialized.len() - 1] == DrawInstructionsVec::deserialize(&serialized).unwrap().serialize());
489 let instructions = Vec::new();
490 let serialized = instructions.serialize() + "\n";
491 assert!(DrawInstructionsVec::deserialize(&serialized).unwrap().len() == 0);
492}
493
494impl Serializable for WindowLikeType {
495 fn serialize(&self) -> String {
496 match self {
497 WindowLikeType::LockScreen => "LockScreen".to_string(),
498 WindowLikeType::Window => "Window".to_string(),
499 WindowLikeType::DesktopBackground => "DesktopBackground".to_string(),
500 WindowLikeType::Taskbar => "Taskbar".to_string(),
501 WindowLikeType::StartMenu => "StartMenu".to_string(),
502 WindowLikeType::WorkspaceIndicator => "WorkspaceIndicator".to_string(),
503 WindowLikeType::OnscreenKeyboard => "OnscreenKeyboard".to_string(),
504 }
505 }
506 fn deserialize(serialized: &str) -> Result<Self, ()> {
507 let serialized = if serialized.ends_with("\n") { &serialized[..serialized.len() - 1] } else { serialized };
508 match serialized {
509 "LockScreen" => Ok(WindowLikeType::LockScreen),
510 "Window" => Ok(WindowLikeType::Window),
511 "DesktopBackground" => Ok(WindowLikeType::DesktopBackground),
512 "Taskbar" => Ok(WindowLikeType::Taskbar),
513 "StartMenu" => Ok(WindowLikeType::StartMenu),
514 "WorkspaceIndicator" => Ok(WindowLikeType::WorkspaceIndicator),
515 "OnscreenKeyboard" => Ok(WindowLikeType::OnscreenKeyboard),
516 _ => Err(()),
517 }
518 }
519}
520
521#[test]
522fn window_like_type_serialize_deserialize() {
523 let wl_type = WindowLikeType::Window;
524 let serialized = wl_type.serialize();
525 assert!(serialized == WindowLikeType::deserialize(&serialized).unwrap().serialize());
526}
527
528impl Serializable for Dimensions {
529 fn serialize(&self) -> String {
530 array_to_string(self)
531 }
532 fn deserialize(serialized: &str) -> Result<Self, ()> {
533 let serialized = if serialized.ends_with("\n") { &serialized[..serialized.len() - 1] } else { serialized };
535 let d = get_two_array(serialized)?;
536 Ok(d)
537 }
538}
539
540impl Serializable for WindowMessage {
541 fn serialize(&self) -> String {
542 match self {
543 WindowMessage::Init(d) => format!("Init/{}", array_to_string(d)),
544 WindowMessage::KeyPress(kp) => format!("KeyPress/{}", kp.key),
545 WindowMessage::CtrlKeyPress(kp) => format!("CtrlKeyPress/{}", kp.key),
546 WindowMessage::Shortcut(st) => format!("Shortcut/{}", match st {
547 ShortcutType::StartMenu => "StartMenu".to_string(),
548 ShortcutType::SwitchWorkspace(u) => format!("SwitchWorkspace/{}", u),
549 ShortcutType::MoveWindowToWorkspace(u) => format!("MoveWindowToWorkspace/{}", u),
550 ShortcutType::FocusPrevWindow => "FocusPrevWindow".to_string(),
551 ShortcutType::FocusNextWindow => "FocusNextWindow".to_string(),
552 ShortcutType::QuitWindow => "QuitWindow".to_string(),
553 ShortcutType::MoveWindow(d) => format!("MoveWindow/{}", match d {
554 Direction::Left => "Left",
555 Direction::Down => "Down",
556 Direction::Up => "Up",
557 Direction::Right => "Right",
558 }),
559 ShortcutType::MoveWindowToEdge(d) => format!("MoveWindowToEdge/{}", match d {
560 Direction::Left => "Left",
561 Direction::Down => "Down",
562 Direction::Up => "Up",
563 Direction::Right => "Right",
564 }),
565 ShortcutType::ChangeWindowSize(d) => format!("ChangeWindowSize/{}", match d {
566 Direction::Left => "Left",
567 Direction::Down => "Down",
568 Direction::Up => "Up",
569 Direction::Right => "Right",
570 }),
571 ShortcutType::CenterWindow => "CenterWindow".to_string(),
572 ShortcutType::FullscreenWindow => "FullscreenWindow".to_string(),
573 ShortcutType::HalfWidthWindow => "HalfWidthWindow".to_string(),
574 ShortcutType::ClipboardCopy => "ClipboardCopy".to_string(),
575 ShortcutType::ClipboardPaste(s) => format!("ClipboardPaste/{}", s),
576 }),
577 WindowMessage::Info(i) => format!("Info/{}", match i {
578 InfoType::WindowsInWorkspace(wv, u) => {
579 let mut wv_string = String::new();
580 for w in wv {
581 wv_string += &format!("{}\x1F{}\x1F", w.0, w.1);
582 }
583 wv_string = wv_string[..wv_string.len() - 1].to_string();
584 format!("WindowsInWorkspace/{}\x1E{}", wv_string, u)
585 },
586 }),
587 WindowMessage::Focus => "Focus".to_string(),
588 WindowMessage::Unfocus => "Unfocus".to_string(),
589 WindowMessage::FocusClick => "FocusClick".to_string(),
590 WindowMessage::ChangeDimensions(d) => format!("ChangeDimensions/{}", array_to_string(d)),
591 WindowMessage::Touch(u1, u2) => format!("Touch/{}\x1E{}", u1, u2),
592 }
593 }
594 fn deserialize(serialized: &str) -> Result<Self, ()> {
595 let serialized = if serialized.ends_with("\n") { &serialized[..serialized.len() - 1] } else { serialized };
596 let mut parts = serialized.split("/");
597 match parts.next().unwrap_or("Invalid") {
598 "Init" => {
599 let arg = parts.next();
600 if arg.is_none() {
601 return Err(());
602 }
603 let d = get_two_array(arg.unwrap())?;
604 Ok(WindowMessage::Init(d))
605 },
606 "KeyPress" => {
607 let charg = get_rest_of_split(&mut parts, Some("/")).chars().next();
608 if let Some(charg) = charg {
609 Ok(WindowMessage::KeyPress(KeyPress { key: charg }))
610 } else {
611 Err(())
612 }
613 },
614 "CtrlKeyPress" => {
615 let charg = get_rest_of_split(&mut parts, Some("/")).chars().next();
616 if let Some(charg) = charg {
617 Ok(WindowMessage::CtrlKeyPress(KeyPress { key: charg }))
618 } else {
619 Err(())
620 }
621 },
622 "Shortcut" => {
623 let arg = parts.next();
624 if arg.is_none() {
625 return Err(());
626 }
627 let arg = arg.unwrap();
628 let shortcut = match arg {
629 "StartMenu" => Some(ShortcutType::StartMenu),
630 "SwitchWorkspace" | "MoveWindowToWorkspace" => {
631 let narg = parts.next();
632 if narg.is_none() {
633 None
634 } else {
635 let narg = narg.unwrap();
636 if let Ok(n) = narg.parse() {
637 if arg == "SwitchWorkspace" {
638 Some(ShortcutType::SwitchWorkspace(n))
639 } else {
640 Some(ShortcutType::MoveWindowToWorkspace(n))
641 }
642 } else {
643 None
644 }
645 }
646 },
647 "FocusPrevWindow" => Some(ShortcutType::FocusPrevWindow),
648 "FocusNextWindow" => Some(ShortcutType::FocusNextWindow),
649 "QuitWindow" => Some(ShortcutType::QuitWindow),
650 "MoveWindow" | "MoveWindowToEdge" | "ChangeWindowSize" => {
651 let darg = parts.next();
652 if let Some(darg) = darg {
653 let direction = match darg {
654 "Left" => Some(Direction::Left),
655 "Up" => Some(Direction::Up),
656 "Down" => Some(Direction::Down),
657 "Right" => Some(Direction::Right),
658 _ => None,
659 };
660 if let Some(direction) = direction {
661 if arg == "MoveWindow" {
662 Some(ShortcutType::MoveWindow(direction))
663 } else if arg == "MoveWindowToEdge" {
664 Some(ShortcutType::MoveWindowToEdge(direction))
665 } else {
666 Some(ShortcutType::ChangeWindowSize(direction))
667 }
668 } else {
669 None
670 }
671 } else {
672 None
673 }
674 },
675 "CenterWindow" => Some(ShortcutType::CenterWindow),
676 "FullscreenWindow" => Some(ShortcutType::FullscreenWindow),
677 "HalfWidthWindow" => Some(ShortcutType::HalfWidthWindow),
678 "ClipboardCopy" => Some(ShortcutType::ClipboardCopy),
679 "ClipboardPaste" => Some(ShortcutType::ClipboardPaste(get_rest_of_split(&mut parts, Some("/")).replace("𐘂", "\n"))),
680 _ => None,
681 };
682 if let Some(shortcut) = shortcut {
683 Ok(WindowMessage::Shortcut(shortcut))
684 } else {
685 Err(())
686 }
687 },
688 "Info" => {
689 if parts.next().is_none() {
691 return Err(());
692 }
693 let arg = parts.next();
694 if arg.is_none() {
695 return Err(());
696 }
697 let mut parts2 = arg.unwrap().split("\x1E");
698 let arg2 = parts2.next();
699 if arg2.is_none() {
700 return Err(());
701 }
702 let mut w_tuple: (usize, String) = Default::default();
703 let mut w_vec = Vec::new();
704 for (i, a) in arg2.unwrap().split("\x1F").enumerate() {
705 if i % 2 == 0 {
706 if let Ok(n) = a.parse() {
707 w_tuple.0 = n;
708 }
709 } else {
710 w_tuple.1 = a.to_string();
711 w_vec.push(w_tuple.clone());
712 }
713 }
714 let arg2 = parts2.next();
715 if arg2.is_none() {
716 return Err(());
717 }
718 if let Ok(n) = arg2.unwrap().parse() {
719 return Ok(WindowMessage::Info(InfoType::WindowsInWorkspace(w_vec, n)));
720 } else {
721 return Err(());
722 }
723 },
724 "Focus" => Ok(WindowMessage::Focus),
725 "Unfocus" => Ok(WindowMessage::Unfocus),
726 "FocusClick" => Ok(WindowMessage::FocusClick),
727 "ChangeDimensions" => {
728 let arg = parts.next();
729 if arg.is_none() {
730 return Err(());
731 }
732 let d = get_two_array(arg.unwrap())?;
733 Ok(WindowMessage::ChangeDimensions(d))
734 },
735 "Touch" => {
736 let arg = parts.next();
737 if arg.is_none() {
738 return Err(());
739 }
740 let mut parts2 = arg.unwrap().split("\x1E");
741 let arg2 = parts2.next();
742 if arg2.is_none() {
743 return Err(());
744 }
745 let u1 = arg2.unwrap().parse();
746 let arg2 = parts2.next();
747 if u1.is_err() || arg2.is_none() {
748 return Err(());
749 }
750 let u2 = arg2.unwrap().parse();
751 if u2.is_err() {
752 return Err(());
753 }
754 Ok(WindowMessage::Touch(u1.unwrap(), u2.unwrap()))
755 },
756 _ => Err(()),
757 }
758 }
759}
760
761#[test]
762fn window_message_serialize_deserialize() {
763 for wm in [
764 WindowMessage::Init([1000, 1001]),
765 WindowMessage::KeyPress(KeyPress { key: 'a' }),
766 WindowMessage::KeyPress(KeyPress { key: '/' }),
767 WindowMessage::KeyPress(KeyPress { key: '𐘂' }),
768 WindowMessage::CtrlKeyPress(KeyPress { key: ';' }),
769 WindowMessage::Shortcut(ShortcutType::StartMenu),
770 WindowMessage::Shortcut(ShortcutType::MoveWindowToWorkspace(7)),
771 WindowMessage::Shortcut(ShortcutType::ClipboardPaste("105/20 Azumanga".to_string())),
772 WindowMessage::Info(InfoType::WindowsInWorkspace(vec![(1, "Terminal".to_string()), (2, "Minesweeper".to_string()), (12, "Test Test".to_string())], 5)),
773 WindowMessage::Focus,
774 WindowMessage::Unfocus,
775 WindowMessage::FocusClick,
776 WindowMessage::ChangeDimensions([999, 250]),
777 WindowMessage::Touch(12, 247),
778 ] {
779 let serialized = wm.serialize();
780 assert!(serialized == WindowMessage::deserialize(&serialized).unwrap().serialize());
781 }
782}
783