main.rs 4.8 KB

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