bspwm.rs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. use std::io::prelude::*;
  2. use std::io::BufReader;
  3. use std::process::{Command, Stdio};
  4. use std::sync::mpsc;
  5. use std::thread;
  6. use ui::widget;
  7. const MARGIN: u16 = 7;
  8. struct Desktop {
  9. name: String,
  10. selected: bool,
  11. urgent: bool
  12. }
  13. pub struct Bspwm {
  14. context: widget::DrawContext,
  15. tx: mpsc::Sender<widget::WidgetMessage>,
  16. desktops: Vec<Desktop>
  17. }
  18. impl Bspwm {
  19. pub fn new(tx: mpsc::Sender<widget::WidgetMessage>, context: widget::DrawContext) -> Bspwm {
  20. Bspwm {
  21. context: context,
  22. tx: tx,
  23. desktops: vec![]
  24. }
  25. }
  26. }
  27. impl widget::Widget for Bspwm {
  28. fn init(&mut self) {
  29. let tx = self.tx.clone();
  30. thread::spawn(move || monitor_thread(tx));
  31. }
  32. fn render(&mut self, x: u16) {
  33. let mut offset = x;
  34. for desktop in self.desktops.iter() {
  35. let text_width = self.context.measure_text(&desktop.name);
  36. if desktop.selected {
  37. self.context.set_bg_color(0x6666, 0xCCCC, 0x6666, 0xFFFF);
  38. }
  39. else if desktop.urgent {
  40. self.context.set_bg_color(0xCCCC, 0x0, 0x3333, 0xFFFF);
  41. }
  42. else {
  43. self.context.set_bg_color(0x0, 0x0, 0x0, 0xFFFF);
  44. }
  45. self.context.draw_bg(offset, text_width + MARGIN * 2);
  46. self.context.draw_text(&desktop.name, offset + MARGIN);
  47. offset += text_width + MARGIN * 2;
  48. }
  49. }
  50. fn width(&mut self) -> u16 {
  51. let mut sum = 0;
  52. for desktop in self.desktops.iter() {
  53. sum += self.context.measure_text(&desktop.name) + MARGIN * 2;
  54. }
  55. sum
  56. }
  57. fn handle_event(&mut self, event: &widget::WidgetMessage) -> bool {
  58. match event {
  59. &widget::WidgetMessage::BspwmEvent(ref line) => {
  60. self.desktops = parse_bspwm(line);
  61. self.tx.send(widget::WidgetMessage::Relayout).expect("Failed to send relayout");
  62. },
  63. _ => {}
  64. }
  65. false
  66. }
  67. }
  68. fn monitor_thread(tx: mpsc::Sender<widget::WidgetMessage>) {
  69. let bspc = Command::new("bspc")
  70. .arg("subscribe")
  71. .arg("report")
  72. .stdout(Stdio::piped())
  73. .spawn()
  74. .ok()
  75. .expect("Failed to start bspc subscribe");
  76. let stdout = bspc.stdout.unwrap();
  77. let mut reader = BufReader::new(stdout);
  78. let mut line = String::new();
  79. loop {
  80. line.clear();
  81. reader.read_line(&mut line).ok().expect("Failed to read line");
  82. let kind = line.remove(0);
  83. let line = line.trim();
  84. match kind {
  85. 'W' => {
  86. let event = widget::WidgetMessage::BspwmEvent(line.to_string());
  87. tx.send(event).expect("Failed to send bswpm event")
  88. },
  89. _ => {}
  90. }
  91. }
  92. }
  93. fn parse_bspwm(line: &str) -> Vec<Desktop> {
  94. let mut desktops = vec![];
  95. let elems = line.split(':');
  96. for elem in elems {
  97. let mut chars = elem.chars();
  98. let kind = chars.next().unwrap();
  99. let name = chars.collect::<String>();
  100. if kind == 'M' || kind == 'm' {}
  101. else if kind == 'L' {}
  102. else if kind == 'G' {}
  103. else if kind == 'T' {}
  104. else {
  105. let empty = kind == 'f';
  106. let urgent = kind == 'U' || kind == 'u';
  107. let selected = kind.is_uppercase();
  108. if !empty {
  109. desktops.push(Desktop {
  110. name: name,
  111. selected: selected,
  112. urgent: urgent
  113. })
  114. }
  115. }
  116. }
  117. desktops
  118. }