Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ryzhpolsos/redeye/llms.txt

Use this file to discover all available pages before exploring further.

Variables are the primary way to separate values from structure in RedEye configuration. Instead of hardcoding pixel sizes and color codes throughout dozens of XML files, you define named values once — in a <variables> block or an imported file — and reference them everywhere else with the ${varName} syntax. Changing a single variable propagates the new value across every widget that references it.

Defining variables

Use a <variables> block with one <set> element per variable. You can place a <variables> block anywhere inside <layout>, inside a <window>, or in any imported file:
<variables>
    <set name="taskbar.item.size" value="50"/>
    <set name="taskbar.margin"    value="20"/>
    <set name="startMenu.width"   value="400"/>
    <set name="startMenu.height"  value="600"/>
</variables>
Variable names are arbitrary strings. The dot-notation convention (e.g. taskbar.margin) is only a naming convention — dots have no special meaning to the parser.

Scoping

Variables are scoped to the ConfigNode in which they are set and are visible to all descendant nodes. A variable set at the <layout> level is accessible everywhere inside the layout; a variable set inside a <window> is only accessible to that window’s children. Variable lookup walks up the node tree until it finds a match or reaches the root, at which point it returns an empty string.
Variables do not propagate upward. Setting a variable inside a child node does not affect the parent or its siblings.

Referencing variables

Use ${variableName} in any attribute value or expression to substitute the variable’s current string value:
<window width="${taskbar.width}" height="${taskbar.height}">
    <panel backgroundColor="${theme.color.background}"/>
</window>
Variable references are evaluated lazily — every time RedEye reads an attribute, it substitutes variables at that moment. This means variables set after a widget is defined can still be resolved correctly as long as they are set before the attribute is actually consumed.

System variables

RedEye automatically sets two variables at startup, before any config files are processed:
VariableValue
screen.widthTotal pixel width of all monitors combined (sum of all screen widths)
screen.heightTotal pixel height of all monitors combined (sum of all screen heights)
These are set from Screen.AllScreens in Config.cs:
<!-- Full-screen desktop window -->
<window
    id="desktop"
    x="0"
    y="0"
    width="${screen.width}"
    height="${screen.height}"
    type="background"
    border="none"/>
Both screen.width and screen.height sum the corresponding dimension across all connected displays. On a multi-monitor setup this means they represent the full virtual desktop span. Plan your layout accordingly if you want to target only the primary monitor.

Theme variables (theme.xml)

The file config/ui/theme.xml defines a shared set of design-token variables that are imported near the top of config.xml. All other UI files reference these tokens, making it possible to restyle the entire shell by editing one file:
<variables id="themevars">
    <!-- Background colors -->
    <set name="theme.color.background"       value="#13293d"/>
    <set name="theme.color.backgroundChild"  value="#2a628f"/>
    <set name="theme.color.backgroundActive" value="#3e92cc"/>

    <!-- Typography -->
    <set name="theme.font.main"  value="Segoe UI,10"/>
    <set name="theme.font.color" value="#ffffff"/>

    <!-- Spacing scale -->
    <set name="theme.paddingLarge"  value="16"/>
    <set name="theme.paddingMiddle" value="8"/>
    <set name="theme.paddingSmall"  value="4"/>
</variables>

Theme token reference

VariableDefaultUsage
theme.color.background#13293dPrimary window background
theme.color.backgroundChild#2a628fSecondary surface color (buttons, panels)
theme.color.backgroundActive#3e92ccHover and active state color
theme.font.mainSegoe UI,10Default font for labels and buttons
theme.font.color#ffffffDefault text color
theme.paddingLarge16Large spacing unit in pixels
theme.paddingMiddle8Medium spacing unit in pixels
theme.paddingSmall4Small spacing unit in pixels
To retheme the shell, override any of these variables before the UI files are imported. Because imports are processed in order, a <variables> block placed after <import from="config/ui/theme.xml"/> will overwrite the defaults:
<import from="config/ui/theme.xml"/>

<layout>
    <variables>
        <!-- Override the theme for a dark red scheme -->
        <set name="theme.color.background"       value="#1a0000"/>
        <set name="theme.color.backgroundChild"  value="#4d0000"/>
        <set name="theme.color.backgroundActive" value="#cc0000"/>
    </variables>

    <import from="config/ui/taskbar.xml"/>
</layout>

calc(...) — arithmetic expressions

The calc() function evaluates a mathematical expression string and returns the numeric result as a string. It is the standard way to compute derived sizes:
<variables>
    <set name="taskbar.height"
         value="calc('${taskbar.item.size} + ${theme.paddingMiddle} * 2')"/>

    <set name="taskbar.width"
         value="calc('${screen.width} - ${taskbar.margin} * 2')"/>

    <set name="workArea.y"
         value="calc('${taskbar.height} + ${taskbar.margin} * 2')"/>
</variables>
The expression inside the single quotes can use standard arithmetic operators (+, -, *, /) and variable substitutions. The result is always a string representation of a number.
Wrap the entire arithmetic string in single quotes so the RWML parser treats it as a string literal before passing it to the arithmetic evaluator. Without quotes, the parser may misinterpret operators as expression delimiters.

Using calc() inline in attribute values

You can also use calc() directly in an attribute value without a <set>:
<windowList
    width="calc('${taskbar.width} - ${taskbar.tray.width} - ${taskbar.item.size}')"/>

expand(...) — environment variable expansion

The expand() function calls Environment.ExpandEnvironmentVariables() on its argument, substituting %VARIABLE% placeholders with Windows environment variable values:
<set name="desktop.wallpaper"
     value="expand('%SYSTEMROOT%\Web\Wallpaper\Windows\img0.jpg')"/>
<image src="res.loadIcon(expand('%SYSTEMROOT%\System32\shell32.dll'), -171)"/>
This lets you reference system paths portably without hardcoding C:\Windows, since %SYSTEMROOT% resolves correctly regardless of the system drive.

Real-world variable example

The following shows the complete variable setup from config.xml, illustrating how system variables, theme tokens, calc(), and expand() work together:
<variables>
    <!-- Taskbar item size -->
    <set name="taskbar.item.size" value="50"/>

    <!-- Computed taskbar dimensions -->
    <set name="taskbar.margin" value="20"/>
    <set name="taskbar.width"
         value="calc('${screen.width} - ${taskbar.margin} * 2')"/>
    <set name="taskbar.height"
         value="calc('${taskbar.item.size} + ${theme.paddingMiddle} * 2')"/>

    <!-- Tray area -->
    <set name="taskbar.tray.width" value="200"/>

    <!-- Work area (space below taskbar) -->
    <set name="workArea.x"      value="0"/>
    <set name="workArea.y"
         value="calc('${taskbar.height} + ${taskbar.margin} * 2')"/>
    <set name="workArea.width"  value="${screen.width}"/>
    <set name="workArea.height"
         value="calc('${screen.height} - ${taskbar.height} - ${taskbar.margin} * 2')"/>

    <!-- Desktop wallpaper path from environment -->
    <set name="desktop.wallpaper"
         value="expand('%SYSTEMROOT%\Web\Wallpaper\Windows\img0.jpg')"/>

    <!-- Start menu dimensions -->
    <set name="startMenu.width"     value="400"/>
    <set name="startMenu.height"    value="600"/>
    <set name="startMenu.item.size" value="50"/>
</variables>

Using variables in widget events

Variable substitution also works in event handler attributes, where the values are evaluated at the time the event fires rather than at load time:
<panel
    backgroundColor="if(${window.isActive},
                        ${theme.color.backgroundActive},
                        ${theme.color.backgroundChild})">
Here ${window.isActive} is a context variable injected by the <windowList> widget for each tracked window, and the if() function selects a theme color based on it.

Build docs developers (and LLMs) love