Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec5cba13c8 | ||
|
|
4c4c9a1b35 | ||
|
|
6cc8e06e89 | ||
|
|
dfe065d26a | ||
|
|
c1afd3f33e | ||
|
|
724ffbd494 | ||
|
|
7c6a7d6b6d | ||
|
|
667b4cd2d9 | ||
|
|
c5a41244b4 | ||
|
|
d32b82a2bb | ||
|
|
11af21ee6d | ||
|
|
fa4627316d |
22
Cargo.toml
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ming-wm"
|
name = "ming-wm"
|
||||||
version = "1.0.1"
|
version = "1.1.0"
|
||||||
repository = "https://github.com/stjet/ming-wm"
|
repository = "https://github.com/stjet/ming-wm"
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@@ -9,29 +9,25 @@ 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
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["linux"]
|
members = [ "wm", "linux" ]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
bmp-rust = "0.5.0"
|
bmp-rust = "0.5.0"
|
||||||
blake2 = { version = "0.10.6", default-features = false }
|
bitcoin_hashes = { version = "0.16.0", default-features = false }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ming-wm-lib = { path = "ming-wm-lib" }
|
ming-wm-lib = { path = "ming-wm-lib" }
|
||||||
blake2 = { version = "0.10.6", default-features = false }
|
wm = { path = "wm", optional = true }
|
||||||
linux = { path = "linux" }
|
linux = { path = "linux", optional = true }
|
||||||
termion = { version = "4.0.3", optional = true }
|
|
||||||
rodio = { version = "0.19.0", default-features = false, features = [ "flac", "mp3", "symphonia-vorbis", "wav" ], optional = true }
|
rodio = { version = "0.19.0", default-features = false, features = [ "flac", "mp3", "symphonia-vorbis", "wav" ], optional = true }
|
||||||
rand = { version = "0.9.0", default-features = false, features = [ "small_rng" ], optional = true }
|
rand = { version = "0.9.0", default-features = false, features = [ "small_rng" ], optional = true }
|
||||||
id3 = { version = "1.10.0", optional = true }
|
id3 = { version = "1.10.0", optional = true }
|
||||||
mp4ameta = { version = "0.11.0", optional = true }
|
mp4ameta = { version = "0.11.0", optional = true }
|
||||||
metaflac = { version = "0.2.5", optional = true }
|
metaflac = { version = "0.2.5", optional = true }
|
||||||
bmp-rust = "0.5.0"
|
|
||||||
pty-process = { version = "0.5.1", optional = true }
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ "main", "terminal" ]
|
default = [ "wm", "terminal" ]
|
||||||
main = [ "termion" ]
|
terminal = [ "linux" ]
|
||||||
terminal = [ "pty-process" ]
|
|
||||||
audio_player = [ "id3", "mp4ameta", "metaflac", "rand", "rodio" ]
|
audio_player = [ "id3", "mp4ameta", "metaflac", "rand", "rodio" ]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
@@ -39,8 +35,8 @@ lto = true
|
|||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "ming"
|
name = "ming"
|
||||||
path = "src/bin/main.rs"
|
path = "src/bin/wm.rs"
|
||||||
required-features = [ "main" ]
|
required-features = [ "wm" ]
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "mingFiles_Audio_Player"
|
name = "mingFiles_Audio_Player"
|
||||||
|
|||||||
14
README.md
@@ -1,4 +1,4 @@
|
|||||||
Ming-wm is a keyboard-based, retro-themed window manager for Linux. It is neither for Wayland or the X Window System - it writes directly to the framebuffer. Inspirations include i3, Haiku, SerenityOS, and Windows98, and it is a conceptual successor to the previous [mingde](https://github.com/stjet/mingde) and [ming-os](https://github.com/stjet/ming-os).
|
Ming-wm is a keyboard-based, retro-themed window manager for Linux. It is neither for Wayland or the X Window System - it writes directly to the framebuffer. Inspirations include i3, Haiku, SerenityOS, and Windows98, and it is a conceptual successor to my previous projects [ming-de](https://github.com/stjet/mingde) and [ming-os](https://github.com/stjet/ming-os).
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||
@@ -49,9 +49,9 @@ Usage for most of the included windows and window-likes are included in `docs/wi
|
|||||||
|
|
||||||
## Running on Mobile Linux
|
## 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. If someone knows why this is the case, and/or how to fix this, please let me know.
|
More or the less the same, but includes with an onscreen keyboard for touchscreens.
|
||||||
|
|
||||||
`evtest` needs to be installed. Currently, the input device is assumed to be at `/dev/first-touchscreen`.
|
Currently, the touchscreen input device is assumed to be at `/dev/input/by-path/first-touchscreen`, but this is easily editable (see `src/bin/wm.rs`). For touchscreen support, the user running `ming` needs to have read permissions for that `/dev/input/` file.
|
||||||
|
|
||||||
```
|
```
|
||||||
ming touch
|
ming touch
|
||||||
@@ -73,12 +73,18 @@ See [/docs/philosophy.md](/docs/philosophy.md) for some hopefully interesting ra
|
|||||||
|
|
||||||
Windows (may be called apps in other window managers) can be developed in any language, though it is easiest to do so in Rust because the `ming-wm-lib` crate can be used.
|
Windows (may be called apps in other window managers) can be developed in any language, though it is easiest to do so in Rust because the `ming-wm-lib` crate can be used.
|
||||||
|
|
||||||
See [koxinga](https://github.com/stjet/koxinga) or `src/bin` for examples. The `docs` directory includes a [brief introduction to writing windows](docs/system/writing_windows.md), and (incomplete) documentation on the workings of ming-wm.
|
The `docs` directory includes a [brief introduction to writing windows](docs/system/writing_windows.md), and (incomplete) documentation on the workings of ming-wm.
|
||||||
|
|
||||||
|
See [koxinga](https://github.com/stjet/koxinga) or `src/bin` for examples.
|
||||||
|
|
||||||
|
A (very poorly written, and WIP) window is being written in Lisp Scheme: [ming-flashcards](https://github.com/stjet/ming-flashcards).
|
||||||
|
|
||||||
## Security
|
## 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.
|
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.
|
||||||
|
|
||||||
|
Understand the implications of adding the user to the `video` group. And if the permissions of a `/dev/input/` file was changed for touchscreen support, understand those implications too.
|
||||||
|
|
||||||
Obviously, don't run the executable with `sudo` or `doas`, or as the root user!
|
Obviously, don't run the executable with `sudo` or `doas`, or as the root user!
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|||||||
BIN
bmps/ming-wm.bmp
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
73
bmps/ming-wm.svg
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="210mm"
|
||||||
|
height="297mm"
|
||||||
|
viewBox="0 0 210 297"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
xml:space="preserve"
|
||||||
|
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||||
|
sodipodi:docname="ming-wm.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:zoom="4.3046016"
|
||||||
|
inkscape:cx="449.86742"
|
||||||
|
inkscape:cy="483.20383"
|
||||||
|
inkscape:window-width="706"
|
||||||
|
inkscape:window-height="855"
|
||||||
|
inkscape:window-x="723"
|
||||||
|
inkscape:window-y="34"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" /><defs
|
||||||
|
id="defs1" /><g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"><rect
|
||||||
|
style="fill:#ffc90e;fill-opacity:1;stroke:none;stroke-width:1.13352"
|
||||||
|
id="rect1"
|
||||||
|
width="10.583"
|
||||||
|
height="10.583"
|
||||||
|
x="116.72247"
|
||||||
|
y="121.45529"
|
||||||
|
inkscape:export-filename="/home/jondough/Downloads/image1.png"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" /><ellipse
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.53688"
|
||||||
|
id="path1"
|
||||||
|
cx="122.01397"
|
||||||
|
cy="126.7468"
|
||||||
|
rx="3"
|
||||||
|
ry="3.1378791" /><text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.76389px;line-height:1.25;font-family:'Nimbus Roman';-inkscape-font-specification:'Nimbus Roman, ';text-align:start;letter-spacing:0px;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.25"
|
||||||
|
x="123.14632"
|
||||||
|
y="129.68439"
|
||||||
|
id="text1"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan1"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.76389px;font-family:'Nimbus Roman';-inkscape-font-specification:'Nimbus Roman, ';letter-spacing:0px;fill:#000000;stroke:none;stroke-width:1.25"
|
||||||
|
x="123.14632"
|
||||||
|
y="129.68439">wm</tspan></text><text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52778px;line-height:1.25;font-family:'Shippori Mincho';-inkscape-font-specification:'Shippori Mincho';text-align:start;letter-spacing:0px;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.25"
|
||||||
|
x="120.23068"
|
||||||
|
y="128.04678"
|
||||||
|
id="text2"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan2"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52778px;font-family:'Shippori Mincho';-inkscape-font-specification:'Shippori Mincho';fill:#000000;stroke-width:1.25"
|
||||||
|
x="120.23068"
|
||||||
|
y="128.04678">明</tspan></text></g></svg>
|
||||||
|
After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 4.6 MiB |
BIN
bmps/mingde.bmp
|
Before Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 70 B After Width: | Height: | Size: 70 B |
|
Before Width: | Height: | Size: 250 B After Width: | Height: | Size: 250 B |
|
Before Width: | Height: | Size: 250 B After Width: | Height: | Size: 250 B |
|
Before Width: | Height: | Size: 582 B After Width: | Height: | Size: 534 B |
|
Before Width: | Height: | Size: 630 B After Width: | Height: | Size: 534 B |
|
Before Width: | Height: | Size: 470 B After Width: | Height: | Size: 374 B |
|
Before Width: | Height: | Size: 438 B After Width: | Height: | Size: 374 B |
BIN
bmps/shippori-mincho/、9.bmp
Normal file
|
After Width: | Height: | Size: 90 B |
BIN
bmps/shippori-mincho/ァ5.bmp
Normal file
|
After Width: | Height: | Size: 222 B |
BIN
bmps/shippori-mincho/ガ3.bmp
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
bmps/shippori-mincho/ギ3.bmp
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
bmps/shippori-mincho/グ3.bmp
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
bmps/shippori-mincho/ゲ3.bmp
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
bmps/shippori-mincho/ゴ1.bmp
Normal file
|
After Width: | Height: | Size: 306 B |
BIN
bmps/shippori-mincho/ザ2.bmp
Normal file
|
After Width: | Height: | Size: 454 B |
BIN
bmps/shippori-mincho/ジ3.bmp
Normal file
|
After Width: | Height: | Size: 378 B |
BIN
bmps/shippori-mincho/ズ3.bmp
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
bmps/shippori-mincho/ゼ3.bmp
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
bmps/shippori-mincho/ゾ3.bmp
Normal file
|
After Width: | Height: | Size: 378 B |
BIN
bmps/shippori-mincho/ダ3.bmp
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
bmps/shippori-mincho/ヂ3.bmp
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
bmps/shippori-mincho/ッ6.bmp
Normal file
|
After Width: | Height: | Size: 198 B |
BIN
bmps/shippori-mincho/ヅ3.bmp
Normal file
|
After Width: | Height: | Size: 378 B |
BIN
bmps/shippori-mincho/デ3.bmp
Normal file
|
After Width: | Height: | Size: 378 B |
BIN
bmps/shippori-mincho/ド3.bmp
Normal file
|
After Width: | Height: | Size: 270 B |
BIN
bmps/shippori-mincho/バ6.bmp
Normal file
|
After Width: | Height: | Size: 294 B |
BIN
bmps/shippori-mincho/パ6.bmp
Normal file
|
After Width: | Height: | Size: 294 B |
BIN
bmps/shippori-mincho/ビ5.bmp
Normal file
|
After Width: | Height: | Size: 250 B |
BIN
bmps/shippori-mincho/ピ4.bmp
Normal file
|
After Width: | Height: | Size: 278 B |
BIN
bmps/shippori-mincho/ブ3.bmp
Normal file
|
After Width: | Height: | Size: 378 B |
BIN
bmps/shippori-mincho/プ0.bmp
Normal file
|
After Width: | Height: | Size: 378 B |
BIN
bmps/shippori-mincho/ボ3.bmp
Normal file
|
After Width: | Height: | Size: 378 B |
BIN
bmps/shippori-mincho/ポ4.bmp
Normal file
|
After Width: | Height: | Size: 342 B |
BIN
bmps/shippori-mincho/ャ5.bmp
Normal file
|
After Width: | Height: | Size: 250 B |
BIN
bmps/shippori-mincho/ュ8.bmp
Normal file
|
After Width: | Height: | Size: 166 B |
BIN
bmps/shippori-mincho/ョ7.bmp
Normal file
|
After Width: | Height: | Size: 154 B |
BIN
bmps/shippori-mincho/全0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/創0.bmp
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
bmps/shippori-mincho/咲0.bmp
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
bmps/shippori-mincho/声0.bmp
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
bmps/shippori-mincho/子1.bmp
Normal file
|
After Width: | Height: | Size: 538 B |
BIN
bmps/shippori-mincho/年0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/度0.bmp
Normal file
|
After Width: | Height: | Size: 582 B |
|
Before Width: | Height: | Size: 582 B After Width: | Height: | Size: 582 B |
BIN
bmps/shippori-mincho/思1.bmp
Normal file
|
After Width: | Height: | Size: 538 B |
BIN
bmps/shippori-mincho/教0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/某0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/森0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/猫0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/的0.bmp
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
bmps/shippori-mincho/眩0.bmp
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
bmps/shippori-mincho/穴0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/窓0.bmp
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
bmps/shippori-mincho/義0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/老0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/胸0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/返0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/過0.bmp
Executable file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/降0.bmp
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
bmps/shippori-mincho/馬0.bmp
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
bmps/shippori-mincho/騒0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
13
build.rs
@@ -4,7 +4,7 @@ use std::env;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use blake2::{ Blake2b512, Digest };
|
use bitcoin_hashes::Sha512;
|
||||||
use bmp_rust::bmp::BMP;
|
use bmp_rust::bmp::BMP;
|
||||||
|
|
||||||
fn font_chars_to_alphas(dir: &str) {
|
fn font_chars_to_alphas(dir: &str) {
|
||||||
@@ -15,8 +15,7 @@ fn font_chars_to_alphas(dir: &str) {
|
|||||||
if file_name.len() < 2 {
|
if file_name.len() < 2 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if file_name[1] == "bmp" {
|
if file_name[1] == "bmp" && !path.is_dir() {
|
||||||
if !path.is_dir() {
|
|
||||||
let mut ch: Vec<Vec<String>> = Vec::new();
|
let mut ch: Vec<Vec<String>> = Vec::new();
|
||||||
let b = BMP::new_from_file(&path.clone().into_os_string().into_string().unwrap()).unwrap();
|
let b = BMP::new_from_file(&path.clone().into_os_string().into_string().unwrap()).unwrap();
|
||||||
let dib_header = b.get_dib_header().unwrap();
|
let dib_header = b.get_dib_header().unwrap();
|
||||||
@@ -44,17 +43,15 @@ fn font_chars_to_alphas(dir: &str) {
|
|||||||
).unwrap();
|
).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
//hash + "salt" password and add to build
|
//hash + "salt" password and add to build
|
||||||
let password = read_to_string("password.env").unwrap_or("password".to_string()).replace("\n", "") + "salt?sorrycryptographers";
|
let password = read_to_string("password.env").unwrap_or("password".to_string()).replace("\n", "") + "salt?sorrycryptographers!1!";
|
||||||
let mut hasher = Blake2b512::new();
|
let hash = Sha512::hash(password.as_bytes()).to_byte_array();
|
||||||
hasher.update(password.as_bytes());
|
|
||||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
let dest_path = Path::new(&out_dir).join("password.rs");
|
let dest_path = Path::new(&out_dir).join("password.rs");
|
||||||
write(&dest_path, format!("pub const PASSWORD_HASH: [u8; 64] = {:?};", hasher.finalize())).unwrap();
|
write(&dest_path, format!("pub const PASSWORD_HASH: [u8; 64] = {:?};", hash)).unwrap();
|
||||||
//process bmps
|
//process bmps
|
||||||
for entry in read_dir("./bmps").unwrap() {
|
for entry in read_dir("./bmps").unwrap() {
|
||||||
let path = entry.unwrap().path();
|
let path = entry.unwrap().path();
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 948 KiB After Width: | Height: | Size: 906 KiB |
@@ -69,5 +69,10 @@ More often than not, not relying on dependencies removes unnecessary bloat and c
|
|||||||
Expect to see more dependencies in Cargo.toml eliminated soon.
|
Expect to see more dependencies in Cargo.toml eliminated soon.
|
||||||
|
|
||||||
PS:
|
PS:
|
||||||
1. `rodio` is unlikely to ever be eliminated (simply because audio is *complex*), and it's optional (if the audio player is not wanted)
|
1. `rodio` is unlikely to ever be eliminated (simply because audio is *complex*), and it's optional (if the audio player is not wanted). The dependency which provides hashing will also not be removed as I am not a cryptographer and not (quite) stupid enough to pretend being one
|
||||||
2.`bmp-rust` is written by me and so isn't technically an external dependency
|
2. `bmp-rust` is written by me and so isn't technically an external dependency
|
||||||
|
|
||||||
|
> ### Update
|
||||||
|
> Ignoring the audio player dependencies and `bmp-rust`, the only dependencies not written by me are now `libc` for libc Rust bindings and `bitcoin-hashes` for SHA-512 password hashing (yes, I know SHA-512 is not the greatest password hash function, but it is lightweight, relatively).
|
||||||
|
>
|
||||||
|
> Prior dependencies like `termion`, `linux_framebuffer`, `pty-process`, `evtest` have been removed and replaced by a me-written version in the `linux` crate. As of v1.1, the dependency removing goal has been achieved. Huzzah!
|
||||||
|
|||||||
3
docs/system/integration.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
## Launch on Login
|
||||||
|
|
||||||
|
To launch on user login, simply add `ming` as the last line of `~/.profile`. This should work for most shells.
|
||||||
26
docs/system/keys.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
Relevant section taken from `src/bin/main.rs`:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn key_to_char(key: Key) -> Option<KeyChar> {
|
||||||
|
match key {
|
||||||
|
Key::Char('\n') => Some(KeyChar::Press('𐘂')),
|
||||||
|
Key::Char(c) => Some(KeyChar::Press(c)),
|
||||||
|
Key::Alt(c) => Some(KeyChar::Alt(c)),
|
||||||
|
Key::Ctrl(c) => Some(KeyChar::Ctrl(c)),
|
||||||
|
Key::Backspace => Some(KeyChar::Press('𐘁')),
|
||||||
|
Key::Esc => Some(KeyChar::Press('𐘃')),
|
||||||
|
Key::Up => Some(KeyChar::Press('𐙘')),
|
||||||
|
Key::Down => Some(KeyChar::Press('𐘞')),
|
||||||
|
Key::Left => Some(KeyChar::Press('𐙣')),
|
||||||
|
Key::Right => Some(KeyChar::Press('𐙥')),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The special keys backspace, enter, escape, and the arrows, are represented by a single Linear A char. For ease, there are [methods](https://docs.rs/ming-wm-lib/latest/ming_wm_lib/messages/struct.KeyPress.html) to check whether a key press is a backspace, enter, etc, without pasting the Linear A into the code.
|
||||||
|
|
||||||
|
Although the arrow keys are supported, please try and support the Vim `hjkl` if possible!
|
||||||
|
|
||||||
|
The `Press` events are sent as `WindowMessage::KeyPress(KeyPress)`, and the `Ctrl` events are sent as `WindowMessage::CtrlKeyPress(KeyPress)`. Any keys pressed along with the Alt key are not passed to the windows.
|
||||||
|
|
||||||
@@ -16,5 +16,9 @@
|
|||||||
- Alt+J: Move window to bottom edge
|
- Alt+J: Move window to bottom edge
|
||||||
- Alt+K: Move window to top edge
|
- Alt+K: Move window to top edge
|
||||||
- Alt+L: Move window to right edge
|
- Alt+L: Move window to right edge
|
||||||
|
- Alt+n: Expand window width
|
||||||
|
- Alt+m: Expand window height
|
||||||
|
- Alt+N: Shrink window width
|
||||||
|
- Alt+M: Shrink window height
|
||||||
- Alt+1, Alt+2, ..., Alt+[n], ..., Alt+9: Switch to workspace [n]
|
- Alt+1, Alt+2, ..., Alt+[n], ..., Alt+9: Switch to workspace [n]
|
||||||
- Alt+shift+1, Alt+shift+2, ..., Alt+shift+[n], ..., Alt+shift+9: Move window to workspace [n]
|
- Alt+shift+1, Alt+shift+2, ..., Alt+shift+[n], ..., Alt+shift+9: Move window to workspace [n]
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ Since the windows and the window manager are separate binaries, they need some w
|
|||||||
|
|
||||||
The serialization format is in `ming-wm-lib/src/serialize.rs`. Make sure any newlines (`\n`) in strings are removed before/after serializations. When doing IPC, the window manager assumes the response to a query is one line, so if a newline is present, it will fail to parse the response.
|
The serialization format is in `ming-wm-lib/src/serialize.rs`. Make sure any newlines (`\n`) in strings are removed before/after serializations. When doing IPC, the window manager assumes the response to a query is one line, so if a newline is present, it will fail to parse the response.
|
||||||
|
|
||||||
|
> In the case of `WindowMessage::Request(WindowManagerRequest::ClipboardCopy(<copy_string>))`, windows should convert any `\n` into `𐘂` when copying to clipboard and vice versa when pasting, in order to allow for multi-line clipboard contents.
|
||||||
|
|
||||||
## Hello, World!
|
## Hello, World!
|
||||||
|
|
||||||
A minimal example using `ming-wm-lib`.
|
A minimal example using `ming-wm-lib`.
|
||||||
@@ -101,8 +103,17 @@ mv target/release/mingMisc_Example /usr/bin/mingMisc_Example #or whatever direct
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## Now what?
|
||||||
|
|
||||||
|
Handle various inputs in `handle_message`, and have it mutate the state. Draw the relevant state in `draw`. Not too hard, eh?
|
||||||
|
|
||||||
|
Besides looking at the examples (Koxinga, `src/bin`), read the [ming-wm-lib docs](https://docs.rs/ming-wm-lib)!
|
||||||
|
|
||||||
|
Also, `docs/system/keys.md` may be useful.
|
||||||
|
|
||||||
## Tips
|
## Tips
|
||||||
|
|
||||||
- For windows that are separate binaries, the Elm Architecture obviously cannot be enforced (unless the window is written in Rust and uses the `ming-wm-lib`. However, the design of the IPC and the nature of the window manager being keyboard-driven makes it so using the Elm Architecture is highly recommended.
|
- For windows that are separate binaries, the Elm Architecture obviously cannot be enforced (unless the window is written in Rust and uses the `ming-wm-lib`. However, the design of the IPC and the nature of the window manager being keyboard-driven makes it so using the Elm Architecture is highly recommended.
|
||||||
- Since the window manager currently queries and reads the responses to/from window binaries in the main thread, while the response is being waited for, the window manager is "frozen". Therefore, time-consuming tasks (>1 second) should not be done in the main thread, but rather a separate thread. For example, the ming-wm audio player (`src/bin/audio_player.rs`) does the time-consuming process of reading audio files in a separate thread to not hold up the window manager, and provide quick responses.
|
- Since the window manager currently queries and reads the responses to/from window binaries in the main thread, while the response is being waited for, the window manager is "frozen". Therefore, time-consuming tasks (>1 second) should not be done in the main thread, but rather a separate thread. For example, the ming-wm audio player (`src/bin/audio_player.rs`) does the time-consuming process of reading audio files in a separate thread to not hold up the window manager, and provide quick responses.
|
||||||
|
- Window panics will be logged to `~/.local/share/ming-wm/logs.txt`.
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ Type to write commands, backspace to delete last character, and enter to run com
|
|||||||
|
|
||||||
Tab completion is supported for the `<dir>` and `<dir / playlist file>` arguments.
|
Tab completion is supported for the `<dir>` and `<dir / playlist file>` arguments.
|
||||||
|
|
||||||
|
The copy shortcut will copy the currently playing song's file name, if there is a currently playing song.
|
||||||
|
|
||||||
## Playlists
|
## Playlists
|
||||||
|
|
||||||
Example playlist file:
|
Example playlist file:
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ Barebones file explorer.
|
|||||||
|
|
||||||
## Navigation
|
## Navigation
|
||||||
|
|
||||||
- `j`: Move down
|
- `j` (or down arrow): Move down
|
||||||
- `k`: Move up
|
- `k` (or up arrow): Move up
|
||||||
- `i`: See info about current file / directory (press any key to escape info screen)
|
- `i`: See info about current file / directory (press any key to escape info screen)
|
||||||
- `Enter`: Go into directory
|
- `Enter`: Go into directory
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ It is probably best to read a Vim tutorial for the basics. All supportd keystrok
|
|||||||
- `t[abe] <file>`, `[tab]n`, `[tab]p`
|
- `t[abe] <file>`, `[tab]n`, `[tab]p`
|
||||||
- `q[uit]`
|
- `q[uit]`
|
||||||
- `w[rite]`
|
- `w[rite]`
|
||||||
|
- `/<query>`
|
||||||
|
|
||||||
Tab completion is supported for the `<file>` argument.
|
Tab completion is supported for the `<file>` argument.
|
||||||
|
|
||||||
@@ -23,15 +24,17 @@ Tab completion is supported for the `<file>` argument.
|
|||||||
- `r`
|
- `r`
|
||||||
- `dd`
|
- `dd`
|
||||||
- `dw`
|
- `dw`
|
||||||
|
- `d$`
|
||||||
- `G`
|
- `G`
|
||||||
- `gg`
|
- `gg`
|
||||||
- `<number>gg`
|
- `<number>gg`
|
||||||
- `f<char>`
|
- `f<char>`
|
||||||
- `F<char>`
|
- `F<char>`
|
||||||
- `x`
|
- `x`
|
||||||
- `h`, `j`, `k`, `l`
|
- `h` (or left arrow), `j` (or down arrow), `k` (or up arrow), `l` (or right arrow)
|
||||||
- `<num>h`, `<num>j`, `<num>k`, `<num>l`
|
- `<num>h`, `<num>j` (or down arrow), `<num>k` (or up arrow), `<num>l`
|
||||||
- `0`, `^`, `$`
|
- `0`, `^`, `$`
|
||||||
|
- `%`
|
||||||
|
|
||||||
### Malvim Specific
|
### Malvim Specific
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ The start menu, which can be opened and closed with the [Alt+s shortcut](../syst
|
|||||||
|
|
||||||
## Navigation
|
## Navigation
|
||||||
|
|
||||||
Use the 'j' and 'k' keys to move down and up respectively. Going down past the last option returns the selection to the first option, and vice versa (it loops).
|
Use the 'j' and 'k' keys to move down and up respectively. The up and down arrow keys can also be used. Going down past the last option returns the selection to the first option, and vice versa (it loops).
|
||||||
|
|
||||||
Hitting the 'enter' key will either open a subfolder containing window-likes, if a category is selected, or the corresponding window-like, if a window-like is selected. It may also exit a subfolder and return to the category selection if "Back" is selected and 'enter' is hit. There is another special case: hitting 'enter' while the "Logout" option is selected will, as the name implies, logout and return to the lock screen (this does not log out of the Linux user!).
|
Hitting the 'enter' key will either open a subfolder containing window-likes, if a category is selected, or the corresponding window-like, if a window-like is selected. It may also exit a subfolder and return to the category selection if "Back" is selected and 'enter' is hit. There is another special case: hitting 'enter' while the "Logout" option is selected will, as the name implies, logout and return to the lock screen (this does not log out of the Linux user!).
|
||||||
|
|
||||||
For faster navigation, hitting any lower-case letter (besides 'j' and 'k') will move the selection to the next option that starts with that letter (non-looping). For example, when first opening the start menu, hitting 'e' will move the selection to "Editing". Hitting any upper-case letter will move the selection to any previous option that starts with that letter (also non-looping). For example, when initially opening the start menu, the selected option is "About". After hitting 'j' (moving down), hitting 'A' will return the selection to "About".
|
For faster navigation, hitting any lower-case letter (besides 'j' and 'k') will move the selection to the next option that starts with that letter (non-looping). For example, when first opening the start menu, hitting 'e' will move the selection to "Editing". Hitting any upper-case letter will move the selection to any previous option that starts with that letter (also non-looping). For example, when initially opening the start menu, the selected option is "About". After hitting 'j' (moving down), hitting 'A' will return the selection to "About".
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ The terminal starts off in INPUT mode, which allows entering commands to run. If
|
|||||||
|
|
||||||
In INPUT mode, commands can be freely typed. There are a few special control sequences:
|
In INPUT mode, commands can be freely typed. There are a few special control sequences:
|
||||||
|
|
||||||
- `ctrl+p`: Equivalent to the up arrow in most terminals. Brings up the previous command in the command history, and so on.
|
- `ctrl+p` (or up arrow): Equivalent to the up arrow in most terminals. Brings up the previous command in the command history, and so on.
|
||||||
- `ctrl+n`: Equivalent to the down arrow in most terminals. Either clears the current input if not in a previous command, else brings up the next command in the command history.
|
- `ctrl+n` (or down arrow): Equivalent to the down arrow in most terminals. Either clears the current input if not in a previous command, else brings up the next command in the command history.
|
||||||
|
|
||||||
Tab completion is also supported, though only for file/directory paths.
|
Tab completion is also supported, though only for file/directory paths.
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ To get sudo to read from stdin, the `-S` option will need to be used (eg, `sudo
|
|||||||
|
|
||||||
## 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. The copy shortcut will copy the output of the last ran command.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
|||||||
9
install
@@ -1,10 +1,11 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
rm -rf /usr/local/bin/ming_bmps
|
rm -rf /usr/local/bin/ming_bmps
|
||||||
cp -r ./bmps /usr/local/bin/ming_bmps
|
cp -r ./bmps /usr/local/bin/ming_bmps
|
||||||
rm -rf /usr/local/bin/ming_bmps/nimbus-roman/*.bmp
|
rm -f /usr/local/bin/ming_bmps/nimbus-roman/*.bmp
|
||||||
rm -rf /usr/local/bin/ming_bmps/nimbus-romano/*.bmp
|
rm -f /usr/local/bin/ming_bmps/nimbus-romano/*.bmp
|
||||||
rm -rf /usr/local/bin/ming_bmps/shippori-mincho/*.bmp
|
rm -f /usr/local/bin/ming_bmps/shippori-mincho/*.bmp
|
||||||
rm /usr/local/bin/ming_bmps/*1440x842.bmp
|
rm -f /usr/local/bin/ming_bmps/*1440x842.bmp
|
||||||
|
rm -f /usr/local/bin/ming_bmps/*.svg
|
||||||
rm -rf /usr/local/bin/ming_docs
|
rm -rf /usr/local/bin/ming_docs
|
||||||
cp -r ./docs /usr/local/bin/ming_docs
|
cp -r ./docs /usr/local/bin/ming_docs
|
||||||
rm -rf /usr/local/bin/ming_docs/images
|
rm -rf /usr/local/bin/ming_docs/images
|
||||||
|
|||||||
108
linux/src/input.rs
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
use std::os::fd::RawFd;
|
||||||
|
use std::mem::size_of;
|
||||||
|
use std::ffi::CString;
|
||||||
|
|
||||||
|
use libc::{ open, close, read, poll, pollfd, input_event, timeval, __u16, __s32, c_void };
|
||||||
|
|
||||||
|
//https://stackoverflow.com/questions/15949163/read-from-dev-input#15949311
|
||||||
|
//https://www.man7.org/linux/man-pages/man2/poll.2.html
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[repr(u16)]
|
||||||
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
|
pub enum EventType {
|
||||||
|
EV_SYN = 0, //event sep
|
||||||
|
EV_KEY,
|
||||||
|
EV_REL,
|
||||||
|
EV_ABS,
|
||||||
|
//nothing below will probably ever be relevant to ming-wm
|
||||||
|
EV_MSC, //misc
|
||||||
|
EV_SW, //switch/toggle
|
||||||
|
EV_LED,
|
||||||
|
EV_SND,
|
||||||
|
EV_REP,
|
||||||
|
EV_FF,
|
||||||
|
EV_PWR,
|
||||||
|
EV_FF_STATUS,
|
||||||
|
Unknown(__u16),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<__u16> for EventType {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: __u16) -> Result<Self, Self::Error> {
|
||||||
|
//if the list is any longer should probably somehow make this a macro
|
||||||
|
let values = [Self::EV_SYN, Self::EV_KEY, Self::EV_REL, Self::EV_ABS, Self::EV_MSC, Self::EV_SW, Self::EV_LED, Self::EV_SND, Self::EV_REP, Self::EV_FF, Self::EV_PWR, Self::EV_FF_STATUS];
|
||||||
|
let value = value as usize;
|
||||||
|
if value >= values.len() {
|
||||||
|
Err(())
|
||||||
|
} else {
|
||||||
|
Ok(values[value])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//we do not care about time. no one cares about time (probably)
|
||||||
|
pub struct InputEvent {
|
||||||
|
pub type_: EventType,
|
||||||
|
pub code: __u16, //depends on EventType
|
||||||
|
pub value: __s32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Input(RawFd);
|
||||||
|
|
||||||
|
impl Input {
|
||||||
|
pub fn new(input_name: &str) -> Result<Self, ()> {
|
||||||
|
let input_name = CString::new(input_name).unwrap();
|
||||||
|
let fd = unsafe { open(input_name.as_ptr(), libc::O_RDONLY | libc::O_NONBLOCK) };
|
||||||
|
if fd == -1 {
|
||||||
|
Err(())
|
||||||
|
} else {
|
||||||
|
Ok(Self(fd))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for Input {
|
||||||
|
type Item = InputEvent;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
//wait until there is something available
|
||||||
|
let mut fds = vec![pollfd {
|
||||||
|
fd: self.0,
|
||||||
|
events: libc::POLLIN, //return when "there is data to read"
|
||||||
|
revents: 0,
|
||||||
|
}];
|
||||||
|
let poll_result = unsafe { poll(fds.as_mut_ptr(), 1, -1) }; //neg num means no timeout
|
||||||
|
if poll_result == -1 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
//now read the event
|
||||||
|
let ie_size = size_of::<input_event>();
|
||||||
|
let mut ie = input_event {
|
||||||
|
time: timeval {
|
||||||
|
tv_sec: 0,
|
||||||
|
tv_usec: 0,
|
||||||
|
},
|
||||||
|
type_: 0,
|
||||||
|
code: 0,
|
||||||
|
value: 0,
|
||||||
|
};
|
||||||
|
let read_result = unsafe { read(self.0, &mut ie as *mut _ as *mut c_void, ie_size) };
|
||||||
|
if read_result == -1 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let type_ = ie.type_.try_into().unwrap_or(EventType::Unknown(ie.type_));
|
||||||
|
Some(Self::Item {
|
||||||
|
type_,
|
||||||
|
code: ie.code,
|
||||||
|
value: ie.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Input {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { close(self.0) };
|
||||||
|
}
|
||||||
|
}
|
||||||
89
linux/src/keys.rs
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
use std::io::{ Read, Stdin };
|
||||||
|
use std::sync::mpsc::{ channel, Receiver };
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
//includes a section on reading keys
|
||||||
|
//https://viewsourcecode.org/snaptoken/kilo/02.enteringRawMode.html
|
||||||
|
|
||||||
|
const ALPHABET: [char; 26] = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
|
||||||
|
|
||||||
|
pub enum Key {
|
||||||
|
Char(char),
|
||||||
|
Alt(char),
|
||||||
|
Ctrl(char),
|
||||||
|
Backspace,
|
||||||
|
Esc,
|
||||||
|
ArrowUp,
|
||||||
|
ArrowDown,
|
||||||
|
ArrowLeft,
|
||||||
|
ArrowRight,
|
||||||
|
Other(u8), //we don't get about anything else, lmao
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RawStdin {
|
||||||
|
//bytes: Peekable<Bytes<StdinLock<'a>>>,
|
||||||
|
receiver: Receiver<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawStdin {
|
||||||
|
pub fn new(stdin: Stdin) -> Self {
|
||||||
|
let (sender, receiver) = channel();
|
||||||
|
thread::spawn(move || {
|
||||||
|
let bytes = stdin.lock().bytes();
|
||||||
|
for b in bytes {
|
||||||
|
sender.send(b.unwrap()).unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
RawStdin {
|
||||||
|
//bytes: stdin.lock().bytes().peekable(),
|
||||||
|
receiver,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for RawStdin {
|
||||||
|
type Item = Key;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let first = self.receiver.recv().unwrap();
|
||||||
|
Some(match first {
|
||||||
|
1..=26 => {
|
||||||
|
//ctrl
|
||||||
|
if first == 9 {
|
||||||
|
Key::Char('\t')
|
||||||
|
} else if first == 13 {
|
||||||
|
//ctrl+m and enter give the same thing
|
||||||
|
Key::Char('\n')
|
||||||
|
} else {
|
||||||
|
Key::Ctrl(ALPHABET[first as usize - 1])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
27 => {
|
||||||
|
//escape sequence
|
||||||
|
//not handling escape sequences that are 3+ bytes is probably going to come back to bite us
|
||||||
|
let n = self.receiver.try_recv();
|
||||||
|
if let Ok(b'[') = n {
|
||||||
|
let n = self.receiver.recv().unwrap();
|
||||||
|
match n {
|
||||||
|
b'A' => Key::ArrowUp,
|
||||||
|
b'B' => Key::ArrowDown,
|
||||||
|
b'C' => Key::ArrowRight,
|
||||||
|
b'D' => Key::ArrowLeft,
|
||||||
|
_ => Key::Other(n),
|
||||||
|
}
|
||||||
|
} else if n.is_ok() {
|
||||||
|
//Alt+<char> sends Esc+<char>
|
||||||
|
Key::Alt(char::from(n.unwrap()))
|
||||||
|
} else {
|
||||||
|
Key::Esc
|
||||||
|
}
|
||||||
|
},
|
||||||
|
127 => {
|
||||||
|
Key::Backspace
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
Key::Char(char::from(first))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,2 +1,5 @@
|
|||||||
pub mod fb;
|
pub mod fb;
|
||||||
|
pub mod raw;
|
||||||
|
pub mod keys;
|
||||||
|
pub mod pty;
|
||||||
|
pub mod input;
|
||||||
|
|||||||
55
linux/src/pty.rs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
use std::ptr;
|
||||||
|
use std::process::{ Command, Child };
|
||||||
|
use std::fs::File;
|
||||||
|
use std::os::fd::{ OwnedFd, FromRawFd };
|
||||||
|
|
||||||
|
use libc::openpty;
|
||||||
|
|
||||||
|
//basically the master and slave are linked? slave behaves just like normal terminal
|
||||||
|
//I don't totally get it, I guess just attach the command's stdout and stderr to ptyslave for reading?
|
||||||
|
|
||||||
|
pub struct PtyMaster {
|
||||||
|
pub file: File,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PtyMaster {
|
||||||
|
pub fn new(fd: OwnedFd) -> Self {
|
||||||
|
Self {
|
||||||
|
file: File::from(fd),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PtySlave {
|
||||||
|
pub file: File,
|
||||||
|
fd: OwnedFd,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PtySlave {
|
||||||
|
pub fn new(fd: OwnedFd) -> Self {
|
||||||
|
Self {
|
||||||
|
file: File::from(fd.try_clone().unwrap()),
|
||||||
|
fd,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//assume stdin is piped
|
||||||
|
pub fn attach_and_spawn(&self, command: &mut Command) -> std::io::Result<Child> {
|
||||||
|
command.stdout(self.fd.try_clone().unwrap());
|
||||||
|
command.stderr(self.fd.try_clone().unwrap());
|
||||||
|
command.spawn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_pty() -> Result<(PtyMaster, PtySlave), ()> {
|
||||||
|
let mut master_fd = 0;
|
||||||
|
let mut slave_fd = 0;
|
||||||
|
let result = unsafe { openpty(&mut master_fd, &mut slave_fd, ptr::null_mut(), ptr::null_mut(), ptr::null_mut()) };
|
||||||
|
if result == -1 {
|
||||||
|
Err(())
|
||||||
|
} else {
|
||||||
|
let master_fd = unsafe { OwnedFd::from_raw_fd(master_fd) };
|
||||||
|
let slave_fd = unsafe { OwnedFd::from_raw_fd(slave_fd) };
|
||||||
|
Ok((PtyMaster::new(master_fd), PtySlave::new(slave_fd)))
|
||||||
|
}
|
||||||
|
}
|
||||||
65
linux/src/raw.rs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
use std::io::Stdout;
|
||||||
|
use std::mem::zeroed;
|
||||||
|
use std::os::fd::AsRawFd;
|
||||||
|
|
||||||
|
use libc::{ cfmakeraw, c_int, tcgetattr, tcsetattr, termios, TCSAFLUSH };
|
||||||
|
|
||||||
|
//https://viewsourcecode.org/snaptoken/kilo/02.enteringRawMode.html
|
||||||
|
//on TCSAFLUSH: "The TCSAFLUSH argument specifies when to apply the change: in this case, it waits for all pending output to be written to the terminal, and also discards any input that hasn't been read."
|
||||||
|
|
||||||
|
//https://www.man7.org/linux/man-pages/man3/termios.3.html
|
||||||
|
//(use cfmakeraw instead doing all those bitwise stuff manually)
|
||||||
|
|
||||||
|
//enter and exit tty raw mode
|
||||||
|
|
||||||
|
pub struct RawStdout {
|
||||||
|
pub stdout: Stdout,
|
||||||
|
old_termios: termios,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawStdout {
|
||||||
|
pub fn new(stdout: Stdout) -> Self {
|
||||||
|
RawStdout {
|
||||||
|
stdout,
|
||||||
|
old_termios: unsafe { zeroed() },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_termios(raw_fd: c_int) -> Result<termios, ()> {
|
||||||
|
let mut termios_struct: termios = unsafe { zeroed() };
|
||||||
|
let result = unsafe {
|
||||||
|
tcgetattr(raw_fd, &mut termios_struct)
|
||||||
|
};
|
||||||
|
if result != -1 {
|
||||||
|
Ok(termios_struct)
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enter_raw_mode(&mut self) -> Result<(), ()> {
|
||||||
|
let raw_fd = self.stdout.as_raw_fd();
|
||||||
|
let mut termios_struct = Self::get_termios(raw_fd)?;
|
||||||
|
self.old_termios = termios_struct;
|
||||||
|
let result = unsafe {
|
||||||
|
cfmakeraw(&mut termios_struct);
|
||||||
|
tcsetattr(raw_fd, TCSAFLUSH, &mut termios_struct)
|
||||||
|
};
|
||||||
|
if result != -1 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exit_raw_mode(&mut self) -> Result<(), ()> {
|
||||||
|
let result = unsafe {
|
||||||
|
tcsetattr(self.stdout.as_raw_fd(), TCSAFLUSH, &mut self.old_termios)
|
||||||
|
};
|
||||||
|
if result != -1 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
rm -rf ~/.local/bin/ming_bmps
|
rm -rf ~/.local/bin/ming_bmps
|
||||||
cp -r ./bmps ~/.local/bin/ming_bmps
|
cp -r ./bmps ~/.local/bin/ming_bmps
|
||||||
rm -rf ~/.local/bin/ming_bmps/nimbus-roman/*.bmp
|
rm -f ~/.local/bin/ming_bmps/nimbus-roman/*.bmp
|
||||||
rm -rf ~/.local/bin/ming_bmps/nimbus-romano/*.bmp
|
rm -f ~/.local/bin/ming_bmps/nimbus-romano/*.bmp
|
||||||
rm -rf ~/.local/bin/ming_bmps/shippori-mincho/*.bmp
|
rm -f ~/.local/bin/ming_bmps/shippori-mincho/*.bmp
|
||||||
rm ~/.local/bin/ming_bmps/*1440x842.bmp
|
rm -f ~/.local/bin/ming_bmps/*1440x842.bmp
|
||||||
|
rm -f ~/.local/bin/ming_bmps/*.svg
|
||||||
rm -rf ~/.local/bin/ming_docs
|
rm -rf ~/.local/bin/ming_docs
|
||||||
cp -r ./docs ~/.local/bin/ming_docs
|
cp -r ./docs ~/.local/bin/ming_docs
|
||||||
rm -rf ~/.local/bin/ming_docs/images
|
rm -rf ~/.local/bin/ming_docs/images
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ming-wm-lib"
|
name = "ming-wm-lib"
|
||||||
version = "0.1.4"
|
version = "0.2.0"
|
||||||
repository = "https://github.com/stjet/ming-wm"
|
repository = "https://github.com/stjet/ming-wm"
|
||||||
description = "library for building windows for ming-wm in rust"
|
description = "library for building windows for ming-wm in rust"
|
||||||
|
readme = "README.md"
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1,6 @@
|
|||||||
Library for building [ming-wm](https://github.com/stjet/ming-wm) windows in Rust.
|
Library for building [ming-wm](https://github.com/stjet/ming-wm) windows in Rust.
|
||||||
|
|
||||||
|
Documentation [here](https://docs.rs/ming-wm-lib).
|
||||||
|
|
||||||
|
The most likely usage of this crate is to implement the [WindowLike trait](https://docs.rs/ming-wm-lib/latest/ming_wm_lib/window_manager_types/trait.WindowLike.html), and then set up [IPC](https://docs.rs/ming-wm-lib/latest/ming_wm_lib/ipc/fn.listen.html) (which automatically handles serialisation).
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ use std::vec;
|
|||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
use crate::components::Component;
|
use crate::components::Component;
|
||||||
use ming_wm_lib::framebuffer_types::{ Dimensions, Point };
|
use crate::framebuffer_types::{ Dimensions, Point };
|
||||||
use ming_wm_lib::themes::ThemeInfo;
|
use crate::themes::ThemeInfo;
|
||||||
use ming_wm_lib::messages::WindowMessage;
|
use crate::messages::WindowMessage;
|
||||||
use ming_wm_lib::window_manager_types::DrawInstructions;
|
use crate::window_manager_types::DrawInstructions;
|
||||||
|
|
||||||
pub struct HighlightButton<T> {
|
pub struct HighlightButton<T> {
|
||||||
name_: String,
|
name_: String,
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
use ming_wm_lib::themes::ThemeInfo;
|
use crate::themes::ThemeInfo;
|
||||||
use ming_wm_lib::messages::WindowMessage;
|
use crate::messages::WindowMessage;
|
||||||
use ming_wm_lib::window_manager_types::DrawInstructions;
|
use crate::window_manager_types::DrawInstructions;
|
||||||
|
|
||||||
pub mod toggle_button;
|
pub mod toggle_button;
|
||||||
pub mod highlight_button;
|
pub mod highlight_button;
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
use std::vec;
|
use std::vec;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
use crate::framebuffer_types::{ Dimensions, Point };
|
||||||
use ming_wm_lib::framebuffer_types::{ Dimensions, Point };
|
use crate::themes::ThemeInfo;
|
||||||
use ming_wm_lib::themes::ThemeInfo;
|
use crate::messages::WindowMessage;
|
||||||
use ming_wm_lib::messages::WindowMessage;
|
use crate::window_manager_types::DrawInstructions;
|
||||||
use ming_wm_lib::window_manager_types::DrawInstructions;
|
use crate::utils::calc_actual_lines;
|
||||||
use ming_wm_lib::utils::calc_actual_lines;
|
|
||||||
use crate::components::Component;
|
use crate::components::Component;
|
||||||
|
|
||||||
const MONO_WIDTH: u8 = 10;
|
const MONO_WIDTH: u8 = 10;
|
||||||
@@ -2,10 +2,10 @@ use std::vec;
|
|||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
use crate::components::Component;
|
use crate::components::Component;
|
||||||
use ming_wm_lib::framebuffer_types::{ Dimensions, Point };
|
use crate::framebuffer_types::{ Dimensions, Point };
|
||||||
use ming_wm_lib::themes::ThemeInfo;
|
use crate::themes::ThemeInfo;
|
||||||
use ming_wm_lib::messages::WindowMessage;
|
use crate::messages::WindowMessage;
|
||||||
use ming_wm_lib::window_manager_types::DrawInstructions;
|
use crate::window_manager_types::DrawInstructions;
|
||||||
|
|
||||||
const MONO_WIDTH: u8 = 10;
|
const MONO_WIDTH: u8 = 10;
|
||||||
|
|
||||||
@@ -2,10 +2,10 @@ use std::vec;
|
|||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
use crate::components::Component;
|
use crate::components::Component;
|
||||||
use ming_wm_lib::framebuffer_types::{ Dimensions, Point };
|
use crate::framebuffer_types::{ Dimensions, Point };
|
||||||
use ming_wm_lib::themes::ThemeInfo;
|
use crate::themes::ThemeInfo;
|
||||||
use ming_wm_lib::messages::WindowMessage;
|
use crate::messages::WindowMessage;
|
||||||
use ming_wm_lib::window_manager_types::DrawInstructions;
|
use crate::window_manager_types::DrawInstructions;
|
||||||
|
|
||||||
pub struct ToggleButton<T> {
|
pub struct ToggleButton<T> {
|
||||||
name_: String,
|
name_: String,
|
||||||
@@ -31,6 +31,7 @@ pub trait WindowLike {
|
|||||||
|
|
||||||
const LOG: bool = false;
|
const LOG: bool = false;
|
||||||
|
|
||||||
|
/// Listen and process what the window manager writes to our stdin
|
||||||
pub fn listen(mut window_like: impl WindowLike) {
|
pub fn listen(mut window_like: impl WindowLike) {
|
||||||
panic::set_hook(Box::new(|panic_info| {
|
panic::set_hook(Box::new(|panic_info| {
|
||||||
let (filename, line) = panic_info.location().map(|l| (l.file(), l.line())).unwrap_or(("<unknown>", 0));
|
let (filename, line) = panic_info.location().map(|l| (l.file(), l.line())).unwrap_or(("<unknown>", 0));
|
||||||
@@ -57,22 +58,24 @@ pub fn listen(mut window_like: impl WindowLike) {
|
|||||||
let arg = &parts.collect::<Vec<&str>>().join(" ");
|
let arg = &parts.collect::<Vec<&str>>().join(" ");
|
||||||
let output = match method {
|
let output = match method {
|
||||||
"handle_message" => {
|
"handle_message" => {
|
||||||
format!("{}", &window_like.handle_message(WindowMessage::deserialize(arg).unwrap()).serialize())
|
//newlines allowed for ClipboardCopy, but represented by the Linear A char
|
||||||
|
window_like.handle_message(WindowMessage::deserialize(arg).unwrap()).serialize().to_string()
|
||||||
},
|
},
|
||||||
"draw" => {
|
"draw" => {
|
||||||
format!("{}", &window_like.draw(&ThemeInfo::deserialize(arg).unwrap()).serialize().replace("\n", ""))
|
//newlines never allowed
|
||||||
|
window_like.draw(&ThemeInfo::deserialize(arg).unwrap()).serialize().replace("\n", "").to_string()
|
||||||
},
|
},
|
||||||
"title" => {
|
"title" => {
|
||||||
format!("{}", window_like.title())
|
window_like.title().to_string()
|
||||||
},
|
},
|
||||||
"resizable" => {
|
"resizable" => {
|
||||||
format!("{}", window_like.resizable())
|
window_like.resizable().to_string()
|
||||||
},
|
},
|
||||||
"subtype" => {
|
"subtype" => {
|
||||||
format!("{}", &window_like.subtype().serialize())
|
window_like.subtype().serialize().to_string()
|
||||||
},
|
},
|
||||||
"ideal_dimensions" => {
|
"ideal_dimensions" => {
|
||||||
format!("{}", &window_like.ideal_dimensions(Dimensions::deserialize(arg).unwrap()).serialize())
|
window_like.ideal_dimensions(Dimensions::deserialize(arg).unwrap()).serialize().to_string()
|
||||||
},
|
},
|
||||||
_ => String::new(),
|
_ => String::new(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ pub mod themes;
|
|||||||
pub mod serialize;
|
pub mod serialize;
|
||||||
pub mod messages;
|
pub mod messages;
|
||||||
pub mod ipc;
|
pub mod ipc;
|
||||||
|
pub mod components;
|
||||||
pub mod dirs;
|
pub mod dirs;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod logging;
|
pub mod logging;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use std::io::Write;
|
|||||||
|
|
||||||
use crate::dirs::data_dir;
|
use crate::dirs::data_dir;
|
||||||
|
|
||||||
|
/// Writes to `<XDG data directory>/ming-wm/logs.txt`. Use only for debugging!
|
||||||
pub fn log(message: &str) {
|
pub fn log(message: &str) {
|
||||||
let data = data_dir().unwrap().into_os_string().into_string().unwrap();
|
let data = data_dir().unwrap().into_os_string().into_string().unwrap();
|
||||||
let _ = create_dir(format!("{}/ming-wm", data));
|
let _ = create_dir(format!("{}/ming-wm", data));
|
||||||
|
|||||||
@@ -4,12 +4,14 @@ use std::vec::Vec;
|
|||||||
use crate::framebuffer_types::Dimensions;
|
use crate::framebuffer_types::Dimensions;
|
||||||
use crate::window_manager_types::{ WindowLike, KeyChar };
|
use crate::window_manager_types::{ WindowLike, KeyChar };
|
||||||
|
|
||||||
|
/// Window manager internal usage
|
||||||
pub enum WindowManagerMessage {
|
pub enum WindowManagerMessage {
|
||||||
KeyChar(KeyChar),
|
KeyChar(KeyChar),
|
||||||
Touch(usize, usize),
|
Touch(usize, usize),
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Window manager internal usage
|
||||||
pub type WindowBox = Box<dyn WindowLike>;
|
pub type WindowBox = Box<dyn WindowLike>;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -50,10 +52,50 @@ impl WindowMessageResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//struct because may add more fields later (so struct is better for code backward compatibility)
|
||||||
pub struct KeyPress {
|
pub struct KeyPress {
|
||||||
pub key: char,
|
pub key: char,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl KeyPress {
|
||||||
|
pub fn is_enter(&self) -> bool {
|
||||||
|
self.key == '𐘂'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_backspace(&self) -> bool {
|
||||||
|
self.key == '𐘁'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_escape(&self) -> bool {
|
||||||
|
self.key == '𐘃'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_up_arrow(&self) -> bool {
|
||||||
|
self.key == '𐙘'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_down_arrow(&self) -> bool {
|
||||||
|
self.key == '𐘞'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_left_arrow(&self) -> bool {
|
||||||
|
self.key == '𐙣'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_right_arrow(&self) -> bool {
|
||||||
|
self.key == '𐙥'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_arrow(&self) -> bool {
|
||||||
|
self.is_up_arrow() || self.is_down_arrow() || self.is_left_arrow() || self.is_right_arrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is not enter, backspace, arrow keys (the Linear A stuff)
|
||||||
|
pub fn is_regular(&self) -> bool {
|
||||||
|
!self.is_enter() && !self.is_backspace() && !self.is_escape() && !self.is_arrow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
Left,
|
Left,
|
||||||
@@ -87,7 +129,7 @@ pub type WindowsVec = Vec<(usize, String)>;
|
|||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum InfoType {
|
pub enum InfoType {
|
||||||
//let taskbar know what the current windows in the workspace are
|
/// Let taskbar know what the current windows in the workspace are
|
||||||
WindowsInWorkspace(WindowsVec, usize), //Vec<(id, name)>, focused id
|
WindowsInWorkspace(WindowsVec, usize), //Vec<(id, name)>, focused id
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
@@ -102,7 +144,8 @@ pub enum WindowMessage {
|
|||||||
Unfocus,
|
Unfocus,
|
||||||
FocusClick,
|
FocusClick,
|
||||||
ChangeDimensions(Dimensions),
|
ChangeDimensions(Dimensions),
|
||||||
Touch(usize, usize), //for onscreen keyboard only
|
/// For onscreen keyboard only
|
||||||
|
Touch(usize, usize),
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,10 +39,10 @@ fn option_to_string<T: Display>(option: &Option<T>) -> String {
|
|||||||
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];
|
||||||
let mut c_i = 0;
|
|
||||||
//won't return error if rgb is 0, 1, or 2 elements.
|
//won't return error if rgb is 0, 1, or 2 elements.
|
||||||
//I guess that's okay, since it doesn't panic either
|
//I guess that's okay, since it doesn't panic either
|
||||||
for c in rgb {
|
//c_i is the loop counter. enumerate(), you are awesome
|
||||||
|
for (c_i, c) in rgb.enumerate() {
|
||||||
if c_i == 3 {
|
if c_i == 3 {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,6 @@ fn get_color(serialized: &str) -> Result<[u8; 3], ()> {
|
|||||||
} else {
|
} else {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
c_i += 1;
|
|
||||||
}
|
}
|
||||||
Ok(color)
|
Ok(color)
|
||||||
}
|
}
|
||||||
@@ -68,7 +67,7 @@ fn get_two_array(serialized: &str) -> Result<[usize; 2], ()> {
|
|||||||
}
|
}
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
return Ok(a);
|
Ok(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Serializable {
|
pub trait Serializable {
|
||||||
@@ -87,9 +86,8 @@ impl Serializable for ThemeInfo {
|
|||||||
let serialized = if serialized.ends_with("\n") { &serialized[..serialized.len() - 1] } else { serialized };
|
let serialized = if serialized.ends_with("\n") { &serialized[..serialized.len() - 1] } else { serialized };
|
||||||
let mut theme_info: ThemeInfo = Default::default();
|
let mut theme_info: ThemeInfo = Default::default();
|
||||||
let arrays = serialized.split(":");
|
let arrays = serialized.split(":");
|
||||||
let mut a_i = 0;
|
|
||||||
//won't error or panic if less than 9... rest will just be black by default I guess
|
//won't error or panic if less than 9... rest will just be black by default I guess
|
||||||
for a in arrays {
|
for (a_i, a) in arrays.enumerate() {
|
||||||
if a_i == 9 {
|
if a_i == 9 {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
@@ -127,7 +125,6 @@ impl Serializable for ThemeInfo {
|
|||||||
if a_i == 8 {
|
if a_i == 8 {
|
||||||
return Ok(theme_info);
|
return Ok(theme_info);
|
||||||
}
|
}
|
||||||
a_i += 1;
|
|
||||||
}
|
}
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
@@ -149,7 +146,7 @@ impl Serializable for WindowMessageResponse {
|
|||||||
WindowMessageResponse::Request(req) => {
|
WindowMessageResponse::Request(req) => {
|
||||||
let req = match req {
|
let req = match req {
|
||||||
WindowManagerRequest::OpenWindow(name) => format!("OpenWindow/{}", name),
|
WindowManagerRequest::OpenWindow(name) => format!("OpenWindow/{}", name),
|
||||||
WindowManagerRequest::ClipboardCopy(name) => format!("ClipboardCopy/{}", name),
|
WindowManagerRequest::ClipboardCopy(copy_string) => format!("ClipboardCopy/{}", copy_string.replace("\n", "𐘂")), //serialised output must be 1 line
|
||||||
WindowManagerRequest::CloseStartMenu => "CloseStartMenu".to_string(),
|
WindowManagerRequest::CloseStartMenu => "CloseStartMenu".to_string(),
|
||||||
WindowManagerRequest::Unlock => "Unlock".to_string(),
|
WindowManagerRequest::Unlock => "Unlock".to_string(),
|
||||||
WindowManagerRequest::Lock => "Lock".to_string(),
|
WindowManagerRequest::Lock => "Lock".to_string(),
|
||||||
@@ -220,7 +217,7 @@ impl Serializable for DrawInstructions {
|
|||||||
match self {
|
match self {
|
||||||
//use \x1E (record separator) because it won't be in strings. it better fucking not be at least
|
//use \x1E (record separator) because it won't be in strings. it better fucking not be at least
|
||||||
DrawInstructions::Rect(p, d, c) => format!("Rect/{}\x1E{}\x1E{}", array_to_string(p), array_to_string(d), array_to_string(c)),
|
DrawInstructions::Rect(p, d, c) => format!("Rect/{}\x1E{}\x1E{}", array_to_string(p), array_to_string(d), array_to_string(c)),
|
||||||
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)),
|
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)),
|
||||||
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),
|
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),
|
||||||
DrawInstructions::Bmp(p, s, b) => format!("Bmp/{}\x1E{}\x1E{}", array_to_string(p), s, b),
|
DrawInstructions::Bmp(p, s, b) => format!("Bmp/{}\x1E{}\x1E{}", array_to_string(p), s, b),
|
||||||
DrawInstructions::Circle(p, u, c) => format!("Circle/{}\x1E{}\x1E{}", array_to_string(p), u, array_to_string(c)),
|
DrawInstructions::Circle(p, u, c) => format!("Circle/{}\x1E{}\x1E{}", array_to_string(p), u, array_to_string(c)),
|
||||||
@@ -649,7 +646,7 @@ impl Serializable for WindowMessage {
|
|||||||
"FullscreenWindow" => Some(ShortcutType::FullscreenWindow),
|
"FullscreenWindow" => Some(ShortcutType::FullscreenWindow),
|
||||||
"HalfWidthWindow" => Some(ShortcutType::HalfWidthWindow),
|
"HalfWidthWindow" => Some(ShortcutType::HalfWidthWindow),
|
||||||
"ClipboardCopy" => Some(ShortcutType::ClipboardCopy),
|
"ClipboardCopy" => Some(ShortcutType::ClipboardCopy),
|
||||||
"ClipboardPaste" => Some(ShortcutType::ClipboardPaste(get_rest_of_split(&mut parts, Some("/")))),
|
"ClipboardPaste" => Some(ShortcutType::ClipboardPaste(get_rest_of_split(&mut parts, Some("/")).replace("𐘂", "\n"))),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
if let Some(shortcut) = shortcut {
|
if let Some(shortcut) = shortcut {
|
||||||
@@ -674,8 +671,7 @@ impl Serializable for WindowMessage {
|
|||||||
}
|
}
|
||||||
let mut w_tuple: (usize, String) = Default::default();
|
let mut w_tuple: (usize, String) = Default::default();
|
||||||
let mut w_vec = Vec::new();
|
let mut w_vec = Vec::new();
|
||||||
let mut i = 0;
|
for (i, a) in arg2.unwrap().split("\x1F").enumerate() {
|
||||||
for a in arg2.unwrap().split("\x1F") {
|
|
||||||
if i % 2 == 0 {
|
if i % 2 == 0 {
|
||||||
if let Ok(n) = a.parse() {
|
if let Ok(n) = a.parse() {
|
||||||
w_tuple.0 = n;
|
w_tuple.0 = n;
|
||||||
@@ -684,7 +680,6 @@ impl Serializable for WindowMessage {
|
|||||||
w_tuple.1 = a.to_string();
|
w_tuple.1 = a.to_string();
|
||||||
w_vec.push(w_tuple.clone());
|
w_vec.push(w_tuple.clone());
|
||||||
}
|
}
|
||||||
i += 1;
|
|
||||||
}
|
}
|
||||||
let arg2 = parts2.next();
|
let arg2 = parts2.next();
|
||||||
if arg2.is_none() {
|
if arg2.is_none() {
|
||||||
|
|||||||
@@ -97,12 +97,13 @@ const THEME_INFOS: [(Themes, ThemeInfo); 5] = [
|
|||||||
//
|
//
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/// Window manager internal usage
|
||||||
pub fn get_theme_info(theme: &Themes) -> Option<ThemeInfo> {
|
pub fn get_theme_info(theme: &Themes) -> Option<ThemeInfo> {
|
||||||
for pair in THEME_INFOS {
|
for pair in THEME_INFOS {
|
||||||
if &pair.0 == theme {
|
if &pair.0 == theme {
|
||||||
return Some(pair.1);
|
return Some(pair.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return None;
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ pub trait Substring {
|
|||||||
fn substring(&self, start: usize, end: usize) -> &str;
|
fn substring(&self, start: usize, end: usize) -> &str;
|
||||||
fn remove(&self, index: usize, len: usize) -> String;
|
fn remove(&self, index: usize, len: usize) -> String;
|
||||||
fn remove_last(&self) -> String;
|
fn remove_last(&self) -> String;
|
||||||
|
fn find_substring(&self, substr: &str) -> Option<usize>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Substring for String {
|
impl Substring for String {
|
||||||
@@ -29,6 +30,14 @@ impl Substring for String {
|
|||||||
byte_end += char_length;
|
byte_end += char_length;
|
||||||
}
|
}
|
||||||
&self[byte_start..byte_end]
|
&self[byte_start..byte_end]
|
||||||
|
/*
|
||||||
|
let mut result = String::new();
|
||||||
|
let mut chars = self.chars().skip(start);
|
||||||
|
for _i in 0..(end - start) {
|
||||||
|
result += &chars.next().unwrap().to_string();
|
||||||
|
}
|
||||||
|
result
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove(&self, index: usize, len: usize) -> String {
|
fn remove(&self, index: usize, len: usize) -> String {
|
||||||
@@ -38,13 +47,26 @@ impl Substring for String {
|
|||||||
fn remove_last(&self) -> String {
|
fn remove_last(&self) -> String {
|
||||||
self.substring(0, self.chars().count() - 1).to_string()
|
self.substring(0, self.chars().count() - 1).to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_substring(&self, substr: &str) -> Option<usize> {
|
||||||
|
//slightly inefficient
|
||||||
|
let substr_len = substr.chars().count();
|
||||||
|
let self_len = self.chars().count();
|
||||||
|
if substr_len <= self_len {
|
||||||
|
for start in 0..=(self_len - substr_len) {
|
||||||
|
if self.substring(start, start + substr_len) == substr {
|
||||||
|
return Some(start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//the tuple is first, line #, actual line
|
//the tuple is first, line #, actual line
|
||||||
pub fn calc_actual_lines<'a>(lines: impl Iterator<Item = &'a String>, max_chars_per_line: usize, one_extra: bool) -> Vec<(bool, usize, String)> {
|
pub fn calc_actual_lines<'a>(lines: impl Iterator<Item = &'a String>, max_chars_per_line: usize, one_extra: bool) -> Vec<(bool, usize, String)> {
|
||||||
let mut actual_lines = Vec::new();
|
let mut actual_lines = Vec::new();
|
||||||
let mut line_num = 0;
|
for (line_num, real_line) in lines.enumerate() {
|
||||||
for real_line in lines {
|
|
||||||
let mut line = real_line.to_string() + if one_extra { " " } else { "" };
|
let mut line = real_line.to_string() + if one_extra { " " } else { "" };
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
loop {
|
loop {
|
||||||
@@ -62,7 +84,6 @@ pub fn calc_actual_lines<'a>(lines: impl Iterator<Item = &'a String>, max_chars_
|
|||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
line_num += 1;
|
|
||||||
}
|
}
|
||||||
actual_lines
|
actual_lines
|
||||||
}
|
}
|
||||||
@@ -132,7 +153,7 @@ pub fn hex_to_u8(c1: char, c2: char) -> u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_hex(c: char) -> bool {
|
pub fn is_hex(c: char) -> bool {
|
||||||
HEX_CHARS.iter().position(|hc| hc == &c).is_some()
|
HEX_CHARS.iter().any(|hc| hc == &c)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn point_inside(point: Point, top_left: Point, size: Dimensions) -> bool {
|
pub fn point_inside(point: Point, top_left: Point, size: Dimensions) -> bool {
|
||||||
@@ -194,3 +215,15 @@ pub fn path_autocomplete(current_path: &str, partial_path: &str) -> Option<Strin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_all_files(dir: PathBuf) -> Vec<PathBuf> {
|
||||||
|
let mut files = Vec::new();
|
||||||
|
for entry in read_dir(dir).unwrap() {
|
||||||
|
let path = entry.unwrap().path();
|
||||||
|
if path.is_dir() {
|
||||||
|
files.extend(get_all_files(path));
|
||||||
|
} else {
|
||||||
|
files.push(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
files
|
||||||
|
}
|
||||||
|
|||||||