Use fruitbasket to trampoline example into an app bundle
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"]
## Run the example
-`$ cargo test && cargo run --example example_launcher`
+`$ cargo test && cargo run --example example`
## Cargo Crate
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
// 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;
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")));
// 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);
}
-#!/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!"
-
-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");
-}
//! 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
//!