# `Drafter.AppRegistry`
[🔗](https://github.com/jaman/drafter/blob/main/lib/drafter/registry/app_registry.ex#L1)

Registry of running application loops, keyed by session.

A loop registers itself under its session id — the compositor pid held in the
calling process's dictionary — so concurrent sessions do not collide.

`whereis/0` resolves the caller's own session. A caller with no session id gets
the sole registered loop, or `nil` when several are running. Pass an id from
`current_session/0` to `whereis/1` or `send_to_loop/2` to name a loop from a
process that sits outside any session.

Also holds the render frame interval, which per-widget render processes read to
throttle themselves to the application's frame rate.

# `current_session`

```elixir
@spec current_session() :: term()
```

The calling process's session id, for later use with `whereis/1`.

# `ensure_table`

```elixir
@spec ensure_table() :: :ok
```

Creates the backing ETS table if it does not exist. Returns `:ok` either way.

Called by `register/0`, `unregister/0`, and `set_frame_interval/1`, so callers do
not normally need it.

# `get_frame_interval`

```elixir
@spec get_frame_interval() :: pos_integer() | nil
```

The recorded frame interval in milliseconds, or `nil` when none was set or the
registry has not been started.

# `register`

```elixir
@spec register() :: true
```

Registers the calling process as the application loop for its session.

The session id is the `:drafter_compositor` pid in the caller's process
dictionary, so this must be called from the loop process itself, after that pid has
been adopted. Replaces any loop already registered for that session. Returns `true`.

# `send_to_loop`

```elixir
@spec send_to_loop(term()) :: :ok | {:error, :no_loop}
```

Sends a message to the loop resolved by `whereis/0`.

Returns `:ok`, or `{:error, :no_loop}` when no loop resolved.

# `send_to_loop`

```elixir
@spec send_to_loop(term(), term()) :: :ok | {:error, :no_loop}
```

Sends a message to `session`'s loop.

Returns `:ok`, or `{:error, :no_loop}` when that session has no loop.

# `set_frame_interval`

```elixir
@spec set_frame_interval(pos_integer() | nil) :: true
```

Records the render frame interval that per-widget render processes throttle to.

`ms` is a millisecond interval, or `nil` for unthrottled rendering. One value is
held per node, not per session. Returns `true`.

# `unregister`

```elixir
@spec unregister() :: true
```

Removes the entry for the calling process's session. Returns `true`, whether or not
an entry existed.

# `whereis`

```elixir
@spec whereis() :: pid() | nil
```

The live loop for the calling process's session, or `nil`.

Falls back to the sole registered loop when the caller carries no session id.
Returns `nil`, after logging once per node, when there is no session id and several
loops are running.

# `whereis`

```elixir
@spec whereis(term()) :: pid() | nil
```

The live loop registered for `session`, or `nil`.

`session` is an id from `current_session/0`. Falls back to the sole registered
loop when `session` has none of its own.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
