From cfece80c6690786cbb1d914bea0d1c4b6546c495 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Tue, 22 Oct 2024 05:28:23 +0000 Subject: [PATCH] separate windows out, IPCcargo run --release! --- Cargo.toml | 5 +- src/{window_likes => bin}/audio_player.rs | 31 +++++--- src/{ => bin}/main.rs | 21 +---- src/{window_likes => bin}/malvim.rs | 35 ++++---- src/{window_likes => bin}/minesweeper.rs | 31 +++++--- src/{window_likes => bin}/start_menu.rs | 23 ++++-- src/{window_likes => bin}/terminal.rs | 21 +++-- src/bin/test.rs | 11 +++ src/components/highlight_button.rs | 4 +- src/components/toggle_button.rs | 6 +- .../desktop_background.rs | 0 .../lock_screen.rs | 10 +-- src/essential/mod.rs | 5 ++ src/{window_likes => essential}/taskbar.rs | 7 +- .../workspace_indicator.rs | 4 +- src/ipc.rs | 51 ++++++++++++ src/lib.rs | 12 +++ src/messages.rs | 17 ++-- src/proxy_window_like.rs | 79 +++++++++++++++++++ src/themes.rs | 3 + src/window_likes/mod.rs | 11 --- src/window_manager.rs | 53 ++++++------- 22 files changed, 305 insertions(+), 135 deletions(-) rename src/{window_likes => bin}/audio_player.rs (84%) rename src/{ => bin}/main.rs (72%) rename src/{window_likes => bin}/malvim.rs (92%) rename src/{window_likes => bin}/minesweeper.rs (89%) rename src/{window_likes => bin}/start_menu.rs (93%) rename src/{window_likes => bin}/terminal.rs (91%) create mode 100644 src/bin/test.rs rename src/{window_likes => essential}/desktop_background.rs (100%) rename src/{window_likes => essential}/lock_screen.rs (76%) create mode 100644 src/essential/mod.rs rename src/{window_likes => essential}/taskbar.rs (89%) rename src/{window_likes => essential}/workspace_indicator.rs (90%) create mode 100644 src/ipc.rs create mode 100644 src/lib.rs create mode 100644 src/proxy_window_like.rs delete mode 100644 src/window_likes/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 79a1f12..bb8c47d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,8 @@ [package] -name = "ming-os-kernel" +name = "ming-wm" version = "0.1.0" edition = "2018" +default-run = "main" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -12,3 +13,5 @@ bmp-rust = "0.4.1" termion = "4.0.3" rodio = "0.19.0" rand = "0.8.5" +ron = "0.8" +serde = { version = "1", features = ["derive"] } diff --git a/src/window_likes/audio_player.rs b/src/bin/audio_player.rs similarity index 84% rename from src/window_likes/audio_player.rs rename to src/bin/audio_player.rs index 38203ce..711fd42 100644 --- a/src/window_likes/audio_player.rs +++ b/src/bin/audio_player.rs @@ -7,12 +7,13 @@ use std::fs::File; use rodio::{ Decoder, OutputStream, Sink, Source }; use rand::prelude::*; -use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType }; -use crate::messages::{ WindowMessage, WindowMessageResponse }; -use crate::framebuffer::Dimensions; -use crate::themes::ThemeInfo; -use crate::utils::{ concat_paths, format_seconds }; -use crate::fs::get_all_files; +use ming_wm::window_manager::{ DrawInstructions, WindowLike, WindowLikeType }; +use ming_wm::messages::{ WindowMessage, WindowMessageResponse }; +use ming_wm::framebuffer::Dimensions; +use ming_wm::themes::ThemeInfo; +use ming_wm::utils::{ concat_paths, format_seconds }; +use ming_wm::fs::get_all_files; +use ming_wm::ipc::listen; const MONO_WIDTH: u8 = 10; const LINE_HEIGHT: usize = 18; @@ -59,13 +60,13 @@ impl WindowLike for AudioPlayer { } fn draw(&self, theme_info: &ThemeInfo) -> Vec { - let mut instructions = vec![DrawInstructions::Text([2, self.dimensions[1] - LINE_HEIGHT], "times-new-roman", if self.command.len() > 0 { self.command.clone() } else { self.response.clone() }, theme_info.text, theme_info.background, None, None)]; + let mut instructions = vec![DrawInstructions::Text([2, self.dimensions[1] - LINE_HEIGHT], "times-new-roman".to_string(), if self.command.len() > 0 { self.command.clone() } else { self.response.clone() }, theme_info.text, theme_info.background, None, None)]; if let Some(sink) = &self.sink { let current = &self.queue[self.queue.len() - sink.len()]; let current_name = current.0.file_name().unwrap().to_string_lossy().into_owned(); - instructions.push(DrawInstructions::Text([self.dimensions[0] / 2 - current_name.len() * MONO_WIDTH as usize / 2, 2], "times-new-romono", current_name.clone(), theme_info.text, theme_info.background, Some(0), Some(MONO_WIDTH))); + instructions.push(DrawInstructions::Text([self.dimensions[0] / 2 - current_name.len() * MONO_WIDTH as usize / 2, 2], "times-new-romono".to_string(), current_name.clone(), theme_info.text, theme_info.background, Some(0), Some(MONO_WIDTH))); let time_string = format!("{}/{}", format_seconds(sink.get_pos().as_secs()), format_seconds(current.1)); - instructions.push(DrawInstructions::Text([self.dimensions[0] / 2 - time_string.len() * MONO_WIDTH as usize / 2, LINE_HEIGHT + 2], "times-new-romono", time_string, theme_info.text, theme_info.background, Some(0), Some(MONO_WIDTH))); + instructions.push(DrawInstructions::Text([self.dimensions[0] / 2 - time_string.len() * MONO_WIDTH as usize / 2, LINE_HEIGHT + 2], "times-new-romono".to_string(), time_string, theme_info.text, theme_info.background, Some(0), Some(MONO_WIDTH))); } // instructions @@ -73,8 +74,8 @@ impl WindowLike for AudioPlayer { //properties - fn title(&self) -> &'static str { - "Audio Player" + fn title(&self) -> String { + "Audio Player".to_string() } fn subtype(&self) -> WindowLikeType { @@ -98,13 +99,13 @@ impl AudioPlayer { } //t: toggle pause/play - //h: prev //l: next/skip //j: volume down //k: volume up //b : set base directory //p /: play directory or playlist in random order - //just hit enter to refresh + //todo: h for help? + //just hit enter or any key to refresh fn process_command(&mut self) -> String { if self.command.len() == 1 { if let Some(sink) = &mut self.sink { @@ -175,3 +176,7 @@ impl AudioPlayer { } } +pub fn main() { + listen(AudioPlayer::new()); +} + diff --git a/src/main.rs b/src/bin/main.rs similarity index 72% rename from src/main.rs rename to src/bin/main.rs index 74c2118..b29167c 100644 --- a/src/main.rs +++ b/src/bin/main.rs @@ -1,24 +1,7 @@ use linux_framebuffer::Framebuffer; -mod framebuffer; -use framebuffer::FramebufferInfo; - -mod window_manager; -use window_manager::init; - -mod window_likes; - -mod components; - -mod themes; - -mod keyboard; - -mod messages; - -mod fs; - -mod utils; +use ming_wm::framebuffer::FramebufferInfo; +use ming_wm::window_manager::init; fn main() { let mut fb = Framebuffer::new("/dev/fb0").unwrap(); diff --git a/src/window_likes/malvim.rs b/src/bin/malvim.rs similarity index 92% rename from src/window_likes/malvim.rs rename to src/bin/malvim.rs index 77cfcce..6c4f5a4 100644 --- a/src/window_likes/malvim.rs +++ b/src/bin/malvim.rs @@ -4,11 +4,12 @@ use std::fmt; use std::path::PathBuf; use std::fs::{ read_to_string, write }; -use crate::messages::{ WindowMessage, WindowMessageResponse }; -use crate::themes::ThemeInfo; -use crate::framebuffer::Dimensions; -use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType }; -use crate::utils::{ calc_actual_lines, calc_new_cursor_pos, Substring }; +use ming_wm::messages::{ WindowMessage, WindowMessageResponse }; +use ming_wm::themes::ThemeInfo; +use ming_wm::framebuffer::Dimensions; +use ming_wm::window_manager::{ DrawInstructions, WindowLike, WindowLikeType }; +use ming_wm::utils::{ calc_actual_lines, calc_new_cursor_pos, Substring }; +use ming_wm::ipc::listen; const MONO_WIDTH: u8 = 10; const LINE_HEIGHT: usize = 18; @@ -302,7 +303,7 @@ impl WindowLike for Malvim { }; instructions.extend(vec![ DrawInstructions::Rect([used_width, 2], [future_used_width, BAND_HEIGHT - 2], background), - DrawInstructions::Text([used_width + 2, 2], "times-new-romono", if file_info.changed { "+ ".to_string() } else { String::new() } + &file_info.name, theme_info.alt_text, background, Some(0), Some(MONO_WIDTH)), + DrawInstructions::Text([used_width + 2, 2], "times-new-romono".to_string(), if file_info.changed { "+ ".to_string() } else { String::new() } + &file_info.name, theme_info.alt_text, background, Some(0), Some(MONO_WIDTH)), ]); used_width = future_used_width; } @@ -320,13 +321,13 @@ impl WindowLike for Malvim { //write line num text (if start of line) let y0 = BAND_HEIGHT + rel_line_num * LINE_HEIGHT + PADDING; if line.0 { - instructions.push(DrawInstructions::Text([PADDING, y0], "times-new-romono", line.1.to_string(), theme_info.alt_secondary, theme_info.alt_background, Some(0), Some(MONO_WIDTH))); + instructions.push(DrawInstructions::Text([PADDING, y0], "times-new-romono".to_string(), line.1.to_string(), theme_info.alt_secondary, theme_info.alt_background, Some(0), Some(MONO_WIDTH))); sub_line_num = 0; } let x1 = current.line_num_width + PADDING * 2; //write actual line //line.2 - instructions.push(DrawInstructions::Text([x1, y0], "times-new-romono", line.2.clone(), theme_info.alt_text, theme_info.alt_background, Some(0), Some(MONO_WIDTH))); + instructions.push(DrawInstructions::Text([x1, y0], "times-new-romono".to_string(), line.2.clone(), theme_info.alt_text, theme_info.alt_background, Some(0), Some(MONO_WIDTH))); sub_line_num += 1; let max = sub_line_num * current.max_chars_per_line; let min = max - current.max_chars_per_line; @@ -336,32 +337,32 @@ impl WindowLike for Malvim { instructions.push(DrawInstructions::Rect(top_left, [MONO_WIDTH as usize, LINE_HEIGHT], theme_info.top)); //draw the char over it if line.2.len() > 0 { - instructions.push(DrawInstructions::Text(top_left, "times-new-romono", line.2.chars().nth(current_file.cursor_pos - min).unwrap().to_string(), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH))); + instructions.push(DrawInstructions::Text(top_left, "times-new-romono".to_string(), line.2.chars().nth(current_file.cursor_pos - min).unwrap().to_string(), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH))); } } } } //bottom blue band stuff //write mode - instructions.push(DrawInstructions::Text([0, self.dimensions[1] - BAND_HEIGHT * 2 + 1], "times-new-romono", self.mode.to_string(), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH))); + instructions.push(DrawInstructions::Text([0, self.dimensions[1] - BAND_HEIGHT * 2 + 1], "times-new-romono".to_string(), self.mode.to_string(), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH))); let file_status; if self.files.len() > 0 { file_status = self.files[self.current_file_index].name.clone(); } else { file_status = "No file open".to_string(); } - instructions.push(DrawInstructions::Text([self.dimensions[0] - file_status.len() * (MONO_WIDTH as usize), self.dimensions[1] - BAND_HEIGHT * 2 + 1], "times-new-romono", file_status, theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH))); + instructions.push(DrawInstructions::Text([self.dimensions[0] - file_status.len() * (MONO_WIDTH as usize), self.dimensions[1] - BAND_HEIGHT * 2 + 1], "times-new-romono".to_string(), file_status, theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH))); //write command or bottom message if self.mode == Mode::Command { - instructions.push(DrawInstructions::Text([0, self.dimensions[1] - BAND_HEIGHT], "times-new-romono", ":".to_string() + &self.command.clone().unwrap_or("".to_string()), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH))); + instructions.push(DrawInstructions::Text([0, self.dimensions[1] - BAND_HEIGHT], "times-new-romono".to_string(), ":".to_string() + &self.command.clone().unwrap_or("".to_string()), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH))); } else if self.mode == Mode::Normal && self.bottom_message.is_some() { - instructions.push(DrawInstructions::Text([0, self.dimensions[1] - BAND_HEIGHT], "times-new-romono", self.bottom_message.clone().unwrap(), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH))); + instructions.push(DrawInstructions::Text([0, self.dimensions[1] - BAND_HEIGHT], "times-new-romono".to_string(), self.bottom_message.clone().unwrap(), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH))); } instructions } - fn title(&self) -> &'static str { - "Malvim" + fn title(&self) -> String { + "Malvim".to_string() } fn subtype(&self) -> WindowLikeType { @@ -497,3 +498,7 @@ impl Malvim { } } +pub fn main() { + listen(Malvim::new()); +} + diff --git a/src/window_likes/minesweeper.rs b/src/bin/minesweeper.rs similarity index 89% rename from src/window_likes/minesweeper.rs rename to src/bin/minesweeper.rs index a7c9f75..c81c036 100644 --- a/src/window_likes/minesweeper.rs +++ b/src/bin/minesweeper.rs @@ -3,10 +3,11 @@ use std::vec; use std::collections::VecDeque; use core::convert::TryFrom; -use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType }; -use crate::messages::{ WindowMessage, WindowMessageResponse }; -use crate::framebuffer::Dimensions; -use crate::themes::ThemeInfo; +use ming_wm::window_manager::{ DrawInstructions, WindowLike, WindowLikeType }; +use ming_wm::messages::{ WindowMessage, WindowMessageResponse }; +use ming_wm::framebuffer::Dimensions; +use ming_wm::themes::ThemeInfo; +use ming_wm::ipc::listen; const HEX_CHARS: [char; 16] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; @@ -156,8 +157,8 @@ impl WindowLike for Minesweeper { fn draw(&self, theme_info: &ThemeInfo) -> Vec { if self.state == State::Seed { vec![ - DrawInstructions::Text([4, 4], "times-new-roman", "Type in random characters to initalise the seed".to_string(), theme_info.text, theme_info.background, None, None), - DrawInstructions::Text([4, 4 + 16], "times-new-roman", self.random_chars.clone(), theme_info.text, theme_info.background, None, None), + DrawInstructions::Text([4, 4], "times-new-roman".to_string(), "Type in random characters to initalise the seed".to_string(), theme_info.text, theme_info.background, None, None), + DrawInstructions::Text([4, 4 + 16], "times-new-roman".to_string(), self.random_chars.clone(), theme_info.text, theme_info.background, None, None), ] } else { let mut instructions = vec![ @@ -194,7 +195,7 @@ impl WindowLike for Minesweeper { let tile = &self.tiles[y][x]; if tile.revealed { if tile.mine { - instructions.push(DrawInstructions::Text([x * tile_size + tile_size / 2 + 2, y * tile_size + tile_size / 2], "times-new-roman", "x".to_string(), [255, 0, 0], theme_info.background, None, None)); + instructions.push(DrawInstructions::Text([x * tile_size + tile_size / 2 + 2, y * tile_size + tile_size / 2], "times-new-roman".to_string(), "x".to_string(), [255, 0, 0], theme_info.background, None, None)); } else { let color = match tile.touching { 1 => [0, 0, 255], @@ -207,7 +208,7 @@ impl WindowLike for Minesweeper { //8 _ => [128, 128, 128], }; - instructions.push(DrawInstructions::Text([x * tile_size + tile_size / 2 + 5, y * tile_size + tile_size / 2 + 2], "times-new-roman", tile.touching.to_string(), color, theme_info.background, None, None)); + instructions.push(DrawInstructions::Text([x * tile_size + tile_size / 2 + 5, y * tile_size + tile_size / 2 + 2], "times-new-roman".to_string(), tile.touching.to_string(), color, theme_info.background, None, None)); } } else { let top_left = [x * tile_size + 6, y * tile_size + 5]; @@ -225,15 +226,15 @@ impl WindowLike for Minesweeper { //right bottom DrawInstructions::Rect([top_left[0] + tile_size - 4, top_left[1] + 3], [3, tile_size - 4], [128, 128, 128]), // - DrawInstructions::Text([x * tile_size + tile_size / 2 - 2, y * tile_size + tile_size / 2], "times-new-roman", u8_to_hex((y * 16 + x) as u8), theme_info.text, theme_info.background, None, None), + DrawInstructions::Text([x * tile_size + tile_size / 2 - 2, y * tile_size + tile_size / 2], "times-new-roman".to_string(), u8_to_hex((y * 16 + x) as u8), theme_info.text, theme_info.background, None, None), ]); } } } if self.state == State::Lost { - instructions.extend(vec![DrawInstructions::Text([4, 4], "times-new-roman", "You LOST!!! Press a key to play again.".to_string(), theme_info.text, theme_info.background, None, None)]); + instructions.extend(vec![DrawInstructions::Text([4, 4], "times-new-roman".to_string(), "You LOST!!! Press a key to play again.".to_string(), theme_info.text, theme_info.background, None, None)]); } else if self.state == State::Won { - instructions.extend(vec![DrawInstructions::Text([4, 4], "times-new-roman", "You WON!!! Press a key to play again.".to_string(), theme_info.text, theme_info.background, None, None)]); + instructions.extend(vec![DrawInstructions::Text([4, 4], "times-new-roman".to_string(), "You WON!!! Press a key to play again.".to_string(), theme_info.text, theme_info.background, None, None)]); } instructions } @@ -241,8 +242,8 @@ impl WindowLike for Minesweeper { //properties - fn title(&self) -> &'static str { - "Minesweeper" + fn title(&self) -> String { + "Minesweeper".to_string() } fn subtype(&self) -> WindowLikeType { @@ -349,3 +350,7 @@ impl Minesweeper { // } +pub fn main() { + listen(Minesweeper::new()); +} + diff --git a/src/window_likes/start_menu.rs b/src/bin/start_menu.rs similarity index 93% rename from src/window_likes/start_menu.rs rename to src/bin/start_menu.rs index c7f5e14..c6edb80 100644 --- a/src/window_likes/start_menu.rs +++ b/src/bin/start_menu.rs @@ -1,13 +1,18 @@ +#![allow(warnings)] + use std::vec; use std::vec::Vec; use std::boxed::Box; -use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType }; -use crate::messages::{ WindowMessage, WindowMessageResponse, WindowManagerRequest }; -use crate::framebuffer::Dimensions; -use crate::themes::ThemeInfo; -use crate::components::Component; -use crate::components::highlight_button::HighlightButton; +use ming_wm::window_manager::{ DrawInstructions, WindowLike, WindowLikeType }; +use ming_wm::messages::{ WindowMessage, WindowMessageResponse, WindowManagerRequest }; +use ming_wm::framebuffer::Dimensions; +use ming_wm::themes::ThemeInfo; +use ming_wm::components::Component; +use ming_wm::components::highlight_button::HighlightButton; +use ming_wm::ipc::listen; + +//todo: move to essential static CATEGORIES: [&'static str; 9] = ["About", "Utils", "Games", "Editing", "Files", "System", "Misc", "Help", "Logout"]; @@ -160,7 +165,7 @@ impl StartMenu { }, StartMenuMessage::WindowClick(name) => { //open the selected window - WindowMessageResponse::Request(WindowManagerRequest::OpenWindow(name)) + WindowMessageResponse::Request(WindowManagerRequest::OpenWindow(name.to_string())) }, StartMenuMessage::Back => { self.add_category_components(); @@ -193,3 +198,7 @@ impl StartMenu { } } +pub fn main() { + listen(StartMenu::new()); +} + diff --git a/src/window_likes/terminal.rs b/src/bin/terminal.rs similarity index 91% rename from src/window_likes/terminal.rs rename to src/bin/terminal.rs index 7a27880..d79d435 100644 --- a/src/window_likes/terminal.rs +++ b/src/bin/terminal.rs @@ -4,11 +4,12 @@ use std::process::{ Command, Output }; use std::str::from_utf8; use std::io; -use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType }; -use crate::messages::{ WindowMessage, WindowMessageResponse }; -use crate::framebuffer::Dimensions; -use crate::themes::ThemeInfo; -use crate::utils::concat_paths; +use ming_wm::window_manager::{ DrawInstructions, WindowLike, WindowLikeType }; +use ming_wm::messages::{ WindowMessage, WindowMessageResponse }; +use ming_wm::framebuffer::Dimensions; +use ming_wm::themes::ThemeInfo; +use ming_wm::utils::concat_paths; +use ming_wm::ipc::listen; const MONO_WIDTH: u8 = 10; const LINE_HEIGHT: usize = 15; @@ -92,14 +93,14 @@ impl WindowLike for Terminal { break; } let line = self.actual_lines[line_num].clone(); - instructions.push(DrawInstructions::Text([PADDING, text_y], "times-new-romono", line, theme_info.alt_text, theme_info.alt_background, Some(0), Some(MONO_WIDTH))); + instructions.push(DrawInstructions::Text([PADDING, text_y], "times-new-romono".to_string(), line, theme_info.alt_text, theme_info.alt_background, Some(0), Some(MONO_WIDTH))); text_y += LINE_HEIGHT; } instructions } - fn title(&self) -> &'static str { - "Terminal" + fn title(&self) -> String { + "Terminal".to_string() } fn subtype(&self) -> WindowLikeType { @@ -171,3 +172,7 @@ impl Terminal { } } +pub fn main() { + listen(Terminal::new()); +} + diff --git a/src/bin/test.rs b/src/bin/test.rs new file mode 100644 index 0000000..3ec9335 --- /dev/null +++ b/src/bin/test.rs @@ -0,0 +1,11 @@ +use std::process::{ Command, Stdio }; +use std::io::{ Read, Write }; + +fn main() { + println!("a"); + let mut a = Command::new("cargo").arg("run").arg("-q").arg("--bin").arg("start_menu").stdout(Stdio::piped()).stdin(Stdio::piped()).stderr(Stdio::null()).spawn().unwrap(); + a.stdin.unwrap().write_all("subtype\n".to_string().as_bytes()); + let mut output = String::new(); + a.stdout.as_mut().unwrap().read_to_string(&mut output); + println!("{}", output); +} diff --git a/src/components/highlight_button.rs b/src/components/highlight_button.rs index fca949e..9101c44 100644 --- a/src/components/highlight_button.rs +++ b/src/components/highlight_button.rs @@ -38,12 +38,12 @@ impl Component for HighlightButton { vec![ //highlight background DrawInstructions::Rect(self.top_left, self.size, theme_info.top), - DrawInstructions::Text([self.top_left[0] + 4, self.top_left[1] + (self.size[1] - font_height) / 2], "times-new-roman", self.text.to_string(), theme_info.top_text, theme_info.top, None, None), + DrawInstructions::Text([self.top_left[0] + 4, self.top_left[1] + (self.size[1] - font_height) / 2], "times-new-roman".to_string(), self.text.to_string(), theme_info.top_text, theme_info.top, None, None), ] } else { vec![ DrawInstructions::Rect(self.top_left, self.size, theme_info.background), - DrawInstructions::Text([self.top_left[0] + 4, self.top_left[1] + (self.size[1] - font_height) / 2], "times-new-roman", self.text.to_string(), theme_info.text, theme_info.background, None, None), + DrawInstructions::Text([self.top_left[0] + 4, self.top_left[1] + (self.size[1] - font_height) / 2], "times-new-roman".to_string(), self.text.to_string(), theme_info.text, theme_info.background, None, None), ] } } diff --git a/src/components/toggle_button.rs b/src/components/toggle_button.rs index c519df4..3fcdb1c 100644 --- a/src/components/toggle_button.rs +++ b/src/components/toggle_button.rs @@ -17,7 +17,7 @@ pub struct ToggleButton { name_: String, top_left: Point, size: Dimensions, - text: &'static str, + text: String, draw_bg: bool, pub inverted: bool, //whether is it clicked or not alignment: ToggleButtonAlignment, @@ -54,7 +54,7 @@ impl Component for ToggleButton { //the background if self.draw_bg //DrawInstructions::Rect(), //the text (for now, hardcoded top left) - DrawInstructions::Text([self.top_left[0] + 4, self.top_left[1] + (self.size[1] - font_height) / 2], "times-new-roman", self.text.to_string(), theme_info.text, theme_info.background, None, None), + DrawInstructions::Text([self.top_left[0] + 4, self.top_left[1] + (self.size[1] - font_height) / 2], "times-new-roman".to_string(), self.text.to_string(), theme_info.text, theme_info.background, None, None), ] } @@ -73,7 +73,7 @@ impl Component for ToggleButton { } impl ToggleButton { - pub fn new(name_: String, top_left: Point, size: Dimensions, text: &'static str, click_return: T, unclick_return: T, draw_bg: bool, alignment: Option) -> Self { + pub fn new(name_: String, top_left: Point, size: Dimensions, text: String, click_return: T, unclick_return: T, draw_bg: bool, alignment: Option) -> Self { Self { name_, top_left, diff --git a/src/window_likes/desktop_background.rs b/src/essential/desktop_background.rs similarity index 100% rename from src/window_likes/desktop_background.rs rename to src/essential/desktop_background.rs diff --git a/src/window_likes/lock_screen.rs b/src/essential/lock_screen.rs similarity index 76% rename from src/window_likes/lock_screen.rs rename to src/essential/lock_screen.rs index b1cca50..c5b7be4 100644 --- a/src/window_likes/lock_screen.rs +++ b/src/essential/lock_screen.rs @@ -50,11 +50,11 @@ impl WindowLike for LockScreen { fn draw(&self, _theme_info: &ThemeInfo) -> Vec { vec![ DrawInstructions::Rect([0, 0], self.dimensions, [0, 0, 0]), - DrawInstructions::Text([4, 4], "times-new-roman", "The bulldozer outside the kitchen window was quite a big one.".to_string(), [255, 255, 255], [0, 0, 0], None, None), - DrawInstructions::Text([4, 4 + 16], "times-new-roman", "\"Yellow,\" he thought, and stomped off back to his bedroom to get dressed.".to_string(), [255, 255, 255], [0, 0, 0], None, None), - DrawInstructions::Text([4, 4 + 16 * 2], "times-new-roman", "He stared at it.".to_string(), [255, 255, 255], [0, 0, 0], None, None), - DrawInstructions::Text([4, 4 + 16 * 3], "times-new-roman", "Password: ".to_string(), [255, 255, 255], [0, 0, 0], None, None), - DrawInstructions::Text([77, 4 + 16 * 3], "times-new-roman", "*".repeat(self.input_password.len()), [255, 255, 255], [0, 0, 0], None, None), + DrawInstructions::Text([4, 4], "times-new-roman".to_string(), "The bulldozer outside the kitchen window was quite a big one.".to_string(), [255, 255, 255], [0, 0, 0], None, None), + DrawInstructions::Text([4, 4 + 16], "times-new-roman".to_string(), "\"Yellow,\" he thought, and stomped off back to his bedroom to get dressed.".to_string(), [255, 255, 255], [0, 0, 0], None, None), + DrawInstructions::Text([4, 4 + 16 * 2], "times-new-roman".to_string(), "He stared at it.".to_string(), [255, 255, 255], [0, 0, 0], None, None), + DrawInstructions::Text([4, 4 + 16 * 3], "times-new-roman".to_string(), "Password: ".to_string(), [255, 255, 255], [0, 0, 0], None, None), + DrawInstructions::Text([77, 4 + 16 * 3], "times-new-roman".to_string(), "*".repeat(self.input_password.len()), [255, 255, 255], [0, 0, 0], None, None), ] } diff --git a/src/essential/mod.rs b/src/essential/mod.rs new file mode 100644 index 0000000..b80c7a5 --- /dev/null +++ b/src/essential/mod.rs @@ -0,0 +1,5 @@ +pub mod desktop_background; +pub mod taskbar; +pub mod lock_screen; +pub mod workspace_indicator; + diff --git a/src/window_likes/taskbar.rs b/src/essential/taskbar.rs similarity index 89% rename from src/window_likes/taskbar.rs rename to src/essential/taskbar.rs index bdaadc2..cbbaae8 100644 --- a/src/window_likes/taskbar.rs +++ b/src/essential/taskbar.rs @@ -33,7 +33,7 @@ impl WindowLike for Taskbar { WindowMessage::Init(dimensions) => { self.dimensions = dimensions; self.components = vec![ - Box::new(ToggleButton::new("start-button".to_string(), [PADDING, PADDING], [44, self.dimensions[1] - (PADDING * 2)], "Start", TaskbarMessage::ShowStartMenu, TaskbarMessage::HideStartMenu, false, Some(ToggleButtonAlignment::Left))), + Box::new(ToggleButton::new("start-button".to_string(), [PADDING, PADDING], [44, self.dimensions[1] - (PADDING * 2)], "Start".to_string(), TaskbarMessage::ShowStartMenu, TaskbarMessage::HideStartMenu, false, Some(ToggleButtonAlignment::Left))), ]; WindowMessageResponse::JustRerender }, @@ -79,7 +79,8 @@ impl WindowLike for Taskbar { break; } let info = &self.windows_in_workspace[wi]; - let mut b = ToggleButton::new(info.1.to_string() + "-window", [PADDING * 2 + 44 + (META_WIDTH + PADDING) * wi, PADDING], [META_WIDTH, self.dimensions[1] - (PADDING * 2)], info.1, TaskbarMessage::Nothing, TaskbarMessage::Nothing, false, Some(ToggleButtonAlignment::Left)); + let name = &info.1; + let mut b = ToggleButton::new(name.to_string() + "-window", [PADDING * 2 + 44 + (META_WIDTH + PADDING) * wi, PADDING], [META_WIDTH, self.dimensions[1] - (PADDING * 2)], name.to_string(), TaskbarMessage::Nothing, TaskbarMessage::Nothing, false, Some(ToggleButtonAlignment::Left)); b.inverted = info.0 == self.focused_id; instructions.extend(b.draw(theme_info)); } @@ -110,7 +111,7 @@ impl Taskbar { if let Some(message) = message { match message { TaskbarMessage::ShowStartMenu => { - WindowMessageResponse::Request(WindowManagerRequest::OpenWindow("StartMenu")) + WindowMessageResponse::Request(WindowManagerRequest::OpenWindow("StartMenu".to_string())) }, TaskbarMessage::HideStartMenu => { WindowMessageResponse::Request(WindowManagerRequest::CloseStartMenu) diff --git a/src/window_likes/workspace_indicator.rs b/src/essential/workspace_indicator.rs similarity index 90% rename from src/window_likes/workspace_indicator.rs rename to src/essential/workspace_indicator.rs index 3433f35..3c61d82 100644 --- a/src/window_likes/workspace_indicator.rs +++ b/src/essential/workspace_indicator.rs @@ -44,9 +44,9 @@ impl WindowLike for WorkspaceIndicator { for w in 0..9 { if w == self.current_workspace as usize { instructions.push(DrawInstructions::Rect([w * WIDTH, 0], [WIDTH, self.dimensions[1]], theme_info.top)); - instructions.push(DrawInstructions::Text([w * WIDTH + 5, 4], "times-new-roman", (w + 1).to_string(), theme_info.top_text, theme_info.top, None, None)); + instructions.push(DrawInstructions::Text([w * WIDTH + 5, 4], "times-new-roman".to_string(), (w + 1).to_string(), theme_info.top_text, theme_info.top, None, None)); } else { - instructions.push(DrawInstructions::Text([w * WIDTH + 5, 4], "times-new-roman", (w + 1).to_string(), theme_info.text, theme_info.background, None, None)); + instructions.push(DrawInstructions::Text([w * WIDTH + 5, 4], "times-new-roman".to_string(), (w + 1).to_string(), theme_info.text, theme_info.background, None, None)); } } instructions diff --git a/src/ipc.rs b/src/ipc.rs new file mode 100644 index 0000000..0171415 --- /dev/null +++ b/src/ipc.rs @@ -0,0 +1,51 @@ +use std::io::{ stdin, BufRead }; + +//use serde::{ Deserialize, Serialize }; +use ron; + +use crate::window_manager::WindowLike; + +/* +pub trait WindowLike { + fn handle_message(&mut self, message: WindowMessage) -> WindowMessageResponse; + + fn draw(&self, theme_info: &ThemeInfo) -> Vec; + + //properties + fn title(&self) -> &'static str { + "" + } + + fn resizable(&self) -> bool { + false + } + + fn subtype(&self) -> WindowLikeType; + + fn ideal_dimensions(&self, dimensions: Dimensions) -> Dimensions; //needs &self or its not object safe or some bullcrap +} +*/ + +pub fn listen(mut window_like: impl WindowLike) { + let mut stdin = stdin(); + for line in stdin.lock().lines() { + let line = line.unwrap().clone(); + let mut parts = line.split(" "); + let method = parts.next().unwrap(); + let arg = &parts.collect::>().join(" "); + if method == "handle_message" { + println!("{}", ron::to_string(&window_like.handle_message(ron::from_str(arg).unwrap())).unwrap()); + } else if method == "draw" { + println!("{}", ron::to_string(&window_like.draw(&ron::from_str(arg).unwrap())).unwrap()); + } else if method == "title" { + println!("{}", window_like.title()); + } else if method == "resizable" { + println!("{}", window_like.resizable()); + } else if method == "subtype" { + println!("{}", ron::to_string(&window_like.subtype()).unwrap()); + } else if method == "ideal_dimensions" { + println!("{:?}", window_like.ideal_dimensions(ron::from_str(arg).unwrap())); + } + } +} + diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d53a6f6 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,12 @@ +pub mod framebuffer; +pub mod window_manager; +pub mod components; +pub mod themes; +pub mod messages; +pub mod fs; +pub mod utils; +pub mod ipc; +mod proxy_window_like; +mod keyboard; +mod essential; + diff --git a/src/messages.rs b/src/messages.rs index 5451cff..7d77e5c 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -2,6 +2,8 @@ use std::boxed::Box; use std::fmt; use std::vec::Vec; +use serde::{ Deserialize, Serialize }; + use crate::keyboard::KeyChar; use crate::framebuffer::Dimensions; use crate::window_manager::WindowLike; @@ -22,9 +24,9 @@ impl PartialEq for WindowBox { } */ -#[derive(PartialEq)] +#[derive(PartialEq, Serialize, Deserialize)] pub enum WindowManagerRequest { - OpenWindow(&'static str), + OpenWindow(String), CloseStartMenu, Unlock, Lock, @@ -37,19 +39,20 @@ impl fmt::Debug for WindowManagerRequest{ } } -#[derive(PartialEq, Debug)] +#[derive(PartialEq, Debug, Serialize, Deserialize)] pub enum WindowMessageResponse { Request(WindowManagerRequest), JustRerender, DoNothing, } +#[derive(Serialize, Deserialize)] pub struct KeyPress { pub key: char, // } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Serialize, Deserialize)] pub enum Direction { Left, Down, @@ -58,7 +61,7 @@ pub enum Direction { } //todo, rename to CommandType -#[derive(PartialEq)] +#[derive(PartialEq, Serialize, Deserialize)] pub enum ShortcutType { StartMenu, SwitchWorkspace(u8), @@ -74,14 +77,16 @@ pub enum ShortcutType { // } -pub type WindowsVec = Vec<(usize, &'static str)>; +pub type WindowsVec = Vec<(usize, String)>; +#[derive(Serialize, Deserialize)] pub enum InfoType { //let taskbar know what the current windows in the workspace are WindowsInWorkspace(WindowsVec, usize), //Vec, focused id // } +#[derive(Serialize, Deserialize)] pub enum WindowMessage { Init(Dimensions), KeyPress(KeyPress), diff --git a/src/proxy_window_like.rs b/src/proxy_window_like.rs new file mode 100644 index 0000000..aa51eb2 --- /dev/null +++ b/src/proxy_window_like.rs @@ -0,0 +1,79 @@ +use std::vec::Vec; +use std::process::{ Command, Child, Stdio }; +use std::io::{ BufReader, BufRead, Read, Write }; +use std::cell::RefCell; + +use ron; + +use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType }; +use crate::messages::{ WindowMessage, WindowMessageResponse }; +use crate::framebuffer::Dimensions; +use crate::themes::ThemeInfo; + +pub struct ProxyWindowLike { + process: RefCell, +} + +impl WindowLike for ProxyWindowLike { + fn handle_message(&mut self, message: WindowMessage) -> WindowMessageResponse { + self.process.borrow_mut().stdin.as_mut().unwrap().write_all(("handle_message ".to_string() + &ron::to_string(&message).unwrap() + "\n").as_bytes()); + let output = self.read_line(); + ron::from_str(&output).unwrap() + } + + fn draw(&self, theme_info: &ThemeInfo) -> Vec { + self.process.borrow_mut().stdin.as_mut().unwrap().write_all(("draw ".to_string() + &ron::to_string(&theme_info).unwrap() + "\n").as_bytes()); + let output = self.read_line(); + ron::from_str(&output).unwrap() + } + + //properties + fn title(&self) -> String { + self.process.borrow_mut().stdin.as_mut().unwrap().write_all("title\n".as_bytes()); + self.read_line() + } + + fn resizable(&self) -> bool { + self.process.borrow_mut().stdin.as_mut().unwrap().write_all("resizable\n".to_string().as_bytes()); + let output = self.read_line(); + ron::from_str(&output).unwrap() + } + + fn subtype(&self) -> WindowLikeType { + self.process.borrow_mut().stdin.as_mut().unwrap().write_all("subtype\n".to_string().as_bytes()); + let output = self.read_line(); + ron::from_str(&output).unwrap() + } + + fn ideal_dimensions(&self, dimensions: Dimensions) -> Dimensions { + self.process.borrow_mut().stdin.as_mut().unwrap().write_all(("ideal_dimensions".to_string() + &ron::to_string(&dimensions).unwrap() + "\n").as_bytes()); + let output = self.read_line(); + ron::from_str(&output).unwrap() + } +} + +//kill process when this window like dropped +impl Drop for ProxyWindowLike { + fn drop(&mut self) { + self.process.borrow_mut().kill(); + } +} + +impl ProxyWindowLike { + pub fn new(file: &str) -> Self { + ProxyWindowLike { + //--quiet + process: RefCell::new(Command::new("cargo").arg("run").arg("--quiet").arg("--release").arg("--bin").arg(file).stdout(Stdio::piped()).stdin(Stdio::piped()).stderr(Stdio::null()).spawn().unwrap()), + } + } + + fn read_line(&self) -> String { + let mut output = String::new(); + let mut buffer = self.process.borrow_mut(); + let buffer = buffer.stdout.as_mut().unwrap(); + let mut reader = BufReader::new(buffer); + reader.read_line(&mut output).unwrap(); + output + } +} + diff --git a/src/themes.rs b/src/themes.rs index 8343fe0..2b36399 100644 --- a/src/themes.rs +++ b/src/themes.rs @@ -1,3 +1,5 @@ +use serde::{ Deserialize, Serialize }; + use crate::framebuffer::RGBColor; #[derive(PartialEq, Default)] @@ -7,6 +9,7 @@ pub enum Themes { // } +#[derive(Serialize, Deserialize)] pub struct ThemeInfo { pub top: RGBColor, pub background: RGBColor, diff --git a/src/window_likes/mod.rs b/src/window_likes/mod.rs deleted file mode 100644 index 39676c6..0000000 --- a/src/window_likes/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub mod desktop_background; -pub mod taskbar; -pub mod start_menu; -pub mod lock_screen; -pub mod workspace_indicator; - -pub mod minesweeper; -pub mod terminal; -pub mod malvim; -pub mod audio_player; - diff --git a/src/window_manager.rs b/src/window_manager.rs index b632c24..a0b95e1 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -11,21 +11,17 @@ use linux_framebuffer::Framebuffer; use termion::input::TermRead; use termion::raw::IntoRawMode; use termion::cursor; +use serde::{ Deserialize, Serialize }; use crate::framebuffer::{ FramebufferWriter, FramebufferInfo, Point, Dimensions, RGBColor }; -use crate::window_likes::desktop_background::DesktopBackground; -use crate::window_likes::taskbar::Taskbar; -use crate::window_likes::lock_screen::LockScreen; -use crate::window_likes::workspace_indicator::WorkspaceIndicator; use crate::themes::{ ThemeInfo, Themes, get_theme_info }; use crate::keyboard::{ KeyChar, key_to_char }; use crate::messages::*; - -use crate::window_likes::start_menu::StartMenu; -use crate::window_likes::minesweeper::Minesweeper; -use crate::window_likes::terminal::Terminal; -use crate::window_likes::malvim::Malvim; -use crate::window_likes::audio_player::AudioPlayer; +use crate::proxy_window_like::ProxyWindowLike; +use crate::essential::desktop_background::DesktopBackground; +use crate::essential::taskbar::Taskbar; +use crate::essential::lock_screen::LockScreen; +use crate::essential::workspace_indicator::WorkspaceIndicator; //todo, better error handling for windows @@ -71,15 +67,15 @@ pub fn min(one: usize, two: usize) -> usize { if one > two { two } else { one } } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub enum DrawInstructions { Rect(Point, Dimensions, RGBColor), - Text(Point, &'static str, String, RGBColor, RGBColor, Option, Option), //font and text + Text(Point, String, String, RGBColor, RGBColor, Option, Option), //font and text Gradient(Point, Dimensions, RGBColor, RGBColor, usize), Mingde(Point), } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub enum WindowLikeType { LockScreen, Window, @@ -92,15 +88,18 @@ pub enum WindowLikeType { pub trait WindowLike { fn handle_message(&mut self, message: WindowMessage) -> WindowMessageResponse; + fn draw(&self, theme_info: &ThemeInfo) -> Vec; + //properties - fn title(&self) -> &'static str { - "" + fn title(&self) -> String { + String::new() } + fn resizable(&self) -> bool { false } + fn subtype(&self) -> WindowLikeType; - fn draw(&self, theme_info: &ThemeInfo) -> Vec; fn ideal_dimensions(&self, dimensions: Dimensions) -> Dimensions; //needs &self or its not object safe or some bullcrap } @@ -222,7 +221,7 @@ impl WindowManager { fn taskbar_update_windows(&mut self) { let taskbar_index = self.window_infos.iter().position(|w| w.window_like.subtype() == WindowLikeType::Taskbar).unwrap(); - let mut relevant: WindowsVec = self.get_windows_in_workspace(false).iter().map(|w| (w.id, w.window_like.title())).collect(); + let mut relevant: WindowsVec = self.get_windows_in_workspace(false).iter().map(|w| (w.id, w.window_like.title().to_string())).collect(); relevant.sort_by(|a, b| a.0.cmp(&b.0)); //sort by ids so order is consistent let message = WindowMessage::Info(InfoType::WindowsInWorkspace( relevant, @@ -500,13 +499,13 @@ impl WindowManager { if subtype != WindowLikeType::Taskbar && subtype != WindowLikeType::StartMenu { return; } - let w: WindowBox = match w { - "Minesweeper" => Box::new(Minesweeper::new()), - "Malvim" => Box::new(Malvim::new()), - "Terminal" => Box::new(Terminal::new()), - "Audio Player" => Box::new(AudioPlayer::new()), - "StartMenu" => Box::new(StartMenu::new()), - _ => panic!("no such window"), + let w: WindowBox = match w.as_str() { + "Minesweeper" => Box::new(ProxyWindowLike::new("minesweeper")), + "Malvim" => Box::new(ProxyWindowLike::new("malvim")), + "Terminal" => Box::new(ProxyWindowLike::new("terminal")), + "Audio Player" => Box::new(ProxyWindowLike::new("audio_player")), + "StartMenu" => Box::new(ProxyWindowLike::new("start_menu")), + _ => panic!("window not found"), //todo: do not panic }; //close start menu if open self.toggle_start_menu(true); @@ -588,7 +587,7 @@ impl WindowManager { instructions = instructions.iter().map(|instruction| { match instruction { DrawInstructions::Rect(top_left, dimensions, color) => DrawInstructions::Rect(WindowManager::get_true_top_left(top_left, is_window), *dimensions, *color), - DrawInstructions::Text(top_left, font_name, text, color, bg_color, horiz_spacing, mono_width) => DrawInstructions::Text(WindowManager::get_true_top_left(top_left, is_window), font_name, text.clone(), *color, *bg_color, *horiz_spacing, *mono_width), + DrawInstructions::Text(top_left, font_name, text, color, bg_color, horiz_spacing, mono_width) => DrawInstructions::Text(WindowManager::get_true_top_left(top_left, is_window), font_name.clone(), text.clone(), *color, *bg_color, *horiz_spacing, *mono_width), DrawInstructions::Mingde(top_left) => DrawInstructions::Mingde(WindowManager::get_true_top_left(top_left, is_window)), DrawInstructions::Gradient(top_left, dimensions, start_color, end_color, steps) => DrawInstructions::Gradient(WindowManager::get_true_top_left(top_left, is_window), *dimensions, *start_color, *end_color, *steps), } @@ -602,7 +601,7 @@ impl WindowManager { DrawInstructions::Rect([0, 0], [1, window_dimensions[1]], theme_info.border_left_top), //top DrawInstructions::Rect([1, 1], [window_dimensions[0] - 2, WINDOW_TOP_HEIGHT - 3], theme_info.top), - DrawInstructions::Text([4, 4], "times-new-roman", window_info.window_like.title().to_string(), theme_info.top_text, theme_info.top, None, None), + DrawInstructions::Text([4, 4], "times-new-roman".to_string(), window_info.window_like.title().to_string(), theme_info.top_text, theme_info.top, None, None), //top bottom border DrawInstructions::Rect([1, WINDOW_TOP_HEIGHT - 2], [window_dimensions[0] - 2, 2], theme_info.border_left_top), //right bottom border @@ -632,7 +631,7 @@ impl WindowManager { window_writer.draw_rect(top_left, true_dimensions, color); }, DrawInstructions::Text(top_left, font_name, text, color, bg_color, horiz_spacing, mono_width) => { - window_writer.draw_text(top_left, font_name, &text, color, bg_color, horiz_spacing.unwrap_or(1), mono_width); + window_writer.draw_text(top_left, &font_name, &text, color, bg_color, horiz_spacing.unwrap_or(1), mono_width); }, DrawInstructions::Mingde(top_left) => { window_writer._draw_mingde(top_left);