# Окно — `$.window`

Всё, что игрок видит «вокруг» игры: заголовок, размер, полноэкранный режим,
курсор и события окна. Низкий уровень — `engine.window.*`, механика — `src/app.c`.

```js
$.window.title('Моя игра');
$.window.size(1280, 720);
$.window.fullscreen(true);
$.window.on('resize', (s) => layout(s.w, s.h));
$.window.on('focus', (on) => { if (!on) $.time.pause(); });
```

---

## 1. Методы

| Вызов | Смысл |
|---|---|
| `title(text?)` | прочитать или задать заголовок |
| `size(w?, h?)` / `pixels()` | логический размер / размер в пикселях |
| `position()` / `move(x, y)` / `center()` | положение окна на рабочем столе |
| `fullscreen(on?)` / `toggleFullscreen()` | полноэкранный режим |
| `show()` / `hide()` / `visible()` | видимость окна |
| `minimize()` / `maximize()` / `restore()` | свёрнуто / развёрнуто / обратно |
| `resize(w, h)` / `resizable(on?)` | изменение размера |
| `focus()` / `focused()` | фокус ввода |
| `vsync(on?)` | вертикальная синхронизация |
| `cursor(name?)` / `cursors()` / `cursorVisible(on?)` | курсор и его видимость |
| `mouseLock(on?)` | захват мыши для взгляда: курсор скрыт, движение только относительное; → включён ли захват на деле |
| `state()` | снимок: `{ w, h, pixel_w, pixel_h, focused, visible, fullscreen }` |
| `on(event, fn)` / `off(event, fn)` | события окна |

События: `resize`, `focus`, `visible`, `fullscreen` — состояние опрашивается раз в
кадр и сравнивается с прошлым, поэтому задержка — один кадр.

## 2. Ограничения

* **системного курсора нет**: `cursor(name)` переключает встроенные формы
  движка (`cursors()` показывает доступные), свой курсор рисуется спрайтом;
* **захват мыши** (`mouseLock`) — режим относительного ввода SDL: скрытое окно
  или окно без фокуса может отказать, поэтому метод возвращает фактическое
  состояние; в вебе это pointer lock, он включается только по жесту
  пользователя;
* **окно одно**: второго окна или откреплённой панели нет;
* **перетаскивание файлов** не поддержано: пути брошенных файлов не приходят;
* **события опрашиваются раз в кадр**: мгновенной реакции на ресайз не ждите.

## 3. Установка

`installWindow($)` ставится при сборке API; `tickWindow()` движок зовёт сам.
Без движка (юнит-тесты) все методы возвращают нули — см. `readState()`.
