pub struct Launcher { /* private fields */ }Implementations§
Source§impl Launcher
impl Launcher
pub fn chrome(self, chrome: Chrome) -> Self
Sourcepub fn frame_latency(self, frames: u32) -> Self
pub fn frame_latency(self, frames: u32) -> Self
How many frames may be queued ahead of the one on screen, for every
window (backlog C47). Two by default
(kui_wgpu::DEFAULT_FRAME_LATENCY): every vsync gets a frame at
light load, where one lost 1–6% of them on macOS. On macOS 14+ the
runner starts frames that run back to back at the display’s vsync
(mod pacer), so the second queued frame is slack and costs no
latency; where it cannot — Linux, a pumped runner — such a frame
reaches the screen a vsync later than with one. One on Windows,
where one already delivered every vsync (RG46). KUI_FRAME_LATENCY
overrides it, and KUI_FRAME_PACING=0 turns the pacing off, for
comparing without a rebuild. Values below one are one.
Sourcepub fn diagnostics(self, on: bool) -> Self
pub fn diagnostics(self, on: bool) -> Self
Whether the core looks for silent misconfigurations and the runner
prints them to stderr (see kui_core::diag). Default: on in debug
builds, off in release — a shipped app stays quiet, a development
build says why the grow weight did nothing.
Sourcepub fn devtools(self, on: bool) -> Self
pub fn devtools(self, on: bool) -> Self
Opens the app inside the core’s devtools panel
(docs/adr/0024-the-devtools-are-the-cores.md): the event stream,
the facts and the tree, docked beside the app’s own tree.
KUI_DEVTOOLS=1 in the environment is the same ask for an app
that never made it. Sugar for setup_core(|c| c.set_devtools(on)).
Sourcepub fn devtools_key(self, key: Accel) -> Self
pub fn devtools_key(self, key: Accel) -> Self
Respells the chord that moves the keyboard into the devtools panel
and back out — and brings a hidden panel back — from its default
Ctrl+Shift+I: Accel::parse("f12"), "mod+shift+d", any
spelling a menu item takes. The panel’s other chords stay
Ctrl+Shift+<letter>; with another chord set, Ctrl+Shift+I is
the app’s again. Sugar for setup_core(|c| c.set_devtools_key(key)).
Sourcepub fn setup_core(self, f: impl FnOnce(&mut Core) + 'static) -> Self
pub fn setup_core(self, f: impl FnOnce(&mut Core) + 'static) -> Self
Runs f on the main window’s core before its first frame — the
place for what a core is told rather than declared: the devtools
doors, a pinned theme, set_native_menus. Every call adds one;
they run in order.
Sourcepub fn core(self, core: Core) -> Self
pub fn core(self, core: Core) -> Self
Opens the main window on core rather than on one the launcher
makes: everything the host registered on it beforehand — fonts,
images, sounds, tokens, a pinned theme, the devtools doors,
set_native_menus, the text-cache budget — reaches the window,
and the core’s session is the app’s, so a declared second window
joins it and the handles a headless frame minted keep drawing. What
the launcher is told still applies on top, in the order it always
has: Launcher::diagnostics (or the build’s default), then
KUI_DEVTOOLS, then every Launcher::setup_core. A C host
registers on a context and hands it to kui_run_with, which is
this door (backlog AR27); a Rust host that built a core to draw
headless first has it too.
Sourcepub fn deferred_events(self) -> Self
pub fn deferred_events(self) -> Self
Says that this app answers an event after on_event returns —
which only a host driving the loop itself can do, since only it has
a turn between pumps (Launcher::open, PumpRunner). Node’s
update is the case: on_event keeps the event, the pump returns,
and JS runs the handler and submits the next view.
What it changes is one thing: an input whose events reached the app
does not ask for the frame itself. Ordinarily it does, and for
an app that answered inside on_event that frame is right — it
shows the button let go and what letting go did. For one that has
not answered yet the same frame shows the button let go and the
count still at its old value, with the new one a pump later: a
two-frame release, plain to see at an 8 ms pump. Declining to ask
leaves the frame to the host, which asks
(PumpRunner::request_redraw, and every setView and drained
pollEvents does) once its handler has run, so the release and its
answer land in one frame.
Nothing else is suppressed. A transition, a caret blink, a
first-frame retry, a Waker wake or the OS’s own repaint still
paint whenever they ask, including during a platform’s modal
move-resize loop, and an input that reached nobody still asks for
its own frame — so the worst this can cost is that a frame some
other subsystem asked for in the same pump shows the input’s
answer one frame late.
Sourcepub fn system(self, pinned: SystemEnv) -> Self
pub fn system(self, pinned: SystemEnv) -> Self
Pins part of env.system for this app’s windows: every field of
pinned that is not “cannot tell” is what the views read, over
whatever the OS says, for as long as the app runs; the fields left
at their default keep following the OS, and a change to one of
those still arrives as the system event, carrying the pin with it.
kui_native::app("mine").system(SystemEnv { motion: MotionPref::Reduced, ..Default::default() });For looking at the window a user who asked for less motion, or a
dark appearance, would get — on a machine whose owner asked for
neither. The headless core takes the same reading through
core.env.system and needs none of this; a window cannot, because
its runner writes the real reading before every frame, which is
why there is no set_env on one and this is on the launcher
instead: the app asking in its own code, the same place
KUI_SMOKE_FRAMES was kept out of a shipped build for — an app you
ship should not change its motion because of a variable in the
environment it was launched from (backlog F47).
Sourcepub fn icon(self, rgba: Vec<u8>, width: u32, height: u32) -> Self
pub fn icon(self, rgba: Vec<u8>, width: u32, height: u32) -> Self
The icon every window of the app is created with: rgba is
width × height pixels, four bytes each, row by row from the top
left, alpha not premultiplied. Windows
shows it in the title bar, Alt-Tab and the taskbar and X11 in the
window manager’s; macOS draws the bundle’s .icns in the Dock and
Wayland the .desktop file’s icon, and neither has a window icon,
so there it is nothing. Something a taskbar can shrink cleanly —
64 to 256 px. Panics when the pixels are not that size, a
programming error at startup; Launcher::try_icon says why
instead.
kui_native::app("mine").icon(rgba, 64, 64);A Windows program’s own icon is a resource linked into its
executable, where Explorer finds it — and winit does not give it to
the windows; Launcher::icon_resource does, and wins over the
pixels there.
Sourcepub fn try_icon(
self,
rgba: Vec<u8>,
width: u32,
height: u32,
) -> Result<Self, String>
pub fn try_icon( self, rgba: Vec<u8>, width: u32, height: u32, ) -> Result<Self, String>
Launcher::icon for pixels that came from outside the program —
Node’s icon option, C’s kui_set_icon — refused with the reason
rather than a panic. The launcher is consumed either way, as
Launcher::try_extension_as’s is.
Sourcepub fn icon_resource(self, id: u16) -> Self
pub fn icon_resource(self, id: u16) -> Self
The executable’s icon resource id as every window’s icon, on
Windows: the .ico a 1 ICON "app.ico" line in the program’s .rc
links in, the one Explorer already draws for the file — each of the
title bar and the taskbar loads the frame drawn for its own size.
A resource the executable does not have is said once on stderr, and
Launcher::icon’s pixels are used if there are any. Nothing on
other platforms, so an app passes both and each OS takes its own.
Sourcepub fn custom_titlebar(self) -> Self
pub fn custom_titlebar(self) -> Self
Shorthand for .chrome(Chrome::Custom).
Sourcepub fn borderless(self) -> Self
pub fn borderless(self) -> Self
Shorthand for .chrome(Chrome::Borderless).
Sourcepub fn size(self, w: f64, h: f64) -> Self
pub fn size(self, w: f64, h: f64) -> Self
Initial inner size, logical px (KUI_WINDOW=WxH still overrides).
Clamped into the min_size/max_size bounds, as the OS would.
Sourcepub fn min_size(self, w: f64, h: f64) -> Self
pub fn min_size(self, w: f64, h: f64) -> Self
Smallest inner size the user may resize the window to, logical px. The OS enforces it; the initial size is clamped up into it.
Sourcepub fn max_size(self, w: f64, h: f64) -> Self
pub fn max_size(self, w: f64, h: f64) -> Self
Largest inner size the user may resize the window to, logical px.
A bound below the matching min_size loses to it, as on the OS side.
Sourcepub fn extension(self, ext: impl Extension + 'static) -> Self
pub fn extension(self, ext: impl Extension + 'static) -> Self
Loads ext under its own name as its namespace — import fs binds
fs. The slots it fills are declared as ui.slot("<name>/<slot>")
(ADR 0014). Panics when the name is already another extension’s
namespace: two of one name need extension_as.
Sourcepub fn extension_as(
self,
namespace: impl Into<String>,
ext: impl Extension + 'static,
) -> Self
pub fn extension_as( self, namespace: impl Into<String>, ext: impl Extension + 'static, ) -> Self
Loads ext under namespace — import fs as left. The host
decides the namespace, so the same plugin loaded twice is two
namespaces, two sets of slots and two sets of params. Panics on a
namespace already taken, an empty one, or an extension whose slot
names contain /: all three are programming errors at startup.
Sourcepub fn try_extension_as(
self,
namespace: impl Into<String>,
ext: impl Extension + 'static,
) -> Result<Self, String>
pub fn try_extension_as( self, namespace: impl Into<String>, ext: impl Extension + 'static, ) -> Result<Self, String>
extension_as for a caller that has to report the refusal rather
than die of it — a plugin path that came from outside the program,
which is Node’s extensions option. The launcher is consumed
either way: a host that cannot load the extension it was told to
load has nothing useful left to run.
Sourcepub fn with_extensions(self, extensions: Extensions) -> Self
pub fn with_extensions(self, extensions: Extensions) -> Self
A list already loaded, replacing any extension calls before it —
what a C host built into a context with kui_ctx_add_extension
and hands to kui_run_with, so that the one loader and its error
channel serve the window too.
Sourcepub fn extensions(self, exts: Vec<Box<dyn Extension>>) -> Self
pub fn extensions(self, exts: Vec<Box<dyn Extension>>) -> Self
extension for each, in order.
pub fn run<A: App>(self, app: A) -> Result<(), Box<dyn Error>>
Sourcepub fn open<A: App>(self, app: A) -> Result<PumpRunner<A>, Box<dyn Error>>
pub fn open<A: App>(self, app: A) -> Result<PumpRunner<A>, Box<dyn Error>>
Opens the window but keeps the event loop in the caller’s hands: the
returned PumpRunner processes OS events only when PumpRunner::pump
is called, so a foreign loop (Node/libuv, a game loop, a test harness)
can interleave with winit on the main thread. One event loop per
process — winit event loops are not recreatable on any desktop
platform — but any number of windows on it, and any number of
runners in turn: a runner whose main window has closed parks the
loop, and the next open on the thread takes it back (backlog
F58), so a process can open a window, close it, and open another.
Auto Trait Implementations§
impl !Freeze for Launcher
impl !RefUnwindSafe for Launcher
impl !Send for Launcher
impl !Sync for Launcher
impl !UnwindSafe for Launcher
impl Unpin for Launcher
impl UnsafeUnpin for Launcher
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.