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

Taskbar icon and system menu information always shown on macOS #3921

Open
Jooonnnaass opened this issue Sep 18, 2024 · 2 comments
Open

Taskbar icon and system menu information always shown on macOS #3921

Jooonnnaass opened this issue Sep 18, 2024 · 2 comments
Labels
B - bug Dang, that shouldn't have happened DS - macos

Comments

@Jooonnnaass
Copy link

Description

Im trying to create an overlay application with winit. I create an event loop and create a tray menu with the tray_icon crate.
Based on the MenuItems i create two windows, one for the app config and one for the overlay.

First everything was working fine but for some reason now every time i start the app, the exec icon shows up in the taskbar and the crate name will show up in the system titlebar of macOS even a window wasn't created yet.

I tried different window attributes but nothing works.

None of the opened issues helped me so far.

That's the code for creating the window based on the menu item button click.

                    let overlay_window_attributes = WindowAttributes::default()
                        .with_title("Overlay")
                        .with_inner_size(size)
                        .with_decorations(false)
                        .with_window_level(WindowLevel::AlwaysOnTop)
                        .with_transparent(true);
                    let window = event_loop.create_window(overlay_window_attributes).unwrap();
                    tray_app_state.overlay_window_id = Some(window.id());
                    tray_app_state.windows.insert(window.id(), Box::new(window));

macOS version

macOS
Sonoma 14.5

Winit version

0.30.5

@Jooonnnaass Jooonnnaass added B - bug Dang, that shouldn't have happened DS - macos labels Sep 18, 2024
@Jooonnnaass Jooonnnaass changed the title Titlebar icon and system menu information always shown on macOS Taskbar icon and system menu information always shown on macOS Sep 18, 2024
@madsmtm
Copy link
Member

madsmtm commented Sep 18, 2024

First everything was working fine but for some reason now

Could you give more details on this? Did it work with previous versions of tray_icon and/or winit?

@Jooonnnaass
Copy link
Author

tray-icon = "0.17.0"
winit = "0.30.5"

I never used other versions. Below is the complete code. But it seams quite strange that it suddenly behaves like that because no window is created until tray item action.

#![allow(unused)]

use std::{collections::HashMap, time::Instant};

use tray_icon::{
    menu::{
        accelerator::{Accelerator, Code, Modifiers},
        AboutMetadata, Menu, MenuEvent, MenuItem, PredefinedMenuItem,
    },
    TrayIconBuilder, TrayIconEvent,
};
use winit::{
    dpi::{LogicalPosition, LogicalSize, Position},
    event::{Event, KeyEvent, WindowEvent},
    event_loop::{self, ControlFlow, EventLoopBuilder},
    keyboard::{Key, KeyCode, SmolStr},
    monitor::{MonitorHandle, VideoModeHandle},
    platform::{
        macos::WindowAttributesExtMacOS, modifier_supplement::KeyEventExtModifierSupplement,
    },
    raw_window_handle::HasDisplayHandle,
    window::{Fullscreen, Window, WindowAttributes, WindowId, WindowLevel},
};

struct AppState {
    app_toggle: bool,
    keebplay_toggle: bool,
    capture_sequenz: bool,
    app_window_id: Option<WindowId>,
    overlay_window_id: Option<WindowId>,
    windows: HashMap<WindowId, Box<Window>>,
    key_sequenz: Vec<Key<SmolStr>>,
}

const SEQUENZ_THRESHOLD: i32 = 200;

fn main() {
    let path = concat!(env!("CARGO_MANIFEST_DIR"), "/assets/keyboard.png");

    let tray_menu = Menu::new();

    let mut app_toggle_item = MenuItem::with_id("app_toggle", "Open", true, None);
    let mut keebplay_toggle_item =
        MenuItem::with_id("keebplay_toggle", "Start Keebplay", true, None);
    let quit_item = MenuItem::with_id("quit", "Quit", true, None);

    let _ = tray_menu.append_items(&[
        &app_toggle_item,
        &PredefinedMenuItem::separator(),
        &keebplay_toggle_item,
        &PredefinedMenuItem::separator(),
        &quit_item,
    ]);

    // Since winit doesn't use gtk on Linux, and we need gtk for
    // the tray icon to show up, we need to spawn a thread
    // where we initialize gtk and create the tray_icon
    #[cfg(target_os = "linux")]
    std::thread::spawn(|| {
        use tray_icon::menu::Menu;

        let icon = load_icon(std::path::Path::new(path));

        gtk::init().unwrap();
        let _tray_icon = TrayIconBuilder::new()
            .with_menu(Box::new(tray_menu))
            .with_icon(icon)
            .build()
            .unwrap();

        gtk::main();
    });

    let event_loop = EventLoopBuilder::new().build().unwrap();

    #[cfg(not(target_os = "linux"))]
    let mut tray_icon = None;

    let menu_channel = MenuEvent::receiver();

    let mut app_state = AppState {
        app_toggle: false,
        keebplay_toggle: false,
        capture_sequenz: false,
        app_window_id: None,
        overlay_window_id: None,
        windows: HashMap::new(),
        key_sequenz: Vec::new(),
    };

    let last_keystroke = 0;

    event_loop.run(move |event, event_loop| {
        // We add delay of 16 ms (60fps) to event_loop to reduce cpu load.
        // This can be removed to allow ControlFlow::Poll to poll on each cpu cycle
        // Alternatively, you can set ControlFlow::Wait or use TrayIconEvent::set_event_handler,
        // see https://github.com/tauri-apps/tray-icon/issues/83#issuecomment-1697773065
        event_loop.set_control_flow(ControlFlow::WaitUntil(
            std::time::Instant::now() + std::time::Duration::from_millis(16),
        ));

        #[cfg(not(target_os = "linux"))]
        if let winit::event::Event::NewEvents(winit::event::StartCause::Init) = event {
            let icon = load_icon(std::path::Path::new(path));

            // We create the icon once the event loop is actually running
            // to prevent issues like https://github.com/tauri-apps/tray-icon/issues/90
            tray_icon = Some(
                TrayIconBuilder::new()
                    .with_menu(Box::new(tray_menu.clone()))
                    .with_tooltip("Keebplay")
                    .with_icon(icon)
                    .build()
                    .unwrap(),
            );
            // We have to request a redraw here to have the icon actually show up.
            // Winit only exposes a redraw method on the Window so we use core-foundation directly.
            #[cfg(target_os = "macos")]
            unsafe {
                use core_foundation::runloop::{CFRunLoopGetMain, CFRunLoopWakeUp};

                let rl = CFRunLoopGetMain();
                CFRunLoopWakeUp(rl);
            }
        }

        match event {
            Event::WindowEvent { event, .. } => match event {
                WindowEvent::KeyboardInput { event, .. } => {
                    let this_keystroke = Instant::now();

                    if !app_state.capture_sequenz {
                        app_state.key_sequenz.clear();
                        app_state.capture_sequenz = true;
                    }

                    app_state.key_sequenz.push(event.key_without_modifiers());
                }
                _ => (),
            },
            _ => (),
        };

        if let Ok(event) = menu_channel.try_recv() {
            if event.id == "app_toggle" {
                if app_state.app_toggle {
                    app_state.app_toggle = false;
                    app_toggle_item.set_text("Open");
                    app_state.windows.remove(&app_state.app_window_id.unwrap());
                } else {
                    app_state.app_toggle = true;
                    app_toggle_item.set_text("Stop");
                    let app_window_attributes = WindowAttributes::default()
                        .with_title("App")
                        .with_position(Position::Logical(LogicalPosition::new(0.0, 0.0)))
                        .with_min_inner_size(LogicalSize::new(640.0f32, 480.0f32));
                    let window = event_loop.create_window(app_window_attributes).unwrap();
                    app_state.app_window_id = Some(window.id());
                    app_state.windows.insert(window.id(), Box::new(window));
                }
            }
            if event.id == "keebplay_toggle" {
                if app_state.keebplay_toggle {
                    app_state.keebplay_toggle = false;
                    keebplay_toggle_item.set_text("Start Keebplay");
                    app_state
                        .windows
                        .remove(&app_state.overlay_window_id.unwrap());
                } else {
                    app_state.keebplay_toggle = true;
                    keebplay_toggle_item.set_text("Stop Keebplay");

                    let window_handle = &event_loop.primary_monitor().unwrap();

                    let size =
                        LogicalSize::new(window_handle.size().width, window_handle.size().height);

                    let overlay_window_attributes = WindowAttributes::default()
                        .with_title("Overlay")
                        .with_inner_size(size)
                        .with_window_level(WindowLevel::AlwaysOnTop)
                        .with_transparent(true);
                    let window = event_loop.create_window(overlay_window_attributes).unwrap();
                    app_state.overlay_window_id = Some(window.id());
                    app_state.windows.insert(window.id(), Box::new(window));
                }
            }
            if event.id == "quit" {
                event_loop.exit();
            }
        }
    });
}

fn load_icon(path: &std::path::Path) -> tray_icon::Icon {
    let (icon_rgba, icon_width, icon_height) = {
        let image = image::open(path)
            .expect("Failed to open icon path")
            .into_rgba8();
        let (width, height) = image.dimensions();
        let rgba = image.into_raw();
        (rgba, width, height)
    };
    tray_icon::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon")
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B - bug Dang, that shouldn't have happened DS - macos
Development

No branches or pull requests

2 participants