summary history branches tags files
examples/example.rs
extern crate fruitbasket;
use fruitbasket::ActivationPolicy;
use fruitbasket::Trampoline;
use fruitbasket::FruitApp;
use fruitbasket::InstallDir;
use fruitbasket::RunPeriod;
use fruitbasket::FruitError;
use std::time::Duration;
use std::path::PathBuf;

#[macro_use]
extern crate log;

fn main() {
    let _ = fruitbasket::create_logger(".fruitbasket.log", fruitbasket::LogDir::Home, 5, 2).unwrap();

    // Find the icon file from the Cargo project dir
    let icon = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("examples").join("icon.png");

    // Re-launch self in an app bundle if not already running from one.
    info!("Executable must run from App bundle.  Let's try:");
    let mut app = match Trampoline::new("fruitbasket", "fruitbasket", "com.trevorbentley.fruitbasket")
        .version("2.1.3")
        .icon("fruitbasket.icns")
        .plist_key("CFBundleSpokenName","\"fruit basket\"")
        .plist_keys(&vec![
            ("LSMinimumSystemVersion", "10.12.0"),
            ("LSBackgroundOnly", "1"),
        ])
        .resource(icon.to_str().unwrap())
        .build(InstallDir::Temp) {
            Err(FruitError::UnsupportedPlatform(_)) => {
                info!("This is not a Mac.  App bundling is not supported.");
                info!("It is still safe to use FruitApp::new(), though the dummy app will do nothing.");
                FruitApp::new()
            },
            Err(FruitError::IOError(e)) => {
                info!("IO error! {}", e);
                std::process::exit(1);
            },
            Err(FruitError::GeneralError(e)) => {
                info!("General error! {}", e);
                std::process::exit(1);
            },
            Ok(app) => app,
        };

    // App is guaranteed to be running in a bundle now!

    // Make it a regular app in the dock.
    // Note: Because 'LSBackgroundOnly' is set to true in the Info.plist, the
    // app will launch backgrounded and will not take focus.  If we only did
    // that, the app would stay in 'Prohibited' mode and would not create a dock
    // icon.  By overriding the activation policy now, it will stay background
    // but create the Dock and menu bar entries.  This basically implements a
    // "pop-under" behavior.
    app.set_activation_policy(ActivationPolicy::Regular);

    // Give it a bit of time for the launching process to quit, to prove that
    // the bundled process is not a dependent child of the un-bundled process.
    info!("Spawned process started.  Sleeping for a bit...");
    let _ = app.run(RunPeriod::Time(Duration::from_secs(1)));

    // Demonstrate stopping an infinite run loop from another thread.
    let stopper = app.stopper();
    let _ = std::thread::spawn(move || {
        std::thread::sleep(Duration::from_secs(4));
        info!("Stopping run loop.");
        fruitbasket::FruitApp::stop(&stopper);
    });

    // Run 'forever', until the other thread interrupts.
    info!("Spawned process running!");
    let _ = app.run(RunPeriod::Forever);
    info!("Run loop stopped from other thread.");

    // Find the icon we stored in the bundle
    let icon = fruitbasket::FruitApp::bundled_resource_path("icon", "png");
    info!("Bundled icon: {}", icon.unwrap_or("MISSING!".to_string()));

    // Cleanly terminate
    fruitbasket::FruitApp::terminate(0);
    info!("This will not print.");
}