gui/webview
A native window around HTML, and a whole desktop application layer on top of it.
import gui.webview
- Showing data your program computed
- Handing structured data to the page
- Opening a site or a local server
- An application with a page and a command
- Commands, errors and slow work
- Windows, events and menus
- Dialogs, notifications, secrets and the tray
- A window around a website
- Making installers
- When something does not work
- Choosing the web engine
- Types
- Constants and variables
- Functions
This package opens a native desktop window around HTML, and builds a whole desktop application on top of it, the kind you would build with Tauri or Electron, with no Rust and no second language. There are two levels in one package. The low level is a small window: you create it, show a page with SetHTML or Navigate, and Run keeps it open until the user closes it. The application level starts with Init and adds commands the page can call, events in both directions, packaged files, dialogs, notifications, the keychain, tray icons, menus, a single-instance lock and installers made by salam bundle.
The interface is HTML, CSS and JavaScript. By default it runs in the web view the operating system already has, like Tauri: WebView2 on Windows, WKWebView on macOS and WebKitGTK on Linux, so the program stays one small native executable. The engine is chosen when the program is built; see choosing the web engine for the Chromium option.
A page calls your Salam code with salam.invoke, which returns a promise. Pages can come from three places: files packed inside the executable, so nothing sits in a folder for users to edit; a remote site; or an HTML string. Use it for a small desktop tool, a viewer for data your program computed, or a native window around a web interface your program serves. For pages that run in the user's own browser, see dom; to generate the HTML, see template.
How data moves, and what does not work
- Put the data in the page. The reliable way to give the page your data is to write it into the HTML you pass to
SetHTML, as JSON inside a<script>. Initinstalls a script for every page loaded later, before the page's own scripts run.Evalruns once, on whatever page is loaded at that moment.- Pages load in the background, so code sent with
Evalright afterSetHTMLorNavigatecan run before the new page exists. UseInit, or wait forOnLoad. - The page can talk back with
OnMessage. For a whole application, with commands, events, packaged files and installers, use the application functions such asInit,CommandandOpen, described in the guides further down. Createreports failure by returning a window that is already closed; checkIsClosed()right after it, for example on a Linux server with no display.
What pages may do
- Local pages may run every command. Remote sites get nothing until you name them with
Allow, command by command if you like. - The bridge exists only in the top frame of an allowed origin, and every message carries a secret made for this run, so a frame or another site cannot call you. Answers carry the origin they belong to, so they never reach a page that replaced it.
- A link to any other site opens in the system browser. On Linux the engine cannot tell a frame from the page, so a cross-origin frame there needs its origin in
allow_navigation. - Files inside the executable are compressed and scrambled, which keeps them out of sight. They are not secret: anything a page can read, a determined user can extract. Keep real secrets on your server.
A window needs a desktop session, so the site only compiles these programs; run them on your own machine with salam run. On Linux install libgtk-3-dev and libwebkit2gtk-4.1-dev (WebKitGTK 4.1) first. Windows 10 and 11 already ship WebView2, and macOS ships WKWebView. Building for another system needs nothing extra: --target works from any machine.
Showing data your program computed
The simplest desktop program builds an HTML string and shows it. Everything the page needs, the style sheet included, can travel in that one string, so there are no files to ship next to the executable. HINT_FIXED keeps the window at the size you chose, which suits a small dialog like this order summary.
import gui.webview
import str
struct Item:
pub name: str = ""
pub qty: int = 0
pub price: int = 0
end
func page(items: Vector<Item>): str:
mut rows := ""
mut total := 0
each it in items:
line := it.qty * it.price
total += line
rows = rows + "<tr><td>" + it.name + "</td><td>" + str.FromInt(it.qty) + "</td><td>" + str.FromInt(line) + "</td></tr>"
end
css := "body{font-family:sans-serif;margin:2em}td,th{padding:4px 12px;text-align:left}"
ret "<style>" + css + "</style><h1>Order</h1><table><tr><th>Item</th><th>Qty</th><th>Sum</th></tr>" + rows + "</table><p>Total: " + str.FromInt(total) + "</p>"
end
func main:
mut items := Vector {} as Vector<Item>
items.push(Item { name = "Tea", qty = 2, price = 45 })
items.push(Item { name = "Cake", qty = 1, price = 120 })
mut win := webview.Create()
win.SetTitle("Order")
win.SetSize(480, 320, webview.HINT_FIXED)
win.SetHTML(page(items))
win.Run()
win.Destroy()
endThe item names go into the HTML as they are. When the text comes from a user or a file, pass it through EscapeHTML from template first, or a name with a < in it breaks the page.
Handing structured data to the page
For anything bigger than a table, let JavaScript draw the page and give it the data as JSON. Marshal from encoding/json turns a vector of structs into a JSON array whose keys are the field names, and that text goes straight into a <script> in the page. The script runs as the page loads, so the data is there before anything is drawn.
import gui.webview
import encoding.json
struct Task:
pub title: str = ""
pub done: bool = false
end
func main:
mut tasks := Vector {} as Vector<Task>
tasks.push(Task { title = "Write the report", done = true })
tasks.push(Task { title = "Send it to Sara" })
tasks.push(Task { title = "Book the meeting room" })
page := `<h2 id="count"></h2>
<ul id="list"></ul>
<script>
const tasks = ` + json.Marshal(tasks) + `;
const open = tasks.filter(t => !t.done).length;
document.getElementById("count").textContent = open + " of " + tasks.length + " still open";
for (const t of tasks) {
const li = document.createElement("li");
li.textContent = (t.done ? "[x] " : "[ ] ") + t.title;
document.getElementById("list").appendChild(li);
}
</script>`
mut win := webview.Create(false)
win.SetTitle("Tasks")
win.SetSize(400, 300, webview.HINT_NONE)
win.SetHTML(page)
win.Run()
win.Destroy()
endJSON is valid JavaScript, so no parsing step is needed. One caution: if a value could contain the text </script>, it would end the script early; replace </ with <\/ in the JSON first when the data comes from users.
Opening a site or a local server
Navigate loads an address instead of a string, so the window can show a remote site or a web interface your own program serves on 127.0.0.1. This one takes the address from the command line, so salam run webview-guide-launch.salam http://127.0.0.1:8000 wraps a local development server in a native window.
import gui.webview
import os
func main:
args := os.Args()
mut url := "https://salamlang.github.io/Salam/"
if args.len() > 1:
url = args.get(1)
end
mut win := webview.Create()
win.SetTitle(url)
win.SetSize(1280, 800, webview.HINT_NONE)
win.Navigate(url)
win.Run()
if win.IsClosed():
println "window closed"
end
win.Destroy()
endRun blocks until the user closes the window; the lines after it are where you save state and clean up. Call Destroy once at the end in every case. Terminate makes Run return at its next turn; on Linux and Windows that turn only comes with the next window event, such as a mouse move. On macOS it quits the whole application instead, so the lines after Run do not run there.
An application with a page and a command
While developing, assets_dir serves your folder directly, so a reload shows your edits. Without it the files inside the executable are used.
import gui.webview
func main:
webview.Init(webview.Config { id = "com.example.notes", name = "Notes", assets_dir = "www" })
webview.Command("greet", (c: webview.Call):
c.ResolveStr("Hello " + c.Str("name"))
end)
webview.On("ready", (_data: str):
webview.Emit("saved", `{"count":1}`)
end)
win := webview.Open(webview.WindowOptions { title = "Notes", width = 900, height = 600 })
if win.IsClosed():
println "could not open a window"
ret 1
end
webview.Run()
endThe page calls it like any other async function:
const text = await salam.invoke("greet", { name: "Sara" });
const stop = salam.listen("saved", (data) => console.log(data));
salam.emit("ready", {});
A command normally runs on the UI thread, so keep it short. Register slow work with CommandAsync; the page stays responsive and Resolve is safe from the worker.
Commands, errors and slow work
Arguments arrive as JSON. Str, Int and Bool read one by name and Has tells you whether the page sent it. Finish every call exactly once: with one Resolve method, or with Reject, which makes the page's promise throw an error carrying your message. A second answer is ignored.
A Command runs on the UI thread, so a slow one freezes the window. Register it with CommandAsync and it runs on a worker, where Resolve is safe to call later. Every window call belongs on the UI thread, so a worker hands such work to Dispatch.
import gui.webview
import encoding.json
import sync
func main:
webview.Init(webview.Config { id = "com.example.notes", name = "Notes", assets_dir = "www" })
webview.Command("add", (c: webview.Call):
if not c.Has("a") or not c.Has("b"):
c.Reject("a and b are required")
ret
end
c.ResolveInt(c.Int("a") + c.Int("b"))
end)
webview.CommandAsync("report", (c: webview.Call):
name := c.Str("name")
sync.SleepMs(1500)
c.Resolve(`{"name":` + `"` + json.Escape(name) + `"` + `,"pages":12}`)
end)
webview.On("save", (data: str):
webview.Dispatch(():
webview.Emit("saved", data)
end)
end)
win := webview.Open(webview.WindowOptions { title = "Notes", width = 900, height = 600 })
if win.IsClosed():
println webview.LastError()
ret 1
end
webview.Run()
endtry {
const sum = await salam.invoke("add", { a: 40, b: 2 });
const report = await salam.invoke("report", { name: "March" });
} catch (e) {
console.log(e.message);
}
Windows, events and menus
Open can be called many times. Give each window a label and find it again with GetWindow. Emit on a window reaches only that window, and desktop.Emit reaches all of them. OnClose runs when the user closes a window: return false and the window stays, which is the place to ask about unsaved work.
import gui.webview
func main:
webview.Init(webview.Config { id = "com.example.notes", name = "Notes", assets_dir = "www" })
main_win := webview.Open(webview.WindowOptions { label = "main", title = "Notes", width = 900, height = 600, min_width = 480, min_height = 320 })
main_win.OnClose(():
ret webview.Confirm("Notes", "Close the notes window?")
end)
main_win.OnResize((w: int, h: int):
println "size", w, h
end)
webview.Command("open_help", (c: webview.Call):
help := webview.Open(webview.WindowOptions { label = "help", title = "Help", width = 520, height = 420, html = "<h1>Help</h1>" })
help.Emit("hello", `{"from":"main"}`)
c.ResolveNull()
end)
webview.OnMenu((id: str):
if id == "help":
webview.GetWindow("main").Emit("menu", `"help"`)
end
if id == "quit":
webview.Quit()
end
end)
mut items := Vector {} as Vector<webview.MenuItem>
items.push(webview.Item("help", "Help"))
items.push(webview.Separator())
items.push(webview.Item("quit", "Quit"))
webview.SetMenu(main_win, items)
webview.Run()
endA menu is a list of items made with Item, Separator and Submenu. Every click arrives in OnMenu with the item's id, whichever menu it came from.
Dialogs, notifications, secrets and the tray
These calls use whatever the system provides, so the same program behaves natively on each system. File dialogs return an empty string when the user cancels. SecretSet and SecretGet keep a small value, such as a login token, in the keychain instead of a file in your data folder. SingleInstance returns false when the program is already running, and the running copy gets the new arguments in its callback.
import gui.webview
func main:
webview.Init(webview.Config { id = "com.example.notes", name = "Notes", assets_dir = "www" })
win := webview.Open(webview.WindowOptions { title = "Notes" })
keep := webview.SingleInstance((args: Vector<str>):
println "second start with", args.len(), "arguments"
webview.GetWindow("main").Focus()
end)
if not keep:
ret 0
end
webview.Command("choose_folder", (c: webview.Call):
c.ResolveStr(webview.PickFolder("Choose a folder"))
end)
webview.Command("sign_in", (c: webview.Call):
ok := webview.SecretSet("token", c.Str("token"))
c.ResolveBool(ok)
end)
webview.Command("token", (c: webview.Call):
c.ResolveStr(webview.SecretGet("token"))
end)
webview.Command("done", (c: webview.Call):
webview.Notify("Notes", "Your export is ready")
webview.RequestAttention(win)
c.ResolveNull()
end)
webview.OnTrayClick(():
win.Show()
win.Focus()
end)
mut tray := Vector {} as Vector<webview.MenuItem>
tray.push(webview.Item("quit", "Quit"))
webview.SetTray("icon.png", "Notes", tray)
webview.Run()
endKeep in mind that a page can call a command only if it is allowed to. Local pages may call all of them. If you load a remote site, list the dangerous commands, such as choose_folder above, only for origins you trust.
A window around a website
Give url an address to wrap a site you already run, and use Allow to give that one site access to chosen commands. Your local error page can stay in the assets.
import gui.webview
func main:
webview.Init(webview.Config { id = "com.example.portal", name = "Portal" })
mut allowed := Vector {} as Vector<str>
allowed.push("pick_folder")
webview.Allow("https://app.example.com", allowed)
webview.Command("pick_folder", (c: webview.Call):
c.ResolveStr(webview.PickFolder("Choose a folder"))
end)
win := webview.Open(webview.WindowOptions { title = "Portal", url = "https://app.example.com/" })
win.OnCrash((): win.Navigate(webview.AssetURL("/error.html")) end)
webview.Run()
endMaking installers
Describe the application in salam.toml and run salam bundle. The same command works from any system with --target, and the assets folder goes inside the application.
[app]
id = "com.example.notes"
name = "Notes"
version = "1.0.0"
assets = "www"
icon = "icon.png"
description = "Take notes"
$ salam bundle
$ salam bundle --target=x86_64-w64-windows-gnu
$ salam bundle --target=arm64-apple-macos
On Linux you get a tar archive and a deb package, on Windows a zip with a windowed executable, on macOS an .app. --format also offers rpm, AppImage, NSIS and dmg, which need rpmbuild, appimagetool, makensis and hdiutil. Code signing is up to you.
When something does not work
- If
Opengives a closed window,LastErrorsays why. A missing WebKitGTK or WebView2 runtime shows up here. - A window that opens blank: set
SALAM_WEBVIEW_TRACEto a file name and run again. Each line is one step: how the engine started, each navigation, resource and message, and every message the bridge refused. It also works in a program with no console. - Set
debug = trueinConfigand callOpenDevToolson the window to use the developer tools of the engine. - A command that never answers leaves the page's promise pending forever. Make sure every path ends in a
Resolvemethod orReject.
Choosing the web engine
The engine is chosen when your program is built, not when it runs. By default a program uses the web view of the operating system: WebView2 on Windows, WKWebView on macOS and WebKitGTK on Linux. That is what keeps the executable small, and it is the engine every guide above assumes. Because the web view comes with the system, the same page can look slightly different from one system to another.
For the same engine everywhere you can build against Chromium Embedded Framework (CEF) instead. Build the program with the -DSALAM_WEBVIEW_CEF flag, or let salam bundle do it: set engine = "chromium" and runtime = "dir" in the [app] table of salam.toml, or pass --engine=chromium and --runtime=DIR (the SALAM_CEF_DIR environment variable works too). The runtime folder holds the built salam_webview_cef library, salam_cef_helper and the CEF runtime files (see std/gui/webview/native/CMakeLists.txt in the Salam repository for how to build them). It is copied next to the program, and only for tar on Linux and zip on Windows.
A program can ask which engine it got. Engine returns ENGINE_SYSTEM ("system") or ENGINE_CHROMIUM ("chromium"), EngineName returns a name for people to read (WebKitGTK, WebView2, WKWebView or Chromium Embedded Framework), and SupportsCommands says whether commands work.
import gui.webview
func main:
println "Engine:", webview.Engine()
println "Name:", webview.EngineName()
if webview.Engine() == webview.ENGINE_CHROMIUM:
println "Chromium Embedded Framework"
end
if not webview.SupportsCommands():
println "No commands or events with this engine yet"
end
endBe aware of the limits. With the Chromium engine today, windows open and pages load, but commands, events, custom schemes and the system services (dialogs, notifications, keychain, tray) are not available yet, and SupportsCommands() returns false. Full parity with the system engine is planned. If your program depends on salam.invoke, build it with the default engine for now, or check SupportsCommands() and fall back.
Types
Request
struct Request| Name | Type | Description |
|---|---|---|
url | str = "" | The whole address. |
scheme | str = "" | The scheme, such as app. |
method | str = "GET" | The HTTP method, usually GET. |
path | str = "/" | The path, starting with a slash. |
query | str = "" | The text after the question mark. |
import gui.webview
func main:
webview.SetApp("com.example.window", "Window")
webview.RegisterScheme("app", (r: webview.Request):
body := "<h1>" + r.path + "</h1>"
mut res := webview.Response { mime = "text/html; charset=utf-8", data = body as void*, size = body.len() as i64 }
res.Header("X-Example", r.method + r.query + r.url + r.scheme)
ret res
end)
mut win := webview.Create(true, false)
win.SetTitle("hello")
win.SetSize(800, 600, webview.HINT_NONE)
win.SetMinSize(400, 300)
win.SetIcon("icon.png")
win.SetContextMenu(false)
win.Init("window.salam = { version: 1 };")
win.OnMessage((text: str): println text end)
win.OnNavigate((url: str): ret url != "https://blocked.example/" and webview.NavigationIsMainFrame() end)
win.OnNewWindow((url: str): println url end)
win.OnClose((): ret true end)
win.OnLoad((url: str, done: bool): println url, done end)
win.OnCrash((): println "crashed" end)
win.OnResize((w: int, h: int): println w, h end)
win.Center()
win.Show()
win.Focus()
win.Hide()
win.Minimize()
win.Maximize()
win.OpenDevTools()
win.SetHTML("<h1>hello world</h1>")
win.Eval("document.title = 'ready'")
win.EvalLater("document.title = 'later'")
println win.URL(), win.IsActive(), win.id, win.Native() != null, win.Content() != null
webview.Dispatch((): println "on the UI thread" end)
webview.OnCommand((id: int): println id end)
webview.OnTrayMessage((event: int): println event end)
webview.OnCopyData((_data: void*, size: int): println size end)
webview.NameMessageWindow("example")
println webview.MenuHost() != null, webview.SchemeOrigin("app"), webview.SchemeURL("app", "/x"), webview.PostScript()
win.Run()
webview.RunAll()
webview.Quit()
println webview.LastError()
if not win.IsClosed():
win.Terminate()
end
win.Destroy()
println webview.HINT_FIXED
endResponse
struct Response| Name | Type | Description |
|---|---|---|
status | int = 200 | The HTTP status, 200 by default. |
mime | str = "text/html" | The content type. |
data | void* | A pointer to the body. |
size | i64 = 0 | The body size in bytes. |
headers | Vector | Extra headers, as name and value pairs. |
The example for this item is shown with the ones above: gui-webview-Window.salam
Header
func Header(name: str, value: str)The example for this item is shown with the ones above: gui-webview-Window.salam
WebView
struct WebView| Name | Type | Description |
|---|---|---|
id | int = -1 | The number of this window inside the package. |
The example for this item is shown with the ones above: gui-webview-Window.salam
Destroy
func Destroy()The example for this item is shown with the ones above: gui-webview-Window.salam
Run
func Run()Terminate is called.The example for this item is shown with the ones above: gui-webview-Window.salam
Terminate
func Terminate()Run to return. The window stays open until Destroy.The example for this item is shown with the ones above: gui-webview-Window.salam
SetTitle
func SetTitle(title: str)The example for this item is shown with the ones above: gui-webview-Window.salam
SetSize
func SetSize(width: int, height: int, hints: int)HINT constants: HINT_FIXED stops the user from resizing it.The example for this item is shown with the ones above: gui-webview-Window.salam
SetMinSize
func SetMinSize(width: int, height: int)The example for this item is shown with the ones above: gui-webview-Window.salam
SetIcon
func SetIcon(path: str).ico on Windows, any image on macOS.The example for this item is shown with the ones above: gui-webview-Window.salam
SetHTML
func SetHTML(html: str)The example for this item is shown with the ones above: gui-webview-Window.salam
Navigate
func Navigate(url: str)import gui.webview
func main:
mut win := webview.Create()
win.SetTitle("the Salam language")
win.SetSize(1024, 768, webview.HINT_FIXED)
win.Navigate("https://salamlang.github.io/Salam/")
win.Run()
win.Destroy()
endEval
func Eval(js: str)The example for this item is shown with the ones above: gui-webview-Window.salam
EvalLater
func EvalLater(js: str)Eval, but safe from any thread: the code runs on the UI thread soon after.The example for this item is shown with the ones above: gui-webview-Window.salam
Init
func Init(js: str, all_frames: bool = false)true to run it in frames too.The example for this item is shown with the ones above: gui-webview-Window.salam
URL
func URL(): strThe example for this item is shown with the ones above: gui-webview-Window.salam
Show
func Show()The example for this item is shown with the ones above: gui-webview-Window.salam
Hide
func Hide()The example for this item is shown with the ones above: gui-webview-Window.salam
Focus
func Focus()The example for this item is shown with the ones above: gui-webview-Window.salam
Minimize
func Minimize()The example for this item is shown with the ones above: gui-webview-Window.salam
Maximize
func Maximize()The example for this item is shown with the ones above: gui-webview-Window.salam
Center
func Center()The example for this item is shown with the ones above: gui-webview-Window.salam
IsActive
func IsActive(): boolThe example for this item is shown with the ones above: gui-webview-Window.salam
Native
func Native(): void*GtkWindow*, HWND or NSWindow*.The example for this item is shown with the ones above: gui-webview-Window.salam
Content
func Content(): void*GtkBox on Linux, the window elsewhere.The example for this item is shown with the ones above: gui-webview-Window.salam
OpenDevTools
func OpenDevTools()The example for this item is shown with the ones above: gui-webview-Window.salam
SetContextMenu
func SetContextMenu(enabled: bool)The example for this item is shown with the ones above: gui-webview-Window.salam
OnMessage
func OnMessage(handler: func(str))PostScript.The example for this item is shown with the ones above: gui-webview-Window.salam
OnNavigate
func OnNavigate(handler: func(str): bool)NavigationIsMainFrame.The example for this item is shown with the ones above: gui-webview-Window.salam
OnNewWindow
func OnNewWindow(handler: func(str))The example for this item is shown with the ones above: gui-webview-Window.salam
OnClose
func OnClose(handler: func(): bool)The example for this item is shown with the ones above: gui-webview-Window.salam
OnLoad
func OnLoad(handler: func(str, bool))The example for this item is shown with the ones above: gui-webview-Window.salam
OnCrash
func OnCrash(handler: func())The example for this item is shown with the ones above: gui-webview-Window.salam
OnResize
func OnResize(handler: func(int, int))The example for this item is shown with the ones above: gui-webview-Window.salam
IsClosed
func IsClosed(): boolThe example for this item is shown with the ones above: gui-webview-Window.salam
Config
struct ConfigInit.| Name | Type | Description |
|---|---|---|
id | str = "" | A reverse-domain identifier, such as com.example.notes. It names the data folder and scrambles the asset pack. |
name | str = "" | The name people see. |
version | str = "" | The version text. |
icon | str = "" | An icon file for notifications. |
scheme | str = "app" | The scheme local pages load from, app by default. |
assets_dir | str = "" | Serve pages from this folder. Handy while developing; when it is empty only the pack is used. |
pack_path | str = "" | Read assets from this pack file. By default the pack inside the executable is used. |
csp | str = "" | A Content-Security-Policy header for local pages. |
spa | bool = false | Answer unknown paths with index.html, for single page apps. |
debug | bool = false | Turn on developer tools. |
external_links | bool = true | Open links to other sites in the system browser, on by default. |
import gui.webview
func main:
webview.Init(webview.Config {
id = "com.example.app", name = "App", version = "1.0", scheme = "app", assets_dir = "www", pack_path = "", csp = "default-src 'self'", spa = false, debug = false, external_links = true
})
if not webview.SingleInstance((args: Vector<str>): println args.len() end):
ret
end
mut allowed := Vector {} as Vector<str>
allowed.push("greet")
webview.Allow("https://example.com", allowed)
println webview.Allowed("https://example.com", "greet"), webview.OriginOf("https://example.com/a")
println webview.SafeAssetPath("/a/"), webview.DataDir(), webview.AssetURL("/index.html"), webview.CurrentConfig().name
println webview.PackDir("www", "app.pack", "com.example.app")
webview.Command("greet", (c: webview.Call):
println c.command, c.args, c.origin, c.window, c.Str("name"), c.Int("n"), c.Bool("b"), c.Has("x")
c.ResolveStr("hello")
end)
webview.CommandAsync("slow", (c: webview.Call):
c.Resolve(`{"ok":true}`)
c.ResolveInt(1 as i64)
c.ResolveBool(true)
c.ResolveNull()
c.Reject("no")
end)
webview.On("ready", (data: str): webview.Emit("hello", data) end)
mut scripts := Vector {} as Vector<str>
scripts.push("window.started = true")
mut others := Vector {} as Vector<str>
others.push("https://example.org")
w := webview.Open(webview.WindowOptions {
label = "main", title = "App", width = 800, height = 600, min_width = 400, min_height = 300, url = "", html = "", icon = "", resizable = true, center = true, visible = true, context_menu = true, scripts = scripts, allow_navigation = others
})
w.OnClose((): ret webview.Confirm("Close", "Close the window?") end)
w.OnLoad((url: str, done: bool): println url, done end)
w.OnCrash((): w.Navigate(webview.AssetURL("/error.html")) end)
w.OnResize((x: int, y: int): println x, y end)
w.SetTitle("App")
w.SetSize(900, 700)
w.Show()
w.Focus()
w.Hide()
w.Minimize()
w.Maximize()
w.Eval("document.title")
w.Emit("hello", "1")
w.SetHTML("<h1>hello</h1>")
w.OpenDevTools()
println w.index, w.URL(), w.IsActive(), w.IsClosed(), w.Native() != null, webview.GetWindow("main").index
webview.Dispatch((): println "ui thread" end)
mut items := Vector {} as Vector<webview.MenuItem>
items.push(webview.Item("open", "Open"))
items.push(webview.Separator())
items.push(webview.MenuItem { id = "quit", label = "Quit", separator = false })
mut bar := Vector {} as Vector<webview.MenuItem>
bar.push(webview.Submenu("File", items))
webview.SetMenu(w, bar)
webview.OnMenu((id: str): println id end)
println webview.SetTray("icon.png", "App", items)
webview.OnTrayClick((): w.Focus() end)
webview.RemoveTray()
println webview.PickFolder("Folder"), webview.PickFile("File", "Text", "*.txt"), webview.SaveFile("Save", "a.txt")
webview.Message("Title", "Text")
println webview.Notify("Title", "Text"), webview.OpenURL("https://example.com")
webview.OnNotifyClick((): w.Focus() end)
webview.RequestAttention(w)
println webview.SecretSet("key", "value"), webview.SecretGet("key")
webview.SecretDelete("key")
println webview.LastError()
webview.Run()
webview.Quit()
w.Close()
endWindowOptions
struct WindowOptions| Name | Type | Description |
|---|---|---|
label | str = "main" | A name to find the window by, main by default. |
title | str = "" | The title. |
width | int = 1024 | The width in pixels. |
height | int = 768 | The height in pixels. |
min_width | int = 0 | The smallest width. |
min_height | int = 0 | The smallest height. |
url | str = "" | A remote site to load. Empty means index.html from the assets. |
html | str = "" | HTML to show directly instead of an address. |
icon | str = "" | The icon file. |
resizable | bool = true | The user can resize the window. |
center | bool = true | Start in the middle of the screen. |
visible | bool = true | Show the window at once. |
context_menu | bool = true | Allow the page right-click menu. |
scripts | Vector | JavaScript to install in every page and frame, before the page runs. |
allow_navigation | Vector | Other origins this window may navigate to. They get no access to commands. |
The example for this item is shown with the ones above: gui-webview-App.salam
Call
struct CallResolve methods or Reject, on any thread. A second answer is ignored, and the answer frees the text in the call, so read what you need first.| Name | Type | Description |
|---|---|---|
command | str = "" | The command name. |
args | str = "{}" | The arguments, as JSON text. |
origin | str = "" | The origin of the page that called. |
window | int = -1 | The number of the window that called. |
The example for this item is shown with the ones above: gui-webview-App.salam
Str
func Str(key: str): strThe example for this item is shown with the ones above: gui-webview-App.salam
Int
func Int(key: str): intThe example for this item is shown with the ones above: gui-webview-App.salam
Bool
func Bool(key: str): boolThe example for this item is shown with the ones above: gui-webview-App.salam
Has
func Has(key: str): boolThe example for this item is shown with the ones above: gui-webview-App.salam
Resolve
func Resolve(raw_json: str)The example for this item is shown with the ones above: gui-webview-App.salam
ResolveStr
func ResolveStr(value: str)The example for this item is shown with the ones above: gui-webview-App.salam
ResolveInt
func ResolveInt(value: i64)The example for this item is shown with the ones above: gui-webview-App.salam
ResolveBool
func ResolveBool(value: bool)The example for this item is shown with the ones above: gui-webview-App.salam
ResolveNull
func ResolveNull()The example for this item is shown with the ones above: gui-webview-App.salam
Reject
func Reject(message: str)The example for this item is shown with the ones above: gui-webview-App.salam
Window
struct Window| Name | Type | Description |
|---|---|---|
index | int = -1 | The number of the window. |
The example for this item is shown with the ones above: gui-webview-App.salam
Navigate
func Navigate(url: str)The example for this item is shown with the ones above: gui-webview-App.salam
SetHTML
func SetHTML(html: str)The example for this item is shown with the ones above: gui-webview-App.salam
Eval
func Eval(js: str)The example for this item is shown with the ones above: gui-webview-App.salam
Emit
func Emit(event: str, raw_json: str = "null")The example for this item is shown with the ones above: gui-webview-App.salam
SetTitle
func SetTitle(title: str)The example for this item is shown with the ones above: gui-webview-App.salam
SetSize
func SetSize(width: int, height: int)The example for this item is shown with the ones above: gui-webview-App.salam
Show
func Show()The example for this item is shown with the ones above: gui-webview-App.salam
Hide
func Hide()The example for this item is shown with the ones above: gui-webview-App.salam
Focus
func Focus()The example for this item is shown with the ones above: gui-webview-App.salam
Minimize
func Minimize()The example for this item is shown with the ones above: gui-webview-App.salam
Maximize
func Maximize()The example for this item is shown with the ones above: gui-webview-App.salam
Close
func Close()The example for this item is shown with the ones above: gui-webview-App.salam
URL
func URL(): strThe example for this item is shown with the ones above: gui-webview-App.salam
IsActive
func IsActive(): boolThe example for this item is shown with the ones above: gui-webview-App.salam
IsClosed
func IsClosed(): boolThe example for this item is shown with the ones above: gui-webview-App.salam
OpenDevTools
func OpenDevTools()The example for this item is shown with the ones above: gui-webview-App.salam
OnClose
func OnClose(handler: func(): bool)The example for this item is shown with the ones above: gui-webview-App.salam
OnLoad
func OnLoad(handler: func(str, bool))The example for this item is shown with the ones above: gui-webview-App.salam
OnCrash
func OnCrash(handler: func())The example for this item is shown with the ones above: gui-webview-App.salam
OnResize
func OnResize(handler: func(int, int))The example for this item is shown with the ones above: gui-webview-App.salam
Native
func Native(): void*The example for this item is shown with the ones above: gui-webview-App.salam
MenuItem
struct MenuItem| Name | Type | Description |
|---|---|---|
id | str = "" | What OnMenu receives. |
label | str = "" | The text. |
separator | bool = false | This entry is a line. |
children | Vector | The entries of a submenu. |
The example for this item is shown with the ones above: gui-webview-App.salam
Constants and variables
HINT_NONE
const HINT_NONE: i32 = 0The example for this item is shown with the ones above: gui-webview-Window.salam
HINT_FIXED
const HINT_FIXED: i32 = 1The example for this item is shown with the ones above: gui-webview-Window.salam
ENGINE_SYSTEM
const ENGINE_SYSTEM: str = "system""system": the web view of the operating system, the default.import gui.webview
func main:
println "Engine:", webview.Engine()
println "Name:", webview.EngineName()
if webview.Engine() == webview.ENGINE_CHROMIUM:
println "Chromium Embedded Framework"
end
if not webview.SupportsCommands():
println "No commands or events with this engine yet"
end
endENGINE_CHROMIUM
const ENGINE_CHROMIUM: str = "chromium""chromium": Chromium Embedded Framework, chosen at build time with -DSALAM_WEBVIEW_CEF.The example for this item is shown with the ones above: gui-webview-Engine.salam
Functions
Dispatch
func Dispatch(work: func())The example for this item is shown with the ones above: gui-webview-Window.salam
RunAll
func RunAll()Quit is called.The example for this item is shown with the ones above: gui-webview-Window.salam
Quit
func Quit()The example for this item is shown with the ones above: gui-webview-Window.salam
SetApp
func SetApp(id: str, name: str)The example for this item is shown with the ones above: gui-webview-Window.salam
SetDataDir
func SetDataDir(dir: str)The example for this item is shown with the ones above: gui-webview-Window.salam
RegisterScheme
func RegisterScheme(name: str, handler: func(Request): Response)The example for this item is shown with the ones above: gui-webview-Window.salam
SchemeURL
func SchemeURL(name: str, path: str): strapp://localhost/x, or https://app.localhost/x on Windows.The example for this item is shown with the ones above: gui-webview-Window.salam
SchemeOrigin
func SchemeOrigin(name: str): strThe example for this item is shown with the ones above: gui-webview-Window.salam
LastError
func LastError(): strThe example for this item is shown with the ones above: gui-webview-Window.salam
Trace
func Trace(text: str)SALAM_WEBVIEW_TRACE environment variable, and does nothing when it is unset. The backends use it to record each startup step, navigation and message, so a window that stays blank can be diagnosed, including in an application with no console.The example for this item is shown with the ones above: gui-webview-Window.salam
OnCommand
func OnCommand(handler: func(int))The example for this item is shown with the ones above: gui-webview-Window.salam
OnTrayMessage
func OnTrayMessage(handler: func(int))The example for this item is shown with the ones above: gui-webview-Window.salam
OnCopyData
func OnCopyData(handler: func(void*, int))WM_COPYDATA data sent to the message window.The example for this item is shown with the ones above: gui-webview-Window.salam
MenuHost
func MenuHost(): void*The example for this item is shown with the ones above: gui-webview-Window.salam
NameMessageWindow
func NameMessageWindow(title: str)The example for this item is shown with the ones above: gui-webview-Window.salam
NavigationIsMainFrame
func NavigationIsMainFrame(): boolOnNavigate: whether the page itself is navigating. WebKitGTK cannot tell a frame from the page, so on Linux this reports a user gesture instead.The example for this item is shown with the ones above: gui-webview-Window.salam
PostScript
func PostScript(): strOnMessage. The caller frees it.The example for this item is shown with the ones above: gui-webview-Window.salam
Create
func Create(debug: bool = false, visible: bool = true): WebViewThe example for this item is shown with the ones above: gui-webview-Window.salam
Engine
func Engine(): strENGINE_SYSTEM or ENGINE_CHROMIUM.The example for this item is shown with the ones above: gui-webview-Engine.salam
EngineName
func EngineName(): strThe example for this item is shown with the ones above: gui-webview-Engine.salam
SupportsCommands
func SupportsCommands(): boolThe example for this item is shown with the ones above: gui-webview-Engine.salam
OriginOf
func OriginOf(url: str): strThe example for this item is shown with the ones above: gui-webview-App.salam
Allowed
func Allowed(origin: str, command: str): boolThe example for this item is shown with the ones above: gui-webview-App.salam
PackDir
func PackDir(dir: str, out_path: str, key: str): intThe example for this item is shown with the ones above: gui-webview-App.salam
Init
func Init(config: Config)The example for this item is shown with the ones above: gui-webview-App.salam
CurrentConfig
func CurrentConfig(): ConfigThe example for this item is shown with the ones above: gui-webview-App.salam
DataDir
func DataDir(): strThe example for this item is shown with the ones above: gui-webview-App.salam
Allow
func Allow(origin: str, commands: Vector<str>)*. Call it before opening windows. Nothing remote can call anything by default.The example for this item is shown with the ones above: gui-webview-App.salam
Command
func Command(name: str, handler: func(Call))The example for this item is shown with the ones above: gui-webview-App.salam
CommandAsync
func CommandAsync(name: str, handler: func(Call))The example for this item is shown with the ones above: gui-webview-App.salam
On
func On(event: str, handler: func(str))The example for this item is shown with the ones above: gui-webview-App.salam
Emit
func Emit(event: str, raw_json: str = "null")The example for this item is shown with the ones above: gui-webview-App.salam
AssetURL
func AssetURL(path: str): strThe example for this item is shown with the ones above: gui-webview-App.salam
Open
func Open(options: WindowOptions): WindowIsClosed.The example for this item is shown with the ones above: gui-webview-App.salam
GetWindow
func GetWindow(label: str): WindowThe example for this item is shown with the ones above: gui-webview-App.salam
Run
func Run()Quit is called.The example for this item is shown with the ones above: gui-webview-App.salam
OpenURL
func OpenURL(url: str): boolThe example for this item is shown with the ones above: gui-webview-App.salam
PickFolder
func PickFolder(title: str = "Select a folder"): strThe example for this item is shown with the ones above: gui-webview-App.salam
PickFile
func PickFile(title: str = "Open", filter_name: str = "", patterns: str = ""): str*.txt;*.md.The example for this item is shown with the ones above: gui-webview-App.salam
SaveFile
func SaveFile(title: str = "Save", default_name: str = ""): strThe example for this item is shown with the ones above: gui-webview-App.salam
Message
func Message(title: str, text: str)The example for this item is shown with the ones above: gui-webview-App.salam
Confirm
func Confirm(title: str, text: str): boolThe example for this item is shown with the ones above: gui-webview-App.salam
Notify
func Notify(title: str, body: str, sound: str = ""): booldefault or alert. False when the system has no way to show it.The example for this item is shown with the ones above: gui-webview-App.salam
OnNotifyClick
func OnNotifyClick(handler: func())The example for this item is shown with the ones above: gui-webview-App.salam
RequestAttention
func RequestAttention(window: Window)The example for this item is shown with the ones above: gui-webview-App.salam
SecretSet
func SecretSet(key: str, value: str): boolThe example for this item is shown with the ones above: gui-webview-App.salam
SecretGet
func SecretGet(key: str): strThe example for this item is shown with the ones above: gui-webview-App.salam
SecretDelete
func SecretDelete(key: str)The example for this item is shown with the ones above: gui-webview-App.salam
Item
func Item(id: str, label: str): MenuItemThe example for this item is shown with the ones above: gui-webview-App.salam
Separator
func Separator(): MenuItemThe example for this item is shown with the ones above: gui-webview-App.salam
Submenu
func Submenu(label: str, items: Vector<MenuItem>): MenuItemThe example for this item is shown with the ones above: gui-webview-App.salam
OnMenu
func OnMenu(handler: func(str))The example for this item is shown with the ones above: gui-webview-App.salam
SetMenu
func SetMenu(window: Window, items: Vector<MenuItem>)The example for this item is shown with the ones above: gui-webview-App.salam
SetTray
func SetTray(icon: str, tooltip: str, items: Vector<MenuItem>): boolThe example for this item is shown with the ones above: gui-webview-App.salam
RemoveTray
func RemoveTray()The example for this item is shown with the ones above: gui-webview-App.salam
OnTrayClick
func OnTrayClick(handler: func())The example for this item is shown with the ones above: gui-webview-App.salam
SingleInstance
func SingleInstance(on_second: func(Vector<str>)): boolThe example for this item is shown with the ones above: gui-webview-App.salam
SafeAssetPath
func SafeAssetPath(request_path: str): strThe example for this item is shown with the ones above: gui-webview-App.salam