diff --git a/src/cmds.rs b/src/cmds.rs index 35b0ef9..dcdf539 100644 --- a/src/cmds.rs +++ b/src/cmds.rs @@ -27,7 +27,10 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::sync::atomic; use std::sync::Arc; +use std::sync::Mutex; use std::sync::RwLock; +use std::time::Duration; +use std::time::Instant; use swayipc as s; pub fn run_sway_command_1(cmd: &str) { @@ -225,6 +228,7 @@ impl SwayrCommand { pub struct ExecSwayrCmdArgs<'a> { pub cmd: &'a SwayrCommand, pub extra_props: Arc>>, + pub sequence_timeout: Option, } impl DisplayFormat for SwayrCommand { @@ -246,6 +250,9 @@ fn always_true(_x: &t::DisplayNode) -> bool { static IN_NEXT_PREV_WINDOW_SEQ: atomic::AtomicBool = atomic::AtomicBool::new(false); +lazy_static! { + static ref NEXT_PREV_WINDOW_SEQ_TIMEOUT: Mutex> = Mutex::new(None); +} pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) { let props = args.extra_props; @@ -253,14 +260,25 @@ pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) { if args.cmd.is_prev_next_window_variant() { let before = IN_NEXT_PREV_WINDOW_SEQ.swap(true, atomic::Ordering::SeqCst); - if !before { + if !before + || NEXT_PREV_WINDOW_SEQ_TIMEOUT + .lock() + .unwrap() + .map_or(false, |i| Instant::now() > i) + { + log::info!("Starting new next/prev sequence"); let mut map = props.write().unwrap(); for val in map.values_mut() { val.last_focus_tick_for_next_prev_seq = val.last_focus_tick; } } + if let Some(timeout) = args.sequence_timeout { + *NEXT_PREV_WINDOW_SEQ_TIMEOUT.lock().unwrap() = + Some(Instant::now() + timeout); + } } else { IN_NEXT_PREV_WINDOW_SEQ.store(false, atomic::Ordering::SeqCst); + *NEXT_PREV_WINDOW_SEQ_TIMEOUT.lock().unwrap() = None; } match args.cmd { @@ -473,6 +491,7 @@ pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) { exec_swayr_cmd(ExecSwayrCmdArgs { cmd: c, extra_props: props, + sequence_timeout: args.sequence_timeout, }); } } diff --git a/src/config.rs b/src/config.rs index c2136a8..cc67cca 100644 --- a/src/config.rs +++ b/src/config.rs @@ -28,6 +28,7 @@ pub struct Config { menu: Option, format: Option, layout: Option, + sequence: Option, } fn tilde_expand_file_names(file_names: Vec) -> Vec { @@ -159,6 +160,14 @@ impl Config { .or_else(|| Layout::default().auto_tile_min_window_width_per_output_width_as_map()) .expect("No layout.auto_tile_min_window_width_per_output_width defined.") } + + pub fn get_sequence_timeout(&self) -> u64 { + self.sequence + .as_ref() + .and_then(|s| s.timeout) + .or_else(|| Sequence::default().timeout) + .expect("No sequence.timeout defined") + } } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -187,6 +196,11 @@ pub struct Layout { auto_tile_min_window_width_per_output_width: Option>, } +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Sequence { + timeout: Option, +} + impl Layout { pub fn auto_tile_min_window_width_per_output_width_as_map( &self, @@ -294,12 +308,19 @@ impl Default for Layout { } } +impl Default for Sequence { + fn default() -> Self { + Sequence { timeout: Some(0) } + } +} + impl Default for Config { fn default() -> Self { Config { menu: Some(Menu::default()), format: Some(Format::default()), layout: Some(Layout::default()), + sequence: Some(Sequence::default()), } } } diff --git a/src/demon.rs b/src/demon.rs index c87381a..deef523 100644 --- a/src/demon.rs +++ b/src/demon.rs @@ -26,6 +26,7 @@ use std::os::unix::net::{UnixListener, UnixStream}; use std::sync::Arc; use std::sync::RwLock; use std::thread; +use std::time::Duration; use swayipc as s; pub fn run_demon() { @@ -40,7 +41,7 @@ pub fn run_demon() { monitor_sway_events(extra_props_for_ev_handler, config_for_ev_handler); }); - serve_client_requests(extra_props); + serve_client_requests(extra_props, config); } fn connect_and_subscribe() -> s::Fallible { @@ -230,18 +231,28 @@ fn remove_extra_props( pub fn serve_client_requests( extra_props: Arc>>, + config: config::Config, ) { match std::fs::remove_file(util::get_swayr_socket_path()) { Ok(()) => log::debug!("Deleted stale socket from previous run."), Err(e) => log::error!("Could not delete socket:\n{:?}", e), } + let timeout = match config.get_sequence_timeout() { + 0 => None, + secs => Some(Duration::from_secs(secs)), + }; + match UnixListener::bind(util::get_swayr_socket_path()) { Ok(listener) => { for stream in listener.incoming() { match stream { Ok(stream) => { - handle_client_request(stream, extra_props.clone()); + handle_client_request( + stream, + extra_props.clone(), + timeout, + ); } Err(err) => { log::error!("Error handling client request: {}", err); @@ -259,6 +270,7 @@ pub fn serve_client_requests( fn handle_client_request( mut stream: UnixStream, extra_props: Arc>>, + sequence_timeout: Option, ) { let mut cmd_str = String::new(); if stream.read_to_string(&mut cmd_str).is_ok() { @@ -266,6 +278,7 @@ fn handle_client_request( cmds::exec_swayr_cmd(cmds::ExecSwayrCmdArgs { cmd: &cmd, extra_props, + sequence_timeout, }); } else { log::error!(