@domicile-desktop/sdk 0.0.0-alpha-028d5f9f87e0 → 0.0.0-alpha-e040773499e5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -1
- package/dist/domicile-host.d.ts +589 -354
- package/dist/domicile-host.js +8 -13
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ See [docs/ELEMENTS.md](docs/ELEMENTS.md) for `<app>` input and focus, and the
|
|
|
51
51
|
|
|
52
52
|
| Module | What it is |
|
|
53
53
|
| --- | --- |
|
|
54
|
-
| `./domicile-host` | `DomicileHost`: the type of the desktop `Shell` is handed
|
|
54
|
+
| `./domicile-host` | `DomicileHost`: the type of the desktop `Shell` is handed. Generated from the engine's IDL; see [Generated types](#generated-types). |
|
|
55
55
|
| `./shell` | `Shell`: the export a shell module must provide. Domicile calls it once with the element to draw in. |
|
|
56
56
|
| `./app-element`, `./webview-element` | Types and event names for `<app>` and `<webview>`. |
|
|
57
57
|
| `./bind-keys` | `bindKeys`: grab a shell's own chords by name and handle them by mode. `./key-action` and `./own-keybindings` are its parts. |
|
|
@@ -66,6 +66,22 @@ The compositor's JSON socket protocol lives in
|
|
|
66
66
|
[`@domicile-desktop/e2e-harness`](../e2e-harness/README.md); a page never
|
|
67
67
|
speaks it.
|
|
68
68
|
|
|
69
|
+
## Generated types
|
|
70
|
+
|
|
71
|
+
`src/domicile-host.ts` is generated from the engine's WebIDL in
|
|
72
|
+
`packages/domicile-engine/src/third_party/blink/renderer/modules/domicile/`,
|
|
73
|
+
with the IDL's comments as its docs. Do not edit it.
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
bun run generate # after changing the IDL
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- `codegen/` holds the generator: a parser for the IDL subset the engine uses,
|
|
80
|
+
and the TypeScript it emits. It throws on syntax outside that subset.
|
|
81
|
+
- `EVENT_TYPES` in `codegen/generate-domicile-host.ts` names the event type
|
|
82
|
+
each `on<name>` handler dispatches, which WebIDL cannot express.
|
|
83
|
+
- `scripts/test-host-types-match-the-idl.sh` fails when the file is stale.
|
|
84
|
+
|
|
69
85
|
## Dependencies
|
|
70
86
|
|
|
71
87
|
- `zod` only. Its schemas parse the keywords and rows a newer engine may send
|
package/dist/domicile-host.d.ts
CHANGED
|
@@ -1,540 +1,775 @@
|
|
|
1
|
-
import type { CursorShape } from "./cursor-shape";
|
|
2
|
-
import type { Theme } from "./theme";
|
|
3
|
-
import type { TrayAction } from "./tray";
|
|
4
1
|
/**
|
|
5
|
-
*
|
|
2
|
+
* The cursors a client can ask the chrome to show over its window.
|
|
6
3
|
*
|
|
7
|
-
*
|
|
4
|
+
* The `wp_cursor_shape_v1` shapes, named by the CSS `cursor` keyword the
|
|
5
|
+
* chrome assigns, plus `none` for a hidden cursor. The same set is defined by
|
|
6
|
+
* `domicile_protocol::CursorShape`, `components/domicile/common/cursor_shape.h`
|
|
7
|
+
* and `cursorShapeSchema` in `@domicile/chrome-sdk`.
|
|
8
|
+
*
|
|
9
|
+
* An enum, not a DOMString, so the bindings reject unknown values. CSS ignores
|
|
10
|
+
* an unknown cursor keyword, so a bad value would otherwise show the wrong
|
|
11
|
+
* cursor with no error.
|
|
12
|
+
*
|
|
13
|
+
* Keep the values in the same order as the other lists:
|
|
14
|
+
* `scripts/test-cursor-shapes-agree.sh` compares all four as sequences.
|
|
8
15
|
*/
|
|
9
|
-
export type
|
|
10
|
-
/** An evdev code. Zero is not a key and the engine refuses it. */
|
|
11
|
-
keycode: number;
|
|
12
|
-
altKey?: boolean;
|
|
13
|
-
ctrlKey?: boolean;
|
|
14
|
-
shiftKey?: boolean;
|
|
15
|
-
metaKey?: boolean;
|
|
16
|
-
};
|
|
16
|
+
export type DomicileCursorShape = "none" | "default" | "context-menu" | "help" | "pointer" | "progress" | "wait" | "cell" | "crosshair" | "text" | "vertical-text" | "alias" | "copy" | "move" | "no-drop" | "not-allowed" | "grab" | "grabbing" | "e-resize" | "n-resize" | "ne-resize" | "nw-resize" | "s-resize" | "se-resize" | "sw-resize" | "w-resize" | "ew-resize" | "ns-resize" | "nesw-resize" | "nwse-resize" | "col-resize" | "row-resize" | "all-scroll" | "zoom-in" | "zoom-out";
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
18
|
+
* The desktop's light or dark theme.
|
|
19
19
|
*
|
|
20
|
-
*
|
|
20
|
+
* One of four copies of this set: `domicile_protocol::Theme`,
|
|
21
|
+
* `components/domicile/common/theme.h`, this enum, and `themeSchema` in
|
|
22
|
+
* `@domicile/chrome-sdk`.
|
|
23
|
+
*
|
|
24
|
+
* An enum rather than a `DOMString` because `setTheme()` takes it, so the
|
|
25
|
+
* bindings reject an invalid value at the call. There is no `system` value:
|
|
26
|
+
* the compositor owns the theme.
|
|
27
|
+
*
|
|
28
|
+
* Keep the order in sync with the other copies. `mojom::Theme` is numbered by
|
|
29
|
+
* position, and `scripts/test-themes-agree.sh` compares the order.
|
|
21
30
|
*/
|
|
22
|
-
export type
|
|
31
|
+
export type DomicileTheme = "dark" | "light";
|
|
32
|
+
/**
|
|
33
|
+
* Which button clicked a tray icon: StatusNotifierItem's Activate,
|
|
34
|
+
* SecondaryActivate and ContextMenu.
|
|
35
|
+
*
|
|
36
|
+
* An enum rather than a `DOMString` because activateTrayItem() takes it, so
|
|
37
|
+
* the bindings reject an invalid value at the call.
|
|
38
|
+
*
|
|
39
|
+
* Keep the order in sync with `mojom::TrayAction`, which is numbered by
|
|
40
|
+
* position.
|
|
41
|
+
*/
|
|
42
|
+
export type DomicileTrayAction = "primary" | "secondary" | "context";
|
|
43
|
+
export type DomicileAppEventInit = EventInit & {
|
|
44
|
+
appId?: string;
|
|
45
|
+
};
|
|
46
|
+
/** What `DomicileHost.previewFile()` resolves with. */
|
|
47
|
+
export type DomicileFilePreview = {
|
|
23
48
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
49
|
+
* Which of the rest means anything: "text", "directory", "audio", "binary"
|
|
50
|
+
* or "unreadable". "unreadable" is also what a path outside the compositor's
|
|
51
|
+
* index of the home gets -- see previewFile(). A DOMString rather than an
|
|
52
|
+
* enum: the browser drops an answer whose kind is not one of the five.
|
|
26
53
|
*/
|
|
27
|
-
readonly
|
|
54
|
+
readonly kind: string;
|
|
55
|
+
/** The front of the file, for "text". */
|
|
56
|
+
readonly text: string;
|
|
57
|
+
/** What is in it, for "directory": names, a subdirectory ending in `/`. */
|
|
58
|
+
readonly entries: readonly string[];
|
|
28
59
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
60
|
+
* What a song says of itself, for "audio": each tag empty when it does not
|
|
61
|
+
* say it.
|
|
31
62
|
*/
|
|
32
|
-
readonly
|
|
33
|
-
readonly
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
readonly
|
|
63
|
+
readonly title: string;
|
|
64
|
+
readonly artist: string;
|
|
65
|
+
readonly album: string;
|
|
66
|
+
/** How long it plays, in seconds, for "audio". */
|
|
67
|
+
readonly duration: number;
|
|
37
68
|
/**
|
|
38
|
-
* The
|
|
39
|
-
*
|
|
69
|
+
* The picture it carries of itself, for "audio", as a `data:` URL -- the
|
|
70
|
+
* page cannot read the file to draw one of its own.
|
|
40
71
|
*/
|
|
41
|
-
readonly
|
|
72
|
+
readonly cover: string;
|
|
73
|
+
};
|
|
74
|
+
/** What `DomicileHost.searchFiles()` resolves with. */
|
|
75
|
+
export type DomicileFileSearch = {
|
|
42
76
|
/**
|
|
43
|
-
* The
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
77
|
+
* The front of what matched: paths relative to the home directory the
|
|
78
|
+
* desktop is running as -- `Notes/today.org`, not
|
|
79
|
+
* `/home/you/Notes/today.org` -- already in the order they go on screen, and
|
|
80
|
+
* a directory ends in `/`. Empty is a query that matched nothing.
|
|
47
81
|
*/
|
|
48
|
-
readonly
|
|
49
|
-
|
|
82
|
+
readonly files: readonly string[];
|
|
83
|
+
/** How many paths matched, of which `files` is the front. */
|
|
84
|
+
readonly matched: number;
|
|
50
85
|
/**
|
|
51
|
-
*
|
|
52
|
-
* `rotate-270`.
|
|
86
|
+
* Whether the compositor is still building the index this was found in.
|
|
53
87
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
88
|
+
* THE DIFFERENCE BETWEEN AN INCOMPLETE ANSWER AND A WRONG ONE. The rows are
|
|
89
|
+
* a launcher's whole evidence that a file exists, so an answer from an index
|
|
90
|
+
* still being walked has to arrive saying so. A shell draws this as a line
|
|
91
|
+
* saying the index is being built, and asks again.
|
|
56
92
|
*/
|
|
57
|
-
readonly
|
|
93
|
+
readonly indexing: boolean;
|
|
58
94
|
};
|
|
59
95
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
96
|
+
* A key combination the desktop grabs.
|
|
97
|
+
*
|
|
98
|
+
* Same fields as `DomicileShortcutEvent`, so a shell can compare a press
|
|
99
|
+
* against it directly. `keycode` is a Linux evdev code; `KeyboardEvent.key` is
|
|
100
|
+
* already a string such as "Enter".
|
|
63
101
|
*/
|
|
64
|
-
export type
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
readonly parent: string | null;
|
|
79
|
-
/** A popup's place relative to its parent; `null` for a toplevel. */
|
|
80
|
-
readonly x: number | null;
|
|
81
|
-
readonly y: number | null;
|
|
82
|
-
/** Whether a popup grabbed the pointer; `false` for a toplevel. */
|
|
83
|
-
readonly grab: boolean;
|
|
102
|
+
export type DomicileShortcut = {
|
|
103
|
+
keycode: number;
|
|
104
|
+
altKey?: boolean;
|
|
105
|
+
ctrlKey?: boolean;
|
|
106
|
+
shiftKey?: boolean;
|
|
107
|
+
metaKey?: boolean;
|
|
108
|
+
};
|
|
109
|
+
export type DomicileShortcutEventInit = EventInit & {
|
|
110
|
+
chord?: string;
|
|
111
|
+
keycode?: number;
|
|
112
|
+
altKey?: boolean;
|
|
113
|
+
ctrlKey?: boolean;
|
|
114
|
+
shiftKey?: boolean;
|
|
115
|
+
metaKey?: boolean;
|
|
84
116
|
};
|
|
85
117
|
/**
|
|
86
|
-
*
|
|
87
|
-
*
|
|
118
|
+
* The event behind DomicileHost.onfocusrequested: a client asked for the
|
|
119
|
+
* keyboard.
|
|
88
120
|
*/
|
|
89
121
|
export type DomicileAppEvent = Event & {
|
|
90
|
-
/** The window
|
|
122
|
+
/** The window that asked: the id an <app> element names. */
|
|
91
123
|
readonly appId: string;
|
|
92
124
|
};
|
|
93
|
-
/** A combination claimed with `grabShortcut()` was pressed. */
|
|
94
|
-
export type DomicileShortcutEvent = Event & {
|
|
95
|
-
/**
|
|
96
|
-
* The chord as {@link DomicileHost.grabShortcut} was given it by name —
|
|
97
|
-
* `Meta+Shift+l` — or empty for one grabbed as a keycode.
|
|
98
|
-
*/
|
|
99
|
-
readonly chord: string;
|
|
100
|
-
readonly keycode: number;
|
|
101
|
-
readonly altKey: boolean;
|
|
102
|
-
readonly ctrlKey: boolean;
|
|
103
|
-
readonly shiftKey: boolean;
|
|
104
|
-
readonly metaKey: boolean;
|
|
105
|
-
};
|
|
106
125
|
/**
|
|
107
|
-
*
|
|
126
|
+
* One of the desk's browser windows: a page the browser holds, drawn with
|
|
127
|
+
* `<webview window="id">`. See components/domicile/mojom/browser_windows.mojom.
|
|
108
128
|
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
129
|
+
* An interface for DomicileDisplay's reason: these are read from the
|
|
130
|
+
* desktop's `browserWindows` attribute, and WebIDL forbids a dictionary as an
|
|
131
|
+
* attribute type.
|
|
111
132
|
*/
|
|
112
|
-
export type
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
readonly
|
|
118
|
-
/**
|
|
133
|
+
export type DomicileBrowserWindow = {
|
|
134
|
+
/**
|
|
135
|
+
* The id `<webview window>` and closeBrowserWindow() use. Never reused while
|
|
136
|
+
* the browser runs.
|
|
137
|
+
*/
|
|
138
|
+
readonly id: string;
|
|
139
|
+
/** The page's address. Empty before it has shown anything. */
|
|
140
|
+
readonly url: string;
|
|
141
|
+
/** The page's title. Empty when the page has none. */
|
|
119
142
|
readonly title: string;
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
143
|
+
/**
|
|
144
|
+
* The extension popup window (chrome.windows) whose one tab this is. Null
|
|
145
|
+
* for a tab of the desk's own window.
|
|
146
|
+
*/
|
|
147
|
+
readonly popupWindow: number | null;
|
|
148
|
+
/**
|
|
149
|
+
* The size the popup window asked for, in CSS pixels. 0 on an axis it left
|
|
150
|
+
* unset.
|
|
151
|
+
*/
|
|
152
|
+
readonly width: number;
|
|
153
|
+
readonly height: number;
|
|
126
154
|
};
|
|
127
155
|
/**
|
|
128
|
-
*
|
|
129
|
-
* never crosses into the page.
|
|
156
|
+
* One thing that was copied, as a row of the clipboard's history.
|
|
130
157
|
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
158
|
+
* An interface rather than a dictionary because WebIDL will not have a
|
|
159
|
+
* dictionary as the element type of an attribute's array, which is how these
|
|
160
|
+
* are read -- off DomicileHost.clipboard rather than handed over in a call.
|
|
133
161
|
*/
|
|
134
|
-
export type DomicileFileSearch = {
|
|
135
|
-
readonly files: readonly string[];
|
|
136
|
-
/** The total number of matches; {@link files} holds the first of them. */
|
|
137
|
-
readonly matched: number;
|
|
138
|
-
/**
|
|
139
|
-
* Whether the compositor is still building the index.
|
|
140
|
-
*
|
|
141
|
-
* When true, the results may be incomplete. Show them and search again.
|
|
142
|
-
*/
|
|
143
|
-
readonly indexing: boolean;
|
|
144
|
-
};
|
|
145
|
-
/** One entry in the clipboard history. */
|
|
146
162
|
export type DomicileClipboardEntry = {
|
|
147
163
|
/**
|
|
148
|
-
*
|
|
164
|
+
* What DomicileHost.copyClipboardEntry() names this row by.
|
|
149
165
|
*
|
|
150
|
-
*
|
|
166
|
+
* Assigned by the compositor and never reused, so an id a shell is holding
|
|
167
|
+
* either names the row it was told about or names nothing at all. NOT a
|
|
168
|
+
* position: the list a copy re-orders keeps every id it had.
|
|
151
169
|
*/
|
|
152
170
|
readonly id: number;
|
|
153
171
|
/**
|
|
154
|
-
*
|
|
155
|
-
*
|
|
172
|
+
* Enough of what was copied to recognize it by, and not necessarily all of
|
|
173
|
+
* it: a long copy is cut down to a row, because this is what a panel draws
|
|
174
|
+
* and the rest of a copied file is not a row.
|
|
175
|
+
*
|
|
176
|
+
* What goes back on the clipboard is always the whole thing, which is the
|
|
177
|
+
* reason a row is an id and a preview rather than the text: the bytes stay
|
|
178
|
+
* in the compositor, and a password manager's copy is a row in this list.
|
|
156
179
|
*/
|
|
157
180
|
readonly preview: string;
|
|
158
181
|
};
|
|
159
|
-
/** One system tray icon. */
|
|
160
|
-
export type DomicileTrayItem = {
|
|
161
|
-
/** The id to pass to {@link DomicileHost.activateTrayItem}. */
|
|
162
|
-
readonly id: string;
|
|
163
|
-
/** A text label. Never empty. */
|
|
164
|
-
readonly title: string;
|
|
165
|
-
/** The icon as a `data:` URL, or empty if it could not be drawn. */
|
|
166
|
-
readonly icon: string;
|
|
167
|
-
};
|
|
168
|
-
/** One button of a notification. */
|
|
169
|
-
export type DomicileNotificationAction = {
|
|
170
|
-
/** The key to pass to {@link DomicileHost.invokeNotificationAction}. */
|
|
171
|
-
readonly key: string;
|
|
172
|
-
/** The button text. */
|
|
173
|
-
readonly label: string;
|
|
174
|
-
};
|
|
175
|
-
/** One notification. */
|
|
176
|
-
export type DomicileNotification = {
|
|
177
|
-
/** The id the host's dismiss and invoke calls take. */
|
|
178
|
-
readonly id: number;
|
|
179
|
-
/** The sender's name; may be empty. */
|
|
180
|
-
readonly appName: string;
|
|
181
|
-
readonly summary: string;
|
|
182
|
-
/** Plain text, never markup; may be empty. */
|
|
183
|
-
readonly body: string;
|
|
184
|
-
/** A `data:` URL, or empty. */
|
|
185
|
-
readonly icon: string;
|
|
186
|
-
/** `"low"`, `"normal"` or `"critical"`. */
|
|
187
|
-
readonly urgency: string;
|
|
188
|
-
readonly actions: readonly DomicileNotificationAction[];
|
|
189
|
-
/** Whether it offers the `"default"` action, triggered by clicking it. */
|
|
190
|
-
readonly clickable: boolean;
|
|
191
|
-
/**
|
|
192
|
-
* Requested display time in milliseconds: `0` until dismissed, `-1` for
|
|
193
|
-
* the shell's default.
|
|
194
|
-
*/
|
|
195
|
-
readonly timeoutMs: number;
|
|
196
|
-
/** Milliseconds since the epoch, on the compositor's clock. */
|
|
197
|
-
readonly time: number;
|
|
198
|
-
};
|
|
199
182
|
/**
|
|
200
|
-
*
|
|
183
|
+
* One screen of the desktop.
|
|
184
|
+
*
|
|
185
|
+
* An interface because WebIDL does not allow a dictionary as an attribute type.
|
|
201
186
|
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
* docs/SHELL-BROWSER-WINDOWS.md.
|
|
187
|
+
* Sizes are integers because the desktop config uses whole pixels. Other sizes
|
|
188
|
+
* on this channel come from layout boxes and are fractional.
|
|
205
189
|
*/
|
|
206
|
-
export type
|
|
207
|
-
/**
|
|
208
|
-
* The id `<webview window>` and {@link DomicileHost.closeBrowserWindow} take.
|
|
209
|
-
* Never reused while the browser runs.
|
|
210
|
-
*/
|
|
211
|
-
readonly id: string;
|
|
212
|
-
/** The page's address. Empty before the page has loaded. */
|
|
213
|
-
readonly url: string;
|
|
214
|
-
/** The page's title. Empty when the page has none. */
|
|
215
|
-
readonly title: string;
|
|
190
|
+
export type DomicileDisplay = {
|
|
216
191
|
/**
|
|
217
|
-
* The
|
|
218
|
-
* `
|
|
192
|
+
* The compositor's name for this screen from the config, such as `left`.
|
|
193
|
+
* `domicile-0` when Domicile runs in a window instead of driving displays.
|
|
219
194
|
*/
|
|
220
|
-
readonly
|
|
195
|
+
readonly name: string;
|
|
221
196
|
/**
|
|
222
|
-
* The
|
|
223
|
-
*
|
|
197
|
+
* The top-left corner in desktop coordinates. The origin is the top-left of
|
|
198
|
+
* the displays' bounding box. Signed because the config can place a display
|
|
199
|
+
* left of or above the origin.
|
|
224
200
|
*/
|
|
201
|
+
readonly x: number;
|
|
202
|
+
readonly y: number;
|
|
203
|
+
/** The logical size, in the CSS pixels a shell lays out in. */
|
|
225
204
|
readonly width: number;
|
|
226
205
|
readonly height: number;
|
|
206
|
+
/**
|
|
207
|
+
* The scale advertised to Wayland clients on this screen. This is not the
|
|
208
|
+
* shell's `devicePixelRatio`: the shell is one page at one density across
|
|
209
|
+
* all screens.
|
|
210
|
+
*/
|
|
211
|
+
readonly scale: number;
|
|
212
|
+
/**
|
|
213
|
+
* The panel's mode in physical pixels, before rotation. A portrait 4K
|
|
214
|
+
* panel has a 3840x2160 mode and an 1800x3200 logical size. The mode does
|
|
215
|
+
* not follow from the size because `scale` is an integer.
|
|
216
|
+
*
|
|
217
|
+
* Zero when the desktop has no modes, such as when running in a window.
|
|
218
|
+
*/
|
|
219
|
+
readonly modeWidth: number;
|
|
220
|
+
readonly modeHeight: number;
|
|
221
|
+
/**
|
|
222
|
+
* The monitor's rotation: `normal`, `rotate-90`, `rotate-180` or
|
|
223
|
+
* `rotate-270`, as the config file spells them.
|
|
224
|
+
*
|
|
225
|
+
* Follows the wl_output convention: the name is the clockwise turn applied
|
|
226
|
+
* to content, not the panel's turn. A shell applies it as written.
|
|
227
|
+
*
|
|
228
|
+
* A DOMString because an enum would need another IDL file and another patched
|
|
229
|
+
* entry in `bindings/idl_in_modules.gni`. The browser maps any other name to
|
|
230
|
+
* `normal`.
|
|
231
|
+
*/
|
|
232
|
+
readonly transform: string;
|
|
227
233
|
};
|
|
228
234
|
/**
|
|
229
|
-
* One extension with an action.
|
|
235
|
+
* One extension with an action, as a shell's tray draws it.
|
|
236
|
+
*
|
|
237
|
+
* An interface rather than a dictionary for DomicileClipboardEntry's reason:
|
|
238
|
+
* WebIDL will not have a dictionary as the element type of an attribute's
|
|
239
|
+
* array, and these are read off DomicileHost.extensions.
|
|
230
240
|
*
|
|
231
|
-
* The state is the
|
|
241
|
+
* The state is the active tab's -- the <webview> that last had focus -- or the
|
|
242
|
+
* action's default where there is none. See docs/architecture/EXTENSIONS.md.
|
|
232
243
|
*/
|
|
233
244
|
export type DomicileExtension = {
|
|
234
|
-
/**
|
|
245
|
+
/** What DomicileHost.activateExtension() names it by. */
|
|
235
246
|
readonly id: string;
|
|
236
247
|
readonly name: string;
|
|
237
248
|
/** The action's tooltip. */
|
|
238
249
|
readonly title: string;
|
|
239
250
|
/**
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
251
|
+
* data:image/png;base64,..., drawn at this page's device pixel ratio. Not a
|
|
252
|
+
* chrome-extension:// URL: action.setIcon({imageData}) sets an icon that has
|
|
253
|
+
* none.
|
|
243
254
|
*/
|
|
244
255
|
readonly icon: string;
|
|
245
256
|
readonly badgeText: string;
|
|
246
|
-
/** A CSS color,
|
|
257
|
+
/** A CSS color, #rrggbbaa. Fully transparent when the extension set none. */
|
|
247
258
|
readonly badgeColor: string;
|
|
248
259
|
/**
|
|
249
|
-
* The popup
|
|
250
|
-
*
|
|
251
|
-
*
|
|
260
|
+
* The popup a click opens, in a <webview> the shell draws; null for an
|
|
261
|
+
* action whose click is its `action.onClicked`. Either way the click is
|
|
262
|
+
* activateExtension().
|
|
252
263
|
*/
|
|
253
264
|
readonly popup: string | null;
|
|
254
|
-
/**
|
|
265
|
+
/** False after the extension's action.disable(). */
|
|
255
266
|
readonly enabled: boolean;
|
|
256
267
|
};
|
|
257
|
-
/** Every event
|
|
268
|
+
/** Every event `DomicileHost` fires, by name. */
|
|
258
269
|
export type DomicileHostEventMap = {
|
|
259
|
-
/**
|
|
260
|
-
* A client asked for keyboard focus. Focus has not moved; the shell may call
|
|
261
|
-
* `focusApp()`. See `focus_requested` in `domicile-protocol`.
|
|
262
|
-
*/
|
|
263
|
-
focusrequested: DomicileAppEvent;
|
|
270
|
+
/** A grabbed shortcut fired, as a DomicileShortcutEvent. */
|
|
264
271
|
shortcut: DomicileShortcutEvent;
|
|
265
272
|
/**
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
273
|
+
* A client asked for the keyboard, as a DomicileAppEvent naming it; nothing
|
|
274
|
+
* has moved. The shell answers by calling focusApp(), or does not, which
|
|
275
|
+
* refuses it.
|
|
269
276
|
*/
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Every unanswered portal request: `data` is the compositor's
|
|
273
|
-
* `portal_requests` line. Fired on every change. A listener added later is
|
|
274
|
-
* sent the latest line. See `docs/architecture/PORTALS.md`.
|
|
275
|
-
*/
|
|
276
|
-
portalrequests: MessageEvent<string>;
|
|
277
|
+
focusrequested: DomicileAppEvent;
|
|
277
278
|
/**
|
|
278
|
-
*
|
|
279
|
-
*
|
|
279
|
+
* The desktop changed: a screen arrived or left, a display was resized, or
|
|
280
|
+
* its density moved. Read `displays` for what it is now.
|
|
280
281
|
*/
|
|
281
282
|
displayschanged: Event;
|
|
282
283
|
/**
|
|
283
|
-
* A
|
|
284
|
-
*
|
|
285
|
-
*/
|
|
286
|
-
browserwindowschanged: Event;
|
|
287
|
-
/**
|
|
288
|
-
* A window appeared, closed, or changed. Bare — read
|
|
289
|
-
* {@link DomicileHost.windows} for what they are now.
|
|
284
|
+
* A window appeared, closed, or changed: its title, size, limits, cursor or
|
|
285
|
+
* popup placement. Read `windows` for what they are now.
|
|
290
286
|
*/
|
|
291
287
|
windowschanged: Event;
|
|
292
288
|
/**
|
|
293
|
-
* The compositor said where the keyboard is
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
* now.
|
|
289
|
+
* The compositor said where the keyboard is: `focusedWindow` may have
|
|
290
|
+
* changed. Every time, and once after the windows already running are
|
|
291
|
+
* replayed to a page that has just connected -- which is how a page tells a
|
|
292
|
+
* window opened now from one that was running.
|
|
298
293
|
*/
|
|
299
294
|
focusedwindowchanged: Event;
|
|
300
|
-
/** Bare: the attribute it names moved. */
|
|
301
295
|
clipboardchanged: Event;
|
|
302
|
-
/** Bare: the attribute it names moved. */
|
|
303
296
|
traychanged: Event;
|
|
304
|
-
/** Bare: the attribute it names moved. */
|
|
305
297
|
notificationschanged: Event;
|
|
306
|
-
/** Bare: the attribute it names moved. */
|
|
307
298
|
extensionschanged: Event;
|
|
308
|
-
/** Bare: the attribute it names moved. */
|
|
309
299
|
idlechanged: Event;
|
|
310
|
-
/** Bare: the attribute it names moved. */
|
|
311
300
|
lockedchanged: Event;
|
|
312
|
-
/** Bare: the attribute it names moved. */
|
|
313
301
|
themechanged: Event;
|
|
314
|
-
/** Bare: the attribute it names moved. */
|
|
315
302
|
windowsthemechanged: Event;
|
|
316
|
-
/** Bare: the attributes it names moved. */
|
|
317
303
|
modifierschanged: Event;
|
|
304
|
+
/**
|
|
305
|
+
* Fires when a window opens, closes, navigates or changes title. Read
|
|
306
|
+
* `browserWindows` for the current list.
|
|
307
|
+
*/
|
|
308
|
+
browserwindowschanged: Event;
|
|
309
|
+
/**
|
|
310
|
+
* An answer to callSystem(), as a MessageEvent whose `data` is the
|
|
311
|
+
* compositor's `system_reply`, `system_event` or `system_end` line.
|
|
312
|
+
*/
|
|
313
|
+
system: MessageEvent<string>;
|
|
314
|
+
/**
|
|
315
|
+
* Every unanswered portal request, as a MessageEvent whose `data` is the
|
|
316
|
+
* compositor's `portal_requests` line. Fired on every change. A listener
|
|
317
|
+
* added later is sent the latest line, so a shell that listens late still
|
|
318
|
+
* sees pending dialogs.
|
|
319
|
+
*/
|
|
320
|
+
portalrequests: MessageEvent<string>;
|
|
318
321
|
};
|
|
319
322
|
/**
|
|
320
|
-
* The shell's control channel to the compositor.
|
|
323
|
+
* The desktop a shell is handed — the shell's control channel to the compositor.
|
|
321
324
|
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
325
|
+
* Not a web standard and not proposed as one. It exists in Domicile's engine
|
|
326
|
+
* fork, on documents served over domicile://, and nowhere else.
|
|
324
327
|
*
|
|
325
|
-
*
|
|
326
|
-
* and
|
|
327
|
-
*
|
|
328
|
-
*
|
|
328
|
+
* This is the typed surface rather than a message pipe: the page calls methods
|
|
329
|
+
* and listens for events, and the wire protocol lives in the browser process.
|
|
330
|
+
* The reason is that the protocol carries Spawn, and a page that cannot
|
|
331
|
+
* construct a message cannot construct a malformed one. The cost, which is
|
|
332
|
+
* real, is that adding a message means an engine release rather than editing a
|
|
333
|
+
* TypeScript file.
|
|
329
334
|
*/
|
|
330
335
|
export type DomicileHost = {
|
|
331
336
|
/**
|
|
332
|
-
* Run a command on the desktop
|
|
337
|
+
* Run a command on the machine running the desktop.
|
|
333
338
|
*
|
|
334
|
-
*
|
|
339
|
+
* Sequence<DOMString> rather than a single string: splitting a command line
|
|
340
|
+
* is a shell's job and there is no shell in this path.
|
|
335
341
|
*/
|
|
336
342
|
spawn(command: readonly string[]): void;
|
|
337
343
|
/**
|
|
338
|
-
*
|
|
339
|
-
* call
|
|
344
|
+
* Ask what in the home matches `query`. Resolves with the answer. A newer
|
|
345
|
+
* call supersedes this one, which rejects with an AbortError: a launcher
|
|
346
|
+
* wants the answer to what is typed now.
|
|
347
|
+
*
|
|
348
|
+
* IT TAKES NO PATH, AND THAT IS THE POINT RATHER THAN AN OVERSIGHT. A shell
|
|
349
|
+
* is served over domicile:// so that it has an origin without a TCP port,
|
|
350
|
+
* not so that it gets a filesystem. A call that named a directory would be
|
|
351
|
+
* one, and every document this engine serves would have it. What gets
|
|
352
|
+
* searched is the compositor's decision -- see `domicile_host::file_search`
|
|
353
|
+
* -- and the query is only words to match.
|
|
340
354
|
*
|
|
341
|
-
*
|
|
342
|
-
*
|
|
343
|
-
*
|
|
355
|
+
* ONLY WHAT MATCHED CROSSES. The compositor's index is the whole home; a
|
|
356
|
+
* page handed that to filter was a desktop that took no input while it
|
|
357
|
+
* arrived.
|
|
344
358
|
*/
|
|
345
359
|
searchFiles(query: string): Promise<DomicileFileSearch>;
|
|
346
360
|
/**
|
|
347
|
-
*
|
|
348
|
-
* with
|
|
361
|
+
* Ask what is in one file. Resolves with the answer. A newer call
|
|
362
|
+
* supersedes this one, as with searchFiles().
|
|
349
363
|
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
364
|
+
* THIS ONE TAKES A PATH, which searchFiles() above says is the point of not
|
|
365
|
+
* taking one -- so what it may name is narrow: a path relative to the home,
|
|
366
|
+
* as searchFiles() named it (a directory without its trailing `/`). The
|
|
367
|
+
* compositor answers only for a path in its own index of the home, and
|
|
368
|
+
* anything else comes back "unreadable", so this reads nothing a search
|
|
369
|
+
* could not already have named.
|
|
352
370
|
*/
|
|
353
371
|
previewFile(path: string): Promise<DomicileFilePreview>;
|
|
354
372
|
/**
|
|
355
|
-
* A system call:
|
|
356
|
-
*
|
|
357
|
-
*
|
|
358
|
-
*
|
|
373
|
+
* A system call: a file, a directory, a watch or a process. `request` is
|
|
374
|
+
* the call as JSON, such as `{"call":"read_file","path":"/sys/x"}`. Answered
|
|
375
|
+
* with `system` events whose `data` carries `id`. The compositor checks
|
|
376
|
+
* every call, the lock included. See docs/SHELL-SYSTEM-ACCESS.md and
|
|
377
|
+
* the SDK's `system` module, which is the way to call this.
|
|
359
378
|
*/
|
|
360
379
|
callSystem(id: number, request: string): void;
|
|
361
380
|
/**
|
|
362
|
-
* Answer portal request `id
|
|
363
|
-
* with a string `kind`, such as `{"kind":"access"}
|
|
364
|
-
*
|
|
381
|
+
* Answer portal request `id`, which a `portalrequests` event listed.
|
|
382
|
+
* `answer` is JSON with a string `kind`, such as `{"kind":"access"}`. One
|
|
383
|
+
* that is not is dropped in the browser. The compositor checks the rest. See
|
|
384
|
+
* docs/architecture/PORTALS.md.
|
|
365
385
|
*/
|
|
366
386
|
answerPortalRequest(id: number, answer: string): void;
|
|
367
387
|
/**
|
|
368
|
-
* Put a clipboard history
|
|
388
|
+
* Put a row of the clipboard's history back on the clipboard.
|
|
369
389
|
*
|
|
370
|
-
*
|
|
371
|
-
*
|
|
372
|
-
*
|
|
390
|
+
* IT NAMES A ROW AND CARRIES NO TEXT: a shell is served over domicile:// so
|
|
391
|
+
* that it has an origin, not so that it gets the machine, and a call that
|
|
392
|
+
* took bytes would let this document write the desktop's clipboard rather
|
|
393
|
+
* than choose among what has already been copied on it. `entry` is an id
|
|
394
|
+
* `clipboard` lists.
|
|
395
|
+
*
|
|
396
|
+
* No answer, and none to want: what follows is that the next paste in any
|
|
397
|
+
* window is that row, served by the compositor rather than by whichever
|
|
398
|
+
* client first copied it -- which is the whole of what a clipboard manager
|
|
399
|
+
* is for. An id the history has since dropped sets nothing.
|
|
373
400
|
*/
|
|
374
401
|
copyClipboardEntry(entry: number): void;
|
|
375
402
|
/**
|
|
376
|
-
*
|
|
377
|
-
*
|
|
403
|
+
* Click an icon in the system tray, with the button `action` names.
|
|
404
|
+
*
|
|
405
|
+
* It names an icon `tray` lists and a button, and nothing about
|
|
406
|
+
* what the click does, for copyClipboardEntry's reason: that is the
|
|
407
|
+
* application's. An id that names no icon now is a click that raced the
|
|
408
|
+
* application going away, and does nothing; an empty one throws.
|
|
409
|
+
*/
|
|
410
|
+
activateTrayItem(id: string, action: DomicileTrayAction): void;
|
|
411
|
+
/**
|
|
412
|
+
* Clear notifications: ids `notifications` lists. Each application hears
|
|
413
|
+
* its notification was dismissed, and the next `notificationschanged`
|
|
414
|
+
* leaves them out. An id already gone is passed over.
|
|
415
|
+
*/
|
|
416
|
+
dismissNotifications(ids: readonly number[]): void;
|
|
417
|
+
/**
|
|
418
|
+
* Press one of a notification's actions -- "default" for the notification
|
|
419
|
+
* itself. It names a notification and a key it offered, and nothing about
|
|
420
|
+
* what the press does, for copyClipboardEntry's reason: that is the
|
|
421
|
+
* application's. An empty action throws.
|
|
422
|
+
*/
|
|
423
|
+
invokeNotificationAction(id: number, action: string): void;
|
|
424
|
+
/**
|
|
425
|
+
* Which window has the keyboard: the compositor's seat, and where the keys
|
|
426
|
+
* this page hears are sent. focusChrome() takes it back to the page.
|
|
378
427
|
*/
|
|
379
428
|
focusApp(appId: string): void;
|
|
380
429
|
focusChrome(): void;
|
|
381
430
|
/**
|
|
382
|
-
*
|
|
431
|
+
* Put the pointer at a place in this page, in the page's own coordinates --
|
|
432
|
+
* the ones a PointerEvent reports as clientX/clientY.
|
|
383
433
|
*
|
|
384
|
-
*
|
|
385
|
-
*
|
|
434
|
+
* THE COMPANION TO MOVING THE KEYBOARD. A desktop whose focus follows the
|
|
435
|
+
* cursor has to take the cursor with it when a key moves the focus, or the
|
|
436
|
+
* next pointer event hands the focus back to whatever the pointer is still
|
|
437
|
+
* over. Every other compositor does this itself; here the shell is a page,
|
|
438
|
+
* and a page can read where the pointer is and cannot put it anywhere.
|
|
439
|
+
*
|
|
440
|
+
* Doubles for resizeApp's reason: a place in a page is a CSS pixel and a CSS
|
|
441
|
+
* pixel is fractional. A coordinate outside this page is clamped to its own
|
|
442
|
+
* box -- what a page may move is the pointer over itself -- and NaN throws.
|
|
386
443
|
*/
|
|
387
444
|
warpPointer(x: number, y: number): void;
|
|
388
|
-
/**
|
|
445
|
+
/**
|
|
446
|
+
* Ask a client to close. Not a kill -- the client decides, which is why a
|
|
447
|
+
* window can refuse and show a save dialog instead.
|
|
448
|
+
*/
|
|
389
449
|
closeApp(appId: string): void;
|
|
390
450
|
/**
|
|
391
|
-
*
|
|
392
|
-
*
|
|
451
|
+
* The layout box, as a resize. For an <app> the box IS the configure.
|
|
452
|
+
*
|
|
453
|
+
* Doubles because a CSS pixel is fractional and this comes from a layout box.
|
|
454
|
+
*/
|
|
455
|
+
resizeApp(appId: string, width: number, height: number): void;
|
|
456
|
+
/**
|
|
457
|
+
* Where the page put an <app>, in the page's CSS pixels. The client draws at
|
|
458
|
+
* the scale of the monitor holding most of that box. Layout still places the
|
|
459
|
+
* window; this only tells the compositor where it ended up.
|
|
393
460
|
*/
|
|
394
461
|
setAppBounds(appId: string, x: number, y: number, width: number, height: number): void;
|
|
395
462
|
/**
|
|
396
|
-
*
|
|
463
|
+
* Draw the desktop the other way round.
|
|
464
|
+
*
|
|
465
|
+
* THE ONE CALL HERE THAT SAYS WHAT THE DESKTOP IS rather than asking it for
|
|
466
|
+
* something. It reaches the compositor and comes back as `themechanged` --
|
|
467
|
+
* to every chrome on the desk, this one included, which is why a shell
|
|
468
|
+
* renders from `theme` rather than from its own click. Three monitors are
|
|
469
|
+
* three pages and the toggle is on one of them.
|
|
397
470
|
*
|
|
398
|
-
*
|
|
399
|
-
*
|
|
400
|
-
*
|
|
471
|
+
* It has to leave the page at all because the compositor is the only process
|
|
472
|
+
* the desk's CLIENTS can hear: it answers the settings portal GTK, Qt and
|
|
473
|
+
* Electron read a color scheme from, out of this same value. A theme kept in
|
|
474
|
+
* the renderer would be a desktop whose panels went dark and whose windows
|
|
475
|
+
* stayed light.
|
|
476
|
+
*
|
|
477
|
+
* A DomicileTheme rather than a DOMString, so a word that is not one of the
|
|
478
|
+
* two is refused at the call instead of at the socket -- see
|
|
479
|
+
* domicile_theme.idl.
|
|
401
480
|
*/
|
|
402
|
-
setTheme(theme:
|
|
481
|
+
setTheme(theme: DomicileTheme): void;
|
|
403
482
|
/**
|
|
404
|
-
*
|
|
483
|
+
* Offer a passphrase at a locked desk.
|
|
484
|
+
*
|
|
485
|
+
* THE WAY OUT OF THE ONE STATE THIS PAGE CANNOT CHANGE BY DRAWING. While the
|
|
486
|
+
* desk is locked the compositor puts nothing this page forwards into the
|
|
487
|
+
* Wayland seat -- no client sees a keystroke or a click -- and this call is
|
|
488
|
+
* the only thing that ends it. The page keeps its own keys throughout, which
|
|
489
|
+
* is what makes a lock screen possible: it is the thing forwarding, so it can
|
|
490
|
+
* take a passphrase while nothing it forwards arrives anywhere.
|
|
405
491
|
*
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
*
|
|
492
|
+
* ANSWERED WITH `lockedchanged` AND NOT WITH A RETURN VALUE, and only when
|
|
493
|
+
* the desk actually opened. A wrong passphrase produces nothing at all: the
|
|
494
|
+
* compositor says so in its own log, without the passphrase in it. A page
|
|
495
|
+
* that cleared its own lock screen because it believed its own keystrokes
|
|
496
|
+
* would be a lock anybody with the devtools could open -- and the event goes
|
|
497
|
+
* to every chrome on the desk rather than to this one, because three monitors
|
|
498
|
+
* are three pages and the desk they draw has one lock.
|
|
409
499
|
*/
|
|
410
500
|
unlock(passphrase: string): void;
|
|
411
501
|
/**
|
|
412
|
-
* Lock the
|
|
413
|
-
*
|
|
414
|
-
* Answered with `lockedchanged` to every chrome. Does nothing when no lock
|
|
415
|
-
* is configured.
|
|
502
|
+
* Lock the desk now, whoever is at it. Answered like unlock(): with
|
|
503
|
+
* `lockedchanged` to every chrome, and only when the desk actually shut.
|
|
416
504
|
*/
|
|
417
505
|
lock(): void;
|
|
418
506
|
/**
|
|
419
|
-
*
|
|
420
|
-
* transition, so client windows can switch theme now.
|
|
507
|
+
* This page's old frame is held for `theme`: turn the desk's windows now.
|
|
421
508
|
*
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
*
|
|
509
|
+
* Called from inside a shell's wipe, once the frame it wipes away from is
|
|
510
|
+
* captured, so that the wipe passes across windows that turn inside it
|
|
511
|
+
* rather than over windows that had already turned. Answered with a
|
|
512
|
+
* `windowsthemechanged` once every chrome has called it and the windows have
|
|
513
|
+
* had their chance to repaint -- or once the compositor stopped waiting.
|
|
425
514
|
*/
|
|
426
|
-
themeCaptured(theme:
|
|
515
|
+
themeCaptured(theme: DomicileTheme): void;
|
|
427
516
|
/**
|
|
428
|
-
* Route a key combination to the page
|
|
517
|
+
* Route a key combination to the page rather than to the focused client.
|
|
429
518
|
*
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
* `shortcut` events whose `chord` is this string, from a `<webview>` or this
|
|
433
|
-
* page (taken from the page).
|
|
519
|
+
* The press comes back as a `shortcut` event carrying the same fields, so a
|
|
520
|
+
* shell compares what it grabbed against what fired without parsing a string.
|
|
434
521
|
*
|
|
435
|
-
*
|
|
436
|
-
*
|
|
522
|
+
* The same, by name: `grabShortcut("Meta+Shift+l")`, in sway's grammar. The
|
|
523
|
+
* engine finds the key the keysym is on, from the keyboard the compositor
|
|
524
|
+
* describes, and finds it again whenever the layout changes. The press comes
|
|
525
|
+
* back as a `shortcut` event whose `chord` is this string -- pressed in a
|
|
526
|
+
* `<webview>` or on this page, where it is taken from the page.
|
|
437
527
|
*
|
|
438
|
-
*
|
|
439
|
-
*
|
|
528
|
+
* Throws a SyntaxError for a chord written wrong, and a NotFoundError for a
|
|
529
|
+
* keysym the keyboard cannot type; before any keyboard is described, that
|
|
530
|
+
* one is a console warning once it is.
|
|
440
531
|
*/
|
|
441
|
-
grabShortcut(shortcut:
|
|
532
|
+
grabShortcut(shortcut: DomicileShortcut | string): void;
|
|
442
533
|
/**
|
|
443
|
-
* Click an extension's action
|
|
444
|
-
*
|
|
445
|
-
*
|
|
534
|
+
* Click an extension's action, popup or not: the extension is granted
|
|
535
|
+
* activeTab on the active tab, as a toolbar click grants it in Chrome. Then
|
|
536
|
+
* an action with no popup has its `action.onClicked` dispatched; one with a
|
|
537
|
+
* popup is the shell's to open, as a <webview> at the `popup` its
|
|
538
|
+
* `extensions` entry names, and is opened after this call.
|
|
539
|
+
*
|
|
540
|
+
* NOT THE COMPOSITOR'S. An action lives in this browser, so the call goes no
|
|
541
|
+
* further than the browser process, over the tray's own pipe -- see
|
|
542
|
+
* components/domicile/mojom/extension_tray.mojom. An id that names no
|
|
543
|
+
* extension with an action now is a click that raced an uninstall, and does
|
|
544
|
+
* nothing; an empty one throws.
|
|
446
545
|
*/
|
|
447
546
|
activateExtension(id: string): void;
|
|
448
547
|
/**
|
|
449
548
|
* Opens a browser window at `url`, for the shell's own UI such as a `+`
|
|
450
|
-
* button. It appears in the next `browserwindowschanged`.
|
|
451
|
-
*
|
|
452
|
-
* the same way.
|
|
549
|
+
* button or a launcher. It appears in the next `browserwindowschanged`. A
|
|
550
|
+
* domicile:// address shows blocked, as in a <webview>.
|
|
453
551
|
*/
|
|
454
552
|
openBrowserWindow(url: string): void;
|
|
455
553
|
/**
|
|
456
|
-
* Closes
|
|
457
|
-
*
|
|
554
|
+
* Closes window `id`; it leaves the next `browserwindowschanged`. An unknown
|
|
555
|
+
* id does nothing.
|
|
458
556
|
*/
|
|
459
557
|
closeBrowserWindow(id: string): void;
|
|
460
558
|
/**
|
|
461
|
-
*
|
|
462
|
-
* the application has exited. Throws on an empty id.
|
|
463
|
-
*/
|
|
464
|
-
activateTrayItem(id: string, action: TrayAction): void;
|
|
465
|
-
/**
|
|
466
|
-
* Dismiss notifications by id (from {@link notifications}) and tell their
|
|
467
|
-
* applications. Unknown ids are ignored.
|
|
468
|
-
*/
|
|
469
|
-
dismissNotifications(ids: readonly number[]): void;
|
|
470
|
-
/**
|
|
471
|
-
* Invoke a notification's action (`"default"` for clicking it), then close
|
|
472
|
-
* it. Unknown actions are ignored.
|
|
473
|
-
*/
|
|
474
|
-
invokeNotificationAction(id: number, action: string): void;
|
|
475
|
-
/**
|
|
476
|
-
* The desktop's screens.
|
|
559
|
+
* The screens of the desktop.
|
|
477
560
|
*
|
|
478
|
-
* An attribute
|
|
479
|
-
*
|
|
480
|
-
*
|
|
481
|
-
|
|
482
|
-
readonly displays: readonly DomicileDisplay[] | null;
|
|
483
|
-
/**
|
|
484
|
-
* The browser windows, oldest first.
|
|
561
|
+
* An attribute rather than an event payload, because the desktop is a fact
|
|
562
|
+
* and not a stream. A shell reads this when it needs it -- including a
|
|
563
|
+
* component that mounts long after the description arrived, which an event
|
|
564
|
+
* would have left with nothing.
|
|
485
565
|
*
|
|
486
|
-
*
|
|
487
|
-
*
|
|
566
|
+
* NULL UNTIL THE COMPOSITOR HAS DESCRIBED THE DESKTOP, and an empty array
|
|
567
|
+
* for a desktop with no screens on it. They are different states and a shell
|
|
568
|
+
* renders them differently: nothing at all is what an unknown screen shows,
|
|
569
|
+
* which is the right answer for "there is no such screen" and the wrong one
|
|
570
|
+
* for "wait". `domicile-protocol` carries that distinction deliberately --
|
|
571
|
+
* an empty `Vec` that serializes to nothing and one that serializes to `[]`
|
|
572
|
+
* both come back empty, and only the second is a desktop a shell can parse
|
|
573
|
+
* -- and an attribute that started empty threw it away again here.
|
|
574
|
+
*
|
|
575
|
+
* The compositor describes at least one output, so it does not send the
|
|
576
|
+
* empty one; the `domicile` daemon, which no desktop has been described to,
|
|
577
|
+
* does. Leaning on "in practice it never happens" is what made the SDK guess,
|
|
578
|
+
* and this is instead of the guess.
|
|
579
|
+
*
|
|
580
|
+
* No [SameObject]: the compositor sends the whole desktop each time it
|
|
581
|
+
* changes and a FrozenArray is frozen, so this is a different array after
|
|
582
|
+
* every `displayschanged`. That is also the shape a shell wants -- an
|
|
583
|
+
* identity that survived a desktop it no longer describes would be worse.
|
|
488
584
|
*/
|
|
489
|
-
readonly
|
|
585
|
+
readonly displays: readonly DomicileDisplay[] | null;
|
|
490
586
|
/**
|
|
491
|
-
* Every client window, in the order they appeared
|
|
492
|
-
*
|
|
493
|
-
*
|
|
494
|
-
*
|
|
587
|
+
* Every client window on the desktop, in the order they appeared: what the
|
|
588
|
+
* compositor has said about each so far. Reading it binds the channel, and
|
|
589
|
+
* the compositor announces the windows already running as it does, so a
|
|
590
|
+
* shell that reads late misses nothing -- it reads, then listens for
|
|
591
|
+
* `windowschanged`. A different array after every change, for `displays`'s
|
|
592
|
+
* reason.
|
|
495
593
|
*/
|
|
496
594
|
readonly windows: readonly DomicileWindow[];
|
|
497
|
-
/** The window holding the keyboard, or
|
|
595
|
+
/** The window holding the keyboard, or null when the shell's page holds it. */
|
|
498
596
|
readonly focusedWindow: string | null;
|
|
499
597
|
/**
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
* and
|
|
598
|
+
* THE DESK'S STATE, AS ATTRIBUTES. Each is what the compositor last said,
|
|
599
|
+
* null until it has said anything, and a bare `<name>changed` event says it
|
|
600
|
+
* moved: a shell reads, then listens, and one that listens late misses
|
|
601
|
+
* nothing. See docs/architecture/WINDOW-DOMICILE.md.
|
|
503
602
|
*/
|
|
504
603
|
readonly clipboard: readonly DomicileClipboardEntry[] | null;
|
|
505
|
-
/** The system tray: every application showing an icon, in the order they registered. */
|
|
506
604
|
readonly tray: readonly DomicileTrayItem[] | null;
|
|
507
|
-
/** The desk's notifications: every one not yet cleared, oldest first. */
|
|
508
605
|
readonly notifications: readonly DomicileNotification[] | null;
|
|
509
|
-
/** The extensions with an action, from this browser rather than the compositor. */
|
|
510
606
|
readonly extensions: readonly DomicileExtension[] | null;
|
|
511
|
-
/**
|
|
512
|
-
* Whether anybody is at this desktop. **Not `document.visibilityState`**: a
|
|
513
|
-
* shell's document stays visible while the glass is off. `null` on a desktop
|
|
514
|
-
* with no idle timeout.
|
|
515
|
-
*/
|
|
516
607
|
readonly idle: boolean | null;
|
|
517
|
-
/**
|
|
518
|
-
* Whether this desk is locked: `true` is a desk that delivers nothing to
|
|
519
|
-
* any client. The compositor holds it, so a reload does not open it. `null`
|
|
520
|
-
* on a desktop with no passphrase.
|
|
521
|
-
*/
|
|
522
608
|
readonly locked: boolean | null;
|
|
609
|
+
readonly theme: DomicileTheme | null;
|
|
610
|
+
readonly windowsTheme: DomicileTheme | null;
|
|
523
611
|
/**
|
|
524
|
-
*
|
|
525
|
-
*
|
|
526
|
-
|
|
527
|
-
readonly theme: Theme | null;
|
|
528
|
-
/**
|
|
529
|
-
* Which way round the desk's windows are drawn: {@link theme}'s other half,
|
|
530
|
-
* moved once they have turned — see {@link themeCaptured}.
|
|
612
|
+
* The compositor seat's modifiers -- only the keys forwarded to a client;
|
|
613
|
+
* see @domicile-desktop/sdk's README before trusting them over a page's
|
|
614
|
+
* own key events.
|
|
531
615
|
*/
|
|
532
|
-
readonly windowsTheme: Theme | null;
|
|
533
|
-
/** The compositor seat's — see the README before trusting them. */
|
|
534
616
|
readonly altKey: boolean | null;
|
|
535
617
|
readonly ctrlKey: boolean | null;
|
|
536
618
|
readonly shiftKey: boolean | null;
|
|
537
619
|
readonly metaKey: boolean | null;
|
|
620
|
+
/**
|
|
621
|
+
* The desk's browser windows, oldest first. Null until the browser lists
|
|
622
|
+
* them, which it does as soon as this page listens. The browser holds each
|
|
623
|
+
* page; draw one with `<webview window="id">`. A shell loaded over this one
|
|
624
|
+
* gets the same windows and pages. See
|
|
625
|
+
* components/domicile/mojom/browser_windows.mojom.
|
|
626
|
+
*
|
|
627
|
+
* A window a program opens (`domicile open-url`, a page's target="_blank",
|
|
628
|
+
* an extension) appears here in the next `browserwindowschanged`. No
|
|
629
|
+
* [SameObject], for `displays`' reason.
|
|
630
|
+
*/
|
|
631
|
+
readonly browserWindows: readonly DomicileBrowserWindow[] | null;
|
|
632
|
+
/**
|
|
633
|
+
* Typed by the event map rather than by inheriting `EventTarget`, whose
|
|
634
|
+
* overloads take any name and type every listener's event as `Event`.
|
|
635
|
+
* `dispatchEvent` is left out: a page does not dispatch to it.
|
|
636
|
+
*/
|
|
538
637
|
addEventListener<T extends keyof DomicileHostEventMap>(type: T, listener: (event: DomicileHostEventMap[T]) => void): void;
|
|
539
638
|
removeEventListener<T extends keyof DomicileHostEventMap>(type: T, listener: (event: DomicileHostEventMap[T]) => void): void;
|
|
540
639
|
};
|
|
640
|
+
/**
|
|
641
|
+
* One notification: an application's call to org.freedesktop.Notifications,
|
|
642
|
+
* which the compositor serves -- a page's own Web Notification included,
|
|
643
|
+
* because the browser shows one by calling that server.
|
|
644
|
+
*
|
|
645
|
+
* An interface rather than a dictionary for DomicileTrayItem's reason: these
|
|
646
|
+
* are read off DomicileHost.notifications.
|
|
647
|
+
*/
|
|
648
|
+
export type DomicileNotification = {
|
|
649
|
+
/**
|
|
650
|
+
* What DomicileHost.dismissNotifications() and invokeNotificationAction()
|
|
651
|
+
* name this notification by. One its application replaced keeps its id.
|
|
652
|
+
*/
|
|
653
|
+
readonly id: number;
|
|
654
|
+
/** Who sent it, as it named itself. May be empty. */
|
|
655
|
+
readonly appName: string;
|
|
656
|
+
/** The one line that says what happened. */
|
|
657
|
+
readonly summary: string;
|
|
658
|
+
/** More, as plain text: the compositor tells senders it takes no markup. */
|
|
659
|
+
readonly body: string;
|
|
660
|
+
/**
|
|
661
|
+
* The picture, as a `data:` URL, or empty for nothing to draw. A URL rather
|
|
662
|
+
* than a path for DomicileTrayItem.icon's reason.
|
|
663
|
+
*/
|
|
664
|
+
readonly icon: string;
|
|
665
|
+
/**
|
|
666
|
+
* "low", "normal" or "critical": the spec's urgency hint. A word rather than
|
|
667
|
+
* an enum because it is only ever read, and the SDK parses it.
|
|
668
|
+
*/
|
|
669
|
+
readonly urgency: string;
|
|
670
|
+
/** Its buttons. A press on the notification itself is `clickable`. */
|
|
671
|
+
readonly actions: readonly DomicileNotificationAction[];
|
|
672
|
+
/** Whether it offers the "default" action: a press on the notification. */
|
|
673
|
+
readonly clickable: boolean;
|
|
674
|
+
/**
|
|
675
|
+
* How long it asked to stay up, in milliseconds: 0 for until it is
|
|
676
|
+
* dismissed, -1 for the shell's choice.
|
|
677
|
+
*/
|
|
678
|
+
readonly timeoutMs: number;
|
|
679
|
+
/**
|
|
680
|
+
* When it arrived or was last replaced, in milliseconds since the epoch on
|
|
681
|
+
* the compositor's clock.
|
|
682
|
+
*/
|
|
683
|
+
readonly time: number;
|
|
684
|
+
};
|
|
685
|
+
/**
|
|
686
|
+
* One button of a notification.
|
|
687
|
+
*
|
|
688
|
+
* An interface rather than a dictionary because these are read off a
|
|
689
|
+
* DomicileNotification's array; see DomicileTrayItem.
|
|
690
|
+
*/
|
|
691
|
+
export type DomicileNotificationAction = {
|
|
692
|
+
/** The id DomicileHost.invokeNotificationAction() takes. */
|
|
693
|
+
readonly key: string;
|
|
694
|
+
/** The button's label. */
|
|
695
|
+
readonly label: string;
|
|
696
|
+
};
|
|
697
|
+
/**
|
|
698
|
+
* A combination claimed with grabShortcut() was pressed.
|
|
699
|
+
*
|
|
700
|
+
* Its own type rather than a DomicileAppEvent with the combination in the
|
|
701
|
+
* `title` slot. A shortcut is not a window's name and does not belong to a
|
|
702
|
+
* window at all: it fires whatever holds the keyboard, which is the point of
|
|
703
|
+
* grabbing it.
|
|
704
|
+
*
|
|
705
|
+
* Only presses. A release changes nothing and would arrive as a second event
|
|
706
|
+
* for one keystroke.
|
|
707
|
+
*/
|
|
708
|
+
export type DomicileShortcutEvent = Event & {
|
|
709
|
+
/**
|
|
710
|
+
* The chord as the shell grabbed it -- `Meta+Shift+l` -- or empty for one
|
|
711
|
+
* grabbed as a keycode. See DomicileHost.grabShortcut().
|
|
712
|
+
*/
|
|
713
|
+
readonly chord: string;
|
|
714
|
+
/** The Linux evdev code, the same numbering key() forwards in. */
|
|
715
|
+
readonly keycode: number;
|
|
716
|
+
readonly altKey: boolean;
|
|
717
|
+
readonly ctrlKey: boolean;
|
|
718
|
+
readonly shiftKey: boolean;
|
|
719
|
+
readonly metaKey: boolean;
|
|
720
|
+
};
|
|
721
|
+
/**
|
|
722
|
+
* One icon in the system tray.
|
|
723
|
+
*
|
|
724
|
+
* An interface rather than a dictionary for DomicileClipboardEntry's reason:
|
|
725
|
+
* WebIDL will not have a dictionary as the element type of an attribute's
|
|
726
|
+
* array, and these are read off DomicileHost.tray.
|
|
727
|
+
*/
|
|
728
|
+
export type DomicileTrayItem = {
|
|
729
|
+
/**
|
|
730
|
+
* What DomicileHost.activateTrayItem() names this icon by: the bus name the
|
|
731
|
+
* application answers on and the object path it answers at, written together.
|
|
732
|
+
*/
|
|
733
|
+
readonly id: string;
|
|
734
|
+
/**
|
|
735
|
+
* What the icon is, in words: its tooltip's title, its title, or its id, the
|
|
736
|
+
* first the application said. Never empty.
|
|
737
|
+
*/
|
|
738
|
+
readonly title: string;
|
|
739
|
+
/**
|
|
740
|
+
* The picture, as a `data:` URL to draw, or empty for one the compositor
|
|
741
|
+
* could not draw. A URL rather than a path: the page may draw what the
|
|
742
|
+
* compositor read and cannot read it.
|
|
743
|
+
*/
|
|
744
|
+
readonly icon: string;
|
|
745
|
+
};
|
|
746
|
+
/**
|
|
747
|
+
* One client window on the desktop, as `DomicileHost.windows` lists it: what
|
|
748
|
+
* the compositor has said about it so far. Replaced, never edited: a change to
|
|
749
|
+
* any window is a new `windows` array and a `windowschanged` event.
|
|
750
|
+
*/
|
|
751
|
+
export type DomicileWindow = {
|
|
752
|
+
readonly appId: string;
|
|
753
|
+
/** Empty until the client names itself. */
|
|
754
|
+
readonly title: string;
|
|
755
|
+
/**
|
|
756
|
+
* The size the client last committed, in CSS pixels; null until it has
|
|
757
|
+
* committed one.
|
|
758
|
+
*/
|
|
759
|
+
readonly width: number | null;
|
|
760
|
+
readonly height: number | null;
|
|
761
|
+
/** The limits the client asked for; null where it asked for none. */
|
|
762
|
+
readonly minWidth: number | null;
|
|
763
|
+
readonly minHeight: number | null;
|
|
764
|
+
readonly maxWidth: number | null;
|
|
765
|
+
readonly maxHeight: number | null;
|
|
766
|
+
readonly cursor: DomicileCursorShape;
|
|
767
|
+
/**
|
|
768
|
+
* A popup's parent window and its place relative to it, and whether it
|
|
769
|
+
* grabbed the pointer; null and false for a toplevel.
|
|
770
|
+
*/
|
|
771
|
+
readonly parent: string | null;
|
|
772
|
+
readonly x: number | null;
|
|
773
|
+
readonly y: number | null;
|
|
774
|
+
readonly grab: boolean;
|
|
775
|
+
};
|
package/dist/domicile-host.js
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
1
|
+
// Generated from the engine's WebIDL by `codegen/generate-domicile-host.ts`.
|
|
2
|
+
// Do not edit. Change the IDL in
|
|
3
|
+
// `packages/domicile-engine/src/third_party/blink/renderer/modules/domicile/`
|
|
4
|
+
// and run `bun run generate` in `packages/chrome-sdk`.
|
|
3
5
|
//
|
|
4
|
-
//
|
|
5
|
-
// `
|
|
6
|
-
// If they disagree, the IDL is correct. See
|
|
7
|
-
// `docs/architecture/WINDOW-DOMICILE.md`.
|
|
6
|
+
// The desktop a shell is handed (`Shell(root, domicile)`). There is no global;
|
|
7
|
+
// a shell keeps what it was handed. See `shell.ts`.
|
|
8
8
|
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// no global is declared here; a shell keeps what it was handed. See
|
|
12
|
-
// `shell.ts`.
|
|
13
|
-
//
|
|
14
|
-
// Sizes and coordinates are fractional CSS pixels, except in
|
|
15
|
-
// {@link DomicileDisplay}. Keycodes are Linux evdev codes.
|
|
9
|
+
// Sizes and coordinates are fractional CSS pixels, except in `DomicileDisplay`.
|
|
10
|
+
// Keycodes are Linux evdev codes.
|
|
16
11
|
export {};
|
package/package.json
CHANGED
|
@@ -91,11 +91,12 @@
|
|
|
91
91
|
},
|
|
92
92
|
"scripts": {
|
|
93
93
|
"build": "tsc -p tsconfig.build.json",
|
|
94
|
+
"generate": "bun codegen/generate-domicile-host.ts",
|
|
94
95
|
"test:types": "tsc --noEmit",
|
|
95
96
|
"test:unit": "bun test"
|
|
96
97
|
},
|
|
97
98
|
"type": "module",
|
|
98
|
-
"version": "0.0.0-alpha-
|
|
99
|
+
"version": "0.0.0-alpha-e040773499e5",
|
|
99
100
|
"repository": {
|
|
100
101
|
"type": "git",
|
|
101
102
|
"url": "git+https://github.com/cprussin/domicile.git",
|