defmodule Scenic.Driver.Renderling.Window do @moduledoc """ The Scenic for windowed applications. """ alias Scenic.ViewPort alias Scenic.Driver.Renderling.Window.{Config, Nif} use Scenic.Driver require Logger @position_schema [ scaled: [type: :boolean, default: false], centered: [type: :boolean, default: false], orientation: [type: {:in, [:normal, :left, :right, :upside_down]}, default: :normal] ] @window_schema [ title: [type: :string, default: "Scenic Window"], resizeable: [type: :boolean, default: false] ] @opts_schema [ name: [type: {:or, [:atom, :string]}], antialias: [type: :boolean, default: true], position: [type: :keyword_list, keys: @position_schema, default: []], window: [type: :keyword_list, keys: @window_schema, default: []], cursor: [type: :boolean, default: false], key_map: [type: :atom, default: Scenic.KeyMap.USEnglish], on_close: [ type: {:or, [:mfa, {:in, [:restart, :stop_driver, :stop_viewport, :stop_system, :halt_system]}]}, default: :restart ], input_blacklist: [type: {:list, :string}, default: []] ] @doc false @impl Scenic.Driver def validate_opts(opts), do: NimbleOptions.validate(opts, @opts_schema) @doc false @impl true def init(driver, opts) do {width, height} = driver.viewport.size config = opts |> Keyword.update( :window, [width: width, height: height], &Keyword.merge(&1, width: width, height: height) ) |> Config.init() driver = assign(driver, config: config, server: Nif.init(config)) Process.flag(:trap_exit, true) Logger.info("#{inspect(__MODULE__)}: start #{inspect(opts)}, pid: #{inspect(self())}") {:ok, driver} end @doc false @impl true def update_scene(ids, driver) do Enum.reduce_while(ids, {:ok, driver}, fn id, {:ok, driver} -> case ViewPort.get_script(driver.viewport, id) do {:ok, script} -> Nif.update_scene(script, id, driver.assigns.server) {:cont, {:ok, driver}} {:error, reason} -> {:halt, {:error, reason}} end end) end @doc false @impl true def reset_scene(driver) do Nif.reset_scene(driver.assigns.server) {:ok, driver} end @doc false @impl true def del_scripts(ids, driver) do Nif.del_scripts(ids, driver.assigns.server) {:ok, driver} end @doc false @impl true def clear_color(color, driver) do Nif.clear_color(color, driver.assigns.server) {:ok, driver} end @doc false @impl GenServer def terminate(_, driver) do Nif.terminate(driver.assigns.server) end @doc false @impl GenServer def handle_info(:shutdown, driver) do case driver.assigns.config.on_close do :restart -> {:stop, :normal, driver} :stop_driver -> ViewPort.stop_driver(driver.viewport, self()) {:stop, :normal, driver} :stop_viewport -> ViewPort.stop(driver.viewport) {:stop, :normal, driver} :stop_system -> System.stop(:shutdown) {:stop, :normal, driver} :halt_system -> System.halt(:shutdown) {:stop, :normal, driver} {module, _fun, 1} -> module.fun(:shutdown) {:stop, :normal, driver} end end def handle_info(msg, driver) do dbg(msg) {:noreply, driver} end end