Skip to content

Commit f4c070e

Browse files
committed
Embed icon to source code
1 parent 8165826 commit f4c070e

File tree

7 files changed

+40
-84
lines changed

7 files changed

+40
-84
lines changed

Cargo.toml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ overtls = { version = "0.3.6" }
1515
qrcode = "0.14.1"
1616
rfd = { version = "0.15.4", default-features = false, features = ["xdg-portal", "tokio"] }
1717
rqrr = "0.10.0"
18-
run-as = { version = "1.2.4", default-features = false }
18+
run-as = { version = "1.2.5", default-features = false }
1919
screenshot = { version = "0.0.7", git = "https://github.com/ssrlive/screenshot-rs.git", rev = "36f877f" }
2020
serde = { version = "1.0.219", features = ["derive"] }
2121
serde_json = "1.0.143"
@@ -25,3 +25,18 @@ tun2proxy = { version = "0.7.14", default-features = false }
2525

2626
[target.'cfg(target_os = "linux")'.dependencies]
2727
gtk = "0.18.2"
28+
29+
[package.metadata.bundle]
30+
name = "OverTLS GUI"
31+
identifier = "com.ssrlive.overtlsgui"
32+
icon = ["assets/main.png"]
33+
version = "0.1.0"
34+
resources = ["assets"]
35+
copyright = "Copyright (c) ssrlive 2025. All rights reserved."
36+
category = "Utility"
37+
short_description = "OverTLS clients manager"
38+
long_description = """
39+
A graphical user interface for managing OverTLS clients.
40+
"""
41+
osx_frameworks = ["SDL2"]
42+
osx_url_schemes = ["com.ssrlive.overtlsgui"]

build.rs

Lines changed: 1 addition & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1 @@
1-
use std::fs;
2-
use std::path::Path;
3-
4-
fn main() {
5-
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
6-
let src = Path::new(&manifest_dir).join("assets");
7-
let out_dir = std::env::var("OUT_DIR").unwrap();
8-
let profile = std::env::var("PROFILE").unwrap_or_else(|_| "debug".to_string());
9-
let bin_dir = extract_matching_parent_dir(&out_dir, &profile).expect("Failed to find bin dir");
10-
let dst = bin_dir.join("assets");
11-
if src.exists() {
12-
copy_dir_all(&src, &dst).expect("Failed to copy assets directory");
13-
}
14-
}
15-
16-
fn copy_dir_all(src: &Path, dst: &Path) -> std::io::Result<()> {
17-
if !dst.exists() {
18-
fs::create_dir_all(dst)?;
19-
}
20-
for entry in fs::read_dir(src)? {
21-
let entry = entry?;
22-
let file_type = entry.file_type()?;
23-
let src_path = entry.path();
24-
let dst_path = dst.join(entry.file_name());
25-
if file_type.is_dir() {
26-
copy_dir_all(&src_path, &dst_path)?;
27-
} else {
28-
fs::copy(&src_path, &dst_path)?;
29-
}
30-
}
31-
Ok(())
32-
}
33-
34-
pub fn extract_matching_parent_dir<P: AsRef<std::path::Path>>(path: P, match_name: &str) -> std::io::Result<std::path::PathBuf> {
35-
path.as_ref()
36-
.ancestors()
37-
.find(|p| p.file_name() == Some(std::ffi::OsStr::new(match_name)))
38-
.map(|p| p.to_path_buf())
39-
.ok_or_else(|| {
40-
std::io::Error::new(
41-
std::io::ErrorKind::NotFound,
42-
format!("No parent directory matching '{match_name}' found"),
43-
)
44-
})
45-
}
1+
fn main() {}

src/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -504,11 +504,11 @@ async fn main() -> Result<(), BoxError> {
504504
}
505505
});
506506

507-
let icon_path = util::get_main_icon_path()?;
508-
util::set_window_icon(&mut win, icon_path.clone())?;
507+
let icon = util::get_embedded_main_icon()?;
508+
win.set_icon(Some(icon));
509509

510510
let tray_icon_closur = || -> Result<(tray_icon::TrayIcon, tray_icon::menu::MenuItem, tray_icon::menu::MenuItem), BoxError> {
511-
let icon = util::load_icon(icon_path)?;
511+
let icon = util::load_icon_from_bytes(util::MAIN_ICON_BYTES)?;
512512

513513
let show_item = tray_icon::menu::MenuItem::new("Show main window", true, None);
514514
let quit_item = tray_icon::menu::MenuItem::new("Quit", true, None);

src/node_details_dialog.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use fltk::{
55
frame::Frame,
66
group::Flex,
77
input::Input,
8-
prelude::{ButtonExt, GroupExt, InputExt, WidgetBase, WidgetExt},
8+
prelude::{ButtonExt, GroupExt, InputExt, WidgetBase, WidgetExt, WindowExt},
99
window::Window,
1010
};
1111
use overtls::{ClientConfig, TunnelPath};
@@ -52,6 +52,8 @@ pub fn show_node_details(win: &Window, node_cfg: Option<OverTlsNode>, tx: std::s
5252
};
5353

5454
let mut dlg = Window::new(x, y, dialog_w, dialog_h, &*title);
55+
let icon = crate::util::get_embedded_main_icon().unwrap();
56+
dlg.set_icon(Some(icon));
5557

5658
let mut flex = Flex::default_fill().column();
5759
flex.fixed(&dlg, dialog_h);

src/qr_code_dialog.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ pub fn qr_code_dialog(parent: &Window, title: &str, ssr_url: &str) -> std::io::R
2121
let x = parent.x() + (parent.width() - dlg_width) / 2;
2222
let y = parent.y() + (parent.height() - dlg_width) / 2;
2323
let mut win = Window::new(x, y, dlg_width, dlg_width, title);
24+
let icon = crate::util::get_embedded_main_icon()?;
25+
win.set_icon(Some(icon));
26+
2427
let mut frame = Frame::new(72, 72, 256, 256, "");
2528
let png = PngImage::from_data(&png_bytes).map_err(|e| std::io::Error::other(format!("FLTK image error: {e}")))?;
2629
frame.set_image(Some(png));

src/settings_dialog.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use fltk::{
55
frame::Frame,
66
group::Flex,
77
input::Input,
8-
prelude::{ButtonExt, GroupExt, InputExt, MenuExt, WidgetBase, WidgetExt},
8+
prelude::{ButtonExt, GroupExt, InputExt, MenuExt, WidgetBase, WidgetExt, WindowExt},
99
window::Window,
1010
};
1111

@@ -93,6 +93,9 @@ pub fn show_settings_dialog(win: &Window, system_settings: &SystemSettings, tx:
9393
let x = win.x() + (win.width() - dialog_w) / 2;
9494
let y = win.y() + (win.height() - dialog_h) / 2;
9595
let mut dlg = Window::new(x, y, dialog_w, dialog_h, "Settings");
96+
let icon = crate::util::get_embedded_main_icon().unwrap();
97+
dlg.set_icon(Some(icon));
98+
9699
let mut tabs = fltk::group::Tabs::new(0, 0, dialog_w, dialog_h, "");
97100
tabs.set_tab_align(Align::Top);
98101

src/util.rs

Lines changed: 10 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -41,40 +41,17 @@ pub fn file_chooser_save_file(title: &str, default_path: Option<&str>, filter: &
4141
.save_file()
4242
}
4343

44-
pub fn load_icon<P: AsRef<std::path::Path>>(path: P) -> std::io::Result<tray_icon::Icon> {
45-
let (icon_rgba, icon_width, icon_height) = {
46-
let image = image::open(path)
47-
.map_err(|e| std::io::Error::other(format!("Failed to open icon path {e}")))?
48-
.into_rgba8();
49-
let (width, height) = image.dimensions();
50-
let rgba = image.into_raw();
51-
(rgba, width, height)
52-
};
53-
tray_icon::Icon::from_rgba(icon_rgba, icon_width, icon_height)
54-
.map_err(|e| std::io::Error::other(format!("Failed to create tray icon: {e}")))
44+
pub fn load_icon_from_bytes(bytes: &[u8]) -> std::io::Result<tray_icon::Icon> {
45+
let image = image::load_from_memory(bytes)
46+
.map_err(|e| std::io::Error::other(format!("Failed to load icon from memory: {e}")))?
47+
.into_rgba8();
48+
let (width, height) = image.dimensions();
49+
let rgba = image.into_raw();
50+
tray_icon::Icon::from_rgba(rgba, width, height).map_err(|e| std::io::Error::other(format!("Failed to create tray icon: {e}")))
5551
}
5652

57-
/// Get the path to the application icon (assets/main.png) relative to the executable.
58-
pub fn get_main_icon_path() -> std::io::Result<PathBuf> {
59-
let exe_path = std::env::current_exe()?;
60-
let exe_dir = exe_path
61-
.parent()
62-
.ok_or_else(|| std::io::Error::other("Failed to get executable directory"))?;
63-
let icon_path = exe_dir.join("assets").join("main.png");
64-
if icon_path.exists() {
65-
Ok(icon_path)
66-
} else {
67-
Err(std::io::Error::other(format!("Icon file not found at {icon_path:?}")))
68-
}
69-
}
53+
pub const MAIN_ICON_BYTES: &[u8] = include_bytes!("../assets/main.png");
7054

71-
pub fn set_window_icon<P: AsRef<std::path::Path>>(window: &mut fltk::window::Window, icon_path: P) -> std::io::Result<()> {
72-
let mut f = std::fs::File::open(icon_path.as_ref())?;
73-
use std::io::Read;
74-
let mut buf = Vec::new();
75-
f.read_to_end(&mut buf)?;
76-
let png = fltk::image::PngImage::from_data(&buf).map_err(|e| std::io::Error::other(format!("Failed to load icon data: {e}")))?;
77-
use fltk::prelude::WindowExt;
78-
window.set_icon(Some(png));
79-
Ok(())
55+
pub fn get_embedded_main_icon() -> std::io::Result<fltk::image::PngImage> {
56+
fltk::image::PngImage::from_data(MAIN_ICON_BYTES).map_err(|e| std::io::Error::other(format!("Failed to load embedded icon: {e}")))
8057
}

0 commit comments

Comments
 (0)