Workspaces
The multi-window desktop — arrangement, the minimized-window rail, the menu bar, and how a chart layout is persisted to workspace.json and named layouts without ever bricking startup.
The desktop workspace is crates/vike-app-core/src/workspace/mod.rs: multi-window management,
arrangement and layout persistence, split by concern into state (per-window state and the window
chrome loop), arrange (cascade, tile, grid, maximize and restore), persist (the chart layout as
JSON), menu (the menu bar, command emission only) and rail (the left rail of minimized windows).
It is egui-only and free of app content — tool-window view state lives elsewhere — which is what let
it move out of the GUI shell into a crate CI tests.
Windows
crates/vike-app-core/src/workspace/state.rs says how a window behaves: each is a floating
egui::Window, egui owns the live geometry so the user can drag and resize, and the app reads the
rectangle back each frame. An arrange or maximize action forces geometry for a single frame through
pending and then releases it. A freshly opened or restored window is pinned to its intended size
for OPEN_PIN_FRAMES — eight frames — because an unpinned window would otherwise auto-shrink to
its content over the first few frames. WinKind names the twelve kinds and WinKind::LAUNCHERS
the nine in the launcher row; The desktop app lists them.
WinState carries window chrome plus chart content: symbol, interval, the data venue the live bar
feed subscribes to (DEFAULT_VENUE is "binance", the value that keeps every pre-feature path
byte-identical), the picked instrument's asset class for feed routing, style, indicators, scale,
invert, chart options, pane fractions, the sync group, the order-flow toggles and the compare
series. The chart key it builds, series_key, spells a non-Binance series as venue:SYMBOL@interval
and a Binance one bare. Build that key by hand and drop the venue, and every non-Binance series
lands in the Binance-shaped slot — which is why series_key exists as one function rather than a
format string repeated at each call site.
Tool-window view state is deliberately not in WinState. crates/vike-app-core/src/tools.rs's
ToolView is the per-window state for the tool windows (selection, filters, page, expiry, the
order-ticket out-slots), owned by the app keyed by window id and taken out of the map around each
draw; ToolData is the fetch-thread-owned data behind News, Calendar and Options.
Arrange, menu, rail
crates/vike-app-core/src/workspace/arrange.rs's Arrange offers Cascade, TileH, TileV, Grid,
MinimizeAll and RestoreAll, plus per-window maximize and restore. Its naming is explicit: Tile
Horizontal is full-width rows stacked vertically; Tile Vertical is full-height columns side by side.
Arranging never draws — it writes one-frame pending rectangles that the window loop consumes next
frame.
crates/vike-app-core/src/workspace/menu.rs is pure command emission: menu_bar returns a
MenuResult of the actions chosen this frame and the app applies them. File holds New chart window,
Open and Save Workspace, Save layout as…, the Load layout and Delete layout submenus, Export chart
image… and Exit; View holds Timezone; Window holds the six arrange actions and Toggle left panel.
crates/vike-app-core/src/workspace/rail.rs draws the left rail as vertical tabs, one per minimized
window, sized to their rotated text; clicking a tab restores its window. New windows land in a
cascade slot decided by crates/vike-app-core/src/window_spawn.rs, which also builds the window's
state and names the live subscriptions it needs before it can paint.
What is persisted
crates/vike-app-core/src/workspace/persist.rs captures chart windows only. Its header lists the
scope: symbol, interval, style, geometry, minimized and maximized state, follow-live flags, the
price-scale mode, the flattened ChartOptions, the per-pane heights, and per-indicator parameters
and per-line colour and width. WinSnap also carries the venue, the asset class, the invert flag,
pane membership and order, the sync group, the CVD, profile and tick-size order-flow settings, and
the compare series with their panes and axis pins. Tool windows are launcher-recreatable and carry
runtime state, so they are skipped. Workspace adds the globals: the display timezone, the
order-flow backfill hours (default 2.0), the GPU candle-layer toggle (default off) and the indicator
favourites.
The file is $VIKE_WORKSPACE, else <state_dir>/workspace.json, where the state directory is
VIKE_STATE_ROOT or the project's settings/state. It is loaded automatically at startup when
present — skipped under VIKE_SHOT so QA captures stay deterministic — and written only by an
explicit File → Save Workspace. save_path returns an error, never a different location, when no
state directory resolves, and the caller surfaces it: a save that silently landed elsewhere would be
found by nothing.
A corrupt or old file never bricks startup
load_from treats an unparseable file as "no saved workspace" with a warning and falls back to the
default layout. VERSION is 2 and a v1 file still loads: ChartOptions is flattened with a
struct-level default, so every colour and flag absent from an old file takes its custom default
rather than a type-zero, and every later field is #[serde(default)]. Pane keys written under the
old Osc spelling are accepted through a serde alias, because a parse error on one entry would
reset the whole saved workspace.
Named layouts
The single workspace.json stays the default, auto-loaded layout. Any number of named layouts can be
saved as layouts/<name>.json beside it — same schema, same forward-compatibility — driven by
save_layout, load_layout, delete_layout and list_layouts. sanitize_layout_name maps a
user-entered name to a safe filename stem (alphanumerics, dash, underscore and space survive;
everything else becomes an underscore), and the stem is the displayed name. last_layout.txt
remembers the layout last loaded or saved-as so a restart can reopen it; a stale pointer to a
deleted layout is ignored. base_dir is one base for the layouts directory, the pointer file and
the backend registry's backends.json, so the family can never half-move when $VIKE_WORKSPACE
relocates it.
Which windows a fresh launch opens is crates/vike-app-core/src/startup.rs's plan: a restored
workspace (a named layout is preferred over workspace.json when one was last active), one of the
QA capture tool windows, or the default BTCUSDT chart — and, for each, which feeds must be ensured
before it can paint.
Observe mode
vike-desktop --observe against a headless daemon — the one mode the shipped binary can compose, the two the library still declares and nothing reaches, the self-healing bridge, and the control channel that can place real orders.
The trade panel
Order entry and sizing from a window — the equity hero, the per-venue accounts table, the trade card with its size modes, leverage and TP/SL bracket, and the one dispatch chokepoint every order crosses.