Thomas Dy 7 жил өмнө
parent
commit
49e95eccb9
4 өөрчлөгдсөн 145 нэмэгдсэн , 1 устгасан
  1. 138 0
      src/ui/bspwm.rs
  2. 4 0
      src/ui/mod.rs
  3. 2 1
      src/ui/panel.rs
  4. 1 0
      src/ui/widget.rs

+ 138 - 0
src/ui/bspwm.rs

@@ -0,0 +1,138 @@
+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<widget::WidgetMessage>,
+    desktops: Vec<Desktop>
+}
+
+impl Bspwm {
+    pub fn new(tx: mpsc::Sender<widget::WidgetMessage>, 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<widget::WidgetMessage>) {
+    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<Desktop> {
+    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::<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 {
+                desktops.push(Desktop {
+                    name: name,
+                    selected: selected,
+                    urgent: urgent
+                })
+            }
+        }
+    }
+
+    desktops
+}
+

+ 4 - 0
src/ui/mod.rs

@@ -4,6 +4,7 @@ mod ext;
 mod title;
 mod tray;
 mod sensors;
+mod bspwm;
 mod util;
 mod widget;
 mod x11;
@@ -45,6 +46,9 @@ pub fn ui_main(cfg: &Config) -> i32 {
 
         let mut panel = panel::Panel::new(conn, cfg);
 
+        let bspwm = bspwm::Bspwm::new(tx.clone(), panel.make_draw_context());
+        panel.add_left_widget(Box::new(bspwm));
+
         let title = title::Title::new(panel.conn.clone(), panel.make_draw_context());
         panel.add_left_widget(Box::new(title));
 

+ 2 - 1
src/ui/panel.rs

@@ -128,7 +128,8 @@ impl Panel {
             widget::WidgetMessage::Relayout =>
                 self.relayout(),
             widget::WidgetMessage::Quit =>
-                self.finish()
+                self.finish(),
+            _ => {}
         }
         should_exit
     }

+ 1 - 0
src/ui/widget.rs

@@ -8,6 +8,7 @@ pub enum WidgetMessage {
     Relayout,
     Update,
     Quit,
+    BspwmEvent(String),
     XcbEvent(xcb::GenericEvent)
 }