Packages

Multi-surface application runtime for Elixir. One TEA module renders to terminal, browser (LiveView), SSH, and MCP (agents). 30+ widgets, flexbox + CSS grid, AI agent runtime, distributed swarm with CRDTs, time-travel debugging, session recording, sandboxed REPL, and agentic commerce.

Current section

Files

Jump to
raxol lib raxol terminal window window_manager.ex
Raw

lib/raxol/terminal/window/window_manager.ex

defmodule Raxol.Terminal.Window.Manager do
@moduledoc """
Refactored Window.Manager that delegates to GenServer implementation.
This module provides the same API as the original Terminal.Window.Manager but uses
a supervised GenServer instead of the Process dictionary for state management.
## Migration Notice
This module is a drop-in replacement for `Raxol.Terminal.Window.Manager`.
All functions maintain backward compatibility while providing improved
fault tolerance and functional programming patterns.
## Benefits over Process Dictionary
- Supervised state management with fault tolerance
- Pure functional window management
- Z-order window stacking support
- Spatial navigation mapping
- Better debugging and testing capabilities
- No global state pollution
## New Features
- Window Z-ordering for proper stacking
- Spatial position tracking for navigation
- Custom navigation paths between windows
- Hierarchical window relationships
"""
alias Raxol.Terminal.Window.Manager.WindowManagerServer, as: Server
alias Raxol.Terminal.{Window, Config}
@type t :: %{tabs: map()}
@type window_id :: String.t()
@type window_state :: :active | :inactive | :minimized | :maximized
@doc """
Ensures the Window Manager server is started.
"""
def ensure_started do
case Process.whereis(Server) do
nil ->
case Server.start_link() do
{:ok, _pid} -> :ok
{:error, {:already_started, _pid}} -> :ok
error -> error
end
_pid ->
:ok
end
end
@doc """
Creates a new window manager instance.
For backward compatibility, returns {:ok, pid()} of the GenServer.
"""
@spec new() :: {:ok, pid()}
def new() do
start_link()
end
@doc """
Creates a new window manager instance for testing.
Returns a simple map structure instead of a process.
"""
@spec new_for_test() :: map()
def new_for_test() do
%{
title: "",
icon_name: "",
icon_title: "",
windows: %{},
active_window: nil,
state: :normal,
size: {80, 24}
}
end
@doc """
Starts the window manager.
"""
@spec start_link() :: {:ok, pid()}
def start_link, do: start_link([])
@spec start_link(list()) :: {:ok, pid()}
def start_link(_opts) do
ensure_started()
# Return self() for backward compatibility with Process dictionary version
{:ok, self()}
end
@doc """
Gets the window manager state as a map.
"""
@spec get_state(pid()) :: map()
def get_state(_pid) do
ensure_started()
Server.get_state()
end
@doc """
Gets the window state.
"""
@spec get_window_state(pid()) :: atom()
def get_window_state(_pid) do
ensure_started()
Server.get_window_state()
end
@doc """
Gets the window size.
"""
@spec get_window_size(pid()) :: {integer(), integer()}
def get_window_size(_pid) do
ensure_started()
Server.get_window_size()
end
@doc """
Sets the window state.
"""
@spec set_window_state(pid(), atom()) :: :ok
def set_window_state(pid, state) when is_pid(pid) do
ensure_started()
Server.set_window_state(state)
end
@spec set_window_state(window_id(), window_state()) ::
{:ok, Window.t()} | {:error, :not_found}
def set_window_state(id, state) do
ensure_started()
Server.set_window_state(Server, id, state)
end
@doc """
Sets the window size.
"""
@spec set_window_size(pid(), integer(), integer()) :: :ok
def set_window_size(pid, width, height)
when is_pid(pid) and width > 0 and height > 0 do
ensure_started()
Server.set_window_size(width, height)
end
def set_window_size(pid, _width, _height) when is_pid(pid) do
# Ignore invalid sizes (negative or zero)
:ok
end
@spec set_window_size(window_id(), integer(), integer()) ::
{:ok, Window.t()} | {:error, :not_found}
def set_window_size(id, width, height) do
ensure_started()
Server.set_window_size(Server, id, width, height)
end
@doc """
Sets the window title.
"""
@spec set_window_title(pid(), String.t()) :: :ok
def set_window_title(pid, title) when is_pid(pid) do
ensure_started()
Server.set_window_title(title)
end
@spec set_window_title(window_id(), String.t()) ::
{:ok, Window.t()} | {:error, :not_found}
def set_window_title(id, title) do
ensure_started()
Server.set_window_title(Server, id, title)
end
@doc """
Sets the icon name.
"""
@spec set_icon_name(pid(), String.t()) :: :ok
def set_icon_name(pid, icon_name) when is_pid(pid) do
ensure_started()
Server.set_icon_name(icon_name)
end
@spec set_icon_name(t(), String.t()) :: t()
def set_icon_name(manager, _icon_name) do
# For test purposes, just return the manager
manager
end
@doc """
Creates a new window with the given configuration.
"""
@spec create_window(Config.t()) :: {:ok, Window.t()} | {:error, term()}
def create_window(%Config{} = config) do
ensure_started()
Server.create_window(config)
end
@doc """
Creates a new window with dimensions.
"""
@spec create_window(integer(), integer()) ::
{:ok, Window.t()} | {:error, term()}
def create_window(width, height)
when is_integer(width) and is_integer(height) do
ensure_started()
Server.create_window(width, height)
end
@doc """
Gets a window by ID.
"""
@spec get_window(window_id()) :: {:ok, Window.t()} | {:error, :not_found}
def get_window(id) do
ensure_started()
Server.get_window(id)
end
@doc """
Destroys a window by ID.
"""
@spec destroy_window(window_id()) :: :ok | {:error, :not_found}
def destroy_window(id) do
ensure_started()
Server.destroy_window(id)
end
@doc """
Lists all windows.
"""
@spec list_windows() :: {:ok, [Window.t()]}
def list_windows do
ensure_started()
Server.list_windows()
end
# Additional helper functions
@doc """
Sets the active window.
"""
def set_active_window(window_id) do
ensure_started()
Server.set_active_window(window_id)
end
@doc """
Gets the active window.
"""
def get_active_window do
ensure_started()
Server.get_active_window()
end
@doc """
Moves a window to the front (top of Z-order).
"""
def move_window_to_front(window_id) do
ensure_started()
Server.move_window_to_front(window_id)
end
@doc """
Moves a window to the back (bottom of Z-order).
"""
def move_window_to_back(window_id) do
ensure_started()
Server.move_window_to_back(window_id)
end
@doc """
Registers a window's spatial position for navigation.
"""
def register_window_position(window_id, x, y, width, height) do
ensure_started()
Server.register_window_position(window_id, x, y, width, height)
end
@doc """
Defines a navigation path between windows.
"""
def define_navigation_path(from_id, direction, to_id) do
ensure_started()
Server.define_navigation_path(from_id, direction, to_id)
end
@doc """
Counts the number of windows.
"""
def count_windows do
ensure_started()
{:ok, windows} = Server.list_windows()
length(windows)
end
@doc """
Checks if a window exists.
"""
def window_exists?(window_id) do
ensure_started()
case Server.get_window(window_id) do
{:ok, _} -> true
{:error, :not_found} -> false
end
end
@doc """
Sets the window position.
"""
@spec set_window_position(window_id(), integer(), integer()) ::
{:ok, Window.t()} | {:error, :not_found}
def set_window_position(id, x, y) do
ensure_started()
Server.set_window_position(id, x, y)
end
@doc """
Creates a child window.
"""
@spec create_child_window(window_id(), Config.t()) ::
{:ok, Window.t()} | {:error, term()}
def create_child_window(parent_id, config) do
ensure_started()
Server.create_child_window(parent_id, config)
end
@doc """
Gets child windows of a parent.
"""
@spec get_child_windows(window_id()) ::
{:ok, [Window.t()]} | {:error, :not_found}
def get_child_windows(parent_id) do
ensure_started()
Server.get_child_windows(parent_id)
end
@doc """
Gets the parent window of a child.
"""
@spec get_parent_window(window_id()) ::
{:ok, Window.t()} | {:error, :not_found | :no_parent}
def get_parent_window(child_id) do
ensure_started()
Server.get_parent_window(child_id)
end
@doc """
Resets the window manager to initial state.
"""
def reset do
ensure_started()
Server.reset()
end
end