bspwm.rs 4.1 KB

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