DatumHueEnterprise v0.0.24datumhue.com
Contents

How your app runs

Your app's script runs once when the app starts; after that, DatumHue calls the callbacks your script registered, until something ends the app. What keeps an app running depends on whether it has a window.

The script and its callbacks

The script body is your app's start: it runs once, top to bottom, when the app starts. Read the arguments it was launched with from datumhue.args.argv. The body may wait on slow work, such as loading an image or reading a file: it pauses there and goes on when the result is ready (Waiting).

Everything after that happens in callbacks, functions your app hands to DatumHue to call later:

CallbackRegistered withRuns
Per-frame handlerdatumhue.on_updateonce a frame, with the seconds since its last run
Timerdatumhue.time.after, datumhue.time.everywhen its time comes, before that frame's per-frame handler
UI handlera widget's on_click and its other on_ keyswhen someone uses the widget
Subscriptiondatumhue.events.on, datumhue.messaging.subscribewhen the event or message arrives

A timer's callback gets dt, the seconds the timer ran since its last fire, or since it started for the first, leaving out any time it was paused. A repeating timer that falls behind, because a frame or a callback runs long or a callback waits for a result, fires once, with a dt that covers the whole gap.

An app runs one callback at a time. Each runs to its end before the next one starts, so your app never sees one of its callbacks half done.

A callback that runs long goes on into the next frames. Until it ends, what someone types or presses on a gamepad waits instead of reaching your app's widgets, and DatumHue leaves your app's focus as the callback leaves it, even on a widget the callback hid. When the callback ends, the waiting input arrives in order, at the widget focused then. A call that waits for a result (Waiting) is a pause, not a long run: your widgets get input while it waits.

DatumHue picks the handlers that hear an event only between your app's callbacks, never part-way through one, and the script body counts as a callback here. So an event a callback causes, such as the app_spawned of an app it starts, reaches a handler the callback subscribes after causing it. A click someone makes while the callback runs, on a widget the callback then removes, reaches no handler. A call that waits for a result opens such a gap too, so subscribe before that call, not after it.

UI apps and service apps

An app is either a UI app, with a window, or a service app, with none.

UI appService app
Windowa root container that holds its UInone: the namespaces the reference marks "UI apps only" are missing
Started bydatumhue run app.lua, or a packagedatumhue run --service app.lua, or a package with service #true
Endsonly when something ends italso as soon as nothing is registered

A UI app stays open with no callbacks at all: its window is reason enough. A service app lives only while it has something left to do. These count as registered:

  • the per-frame handler;
  • a timer that has fires left;
  • a subscription: events, messages, document watchers, input feeds, and anything else that returns a Subscription;
  • a callback on something the app owns: a widget handler, a collision callback, an animation's callback, a route hook;
  • a call that is still waiting for its result.

When the last of these is gone, the service app ends. This one ticks three times, then stops its timer, and with it the app:

ticker.lualua
local ticks = 0
local timer
timer = datumhue.time.every(0.2, function()
    ticks = ticks + 1
    print("tick " .. ticks)
    if ticks == 3 then
        timer:unsubscribe()
        print("stopped: nothing is registered")
    end
end)

In this example: datumhue.time.every

Run it as a service app, and it prints three ticks, then ends on its own:

sh
$ datumhue run --service ticker.lua

How an app ends

An app ends when:

  • it calls datumhue.app.terminate;
  • an app that manages it calls datumhue.wm.terminate_app on it;
  • the app that started it ends: ending an app ends every app it started, and every app those started;
  • an error escapes one of its callbacks (below);
  • one of its callbacks runs past the step limit it was started with, without pausing (Launch other apps);
  • it is a service app with nothing registered.

Everything the app made goes with it: its window, its widgets, its drawings and its timers. If it had focus, the frontmost app left takes focus. The app that started it hears it end through the app_terminated event (Launch other apps).

To save state on the way out, register a handler with datumhue.on_terminate. It runs once, within a short time limit, before the cleanup. It does not run after a crash, cannot stop the ending, and does not keep a service app alive.

An app that ends itself then runs the __gc finalizers of the tables it still has, once each, as Lua does when it closes, within a time limit of their own as short as the handler's. An app that crashed, in its handler too, or that another app ended runs none.

When a callback errors

An error that escapes any callback ends your app. The script body, the per-frame handler, timers, UI handlers and subscriptions all follow this one rule. The log names your app and shows the error with its traceback, and the whole app ends as above, never just the part that failed. Other apps are untouched, and when the app is the one datumhue run started, the command exits with a failure code.

To survive an error, catch it where it can happen: call the risky part with pcall inside the callback, and handle the result. A caught error ends nothing. Some callbacks run on the spot, inside one of your own calls, as a router's page builder does. An error in one of those raises at that call, so a pcall around the call catches it too.

Sessions

Every launch has a session, an id that tells it apart from other launches running at the same time. Every app of the launch reads it with datumhue.app.session. A launch starts with a fresh session.

A launch can name its session with --session, or take the most recent one again with --continue. In a browser a launch is one tab: its session lasts through reloads of the tab and ends when the tab closes.

The app window

A UI app's window is its root container. A window manager places, sizes and stacks it, and nothing your app shows reaches outside it. Inside is the content area, where your UI lives: everything you build on datumhue.ui.root, and every canvas or image you mount without naming a parent, lands there.

text
root container    placed by the window manager, clips its contents
+-- content area  fills the root container
    +-- your panels, labels, buttons, canvases ...

datumhue.screen works on the window of the app that calls it. The root app, usually the window manager, drives the whole workstation window; any other app drives its own root container:

CallFrom the root appFrom any other app
datumhue.screen.fullscreenthe workstation window goes full screenasks the window manager to maximize its root container
datumhue.screen.request_resolutionasks for a workstation window sizeasks for a root container size
datumhue.screen.width, datumhue.screen.heightthe workstation window's sizeits root container's size

A request is a proposal: the window manager answers it, and the size properties report what is in effect. Fit any window size shows how to follow size changes, and Write a window manager or launcher how windows get their frames.

See also

Reference used on this page: datumhue.on_update datumhue.time.after datumhue.time.every datumhue.events.on datumhue.messaging.subscribe datumhue.screen.fullscreen datumhue.screen.request_resolution datumhue.screen.width datumhue.screen.height datumhue.args Subscription:unsubscribe Timer:unsubscribe datumhue.app.terminate datumhue.wm.terminate_app datumhue.on_terminate datumhue.app.session datumhue.ui.root datumhue.screen

datumhue.com

(c) 2026 Shuusei AB. Quote excerpts of this manual, with attribution to DatumHue, in your own documentation, tutorials, course materials, reviews, and other writing or video. Republishing it in whole or in substantial part needs written permission: support@datumhue.com.

Victor Mono is licensed under the SIL Open Font License 1.1
Copyright (c) 2024, Rune Bjørnerås (https://github.com/rubjo)

This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL


-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------

PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.

The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.

DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.

"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).

"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).

"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.

"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.

PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:

1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.

2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.

3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.

4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.

5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.

TERMINATION
This license becomes null and void if any of the above conditions are
not met.

DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Try

    ↑↓ selectEnter openTab filter

    Settings

    Theme
    Text
    Print

    Keyboard shortcuts

    / or Ctrl KSearch
    ↑ ↓ EnterPick a result
    TabNext result filter
    j kNext or previous entry
    [ ]Previous or next page
    yCopy a link to the current entry
    ?These shortcuts
    EscClose

    On this page