123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- use std::io::prelude::*;
- use std::io::BufReader;
- use std::process::{Command, Stdio};
- use std::thread;
- use ui::draw_context::DrawContext;
- use widgets::{Message, MessageSender, Widget};
- const MARGIN: u16 = 7;
- struct Desktop {
- name: String,
- selected: bool,
- urgent: bool,
- position: u16,
- width: u16
- }
- impl Desktop {
- fn contains(&self, x: u16) -> bool {
- x >= self.position && x < self.position + self.width
- }
- }
- pub struct Bspwm {
- context: DrawContext,
- tx: MessageSender,
- desktops: Vec<Desktop>
- }
- impl Bspwm {
- pub fn new(tx: MessageSender, context: DrawContext) -> Bspwm {
- Bspwm {
- context: context,
- tx: tx,
- desktops: vec![]
- }
- }
- fn parse_bspwm(&mut self, line: &str) {
- let (kind, line) = line.split_at(1);
- if kind != "W" { return };
- let mut desktops = vec![];
- let elems = line.split(':');
- let mut pos = 0;
- for elem in elems {
- let mut chars = elem.chars();
- let kind = chars.next().unwrap();
- let name = chars.collect::<String>();
- 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 {
- let width = self.context.measure_text(&name) + MARGIN * 2;
- desktops.push(Desktop {
- name: name,
- selected: selected,
- urgent: urgent,
- position: pos,
- width: width
- });
- pos += width;
- }
- }
- }
- self.desktops = desktops;
- }
- }
- impl Widget for Bspwm {
- fn init(&mut self) {
- let tx = self.tx.clone();
- thread::spawn(move || monitor_thread(tx));
- }
- fn render(&mut self, x: u16, _w: u16) {
- for desktop in self.desktops.iter() {
- 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(x + desktop.position, desktop.width);
- self.context.draw_text(&desktop.name, x + desktop.position + MARGIN);
- }
- }
- 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: &Message) -> bool {
- match event {
- &Message::BspwmEvent(ref line) => {
- self.parse_bspwm(line);
- self.tx.send(Message::Relayout).expect("Failed to send relayout");
- },
- &Message::MousePress(x) => {
- for desktop in self.desktops.iter() {
- if desktop.contains(x) {
- switch_desktop(&desktop.name);
- }
- }
- },
- _ => {}
- }
- false
- }
- }
- fn monitor_thread(tx: MessageSender) {
- 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 event = Message::BspwmEvent(line.clone());
- tx.send(event).ok();
- }
- }
- fn switch_desktop(name: &str) {
- Command::new("bspc")
- .arg("desktop")
- .arg("-f")
- .arg(name)
- .output()
- .ok();
- }
|