From 992800800b2d49aabadc5b7632635287e7ac0d4a Mon Sep 17 00:00:00 2001 From: Skia Date: Sat, 26 Dec 2020 04:28:06 +0100 Subject: [PATCH] First 'working' version --- Cargo.lock | 80 +++++++++++++++++++++++++++++++ Cargo.toml | 2 + src/main.rs | 135 ++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 209 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 81cf702..884d903 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,9 +6,89 @@ version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +[[package]] +name = "itoa" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "serde" +version = "1.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "swaysome" version = "0.1.0" dependencies = [ "byteorder", + "serde", + "serde_json", ] + +[[package]] +name = "syn" +version = "1.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a571a711dddd09019ccc628e1b17fe87c59b09d513c06c026877aa708334f37a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" diff --git a/Cargo.toml b/Cargo.toml index 99029a3..fa7a0fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,5 @@ edition = "2018" [dependencies] byteorder = "1" +serde = { version = "1", features = ["derive"] } +serde_json = "1" diff --git a/src/main.rs b/src/main.rs index 83d8d60..63726cf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ // client.rs extern crate byteorder; +extern crate serde; +extern crate serde_json; use std::env; use std::path::Path; @@ -9,8 +11,55 @@ use std::os::unix::net::UnixStream; use std::mem; use std::io::Cursor; +use serde::{Deserialize, Serialize}; + use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian}; +const RUN_COMMAND: u32 = 0; +const GET_WORKSPACES: u32 = 1; +const SUBSCRIBE: u32 = 2; +const GET_OUTPUTS: u32 = 3; + +#[derive(Serialize, Deserialize)] +struct WorkspaceRect { + x: usize, + y: usize, +} + +#[derive(Serialize, Deserialize)] +struct Workspace { + num: usize, + name: String, + visible: bool, + focused: bool, + rect: WorkspaceRect, + output: String, +} + +#[derive(Serialize, Deserialize)] +struct OutputMode { + width: usize, + height: usize, + refresh: usize, +} + +#[derive(Serialize, Deserialize)] +struct Output { + name: String, + make: String, + model: String, + serial: String, + active: bool, + primary: bool, + focused: bool, + scale: f32, + subpixel_hinting: String, + transform: String, + current_workspace: String, + modes: Vec, + current_mode: OutputMode, +} + fn get_stream() -> UnixStream { let socket_path = match env::var("I3SOCK") { @@ -37,20 +86,23 @@ fn send_msg(mut stream: &UnixStream, msg_type: u32, payload: &str) { // let magic = b"i3-ipc"; // let mut msg = b"i3-ipc".to_vec(); - let mut msg: [u8; 6 * mem::size_of::() + 2 * mem::size_of::()] = *b"i3-ipc00000000"; + let mut msg_prefix: [u8; 6 * mem::size_of::() + 2 * mem::size_of::()] = *b"i3-ipc00000000"; - msg[6..].as_mut() + msg_prefix[6..].as_mut() .write_u32::(payload_length) .expect("Unable to write"); - msg[10..].as_mut() + msg_prefix[10..].as_mut() .write_u32::(msg_type) .expect("Unable to write"); - // let msg = format!("{}{}{}{}", magic, pl_t, pl_l, payload); - println!("msg: {:x?}", msg); + // let msg_prefix = format!("{}{}{}{}", magic, pl_t, pl_l, payload); + println!("msg_prefix: {:x?}", msg_prefix); - match stream.write_all(&msg) { + let mut msg: Vec = msg_prefix[..].to_vec(); + msg.extend(payload.as_bytes()); + + match stream.write_all(&msg[..]) { Err(_) => panic!("couldn't send message"), Ok(_) => {} } @@ -83,6 +135,64 @@ fn read_msg(mut stream: &UnixStream) -> Result { } } +fn get_current_output_name(stream: &UnixStream) -> String { + send_msg(&stream, GET_OUTPUTS, ""); + let o = match read_msg(&stream) { + Ok(msg) => msg, + Err(_) => panic!("Unable to get current workspace"), + }; + let outputs: Vec = serde_json::from_str(&o).unwrap(); + + let focused_output_index = match outputs.iter().position(|x| x.focused) { + Some(i) => i, + None => panic!("WTF! No focused output???"), + }; + + // outputs[focused_output_index].name.clone() + format!("{}", focused_output_index) +} + +fn get_current_workspace_name(stream: &UnixStream) -> String { + send_msg(&stream, GET_WORKSPACES, ""); + let ws = match read_msg(&stream) { + Ok(msg) => msg, + Err(_) => panic!("Unable to get current workspace"), + }; + let workspaces: Vec = serde_json::from_str(&ws).unwrap(); + + let focused_workspace_index = match workspaces.iter().position(|x| x.focused) { + Some(i) => i, + None => panic!("WTF! No focused workspace???"), + }; + + workspaces[focused_workspace_index].name.clone() +} + +fn move_container_to_workspace(stream: &UnixStream, workspace_name: &String) { + let mut cmd: String = "move container to workspace ".to_string(); + let output = get_current_output_name(stream); + cmd.push_str(&output); + cmd.push_str(&workspace_name); + println!("Sending command: '{}'", &cmd); + send_msg(&stream, RUN_COMMAND, &cmd); + match read_msg(&stream) { + Ok(msg) => println!("msg: {}", msg), + Err(_) => panic!("Unable to get current workspace"), + }; +} + +fn focus_to_workspace(stream: &UnixStream, workspace_name: &String) { + let mut cmd: String = "workspace ".to_string(); + let output = get_current_output_name(stream); + cmd.push_str(&output); + cmd.push_str(&workspace_name); + println!("Sending command: '{}'", &cmd); + send_msg(&stream, RUN_COMMAND, &cmd); + match read_msg(&stream) { + Ok(msg) => println!("msg: {}", msg), + Err(_) => panic!("Unable to get current workspace"), + }; +} fn main() { // `args` returns the arguments passed to the program @@ -91,8 +201,17 @@ fn main() { let mut stream = get_stream(); - send_msg(&stream, 1, ""); + println!("Current workspace name: {}", get_current_workspace_name(&mut stream)); - read_msg(&stream); + send_msg(&stream, 3, ""); + match read_msg(&stream) { + Ok(msg) => println!("outputs: {}", msg), + Err(_) => panic!("Unable to get current workspace"), + }; + match args[1].as_str() { + "move" => move_container_to_workspace(&stream, &args[2]), + "focus" => focus_to_workspace(&stream, &args[2]), + _ => {}, + } }