summary history branches tags files
commit:af44a29e24300fd1b78abbf162d36d8a0a6585f6
author:Trevor Bentley
committer:Trevor Bentley
date:Sat Jul 29 23:07:52 2017 +0200
parents:6233cb4575014f374c2f2549b2438f9e32f9d809
Use fruitbasket to trampoline example into an app bundle
diff --git a/Cargo.toml b/Cargo.toml
line changes: +4/-0
index bac353c..674b67c
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -30,6 +30,10 @@ cocoa = "0.9.2"
 objc-foundation = "0.1.1"
 objc_id = "0.1"
 
+[target."cfg(target_os = \"macos\")".dependencies.fruitbasket]
+version = "0.3"
+features = ["logging"]
+
 [target."cfg(target_os = \"macos\")".dependencies.objc]
 version = "0.2.2"
 features = ["exception"]

diff --git a/README.md b/README.md
line changes: +2/-2
index bd45fa5..a5cbb0c
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ Source for following screencast in `examples/example.rs`
 
 ## Run the example
 
-`$ cargo test && cargo run --example example_launcher`
+`$ cargo test && cargo run --example example`
 
 ## Cargo Crate
 
@@ -32,7 +32,7 @@ Note that access to the Control Strip is forbidden by Apple's guidelines.  Rubra
 
 To communicate with the Touch Bar service, apps using Rubrail *must* be executed from an app bundle (.app).  Running the executable directly will not crash, but the icon will not be registered with the Touch Bar service, so your Touch Bar UI will be unavailable.
 
-The included example comes with a bundling script (examples/example.sh) and a launcher (examples/example_launcher.rs) to move itself into an app bundle and execute.
+The included example uses the [fruitbasket](https://github.com/mrmekon/fruitbasket) crate to automatically re-launch itself as an OS X app bundle.
 
 
 ### Limitations

diff --git a/examples/example.rs b/examples/example.rs
line changes: +19/-11
index 24c4a2b..1a0e9e4
--- a/examples/example.rs
+++ b/examples/example.rs
@@ -6,16 +6,16 @@
 // Usage notes:
 //
 // To access the touchbar, Rubrail *must* execute inside an OS X app bundle.
-// Since Cargo doesn't do that itself, this example is packaged with a second
-// wrapper example (example_launcher), and a bundling script (example.sh).
-// They can all be used together to setup and run the example from a bundle.
+// Since Cargo doesn't do that itself, this example uses the Trampoline feature
+// of the fruitbasket crate to relaunch itself in an app bundle.
 //
 // Simply run:
 //
-// $ cargo test && cargo run --example example_launcher
+// $ cargo test && cargo run --example example
 //
 //
 extern crate rubrail;
+extern crate fruitbasket;
 
 use rubrail::Touchbar;
 use rubrail::TTouchbar;
@@ -153,10 +153,19 @@ fn populate(bar_rc: Rc<RefCell<Touchbar>>, count: u32) {
 
 fn main() {
     // Write log to home directory
-    rubrail::app::create_logger(".rubrail.log");
-
-    // Initialize OS X application.  A real app should probably not use this.
-    rubrail::app::init_app();
+    fruitbasket::create_logger(".rubrail.log", fruitbasket::LogDir::Home, 5, 2).unwrap();
+
+    // Initialize OS X application.
+    let icon = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
+        .join("examples").join("icon.png");
+    let mut nsapp = fruitbasket::Trampoline::new(
+        "rubrail_example", "rubrail_example", "com.trevorbentley.rubrail_example")
+        .icon("icon.png")
+        .version(env!("CARGO_PKG_VERSION"))
+        .plist_key("LSBackgroundOnly", "1")
+        .resource(icon.to_str().unwrap())
+        .build(fruitbasket::InstallDir::Custom("target/".to_string())).unwrap();
+    nsapp.set_activation_policy(fruitbasket::ActivationPolicy::Prohibited);
 
     // Initialize the touchbar
     let bar_rc = Rc::new(RefCell::new(Touchbar::alloc("bar")));
@@ -164,7 +173,6 @@ fn main() {
     // Populate the touchbar with UI elements
     populate(bar_rc.clone(), 1);
 
-    // Enter OS X application loop.  A real application should probably implement
-    // this itself.
-    rubrail::app::run_forever();
+    // Enter OS X application loop.
+    nsapp.run(fruitbasket::RunPeriod::Forever);
 }

diff --git a/examples/example.sh b/examples/example.sh
line changes: +0/-34
index 9188b47..0000000
--- a/examples/example.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/bash
-
-DST="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-APPDIR="RubrailExample.app"
-
-
-echo "Building OS X app..."
-
-rm -rf "$DST/$APPDIR"
-mkdir "$DST/$APPDIR/"
-mkdir "$DST/$APPDIR/Contents/"
-mkdir "$DST/$APPDIR/Contents/Resources/"
-mkdir "$DST/$APPDIR/Contents/MacOS/"
-
-cp -a "$DST/example" "$DST/$APPDIR/Contents/MacOS/"
-cp -a "$DST/icon.png" "$DST/$APPDIR/Contents/Resources/"
-
-cat > "$DST/$APPDIR/Contents/Info.plist" << EOF
-{
-   CFBundleName = rubrail;
-   CFBundleDisplayName = RubrailExample;
-   CFBundleIdentifier = "com.trevorbentley.rubrail";
-   CFBundleExecutable = example;
-   CFBundleIconFile = "rubrail.icns";
-
-   CFBundleVersion = "0.0.2";
-   CFBundleInfoDictionaryVersion = "6.0";
-   CFBundlePackageType = APPL;
-   CFBundleSignature = xxxx;
-
-   LSMinimumSystemVersion = "10.10.0";
-}
-EOF
-echo "Done!"

diff --git a/examples/example_launcher.rs b/examples/example_launcher.rs
line changes: +0/-31
index d9d160e..0000000
--- a/examples/example_launcher.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-
-fn main() {
-    let exe = std::env::current_exe().unwrap();
-    let mut exe_dir = exe.clone();
-    exe_dir.pop();
-    let mut resource_dir = exe_dir.clone();
-    resource_dir.pop();
-    resource_dir.pop();
-    resource_dir.pop();
-    resource_dir.push("examples");
-    let mut example_app = exe_dir.clone();
-    example_app.push("RubrailExample.app");
-    let mut icon_src = resource_dir.clone();
-    icon_src.push("icon.png");
-    let mut script_src = resource_dir.clone();
-    script_src.push("example.sh");
-    let mut icon_dst = exe_dir.clone();
-    icon_dst.push("icon.png");
-    let mut script_dst = exe_dir.clone();
-    script_dst.push("example.sh");
-    let script_exe = script_dst.clone();
-    std::fs::copy(icon_src, icon_dst).unwrap();
-    std::fs::copy(script_src, script_dst).unwrap();
-    let _ = std::process::Command::new(script_exe)
-        .output()
-        .expect("Failed to run bundling script");
-    let _ = std::process::Command::new("open")
-        .arg(example_app)
-        .output()
-        .expect("Failed to launch app bundle");
-}

diff --git a/src/lib.rs b/src/lib.rs
line changes: +4/-4
index 953f8d1..edcc115
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -28,11 +28,11 @@
 //! be registered with the system and will not display on the Control Strip,
 //! making it inaccessible to the user.
 //!
-//! The examples are bundled with a script to generate a minimal valid app
-//! bundle, and a wrapper example to move the real example into a bundle and
-//! execute it.  You can execute the examples correctly with this comand:
+//! The included example uses [fruitbasket](https://github.com/mrmekon/fruitbasket)
+//! to automatically bundle itself into an OS X app at runtime.  You can run the
+//! example with:
 //!
-//! `$ cargo test && cargo run --example example_launcher`
+//! `$ cargo test && cargo run --example example`
 //!
 //! # Memory Management
 //!