Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Platform APIs

Kael provides native platform integration matching (and exceeding) Electron’s capabilities. All APIs work cross-platform on macOS, Windows, and Linux.


File Dialogs

Native open/save file pickers:

#![allow(unused)]
fn main() {
// Open file dialog
let paths = cx.prompt_for_paths(PathPromptOptions {
    files: true,
    directories: false,
    multiple: true,
    prompt: Some("Open".into()),
}).await;

// Save file dialog
let path = cx.prompt_for_new_path(
    &std::env::current_dir()?,
    Some("document.txt"),
).await;
}

Native Menus

Application menu bar (macOS menu bar, Windows/Linux window menu):

#![allow(unused)]
fn main() {
cx.set_menus(vec![
    Menu {
        name: "File".into(),
        items: vec![
            MenuItem::action("New", menu_action::New),
            MenuItem::action("Open...", menu_action::Open),
            MenuItem::separator(),
            MenuItem::action("Save", menu_action::Save),
            MenuItem::action("Save As...", menu_action::SaveAs),
            MenuItem::separator(),
            MenuItem::action("Quit", menu_action::Quit),
        ],
    },
    Menu {
        name: "Edit".into(),
        items: vec![
            MenuItem::action("Undo", menu_action::Undo),
            MenuItem::action("Redo", menu_action::Redo),
            MenuItem::separator(),
            MenuItem::action("Cut", menu_action::Cut),
            MenuItem::action("Copy", menu_action::Copy),
            MenuItem::action("Paste", menu_action::Paste),
        ],
    },
]);
}

System Tray

Tray icon with menu and click handling:

#![allow(unused)]
fn main() {
// Set tray menu
cx.set_tray_menu(vec![
    TrayMenuItem::Action {
        label: "Show Window".into(),
        id: "show".into(),
    },
    TrayMenuItem::Separator,
    TrayMenuItem::Action {
        label: "Quit".into(),
        id: "quit".into(),
    },
]);

cx.set_tray_tooltip("My App — Running");

// Handle tray menu actions
cx.on_tray_menu_action(|action_id, cx| {
    if action_id.as_ref() == "show" {
        // bring window to front
    } else if action_id.as_ref() == "quit" {
        cx.quit();
    }
});

// Handle tray icon clicks
cx.on_tray_icon_event(|event, cx| {
    match event {
        TrayIconEvent::LeftClick => { /* toggle window */ },
        TrayIconEvent::DoubleClick => { /* show window */ },
        _ => {}
    }
});
}

Clipboard

Read and write text and images:

#![allow(unused)]
fn main() {
// Write text
cx.write_to_clipboard(ClipboardItem::new_string("Hello, clipboard!".into()));

// Write text with metadata
cx.write_to_clipboard(ClipboardItem::new_string_with_metadata(
    "formatted text".into(),
    json!({"source": "my_app"}).to_string(),
));

// Read
if let Some(item) = cx.read_from_clipboard() {
    if let Some(text) = item.text() {
        println!("Got: {}", text);
    }
}
}

Global Hotkeys

System-wide keyboard shortcuts (work even when app is unfocused):

#![allow(unused)]
fn main() {
cx.register_global_hotkey(1, &Keystroke::parse("cmd-shift-k")?)?;

cx.on_global_hotkey(|id| {
    match id {
        1 => { /* Cmd+Shift+K pressed anywhere */ },
        _ => {}
    }
});
}

Notifications

OS-level notifications (not in-app toasts):

#![allow(unused)]
fn main() {
cx.show_notification("Build Complete", "All tests passed")?;

cx.show_notification_with_actions(
    "Update Available",
    "Version 2.0 is ready to install",
    &[
        NotificationAction { id: "install".into(), label: "Install Now".into() },
        NotificationAction { id: "later".into(), label: "Remind Later".into() },
    ],
    |action_id| {
        println!("User clicked: {}", action_id);
    },
)?;
}

Deep Linking

Register and handle custom URL schemes. These methods are called on Application before .run():

#![allow(unused)]
fn main() {
Application::new()
    // Handle all opened URLs
    .on_open_urls(|urls| {
        for url in urls {
            println!("Opened: {}", url);
        }
    })
    // Handle specific scheme with app context
    .on_deep_link("myapp", |url, cx| {
        // Handle myapp://path/to/resource
    })
    .run(|cx| {
        // ...
    });
}

Multi-Window

Open multiple windows with independent views:

#![allow(unused)]
fn main() {
cx.open_window(
    WindowOptions {
        window_bounds: Some(WindowBounds::Windowed(bounds)),
        ..Default::default()
    },
    |_window, cx| cx.new(|_| SettingsView::new()),
).unwrap();
}

Kael windows follow native platform conventions automatically:

  • Scroll-to-focus — scrolling over an unfocused Kael window activates it, matching standard macOS/Windows behavior
  • Smooth zoom — double-clicking the titlebar animates the window to fill the screen using native Core Animation transitions
  • Live resize — content reflows smoothly during window drag-resizing

Auto-Update

Built-in application update pipeline:

#![allow(unused)]
fn main() {
let config = AutoUpdaterConfig {
    feed_url: "https://releases.myapp.com/appcast.xml".into(),
    ..Default::default()
};

let updater = AutoUpdater::new(config, current_version, http_client);

// Check for updates
let status = updater.check_for_updates().await;
match status {
    UpdateStatus::UpdateAvailable(info) => {
        println!("New version: {}", info.version);
    }
    UpdateStatus::UpToDate => println!("Already up to date"),
    _ => {}
}
}

Printing

Native print dialog and custom rendering:

#![allow(unused)]
fn main() {
let job = PrintJob::new("Document")
    .orientation(PrintOrientation::Portrait)
    .page(PrintPage::new(size(px(612.0), px(792.0)), |ctx| {
        ctx.draw_text("Hello, printed world!", point(72.0, 72.0), style);
    }));

window.show_print_dialog(job);
}

Power Management

Prevent sleep and detect power state:

#![allow(unused)]
fn main() {
// Prevent display sleep during video playback
let blocker = cx.start_power_save_blocker(PowerSaveBlockerKind::PreventDisplaySleep);

// Check power mode
match cx.power_mode() {
    PowerMode::Performance => { /* full quality */ },
    PowerMode::LowPower => { /* reduce effects */ },
    _ => {}
}

// Detect idle time
if let Some(idle) = cx.system_idle_time() {
    if idle > Duration::from_secs(300) { /* user is away */ }
}

// Listen for sleep/wake
cx.on_system_power_event(|event, cx| {
    match event {
        SystemPowerEvent::WillSleep => { /* save state */ },
        SystemPowerEvent::DidWake => { /* refresh data */ },
        _ => {}
    }
});
}

Session Persistence

Save and restore window positions across launches:

#![allow(unused)]
fn main() {
let store = SessionStore::new("my-app")?;

// Save current window layout
store.save_window_states(&window_states)?;

// Restore on next launch
if let Ok(states) = store.load_window_states() {
    for (id, state) in &states {
        cx.open_window(WindowOptions {
            window_bounds: Some(state.bounds),
            ..Default::default()
        }, |_, cx| cx.new(|_| MyView::new()));
    }
}
}

Display Information

Enumerate monitors and get DPI:

#![allow(unused)]
fn main() {
let displays = cx.displays();
let primary = cx.primary_display();

for display in &displays {
    println!("Display {}: {:?}", display.id(), display.bounds());
}
}

Crash Reporting

Automatic crash capture with remote submission:

#![allow(unused)]
fn main() {
use kael::CrashReporter;

let mut reporter = CrashReporter {
    app_id: "my-app".into(),
    crash_dir: std::env::temp_dir().join("crashes"),
    ..Default::default()
};

reporter.install_hook();
}

App Lifecycle

Launch at login and update the dock/taskbar:

#![allow(unused)]
fn main() {
cx.set_auto_launch("com.example.app", true)?;
let enabled = cx.is_auto_launch_enabled("com.example.app");

cx.set_dock_badge(Some("3"));   // None clears it
cx.set_dock_menu(dock_menu_items);
}

Enforce a single running instance — acquire a lock at startup and forward later launches to the existing process:

#![allow(unused)]
fn main() {
use kael::{SingleInstance, send_activate_to_existing};

match SingleInstance::acquire("com.example.app") {
    Ok(instance) => {
        instance.on_activate(Box::new(|| { /* focus the existing window */ }));
        // ... run the app ...
    }
    Err(_already_running) => {
        send_activate_to_existing("com.example.app")?;
        return; // this duplicate launch exits
    }
}
}

Biometric Authentication

Gate sensitive actions behind Touch ID / Face ID / Windows Hello. Check availability, then prompt with a reason string and a completion callback:

#![allow(unused)]
fn main() {
use kael::BiometricStatus;

if let BiometricStatus::Available(_kind) = cx.biometric_status() {
    cx.authenticate_biometric("Unlock your vault", |success| {
        if success { /* proceed */ }
    });
}
}

BiometricStatus is Available(BiometricKind) or Unavailable; BiometricKind identifies the method (Touch ID, Face ID, fingerprint, Windows Hello).

Screen & Media Capture

Enumerate capturable displays/windows and stream frames (build with the screen-capture feature):

#![allow(unused)]
fn main() {
if cx.is_screen_capture_supported() {
    // enumerate sources via cx.screen_capture_sources(..), then start a
    // capture stream whose frames arrive as ScreenCaptureFrame values
}
}

See examples/capture_demo.rs.