Experimental command socket support

Introduces "start-or-kill" and "toggle-visible" commands. How the
command socket is used will likely change soon.
This commit is contained in:
Kenny Levinsen
2019-08-27 15:09:19 +02:00
parent 1cadf43d49
commit 6deffa91bb
6 changed files with 169 additions and 59 deletions
+40 -26
View File
@@ -17,6 +17,8 @@ use wayland_protocols::wlr::unstable::layer_shell::v1::client::{
use crate::color::Color; use crate::color::Color;
use crate::buffer::Buffer; use crate::buffer::Buffer;
use crate::cmd::Cmd;
use crate::modules::backlight::Backlight; use crate::modules::backlight::Backlight;
use crate::modules::battery::UpowerBattery; use crate::modules::battery::UpowerBattery;
use crate::modules::calendar::Calendar; use crate::modules::calendar::Calendar;
@@ -25,12 +27,9 @@ use crate::modules::launcher::Launcher;
use crate::modules::module::{Input, Module}; use crate::modules::module::{Input, Module};
use crate::modules::sound::PulseAudio; use crate::modules::sound::PulseAudio;
pub enum Cmd { pub enum OutputMode {
Exit, Active,
Draw, All,
ForceDraw,
MouseInput { pos: (u32, u32), input: Input },
KeyboardInput { input: Input },
} }
struct AppInner { struct AppInner {
@@ -41,12 +40,13 @@ struct AppInner {
outputs: Vec<(u32, wl_output::WlOutput)>, outputs: Vec<(u32, wl_output::WlOutput)>,
shell: Option<zwlr_layer_shell_v1::ZwlrLayerShellV1>, shell: Option<zwlr_layer_shell_v1::ZwlrLayerShellV1>,
dimensions: (u32, u32), dimensions: (u32, u32),
draw_tx: Sender<bool>, draw_tx: Sender<Cmd>,
all_outputs: bool, output_mode: OutputMode,
visible: bool,
} }
impl AppInner { impl AppInner {
fn new(tx: Sender<bool>, all_outputs: bool) -> AppInner{ fn new(tx: Sender<Cmd>, output_mode: OutputMode) -> AppInner{
AppInner{ AppInner{
compositor: None, compositor: None,
surfaces: Vec::new(), surfaces: Vec::new(),
@@ -56,7 +56,8 @@ impl AppInner {
shell: None, shell: None,
dimensions: (0, 0), dimensions: (0, 0),
draw_tx: tx, draw_tx: tx,
all_outputs: all_outputs, output_mode: output_mode,
visible: true,
} }
} }
@@ -65,7 +66,7 @@ impl AppInner {
shell: &zwlr_layer_shell_v1::ZwlrLayerShellV1, shell: &zwlr_layer_shell_v1::ZwlrLayerShellV1,
dimensions: (u32, u32), dimensions: (u32, u32),
configured_surfaces: Arc<Mutex<usize>>, configured_surfaces: Arc<Mutex<usize>>,
tx: Sender<bool>, tx: Sender<Cmd>,
output: Option<&wl_output::WlOutput> output: Option<&wl_output::WlOutput>
) -> ( ) -> (
wl_surface::WlSurface, wl_surface::WlSurface,
@@ -87,7 +88,7 @@ impl AppInner {
zwlr_layer_surface_v1::Event::Configure { serial, .. } => { zwlr_layer_surface_v1::Event::Configure { serial, .. } => {
*(configured_surfaces.lock().unwrap()) += 1; *(configured_surfaces.lock().unwrap()) += 1;
layer.ack_configure(serial); layer.ack_configure(serial);
tx.send(false).unwrap(); tx.send(Cmd::ForceDraw).unwrap();
} }
_ => unreachable!(), _ => unreachable!(),
}, },
@@ -114,10 +115,6 @@ impl AppInner {
None => return, None => return,
}; };
if !self.all_outputs && self.shell_surfaces.len() > 0 {
return;
}
for shell_surface in self.shell_surfaces.iter() { for shell_surface in self.shell_surfaces.iter() {
shell_surface.destroy(); shell_surface.destroy();
} }
@@ -127,7 +124,18 @@ impl AppInner {
self.configured_surfaces = Arc::new(Mutex::new(0)); self.configured_surfaces = Arc::new(Mutex::new(0));
if self.all_outputs { if self.visible {
match self.output_mode {
OutputMode::Active => {
if self.shell_surfaces.len() > 0 {
return;
}
let (surface, shell_surface) = AppInner::add_shell_surface(&compositor, &shell, self.dimensions, self.configured_surfaces.clone(), self.draw_tx.clone(), None);
self.surfaces = vec![surface];
self.shell_surfaces = vec![shell_surface];
},
OutputMode::All => {
let mut surfaces = Vec::new(); let mut surfaces = Vec::new();
let mut shell_surfaces = Vec::new(); let mut shell_surfaces = Vec::new();
for output in self.outputs.iter() { for output in self.outputs.iter() {
@@ -137,13 +145,13 @@ impl AppInner {
} }
self.surfaces = surfaces; self.surfaces = surfaces;
self.shell_surfaces = shell_surfaces; self.shell_surfaces = shell_surfaces;
} else {
let (surface, shell_surface) = AppInner::add_shell_surface(&compositor, &shell, self.dimensions, self.configured_surfaces.clone(), self.draw_tx.clone(), None);
self.surfaces = vec![surface];
self.shell_surfaces = vec![shell_surface];
} }
}
self.draw_tx.send(false).unwrap(); self.draw_tx.send(Cmd::ForceDraw).unwrap();
} else {
self.surfaces = Vec::new();
self.shell_surfaces = Vec::new();
}
} }
fn add_output(&mut self, id: u32, output: wl_output::WlOutput) { fn add_output(&mut self, id: u32, output: wl_output::WlOutput) {
@@ -249,6 +257,12 @@ impl App {
Ok(()) Ok(())
} }
pub fn toggle_visible(&mut self) {
let mut inner = self.inner.lock().unwrap();
inner.visible = !inner.visible;
inner.outputs_changed();
}
pub fn cmd_queue(&self) -> Arc<Mutex<VecDeque<Cmd>>> { pub fn cmd_queue(&self) -> Arc<Mutex<VecDeque<Cmd>>> {
self.cmd_queue.clone() self.cmd_queue.clone()
} }
@@ -291,8 +305,8 @@ impl App {
None None
} }
pub fn new(tx: Sender<bool>, all_outputs: bool) -> App { pub fn new(tx: Sender<Cmd>, output_mode: OutputMode) -> App {
let inner = Arc::new(Mutex::new(AppInner::new(tx.clone(), all_outputs))); let inner = Arc::new(Mutex::new(AppInner::new(tx.clone(), output_mode)));
// //
// Set up modules // Set up modules
@@ -304,7 +318,7 @@ impl App {
Module::new(Box::new(Calendar::new()), (0, 368, 1232, 344)), Module::new(Box::new(Calendar::new()), (0, 368, 1232, 344)),
]; ];
if let Ok(m) = Launcher::new() { if let Ok(m) = Launcher::new(tx.clone()) {
modules.push(Module::new(Box::new(m), (0, 728, 1232, 32))); modules.push(Module::new(Box::new(m), (0, 728, 1232, 32)));
} }
+103 -15
View File
@@ -1,7 +1,8 @@
use std::io::{Read, Write}; use std::io::{Read, Write, BufRead, BufReader};
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
use std::env; use std::env;
use std::os::unix::net::{UnixStream, UnixListener};
use nix::poll::{poll, PollFd, PollFlags}; use nix::poll::{poll, PollFd, PollFlags};
use os_pipe::pipe; use os_pipe::pipe;
@@ -11,31 +12,114 @@ mod color;
mod draw; mod draw;
mod modules; mod modules;
mod app; mod app;
mod cmd;
use app::{App, Cmd}; use app::{App, OutputMode};
use cmd::Cmd;
enum Mode {
Start,
StartOrKill,
ToggleVisible,
}
fn main() { fn main() {
let (mut rx_pipe, mut tx_pipe) = pipe().unwrap(); let socket_path = match env::var("XDG_RUNTIME_DIR") {
let (tx_draw, rx_draw) = channel(); Ok(dir) => dir + "/wldash",
Err(_) => "/tmp/wldash".to_string(),
let all_outputs = match env::var("WLDASH_ALL_OUTPUTS") {
Ok(_) => true,
Err(_) => false,
}; };
let mut app = App::new(tx_draw, all_outputs); 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,
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);
};
}
}
let _ = std::fs::remove_file(socket_path.clone());
let listener = UnixListener::bind(socket_path.clone()).unwrap();
let (mut rx_pipe, mut tx_pipe) = pipe().unwrap();
let ipc_pipe = tx_pipe.try_clone().unwrap();
let (tx_draw, rx_draw) = channel();
let output_mode = match env::var("WLDASH_ALL_OUTPUTS") {
Ok(_) => OutputMode::All,
Err(_) => OutputMode::Active,
};
let mut app = App::new(tx_draw, output_mode);
app.wipe(); app.wipe();
let worker_queue = app.cmd_queue(); let worker_queue = app.cmd_queue();
std::thread::spawn(move || loop { std::thread::spawn(move || loop {
if rx_draw.recv().unwrap() { let cmd = rx_draw.recv().unwrap();
worker_queue.lock().unwrap().push_back(Cmd::Draw); worker_queue.lock().unwrap().push_back(cmd);
} else {
worker_queue.lock().unwrap().push_back(Cmd::ForceDraw);
}
tx_pipe.write_all(&[0x1]).unwrap(); tx_pipe.write_all(&[0x1]).unwrap();
}); });
let ipc_queue = app.cmd_queue();
std::thread::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();
std::thread::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,
}
}
});
let mut fds = [ let mut fds = [
PollFd::new(app.event_queue().get_connection_fd(), PollFlags::POLLIN), PollFd::new(app.event_queue().get_connection_fd(), PollFlags::POLLIN),
PollFd::new(rx_pipe.as_raw_fd(), PollFlags::POLLIN), PollFd::new(rx_pipe.as_raw_fd(), PollFlags::POLLIN),
@@ -70,8 +154,12 @@ fn main() {
}); });
q.lock().unwrap().push_back(Cmd::Draw); q.lock().unwrap().push_back(Cmd::Draw);
} }
Cmd::ToggleVisible => {
app.toggle_visible();
}
Cmd::Exit => { Cmd::Exit => {
std::process::exit(0); let _ = std::fs::remove_file(socket_path);
return;
} }
}, },
None => { None => {
+3 -2
View File
@@ -2,6 +2,7 @@ use crate::buffer::Buffer;
use crate::color::Color; use crate::color::Color;
use crate::draw::{draw_bar, draw_box, Font, ROBOTO_REGULAR}; use crate::draw::{draw_bar, draw_box, Font, ROBOTO_REGULAR};
use crate::modules::module::{Input, ModuleImpl}; use crate::modules::module::{Input, ModuleImpl};
use crate::cmd::Cmd;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@@ -129,7 +130,7 @@ impl UpowerBattery {
}) })
} }
pub fn new(listener: Sender<bool>) -> Result<Self, ::std::io::Error> { pub fn new(listener: Sender<Cmd>) -> Result<Self, ::std::io::Error> {
let d = UpowerBattery::from_device("BAT0")?; let d = UpowerBattery::from_device("BAT0")?;
let path = d.device_path.clone(); let path = d.device_path.clone();
let inner = d.inner.clone(); let inner = d.inner.clone();
@@ -175,7 +176,7 @@ impl UpowerBattery {
inner.state = state; inner.state = state;
inner.capacity = capacity; inner.capacity = capacity;
inner.dirty = true; inner.dirty = true;
listener.send(true).unwrap(); listener.send(Cmd::Draw).unwrap();
} }
} }
}); });
+3 -2
View File
@@ -2,6 +2,7 @@ use crate::buffer::Buffer;
use crate::color::Color; use crate::color::Color;
use crate::draw::{Font, ROBOTO_REGULAR}; use crate::draw::{Font, ROBOTO_REGULAR};
use crate::modules::module::{Input, ModuleImpl}; use crate::modules::module::{Input, ModuleImpl};
use crate::cmd::Cmd;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
@@ -15,7 +16,7 @@ pub struct Clock {
} }
impl Clock { impl Clock {
pub fn new(ch: Sender<bool>) -> Clock { pub fn new(ch: Sender<Cmd>) -> Clock {
std::thread::spawn(move || loop { std::thread::spawn(move || loop {
let n = Local::now(); let n = Local::now();
let target = (n + Duration::seconds(60)) let target = (n + Duration::seconds(60))
@@ -27,7 +28,7 @@ impl Clock {
let d = target - n; let d = target - n;
std::thread::sleep(d.to_std().unwrap()); std::thread::sleep(d.to_std().unwrap());
ch.send(true).unwrap(); ch.send(Cmd::Draw).unwrap();
}); });
let mut date_cache = Font::new(&ROBOTO_REGULAR, 64.0); let mut date_cache = Font::new(&ROBOTO_REGULAR, 64.0);
+8 -3
View File
@@ -2,7 +2,9 @@ use crate::buffer::Buffer;
use crate::color::Color; use crate::color::Color;
use crate::draw::{Font, ROBOTO_REGULAR}; use crate::draw::{Font, ROBOTO_REGULAR};
use crate::modules::module::{Input, ModuleImpl}; use crate::modules::module::{Input, ModuleImpl};
use crate::cmd::Cmd;
use std::sync::mpsc::Sender;
use std::cell::RefCell; use std::cell::RefCell;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::io::Read; use std::io::Read;
@@ -20,10 +22,11 @@ pub struct Launcher {
offset: usize, offset: usize,
font: RefCell<Font>, font: RefCell<Font>,
dirty: bool, dirty: bool,
tx: Sender<Cmd>,
} }
impl Launcher { impl Launcher {
pub fn new() -> Result<Launcher, ::std::io::Error> { pub fn new(listener: Sender<Cmd>) -> Result<Launcher, ::std::io::Error> {
if !atty::is(Stream::Stdin) { if !atty::is(Stream::Stdin) {
let mut inbuf = String::new(); let mut inbuf = String::new();
std::io::stdin().read_to_string(&mut inbuf)?; std::io::stdin().read_to_string(&mut inbuf)?;
@@ -42,6 +45,7 @@ impl Launcher {
offset: 0, offset: 0,
font: RefCell::new(Font::new(&ROBOTO_REGULAR, 32.0)), font: RefCell::new(Font::new(&ROBOTO_REGULAR, 32.0)),
dirty: true, dirty: true,
tx: listener,
}) })
} else { } else {
Ok(Launcher { Ok(Launcher {
@@ -52,6 +56,7 @@ impl Launcher {
offset: 0, offset: 0,
font: RefCell::new(Font::new(&ROBOTO_REGULAR, 32.0)), font: RefCell::new(Font::new(&ROBOTO_REGULAR, 32.0)),
dirty: true, dirty: true,
tx: listener,
}) })
} }
} }
@@ -313,12 +318,12 @@ impl ModuleImpl for Launcher {
}, },
Some('!') => { Some('!') => {
println!("{}", self.input.chars().skip(1).collect::<String>()); println!("{}", self.input.chars().skip(1).collect::<String>());
std::process::exit(0); self.tx.send(Cmd::Exit).unwrap();
} }
_ => { _ => {
if self.matches.len() > self.offset { if self.matches.len() > self.offset {
println!("{}", self.matches[self.offset]); println!("{}", self.matches[self.offset]);
std::process::exit(0); self.tx.send(Cmd::Exit).unwrap();
} }
} }
}; };
+3 -2
View File
@@ -2,6 +2,7 @@ use crate::buffer::Buffer;
use crate::color::Color; use crate::color::Color;
use crate::draw::{draw_bar, draw_box, Font, ROBOTO_REGULAR}; use crate::draw::{draw_bar, draw_box, Font, ROBOTO_REGULAR};
use crate::modules::module::{Input, ModuleImpl}; use crate::modules::module::{Input, ModuleImpl};
use crate::cmd::Cmd;
use std::cell::RefCell; use std::cell::RefCell;
use std::cmp::{max, min}; use std::cmp::{max, min};
@@ -404,7 +405,7 @@ pub struct PulseAudio {
} }
impl PulseAudio { impl PulseAudio {
pub fn new(listener: Sender<bool>) -> Result<PulseAudio, ::std::io::Error> { pub fn new(listener: Sender<Cmd>) -> Result<PulseAudio, ::std::io::Error> {
let (tx, rx) = channel(); let (tx, rx) = channel();
let mut font = Font::new(&ROBOTO_REGULAR, 24.0); let mut font = Font::new(&ROBOTO_REGULAR, 24.0);
font.add_str_to_cache("volume"); font.add_str_to_cache("volume");
@@ -419,7 +420,7 @@ impl PulseAudio {
rx.recv().unwrap(); rx.recv().unwrap();
device.lock().unwrap().get_info().unwrap(); device.lock().unwrap().get_info().unwrap();
*(dirty.lock().unwrap()) = true; *(dirty.lock().unwrap()) = true;
listener.send(true).unwrap(); listener.send(Cmd::Draw).unwrap();
}); });
Ok(pa) Ok(pa)
} }