mirror of
https://github.com/elkowar/eww.git
synced 2024-09-11 19:57:16 +03:00
Support --duration close timer for windows (#884)
This commit is contained in:
parent
393f7fa401
commit
a9a35c1804
@ -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
7
Cargo.lock
generated
@ -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",
|
||||
|
@ -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"
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user