use std::io::prelude::*; use std::io::BufReader; use std::process::{Command, Stdio}; use std::sync::mpsc; use std::thread; use ui::widget; const MARGIN: u16 = 7; struct Desktop { name: String, selected: bool, urgent: bool } pub struct Bspwm { context: widget::DrawContext, tx: mpsc::Sender, desktops: Vec } impl Bspwm { pub fn new(tx: mpsc::Sender, context: widget::DrawContext) -> Bspwm { Bspwm { context: context, tx: tx, desktops: vec![] } } } impl widget::Widget for Bspwm { fn init(&mut self) { let tx = self.tx.clone(); thread::spawn(move || monitor_thread(tx)); } fn render(&mut self, x: u16) { let mut offset = x; for desktop in self.desktops.iter() { let text_width = self.context.measure_text(&desktop.name); if desktop.selected { self.context.set_bg_color(0x6666, 0xCCCC, 0x6666, 0xFFFF); } else if desktop.urgent { self.context.set_bg_color(0xCCCC, 0x0, 0x3333, 0xFFFF); } else { self.context.set_bg_color(0x0, 0x0, 0x0, 0xFFFF); } self.context.draw_bg(offset, text_width + MARGIN * 2); self.context.draw_text(&desktop.name, offset + MARGIN); offset += text_width + MARGIN * 2; } } fn width(&mut self) -> u16 { let mut sum = 0; for desktop in self.desktops.iter() { sum += self.context.measure_text(&desktop.name) + MARGIN * 2; } sum } fn handle_event(&mut self, event: &widget::WidgetMessage) -> bool { match event { &widget::WidgetMessage::BspwmEvent(ref line) => { self.desktops = parse_bspwm(line); self.tx.send(widget::WidgetMessage::Relayout).expect("Failed to send relayout"); }, _ => {} } false } } fn monitor_thread(tx: mpsc::Sender) { let bspc = Command::new("bspc") .arg("subscribe") .arg("report") .stdout(Stdio::piped()) .spawn() .ok() .expect("Failed to start bspc subscribe"); let stdout = bspc.stdout.unwrap(); let mut reader = BufReader::new(stdout); let mut line = String::new(); loop { line.clear(); reader.read_line(&mut line).ok().expect("Failed to read line"); let kind = line.remove(0); let line = line.trim(); match kind { 'W' => { let event = widget::WidgetMessage::BspwmEvent(line.to_string()); tx.send(event).expect("Failed to send bswpm event") }, _ => {} } } } fn parse_bspwm(line: &str) -> Vec { let mut desktops = vec![]; let elems = line.split(':'); for elem in elems { let mut chars = elem.chars(); let kind = chars.next().unwrap(); let name = chars.collect::(); if kind == 'M' || kind == 'm' {} else if kind == 'L' {} else if kind == 'G' {} else if kind == 'T' {} else { let empty = kind == 'f'; let urgent = kind == 'U' || kind == 'u'; let selected = kind.is_uppercase(); if !empty { desktops.push(Desktop { name: name, selected: selected, urgent: urgent }) } } } desktops }