dynamically find window binaries instead of hardcode

also, terminal compile fix whoops
This commit is contained in:
stjet
2025-03-02 07:45:36 +00:00
parent 1a5eba7191
commit 1b9922d70f
18 changed files with 172 additions and 81 deletions

1
.gitignore vendored
View File

@@ -2,5 +2,6 @@ target/
Cargo.lock Cargo.lock
ming-wm ming-wm
password.txt password.txt
password.env
bmps/ignore-*.bmp bmps/ignore-*.bmp
*.alpha *.alpha

View File

@@ -2,7 +2,7 @@
name = "ming-wm" name = "ming-wm"
version = "0.1.0" version = "0.1.0"
edition = "2024" edition = "2024"
default-run = "main" default-run = "ming"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -32,13 +32,32 @@ audio_player = [ "id3", "mp4ameta", "metaflac", "rand", "rodio" ]
lto = true lto = true
[[bin]] [[bin]]
name = "main" name = "ming"
path = "src/bin/main.rs"
required-features = [ "main" ] required-features = [ "main" ]
[[bin]] [[bin]]
name = "audio_player" name = "mingFiles_Audio_Player"
path = "src/bin/audio_player.rs"
required-features = [ "audio_player" ] required-features = [ "audio_player" ]
[[bin]] [[bin]]
name = "terminal" name = "mingGames_Minesweeper"
path = "src/bin/minesweeper.rs"
[[bin]]
name = "mingUtils_Terminal"
path = "src/bin/terminal.rs"
required-features = [ "terminal" ] required-features = [ "terminal" ]
[[bin]]
name = "mingFiles_File_Explorer"
path = "src/bin/file_explorer.rs"
[[bin]]
name = "mingEditing_Malvim"
path = "src/bin/malvim.rs"
[[bin]]
name = "mingGames_Reversi"
path = "src/bin/reversi.rs"

View File

@@ -3,22 +3,37 @@ Ming-wm is a keyboard-based, retro-themed window manager for Linux. It is single
![example 1](/docs/images/ws1.png) ![example 1](/docs/images/ws1.png)
![example 2](/docs/images/ws3.png) ![example 2](/docs/images/ws3.png)
## Running ## Building
Create a `password.txt` file in the same directory as `build.rs`, otherwise the default password will be "incorrect mule lightbulb niche". Create a `password.env` file in the same directory as `build.rs`, otherwise the default password will be "incorrect mule lightbulb niche".
For best performance: For best performance:
``` ```
cargo build --release --all-features cargo build --release --all-features
# Either,
./target/release/main
# or
cargo run --release
``` ```
The user may need to be added to the `video` group.
Exclude `--all-features` if the audio player window is not needed. To compile and use the audio player window, ALSA dev packages need to be installed (`alsa-lib-dev` on Alpine, `libasound2-dev` on Debian, `alsa-lib-devl` on Fedora, already included with `alsa-lib` on Arch). Exclude `--all-features` if the audio player window is not needed. To compile and use the audio player window, ALSA dev packages need to be installed (`alsa-lib-dev` on Alpine, `libasound2-dev` on Debian, `alsa-lib-devl` on Fedora, already included with `alsa-lib` on Arch).
### Running on Mobile Linux ## Installing
After building, to properly install ming-wm, run the following to put the necessary binaries, font data, and bmp files into `/usr/local/bin`:
```bash
chmod +x ./install
sudo ./install
```
Alternatively, to move the binaries to `~/.local/bin` (which probably needs to be added to `PATH`, run the following:
```bash
chmod +x local-install
sudo ./local-install
```
## Running on Mobile Linux
Running with an onscreen keyboard. The framebuffer may not be redrawn to the screen without a (real) key press. The volume down button seems to work. Running with an onscreen keyboard. The framebuffer may not be redrawn to the screen without a (real) key press. The volume down button seems to work.
@@ -26,22 +41,30 @@ Running with an onscreen keyboard. The framebuffer may not be redrawn to the scr
``` ```
cargo build --release cargo build --release
./target/release/main touch ./target/release/ming touch
``` ```
Optionally, in landscape mode (todo: osk may be broken in landscape mode): Optionally, in landscape mode (todo: osk may be broken in landscape mode):
``` ```
cargo build --release cargo build --release
./target/release/main touch rotate ./target/release/ming touch rotate
``` ```
After testing, the install scripts in the previous section can be used.
![mobile example](/docs/images/mobile.png) ![mobile example](/docs/images/mobile.png)
## Philosophy ## Philosophy
See [/docs/philosophy.md](/docs/philosophy.md) for some hopefully interesting ramblings. See [/docs/philosophy.md](/docs/philosophy.md) for some hopefully interesting ramblings.
## Security
Make sure the permissions of `password.env` are so other users cannot read or write to it. If there is no plan to recompile, just delete it.
Obviously, don't run the executable with `sudo` or `doas`, or as the root user!
## License ## License
Licensed under the GPLv3. The font data in the `bmps/shippori-mincho` folder are covered by the OFL. The font was created by FONTDASU. The font data in `bmps/nimbus-roman` are licensed under the AGPL. This is a very slightly modified version of the font was created by URW Studio. The font data in `bmps/nimbus-romono` is also licensed under the AGPL. This is a slightly modified version of the Nimbus Roman font by URW Studio. Licensed under the GPLv3. The font data in the `bmps/shippori-mincho` folder are covered by the OFL. The font was created by FONTDASU. The font data in `bmps/nimbus-roman` are licensed under the AGPL. This is a very slightly modified version of the font was created by URW Studio. The font data in `bmps/nimbus-romono` is also licensed under the AGPL. This is a slightly modified version of the Nimbus Roman font by URW Studio.

View File

@@ -2,6 +2,7 @@ use std::fs::{ read_dir, read_to_string, write, File };
use std::io::Write; use std::io::Write;
use std::env; use std::env;
use std::path::Path; use std::path::Path;
use std::process::Command;
use blake2::{ Blake2b512, Digest }; use blake2::{ Blake2b512, Digest };
use bmp_rust::bmp::BMP; use bmp_rust::bmp::BMP;
@@ -48,7 +49,7 @@ fn font_chars_to_alphas(dir: &str) {
fn main() { fn main() {
//hash + "salt" password and add to build //hash + "salt" password and add to build
let password = read_to_string("password.txt").unwrap_or("incorrect mule lightbulb niche".to_string()).replace("\n", "") + "salt?sorrycryptographers"; let password = read_to_string("password.env").unwrap_or("incorrect mule lightbulb niche".to_string()).replace("\n", "") + "salt?sorrycryptographers";
let mut hasher = Blake2b512::new(); let mut hasher = Blake2b512::new();
hasher.update(password.as_bytes()); hasher.update(password.as_bytes());
let out_dir = env::var_os("OUT_DIR").unwrap(); let out_dir = env::var_os("OUT_DIR").unwrap();
@@ -61,4 +62,7 @@ fn main() {
font_chars_to_alphas(path.to_str().unwrap()); font_chars_to_alphas(path.to_str().unwrap());
} }
} }
//copy bmp folders to target
let profile = env::var_os("PROFILE").unwrap().to_string_lossy().to_string();
Command::new("cp").arg("-r").arg("./bmps").arg(format!("./target/{}/bmps", profile)).output().unwrap();
} }

View File

@@ -8,16 +8,16 @@ In `$XDG_CONFIG_DIR/ming-wm/desktop-background`, you can configure what the desk
If a line starts with "#", and is followed by 6 lowercase hex characters, then it will interpreted as a RGB colour. If a line starts with "#", and is followed by 6 lowercase hex characters, then it will interpreted as a RGB colour.
If a line starts with "r", then what follows with be interpreted as a path to a BMP image file in BGRA order, and if it starts with any other character, what follows will be interpreted as a path to a BMP image file in RGBA order. If a line starts with "r", then what follows with be interpreted as a path to a BMP image file in BGRA order, and if it starts with any other character, what follows will be interpreted as a path to a BMP image file in RGBA order. The path should be absolute.
Example: Example:
``` ```
#008080 #008080
#003153 #003153
r./bmps/castle1440x842.bmp r/home/username/Pictures/castle1440x842.bmp
r./bmps/ming1440x842.bmp r/home/username/Pictures/ming1440x842.bmp
r./bmps/blur1440x842.bmp r/home/username/Pictures/blur1440x842.bmp
``` ```
## Unrelated: Themes Config ## Unrelated: Themes Config

View File

@@ -15,6 +15,10 @@ Once a command is entered, hit 'enter' to execute it. The terminal will change i
In STDIN mode, any keys typed followed by the 'enter' key will send those keys to the command's STDIN, if it is still running. To escape STDIN mode, use the `esc` key. In STDIN mode, any keys typed followed by the 'enter' key will send those keys to the command's STDIN, if it is still running. To escape STDIN mode, use the `esc` key.
### Sudo
To get sudo to read from stdin, the `-S` option will need to be used (eg, `sudo -S ls`). Also, the password prompt will not show since the terminal is line-buffered. Just switch to STDIN mode, type in the password and hit enter.
## Copy / Paste ## Copy / Paste
This window-like supports the paste [shortcut](../system/shortcuts.md) (`Alt+P`) if in INPUT or STDIN mode. This window-like supports the paste [shortcut](../system/shortcuts.md) (`Alt+P`) if in INPUT or STDIN mode.

9
install Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/bash
cp -r ./target/release/bmps /usr/local/bin/bmps
cp ./target/release/ming /usr/local/bin/ming
cp ./target/release/mingUtils_Terminal /usr/local/bin/mingUtils_Terminal
cp ./target/release/mingGames_Reversi /usr/local/bin/mingGames_Reversi
cp ./target/release/mingGames_Minesweeper /usr/local/bin/mingGames_Minesweeper
cp ./target/release/mingFiles_File_Explorer /usr/local/bin/mingFiles_File_Explorer
cp ./target/release/mingFiles_Audio_Player /usr/local/bin/mingFiles_Audio_Player
cp ./target/release/mingEditing_Malvim /usr/local/bin/mingEditing_Malvim

9
local-install Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/bash
cp -r ./target/release/bmps ~/.local/bin/bmps
cp ./target/release/ming ~/.local/bin/ming
cp ./target/release/mingUtils_Terminal ~/.local/bin/mingUtils_Terminal
cp ./target/release/mingGames_Reversi ~/.local/bin/mingGames_Reversi
cp ./target/release/mingGames_Minesweeper ~/.local/bin/mingGames_Minesweeper
cp ./target/release/mingFiles_File_Explorer ~/.local/bin/mingFiles_File_Explorer
cp ./target/release/mingFiles_Audio_Player ~/.local/bin/mingFiles_Audio_Player
cp ./target/release/mingEditing_Malvim ~/.local/bin/mingEditing_Malvim

View File

@@ -242,6 +242,8 @@ impl AudioPlayer {
if new_path.exists() { if new_path.exists() {
self.base_directory = new_path.to_str().unwrap().to_string(); self.base_directory = new_path.to_str().unwrap().to_string();
return "Set new base directory".to_string(); return "Set new base directory".to_string();
} else {
return "Failed to set new base directory".to_string();
} }
} }
} }

View File

@@ -11,7 +11,7 @@ use std::fmt;
use pty_process::blocking; use pty_process::blocking;
use ming_wm::window_manager::{ DrawInstructions, WindowLike, WindowLikeType }; use ming_wm::window_manager::{ DrawInstructions, WindowLike, WindowLikeType };
use ming_wm::messages::{ WindowMessage, WindowMessageResponse }; use ming_wm::messages::{ WindowMessage, WindowMessageResponse, ShortcutType };
use ming_wm::framebuffer::Dimensions; use ming_wm::framebuffer::Dimensions;
use ming_wm::themes::ThemeInfo; use ming_wm::themes::ThemeInfo;
use ming_wm::utils::{ concat_paths, Substring }; use ming_wm::utils::{ concat_paths, Substring };
@@ -202,9 +202,9 @@ impl WindowLike for Terminal {
ShortcutType::ClipboardPaste(copy_string) => { ShortcutType::ClipboardPaste(copy_string) => {
if self.mode == Mode::Input || self.mode == Mode::Stdin { if self.mode == Mode::Input || self.mode == Mode::Stdin {
if self.mode == Mode::Input { if self.mode == Mode::Input {
self.current_input += copy_string; self.current_input += &copy_string;
} else { } else {
self.current_stdin_input += copy_string; self.current_stdin_input += &copy_string;
} }
self.calc_actual_lines(); self.calc_actual_lines();
WindowMessageResponse::JustRedraw WindowMessageResponse::JustRedraw
@@ -224,7 +224,7 @@ impl WindowLike for Terminal {
DrawInstructions::Rect([0, 0], self.dimensions, theme_info.alt_background), DrawInstructions::Rect([0, 0], self.dimensions, theme_info.alt_background),
]; ];
//add the visible lines of text //add the visible lines of text
let end_line = self.actual_line_num + self.get_max_lines() - 1; let end_line = self.actual_line_num + self.get_max_lines();
let mut text_y = PADDING; let mut text_y = PADDING;
for line_num in self.actual_line_num..end_line { for line_num in self.actual_line_num..end_line {
if line_num == self.actual_lines.len() { if line_num == self.actual_lines.len() {
@@ -261,7 +261,7 @@ impl Terminal {
} }
fn get_max_lines(&self) -> usize { fn get_max_lines(&self) -> usize {
(self.dimensions[1] - PADDING * 2) / LINE_HEIGHT (self.dimensions[1] - PADDING * 2 - LINE_HEIGHT) / LINE_HEIGHT
} }
fn process_command(&mut self) -> Mode { fn process_command(&mut self) -> Mode {

View File

@@ -11,7 +11,7 @@ pub struct HighlightButton<T> {
name_: String, name_: String,
top_left: Point, top_left: Point,
size: Dimensions, size: Dimensions,
text: String, pub text: String,
pub highlighted: bool, pub highlighted: bool,
click_return: T, click_return: T,
toggle_highlight_return: T, //also unhighlight return toggle_highlight_return: T, //also unhighlight return

View File

@@ -38,3 +38,12 @@ pub fn config_dir() -> Option<PathBuf> {
} }
} }
pub fn exe_dir(add: Option<&str>) -> PathBuf {
let mut exe_dir = env::current_exe().unwrap();
exe_dir.pop();
if let Some(add) = add {
exe_dir.push(add);
}
exe_dir
}

View File

@@ -6,15 +6,17 @@ use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType };
use crate::messages::{ WindowMessage, WindowMessageResponse, WindowManagerRequest }; use crate::messages::{ WindowMessage, WindowMessageResponse, WindowManagerRequest };
use crate::framebuffer::Dimensions; use crate::framebuffer::Dimensions;
use crate::themes::ThemeInfo; use crate::themes::ThemeInfo;
use crate::fs::{ ExeWindowInfos, get_all_executable_windows };
use crate::components::Component; use crate::components::Component;
use crate::components::highlight_button::HighlightButton; use crate::components::highlight_button::HighlightButton;
use crate::dirs::exe_dir;
static CATEGORIES: [&'static str; 9] = ["About", "Utils", "Games", "Editing", "Files", "Internet", "Misc", "Help", "Logout"]; static CATEGORIES: [&'static str; 9] = ["About", "Utils", "Games", "Editing", "Files", "Internet", "Misc", "Help", "Logout"];
#[derive(Clone)] #[derive(Clone)]
enum StartMenuMessage { enum StartMenuMessage {
CategoryClick(&'static str), CategoryClick(&'static str),
WindowClick(&'static str), WindowClick(String),
Back, Back,
ChangeAcknowledge, ChangeAcknowledge,
} }
@@ -22,7 +24,8 @@ enum StartMenuMessage {
#[derive(Default)] #[derive(Default)]
pub struct StartMenu { pub struct StartMenu {
dimensions: Dimensions, dimensions: Dimensions,
components: Vec<Box<dyn Component<StartMenuMessage> + Send>>, executable_windows: ExeWindowInfos,
components: Vec<Box<HighlightButton<StartMenuMessage>>>,
current_focus: String, current_focus: String,
y_each: usize, y_each: usize,
} }
@@ -34,6 +37,7 @@ impl WindowLike for StartMenu {
self.dimensions = dimensions; self.dimensions = dimensions;
self.y_each = (self.dimensions[1] - 1) / CATEGORIES.len(); self.y_each = (self.dimensions[1] - 1) / CATEGORIES.len();
self.add_category_components(); self.add_category_components();
self.executable_windows = get_all_executable_windows();
WindowMessageResponse::JustRedraw WindowMessageResponse::JustRedraw
}, },
WindowMessage::KeyPress(key_press) => { WindowMessage::KeyPress(key_press) => {
@@ -69,7 +73,7 @@ impl WindowLike for StartMenu {
let current_focus_index = self.get_focus_index().unwrap(); let current_focus_index = self.get_focus_index().unwrap();
if key_press.key.is_lowercase() { if key_press.key.is_lowercase() {
//look forwards to see category/window that starts with that char //look forwards to see category/window that starts with that char
if let Some(n_index) = self.components[current_focus_index..].iter().position(|c| c.name().chars().next().unwrap_or('𐘂').to_lowercase().next().unwrap() == key_press.key) { if let Some(n_index) = self.components[current_focus_index..].iter().position(|c| c.text.chars().next().unwrap_or('𐘂').to_lowercase().next().unwrap() == key_press.key) {
//now old focus, not current focus //now old focus, not current focus
self.components[current_focus_index].handle_message(WindowMessage::Unfocus); self.components[current_focus_index].handle_message(WindowMessage::Unfocus);
self.current_focus = self.components[current_focus_index + n_index].name().to_string(); self.current_focus = self.components[current_focus_index + n_index].name().to_string();
@@ -80,7 +84,7 @@ impl WindowLike for StartMenu {
} }
} else { } else {
//look backwards to see category/window that starts with that char //look backwards to see category/window that starts with that char
if let Some(n_index) = self.components[..current_focus_index].iter().rev().position(|c| c.name().chars().next().unwrap_or('𐘂').to_uppercase().next().unwrap() == key_press.key) { if let Some(n_index) = self.components[..current_focus_index].iter().rev().position(|c| c.text.chars().next().unwrap_or('𐘂').to_uppercase().next().unwrap() == key_press.key) {
//now old focus, not current focus //now old focus, not current focus
self.components[current_focus_index].handle_message(WindowMessage::Unfocus); self.components[current_focus_index].handle_message(WindowMessage::Unfocus);
self.current_focus = self.components[current_focus_index - n_index - 1].name().to_string(); self.current_focus = self.components[current_focus_index - n_index - 1].name().to_string();
@@ -105,7 +109,7 @@ impl WindowLike for StartMenu {
//background //background
DrawInstructions::Rect([0, 1], [self.dimensions[0] - 1, self.dimensions[1] - 1], theme_info.background), DrawInstructions::Rect([0, 1], [self.dimensions[0] - 1, self.dimensions[1] - 1], theme_info.background),
//mingde logo //mingde logo
DrawInstructions::Bmp([2, 2], "./bmps/mingde.bmp".to_string(), false), DrawInstructions::Bmp([2, 2], exe_dir(Some("bmps/mingde.bmp")).to_string_lossy().to_string(), false),
//I truly don't know why, it should be - 44 but - 30 seems to work better :shrug: //I truly don't know why, it should be - 44 but - 30 seems to work better :shrug:
DrawInstructions::Gradient([2, 42], [40, self.dimensions[1] - 30], [255, 201, 14], [225, 219, 77], 15), DrawInstructions::Gradient([2, 42], [40, self.dimensions[1] - 30], [255, 201, 14], [225, 219, 77], 15),
]; ];
@@ -147,22 +151,12 @@ impl StartMenu {
)) ))
]; ];
//add window buttons //add window buttons
let mut to_add: Vec<&str> = Vec::new(); if let Some(to_add) = self.executable_windows.get(&("ming".to_string() + name)) {
if name == "Games" { for a in 0..to_add.len() {
to_add.extend(["Minesweeper", "Reversi"]); self.components.push(Box::new(HighlightButton::new(
} else if name == "Editing" { to_add[a].1.to_string(), [42, (a + 1) * self.y_each], [self.dimensions[0] - 42 - 1, self.y_each], to_add[a].0.to_string(), StartMenuMessage::WindowClick(to_add[a].1.clone()), StartMenuMessage::ChangeAcknowledge, false
to_add.push("Malvim"); )));
} else if name == "Utils" { }
to_add.push("Terminal");
} else if name == "Files" {
to_add.extend(["File Explorer", "Audio Player"]);
}
//
for a in 0..to_add.len() {
let w_name = to_add[a];
self.components.push(Box::new(HighlightButton::new(
w_name.to_string(), [42, (a + 1) * self.y_each], [self.dimensions[0] - 42 - 1, self.y_each], w_name.to_string(), StartMenuMessage::WindowClick(w_name), StartMenuMessage::ChangeAcknowledge, false
)));
} }
WindowMessageResponse::JustRedraw WindowMessageResponse::JustRedraw
} }

View File

@@ -1,6 +1,10 @@
use std::fs::{ read_dir, File }; use std::fs::{ read_dir, File };
use std::path::PathBuf; use std::path::PathBuf;
use std::io::Read; use std::io::Read;
use std::collections::HashMap;
use crate::dirs;
use crate::utils::get_rest_of_split;
fn get_font_char(dir: &str, c: char) -> Option<(char, Vec<Vec<u8>>, u8)> { fn get_font_char(dir: &str, c: char) -> Option<(char, Vec<Vec<u8>>, u8)> {
let c = if c == '/' { '𐘋' } else if c == '\\' { '𐚆' } else if c == '.' { '𐘅' } else { c }; let c = if c == '/' { '𐘋' } else if c == '\\' { '𐚆' } else if c == '.' { '𐘅' } else { c };
@@ -20,12 +24,14 @@ fn get_font_char(dir: &str, c: char) -> Option<(char, Vec<Vec<u8>>, u8)> {
pub fn get_font_char_from_fonts(fonts: &[String], c: char) -> (char, Vec<Vec<u8>>, u8) { pub fn get_font_char_from_fonts(fonts: &[String], c: char) -> (char, Vec<Vec<u8>>, u8) {
for font in fonts { for font in fonts {
if let Some(font_char) = get_font_char(&("./bmps/".to_string() + font), c) { let p = dirs::exe_dir(Some(&("bmps/".to_string() + &font))).to_string_lossy().to_string();
if let Some(font_char) = get_font_char(&p, c) {
return font_char; return font_char;
} }
} }
let p = dirs::exe_dir(Some(&("bmps/".to_string() + &fonts[0]))).to_string_lossy().to_string();
//so a ? char must be in every font //so a ? char must be in every font
get_font_char(&("./bmps/".to_string() + &fonts[0]), '?').unwrap() get_font_char(&p, '?').unwrap()
} }
pub fn get_all_files(dir: PathBuf) -> Vec<PathBuf> { pub fn get_all_files(dir: PathBuf) -> Vec<PathBuf> {
@@ -41,3 +47,26 @@ pub fn get_all_files(dir: PathBuf) -> Vec<PathBuf> {
files files
} }
//Category, Vec<Display name, file name>
pub type ExeWindowInfos = HashMap<String, Vec<(String, String)>>;
//well, doesn't actually look to see if its executable. Just if it contains a _ and has no file extension, and is a file
pub fn get_all_executable_windows() -> ExeWindowInfos {
let mut exes = HashMap::new();
for entry in read_dir(dirs::exe_dir(None)).unwrap() {
let pb = entry.unwrap().path();
if pb.is_file() && pb.extension().is_none() {
let parts = pb.file_stem().unwrap().to_string_lossy().to_string();
let mut parts = parts.split('_');
let category = parts.next().unwrap();
let display = get_rest_of_split(&mut parts, Some(" "));
let file_name = pb.file_name().unwrap().to_string_lossy().to_string();
if display != String::new() && category.starts_with("ming") {
let pair = (display, file_name);
exes.entry(category.to_string()).and_modify(|v: &mut Vec<(String, String)>| (*v).push(pair.clone())).or_insert(vec![pair]);
}
}
}
exes
}

View File

@@ -2,12 +2,12 @@ use std::vec::Vec;
use std::process::{ Command, Child, Stdio }; use std::process::{ Command, Child, Stdio };
use std::io::{ BufReader, BufRead, Write }; use std::io::{ BufReader, BufRead, Write };
use std::cell::RefCell; use std::cell::RefCell;
use std::path::Path;
use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType }; use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType };
use crate::messages::{ WindowMessage, WindowMessageResponse }; use crate::messages::{ WindowMessage, WindowMessageResponse };
use crate::framebuffer::Dimensions; use crate::framebuffer::Dimensions;
use crate::themes::ThemeInfo; use crate::themes::ThemeInfo;
use crate::dirs;
use crate::serialize::{ Serializable, DrawInstructionsVec }; use crate::serialize::{ Serializable, DrawInstructionsVec };
pub struct ProxyWindowLike { pub struct ProxyWindowLike {
@@ -74,18 +74,10 @@ impl Drop for ProxyWindowLike {
} }
impl ProxyWindowLike { impl ProxyWindowLike {
pub fn new(command: &mut Command) -> Self { pub fn new(name: &str) -> Self {
let loc = dirs::exe_dir(Some(name)).to_string_lossy().to_string();
ProxyWindowLike { ProxyWindowLike {
process: RefCell::new(command.stdout(Stdio::piped()).stdin(Stdio::piped()).stderr(Stdio::null()).spawn().unwrap()), process: RefCell::new(Command::new(loc).stdout(Stdio::piped()).stdin(Stdio::piped()).stderr(Stdio::null()).spawn().unwrap()),
}
}
pub fn new_rust(file: &str) -> Self {
let loc = format!("./target/release/{}", file);
if Path::new(&loc).exists() {
ProxyWindowLike::new(Command::new(loc).stdout(Stdio::piped()).stdin(Stdio::piped()).stderr(Stdio::null()))
} else {
ProxyWindowLike::new(Command::new("cargo").arg("run").arg("--quiet").arg("--release").arg("--bin").arg(file).stdout(Stdio::piped()).stdin(Stdio::piped()).stderr(Stdio::null()))
} }
} }

View File

@@ -4,6 +4,7 @@ use crate::themes::ThemeInfo;
use crate::messages::{ WindowMessageResponse, WindowManagerRequest, KeyPress, WindowMessage, Direction, ShortcutType, InfoType }; use crate::messages::{ WindowMessageResponse, WindowManagerRequest, KeyPress, WindowMessage, Direction, ShortcutType, InfoType };
use crate::window_manager::{ KeyChar, DrawInstructions, WindowLikeType }; use crate::window_manager::{ KeyChar, DrawInstructions, WindowLikeType };
use crate::framebuffer::Dimensions; use crate::framebuffer::Dimensions;
use crate::utils::get_rest_of_split;
//serde + ron but worse! yay //serde + ron but worse! yay
//not same as ron - simplified //not same as ron - simplified
@@ -33,21 +34,6 @@ fn option_to_string<T: Display>(option: &Option<T>) -> String {
} }
} }
fn get_rest_of_split(split: &mut dyn Iterator<Item = &str>, sep: Option<&str>) -> String {
let mut rest = String::new();
let mut n = split.next();
loop {
rest += &n.unwrap();
n = split.next();
if n.is_some() {
rest += sep.unwrap_or("");
} else {
break;
}
}
rest
}
fn get_color(serialized: &str) -> Result<[u8; 3], ()> { fn get_color(serialized: &str) -> Result<[u8; 3], ()> {
let rgb = serialized.split("\x1F"); let rgb = serialized.split("\x1F");
let mut color = [0; 3]; let mut color = [0; 3];

View File

@@ -157,3 +157,19 @@ pub fn point_inside(point: Point, top_left: Point, size: Dimensions) -> bool {
x >= x2 && y >= y2 && x <= x3 && y <= y3 x >= x2 && y >= y2 && x <= x3 && y <= y3
} }
pub fn get_rest_of_split(split: &mut dyn Iterator<Item = &str>, sep: Option<&str>) -> String {
let mut rest = String::new();
let mut n = split.next();
loop {
if n.is_none() {
break;
}
rest += &n.unwrap();
n = split.next();
if n.is_some() && sep.is_some() {
rest += sep.unwrap();
}
}
rest
}

View File

@@ -633,16 +633,10 @@ impl WindowManager {
return; return;
} }
let w: Option<WindowBox> = match w.as_str() { let w: Option<WindowBox> = match w.as_str() {
"Minesweeper" => Some(Box::new(ProxyWindowLike::new_rust("minesweeper"))),
"Reversi" => Some(Box::new(ProxyWindowLike::new_rust("reversi"))),
"Malvim" => Some(Box::new(ProxyWindowLike::new_rust("malvim"))),
"Terminal" => Some(Box::new(ProxyWindowLike::new_rust("terminal"))),
"Audio Player" => Some(Box::new(ProxyWindowLike::new_rust("audio_player"))),
"File Explorer" => Some(Box::new(ProxyWindowLike::new_rust("file_explorer"))),
"StartMenu" => Some(Box::new(StartMenu::new())), "StartMenu" => Some(Box::new(StartMenu::new())),
"About" => Some(Box::new(About::new())), "About" => Some(Box::new(About::new())),
"Help" => Some(Box::new(Help::new())), "Help" => Some(Box::new(Help::new())),
_ => None, _ => Some(Box::new(ProxyWindowLike::new(&w))),
}; };
if w.is_none() { if w.is_none() {
return; return;