///|
/// High-level managed app that owns the parent dispatcher and child webview
/// process lifecycle.
pub struct Window {
label : String
title : String
width : Int
height : Int
size_hint : SizeHint
debug : Int
devtools : Bool
child_arg : String
mut frameless : Bool
mut resizable : Bool
mut closeable : Bool
mut always_on_top : Bool
mut transparent : Bool
mut title_bar_style : TitleBarStyle
mut title_bar_overlay : Bool
mut traffic_light_position : (Int, Int)
position : (Int, Int)
hidden : Bool
focused : Bool
enable_window_controls_plugin : Bool
mut url : String
mut html : String
pending_custom_protocols : Array[(String, String)]
mut runtime_window_id : Int
plugins : Array[Plugin]
}
///|
/// Creates a managed app. The library handles the parent dispatcher and child
/// webview process automatically.
#alias(new, deprecated="Use `Window()` instead")
pub fn Window::Window(
label? : String = "",
title? : String = "MoonBit WebView",
url? : String = "",
width? : Int = 800,
height? : Int = 600,
size_hint? : SizeHint = None,
debug? : Int = 0,
devtools? : Bool = false,
child_arg? : String = "--moonbit-webview-child",
frameless? : Bool = false,
resizable? : Bool = true,
closeable? : Bool = true,
always_on_top? : Bool = false,
transparent? : Bool = false,
title_bar_style? : TitleBarStyle = Default,
title_bar_overlay? : Bool = false,
traffic_light_position? : (Int, Int) = (-1, -1),
position? : (Int, Int) = (-1, -1),
hidden? : Bool = false,
focused? : Bool = true,
enable_window_controls_plugin? : Bool = true,
) -> Window {
{
label,
title,
url,
width,
height,
debug,
devtools,
child_arg,
frameless,
resizable,
closeable,
always_on_top,
transparent,
title_bar_style,
title_bar_overlay,
traffic_light_position,
position,
hidden,
focused,
enable_window_controls_plugin,
html: "",
pending_custom_protocols: [],
runtime_window_id: -1,
plugins: [],
size_hint,
}
}
///|
/// Returns the stable label used for cross-window addressing.
/// Falls back to the `title` when no explicit label was provided.
pub fn Window::label(self : Window) -> String {
if self.label.is_empty() {
self.title
} else {
self.label
}
}
///|
/// Applies native custom-window style flags.
pub fn Window::set_window_customization(
self : Window,
frameless : Bool,
resizable : Bool,
closeable : Bool,
always_on_top : Bool,
transparent : Bool,
title_bar_style : TitleBarStyle,
title_bar_overlay : Bool,
) -> Unit {
self.frameless = frameless
self.resizable = resizable
self.closeable = closeable
self.always_on_top = always_on_top
self.transparent = transparent
self.title_bar_style = title_bar_style
self.title_bar_overlay = title_bar_overlay
if self.runtime_window_id > 0 {
ignore(
wm_set_window_customization(
self.runtime_window_id,
if frameless {
1
} else {
0
},
if resizable {
1
} else {
0
},
if closeable {
1
} else {
0
},
if always_on_top {
1
} else {
0
},
if transparent {
1
} else {
0
},
title_bar_style,
if title_bar_overlay {
1
} else {
0
},
),
)
}
}
///|
/// Set macOS traffic-light buttons position.
pub fn Window::set_traffic_light_position(
self : Window,
x : Int,
y : Int,
) -> Unit {
self.traffic_light_position = (x, y)
if self.runtime_window_id > 0 {
ignore(
@window_manager.wm_set_traffic_light_position(
self.runtime_window_id,
x,
y,
),
)
}
}
///|
/// Installs a managed plugin into the app.
pub fn Window::install(self : Window, plugin : Plugin) -> Unit {
self.plugins.push(plugin)
}
///|
/// Sets inline HTML content for the child webview.
pub fn Window::set_html(self : Window, html : String) -> Unit {
self.html = html
if self.runtime_window_id > 0 {
ignore(
@window_manager.wm_set_html(
self.runtime_window_id,
@encoding/utf8.encode(html),
),
)
}
}
///|
pub fn Window::navigate(self : Window, url : String) -> Unit {
self.url = url
if self.runtime_window_id > 0 {
ignore(
@window_manager.wm_navigate(
self.runtime_window_id,
@encoding/utf8.encode(url),
),
)
}
}
///|
/// Register a custom scheme for the child webview before it navigates.
pub fn Window::set_custom_protocol(
self : Window,
scheme : String,
root_dir : String,
) -> Unit {
self.pending_custom_protocols.push((scheme, root_dir))
}
///|
/// Runs the managed app end-to-end.
pub async fn Window::run(self : Window) -> Unit {
let args = @env.args()
if args.length() > 1 && args[1] == self.child_arg {
guard WindowManager::connect_child_process() == 0 else {
abort("ManagedApp::run: connect child process failed")
}
self.run_child_async()
return
}
let wm = WindowManager::init()
guard args.length() > 0 else { abort("ManagedApp::run: missing argv[0]") }
let child_pid = wm.spawn_process(args[0], self.child_arg)
guard child_pid > 0 else {
abort("ManagedApp::run: spawn webview process failed")
}
self.build_router().serve(wm, child_pid)
}
///|
/// Encodes a unique child-process marker used to carry a globally-unique
/// window-id `base` and a stable `label` across a re-exec`ed child process.
pub fn child_arg_for(base : Int, label : String) -> String {
"--lepus-child:" + base.to_string() + ":" + label
}
///|
/// Detects whether the current process was spawned as a Lepus multi-window
/// child.
///
/// Returns `(window_id_base, label)` when argv carries a
/// `--lepus-child::