Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add icon to titlebar #715

Closed
1 task done
jermanuts opened this issue Feb 14, 2025 · 6 comments · Fixed by #719
Closed
1 task done

Add icon to titlebar #715

jermanuts opened this issue Feb 14, 2025 · 6 comments · Fixed by #719
Assignees
Labels
enhancement New feature, request, or improvement
Milestone

Comments

@jermanuts
Copy link

jermanuts commented Feb 14, 2025

Is there an existing issue for this?

  • I have searched the existing issues.

Describe the solution you'd like

An icon in the titlebar

Image

https://docs.iced.rs/iced/window/struct.Icon.html

Relevant issue iced-rs/iced#587

Is your feature request related to a problem?

yes, there's no icon in titlebar for Windows

@GyulyVGC GyulyVGC added the enhancement New feature, request, or improvement label Feb 14, 2025
@GyulyVGC
Copy link
Owner

Thanks for the suggestion

@ZeroDot1
Copy link
Contributor

use iced::window;
use iced::window::icon;

// Assuming you have an icon file named "app_icon.png" in the root of your project
const ICON_BYTES: &[u8] = include_bytes!("../app_icon.png");

fn main() -> iced::Result {
    // Load the icon from the raw bytes
    let app_icon = icon::from_file_data(ICON_BYTES, None).expect("Failed to load icon");

    let configs = CONFIGS.clone();
    let boot_task_chain = handle_cli_args();

    let configs1 = Arc::new(Mutex::new(configs));
    let configs2 = configs1.clone();

    let newer_release_available1 = Arc::new(Mutex::new(None));
    let newer_release_available2 = newer_release_available1.clone();

    // ... (rest of your setup code)

    let ConfigWindow { size, position, .. } = configs1.lock().unwrap().window;

    application(SNIFFNET_TITLECASE, Sniffer::update, Sniffer::view)
        .settings(Settings {
            // id needed for Linux Wayland; should match StartupWMClass in .desktop file; see issue #292
            id: Some(String::from(SNIFFNET_LOWERCASE)),
            fonts: vec![
                Cow::Borrowed(SARASA_MONO_BYTES),
                Cow::Borrowed(SARASA_MONO_BOLD_BYTES),
                Cow::Borrowed(ICONS_BYTES),
            ],
            default_font: Font::with_name(FONT_FAMILY_NAME),
            default_text_size: Pixels(FONT_SIZE_BODY),
            antialiasing: false,
        })
        .window(window::Settings {
            size: size.to_size(), // start size
            position: position.to_position(),
            min_size: None, // Some(ConfigWindow::MIN_SIZE.to_size()), // min size allowed
            max_size: None,
            visible: true,
            resizable: true,
            decorations: true,
            transparent: false,
            icon: Some(app_icon), // Set the icon here
            #[cfg(target_os = "linux")]
            platform_specific: PlatformSpecific {
                application_id: String::from(SNIFFNET_LOWERCASE),
                ..PlatformSpecific::default()
            },
            exit_on_close_request: false,
            ..Default::default()
        })
        .subscription(Sniffer::subscription)
        .theme(Sniffer::theme)
        .scale_factor(Sniffer::scale_factor)
        .run_with(move || {
            (
                Sniffer::new(&configs1, newer_release_available1),
                boot_task_chain,
            )
        })
}

@GyulyVGC
Copy link
Owner

Yes, I just have to verify whether it correctly sets the icon.
I remember I tried in the past without success, but probably this was fixed in newer iced versions.

@ZeroDot1
Copy link
Contributor

Image

OK, I quickly implemented it, it works as shown in the screenshot. the best way is to integrate the function into the main rs.

Here is the code:

cargo:
iced = { version = "0.13.1", features = ["tokio", "svg", "advanced", "lazy", "image"] }

main.rs

//! Module containing the entry point of application execution.

#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use std::borrow::Cow;
use std::sync::{Arc, Mutex};
use std::{panic, process, thread};

#[cfg(target_os = "linux")]
use iced::window::settings::PlatformSpecific;
use iced::{application, window, Font, Pixels, Settings};

use chart::types::chart_type::ChartType;
use chart::types::traffic_chart::TrafficChart;
use cli::handle_cli_args;
use configs::types::config_device::ConfigDevice;
use configs::types::config_settings::ConfigSettings;
use gui::pages::types::running_page::RunningPage;
use gui::sniffer::Sniffer;
use gui::styles::style_constants::FONT_SIZE_BODY;
use gui::styles::types::style_type::StyleType;
use gui::types::runtime_data::RunTimeData;
use networking::types::byte_multiple::ByteMultiple;
use networking::types::info_traffic::InfoTraffic;
use networking::types::ip_version::IpVersion;
use networking::types::protocol::Protocol;
use networking::types::service::Service;
use report::types::report_sort_type::ReportSortType;
use translations::types::language::Language;
use utils::formatted_strings::print_cli_welcome_message;

use crate::configs::types::config_window::{ConfigWindow, ToPosition, ToSize};
use crate::configs::types::configs::{Configs, CONFIGS};
use crate::gui::sniffer::FONT_FAMILY_NAME;
use crate::gui::styles::style_constants::{ICONS_BYTES, SARASA_MONO_BOLD_BYTES, SARASA_MONO_BYTES};
use crate::secondary_threads::check_updates::set_newer_release_status;

mod chart;
mod cli;
mod configs;
mod countries;
mod gui;
mod mmdb;
mod networking;
mod notifications;
mod report;
mod secondary_threads;
mod translations;
mod utils;

pub const SNIFFNET_LOWERCASE: &str = "sniffnet";
pub const SNIFFNET_TITLECASE: &str = "Sniffnet";

// Load the icon file as raw bytes
const APP_ICON_BYTES: &[u8] = include_bytes!("app_icon.png");

/// Entry point of application execution
///
/// It initializes shared variables and loads configuration parameters
pub fn main() -> iced::Result {
    #[cfg(all(windows, not(debug_assertions)))]
    let _gag1: gag::Redirect<std::fs::File>;
    #[cfg(all(windows, not(debug_assertions)))]
    let _gag2: gag::Redirect<std::fs::File>;
    #[cfg(all(windows, not(debug_assertions)))]
    if let Some((gag1, gag2)) = utils::formatted_strings::redirect_stdout_stderr_to_file() {
        _gag1 = gag1;
        _gag2 = gag2;
    }

    let configs = CONFIGS.clone();
    let boot_task_chain = handle_cli_args();

    let configs1 = Arc::new(Mutex::new(configs));
    let configs2 = configs1.clone();

    let newer_release_available1 = Arc::new(Mutex::new(None));
    let newer_release_available2 = newer_release_available1.clone();

    // Kill the main thread as soon as a secondary thread panics
    let orig_hook = panic::take_hook();
    panic::set_hook(Box::new(move |panic_info| {
        // Invoke the default handler and exit the process
        orig_hook(panic_info);
        process::exit(1);
    }));

    // Gracefully close the app when receiving SIGINT, SIGTERM, or SIGHUP
    ctrlc::set_handler(move || {
        configs2.lock().unwrap().clone().store();
        process::exit(130);
    })
    .expect("Error setting Ctrl-C handler");

    thread::Builder::new()
        .name("thread_check_updates".to_string())
        .spawn(move || {
            set_newer_release_status(&newer_release_available2);
        })
        .unwrap();

    print_cli_welcome_message();

    let ConfigWindow { size, position, .. } = configs1.lock().unwrap().window;

    // Load the application icon
    let app_icon = window::icon::from_file_data(APP_ICON_BYTES, None).expect("Failed to load app icon");

    application(SNIFFNET_TITLECASE, Sniffer::update, Sniffer::view)
        .settings(Settings {
            // ID needed for Linux Wayland; should match StartupWMClass in .desktop file; see issue #292
            id: Some(String::from(SNIFFNET_LOWERCASE)),
            fonts: vec![
                Cow::Borrowed(SARASA_MONO_BYTES),
                Cow::Borrowed(SARASA_MONO_BOLD_BYTES),
                Cow::Borrowed(ICONS_BYTES),
            ],
            default_font: Font::with_name(FONT_FAMILY_NAME),
            default_text_size: Pixels(FONT_SIZE_BODY),
            antialiasing: false,
        })
        .window(window::Settings {
            size: size.to_size(), // Start size
            position: position.to_position(),
            min_size: None, // Some(ConfigWindow::MIN_SIZE.to_size()), // Min size allowed
            max_size: None,
            visible: true,
            resizable: true,
            decorations: true,
            transparent: false,
            icon: Some(app_icon), // Set the application icon here
            #[cfg(target_os = "linux")]
            platform_specific: PlatformSpecific {
                application_id: String::from(SNIFFNET_LOWERCASE),
                ..PlatformSpecific::default()
            },
            exit_on_close_request: false,
            ..Default::default()
        })
        .subscription(Sniffer::subscription)
        .theme(Sniffer::theme)
        .scale_factor(Sniffer::scale_factor)
        .run_with(move || {
            (
                Sniffer::new(&configs1, newer_release_available1),
                boot_task_chain,
            )
        })
}

@GyulyVGC
Copy link
Owner

Awesome, thanks. Feel free to send a PR 😁

@ZeroDot1
Copy link
Contributor

ZeroDot1 commented Feb 15, 2025

Done via: #717

ZeroDot1 added a commit to ZeroDot1/sniffnet that referenced this issue Feb 15, 2025
@GyulyVGC GyulyVGC self-assigned this Feb 16, 2025
@GyulyVGC GyulyVGC added this to the v1.4.0 milestone Feb 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature, request, or improvement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants