main.rs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. #[macro_use]
  2. extern crate chan;
  3. extern crate chan_signal;
  4. extern crate css_color_parser;
  5. extern crate getopts;
  6. extern crate xcb;
  7. mod atom;
  8. mod tray;
  9. use css_color_parser::Color;
  10. use std::env;
  11. use std::process;
  12. use std::thread;
  13. use std::sync::Arc;
  14. const PROGRAM: &'static str = "rusttray";
  15. const EXIT_WRONG_ARGS: i32 = 1;
  16. const EXIT_FAILED_CONNECT: i32 = 10;
  17. const EXIT_FAILED_SELECT: i32 = 11;
  18. fn main() {
  19. process::exit(real_main());
  20. }
  21. fn real_main() -> i32 {
  22. let signal = chan_signal::notify(&[chan_signal::Signal::INT, chan_signal::Signal::TERM]);
  23. let args: Vec<String> = env::args().collect();
  24. let mut opts = getopts::Options::new();
  25. opts.optopt("i", "icon-size", "size of the tray icons, default 20", "<size>");
  26. opts.optopt("p", "position", "position of the tray, one of: top-left, top-right, bottom-left, bottom-right", "<pos>");
  27. opts.optopt("b", "background", "background color of the tray", "<color>");
  28. opts.optflag("h", "help", "print this help menu");
  29. let matches = match opts.parse(&args[1..]) {
  30. Ok(m) => m,
  31. Err(f) => panic!(f.to_string())
  32. };
  33. if matches.opt_present("h") {
  34. let brief = format!("Usage: {} [options]", PROGRAM);
  35. print!("{}", opts.usage(&brief));
  36. return 0
  37. }
  38. let pos = matches.opt_str("p").unwrap_or("top-left".to_string());
  39. let pos = match pos.as_ref() {
  40. "top-left" => tray::TOP_LEFT,
  41. "top-right" => tray::TOP_RIGHT,
  42. "bottom-left" => tray::BOTTOM_LEFT,
  43. "bottom-right" => tray::BOTTOM_RIGHT,
  44. _ => {
  45. println!("Invalid position specified.");
  46. return EXIT_WRONG_ARGS
  47. }
  48. };
  49. let size = matches.opt_str("i");
  50. let size = match size {
  51. Some(string) => match string.parse::<u16>() {
  52. Ok(size) => size,
  53. Err(e) => {
  54. println!("Invalid size specified, {}.", e.to_string());
  55. return EXIT_WRONG_ARGS
  56. }
  57. },
  58. None => 20
  59. };
  60. let black = Color { r: 0, g: 0, b: 0, a: 1.0 };
  61. let bg = matches.opt_str("b");
  62. let bg = match bg {
  63. Some(color) => match color.parse::<Color>() {
  64. Ok(color) => color,
  65. Err(e) => {
  66. println!("Invalid color specified, {}.", e.to_string());
  67. return EXIT_WRONG_ARGS
  68. }
  69. },
  70. None => black
  71. };
  72. let bg = ((bg.a * 255.0) as u32) << 24 | (bg.r as u32) << 16 | (bg.g as u32) << 8 | (bg.b as u32);
  73. if let Ok((conn, preferred)) = xcb::Connection::connect(None) {
  74. let conn = Arc::new(conn);
  75. let atoms = atom::Atoms::new(&conn);
  76. let mut tray = tray::Tray::new(&conn, &atoms, preferred as usize, size, pos, bg);
  77. if !tray.is_selection_available() {
  78. println!("Another system tray is already running");
  79. return EXIT_FAILED_SELECT
  80. }
  81. let (tx, rx) = chan::sync(0);
  82. {
  83. let conn = conn.clone();
  84. thread::spawn(move || {
  85. loop {
  86. match conn.wait_for_event() {
  87. Some(event) => { tx.send(event); },
  88. None => { break; }
  89. }
  90. }
  91. });
  92. }
  93. tray.create();
  94. loop {
  95. chan_select!(
  96. rx.recv() -> event => {
  97. if let Some(code) = tray.handle_event(event.unwrap()) {
  98. return code
  99. }
  100. },
  101. signal.recv() => {
  102. tray.finish();
  103. }
  104. );
  105. }
  106. }
  107. else {
  108. println!("Could not connect to X server!");
  109. return EXIT_FAILED_CONNECT
  110. }
  111. }