M Cargo.lock => Cargo.lock +3 -3
@@ 485,9 485,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
-version = "0.2.142"
+version = "0.2.143"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
+checksum = "edc207893e85c5d6be840e969b496b53d94cec8be2d501b214f50daa97fa8024"
[[package]]
name = "link-cplusplus"
@@ 861,7 861,7 @@ dependencies = [
[[package]]
name = "swayr"
-version = "0.26.0"
+version = "0.26.1"
dependencies = [
"clap",
"directories",
M README.md => README.md +4 -1
@@ 235,7 235,10 @@ These commands change the layout of the current workspace.
application name and the pid for each window. The result of the command is a
JSON array with objects containing the exit code, stdout, stderr, and a
(system) error field. If any command returns non-zero, so will
- `for-each-window`.
+ `for-each-window`. The shell commands will be executed in parallel they must
+ finish within 2 seconds, otherwise they'll be killed. Otherwise, the command
+ execution would block `swayrd` for as long as the slowest thread requires,
+ e.g., `sleep 10` would block for slightly over 10 seconds.
#### Miscellaneous commands
M swayr/Cargo.toml => swayr/Cargo.toml +1 -1
@@ 1,6 1,6 @@
[package]
name = "swayr"
-version = "0.26.0"
+version = "0.26.1"
description = "A LRU window-switcher (and more) for the sway window manager"
homepage = "https://sr.ht/~tsdh/swayr/"
repository = "https://git.sr.ht/~tsdh/swayr"
M swayr/src/cmds.rs => swayr/src/cmds.rs +23 -9
@@ 29,8 29,10 @@ use rand::prelude::SliceRandom;
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::io::Read;
+use std::sync::mpsc::channel;
use std::sync::Mutex;
use std::sync::MutexGuard;
+use std::thread;
use swayipc as s;
pub fn run_sway_command_1(cmd: &str) -> Result<String, String> {
@@ 794,6 796,7 @@ fn run_shell_command_on_window(
.iter()
.map(|arg| win.subst_node_placeholders(arg, false))
.collect();
+ log::debug!("Running shell command on {}", win.node.id);
match std::process::Command::new(&cmd[0])
.args(&cmd[1..])
.stdout(std::process::Stdio::piped())
@@ 808,8 811,8 @@ fn run_shell_command_on_window(
let mut out = String::new();
let mut err = String::new();
- let mut waits = 0;
- let mut sleep_time = 4;
+ let mut sleep_time: u16 = 4;
+ let mut slept_time: u16 = 0;
loop {
match child.try_wait() {
Ok(Some(status)) => {
@@ 822,7 825,7 @@ fn run_shell_command_on_window(
};
}
Ok(None) => {
- if waits > 10 {
+ if slept_time >= 2000 {
let k = child.kill();
read_from_child(&mut child, &mut out, &mut err);
return ShellCommandResult {
@@ 843,10 846,10 @@ fn run_shell_command_on_window(
sleep_time as u64,
),
);
+ slept_time += sleep_time;
if sleep_time < 100 {
sleep_time *= 2;
}
- waits += 1;
}
}
Err(err) => {
@@ 888,12 891,23 @@ fn for_each_window(
return Err(String::from("No matching windows"));
}
- let mut results = vec![];
- for w in wins {
- let r = run_shell_command_on_window(w, shell_command);
- results.push(r);
- }
+ let (sender, receiver) = channel::<ShellCommandResult>();
+
+ thread::scope(|scope| {
+ for w in wins {
+ let s = sender.clone();
+ scope.spawn(move || {
+ s.send(run_shell_command_on_window(w, shell_command))
+ .expect("Error on send!");
+ });
+ }
+ });
+
+ // Drop the last sender explicity, otherwise receiver.iter().collect()
+ // blocks indefinitely.
+ drop(sender);
+ let results: Vec<ShellCommandResult> = receiver.iter().collect();
let json =
serde_json::to_string_pretty(&results).expect("Error generating JSON");
if results.iter().all(|r| r.exit_code == 0) {