Release 0.1.1: hide client in system tray

This commit is contained in:
Emil
2026-09-10 19:16:13 +03:00
parent ff7c4e02a7
commit 50a2f49e7c
9 changed files with 137 additions and 21 deletions
+2 -1
View File
@@ -1804,9 +1804,10 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "minivless"
version = "0.1.0"
version = "0.1.1"
dependencies = [
"base64 0.22.1",
"dbus",
"libc",
"serde",
"serde_json",
+4 -3
View File
@@ -1,6 +1,6 @@
[package]
name = "minivless"
version = "0.1.0"
version = "0.1.1"
description = "A small personal VLESS client for Linux"
edition = "2021"
license = "MIT"
@@ -8,13 +8,14 @@ rust-version = "1.85"
[features]
default = ["desktop"]
desktop = ["dep:tauri", "dep:tauri-build"]
desktop = ["dep:tauri", "dep:tauri-build", "dep:dbus"]
[build-dependencies]
tauri-build = { version = "2", optional = true , features = [] }
[dependencies]
tauri = { version = "2", optional = true , features = [] }
tauri = { version = "2", optional = true , features = ["tray-icon"] }
dbus = { version = "0.9", optional = true }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
url = "2"
+81 -2
View File
@@ -10,7 +10,83 @@ use std::{path::PathBuf, sync::Arc};
mod desktop {
use super::*;
use std::sync::atomic::{AtomicBool, Ordering};
use tauri::{Manager, State};
use tauri::{
menu::{Menu, MenuItem},
tray::TrayIconBuilder,
Manager, State,
};
struct TrayReady(bool);
fn tray_host_available() -> bool {
use std::time::Duration;
let Ok(connection) = dbus::blocking::Connection::new_session() else {
return false;
};
let proxy = connection.with_proxy(
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
Duration::from_millis(300),
);
let reply: Result<(bool,), _> = proxy.method_call(
"org.freedesktop.DBus",
"NameHasOwner",
("org.kde.StatusNotifierWatcher",),
);
matches!(reply, Ok((true,)))
}
#[tauri::command]
async fn hide_window(
app: tauri::AppHandle,
window: tauri::WebviewWindow,
) -> Result<(), String> {
let tray_ready = app.state::<TrayReady>().0;
let has_host = tray_ready
&& tauri::async_runtime::spawn_blocking(tray_host_available)
.await
.unwrap_or(false);
// A tray icon can be created even when GNOME has no indicator extension.
// Keep the window recoverable from the taskbar in that case.
if has_host {
window.hide()
} else {
window.minimize()
}
.map_err(|_| "Cannot hide the window".into())
}
fn create_tray(app: &tauri::App) -> tauri::Result<()> {
let show = MenuItem::with_id(app, "show", "Show MiniVLESS", true, None::<&str>)?;
let disconnect = MenuItem::with_id(app, "disconnect", "Disconnect", true, None::<&str>)?;
let quit = MenuItem::with_id(app, "quit", "Quit", true, None::<&str>)?;
let menu = Menu::with_items(app, &[&show, &disconnect, &quit])?;
let mut tray = TrayIconBuilder::with_id("minivless-tray")
.menu(&menu)
.tooltip("MiniVLESS");
if let Some(icon) = app.default_window_icon() {
tray = tray.icon(icon.clone());
}
tray.on_menu_event(|app, event| match event.id.as_ref() {
"show" => {
if let Some(window) = app.get_webview_window("main") {
let _ = window.unminimize();
let _ = window.show();
let _ = window.set_focus();
}
}
"disconnect" => app.state::<Arc<AppState>>().disconnect(),
// Reuse the existing CloseRequested handler, which awaits core shutdown.
"quit" => {
if let Some(window) = app.get_webview_window("main") {
let _ = window.close();
}
}
_ => {}
})
.build(app)?;
Ok(())
}
#[tauri::command]
async fn list_applications() -> Result<Vec<ApplicationInfo>, String> {
tauri::async_runtime::spawn_blocking(processes::list_running)
@@ -79,7 +155,8 @@ mod desktop {
get_status,
get_logs,
load_preferences,
save_preferences
save_preferences,
hide_window
])
.setup(move |app| {
let resources = app.path().resource_dir().ok();
@@ -89,6 +166,8 @@ mod desktop {
std::env::current_exe()?,
);
app.manage(state.clone());
// Lack of tray support must never prevent the VPN client from starting.
app.manage(TrayReady(create_tray(app).is_ok()));
let signals = Arc::new(AtomicBool::new(false));
for sig in [libc::SIGINT, libc::SIGTERM, libc::SIGHUP] {
signal_hook::flag::register(sig, signals.clone())?;
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "MiniVLESS",
"version": "0.1.0",
"version": "0.1.1",
"identifier": "dev.minivless.desktop",
"build": {
"beforeDevCommand": "npm run dev",