summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs76
-rw-r--r--src/state.rs32
-rw-r--r--src/status_cmd.rs56
3 files changed, 94 insertions, 70 deletions
diff --git a/src/main.rs b/src/main.rs
index c6cc525..befd750 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -18,42 +18,72 @@ mod utils;
mod wm_info_provider;
use signal_hook::consts::*;
-use signal_hook_tokio::Signals;
-use futures::stream::StreamExt;
+use std::{io::ErrorKind, os::fd::AsRawFd};
use wayrs_client::connection::Connection;
+use wayrs_client::IoMode;
+
+use nix::{
+ errno::Errno,
+ fcntl::OFlag,
+ poll::{poll, PollFd, PollFlags},
+};
use state::State;
-#[tokio::main(flavor = "current_thread")]
-async fn main() -> anyhow::Result<()> {
- let mut signals = Signals::new([SIGUSR1])?;
+fn main() -> anyhow::Result<()> {
+ let (sig_read, sig_write) = nix::unistd::pipe2(OFlag::O_NONBLOCK | OFlag::O_CLOEXEC)?;
+ signal_hook::low_level::pipe::register(SIGUSR1, sig_write)?;
let mut conn = Connection::connect()?;
- let globals = conn.async_collect_initial_globals().await?;
+ let globals = conn.blocking_collect_initial_globals()?;
let mut state = State::new(&mut conn, &globals);
- conn.async_flush().await?;
+ conn.flush(IoMode::Blocking)?;
+
+ let mut fds = Vec::with_capacity(3);
+ fds.push(PollFd::new(conn.as_raw_fd(), PollFlags::POLLIN));
+ fds.push(PollFd::new(sig_read, PollFlags::POLLIN));
+ if let Some(cmd_fd) = state.status_cmd_fd() {
+ fds.push(PollFd::new(cmd_fd, PollFlags::POLLIN));
+ }
loop {
- tokio::select! {
- recv_events = conn.async_recv_events() => {
- recv_events?;
- conn.dispatch_events(&mut state);
- conn.async_flush().await?;
- }
- reat_res = state.status_cmd_read() => {
- if let Err(e) = reat_res.and_then(|_| state.status_cmd_notify_available(&mut conn)) {
- if let Some(mut status_cmd) = state.shared_state.status_cmd.take() {
- let _ = status_cmd.child.kill();
- }
- state.set_error(&mut conn, e.to_string());
+ match poll(&mut fds, -1) {
+ Ok(_) => (),
+ Err(Errno::EINTR) => continue,
+ Err(e) => bail!(e),
+ }
+
+ if fds[0].any().unwrap_or(false) {
+ match conn.recv_events(IoMode::NonBlocking) {
+ Ok(()) => {
+ conn.dispatch_events(&mut state);
+ conn.flush(IoMode::Blocking)?;
}
- conn.async_flush().await?;
+ Err(e) if e.kind() == ErrorKind::WouldBlock => (),
+ Err(e) => return Err(e.into()),
}
- Some(signal) = signals.next() => match signal {
- SIGUSR1 => state.toggle_visibility(&mut conn),
- _ => unreachable!(),
+ }
+
+ if fds[1].any().unwrap_or(false) {
+ nix::unistd::read(sig_read, &mut [0; 1])?;
+ state.toggle_visibility(&mut conn);
+ }
+
+ if fds.len() > 2 && fds[2].any().unwrap_or(false) {
+ match state.shared_state.status_cmd.as_mut().unwrap().read() {
+ Ok(None) => (),
+ Ok(Some(blocks)) => {
+ state.set_blocks(&mut conn, blocks);
+ conn.flush(IoMode::Blocking)?;
+ }
+ Err(e) => {
+ let _ = state.shared_state.status_cmd.take().unwrap().child.kill();
+ fds.pop().unwrap();
+ state.set_error(&mut conn, e);
+ conn.flush(IoMode::Blocking)?;
+ }
}
}
}
diff --git a/src/state.rs b/src/state.rs
index 53ef4ff..4741efa 100644
--- a/src/state.rs
+++ b/src/state.rs
@@ -1,7 +1,8 @@
use crate::protocol::*;
use crate::wm_info_provider::*;
-use std::future::pending;
+use std::fmt::Display;
+use std::os::fd::{AsRawFd, RawFd};
use wayrs_client::connection::Connection;
use wayrs_client::global::{Global, GlobalExt, Globals, GlobalsExt};
@@ -108,11 +109,11 @@ impl State {
self.draw_all(conn);
}
- pub fn set_error(&mut self, conn: &mut Connection<Self>, error: impl Into<String>) {
+ pub fn set_error(&mut self, conn: &mut Connection<Self>, error: impl Display) {
self.set_blocks(
conn,
vec![Block {
- full_text: error.into(),
+ full_text: error.to_string(),
..Default::default()
}],
);
@@ -124,26 +125,11 @@ impl State {
}
}
- pub async fn status_cmd_read(&mut self) -> anyhow::Result<()> {
- match &mut self.shared_state.status_cmd {
- Some(cmd) => cmd.read().await,
- None => {
- pending::<()>().await;
- unreachable!()
- }
- }
- }
-
- pub fn status_cmd_notify_available(
- &mut self,
- conn: &mut Connection<Self>,
- ) -> anyhow::Result<()> {
- if let Some(cmd) = &mut self.shared_state.status_cmd {
- if let Some(blocks) = cmd.notify_available()? {
- self.set_blocks(conn, blocks);
- }
- }
- Ok(())
+ pub fn status_cmd_fd(&self) -> Option<RawFd> {
+ self.shared_state
+ .status_cmd
+ .as_ref()
+ .map(|cmd| cmd.output.as_raw_fd())
}
fn bind_output(&mut self, conn: &mut Connection<Self>, global: &Global) {
diff --git a/src/status_cmd.rs b/src/status_cmd.rs
index f6c9c2c..6123a7c 100644
--- a/src/status_cmd.rs
+++ b/src/status_cmd.rs
@@ -1,11 +1,9 @@
use std::io::Write;
-use std::process::{Child, ChildStdin, Command, Stdio};
+use std::os::fd::AsRawFd;
+use std::process::{Child, ChildStdin, ChildStdout, Command, Stdio};
use anyhow::Result;
-use tokio::io::AsyncReadExt;
-use tokio::process::ChildStdout;
-
use crate::i3bar_protocol::{Block, Event, Protocol};
const INITIAL_BUF_CAPACITY: usize = 4096;
@@ -17,6 +15,7 @@ pub struct StatusCmd {
input: ChildStdin,
protocol: Protocol,
buf: Vec<u8>,
+ buf_used: usize,
}
impl StatusCmd {
@@ -28,39 +27,48 @@ impl StatusCmd {
.spawn()?;
let output = child.stdout.take().unwrap();
let input = child.stdin.take().unwrap();
+ nix::fcntl::fcntl(
+ output.as_raw_fd(),
+ nix::fcntl::F_SETFL(nix::fcntl::OFlag::O_NONBLOCK),
+ )?;
Ok(Self {
child,
- output: ChildStdout::from_std(output)?,
+ output,
input,
protocol: Protocol::Unknown,
- buf: Vec::with_capacity(INITIAL_BUF_CAPACITY),
+ buf: vec![0; INITIAL_BUF_CAPACITY],
+ buf_used: 0,
})
}
- pub fn notify_available(&mut self) -> Result<Option<Vec<Block>>> {
- let rem = self.protocol.process_new_bytes(&self.buf)?;
- if rem.is_empty() {
- self.buf.clear();
- } else {
- let used = self.buf.len() - rem.len();
- self.buf.drain(..used);
+ pub fn read(&mut self) -> Result<Option<Vec<Block>>> {
+ assert!(self.buf.len() >= INITIAL_BUF_CAPACITY);
+ if self.buf.len() == self.buf_used {
+ // Double the capacity
+ self.buf.resize(self.buf_used * 2, 0);
}
- Ok(self.protocol.get_blocks())
- }
- pub async fn read(&mut self) -> Result<()> {
- assert!(self.buf.capacity() >= INITIAL_BUF_CAPACITY);
- if self.buf.capacity() == self.buf.len() {
- // Double the capacity
- self.buf.reserve(self.buf.len());
+ match nix::unistd::read(self.output.as_raw_fd(), &mut self.buf[self.buf_used..]) {
+ Ok(0) => bail!("status command exited"),
+ Ok(n) => self.buf_used += n,
+ Err(nix::errno::Errno::EAGAIN) => return Ok(None),
+ Err(e) => bail!(e),
}
- let read_len = self.output.read_buf(&mut self.buf).await?;
- if read_len == 0 {
- bail!("status command exited");
+ let rem = self
+ .protocol
+ .process_new_bytes(&self.buf[..self.buf_used])?;
+
+ if rem.is_empty() {
+ self.buf_used = 0;
+ } else {
+ let rem_len = rem.len();
+ self.buf
+ .copy_within((self.buf_used - rem_len)..self.buf_used, 0);
+ self.buf_used = rem_len;
}
- Ok(())
+ Ok(self.protocol.get_blocks())
}
pub fn send_click_event(&mut self, event: &Event) -> Result<()> {