DatumHueEnterprise v0.0.24datumhue.com
Contents

Write a window manager or launcher

Frame the apps you start in windows of your own design, raise them when pressed, decide what Back does in them, reserve shortcuts, and ask the person using the workstation about permissions.

A window manager is an ordinary app that starts other apps and arranges them; the workstation's own is one. The functions in datumhue.wm work on the apps yours manages: the ones it started, and theirs. When you run a program with datumhue run, it is the root app, and manages every app it starts.

Frame each app

wm.wrap_app puts an app in a frame and returns the frame, a UiElement. Its insets reserve room around the app for your decorations: a title bar on top, a border on the other sides. Build the decorations on the frame as you build any UI. Wrap each app as the app_spawned event reports it, unless its has_ui is false: a service app has no window to frame.

This program frames two apps with a title bar and a Close button, raises a window when it is pressed, minimizes a window on an unhandled Back, and cycles through the windows with Control+Tab:

wm.lualua
local wm = datumhue.wm
local token = datumhue.theme.token
local BAR = 36

-- The framed apps, in the order they opened.
local windows = {}

-- Frame each app as it opens: a title bar with a Close button.
datumhue.events.on("app_spawned", function(e)
    -- A service app has no window to frame.
    if not e.has_ui then
        return
    end
    local app = e.app
    local frame = wm.wrap_app(app, {
        top = BAR,
        left = 2,
        right = 2,
        bottom = 2,
    })
    frame.color = token("panel_border")
    local bar = frame:panel({
        width = "100%",
        height = BAR,
        flex_direction = "row",
        align_items = "center",
        justify_content = "space_between",
        padding = { left = 12, right = 4 },
    })
    bar:label({ text = e.app_name })
    bar:button({
        text = "Close",
        on_click = function()
            wm.terminate_app(app)
        end,
    })
    -- A Back the app leaves unhandled minimizes its window.
    frame:on_cancel(function()
        wm.set_app_minimized({ app = app, minimized = true })
    end)
    table.insert(windows, app)
end)

-- Forget a window when its app ends.
datumhue.events.on("app_terminated", function(e)
    for i, app in ipairs(windows) do
        if app == e.app then
            table.remove(windows, i)
            break
        end
    end
end)

-- Bring a window forward and give it focus.
local function raise(app)
    wm.set_app_minimized({ app = app, minimized = false })
    wm.set_app_focused(app)
end

-- A press anywhere in a window raises it.
datumhue.events.on("app_frame_pressed", function(e)
    raise(e.app)
end)

-- Control+Tab raises the next window in turn.
local turn = 0
wm.grab_input({
    chords = { { key = "tab", modifiers = { "control" } } },
    on_press = function()
        if #windows > 0 then
            turn = turn % #windows + 1
            raise(windows[turn])
        end
    end,
})

-- Two apps to manage.
datumhue.app.spawn({
    name = "notes",
    code = 'datumhue.ui.root:label({ text = "Notes go here" })',
    x = 60,
    y = 100,
    width = 320,
    height = 240,
})
datumhue.app.spawn({
    name = "paint",
    code = [[
local canvas = datumhue.draw.new({ width = 200, height = 150 })
canvas:mount({ width = 200, height = 150 })
canvas:circle({ radius = 60, color = datumhue.color("#e67e80") })
]],
    x = 420,
    y = 160,
    width = 320,
    height = 240,
})

In this example: datumhue.wm datumhue.theme.token datumhue.events.on datumhue.wm.wrap_app UiElement.color UiElement:panel UiElement:label UiElement:button datumhue.wm.terminate_app UiElement:on_cancel datumhue.wm.set_app_minimized datumhue.wm.set_app_focused datumhue.wm.grab_input datumhue.app.spawn

wm.set_app_bounds moves and resizes a window, wm.set_app_minimized hides and restores it, and wm.set_frame_insets changes a frame's insets, to hide the title bar of a window gone full screen. Removing a frame hands its app back unframed.

Raise the pressed window

Windows stack with the most recently focused on top. wm.set_app_focused gives an app focus, which brings its window to the front. A press anywhere in a frame, on your decorations or in the app, reaches you as the app_frame_pressed event, so the program answers it by raising that window.

The root app's own UI is the workstation's base layer: focusing it gives it input without covering the windows it manages.

Decide what Back does

A Back an app leaves unhandled (Escape, gamepad B, a browser's or phone's back) reaches the frame you wrapped it in. Set UiElement:on_cancel on the frame to decide what Back means there: the program minimizes the window; a phone-style manager might show its home screen. A frame without a handler passes the request on to your own UI, and from there toward the root.

wm.send_cancel delivers a Back to an app as if the person had pressed it, for a Back button in your title bar. Handle Back covers Back inside an app.

Reserve shortcuts

wm.grab_input reserves key chords and gamepad buttons for your window manager: a grabbed press, made while your app or one it manages has focus, goes to your on_press and to no app. The program's Control+Tab raises the next window on each press. A switcher that shows a list instead steps its selection in on_press and switches in on_release, which runs once as Control comes up. wm.GrabOptions says which keys and buttons you can grab.

Ask about permissions

When an app asks for a permission it does not hold, with app.request_permission or by a manifest that requires it, its parent gets the app_permission_request event. Its request is a PermissionRequest: answer with PermissionRequest:grant or PermissionRequest:deny, now or once the person has chosen. The asking app waits until you answer, and a request you drop unanswered is denied. When the parent has no handler for the event, the request is denied at once.

Describe the permission with app.permission_summary: one plain sentence about what it allows, in your app's language, the same words the workstation's own prompts use.

lua
datumhue.events.on("app_permission_request", function(e)
    local request = e.request
    local card = datumhue.ui.root:panel({ padding = 16, gap = 8 })
    card:label({ text = datumhue.app.permission_summary(e.permission) })
    card:button({
        text = "Allow",
        on_click = function()
            request:grant()
            card:remove()
        end,
    })
    card:button({
        text = "Don't allow",
        on_click = function()
            request:deny()
            card:remove()
        end,
    })
end)

Apps you have not framed

An app you start but do not frame opens in the window of the nearest app above it that has one, or at the top level when no app but the root is above it. app.spawn describes exactly where. It moves, hides and stacks with that window. Wrapping it later lifts it into a frame of its own.

An app started with a host lives in an element of its parent instead (Launch other apps). Its app_spawned reaches you as any app's does, but wm.wrap_app, wm.set_app_bounds and wm.set_app_minimized raise for it: the element places and shows it.

Recover from a failed start

When the workstation starts with errors, it launches @datumhue/fallback as the root app in place of the usual one, from the namespace the workstation starts from. The fallback reads the errors with app.errors and holds the root app's powers, so it can show what went wrong and start what still works.

See also

Reference used on this page: datumhue.wm datumhue.theme.token datumhue.events.on datumhue.wm.wrap_app UiElement.color UiElement:panel UiElement:label UiElement:button datumhue.wm.terminate_app UiElement:on_cancel datumhue.wm.set_app_minimized datumhue.wm.set_app_focused datumhue.wm.grab_input datumhue.app.spawn datumhue.ui.root datumhue.app.permission_summary UiElement:remove PermissionRequest:deny datumhue.wm.set_app_bounds datumhue.wm.set_frame_insets datumhue.wm.send_cancel wm.GrabOptions datumhue.app.request_permission PermissionRequest:grant datumhue.app.errors

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