Script-Created Windows
An active placed Scripted Decoration can create one or more TaskManSync-owned Windows. A Window is another surface of the same script, not a new script type or a way to control other applications’ windows. This complete example opens a small editor from the taskbar and applies a numeric value to the Decoration:
local window
function applyValue(actionId)
local value, err = window:getInput("count")
if value == nil then
if err then log.error(err.message) end
return
end
decoration.text = "Count: " .. value
end
function onLoad()
decoration.text = "Click to edit count"
local err
window, err = ui.createWindow({ title = "Counter", width = 400, height = 240, visible = false })
if not window then
log.error(err.message)
return
end
local ok, contentError = window:setContent({
inputs = {
{ id = "count", kind = "number", label = "Count", value = 0,
minimum = 0, maximum = 999, required = true },
},
actions = {
{ id = "apply", label = "Apply", callback = "applyValue" },
},
})
if not ok then log.error(contentError.message) end
end
function onTaskLeftClick()
if window then window:toggleVisibility() end
endThe returned Window handle is opaque. It does not expose a Qt object, QML object, native Window handle, or arbitrary native properties. Content/action calls return true on admission or nil, error; check failures rather than assuming an invalid content value was installed. Define named action functions before calling setContent().
Window creation options:
| Option | Contract |
|---|---|
title | UTF-8 string, up to 1,024 bytes |
width | Integer 160..4096; default 400 |
height | Integer 160..4096; default 240 |
visible | Boolean; default true |
A Window can be shown, hidden, closed, resized, activated, minimized, restored, maximized, or made fullscreen. The main content is supplied through window:setContent(...).
A Window can also receive focused key presses through a global callback such as this addition to the example above:
function onKey(key, modifiers)
if key == "Escape" and modifiers.ctrl then
window:hide()
end
endOnly semantic key names and modifier booleans are delivered. The callback has no Window ID, so a multi-window script cannot identify the originating Window from its arguments. There are no raw Qt key events, key-release callbacks, global keyboard subscriptions, or key-state polling. When a focused Window is fullscreen, Escape restores normal presentation and is consumed by TaskManSync before Lua receives it. See UI reference for supported key names.
A realized Window can also receive size changes through onResize(windowId, dimensions). The callback receives the logical Window ID, positive columns and rows, and the full surface aspect ratio. Resize delivery is coalesced, and Settings/preview logical Windows do not receive resize notifications.
Window visibility has an important distinction: isVisible() reports logical visibility, not whether the Window currently has focus or is unobscured. A native close or explicit close() can be followed by another show(), which recreates the transient native realization when the logical Window remains valid.
Minimizing leaves logical visibility true. show() also restores, raises, and requests activation of an already-visible Window; the window system may deny activation. toggleVisibility() shows/foregrounds a hidden or inactive Window, but hides a visible active one. raise() and activate() alone do not show a hidden Window.
onClose(windowId) reports explicit close or the native close button; onHide(windowId) reports a visible-to-hidden transition. Closing a Window does not stop the script, periodic updates, or scheduled alarms. Hide does not persist closed state, but close records a private host-managed marker. After reload, a Window created in the same creation order stays closed until show() or toggleVisibility() reopens it, even if its creation options say visible = true. Keep creation order stable when relying on this behavior. Only the closed marker is automatic: Window content, input values, size, and Lua variables are not saved. Persist application values explicitly in storage.
Removing the placement, reloading, faulting, a hand-off to another applet, or shutdown destroys the native Windows and invalidates the old generation’s handles. onStop() is script teardown, not Window closure.
In Settings and preview, ui.createWindow() returns a preview-safe logical handle. The API calls are validated, but they do not create a real top-level window or send GUI commands. “Logical only” means the Window exists only as a validated scripting object for preview purposes; it has no native window behind it. Scripts should not contain separate preview-mode logic.
Window Content
window:setContent(content) replaces the complete logical content. The supported content can include:
- text;
- typed actions;
- semantic inputs;
- animated update opportunities;
- positioned text;
- lines;
- paths;
- Cell Space;
- supported visual buttons.
The content table has text, inputs, actions, animated, and visual fields. Ordinary Window text is a UTF-8 string, not taskbar TDML. Inputs belong in inputs, with their id, kind, optional label, optional typed value, and optional required flag; actions read them through window:getInput(id). Required missing or invalid inputs disable action activation. Input values are not saved automatically, and a new setContent() replaces them with the supplied values. Avoid rebuilding a form on every tick with old defaults while the user is editing it.
visual supplies a clipped custom surface behind the ordinary text/input/action layer. It can combine a background, font family, positioned text items, normalized lines, logical-rectangle paths, grid cells, and positioned buttons. Window positioned text uses fields such as pixelSize, bold, opacity, and color, not TDML markup. Lines and paths use the same record shapes as Decoration graphics. Window visual colors follow Qt color syntax; they should not be assumed to use TDML’s alpha-last hexadecimal convention.
Set animated = true to request onTick(frameTimeSeconds) opportunities while a Window is visible. Hidden Windows do not drive frames. This is separate from periodic Decoration updates and is still coalesced, not an exact frame-rate or immediate-paint guarantee. A taskbar animation that must continue without a visible Window needs its own update requests.
For graphics-heavy or animated displays, Cell Space provides a bounded monospace grid. A batch of Cell Space changes can be applied with:
window:applyCellMutations({
{ op = "set", column = 20, row = 10, character = "@" },
{ op = "clear", column = 21, row = 10 },
})A mutation batch is applied atomically. It can contain at most 8,192 entries.
Cell coordinates are one-based and independent of logical-pixel drawing coordinates. Missing cells are empty; off-grid records are retained but clipped. Mutations change only cells, preserving the form and other graphics; a later setContent() replaces the cells too. Use onResize for grid counts, not pixel dimensions. See the UI reference for full content records, all eight input kinds, rich-text editing, Cell Space characters, and limits.