Flesh out protocol descriptions more

This commit is contained in:
Tony Garnock-Jones 2022-10-12 21:58:29 +02:00
parent b686080af0
commit 8e304902a8
9 changed files with 814 additions and 0 deletions

View File

@ -1 +1,60 @@
# Audio control
- [`[synit]/protocols/schemas/audio.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/audio.prs)
The audio control protocol configures sound sources and sinks, for instance for call audio
control on a mobile phone. This protocol is still *experimental*, as configuration of audio
stacks is complex and I have only a few simple examples to work from thus far. As Synit is
ported to new systems (e.g. new mobile handsets, to desktop machines, and so on), this protocol
will be refined.
**Implementation.** The protocol is (as of October 2022) implemented entirely within the
SqueakPhone Smalltalk image, in class `AudioProfileDaemon`. The audio profile daemon has three
tasks: first, to track Linux input `HEADPHONE_INSERT` and `MICROPHONE_INSERT` events and state,
producing `HeadsetSpeakerPresent` and `HeadsetMicrophonePresent` assertions in response;
second, to track application state such as whether a call is in progress or not; and third, to
respond to changes in device and application state, along with changes in sink/source mapping
configuration, by using the external `amixer` program to enable and disable audio sinks and
sources. The schema definition file contains a few
[comments](https://git.syndicate-lang.org/synit/synit/src/commit/a2babb63d55743ce942562e7ccb9106fdb239cf4/protocols/schemas/audio.prs#L3-L17)
that give some of the flavour of the logic involved.
## Source/Sink mappings
Each different kind of device asserts `Mapping` records to connect abstract `Endpoint` names to
concrete ALSA device names.
```
Mapping = <alsa-mapping @abstract Endpoint @concrete string> .
Endpoint = <source @value Source> / <sink @value Sink> .
Sink = =speaker / =headset / =earpiece .
Source = =speakerphone / =headset / =handset .
```
**Example.** When the Smalltalk code detects that it is running on a PinePhone, it asserts
- `<alsa-mapping <sink speaker> "Line Out">`
- `<alsa-mapping <sink headset> "Headphone">`
- `<alsa-mapping <sink earpiece> "Earpiece">`
- `<alsa-mapping <source speakerphone> "Mic1">`
- `<alsa-mapping <source handset> "Mic1">`
## Audio device state
The current daemon interprets low-level Linux input subsystem events, asserting
`HeadsetSpeakerPresent` and `HeadsetMicrophonePresent` when the relevant hardware is physically
attached to the system. These assertions are in turn used when selecting an audio profile to
enable.
```
HeadsetSpeakerPresent = <headset-speaker-present> .
HeadsetMicrophonePresent = <headset-microphone-present> .
```
## Relevant application state
The current daemon reacts to changes in
[`AlertSoundPlaying`](./soundEffects.md#AlertSoundPlaying),
[`PhoneRinging`](./telephony.md#PhoneRinging),
[`CallInProgress`](./telephony.md#CallInProgress), and
[`Speakerphone`](./telephony.md#Speakerphone) when selecting an audio profile to enable.

View File

@ -1 +1,17 @@
# MIME type support
- [`[synit]/protocols/schemas/mime.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/mime.prs)
Various protocols (e.g. the [sound effects](./soundEffects.md) protocols) rely on the
definition of a [MIME](https://en.wikipedia.org/wiki/MIME) `Value`, compatible with the
[suggested Preserves
convention](https://preserves.dev/conventions.html#mime-type-tagged-binary-data) for MIME
values.
The `type` is a symbol describing the MIME type, for example `application/octet-stream` or
`text/plain`. The `data` is the associated binary data, expected to be in the correct format
for the given `type`.
```
Value = <mime @type symbol @data bytes> .
```

View File

@ -1 +1,118 @@
# Modem support
- [`[synit]/protocols/schemas/hayes.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/hayes.prs)
- [`[synit]/protocols/schemas/samsungGalaxyS7.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/samsungGalaxyS7.prs)
Each particular class of modem has internal protocols needed for controlling it. So far, Synit
is able to interact with generic Hayes-style ("AT-command") modems, as seen in the PinePhone,
as well as with the modem in the Samsung Galaxy S7.
Each modem's internal protocol is spoken across the modem's distinguished dataspace, a
reference to which is held in the modem's [`ModemPresent`](./telephony.md#ModemPresent)
assertion.
## Hayes-style ("AT-command") Modems
As of October 2022, this protocol is implemented entirely in the SqueakPhone Smalltalk image,
in class `HayesModemActor` and friends.
### Presence
Hayes-style modems announce their presence with a subtype of the general `ModemPresent`
assertion schema.
```
ModemPresent = <modem =hayes @devicePath string @dataspace #!InternalProtocol> .
```
(TODO: specify the `InternalProtocol` properly)
```
InternalProtocol = any .
```
### Unsolicited Result Codes
An `UnsolicitedResultCode` message is sent when the modem sends us a "URC", an Unsolicited
Result Code.
```
UnsolicitedResultCode = <unsolicited @result Result> .
```
### Executing AT commands
Assert a `CommandRPC` record to request execution of an AT command string. The completion,
along with any responses, will be send to the `replyTo` entity reference. Alternatively, if no
completion notification or response is desired, send a `CommandEvent` message.
```
CommandRPC = <execute-command @commandText string @replyTo #!CommandResult> .
CommandEvent = <execute-command @commandText string> .
```
The result of a command execution is *asserted* as a `CommandResult` record to the `replyTo`
entity in the `CommandRPC`.
```
CommandResult = <command-result @commandText string @results [Result ...] @finalResult string> .
```
### Responses and Unsolicited Results
The `Result` type appears in both `UnsolicitedResultCode` and `CommandResult` records.
```
Result = <result @text string @tag MaybeString @fields MaybeStrings> .
MaybeString = @present string / @absent #f .
MaybeStrings = @present [string ...] / @absent #f .
```
**Examples.**
- `<unsolicited <result "NO CARRIER" #f #f>>`
- `<unsolicited <result "+CRING: VOICE" "CRING" ["VOICE"]>>`
- `<unsolicited <result "+CLIP: \"+31655555555\",145,,,,0" "CLIP" ["+31655555555" "145" "" "" "" "0"]>>`
- `<unsolicited <result "^DSCI: 2,1,4,0,+31655555555,145" "DSCI" ["2" "1" "4" "0" "+31655555555" "145"]>>`
- `<unsolicited <result "+QIND: \"csq\",12,99" "QIND" ["csq" "12" "99"]>>`
## Samsung Galaxy S7
The Samsung Galaxy S7 was the first modem supported by Synit, but because of problems with the
relevant PostmarketOS kernel, support for it has languished a bit while development has
proceeded based around the PinePhone. As of October 2022, the Samsung modem support protocols
are implemented entirely in the SqueakPhone Smalltalk image, in class
`SamsungGalaxyS7ModemActor` and friends.
### Presence
The modem announces its presence with a subtype of the general `ModemPresent` assertion schema.
```
ModemPresent = <modem =samsung-galaxy-s7 @devicePath string @dataspace #!InternalProtocol> .
```
(TODO: specify the `InternalProtocol` properly)
```
InternalProtocol = any .
```
### Low-level packet I/O
```
ModemPacket = @in <from-modem @packet any> / @out <to-modem @packet any> .
; The bodies are instances of SamsungFmtMessage and SamsungRfsMessage, respectively.
FmtPacket = <fmt @body #!any> .
RfsPacket = <rfs @body #!any> .
```
### Executing commands
Analogous to AT command execution for Hayes-style modems.
```
; Assertion. Asks the modem to execute the given command.
CommandRPC = <execute-command @command FmtPacket @replyTo #!FmtPacket> .
; Message. Asks the modem to execute the given command, but not to send back the reply.
CommandEvent = <execute-command @command FmtPacket> .
```

View File

@ -1 +1,195 @@
# Network core status and configuration
- [`[synit]/protocols/schemas/network.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/network.prs)
[interface monitor]: https://git.syndicate-lang.org/synit/synit/src/branch/main/packaging/packages/synit-config/files/usr/lib/synit/python/synit/daemon/interface_monitor.py
[wifi daemon]: https://git.syndicate-lang.org/synit/synit/src/branch/main/packaging/packages/synit-config/files/usr/lib/synit/python/synit/daemon/wifi_daemon.py
[network.pr]: https://git.syndicate-lang.org/synit/synit/src/branch/main/packaging/packages/synit-config/files/etc/syndicate/services/network.pr
[wifi.pr]: https://git.syndicate-lang.org/synit/synit/src/branch/main/packaging/packages/synit-config/files/etc/syndicate/services/wifi.pr
[modem.pr]: https://git.syndicate-lang.org/synit/synit/src/branch/main/packaging/packages/synit-config/files/etc/syndicate/services/modem.pr
The definitions in this protocol are used by the Synit daemons responsible for detecting and
responding to changes in the configuration of network devices.
**Implementation.** As of October 2022, this protocol is mostly implemented in
- the [interface monitor][],
- the [wifi daemon][], and
- the scripting around [network state changes][network.pr].
- the scripting around the [wifi subsystem][wifi.pr].
- the scripting around [mobile data][modem.pr].
## Network interface presence and state
The [interface monitor][] daemon uses the Linux netlink protocol to monitor changes in
interface presence and state. In response to netlink messages, it maintains an `Interface`
assertion for each network interface in the system.
```
Interface = <interface
@name string
@index int
@type InterfaceType
@administrativeState AdministrativeState
@operationalState OperationalState
@carrier CarrierState
@linkAddr string> .
```
The `InterfaceType` is synthesised by the interface monitor daemon based on somewhat ad-hoc
heuristics.
```
InterfaceType =
/ ; `lo` and friends
=loopback
/ ; `eth0`, bridges, anything that isn't loopback and isn't wireless
=normal
/ ; 'wlan0' and friends
=wireless
.
```
The `AdministrativeState` of an interface describes the state that the operator of the machine
wishes the interface to be in (according to the kernel).
```
AdministrativeState = =unknown / =down / =up .
```
The `OperationalState` and `CarrierState` taken together, by contrast, describe the *actual*
state of the interface.
```
OperationalState =
/ =unknown
/ =down
/ @lowerLayerDown =lower-layer-down
/ =testing
/ =dormant
/ =up
.
CarrierState =
/ @noCarrier =no-carrier
/ =carrier
.
```
## Route presence and state
The [interface monitor][] daemon also listens for netlink messages describing network route
presence and state changes, maintaining a `Route` assertion for each route present.
```
Route = <route
@addressFamily AddressFamily
@destination RouteDestination
@priority int
@typeOfService int
@interfaceName RouteInterface
@gateway Gateway> .
AddressFamily = =ipv4 / =ipv6 / @other int .
RouteDestination = =default / @prefix <prefix @net string @bits int> .
RouteInterface = @name string / @none #f .
Gateway = @addr string / @none #f .
```
## Default route presence
The [network.pr][] scripts respond to presence of `Route` records with a `default`
`destination` field by asserting a `DefaultRoute` record. Applications may use the presence or
absence of a `DefaultRoute` record to decide whether or not internet access is currently
present.
```
DefaultRoute = <default-route @addressFamily AddressFamily> .
```
## Wi-fi associations
The [wifi.pr][] script starts an instance of the [wifi daemon][] and an instance of
[`wpa_supplicant`](https://w1.fi/cgit/hostap/tree/README) for each `Interface` of type
`wireless`. The wifi daemon speaks with the `wpa_supplicant` instance to do network scanning as
well as managing network attachments. It publishes a `WifiAssociation` for each active
connection to a wifi access point.
```
WifiAssociation = <wifi-association @interfaceName string @ssid string @state WifiAssociationState> .
WifiAssociationState = @inProgress =in-progress / =ready .
```
## Hotspots
In future, the software will use `HotspotState` assertions to publish the presence and state of
wifi hotspots hosted by the device.
```
HotspotState = <hotspot-state @interfaceName string @ssid string @stationCount int> .
```
## AP scanning
In future, the software will assert `AvailableAccessPoint` with information it learns from
network scanning.
```
AvailableAccessPoint = <available-ap @interfaceName string @ssid string> .
```
## Network-related user settings
A number of user setting assertions control the network.
### Mobile Data
Asserting `MobileDataApn` and `MobileDataEnabled` causes the [modem.pr][] script to enable a
cellular data link.
```
MobileDataApn = <mobile-data-apn @apn string> .
MobileDataEnabled = <mobile-data-enabled> .
```
### Wifi network preferences
```
WifiAuthentication =
/ ; No authentication necessary: open network
=open
/ ; Pre-shared key (WPA2-PSK etc)
<psk @password string>
/ ; Other, not-yet-implemented
@other any
.
```
Each [wifi daemon][] responds to `SelectedWifiNetwork` assertions for its interface by trying
to connect to the named SSID using the provided credentials. The daemon asserts a
`WifiAssociation` in response.
```
SelectedWifiNetwork = <selected-wifi-network
@interfaceName string
@ssid string
@authentication WifiAuthentication> .
```
In future, user `Hotspot` assertions will cause setup of a wifi hotspot, hosted by the device.
```
Hotspot = <hotspot
@interfaceName string
@ssid string
@authentication WifiAuthentication> .
```
In future, `SavedWifiNetwork` assertions will hold records of previously-configured wifi
connection details.
```
SavedWifiNetwork = <saved-wifi-network
@ssid string
@authentication WifiAuthentication
@priority double> .
```

View File

@ -1 +1,31 @@
# Sound effects
- [`[synit]/protocols/schemas/soundEffects.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/soundEffects.prs)
From time to time, it makes sense for the device to use sound to communicate with the user.
**Implementation.** As of October 2022, the implementation resides within classes
`RingToneDaemon` and `SoundEffectsDaemon` in the SqueakPhone Smalltalk image.
## Continuous sounds
Continuous sounds such as a user's ringtone may be produced by asserting `ContinuousSound` with
an appropriately-type-tagged sound file (such as an mp3 file) as `data`. In response, the sound
effects daemon play the file in a loop and will assert `ContinuousSoundPlaying`.
```
ContinuousSound = <continuous-sound @data mime.Value> .
ContinuousSoundPlaying = <continuous-sound-playing> .
```
## <span id="AlertSoundPlaying"></span>Alert sounds
One-off sound effects such as the notification of a received SMS may be produced by sending an
`AlertSound` message with an appropriately-type-tagged sound file (such as an mp3 file) as
`data`. In response, the sound effects daemon will play the file once and will assert
`AlertSoundPlaying` until the playback is complete.
```
AlertSound = <alert-sound @data mime.Value> .
AlertSoundPlaying = <alert-sound-playing> .
```

View File

@ -1 +1,159 @@
# Telephony (call and SMS) support
- [`[synit]/protocols/schemas/telephony.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/telephony.prs)
The telephony protocol defines record and message types for non-modem-hardware-specific
telephony interactions.
**Implementation.** The protocol is (as of October 2022) implemented entirely within the
SqueakPhone Smalltalk image, in class `CallManager`, `HayesModemActor`,
`SamsungGalaxyS7ModemActor`, and so on.
## <span id="ModemPresent"></span>Available modem devices
A `ModemPresent` record is asserted for each modem available to the telephony subsystem. The
`type` field can, for example, be the symbol `hayes` for a Hayes modem, `samsung-galaxy-s7` for
a Samsung Galaxy S7, and so on. Each modem variant speaks a [variant-specific
protocol](./modem.md) across the `dataspace` reference in the `ModemPresent` record. Finally,
the `devicePath` is a Linux device path representative of the modem, for example
`/dev/umts_boot0` or `/dev/EG25.AT`.
```
ModemPresent = <modem @type symbol @devicePath string @dataspace #!any> .
```
## Telephony addresses (telephone numbers)
An `Address` represents a phone number. The `numberType` selects the numbering plan; the
`number` is the actual address. Numbering plans are complex! The GSM specifications are the
place to go for details. In general, using `international` with numbers like `+31 6 ...` is the
best way forward.
```
Address = <address @numberType NumberType @number string> .
NumberType = =unknown / =international / =national / =gsm0338 .
```
## Ongoing calls
An `ActiveCall` assertion describes an active, ongoing call.
The `callId` is a modem-specific call identification number. (TODO: if two modems are active,
their `callId`s may clash.) The `direction` is `mo` for calls placed by the local phone
endpoint, i.e. those dialed by the local user, and `mt` for calls placed by a remote phone,
i.e. incoming calls, those answered by the local user. The `type` field describes whether the
call is for voice or data; usually, this will be `voice`, but `data` is reported by some modems
when using mobile data connections. As you might imagine, `fax`-type calls are uncommon. The
`peer` field describes the other phone's network address (phone number). Finally, `state`
describes the state of the call.
```
ActiveCall = <call-state @callId CallId @direction CallDirection @type CallType @peer Address @state CallState> .
CallId = int .
CallDirection = =mo / =mt .
CallType = =voice / =data / =fax .
CallState = =hold / =original / =connect / =incoming / =waiting / =end / =alerting .
```
## Answering an incoming call
When an `ActiveCall` record is asserted by the modem, if it has direction `mt` and state
`incoming`, the system should let the user choose to answer the call (or ignore it, etc.). If
the user chooses to answer, an `AnswerCall` message tells the modem to do the necessary. The
`callId` is the same value as in the `ActiveCall` assertion.
```
; Message. Triggers call answering.
AnswerCall = <answer-call @callId int> .
```
## Rejecting and/or disconnecting a call
Sending a `DisconnectCall` message causes the modem to release an active call, either without
answering it (rejection) or while it is established (disconnection). The `callId` is taken from
the `ActiveCall` assertion, or is the symbol `all` to request disconnection of all active
calls. The `cause` field describes the release reason; it should usually be `normal`, but
`busy` or `callRejected` may also be appropriate.
```
DisconnectCall = <disconnect-call @callId CallIdSelector @cause ReleaseCause> .
CallIdSelector = @specificCall int / @allCalls =all .
ReleaseCause =
/ =unassignedNumber
/ =normal
/ =busy
/ =noUserResponding
/ =callRejected
/ =destinationOutOfOrder
/ =normalUnspecified
/ =incompatibleDestination
.
```
## Placing an outbound call
Sending a `PlaceCall` message causes the matching modem (named by its `devicePath`, which
should match a `ModemPresent` assertion) to place an outbound call to the named `peer` (a phone
number).
```
; Message. Starts an outgoing call.
PlaceCall = <place-call @devicePath string @peer Address> .
```
## <span id="CallInProgress"></span>Whole-device call state
Many applications don't care about precise details of individual calls, but only whether or not
some ongoing call is active (alerting, connected, ringing etc.). Those applications may monitor
the `CallInProgress` assertion.
```
CallInProgress = <call-in-progress> .
```
## <span id="PhoneRinging"></span>Whole-device ringing state
A `PhoneRinging` assertion means that an incoming call is signalling the user, asking for a
decision about whether to answer, reject, or ignore the call.
```
PhoneRinging = <phone-ringing> .
```
A `PeerRinging` assertion means that, during the establishment phase of an outgoing call, the
remote party's phone should be ringing.
```
PeerRinging = <peer-ringing> .
```
## SMS deliveries and transmissions
An `SmsDelivery` message indicates that an incoming SMS message has been received. The `smsc`
is the message relay server that forwarded the message on to us; this is usually some carrier-
and even plan-specific address, see the GSM specifications for details. The `peer` is the
sender's phone number. The `timestamp` describes the time associated with the SMS, and the
`body` is the message itself.
```
SmsDelivery = <sms-delivery @smsc Address @peer Address @timestamp time.Stamp @body string> .
```
To send an SMS message, assert an `SmsTransmission` record with the correct `smsc`, the
`peer`'s destination phone number, and the `body` of the message to send. The `continuation`
field should be a reference to an entity that expects the `ok` symbol as a message when the
transmission has been processed by the modem.
```
; Assertion. An outgoing SMS should be transmitted.
SmsTransmission = <sms-transmission @smsc Address @peer Address @body string @continuation #!=ok > .
```
## <span id="Speakerphone"></span>Speakerphone mode
The user may choose to assert a `Speakerphone` record in order to request that the local audio
hardware switch profile to speakerphone mode during a call.
```
Speakerphone = <speakerphone> .
```

View File

@ -1 +1,21 @@
# Time stamps
- [`[synit]/protocols/schemas/time.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/time.prs)
Various protocols rely on the definition of a time stamp type, `Stamp`, compatible with the
[suggested Preserves convention](https://preserves.dev/conventions.html#dates-and-times) for
dates and times.
```
Stamp = <rfc3339 @value string> .
```
From the Preserves convention document:
> Dates, times, moments, and timestamps can be represented with a Record with label `rfc3339`
> having a single field, a `String`, which MUST conform to one of the `full-date`,
> `partial-time`, `full-time`, or `date-time` productions of
> [section 5.6 of RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6).
> (In `date-time`, “T” and
> “Z” MUST be upper-case and “T” MUST be used; a space separating the `full-date` and
> `full-time` MUST NOT be used.)

View File

@ -1 +1,204 @@
# User interface definitions and interaction
- [`[synit]/protocols/schemas/ui.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/ui.prs)
The user interface protocol is perhaps the most subject-to-change part of the whole system. It
is a client-server protocol, similar in spirit to X-Windows, where *clients* request display
and input services from a *server*, to which is attached a display and input devices.
At present, it is a simple system with a fixed set of widget types, a TeX-inspired box-and-glue
layout model, and a very limited set of event types. In future, a
NeWS/Display-PostScript-inspired model could dovetail very nicely with the capability and
dataspace features of Syndicate.
**Implementation.** The SqueakPhone Smalltalk image includes the initial implementation of the
protocol, in classes `WidgetDaemon`, `WidgetBuilder`, `WidgetWindow`, and so on.
## Creating a window
A client *observes* `Window` assertions with an `id` of its choice. The server notices the
client's interest, and in response, creates a fresh dataspace for configuration and interaction
relating to the new window, and asserts a `Window` record mapping the `id` to the new `space`.
```
Window = <window @id WidgetId @space #!any> .
WidgetId = any .
```
## Configuring a window
Within the dataspace referred to by a `Window` assertion—henceforth the *window dataspace*—the
client may assert `WindowCloseable` to add a close button to the window decoration, and may
assert `WindowTitle` to give the window a name.
```
WindowCloseable = <window-closeable> .
WindowTitle = <window-title @title string> .
```
## Creating widget trees
The client may place `Widget` assertions within the window dataspace to create new widgets
within the window. The window is hidden until the first `Widget` is asserted.
`Root` and `Parent` assertions connect new widgets to the overall window layout tree. A `Root`
assertion places the widget directly in the containing window, while a `Parent` assertion marks
a widget as child of another widget. In both cases, the `order` sort key is used when multiple
children are present within a container that supports widget ordering.
```
Widget = <widget @id WidgetId @type WidgetType> .
Parent = <parent @id WidgetId @parentId WidgetId @order SortKey> .
Root = <root @id WidgetId @order SortKey> .
SortKey = @double double / @string string .
```
## Widget Types
Widgets acting as containers for other widgets may be of either `column` or `row` type. Leaf
widgets may be `blank` (for spacing/padding/layout), `text` (a label or editable field), a
`slider`, an `image`, or a [FontAwesome](https://fontawesome.com/) `icon`.
```
WidgetType = NodeType / LeafType .
NodeType = =column / =row .
LeafType = =blank / =text / =slider / =image / =icon .
```
## Configuring widgets
Widgets have *attributes* attached to them. An attribute is a pair of a symbol `key` and a
`value` (of `key`-specific type) attached to a particular widget. Most attribute keys are
expected to have either zero or one `Attribute` records for any given widget, but the
Syndicated Actor Model naturally supports *multiple* values for a given attribute, and some
attribute keys take advantage of this. See [below](#attribute-keys) for more on the available
attribute keys.
```
Attribute = <attribute @id WidgetId @key symbol @value any> .
```
## Events and Widget State
Widgets marked with the [`interactive` attribute](#interactive) generate events in response to
user interaction.
Clients can observe `Touch` assertions to receive information about when the user has a finger
touching the displayed widget on a touchscreen. The assertion for a given widget will appear
when the touch starts, and disappear when the touch ends. Multiple touches, uniquely
identified, may be active simultaneously.
```
Touch = <touch @widget WidgetId @touchId any> .
```
Clients can observe `Click` messages to receive information about when the user removes a
touching finger from a widget while the finger is within the widget's bounds.
```
Click = <click @widget WidgetId> .
```
Finally, whether a widget is marked interactive or not, the UI server actor asserts `State`
assertions containing facts about a given widget's state. For example, a text widget asserts a
`State` assertion with the symbol `text` as its `key` and a string as its `value`; a slider
asserts a `value`-keyed `State`; and a scrollable widget asserts a `visible-scroll-range`-keyed
`State` with a `VisibleScrollRange` value.
```
State = <state @widget WidgetId @key any @value any> .
VisibleScrollRange =
/ =none
/ @visibleScrollRange <visible-scroll-range
<min @minId WidgetId @minSortKey SortKey>
<max @maxId WidgetId @maxSortKey SortKey>>
.
```
## Accessing widget instances
Within the current implementation, access to the raw
[Morphic](http://wiki.squeak.org/squeak/morphic) object representing the widget can be gained
by monitoring `WidgetInstance` assertions. (This is not a sustainable technique, and it will be
replaced in future by an entity-reference-based system.)
```
WidgetInstance = <widget-instance @id WidgetId @instance #!any> .
```
## <span id="attribute-keys"></span>Widget Attributes
### General attributes
interactive - boolean - ?
name - string - morphic name for the widget
### Color and style
The `Color` type describes an RGBA color value where the components are `double`s in the range
`0.0` to `1.0` (inclusive).
```
Color = <rgba @red double @green double @blue double @alpha double> .
```
#### backgroundColor: Color
Sets the background color of the widget.
#### foregroundColor: Color
Text color in a label or editable field; icon color for FontAwesome icons.
#### cornerStyle: `square` or `rounded`
Sets the widget's corner style. Defaults to `square`.
#### cornerRadius: number
Sets the widget's corner radius (where `cornerStyle` is `rounded`), measured in points.
#### fontSize: number
Sets the font size, measured in points.
#### icon: symbol
Sets the FontAwesome icon name for icons.
#### icon-style: symbol
Sets the FontAwesome icon style name for icons.
### Layout
```
; Box-and-glue layout
Fill = @fixed double / <fill @weight int @rank int> .
Sizing = <sizing @ideal double @stretch Fill @shrink Fill> .
BoxSize = <box-size @horizontal Sizing @vertical Sizing> .
```
padding - BoxSize - layout padding
size - BoxSize
spacing - BoxSize
### Sliders
max - number
min - number
orientation - `vertical` or `horizontal` - for sliders
value - number - slider value
### Text fields (labels and editable fields)
readOnly - boolean - set to false to turn a label into an editable field
value - string - label or editable field contents
### Column and row attributes
cells - integer - number of cells per row (column) of the layout matrix - if none, just one row (column) exists
scrollable - boolean

View File

@ -1 +1,18 @@
# User settings
- [`[synit]/protocols/schemas/userSettings.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/userSettings.prs)
```
version 1 .
; Assertion.
CommandRPC = <user-settings-command @action Action @reply #!CommandReply> .
; Message.
CommandEvent = <user-settings-command @action Action> .
CommandReply = =done .
Action = <assert @item any> / <retract @item any> .
; Assertion.
Value = <user-setting @item any> .
```