Use a VecDeque for events so that we're not missing some

main
Tassilo Horn 3 years ago
parent 56c816ee62
commit 7d5f1643c1
  1. 86
      swayrbar/src/bar.rs

@ -20,6 +20,7 @@ use crate::module;
use crate::module::{BarModuleFn, NameAndInstance}; use crate::module::{BarModuleFn, NameAndInstance};
use env_logger::Env; use env_logger::Env;
use serde_json; use serde_json;
use std::collections::VecDeque;
use std::io; use std::io;
use std::process as p; use std::process as p;
use std::sync::Condvar; use std::sync::Condvar;
@ -30,6 +31,7 @@ use swaybar_types as sbt;
use swayipc as si; use swayipc as si;
type NameInstanceAndReason = (String, String, String); type NameInstanceAndReason = (String, String, String);
type Trigger = Arc<(Mutex<VecDeque<NameInstanceAndReason>>, Condvar)>;
pub fn start() { pub fn start() {
env_logger::Builder::from_env(Env::default().default_filter_or("warn")) env_logger::Builder::from_env(Env::default().default_filter_or("warn"))
@ -39,10 +41,8 @@ pub fn start() {
let refresh_interval = config.refresh_interval; let refresh_interval = config.refresh_interval;
let mods: Arc<Vec<Box<dyn BarModuleFn>>> = Arc::new(create_modules(config)); let mods: Arc<Vec<Box<dyn BarModuleFn>>> = Arc::new(create_modules(config));
let mods_for_input = mods.clone(); let mods_for_input = mods.clone();
let trigger: Arc<(Mutex<NameInstanceAndReason>, Condvar)> = Arc::new(( let trigger: Trigger =
Mutex::new((String::new(), String::new(), String::new())), Arc::new((Mutex::new(VecDeque::new()), Condvar::new()));
Condvar::new(),
));
let trigger_for_input = trigger.clone(); let trigger_for_input = trigger.clone();
thread::spawn(move || handle_input(mods_for_input, trigger_for_input)); thread::spawn(move || handle_input(mods_for_input, trigger_for_input));
@ -83,10 +83,7 @@ fn create_modules(config: config::Config) -> Vec<Box<dyn BarModuleFn>> {
mods mods
} }
fn handle_input( fn handle_input(mods: Arc<Vec<Box<dyn BarModuleFn>>>, trigger: Trigger) {
mods: Arc<Vec<Box<dyn BarModuleFn>>>,
trigger: Arc<(Mutex<NameInstanceAndReason>, Condvar)>,
) {
let mut sb = String::new(); let mut sb = String::new();
io::stdin() io::stdin()
.read_line(&mut sb) .read_line(&mut sb)
@ -120,10 +117,8 @@ fn handle_input(
log::debug!("Received click: {:?}", click); log::debug!("Received click: {:?}", click);
if let Some((name, instance)) = handle_click(click, mods.clone()) { if let Some((name, instance)) = handle_click(click, mods.clone()) {
let (mtx, cvar) = &*trigger; let (mtx, cvar) = &*trigger;
let mut name_inst_reason = mtx.lock().unwrap(); let mut queue = mtx.lock().unwrap();
name_inst_reason.0 = name; queue.push_back((name, instance, String::from("click event")));
name_inst_reason.1 = instance;
name_inst_reason.2 = String::from("click event");
cvar.notify_one(); cvar.notify_one();
} }
} }
@ -146,6 +141,9 @@ fn handle_click(
let cfg = m.get_config(); let cfg = m.get_config();
// No refresh for click events for window modules because the // No refresh for click events for window modules because the
// refresh will be triggered by a sway event anyhow. // refresh will be triggered by a sway event anyhow.
//
// TODO: That's too much coupling. The bar module shouldn't do
// specific stuff for certain modules.
if cfg.name == module::window::NAME { if cfg.name == module::window::NAME {
return None; return None;
} }
@ -184,10 +182,7 @@ fn sway_subscribe() -> si::Fallible<si::EventStream> {
]) ])
} }
fn handle_sway_events( fn handle_sway_events(window_mods: Vec<NameAndInstance>, trigger: Trigger) {
window_mods: Vec<NameAndInstance>,
trigger: Arc<(Mutex<NameInstanceAndReason>, Condvar)>,
) {
let mut resets = 0; let mut resets = 0;
let max_resets = 10; let max_resets = 10;
@ -216,12 +211,12 @@ fn handle_sway_events(
); );
for m in &window_mods { for m in &window_mods {
let (mtx, cvar) = &*trigger; let (mtx, cvar) = &*trigger;
let mut name_inst_reason = let mut queue = mtx.lock().unwrap();
mtx.lock().unwrap(); queue.push_back((
name_inst_reason.0 = m.0.to_owned(); m.0.to_owned(),
name_inst_reason.1 = m.1.to_owned(); m.1.to_owned(),
name_inst_reason.2 = String::from("sway event"),
String::from("sway event"); ));
cvar.notify_one(); cvar.notify_one();
} }
} }
@ -248,31 +243,31 @@ fn handle_sway_events(
} }
} }
fn generate_status_1(
mods: &[Box<dyn BarModuleFn>],
name_and_instance: &Option<NameAndInstance>,
) {
let mut blocks = vec![];
for m in mods {
blocks.push(m.build(name_and_instance));
}
let json = serde_json::to_string_pretty(&blocks)
.unwrap_or_else(|_| "".to_string());
println!("{},", json);
}
fn generate_status( fn generate_status(
mods: &[Box<dyn BarModuleFn>], mods: &[Box<dyn BarModuleFn>],
trigger: Arc<(Mutex<NameInstanceAndReason>, Condvar)>, trigger: Trigger,
refresh_interval: u64, refresh_interval: u64,
) { ) {
println!("{{\"version\": 1, \"click_events\": true}}"); println!("{{\"version\": 1, \"click_events\": true}}");
// status_command should output an infinite array meaning we emit an // status_command should output an infinite array meaning we emit an
// opening [ and never the closing bracket. // opening [ and never the closing bracket.
println!("["); println!("[");
generate_status_1(mods, &None);
let mut name_inst_reason: Option<NameInstanceAndReason> = None;
loop { loop {
let mut blocks = vec![];
let name_and_instance = &name_inst_reason.map(|x| (x.0, x.1));
for m in mods {
blocks.push(m.build(name_and_instance));
}
let json = serde_json::to_string_pretty(&blocks)
.unwrap_or_else(|_| "".to_string());
println!("{},", json);
// FIXME: We sometimes miss click or sway events, most probably because
// the corresponding notify_one() is executed when we are not waiting
// here.
let (lock, cvar) = &*trigger; let (lock, cvar) = &*trigger;
let result = cvar let result = cvar
.wait_timeout( .wait_timeout(
@ -280,16 +275,19 @@ fn generate_status(
Duration::from_millis(refresh_interval), Duration::from_millis(refresh_interval),
) )
.unwrap(); .unwrap();
if result.1.timed_out() { let mut queue = result.0;
name_inst_reason = None; if queue.is_empty() {
generate_status_1(mods, &None);
} else { } else {
name_inst_reason = Some((*result.0).clone());
log::debug!( log::debug!(
"Status writing thread woke up early by {} for {}/{}.", "Status writing thread woke up early events:\n{:?}",
&result.0 .2, queue
&result.0 .0,
&result.0 .1
); );
while let Some(name_inst_reason) = queue.pop_front() {
let name_and_instance =
Some(name_inst_reason).map(|x| (x.0, x.1));
generate_status_1(mods, &name_and_instance);
}
} }
} }
} }

Loading…
Cancel
Save