fix: multiple tray icon related: #464

This commit is contained in:
Kevin Yue 2025-02-09 08:23:40 +00:00
parent fe3d3df662
commit c70c7ee5b9
No known key found for this signature in database
GPG Key ID: 7D27E893D5416DE5
4 changed files with 81 additions and 59 deletions

1
Cargo.lock generated
View File

@ -1599,6 +1599,7 @@ dependencies = [
"clap-verbosity-flag", "clap-verbosity-flag",
"dns-lookup", "dns-lookup",
"env_logger", "env_logger",
"gtk",
"log", "log",
"log-reload", "log-reload",
"md5", "md5",

View File

@ -39,6 +39,9 @@ clap-verbosity-flag = { workspace = true, optional = true }
env_logger = { workspace = true, optional = true } env_logger = { workspace = true, optional = true }
log-reload = { version = "0.1", optional = true } log-reload = { version = "0.1", optional = true }
[target.'cfg(not(any(target_os="macos", target_os="windows")))'.dependencies]
gtk = "0.18"
[features] [features]
tauri = ["dep:tauri"] tauri = ["dep:tauri"]
clap = ["dep:clap", "dep:clap-verbosity-flag"] clap = ["dep:clap", "dep:clap-verbosity-flag"]

View File

@ -41,12 +41,6 @@ pub fn patch_gui_runtime_env(hidpi: bool) {
// This is to avoid blank screen on some systems // This is to avoid blank screen on some systems
std::env::set_var("WEBKIT_DISABLE_COMPOSITING_MODE", "1"); std::env::set_var("WEBKIT_DISABLE_COMPOSITING_MODE", "1");
// Workaround for https://github.com/tauri-apps/tao/issues/929
let is_wayland = std::env::var("XDG_SESSION_TYPE").unwrap_or_default() == "wayland";
if is_wayland {
env::set_var("GDK_BACKEND", "x11");
}
if hidpi { if hidpi {
info!("Setting GDK_SCALE=2 and GDK_DPI_SCALE=0.5"); info!("Setting GDK_SCALE=2 and GDK_DPI_SCALE=0.5");
std::env::set_var("GDK_SCALE", "2"); std::env::set_var("GDK_SCALE", "2");

View File

@ -1,73 +1,97 @@
use std::{process::ExitStatus, time::Duration};
use anyhow::bail;
use log::info;
use tauri::WebviewWindow; use tauri::WebviewWindow;
use tokio::process::Command;
pub trait WindowExt { pub trait WindowExt {
fn raise(&self) -> anyhow::Result<()>; fn raise(&self) -> anyhow::Result<()>;
} }
impl WindowExt for WebviewWindow { impl WindowExt for WebviewWindow {
#[cfg(any(target_os = "macos", target_os = "windows"))]
fn raise(&self) -> anyhow::Result<()> { fn raise(&self) -> anyhow::Result<()> {
raise_window(self) self.show()?;
Ok(())
}
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
fn raise(&self) -> anyhow::Result<()> {
unix::raise_window(self)
} }
} }
pub fn raise_window(win: &WebviewWindow) -> anyhow::Result<()> { #[cfg(not(any(target_os = "macos", target_os = "windows")))]
let is_wayland = std::env::var("XDG_SESSION_TYPE").unwrap_or_default() == "wayland"; mod unix {
use std::{process::ExitStatus, time::Duration};
if is_wayland { use anyhow::bail;
win.hide()?; use gtk::{
win.show()?; glib::Cast,
} else { traits::{EventBoxExt, GtkWindowExt, WidgetExt},
if !win.is_visible()? { EventBox,
win.show()?; };
} use log::info;
let title = win.title()?; use tauri::WebviewWindow;
tokio::spawn(async move { use tokio::process::Command;
if let Err(err) = wmctrl_raise_window(&title).await {
info!("Window not raised: {}", err); pub fn raise_window(win: &WebviewWindow) -> anyhow::Result<()> {
let is_wayland = std::env::var("XDG_SESSION_TYPE").unwrap_or_default() == "wayland";
if is_wayland {
let gtk_win = win.gtk_window()?;
if let Some(header) = gtk_win.titlebar() {
let _ = header.downcast::<EventBox>().map(|event_box| {
event_box.set_above_child(false);
});
} }
});
}
// Calling window.show() on Windows will cause the menu to be shown. gtk_win.hide();
// We need to hide it again. gtk_win.show_all();
win.hide_menu()?; } else {
if !win.is_visible()? {
Ok(()) win.show()?;
}
async fn wmctrl_raise_window(title: &str) -> anyhow::Result<()> {
let mut counter = 0;
loop {
if let Ok(exit_status) = wmctrl_try_raise_window(title).await {
if exit_status.success() {
info!("Window raised after {} attempts", counter + 1);
return Ok(());
} }
let title = win.title()?;
tokio::spawn(async move {
if let Err(err) = wmctrl_raise_window(&title).await {
info!("Window not raised: {}", err);
}
});
} }
if counter >= 10 { // Calling window.show() on window object will cause the menu to be shown.
bail!("Failed to raise window: {}", title) // We need to hide it again.
} win.hide_menu()?;
counter += 1; Ok(())
tokio::time::sleep(Duration::from_millis(100)).await; }
async fn wmctrl_raise_window(title: &str) -> anyhow::Result<()> {
let mut counter = 0;
loop {
if let Ok(exit_status) = wmctrl_try_raise_window(title).await {
if exit_status.success() {
info!("Window raised after {} attempts", counter + 1);
return Ok(());
}
}
if counter >= 10 {
bail!("Failed to raise window: {}", title)
}
counter += 1;
tokio::time::sleep(Duration::from_millis(100)).await;
}
}
async fn wmctrl_try_raise_window(title: &str) -> anyhow::Result<ExitStatus> {
let exit_status = Command::new("wmctrl")
.arg("-F")
.arg("-a")
.arg(title)
.spawn()?
.wait()
.await?;
Ok(exit_status)
} }
} }
async fn wmctrl_try_raise_window(title: &str) -> anyhow::Result<ExitStatus> {
let exit_status = Command::new("wmctrl")
.arg("-F")
.arg("-a")
.arg(title)
.spawn()?
.wait()
.await?;
Ok(exit_status)
}