main.rs 3.0 KB

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