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 env_logger::Env;
use serde_json;
use std::collections::VecDeque;
use std::io;
use std::process as p;
use std::sync::Condvar;
@ -30,6 +31,7 @@ use swaybar_types as sbt;
use swayipc as si;
type NameInstanceAndReason = (String, String, String);
type Trigger = Arc<(Mutex<VecDeque<NameInstanceAndReason>>, Condvar)>;
pub fn start() {
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 mods: Arc<Vec<Box<dyn BarModuleFn>>> = Arc::new(create_modules(config));
let mods_for_input = mods.clone();
let trigger: Arc<(Mutex<NameInstanceAndReason>, Condvar)> = Arc::new((
Mutex::new((String::new(), String::new(), String::new())),
Condvar::new(),
));
let trigger: Trigger =
Arc::new((Mutex::new(VecDeque::new()), Condvar::new()));
let trigger_for_input = trigger.clone();
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
}
fn handle_input(
mods: Arc<Vec<Box<dyn BarModuleFn>>>,
trigger: Arc<(Mutex<NameInstanceAndReason>, Condvar)>,
) {
fn handle_input(mods: Arc<Vec<Box<dyn BarModuleFn>>>, trigger: Trigger) {
let mut sb = String::new();
io::stdin()
.read_line(&mut sb)
@ -120,10 +117,8 @@ fn handle_input(
log::debug!("Received click: {:?}", click);
if let Some((name, instance)) = handle_click(click, mods.clone()) {
let (mtx, cvar) = &*trigger;
let mut name_inst_reason = mtx.lock().unwrap();
name_inst_reason.0 = name;
name_inst_reason.1 = instance;
name_inst_reason.2 = String::from("click event");
let mut queue = mtx.lock().unwrap();
queue.push_back((name, instance, String::from("click event")));
cvar.notify_one();
}
}
@ -146,6 +141,9 @@ fn handle_click(
let cfg = m.get_config();
// No refresh for click events for window modules because the
// 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 {
return None;
}
@ -184,10 +182,7 @@ fn sway_subscribe() -> si::Fallible<si::EventStream> {
])
}
fn handle_sway_events(
window_mods: Vec<NameAndInstance>,
trigger: Arc<(Mutex<NameInstanceAndReason>, Condvar)>,
) {
fn handle_sway_events(window_mods: Vec<NameAndInstance>, trigger: Trigger) {
let mut resets = 0;
let max_resets = 10;
@ -216,12 +211,12 @@ fn handle_sway_events(
);
for m in &window_mods {
let (mtx, cvar) = &*trigger;
let mut name_inst_reason =
mtx.lock().unwrap();
name_inst_reason.0 = m.0.to_owned();
name_inst_reason.1 = m.1.to_owned();
name_inst_reason.2 =
String::from("sway event");
let mut queue = mtx.lock().unwrap();
queue.push_back((
m.0.to_owned(),
m.1.to_owned(),
String::from("sway event"),
));
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(
mods: &[Box<dyn BarModuleFn>],
trigger: Arc<(Mutex<NameInstanceAndReason>, Condvar)>,
trigger: Trigger,
refresh_interval: u64,
) {
println!("{{\"version\": 1, \"click_events\": true}}");
// status_command should output an infinite array meaning we emit an
// opening [ and never the closing bracket.
println!("[");
let mut name_inst_reason: Option<NameInstanceAndReason> = None;
generate_status_1(mods, &None);
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 result = cvar
.wait_timeout(
@ -280,16 +275,19 @@ fn generate_status(
Duration::from_millis(refresh_interval),
)
.unwrap();
if result.1.timed_out() {
name_inst_reason = None;
let mut queue = result.0;
if queue.is_empty() {
generate_status_1(mods, &None);
} else {
name_inst_reason = Some((*result.0).clone());
log::debug!(
"Status writing thread woke up early by {} for {}/{}.",
&result.0 .2,
&result.0 .0,
&result.0 .1
"Status writing thread woke up early events:\n{:?}",
queue
);
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