kael 0.1.1

GPU-accelerated native UI framework for Rust — build desktop apps with Metal, DirectX, and Vulkan rendering
Documentation
use crate::{
    Bounds, Pixels, SharedString,
    webview::{PlatformWebView, PlatformWebViewCommand},
};
use anyhow::Result;
use wry::{
    Rect, WebContext,
    dpi::{LogicalPosition, LogicalSize},
};

pub(crate) fn webview_command_id(command: &PlatformWebViewCommand) -> SharedString {
    match command {
        PlatformWebViewCommand::Navigate { id, .. }
        | PlatformWebViewCommand::EvaluateJavaScript { id, .. }
        | PlatformWebViewCommand::PostMessage { id, .. }
        | PlatformWebViewCommand::Reload { id }
        | PlatformWebViewCommand::GoBack { id }
        | PlatformWebViewCommand::GoForward { id } => id.clone(),
    }
}

pub(crate) fn to_wry_rect(bounds: Bounds<Pixels>) -> Rect {
    Rect {
        position: LogicalPosition::new(bounds.origin.x.0 as f64, bounds.origin.y.0 as f64).into(),
        size: LogicalSize::new(bounds.size.width.0 as f64, bounds.size.height.0 as f64).into(),
    }
}

pub(crate) fn json_string_literal(value: &str) -> String {
    serde_json::to_string(value).unwrap_or_else(|_| "\"\"".into())
}

pub(crate) fn bridge_script(storage_key: Option<&SharedString>) -> String {
    let storage_key = storage_key
        .map(|storage_key| {
            format!(
                "window.GPUI_WEBVIEW_STORAGE_ID = {};",
                json_string_literal(storage_key.as_ref())
            )
        })
        .unwrap_or_default();

    format!(
        "(() => {{ {storage_key} if (!window.external) {{ window.external = {{}}; }} window.external.invoke = function(message) {{ const payload = typeof message === 'string' ? message : JSON.stringify(message); window.ipc.postMessage(payload); }}; if (!window.gpui) {{ window.gpui = {{}}; }} window.gpui.postMessage = function(message) {{ window.external.invoke(message); }}; }})();"
    )
}

pub(crate) fn css_script(css: &str) -> String {
    format!(
        "(() => {{ const mount = () => {{ if (!document.head) {{ return; }} const style = document.createElement('style'); style.setAttribute('data-gpui-webview-style', 'true'); style.textContent = {}; document.head.appendChild(style); }}; if (document.head) {{ mount(); }} else {{ document.addEventListener('DOMContentLoaded', mount, {{ once: true }}); }} }})();",
        json_string_literal(css)
    )
}

pub(crate) fn create_web_context(desired: &PlatformWebView) -> Result<Option<WebContext>> {
    desired
        .storage_key
        .as_ref()
        .map(webview_storage_dir)
        .transpose()
        .map(|directory| directory.map(|data_directory| WebContext::new(Some(data_directory))))
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn webview_storage_dir(storage_key: &SharedString) -> Result<std::path::PathBuf> {
    use anyhow::Context as _;
    use std::{env, fs, path::PathBuf};

    let base = env::var_os("XDG_DATA_HOME")
        .map(PathBuf::from)
        .or_else(|| env::var_os("HOME").map(|home| PathBuf::from(home).join(".local/share")))
        .context("XDG_DATA_HOME or HOME environment variable not set for webview storage")?;

    let directory = base
        .join(env!("CARGO_PKG_NAME"))
        .join("webview")
        .join(format!(
            "{:016x}",
            seahash::hash(storage_key.as_ref().as_bytes())
        ));
    fs::create_dir_all(&directory).with_context(|| {
        format!(
            "creating Linux webview storage directory {}",
            directory.display()
        )
    })?;
    Ok(directory)
}

#[cfg(target_os = "windows")]
fn webview_storage_dir(storage_key: &SharedString) -> Result<std::path::PathBuf> {
    use anyhow::Context as _;
    use std::{env, fs, path::PathBuf};

    let base = env::var_os("LOCALAPPDATA")
        .map(PathBuf::from)
        .or_else(|| env::var_os("APPDATA").map(PathBuf::from))
        .context("LOCALAPPDATA or APPDATA environment variable not set for webview storage")?;

    let directory = base
        .join(env!("CARGO_PKG_NAME"))
        .join("webview")
        .join(format!(
            "{:016x}",
            seahash::hash(storage_key.as_ref().as_bytes())
        ));
    fs::create_dir_all(&directory).with_context(|| {
        format!(
            "creating Windows webview storage directory {}",
            directory.display()
        )
    })?;
    Ok(directory)
}