Support --duration close timer for windows (#884)

This commit is contained in:
ElKowar 2023-08-18 15:51:42 +02:00 committed by GitHub
parent 393f7fa401
commit a9a35c1804
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 69 additions and 12 deletions

View File

@ -19,6 +19,7 @@ All notable changes to eww will be listed here, starting at changes since versio
- Add `EWW_TIME` magic variable (By: Erenoit)
- Add trigonometric functions (`sin`, `cos`, `tan`, `cot`) and degree/radian conversions (`degtorad`, `radtodeg`) (By: end-4)
- Add `substring` function to simplexpr
- Add `--duration` flag to `eww open`
## [0.4.0] (04.09.2022)

7
Cargo.lock generated
View File

@ -683,8 +683,7 @@ dependencies = [
"derive_more",
"eww_shared_util",
"extend",
"futures-core",
"futures-util",
"futures",
"gdk",
"gdk-pixbuf",
"gdkx11",
@ -786,6 +785,7 @@ checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
@ -854,10 +854,13 @@ version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",

View File

@ -50,8 +50,7 @@ simple-signal = "1.1"
unescape = "0.1"
tokio = { version = "1.31.0", features = ["full"] }
futures-core = "0.3.28"
futures-util = "0.3.28"
futures = "0.3.28"
tokio-util = "0.7.8"
sysinfo = "0.29.8"

View File

@ -55,6 +55,7 @@ pub enum DaemonCommand {
anchor: Option<AnchorPoint>,
screen: Option<MonitorIdentifier>,
should_toggle: bool,
duration: Option<std::time::Duration>,
sender: DaemonResponseSender,
},
CloseWindows {
@ -114,6 +115,9 @@ pub struct App<B> {
pub app_evt_send: UnboundedSender<DaemonCommand>,
pub script_var_handler: ScriptVarHandlerHandle,
/// Senders that will cancel a windows auto-close timer when started with --duration.
pub window_close_timer_abort_senders: HashMap<String, futures::channel::oneshot::Sender<()>>,
pub paths: EwwPaths,
}
@ -181,20 +185,27 @@ impl<B: DisplayBackend> App<B> {
if should_toggle && self.open_windows.contains_key(w) {
self.close_window(w)
} else {
self.open_window(w, None, None, None, None)
self.open_window(w, None, None, None, None, None)
}
})
.filter_map(Result::err);
sender.respond_with_error_list(errors)?;
}
DaemonCommand::OpenWindow { window_name, pos, size, anchor, screen: monitor, should_toggle, sender } => {
DaemonCommand::OpenWindow {
window_name,
pos,
size,
anchor,
screen: monitor,
should_toggle,
duration,
sender,
} => {
let is_open = self.open_windows.contains_key(&window_name);
let result = if !is_open {
self.open_window(&window_name, pos, size, monitor, anchor)
} else if should_toggle {
let result = if should_toggle && is_open {
self.close_window(&window_name)
} else {
Ok(())
self.open_window(&window_name, pos, size, monitor, anchor, duration)
};
sender.respond_with_result(result)?;
}
@ -294,6 +305,9 @@ impl<B: DisplayBackend> App<B> {
/// Close a window and do all the required cleanups in the scope_graph and script_var_handler
fn close_window(&mut self, window_name: &str) -> Result<()> {
if let Some(old_abort_send) = self.window_close_timer_abort_senders.remove(window_name) {
_ = old_abort_send.send(());
}
let eww_window = self
.open_windows
.remove(window_name)
@ -320,11 +334,13 @@ impl<B: DisplayBackend> App<B> {
size: Option<Coords>,
monitor: Option<MonitorIdentifier>,
anchor: Option<AnchorPoint>,
duration: Option<std::time::Duration>,
) -> Result<()> {
self.failed_windows.remove(window_name);
log::info!("Opening window {}", window_name);
// if an instance of this is already running, close it
// TODO make reopening optional via a --no-reopen flag?
if self.open_windows.contains_key(window_name) {
self.close_window(window_name)?;
}
@ -380,6 +396,34 @@ impl<B: DisplayBackend> App<B> {
}
}));
if let Some(duration) = duration {
let app_evt_sender = self.app_evt_send.clone();
let window_name = window_name.to_string();
let (abort_send, abort_recv) = futures::channel::oneshot::channel();
glib::MainContext::default().spawn_local({
let window_name = window_name.clone();
async move {
tokio::select! {
_ = glib::timeout_future(duration) => {
let (response_sender, mut response_recv) = daemon_response::create_pair();
let command = DaemonCommand::CloseWindows { windows: vec![window_name], sender: response_sender };
if let Err(err) = app_evt_sender.send(command) {
log::error!("Error sending close window command to daemon after gtk window destroy event: {}", err);
}
_ = response_recv.recv().await;
}
_ = abort_recv => {}
}
}
});
if let Some(old_abort_send) = self.window_close_timer_abort_senders.insert(window_name, abort_send) {
_ = old_abort_send.send(());
}
}
self.open_windows.insert(window_name.to_string(), eww_window);
};
@ -407,7 +451,7 @@ impl<B: DisplayBackend> App<B> {
let window_names: Vec<String> =
self.open_windows.keys().cloned().chain(self.failed_windows.iter().cloned()).dedup().collect();
for window_name in &window_names {
self.open_window(window_name, None, None, None, None)?;
self.open_window(window_name, None, None, None, None, None)?;
}
Ok(())
}

View File

@ -120,6 +120,10 @@ pub enum ActionWithServer {
/// If the window is already open, close it instead
#[arg(long = "toggle")]
should_toggle: bool,
/// Automatically close the window after a specified amount of time, i.e.: 1s
#[arg(long, value_parser=parse_duration)]
duration: Option<std::time::Duration>,
},
/// Open multiple windows at once.
@ -218,7 +222,7 @@ impl ActionWithServer {
ActionWithServer::OpenMany { windows, should_toggle } => {
return with_response_channel(|sender| app::DaemonCommand::OpenMany { windows, should_toggle, sender });
}
ActionWithServer::OpenWindow { window_name, pos, size, screen, anchor, should_toggle } => {
ActionWithServer::OpenWindow { window_name, pos, size, screen, anchor, should_toggle, duration } => {
return with_response_channel(|sender| app::DaemonCommand::OpenWindow {
window_name,
pos,
@ -226,6 +230,7 @@ impl ActionWithServer {
anchor,
screen,
should_toggle,
duration,
sender,
})
}
@ -254,3 +259,7 @@ where
let (sender, recv) = daemon_response::create_pair();
(f(sender), Some(recv))
}
fn parse_duration(s: &str) -> Result<std::time::Duration, simplexpr::dynval::ConversionError> {
DynVal::from_string(s.to_owned()).as_duration()
}

View File

@ -84,6 +84,7 @@ pub fn initialize_server<B: DisplayBackend>(
css_provider: gtk::CssProvider::new(),
script_var_handler,
app_evt_send: ui_send.clone(),
window_close_timer_abort_senders: HashMap::new(),
paths,
};