Skip to content
phroun edited this page Aug 22, 2026 · 1 revision

Events are how the display tells a client what the user did. They travel one way — display to client — and, with one exception, only to a client that asked for them.

b=new button caption="Save" action=app.save
sub b click

Nothing arrives until you subscribe

A trinket raises its events whether or not anyone is listening; the connection drops them unless you have subscribed. An unsubscribed trinket therefore looks exactly like a broken one, which is the single most common way to lose an afternoon here.

b=new button caption="OK"
  ->  the user clicks, and nothing reaches the client

b=new button caption="OK"
sub b click
  ->  event click trinket=3

The exception: command

command events flow unconditionally. A Button or a MenuItem with action= reports the command with no subscription at all:

b=new button caption="Save" action=app.save
  ->  event command action=app.save

That is deliberate. A command is what an application binds behaviour to, and the same one may be reachable from a button, a menu item and a keyboard shortcut at once — so it is addressed to the application rather than to any one trinket, and there is no single object to have subscribed to.

Everything else needs sub.

sub and unsub

sub <target> [event ...]
unsub <target> [event ...]

With event names, several at once, written bare:

l=new listview children={
	new item caption="Alpha"
	new item caption="Beta"
}
sub l change activate

With none, it means every event that target has — command included:

sub b
  ->  event command action=app.save
      event click trinket=3

all is the target that means every trinket on the connection:

sub all

unsub mirrors both forms: named events, or bare to drop everything for that target.

sub b click
unsub b click     # click stops arriving

Event names are bare words. A value or a negation is an error, not another meaning:

sub b click=1   ->  sub: event names are bare words
sub b !click    ->  sub: event names are bare words
sub             ->  sub: expected a target (key path, object id, or all)

The name is not checked

sub accepts any word, including one no type emits. A typo subscribes successfully and then delivers nothing, forever:

sub b click     # works
sub b clik      # accepted, and silently useless
sub b nosuch    # the same

There is nothing to distinguish that from a trinket that is not firing, so check spelling against the type's own page, or against describe, which reports each type's events and their fields.

Your own changes do not come back

A property you set from the wire does not raise an event, even when the same change made by the user would:

sub c
set c checked
  ->  nothing

(the user presses Space)
  ->  event toggle trinket=19 !checked

The client that sent the set already knows what it did; echoing it back would only invite a loop. Events report what the user did. This holds across the toolkit — a wire-driven set p minimize=… on an MDIPane, a wire-driven expanded on a TreeView branch, a wire-driven value on an Editor — none of them echo.

The practical consequence: update your own model when you send the change. Do not wait to hear about it.

What an event looks like

event click trinket=3
event change trinket=5 selected=1
event command action=app.save
event toggle trinket=19 !checked

The verb is event, then the type, then named fields. Fields follow the same rules as properties: flags are bare or !-negated, strings are quoted, numbers and words are not.

Almost every event carries trinket, the object id of whatever raised it. command is the exception again — it carries action and no trinket, because the command is the subject.

A field that is absent is not the same as a field that is empty. An MDIPane with nothing active sends window=0 and omits title entirely; a MessageBox closed by a button sends result with that button's word.

Finding out what a type emits

Every type's events are introspectable. describe reports them alongside the properties — name, description, and each field with its kind — so a client can discover them at runtime rather than reading a page:

describe

The event tables on the trinket pages in this wiki are generated from exactly that, so they cannot drift from what a build actually emits. Where a page and your build disagree, the build is right.

Subscribing is per object

A subscription attaches to one object and one event name. It does not spread to children, and it does not survive being applied to a different object.

That matters for types built out of parts. A Dock's click belongs to each entry, not to the row, so a dock of five entries wants five subscriptions:

d=new dockrow children={
	e=new dockentry caption="Report.txt" window=1042
}
sub d.e click

sub all is the blunt instrument for this — every trinket, every event — and is most useful while developing, when you want to see what a trinket actually does before narrowing down.

See also

Common Properties · Buttoncommand and click · MessageBox — the sub-or-silence trap in its purest form · MDIPane — several events from one user action

Clone this wiki locally