Displaying tray icon in macOS

Hi all,

Lately I got stuck on my project (the first one too!). So I am making this application which downloads background wallpaper from Unsplash once every hour, you can check out this fancy website I made if you are interested.

I have a frontend, which allows user configuration, and I use the web-view crate to display a window and accept user input.

So here's when the problem rises: the only usable macOS library I found is tray-item-rs, which only allows tray icon creation on main thread. But the main thread has already been taken away by the webview UI. I have tried reversing them, creating the tray in main thread and the webview in a separate one. This however segfaults when I close the webview window.

I can't create both of them in the main thread, because as far as I know both of them invoke NSApp::run() function, which basically locks the whole thread.

Here is my source code without tray. Any help will be appreciated! I have tried various methods, including but not limited to:

  • Webview in main thread and tray icon in another (results in ILLEGAL_HARDWARE_INSTRUCTION)
  • Tray icon in main thread and webview in another (results in segfault when the webview is closed)
  • Keep webview building process in main thread and start it in tray button callback using Arc<Mutex<..>> (could not get pass compilation, since the builder did not implement Send; also there is this one closure in webview which captures the background worker, so I can't make it into a independent function

Instead of calling .run().unwrap() on lines 124-125, call .build().unwrap() and store the result in a local view binding, then build your tray icon, then call view.run().unwrap():

fn main() {
    let config = Rc::new(RefCell::new(match Config::from_path(DEFAULT_CONFIG_PATH) {
        Ok(x) => x,
        Err(e) => panic!("Couldn't load or create config: {}", e)
    }));
    let worker = Worker::new();
    let html = include_str!("index.html");
    let view = web_view::builder()
        .title("Automagic Wallpaper Changer")
        .content(Content::Html(html))
        .size(350, 620)
        .resizable(false)
        .debug(true)
        .user_data(config.clone())
        .invoke_handler(|web_view, arg| {
            // ...
        })
        .build()
        .unwrap();

    // TODO: build tray icon here

    view.run().unwrap()
}