main.rs 4.8 KB

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