# How Ventoy Implements Theme Switching in the F5 Tools Menu

> Discover how Ventoy implements F5 Tools theme switching. Explore dynamic GRUB menu generation and custom commands that modify the theme environment variable for seamless customization.

- Repository: [longpanda/Ventoy](https://github.com/ventoy/Ventoy)
- Tags: internals
- Published: 2026-03-01

---

**Ventoy implements F5 Tools theme switching by scanning `/ventoy/themes` at boot, dynamically generating GRUB menu entries for each discovered theme, and applying selections through custom GRUB commands that modify the `theme` environment variable.**

The F5 Tools menu in Ventoy provides a **Theme Select** option that allows users to switch GUI themes without rebooting or modifying configuration files manually. This functionality is implemented entirely within the GRUB2 plugin architecture in the `ventoy/Ventoy` repository, specifically through runtime menu injection and custom GRUB commands defined in [`ventoy_plugin.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_plugin.c).

## Theme Discovery and Linked List Management

When the Ventoy plugin initializes, `ventoy_plugin_init()` scans the directory structure for available themes. By default, it searches `/ventoy/themes` (or custom paths defined in [`ventoy.json`](https://github.com/ventoy/Ventoy/blob/main/ventoy.json)) and builds a singly-linked list of available themes.

The following global variables manage the theme state in [`GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_plugin.c`](https://github.com/ventoy/Ventoy/blob/main/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_plugin.c):

- **`g_theme_head`** – Head pointer to the linked list of `theme_list` nodes
- **`g_theme_num`** – Count of discovered theme files
- **`g_theme_single_file`** – Path when only one theme exists
- **`g_theme_id`** – Index of the currently selected theme (0 indicates none)

This discovery phase populates the data structures necessary for the dynamic menu generation that follows.

## Dynamic Menu Generation for Theme Select

The static structure of the F5 Tools menu is defined in [`INSTALL/grub/debug.cfg`](https://github.com/ventoy/Ventoy/blob/main/INSTALL/grub/debug.cfg), which contains a placeholder submenu for theme selection:

```text
submenu "$VTLANG_THEME_SELECT" --class=debug_theme_select --class=F5tool {
    …
}

```

During plugin initialization, the function `ventoy_plugin_build_fstools_menu()` (around line 3300 in [`ventoy_plugin.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_plugin.c)) iterates over the theme linked list and constructs a temporary GRUB script. For each theme node, it generates a `menuentry` that calls the custom command `vt_set_theme_path`:

```c
/* ventoy_plugin.c – L3382-L3386 */
pos += grub_snprintf(buf + pos, bufsize - pos,
    "menuentry \"%s\" --class=debug_theme_item "
    "--class=debug_theme_select --class=F5tool {\n"
    "    vt_set_theme_path \"%s\"\n"
    "}\n",
    name,                /* Display name in menu */
    node->theme.path);   /* Full path to theme.txt */

```

The generated buffer is executed via `grub_script_execute_sourcecode(buf)`, which **injects the entries into the submenu at runtime**. When the user presses **F5** and navigates to **Theme Select**, they see dynamically generated entries for every [`theme.txt`](https://github.com/ventoy/Ventoy/blob/main/theme.txt) file discovered during initialization.

## Applying Themes via Custom GRUB Commands

Theme activation relies on two custom GRUB commands implemented in [`ventoy_plugin.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_plugin.c):

**`vt_set_theme_path`** – Implemented by `ventoy_cmd_set_theme_path()` at lines 3517-3529. This command stores the selected theme's file path in the global buffer `g_ventoy_theme_path`.

**`vt_set_theme`** – Implemented by `ventoy_cmd_set_theme()` at lines 3401-3514. This command handles the actual theme application logic.

When a user selects a theme from the F5 Tools menu, the following sequence occurs:

1. The generated menu entry executes `vt_set_theme_path "/ventoy/themes/name/theme.txt"`, storing the path in `g_ventoy_theme_path`.
2. On the next boot or when the user activates the switch, `ventoy_cmd_set_theme()` processes the selection:
   - Checks for single-file scenarios using `g_theme_single_file`
   - Builds a candidate array (`pThemePath`) when multiple themes exist
   - Applies **resolution-fit** filtering if `g_theme_res_fit` is enabled
   - Handles **random selection** modes (second-based, day-based, or month-based) using `g_theme_random` and `grub_get_datetime`
3. Finally, calls `grub_env_set("theme", selected_path)` to update GRUB's `gfxterm` configuration and apply the theme.

## Code Example: Adding a Custom Theme

To add a new theme manually, place a [`theme.txt`](https://github.com/ventoy/Ventoy/blob/main/theme.txt) file in a subdirectory of `/ventoy/themes`. For example, adding [`/ventoy/themes/custom-dark/theme.txt`](https://github.com/ventoy/Ventoy/blob/main//ventoy/themes/custom-dark/theme.txt) triggers this automatic workflow:

```c
/* Discovery phase pseudo-code from ventoy_plugin.c */
if (find_file("/ventoy/themes/custom-dark/theme.txt")) {
    node = grub_zalloc(sizeof(theme_list));
    node->theme.path = "/ventoy/themes/custom-dark/theme.txt";
    /* Insert into g_theme_head linked list */
    g_theme_num++;
}

```

The plugin then generates this menu entry automatically:

```grub
menuentry "custom-dark" --class=debug_theme_item --class=debug_theme_select --class=F5tool {
    vt_set_theme_path "/ventoy/themes/custom-dark/theme.txt"
}

```

When selected, the path propagates through `vt_set_theme_path` to `vt_set_theme`, which executes:

```c
grub_env_set("theme", "/ventoy/themes/custom-dark/theme.txt");

```

No source code modification or recompilation is required; the plugin detects new themes during the boot-time filesystem scan.

## Summary

- **Theme discovery** occurs at plugin initialization in `ventoy_plugin_init()`, which scans `/ventoy/themes` and populates the `g_theme_head` linked list.
- **Dynamic menu injection** happens through `ventoy_plugin_build_fstools_menu()`, which creates GRUB script code containing `menuentry` definitions for each theme and executes it at runtime.
- **Selection storage** uses the `vt_set_theme_path` command (`ventoy_cmd_set_theme_path`) to cache the user's choice in `g_ventoy_theme_path`.
- **Theme activation** is handled by `vt_set_theme` (`ventoy_cmd_set_theme`), which manages resolution filtering, random selection, and ultimately sets the GRUB `theme` variable via `grub_env_set()`.

## Frequently Asked Questions

### Where does Ventoy scan for theme files?

Ventoy scans the `/ventoy/themes` directory by default during `ventoy_plugin_init()`, though users can configure additional paths in the [`ventoy.json`](https://github.com/ventoy/Ventoy/blob/main/ventoy.json) configuration file. The plugin searches recursively for [`theme.txt`](https://github.com/ventoy/Ventoy/blob/main/theme.txt) files and stores their paths in a linked list (`g_theme_head`) for runtime menu generation.

### What GRUB commands handle theme switching?

Ventoy registers two custom commands in [`ventoy_plugin.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_plugin.c): **`vt_set_theme_path`** (stores the selected path in `g_ventoy_theme_path`) and **`vt_set_theme`** (applies the theme by setting the GRUB `theme` environment variable). These commands are called automatically by the dynamically generated menu entries in the F5 Tools submenu.

### Can I use multiple themes with random selection?

Yes. When multiple themes are present, `ventoy_cmd_set_theme()` supports random selection modes controlled by the `g_theme_random` variable. The implementation uses `grub_get_datetime()` to seed random choices based on seconds, days, or months, and can filter themes by screen resolution if `g_theme_res_fit` is enabled.

### How do I add a new theme without modifying source code?

Place your theme's [`theme.txt`](https://github.com/ventoy/Ventoy/blob/main/theme.txt) file in a subdirectory under `/ventoy/themes` (for example, [`/ventoy/themes/mytheme/theme.txt`](https://github.com/ventoy/Ventoy/blob/main//ventoy/themes/mytheme/theme.txt)). The Ventoy plugin automatically discovers the file during boot, generates a corresponding menu entry in the F5 Tools → Theme Select submenu, and makes it available for immediate selection without requiring recompilation or configuration changes.