Files
wldash/src/main.rs
T

251 lines
8.4 KiB
Rust
Raw Normal View History

2019-09-06 22:48:50 +02:00
use std::default::Default;
use std::env;
2019-09-06 22:48:50 +02:00
use std::fs::File;
2019-08-28 18:06:07 +02:00
use std::io::{BufRead, BufReader, Read, Write};
use std::os::unix::io::AsRawFd;
use std::os::unix::net::{UnixListener, UnixStream};
use std::sync::mpsc::channel;
2019-07-30 00:42:05 +02:00
use nix::poll::{poll, PollFd, PollFlags};
2019-07-30 16:31:42 +02:00
use os_pipe::pipe;
2019-07-30 00:42:05 +02:00
2019-08-28 18:06:07 +02:00
mod app;
2019-07-31 10:26:12 +02:00
mod buffer;
2019-08-28 18:06:07 +02:00
mod cmd;
2019-07-31 10:26:12 +02:00
mod color;
2019-09-06 21:54:04 +02:00
mod config;
2019-08-29 01:03:48 +02:00
mod desktop;
2019-09-06 21:54:04 +02:00
mod doublemempool;
mod draw;
mod widget;
mod widgets;
2019-07-30 00:42:05 +02:00
2019-08-27 15:07:39 +02:00
use app::{App, OutputMode};
use cmd::Cmd;
enum Mode {
Start,
StartOrKill,
ToggleVisible,
2019-09-06 21:54:04 +02:00
PrintConfig,
2019-08-27 15:07:39 +02:00
}
2019-07-30 00:42:05 +02:00
fn main() {
2019-08-27 15:07:39 +02:00
let socket_path = match env::var("XDG_RUNTIME_DIR") {
Ok(dir) => dir + "/wldash",
Err(_) => "/tmp/wldash".to_string(),
};
2019-09-06 21:54:04 +02:00
let config_home = match env::var("XDG_CONFIG_HOME") {
Ok(dir) => dir + "/wldash",
Err(_) => match env::var("HOME") {
Ok(home) => home + "/.config/wldash",
Err(_) => panic!("unable to find user folder"),
2019-09-06 22:48:50 +02:00
},
};
2019-09-06 21:54:04 +02:00
let config: config::Config = match File::open(config_home + "/config.json") {
Ok(f) => {
let reader = BufReader::new(f);
serde_json::from_reader(reader).unwrap()
2019-09-06 22:48:50 +02:00
}
2019-09-06 21:54:04 +02:00
Err(_) => Default::default(),
};
let scale = config.scale;
2019-08-27 15:07:39 +02:00
let args: Vec<String> = env::args().collect();
let mode = match args.len() {
1 => Mode::Start,
2 => match args[1].as_str() {
"start" => Mode::Start,
"start-or-kill" => Mode::StartOrKill,
"toggle-visible" => Mode::ToggleVisible,
2019-09-06 21:54:04 +02:00
"print-config" => Mode::PrintConfig,
2019-08-27 15:07:39 +02:00
s => {
eprintln!("unsupported sub-command {}", s);
std::process::exit(1);
}
},
v => {
eprintln!("expected 0 or 1 arguments, got {}", v);
std::process::exit(1);
}
};
match mode {
Mode::ToggleVisible => {
if let Ok(mut socket) = UnixStream::connect(socket_path.clone()) {
socket.write_all(b"toggle_visible\n").unwrap();
return;
};
eprintln!("wldash is not running");
std::process::exit(1);
}
Mode::StartOrKill => {
if let Ok(mut socket) = UnixStream::connect(socket_path.clone()) {
socket.write_all(b"kill\n").unwrap();
return;
};
}
Mode::Start => {
if let Ok(_) = UnixStream::connect(socket_path.clone()) {
eprintln!("wldash is already running");
std::process::exit(1);
};
}
2019-09-06 21:54:04 +02:00
Mode::PrintConfig => {
println!("{}", serde_json::to_string_pretty(&config).unwrap());
std::process::exit(0);
}
2019-08-27 15:07:39 +02:00
}
let _ = std::fs::remove_file(socket_path.clone());
let listener = UnixListener::bind(socket_path.clone()).unwrap();
2019-09-06 21:54:04 +02:00
let output_mode = match config.output_mode {
config::OutputMode::All => OutputMode::All,
config::OutputMode::Active => OutputMode::Active,
};
2019-09-07 00:24:58 +02:00
let background = config.background;
2019-09-06 21:54:04 +02:00
let (tx_draw, rx_draw) = channel();
let tx_draw_mod = tx_draw.clone();
let (mod_tx, mod_rx) = channel();
std::thread::spawn(move || {
// Print, write to a file, or send to an HTTP server.
match config.widget.construct(tx_draw_mod) {
Some(w) => mod_tx.send(w).unwrap(),
None => panic!("no widget configured"),
}
});
2019-09-07 00:24:58 +02:00
let mut app = App::new(tx_draw, output_mode, background, scale);
2019-09-06 21:54:04 +02:00
let widget = mod_rx.recv().unwrap();
app.set_widget(widget).unwrap();
2019-08-27 15:07:39 +02:00
let (mut rx_pipe, mut tx_pipe) = pipe().unwrap();
let ipc_pipe = tx_pipe.try_clone().unwrap();
2019-07-30 00:42:05 +02:00
2019-07-30 16:31:42 +02:00
let worker_queue = app.cmd_queue();
2019-08-28 18:06:07 +02:00
let _ = std::thread::Builder::new()
.name("cmd_proxy".to_string())
.spawn(move || loop {
let cmd = rx_draw.recv().unwrap();
worker_queue.lock().unwrap().push_back(cmd);
tx_pipe.write_all(&[0x1]).unwrap();
});
2019-07-30 16:31:42 +02:00
2019-08-27 15:07:39 +02:00
let ipc_queue = app.cmd_queue();
2019-08-28 18:06:07 +02:00
let _ = std::thread::Builder::new()
.name("ipc_server".to_string())
.spawn(move || loop {
for stream in listener.incoming() {
match stream {
Ok(stream) => {
let client_queue = ipc_queue.clone();
let mut client_pipe = ipc_pipe.try_clone().unwrap();
let _ = std::thread::Builder::new()
.name("ipc_client".to_string())
.spawn(move || {
let r = BufReader::new(stream);
for line in r.lines() {
match line {
Ok(v) => match v.as_str() {
"kill" => {
client_queue.lock().unwrap().push_back(Cmd::Exit)
}
"toggle_visible" => client_queue
.lock()
.unwrap()
.push_back(Cmd::ToggleVisible),
v => eprintln!("unknown command: {}", v),
},
Err(_) => return,
}
client_pipe.write_all(&[0x1]).unwrap();
}
});
}
Err(_) => break,
2019-08-27 15:07:39 +02:00
}
}
2019-08-28 18:06:07 +02:00
});
2019-08-27 15:07:39 +02:00
2019-07-30 16:31:42 +02:00
let mut fds = [
PollFd::new(app.event_queue().get_connection_fd(), PollFlags::POLLIN),
PollFd::new(rx_pipe.as_raw_fd(), PollFlags::POLLIN),
];
2019-07-30 00:42:05 +02:00
2019-08-05 23:45:59 +02:00
app.cmd_queue().lock().unwrap().push_back(Cmd::Draw);
2019-07-30 00:42:05 +02:00
let q = app.cmd_queue();
loop {
let cmd = q.lock().unwrap().pop_front();
match cmd {
Some(cmd) => match cmd {
Cmd::Draw => {
2019-07-31 00:42:03 +02:00
app.redraw(false).expect("Failed to draw");
2019-07-30 00:42:05 +02:00
app.flush_display();
2019-07-31 10:26:12 +02:00
}
2019-08-10 00:01:23 +02:00
Cmd::ForceDraw => {
app.redraw(true).expect("Failed to draw");
app.flush_display();
}
2019-09-06 21:54:04 +02:00
Cmd::MouseClick { btn, pos } => {
app.get_widget().mouse_click(btn, pos);
q.lock().unwrap().push_back(Cmd::Draw);
2019-07-30 00:42:05 +02:00
}
2019-09-06 21:54:04 +02:00
Cmd::MouseScroll { scroll, pos } => {
app.get_widget().mouse_scroll(scroll, pos);
q.lock().unwrap().push_back(Cmd::Draw);
}
Cmd::Keyboard {
key,
key_state,
modifiers_state,
interpreted,
} => {
app.get_widget()
.keyboard_input(key, modifiers_state, key_state, interpreted);
2019-08-02 15:59:10 +02:00
q.lock().unwrap().push_back(Cmd::Draw);
}
2019-08-27 15:07:39 +02:00
Cmd::ToggleVisible => {
app.toggle_visible();
}
2019-07-30 00:42:05 +02:00
Cmd::Exit => {
2019-08-27 15:07:39 +02:00
let _ = std::fs::remove_file(socket_path);
return;
2019-07-30 00:42:05 +02:00
}
},
None => {
app.flush_display();
poll(&mut fds, -1).unwrap();
if fds[0].revents().unwrap().contains(PollFlags::POLLIN) {
if let Some(guard) = app.event_queue().prepare_read() {
if let Err(e) = guard.read_events() {
if e.kind() != ::std::io::ErrorKind::WouldBlock {
eprintln!(
"Error while trying to read from the wayland socket: {:?}",
e
);
}
}
}
app.event_queue()
.dispatch_pending()
.expect("Failed to dispatch all messages.");
}
if fds[1].revents().unwrap().contains(PollFlags::POLLIN) {
2019-09-06 21:54:04 +02:00
let mut v = [0x00];
2019-07-30 16:31:42 +02:00
rx_pipe.read_exact(&mut v).unwrap();
2019-07-30 00:42:05 +02:00
}
}
}
}
}