main.rs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. #[macro_use]
  2. extern crate failure;
  3. mod config;
  4. mod widgets;
  5. mod window;
  6. use std::os::unix::io::AsRawFd;
  7. use pango::LayoutExt;
  8. use widgets::Size;
  9. use window::{Display,Event,Window};
  10. fn main() -> Result<(), failure::Error> {
  11. // set up the display and the window
  12. let config = config::Config::find_config()?;
  13. let height = config.get_height();
  14. println!("height is {}", height);
  15. let mut d = Display::create()?;
  16. let mut ws = Vec::new();
  17. for (x_off, wd) in d.get_widths()? {
  18. let size = Size { wd, ht: height, xo: x_off, yo: 0 };
  19. let mut w = Window::create(&d, size)?;
  20. // set some window-manager properties: this is a dock
  21. w.change_property("_NET_WM_WINDOW_TYPE", &["_NET_WM_WINDOW_TYPE_DOCK"])?;
  22. // ...and should push other windows out of the way
  23. w.change_property("_NET_WM_STRUT", &[x_off as i64, 0, size.ht as i64, 0])?;
  24. w.change_property(
  25. "_NET_WM_STRUT_PARTIAL",
  26. &[ 0, 0, size.ht as i64, 0,
  27. 0, 0, 0, 0,
  28. 0, size.wd as i64, 0, 0,
  29. ],
  30. )?;
  31. // we won't ever see this, but for good measure.
  32. w.set_title("rbar")?;
  33. // we care about some input events!
  34. w.set_input_masks()?;
  35. w.set_protocols()?;
  36. // and now show it!
  37. w.map();
  38. ws.push(w);
  39. }
  40. // we do some grossness with file descriptors later, so we need
  41. // the file descriptors we care about here
  42. let window_fds: Vec<i32> = ws.iter_mut().map({ |w| w.get_fd() }).collect();
  43. let stdin_fd = std::io::stdin().as_raw_fd();
  44. let mut fds = unsafe { std::mem::uninitialized() };
  45. // To begin with, our left-hand side---which normally is whatever
  46. // was last passed in on stdin---will start as a generic
  47. // message...
  48. let mut input = format!("Loading...");
  49. // And let's get a buffered stdin handle now
  50. let mut stdin = std::io::BufReader::new(std::io::stdin());
  51. // In the absence of other events, let's refresh every five
  52. // seconds. Or whatever.
  53. let mut timer = libc::timeval {
  54. tv_sec: 5,
  55. tv_usec: 0,
  56. };
  57. let mut ctxs = Vec::new();
  58. for w in ws.iter_mut() {
  59. // let's grab the cairo context here
  60. let surf = w.get_cairo_surface();
  61. let ctx = cairo::Context::new(&surf);
  62. let layout = pangocairo::functions::create_layout(&ctx)
  63. .ok_or(format_err!("unable to create layout"))?;
  64. // allow for the whole width of the bar, minus a small fixed amount
  65. layout.set_width((w.width - 20) * pango::SCALE);
  66. // this should also be configurable, but Fira Mono is a good font
  67. let mut font = pango::FontDescription::from_string(config.font());
  68. font.set_weight(pango::Weight::Bold);
  69. layout.set_font_description(&font);
  70. // do an initial pass at drawing the bar!
  71. config.draw(&ctx, &layout, &input, w.size())?;
  72. ctxs.push((ctx, layout, w.size()));
  73. }
  74. let max_fd = window_fds.iter().max().unwrap_or(&0) + 1;
  75. // we're gonna keep looping until we don't
  76. loop {
  77. unsafe {
  78. // set up the FD set to be the X11 fd and the state of stdin
  79. libc::FD_ZERO(&mut fds);
  80. for fd in window_fds.iter() {
  81. libc::FD_SET(*fd, &mut fds);
  82. }
  83. libc::FD_SET(stdin_fd, &mut fds);
  84. timer.tv_sec = 5;
  85. // this will block until there's input on either of the
  86. // above FDs or until five seconds have passed, whichever comes first
  87. libc::select(
  88. max_fd,
  89. &mut fds,
  90. std::ptr::null_mut(),
  91. std::ptr::null_mut(),
  92. &mut timer,
  93. );
  94. }
  95. // if we _did_ have input on stdin, then read it in: that'll
  96. // be our new left-hand text
  97. if unsafe { libc::FD_ISSET(stdin_fd, &mut fds) } {
  98. use std::io::BufRead;
  99. input = String::new();
  100. stdin.read_line(&mut input)?;
  101. if input.len() == 0 {
  102. break;
  103. }
  104. for (ctx, layout, sz) in ctxs.iter() {
  105. config.draw(&ctx, &layout, &input, *sz)?;
  106. }
  107. }
  108. // if we have X11 events, handle them. If any one was a quit
  109. // event, then just... quit.
  110. for w in ws.iter_mut() {
  111. while w.has_events() {
  112. match w.handle() {
  113. Some(Event::QuitEvent) => break,
  114. _e => (),
  115. }
  116. }
  117. }
  118. for (ctx, layout, sz) in ctxs.iter() {
  119. // otherwise, draw the thing!
  120. config.draw(&ctx, &layout, &input, *sz)?;
  121. }
  122. }
  123. Ok(())
  124. }