Skip to content

Add per-window theme overrides#58755

Open
42piratas wants to merge 1 commit into
zed-industries:mainfrom
42piratas:per-window-theme
Open

Add per-window theme overrides#58755
42piratas wants to merge 1 commit into
zed-industries:mainfrom
42piratas:per-window-theme

Conversation

@42piratas
Copy link
Copy Markdown

@42piratas 42piratas commented Jun 6, 2026

What

Let each window use its own theme, chosen by the user, so multiple open projects are visually distinguishable at a glance (e.g. prod vs staging, frontend vs backend). The choice is stored user-side, keyed by workspace, and never written to project settings or settings.json.

Addresses #22370, #19510, and the discussion in #32293.

How it works

The active theme is a single app global read at ~155 cx.theme() call sites, so rather than thread a per-window theme through all of them, the active theme is swapped per window at the start of its render pass:

  • gpui: App::observe_window_draw runs a callback at the top of each Window::draw; App::update_global_quietly mutates a global without scheduling an observer notification (a per-frame notify would cause an unbounded redraw loop).
  • theme: WindowThemeOverrides registry keyed by WindowId. GlobalTheme now distinguishes the per-frame active theme from the configured fallback. A draw hook sets the active theme to the window's override, or the configured theme if none. Because editors build their style (including syntax) live in render, this restyles the whole UI per window with no call-site changes.
  • theme_selector: theme: project (scopes the picker to the current project's window) and theme: clear project.
  • workspace: a window_theme_overrides table (keyed by workspace) persists the choice; it is restored in load_workspace on launch.

Out of scope

Reading a theme from a project's .zed/settings.json (intentionally excluded — keeps the "user decides, an untrusted repo can't restyle the editor" property); per-pane theming.

Known tradeoff

Theme reads that happen outside a render pass (rare — some event handlers) observe the last-drawn window's theme. Everything rendered is correct per window.

Testing

Open two windows on different folders → command palette → theme selector: toggle window in each → pick different themes. Confirm no theme key is written to any settings file; clear window theme reverts to global; quit + relaunch restores each window's theme.

@cla-bot
Copy link
Copy Markdown

cla-bot Bot commented Jun 6, 2026

We require contributors to sign our Contributor License Agreement, and we don't have @42piratas on file. You can sign our CLA at https://zed.dev/cla. Once you've signed, post a comment here that says '@cla-bot check'.

@zed-community-bot zed-community-bot Bot added the first contribution the author's first pull request to Zed. NOTE: the label application is automated via github actions label Jun 6, 2026
@42piratas
Copy link
Copy Markdown
Author

@cla-bot check

@cla-bot cla-bot Bot added the cla-signed The user has signed the Contributor License Agreement label Jun 6, 2026
@cla-bot
Copy link
Copy Markdown

cla-bot Bot commented Jun 6, 2026

The cla-bot has been summoned, and re-checked this pull request!

@42piratas 42piratas marked this pull request as ready for review June 6, 2026 18:36
@42piratas 42piratas mentioned this pull request Jun 6, 2026
1 task
@MrSubidubi MrSubidubi requested a review from probably-neb June 6, 2026 20:22
Allow each window to use its own theme, chosen by the user and stored user-side keyed by workspace, without changing the app-wide `theme` setting or writing any project file. Windows without an override render the configured theme as before.

- gpui: add `App::observe_window_draw` hook (runs at the start of each window's draw) and `App::update_global_quietly` for per-frame global updates that must not notify observers.

- theme: add `WindowThemeOverrides` registry keyed by `WindowId`; split `GlobalTheme` into the per-frame active theme and the configured fallback; swap the active theme per window in a draw hook; drop a window's override when it closes.

- theme_selector: add `theme: project` and `theme: clear project` actions that scope theme selection to the current project's window.

- workspace: persist overrides in a new `window_theme_overrides` table and restore them on launch.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement first contribution the author's first pull request to Zed. NOTE: the label application is automated via github actions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant