# Window
A **WindowApplication** — the object returned by `wm.open(...)` — is one live window in the SGApps window-manager. It owns a DOM node, a header, a content section, and a lifecycle (open → focus/blur → close). Every method below is bound directly on the returned instance; there are no factories or handles in between.
Related: [Window Manager](window-manager.md) covers how to open one; [Dialogs](dialogs.md) covers modal-child windows spawned from any window instance.
## Try it live
The buttons below open real WM windows in this page. First click loads the SDK via `exporter.js` (~1 s); subsequent clicks reuse the same window-manager instance. Close a window via its × button or use "Close all demo windows" below to clear them.
**Open blank windows** — a plain WM window whose `container()` you fill with your own DOM:
▶ Open hello window
▶ Open form example
▶ Open custom (empty)
▶ Open with geometry
**Open full apps** — real SGApps applications booted inside the b2b runtime. First click loads the app module (~1-3 s per app):
▶ Open file-manager
▶ Open code-editor
▶ Open writer
▶ Open spreadsheet
> **Behind the scenes:** the boot script shims `Application.notifyService()` (which many full apps expect but the bare b2b runtime doesn't ship) with the real notify service when available, or `console` as a fallback. In your own integration, load `elements/notify-service` and bind it via `App.bind("notifyService", …)` — see the source of `/scripts/application.js:113-131` for the reference implementation.
**State & chrome:**
▶ Maximize → restore
▶ Toggle chrome
▶ Confirm-before-close
**Cleanup:**
✕ Close all demo windows
## Obtaining a window
```js
// 1. Open a new one from the window-manager
var win = wm.open({ run: ["code-editor"], width: 900, height: 600 });
// 2. From inside an SGApps app, the app's own window is available
// via `this.window()` (in a WindowApplicationInterface constructor)
var win = this.window();
// 3. Iterate every open window in the manager
wm.windows().forEach(function (w) { console.log(w.title()); });
```
## Method reference
Every getter/setter uses the same pattern: **call with no argument → read**, **call with a value → write and return the value**.
### Identity & DOM access
| Method | Description |
|---|---|
| `win.node()` | Root `` DOM element |
| `win.header()` | `` element (title bar) |
| `win.footer()` | `` element (usually hidden) |
| `win.container()` | Content `` — mount your own UI here |
| `win.headerContainer()` | Container within the header for the title text and icon |
| `win.headerControlsContainer()` | Container within the header for close/minimize/maximize buttons |
### Title & icon
| Method | Description |
|---|---|
| `win.title(str?)` | Get or set the title bar text |
| `win.icon(str?)` | Get or set the window icon (path in an icon set — e.g. `"paper/icons/mimetypes/32/text-x-generic"`) |
| `win.description(str?)` | Get or set the description tooltip |
```js
win.title("main.js");
win.icon("paper/icons/mimetypes/32/application-javascript");
win.description("Editing main.js in the code editor");
```
### Geometry
| Method | Description |
|---|---|
| `win.width(n?)` / `win.height(n?)` | Get or set outer size in pixels (minimum enforced: 100 px) |
| `win.top(n?)` / `win.left(n?)` | Get or set position |
| `win.innerHeight()` / `win.innerWidth()` | Read the content-area (section) dimensions |
| `win.redraw()` / `win.redrawImmediate()` | Recompute the content-area geometry after a size change or a chrome-visibility toggle |
```js
win.width(1200);
win.height(800);
win.top(60);
win.left(80);
```
Every `width` / `height` / `top` / `left` setter triggers `redraw()` internally, so the section's `position: absolute` positioning updates without a manual call.
### State — maximized / minimized / pinned
| Method | Description |
|---|---|
| `win.maximize(bool?)` | Get or set maximized state |
| `win.minimize(bool?)` | Get or set minimized state |
| `win.pinned(node?)` | Pin the window inside a specific DOM element (embed-in-page pattern) |
| `win.pinnedBefore(bool?)` | Legacy pinned-flag accessor |
| `win.restore()` | Restore from maximized or pinned state |
```js
win.maximize(true);
setTimeout(function () { win.restore(); }, 3000);
// Pin the window inside a specific container element (great for
// embedding a single app as a widget on a normal HTML page)
win.pinned(document.getElementById("my-widget-slot"));
```
### Chrome visibility
The taskbar/dock trims some chrome by default; these toggles let you strip more when embedding.
| Method | Description |
|---|---|
| `win.controls(bool?)` | Show or hide the whole title bar |
| `win.controlsHeader(bool?)` | Show or hide the header (icon + title + control buttons) |
| `win.controlsHeaderActions(bool?)` | Show or hide the close/minimize/maximize/fullscreen buttons only |
| `win.controlsFooter(bool?)` | Show or hide the footer strip |
### Focus & close
| Method | Description |
|---|---|
| `win.focus()` | Bring the window to front (updates z-index) |
| `win.close(force?)` | Close the window. `force: false` (default) fires `closeRequest` and gives subscribers 500 ms to abort. `force: true` skips the abort window entirely |
```js
win.focus();
// Ask nicely (respects abort)
win.close();
// Force close (bypasses closeRequest handlers)
win.close(true);
```
### Environment & arguments
Every window carries an `env()` object — a merge of the window-manager's global env plus anything passed via `wm.open({ env: {...} })`. It includes the parsed `args`.
| Method | Description |
|---|---|
| `win.env(obj?)` | Get the merged environment, or extend it with `obj` |
| `win.args()` | Parsed arg-map: `--flag` → `{flag: true}`, `--key=value` → `{key: "value"}`, other tokens → `_paths[]` |
| `win.windowManager()` | Reference back to the parent window-manager |
```js
// wm.open({ run: ["code-editor", "--no-sidebar", "/home/user/file.js"] })
console.log(win.args());
// → { "no-sidebar": true, _paths: ["/home/user/file.js"] }
```
### Class management
| Method | Description |
|---|---|
| `win.addClass(str)` | Add `windowManager--window-class--` to the node |
| `win.removeClass(str)` | Remove that class |
Useful for driving CSS variants from your own app:
```js
win.addClass("my-app"); // → .windowManager--window-class--my-app
win.addClass("dark-theme");
```
### Helpers & dialogs
| Method | Description |
|---|---|
| `win.helpers()` | Utility helpers — `adjustToMinSize(w, h)`, `toolbar(config)` |
| `win.dialogs()` | Modal-child dialog factory. See [Dialogs](dialogs.md) |
| `win.toolbarNode(bool\|"default")` | Show/hide/create the auxiliary toolbar node |
| `win.scrolling(bool\|"x"\|"y")` | Enable or restrict content scrolling |
## Events
Every window is an `ApplicationPrototype` instance — listen with `win.on(event, handler)` and emit with `win.emit(event, args)`.
| Event | Payload | Fires when |
|---|---|---|
| `focus` | `()` | Window is brought to front |
| `blur` | `()` | Another window took focus |
| `closeRequest` | `(abort)` | Soft-close initiated; call `abort()` to cancel |
| `closed` | `({force})` | Window has been removed — final teardown moment |
| `event:keydown` | `(ev)` | Key pressed while the window's internal keyboard-capture input has focus |
| `event:keyup` | `(ev)` | Corresponding keyup |
| `event:keypressed` | `(ev)` | Composite keypress (fired after keydown → keyup with the same key) |
| `event:transfer-input` | `()` | Programmatic request to refocus the capture input |
| `action--move` | `(cb)` | User started dragging the window; `cb(newPos)` reports position on drop |
| `action--resize` | `(conf, cb)` | User started resizing; `cb(newSize)` reports size on drop |
## Lifecycle
```
wm.open(conf)
│
1. WindowApplication is constructed — DOM node created, chrome
rendered, `focus` handler wired
│
2. `app.emit("window:open", [win])` on the manager
│
3. Optional app-loader stage — if `conf.run` names a registered app,
the app's module is required, `new AppCtor()`, `handleWindow(win)`,
and `init()`; on success `window:app:loaded` fires
│
4. [live] user interaction — focus, resize, drag, minimize, maximize
│
5. `win.close()` (or user clicks the ✕):
a. `window:close-request` on manager + `closeRequest(abort)` on win
b. If `abort()` was NOT called → 500 ms delay
c. DOM node removed
d. `window:close` on manager + `closed({force:false})` on win
│
OR `win.close(true)` — skips steps a-b, jumps straight to c-d
with `{force:true}` in the payload.
```
## Common patterns
### 1. Confirm before close
```js
var dirty = false;
win.on("someContentChange", function () { dirty = true; });
win.on("closeRequest", function (abort) {
if (!dirty) return; // clean → allow the close
abort(); // hold it while we ask
win.dialogs().confirm("Discard unsaved changes?", {
destructive: true,
yesLabel: "Discard",
noLabel: "Keep editing"
}).then(function (r) {
if (r.result) win.close(true); // bypass this handler on the second pass
});
});
```
### 2. Attach your own UI to `container()`
```js
var win = wm.open({ width: 640, height: 480 });
win.title("My widget");
win.icon("paper/icons/apps/preferences-desktop-color");
var root = document.createElement("div");
root.style.padding = "16px";
root.innerHTML = 'Hello Custom UI mounted directly.
';
win.container().appendChild(root);
```
### 3. Read parsed launch arguments
```js
// wm.open({ run: ["my-app", "--verbose", "--theme=dark", "/home/user/x.txt"] })
// inside your app's `render()`:
var a = this.window().args();
if (a.verbose) enableLogging();
if (a.theme) applyTheme(a.theme);
a._paths.forEach(loadFile);
```
### 4. `api-request::instance` bridge — expose a control surface
Windows containing embedded apps expose an event-based control API so foreign scripts (or a taskbar / dashboard) can drive them without a direct reference:
```js
// Inside the embedded app:
win.on("api-request::attached", function () {
win.on("api-request::ready", function (cb) { cb(readyPromise); });
win.on("api-request::instance", function (cb) { cb(null, this); });
win.on("api-request::instance:save", function (cb) {
saveState().then(function () { cb(null, "ok"); }, cb);
});
});
// From an outside driver (e.g. a taskbar widget):
win.emit("api-request::instance:save", [function (err, msg) {
console.log("save →", err || msg);
}]);
```
### 5. Pin a window inside your own layout
```js
// wm.open() the window as usual, then pin it inside a container.
// The window will size to that container and lose its floating chrome.
var win = wm.open({ run: ["code-editor"] });
win.pinned(document.getElementById("my-editor-slot"));
```
## WindowApplicationInterface (for custom apps)
When you write your own app to run inside the manager (see [Building Custom Apps](building-custom-apps.md)), your constructor must return an object implementing:
| Method | Contract |
|---|---|
| `node()` | Return the root DOM element the manager will insert into the window's `container()` |
| `handleWindow(win)` | Receive the `WindowApplication` — cache it and wire the `api-request::attached` handshake |
| `window()` | Return the cached `WindowApplication` |
| `ready()` | Return a `Promise` that resolves once `init()` → `render()` finishes |
| `render(cb)` | Build the UI, parse `win.env().args`, call `cb()` when done |
| `init()` | Kick off `render()` and return `this` |
| `destroy()` | Clean up subscriptions and DOM listeners — fires on `win.on("closed", ...)` |
## Related
- [Window Manager](window-manager.md) — how to open windows and manage the desktop
- [Dialogs](dialogs.md) — modal-child dialogs spawned from any window
- [Building Custom Apps](building-custom-apps.md) — write your own app to run in the WM
- [API Communication](api-communication.md) — postMessage bridge for iframe-embedded windows