From 8f1cd1a20ec3fdfdba3a87a67ee6822738510a4f Mon Sep 17 00:00:00 2001 From: Benjamin Isbarn Date: Tue, 18 Jun 2024 20:09:29 +0200 Subject: [PATCH] Remove window flicker from open command This solves a problem that had been already solved in 0d1b5e0f9e532ade4b7c9fd77b46b6a29b1d8529 but was reintroduced in a9a35c1804d72ef92e04ee71555bd9e5a08fa17e. Basically before this, the window has been closed and reopened if it existed, which results in flickering due to the animations. In addition to remove the window flicker the timer (if started with --duration) will also be renewed. This fixes #892. --- CHANGELOG.md | 1 + crates/eww/src/app.rs | 62 ++++++++++++++++++++++++------------------- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32e2aa82..b708fa81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to eww will be listed here, starting at changes since versio ## Unreleased ### Fixes +- Fix window flicker when opening an already existing window (By: benesim) - Fix and refactor nix flake (By: w-lfchen) - Fix remove items from systray (By: vnva) diff --git a/crates/eww/src/app.rs b/crates/eww/src/app.rs index 41b3364a..9eedbf60 100644 --- a/crates/eww/src/app.rs +++ b/crates/eww/src/app.rs @@ -362,14 +362,46 @@ impl App { Ok(()) } + fn setup_close_timer(&mut self, instance_id: &str, duration: Duration) { + let app_evt_sender = self.app_evt_send.clone(); + + let (abort_send, abort_recv) = futures::channel::oneshot::channel(); + + glib::MainContext::default().spawn_local({ + let instance_id = instance_id.to_string(); + async move { + tokio::select! { + _ = glib::timeout_future(duration) => { + let (response_sender, mut response_recv) = daemon_response::create_pair(); + let command = DaemonCommand::CloseWindows { windows: vec![instance_id.clone()], 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(instance_id.to_string(), abort_send) { + _ = old_abort_send.send(()); + } + } + fn open_window(&mut self, window_args: &WindowArguments) -> Result<()> { let instance_id = &window_args.instance_id; self.failed_windows.remove(instance_id); log::info!("Opening window {} as '{}'", window_args.window_name, instance_id); - // if an instance of this is already running, close it + // if an instance of this is already running, do nothing, but if a + // duration has been supplied refresh the window close timer + let duration = window_args.duration; if self.open_windows.contains_key(instance_id) { - self.close_window(instance_id)?; + if let Some(duration) = duration { + self.setup_close_timer(instance_id, duration); + } + return Ok(()); } self.instance_id_to_args.insert(instance_id.to_string(), window_args.clone()); @@ -431,32 +463,8 @@ impl App { } })); - let duration = window_args.duration; if let Some(duration) = duration { - let app_evt_sender = self.app_evt_send.clone(); - - let (abort_send, abort_recv) = futures::channel::oneshot::channel(); - - glib::MainContext::default().spawn_local({ - let instance_id = instance_id.to_string(); - async move { - tokio::select! { - _ = glib::timeout_future(duration) => { - let (response_sender, mut response_recv) = daemon_response::create_pair(); - let command = DaemonCommand::CloseWindows { windows: vec![instance_id.clone()], 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(instance_id.to_string(), abort_send) { - _ = old_abort_send.send(()); - } + self.setup_close_timer(instance_id, duration); } self.open_windows.insert(instance_id.to_string(), eww_window);