Rust API
Everything an app needs comes from the sabine crate. It re-exports the bridge, platform and runtime types it uses, so apps depend on sabine alone, plus serde and specta for typed commands.
Adding the crate
Section titled “Adding the crate”The crates aren’t published on crates.io. Depend on a release tag of the repository:
[dependencies]sabine = { git = "https://github.com/Lantharos/Sabine", tag = "v0.68" }serde = { version = "1", features = ["derive"] }serde_json = "1"specta = { version = "=2.0.0-rc.27", features = ["derive"] }Projects created with sabine new already have these. To browse the full API, with every type and method, build the documentation locally from your app’s project:
cargo doc -p sabine --opensabine::prelude brings in the types most apps use:
use sabine::prelude::*;// AppChrome, AppEnvironment, BridgeCommand, BridgeError, BridgeResponse, BridgeResult,// SabineColor, SabineError, SabineLifecyclePolicy, SabineProcess, SabineProcessHandle,// SabineResult, SabineWindow, SabineWindowChrome, TrayIcon, WindowBackgroundEffect,// WindowRegion, WindowRegionRectEntry points
Section titled “Entry points”impl SabineWindow { pub fn main(build: impl FnOnce(Self) -> SabineResult<Self>) -> !; pub fn main_with_process( build: impl FnOnce(Self) -> SabineResult<Self>, launched: impl FnOnce(&SabineProcess), ) -> !; pub fn main_with_process_mut( build: impl FnOnce(Self) -> SabineResult<Self>, launched: impl FnOnce(&mut SabineProcess), ) -> !; pub fn launch(self) -> SabineResult<SabineProcess>;}
pub fn dispatch_host_mode_from_args(args: &[String]) -> bool;SabineWindow::main is the recommended entry point. It runs Sabine’s internal modes when the executable was started as a window host, setup window or notice, loads Sabine.toml, hands a window configured from it to build, launches it, waits, and exits with the window’s exit status. When build returns an error, or the launch fails, it shows a native notice and exits with status 1. A launch handed to an already running instance exits with status 0.
#![cfg_attr(target_os = "windows", windows_subsystem = "windows")]
use sabine::prelude::*;use serde::{Deserialize, Serialize};use specta::Type;
#[derive(Deserialize, Type)]struct NewNote { title: String,}
#[derive(Serialize, Type)]struct Note { id: String, title: String,}
fn main() { SabineWindow::main(|window| { Ok(window .app() .glass() .app_chrome(AppChrome::default()) .min_size(720, 480) .bridge_typed("notes.create", create_note)) });}
fn create_note(note: NewNote) -> Result<Note, BridgeError> { let title = note.title.trim(); if title.is_empty() { return Err(BridgeError::new("A note needs a title")); } Ok(Note { id: format!("note-{}", title.len()), title: title.to_string(), })}main_with_process and main_with_process_mut also hand you the launched SabineProcess before waiting, for example to keep its event emitter in app state or to open more windows:
use sabine::prelude::*;
fn main() { SabineWindow::main_with_process_mut( |window| Ok(window.app().title("Notes")), |process| { let inspector = SabineWindow::for_current_app() .map(|window| window.title("Inspector").size(420, 640)); if let Ok(window) = inspector { let _ = process.open_window(window); } }, );}launch starts the app and returns its SabineProcess without waiting, for apps that run their own loop. When a Windows setup program runs the executable, launch prepares Sabine and exits instead. Call process.wait() when you’re done; on macOS, call it on the main thread, or run an AppKit loop there, since the tray and global shortcuts live on the main thread.
A custom main must let Sabine run its internal modes before parsing arguments, starting a logger or doing anything else, and return when it did:
fn main() { let args = std::env::args().collect::<Vec<_>>(); if sabine::dispatch_host_mode_from_args(&args) { return; } // Parse arguments and set up the app.}Building a window from the manifest
Section titled “Building a window from the manifest”impl SabineWindow { pub fn new() -> Self; pub fn with_manifest(self, path: impl AsRef<Path>) -> SabineResult<Self>; pub fn for_current_app() -> SabineResult<Self>;}main finds Sabine.toml through SABINE_MANIFEST_PATH, next to a bundled executable, in the working directory, or in the Cargo package folder under cargo run. with_manifest applies another one explicitly: identity, version, update source, URL schemes and document types, the production web entry or URL, allowed origins, local file access, the loading screen and, on Linux, the sandbox and shared_runtime. Settings you make in Rust afterwards take precedence.
for_current_app builds a window for another open_window call, with the running app’s identity and web entry, and its development URL during sabine dev.
Recipes
Section titled “Recipes”Recipes set a window up for its role. Later builder calls refine them.
| Recipe | What it sets |
|---|---|
.app() |
System chrome, opaque, the browser-tab lifecycle: the page freezes after five minutes out of sight |
.palette() |
Frameless, glass, hidden when it loses focus, out of the taskbar, the hidden-window lifecycle |
.tray_app() |
Starts hidden and inactive, out of the taskbar, the hidden-window lifecycle. Pair it with .tray_icon(...) and single-instance behavior |
.background() |
Launches without its window: no window host or browser runs until the app is activated or SabineProcessHandle::present is called. Closing the window ends both while the app keeps running |
See Creating windows.
Window builder
Section titled “Window builder”Every builder method takes self and returns Self, so calls chain. A window that isn’t configured otherwise is 900 by 640 logical pixels, at least 420 by 280, titled Sabine, opaque, with system chrome and a #111113 background.
Identity and content
Section titled “Identity and content”| Method | Does |
|---|---|
app_id(impl Into<String>) |
The app id: lowercase letters, digits, dots and hyphens. Required; usually from Sabine.toml |
app_version(impl Into<String>) |
The app’s version |
title(impl Into<String>) |
The window title; must not be empty |
entry(impl Into<String>) |
A local HTML file, served from its folder at sabine://app/ |
url(impl Into<String>) |
A production URL; its exact origin may use the bridge. Exclusive with entry |
content_suffix(impl AsRef<str>) |
Appends a query string or fragment to the page the window opens: the entry, the URL, or the development server’s page in a development run |
allowed_origin(impl Into<String>) |
Lets another origin’s pages use the bridge |
security(ContentSecurity) |
Replaces the allowed origins wholesale |
local_files(bool) |
Lets pages load any readable file through sabine://file/<absolute path> |
runtime(RuntimeConfig) |
Where the app looks for a Chromium runtime |
shared_runtime(bool) |
Linux only. Whether the app’s pages may run in the shared Chromium; true by default |
vaapi_hardware_decode(bool) |
Linux only. VA-API video decoding for WebCodecs and media; off by default |
debug(u16) |
Opens Chromium’s remote debugging on this port, also in production |
Size and placement
Section titled “Size and placement”| Method | Does |
|---|---|
size(u32, u32) |
The initial size in logical pixels |
min_size(u32, u32) |
The minimum size |
fixed_size(u32, u32) |
Sets size and minimum size, and makes the window not resizable |
maximized(bool) |
Opens maximized |
remember_size() |
Opens at the size and maximized state the window closed with; size and maximized apply the first time |
resizable(bool) |
Whether people can resize the window |
Visibility and behavior
Section titled “Visibility and behavior”| Method | Does |
|---|---|
visible(bool) |
Whether the window starts shown. false also applies the hidden-window lifecycle defaults |
hidden() |
visible(false) and active(false) |
active(bool) |
Whether the window takes focus when shown |
hide_on_blur(bool) |
Hides the window when it loses focus, with the hidden-window lifecycle defaults |
hide_on_close(bool) |
Hides the window instead of closing it |
skip_taskbar(bool) |
Off the Windows taskbar, out of the macOS Dock, and out of the taskbar on Wayland compositors with kestrel_window_v1 |
always_on_top(bool) |
Above other windows on Windows, macOS, and Wayland compositors with kestrel_window_v1 |
Appearance and chrome
Section titled “Appearance and chrome”| Method | Does |
|---|---|
transparent(bool) |
A transparent window. false also removes the background effect and blur region |
background_color(SabineColor) |
The color before the first frame and behind Sabine’s own surfaces |
splash(bool) |
Shows Sabine’s loading screen when the page takes longer than 1.5 seconds to appear |
splash_after(Duration) |
The same, after another delay |
glass() |
background_effect(WindowBackgroundEffect::Glass) |
background_effect(WindowBackgroundEffect) |
A desktop material behind the window; any effect makes the window transparent |
app_chrome(AppChrome) |
An app-drawn titlebar with window controls, and glass sidebar regions |
system_chrome() |
The desktop’s own decorations, the default |
frameless() |
No system decorations; the page draws everything |
chrome(SabineWindowChrome) |
Picks a chrome style directly, including Sabine, a titlebar Sabine draws itself |
See Window chrome and Glass and effects.
Regions
Section titled “Regions”| Method | Does |
|---|---|
regions(WindowRegions) |
Sets the blur, opaque and input regions together |
blur_region(WindowRegion) |
Where the background effect shows |
opaque_region(WindowRegion) |
What the page always covers |
input_region(WindowRegion) |
Where the window takes pointer input |
drag_region(WindowRegionRect) |
An area that moves the window |
drag_exclusion_region(WindowRegionRect) |
An area inside a drag region that doesn’t |
titlebar_drag_region(i32) |
A drag strip of this height across the top |
control_region(SabineWindowControlAction, WindowRegionRect) |
An area that minimizes, maximizes or closes the window; a negative x counts from the right edge |
Pages can also mark draggable areas with -webkit-app-region: drag, and change regions while the window runs.
Lifecycle
Section titled “Lifecycle”| Method | Does |
|---|---|
lifecycle_policy(SabineLifecyclePolicy) |
Replaces the whole lifecycle policy |
active_frame_rate(u32) |
The frame rate while active; 0 follows the display |
background_frame_rate(u32) |
The frame rate while suspended; at least 1 |
suspend_on_occluded(bool), suspend_on_blur(bool) |
When the page drops to its background frame rate: out of sight, including minimized, or without focus |
freeze_after(Duration) |
Freezes the page after it has been out of sight this long |
disable_freezing() |
Never freezes the page |
retain_hidden_frame(bool) |
Keeps the last frame while hidden, for a quick return |
See Lifecycle.
Desktop integration
Section titled “Desktop integration”| Method | Does |
|---|---|
tray_icon(TrayIcon) |
The app’s tray icon and menu |
autostart(AutostartEntry) |
Starts the app at login; its id must be the app id |
global_shortcut(GlobalShortcutRegistration) |
A system-wide shortcut; can be called more than once |
native_messaging_host(NativeMessagingHost) |
A browser extension host |
single_instance(SingleInstancePolicy) |
What a second launch does |
single_instance_id(impl Into<String>) |
Names the instance, instead of the app id |
Listeners
Section titled “Listeners”pub fn on_launched(self, listener: impl Fn(SabineProcessHandle) + Send + Sync + 'static) -> Self;pub fn on_visibility_changed(self, listener: impl Fn(WindowVisibility) + Send + Sync + 'static) -> Self;pub fn on_appearance_changed(self, listener: impl Fn(WindowId, Appearance) + Send + Sync + 'static) -> Self;pub fn on_desktop_event(self, listener: impl Fn(&SabineProcessHandle, &PlatformEvent) + Send + Sync + 'static) -> Self;on_launched hands app code that only builds the window a handle to the process. on_desktop_event hears every tray click, global shortcut, later launch and link before the pages do, whether or not a window is open, so a background app can open its window from Rust. on_visibility_changed reports each change of visibility or suspension, starting with the state the window opens in and ending with a hidden report when it closes. on_appearance_changed reports the desktop’s light or dark preference and accent color, starting with the appearance the window opens with.
pub struct WindowVisibility { pub window: WindowId, pub visible: bool, pub suspended: bool,}Bridge commands
Section titled “Bridge commands”pub fn bridge_typed<Req, Res, F>(self, name: impl Into<String>, handler: F) -> Selfwhere Req: serde::de::DeserializeOwned + specta::Type, Res: serde::Serialize + specta::Type, F: Fn(Req) -> Result<Res, BridgeError> + Send + Sync + 'static;
pub fn bridge_typed_async<Req, Res, F, Fut>(self, name: impl Into<String>, handler: F) -> Selfwhere F: Fn(Req) -> Fut + Send + Sync + 'static, Fut: Future<Output = Result<Res, BridgeError>> + Send + 'static;
pub fn bridge_handler<F>(self, name: impl Into<String>, handler: F) -> Selfwhere F: Fn(BridgeCommand) -> BridgeResult + Send + Sync + 'static;
pub fn bridge_handler_async<F, Fut>(self, name: impl Into<String>, handler: F) -> Selfwhere F: Fn(BridgeCommand) -> Fut + Send + Sync + 'static, Fut: Future<Output = BridgeResult> + Send + 'static;
pub fn bridge_descriptor_handler<F>(self, descriptor: BridgeCommandDescriptor, handler: F) -> Self;pub fn bridge_descriptor_handler_async<F, Fut>(self, descriptor: BridgeCommandDescriptor, handler: F) -> Self;
pub fn bridge_event<T: specta::Type>(self, event: &BridgeEvent<T>) -> Self;pub fn bridge_type<T: specta::Type>(self) -> Self;Typed commands deserialize their parameters into Req and answer with Res as JSON, and they appear in the app’s generated TypeScript bindings, as do events declared with bridge_event and extra types added with bridge_type. Raw handlers receive the whole BridgeCommand, including binary bodies. Synchronous handlers run on four worker threads per window and shouldn’t wait on slow work; async handlers are awaited on sabine::async_runtime(). Descriptor handlers let extra origins call one command. Register a command for one desktop under #[cfg(target_os = "...")].
See Commands, Typed bindings and Events.
Window types
Section titled “Window types”AppChrome
Section titled “AppChrome”pub struct AppChrome { pub titlebar: i32, // 38 pub sidebar: i32, // 260; 0 for no sidebar pub radius: i32, // 14 pub control_width: i32, // 46}
impl AppChrome { pub fn new(titlebar: i32, sidebar: i32) -> Self;}app_chrome gives the window a drag strip as tall as titlebar. On Linux and Windows the window turns frameless and gets minimize, maximize and close regions, each control_width wide, at the titlebar’s right end, for the page to draw buttons over. On macOS the window keeps its traffic lights over a transparent titlebar, and the page extends under it. With a sidebar, the window also gets the blur, opaque and input regions of a glass sidebar layout, rounded by radius except on macOS, where the system rounds the window.
Chrome, colors and controls
Section titled “Chrome, colors and controls”pub enum SabineWindowChrome { System, Sabine, Frameless }
pub enum SabineWindowControlAction { Minimize, Maximize, Close }
pub struct SabineWindowControlRegion { pub action: SabineWindowControlAction, pub rect: WindowRegionRect,}
impl SabineColor { pub const fn rgb8(r: u8, g: u8, b: u8) -> Self; pub const fn rgba8(r: u8, g: u8, b: u8, a: u8) -> Self; pub fn opacity(self, alpha: f32) -> Self;}SabineColor is an sRGB color with the same 8-bit channels as CSS.
SabineLifecyclePolicy
Section titled “SabineLifecyclePolicy”pub struct SabineLifecyclePolicy { pub active_frame_rate: u32, // 0: follow the display pub background_frame_rate: u32, // 5 pub suspend_on_occluded: bool, // true pub suspend_on_blur: bool, // false pub freeze_after: Option<Duration>, // None pub retain_hidden_frame: bool, // false}
impl SabineLifecyclePolicy { pub fn browser_tab() -> Self; // default, freezing after 5 minutes pub fn hidden_window() -> Self; // 1 fps in the background, suspend on blur, // freeze after 1 minute, keep the hidden frame}The running app
Section titled “The running app”SabineProcess
Section titled “SabineProcess”impl SabineProcess { pub fn id(&self) -> Option<WindowId>; pub fn handle(&self) -> SabineProcessHandle; pub fn open_window(&mut self, window: SabineWindow) -> SabineResult<WindowId>; pub fn close_window(&mut self, window: WindowId) -> bool; pub fn wait(self) -> std::io::Result<ExitStatus>;
pub fn bridge_event_emitter(&self) -> BridgeEventEmitter; pub fn take_open_urls(&self) -> Vec<String>; pub fn tray(&self) -> Option<TrayHandle>; pub fn notify(&self, notification: &Notification) -> bool; pub fn guest_control(&self, control: &GuestHostControl) -> bool;
pub fn show(&self) -> bool; pub fn hide(&self) -> bool; pub fn set_visible(&self, visible: bool) -> bool; pub fn focus_window(&self) -> bool;
pub fn begin_activity(&self, name: impl Into<String>) -> SabineActivityLease; pub fn begin_activity_with(&self, options: ActivityOptions) -> SabineActivityLease; pub fn activities(&self) -> Vec<ActivityRecord>;
pub fn metrics(&self) -> SabineLaunchMetricsSnapshot;}idis the first window’s id while it is open.WindowIdis au32, the id of the window host’s process.open_windowopens another window with the app’s id and bridge handlers; handlers registered on the window you pass are ignored. It waits up to 20 seconds for the first window to be ready, since the others join its browser.close_windowreturnsfalsefor an unknown id.waitblocks until every window has closed, then returns the first window’s exit status. A background app keeps waiting for its next activation, untilSabineProcessHandle::quitends it.take_open_urlsdrains the queue of URLs and documents the app was asked to open, by its arguments, a second launch, or the system.notifyshows a desktop notification from the first window; its pages hear clicks asnotification.clickevents.- Activities keep every window’s page running while it is out of sight, until the lease is ended or dropped.
ActivityOptions::new(name).keep_running(false)records an activity without keeping pages awake. - Dropping the
SabineProcesscloses its windows.
Methods that return bool report whether at least one window took the message.
SabineProcessHandle
Section titled “SabineProcessHandle”#[derive(Clone)]pub struct SabineProcessHandle { /* … */ }
impl SabineProcessHandle { pub fn open_window(&self, window: SabineWindow) -> SabineResult<WindowId>; pub fn present(&self, activation_token: Option<String>) -> bool; pub fn quit(&self) -> bool; pub fn set_autostart(&self, enabled: bool) -> Result<(), String>;}A handle can be sent to other threads and kept in app state while wait runs. present shows and focuses the app’s window, opening it first while a background app runs without one. Pass the activation token from a notification click or single-instance activation on Wayland, so the window may take focus. open_window from a handle waits in line until the first window is ready, without blocking the wait loop. quit closes every window and ends the app, also a background app or one whose window hides on close, and wait then returns a success status. set_autostart turns the app’s autostart entry on or off; see Starting at login.
BridgeEventEmitter
Section titled “BridgeEventEmitter”impl BridgeEventEmitter { pub fn emit(&self, name: impl Into<String>, payload: serde_json::Value) -> bool; pub fn emit_to(&self, window: WindowId, name: impl Into<String>, payload: serde_json::Value) -> bool; pub fn send<T: Serialize>(&self, event: &BridgeEvent<T>, payload: &T) -> bool; pub fn send_bytes(&self, event: &BridgeEvent<Bytes>, bytes: &[u8]) -> bool; pub fn emit_bytes(&self, name: impl Into<String>, bytes: &[u8]) -> bool; pub fn emit_bytes_to(&self, window: WindowId, name: impl Into<String>, bytes: &[u8]) -> bool;
pub fn set_regions(&self, regions: &WindowRegions) -> bool; pub fn set_regions_of(&self, window: WindowId, regions: &WindowRegions) -> bool; pub fn set_square_corners(&self, square: bool) -> bool;
pub fn notify(&self, window: WindowId, notification: &Notification) -> bool; pub fn print_files(&self, window: WindowId, paths: &[PathBuf], title: Option<&str>) -> bool; pub fn guest_control(&self, window: WindowId, control: &GuestHostControl) -> bool;
pub fn show(&self) -> bool; pub fn hide(&self) -> bool; pub fn set_visible(&self, visible: bool) -> bool; pub fn focus_window(&self) -> bool; pub fn focus_window_with_activation_token(&self, token: Option<&str>) -> bool;}The emitter is Clone, Send and Sync. Events go to every window unless sent with a _to variant. Sending waits while a window’s pages haven’t taken earlier events, so producers run at the pace pages keep up with. Pages receive bytes as a Uint8Array.
TrayHandle
Section titled “TrayHandle”impl TrayHandle { pub fn set_icon(&self, path: Option<PathBuf>, template: bool); pub fn set_tooltip(&self, tooltip: Option<String>); pub fn set_menu(&self, items: Vec<TrayMenuItem>);}Returned by SabineProcess::tray() when the window has a tray icon. See Tray.
Launch metrics
Section titled “Launch metrics”pub struct SabineLaunchMetricsSnapshot { pub label: String, pub elapsed: Duration, pub stages: Vec<SabineLaunchMetric>,}
pub struct SabineLaunchMetric { pub stage: String, pub elapsed: Duration,}See Architecture for the stages.
Bridge types
Section titled “Bridge types”pub struct BridgeCommand { pub name: String, pub params: serde_json::Value, pub origin: Option<String>, pub body: Option<Vec<u8>>, pub window: Option<u32>,}
pub struct BridgeResponse { pub result: serde_json::Value, pub body: Option<Vec<u8>>,}
impl BridgeResponse { pub fn json(result: serde_json::Value) -> Self; pub fn bytes(body: impl Into<Vec<u8>>) -> Self;}
pub struct BridgeError { pub message: String,}
impl BridgeError { pub fn new(message: impl Into<String>) -> Self;}
pub type BridgeResult = Result<BridgeResponse, BridgeError>;window names the window whose page made the call, for answering it alone with emit_to. BridgeError implements Display and std::error::Error; its message is what the page sees when the call fails.
impl BridgeCommandDescriptor { pub fn new(name: impl Into<String>) -> Self; pub fn allowed_origin(self, origin: impl Into<String>) -> Self;}
impl<T> BridgeEvent<T> { pub const fn new(name: &'static str) -> Self; pub const fn name(&self) -> &'static str;}
pub struct Bytes;
pub struct ContentSecurity { pub remote_content: bool, pub allowed_origins: Vec<String>,}Declare events as constants and send them through the emitter:
use sabine::{BridgeEvent, Bytes};
const NOTE_SAVED: BridgeEvent<String> = BridgeEvent::new("notes.saved");const TERMINAL_OUTPUT: BridgeEvent<Bytes> = BridgeEvent::new("terminal.output");Guests
Section titled “Guests”GuestHostControl drives guests from Rust: SabineProcess::guest_control drives the first window’s guests, and the emitter’s guest_control those of the window it names. Controls take effect without an answer; pages observe the results through guest events.
pub enum GuestHostControl { Create(GuestCreateOptions), Destroy { id: String }, Navigate { id: String, url: String }, SetBounds { id: String, bounds: GuestBounds }, SetVisible { id: String, visible: bool }, SetCovered { covered: bool }, Focus { id: String }, Reload { id: String, ignore_cache: bool }, GoBack { id: String }, GoForward { id: String }, SetZoom { id: String, factor: f64 }, ExecuteJavaScript { id: String, code: String }, DownloadAction { download_id: String, action: GuestDownloadAction, save_path: Option<String>, show_dialog: bool, },}
pub enum GuestDownloadAction { Accept, Cancel, Pause, Resume }pub enum GuestPopupPolicy { Deny, NavigateSame, OpenGuest }GuestCreateOptions holds id, url, html, bounds, partition, allow_bridge (false), intercepted_shortcuts, intercept_horizontal_wheel, visible (true), popup_policy (Deny), allow_downloads (true) and background_color, and implements Default. GuestBounds::new(x, y, width, height) takes CSS pixels relative to the window. See Guests.
Async runtime
Section titled “Async runtime”pub fn async_runtime() -> &'static tokio::runtime::Handle;The process’s Tokio runtime, with two worker threads, started on first use. Sabine awaits async bridge handlers and runs its own D-Bus work on it, and apps can spawn their background tasks there too. Synchronous code waits on it with async_runtime().block_on(...); async code never does.
Files and environment
Section titled “Files and environment”AppEnvironment
Section titled “AppEnvironment”pub enum AppEnvironment { Development, Production }
impl AppEnvironment { pub fn current() -> Self; pub fn production_build() -> bool; pub fn of(app_id: &str) -> Self; pub fn as_str(self) -> &'static str; pub fn app_id(self, id: &str) -> String; pub fn app_data_dir(self, app_id: &str) -> PathBuf; pub fn data_dir(self, production: impl AsRef<Path>) -> PathBuf;}currentreadsSABINE_ENV, and treats a setSABINE_DEV_URLas development. A build made for production, withSABINE_ENV=productionwhile it compiles assabine bundledoes, is alwaysProduction.production_buildsays whether this binary was built for production. Such builds ignore the variables that point a development run at its project.app_idappends.devin development.app_data_diris the folder an app keeps its files in: the app id below%APPDATA%,~/Library/Application Supportor$XDG_DATA_HOME, with the.devid in development. It is the folder Sabine’s app sandbox lets the app write.data_dirkeeps an existing production location and puts development data in adevelopmentfolder below it. Neither creates folders.
use sabine::AppEnvironment;
let notes = AppEnvironment::current() .app_data_dir("com.example.notes") .join("notes.json");resource_path
Section titled “resource_path”pub fn resource_path(name: &str) -> Option<PathBuf>;Finds a file or folder listed under [resources] in Sabine.toml: in the source project during sabine dev and cargo run, and in the bundle once the app is packaged. It returns None when the name isn’t listed or the path doesn’t exist.
[resources]server = "../build/server"let server = sabine::resource_path("server").expect("the server ships with the app");Runtime and environment
Section titled “Runtime and environment”pub struct RuntimeConfig { pub mode: RuntimeMode, // SharedPreferred pub index_url: Option<String>, // the CEF build index to download from pub allow_user_install: bool, // true pub allow_bundled: bool, // true pub bundled_dir: Option<PathBuf>,}
pub enum RuntimeMode { SystemRequired, // only a system-wide runtime SystemPreferred, // system-wide, then the user's, then bundled SharedPreferred, // the user's, then system-wide, then bundled Bundled, // only the runtime bundled with the app}Within each location, the newest validated runtime wins. Apps rarely need to change this; offline bundles set bundled_dir from the manifest’s folder. See Shared runtime.
Errors
Section titled “Errors”pub enum SabineError { Runtime(RuntimeError), ManifestRead { path: PathBuf, source: std::io::Error }, ManifestParse { path: PathBuf, source: toml::de::Error }, CreationFailed { message: String }, SetupCancelled, SetupFailed, InstanceAlreadyRunning,}
pub type SabineResult<T> = Result<T, SabineError>;| Variant | Means |
|---|---|
Runtime |
No usable Chromium runtime, or a runtime operation failed |
ManifestRead, ManifestParse |
Sabine.toml couldn’t be read or parsed |
CreationFailed |
The configuration is invalid, or a window, host or service step failed; the message says which |
SetupCancelled |
The person closed the setup window |
SetupFailed |
Setup failed; the setup window already showed why |
InstanceAlreadyRunning |
The launch was handed to the running instance |
SabineWindow::main handles all of these itself: it exits quietly for SetupCancelled and InstanceAlreadyRunning and shows a notice for the others.
Platform types
Section titled “Platform types”These come from Sabine’s platform layer and are re-exported from sabine.
impl TrayIcon { pub fn new(id: impl Into<String>, title: impl Into<String>) -> Self; pub fn icon(self, path: impl Into<PathBuf>) -> Self; pub fn template(self, template: bool) -> Self; pub fn tooltip(self, tooltip: impl Into<String>) -> Self; pub fn menu(self, menu: Vec<TrayMenuItem>) -> Self;}
impl TrayMenuItem { pub fn new(id: impl Into<String>, label: impl Into<String>) -> Self; pub fn separator() -> Self; pub fn checkbox(id: impl Into<String>, label: impl Into<String>, checked: bool) -> Self; pub fn submenu(id: impl Into<String>, label: impl Into<String>, items: Vec<TrayMenuItem>) -> Self; pub fn action(self, action: impl Into<String>) -> Self; pub fn enabled(self, enabled: bool) -> Self;}
pub enum TrayMenuItemKind { Normal, Separator, Checkbox { checked: bool }, Submenu(Vec<TrayMenuItem>) }
pub struct TrayActivation { pub tray_id: String, pub item_id: Option<String>, pub action: Option<String>, pub checked: Option<bool>,}Shortcuts
Section titled “Shortcuts”pub struct GlobalShortcutRegistration { pub id: String, pub shortcut: Shortcut, pub action: String, pub description: Option<String>,}
pub struct Shortcut { pub modifiers: ShortcutModifiers, pub key: String,}
pub struct ShortcutModifiers { pub ctrl: bool, pub alt: bool, pub shift: bool, pub meta: bool }
pub struct GlobalShortcutFailure { pub id: String, pub action: String, pub message: String }Shortcut::new(key) starts with no modifiers. Keys are a single character, a common name such as Space or F13, or a KeyboardEvent.code value such as MediaPlayPause. See Shortcuts.
Notifications and appearance
Section titled “Notifications and appearance”impl Notification { pub fn new(id: impl Into<String>, title: impl Into<String>) -> Self; pub fn body(self, body: impl Into<String>) -> Self; pub fn silent(self, silent: bool) -> Self; pub fn urgency(self, urgency: Urgency) -> Self; pub fn category(self, category: impl Into<String>) -> Self;}
pub enum Urgency { Low, Normal, Critical }
pub struct Appearance { pub dark: bool, pub accent: Option<[u8; 3]>,}Showing a notification with the id of one already shown replaces it. Appearance::accent_hex() returns the accent as a CSS hex color. See Notifications and Appearance and shell.
Launch behavior
Section titled “Launch behavior”pub struct AutostartEntry { pub id: String, pub name: String, pub command: String, pub enabled: bool,}
pub enum SingleInstancePolicy { AllowMultiple, ReuseExisting, FocusExisting }
pub struct NativeMessagingHost { pub id: String, pub name: String, pub executable: PathBuf, pub allowed_origins: Vec<String>, pub allowed_extensions: Vec<String>,}
pub enum PlatformEvent { OpenUrls(Vec<String>), Tray(TrayActivation), GlobalShortcut(GlobalShortcutActivation), GlobalShortcutFailed(GlobalShortcutFailure), SingleInstance(SingleInstanceActivation),}
pub struct GlobalShortcutActivation { pub id: String, pub action: String, pub activation_token: Option<String>,}
pub struct SingleInstanceActivation { pub policy: SingleInstancePolicy, pub arguments: Vec<String>, pub working_directory: Option<PathBuf>, pub activation_token: Option<String>,}.on_desktop_event hands app code each PlatformEvent. SingleInstancePolicy::AllowMultiple is the default; .single_instance_id alone doesn’t turn single-instance behavior on. See Autostart, Single instance and Native messaging.
Effects and regions
Section titled “Effects and regions”pub enum WindowBackgroundEffect { None, Glass, #[cfg(target_os = "windows")] Blur, #[cfg(target_os = "windows")] Mica, #[cfg(target_os = "windows")] MicaAlt, #[cfg(target_os = "macos")] HudWindow, #[cfg(target_os = "macos")] Sidebar,}
impl WindowRegionRect { pub fn new(x: i32, y: i32, width: i32, height: i32) -> Self;}
impl WindowRegion { pub fn empty() -> Self; pub fn rect(x: i32, y: i32, width: i32, height: i32) -> Self; pub fn add_rect(self, x: i32, y: i32, width: i32, height: i32) -> Self; pub fn full() -> Self; pub fn rounded_rect(radius: i32) -> Self; pub fn rounded_left(width: i32, radius: i32) -> Self; pub fn titlebar_and_sidebar(sidebar_width: i32, titlebar_height: i32, radius: i32) -> Self; pub fn content_after_sidebar(sidebar_width: i32, titlebar_height: i32) -> Self; pub fn content_after_sidebar_rounded_right(sidebar_width: i32, titlebar_height: i32, radius: i32) -> Self;}
impl WindowRegions { pub fn new() -> Self; pub fn blur(self, region: WindowRegion) -> Self; pub fn opaque(self, region: WindowRegion) -> Self; pub fn input(self, region: WindowRegion) -> Self;}Every shape except rect follows the window’s size, and their rounded corners turn square while the window is maximized, fullscreen or tiled. The platform-only effects exist only when compiling for that platform, so use them under #[cfg(target_os = "...")].