Refreshing Chrome Policies for Dynamic Omarchy Themes

โšก Chromium ๐Ÿ”ง C++ ๐Ÿ‘ค Helmut Januschka

Using managed theme policies and an explicit refresh command to update a running browser.

Update: Policy Refresh Landed

Using Managed Policies

The direct theme CLI approach was not accepted upstream. Discussion with Brave and Chromium reviewers pointed to a supported alternative: Chrome's managed policies can already set theme colors.

However, there was a catch: applying policies took 5+ seconds to take effect. This wasn't the instant response Omarchy users expected.

Refreshing Without the Delay

The remaining gap was an explicit way to refresh policies in a running browser:

# Instantly refresh and apply platform policies
chromium --refresh-platform-policy

The flag asks a running Chrome instance to reload platform policies immediately instead of waiting for the normal refresh interval. It is general policy infrastructure rather than a theme-specific command.

Implementation

Review with Chrome's policy team refined the command name and startup behavior. The final implementation (MERGED --refresh-platform-policy flag) adds:

// chrome/common/chrome_switches.cc
const char kRefreshPlatformPolicy[] = "refresh-platform-policy";

// chrome/browser/ui/startup/startup_browser_creator.cc
// Trigger immediate policy refresh when Chrome is already running
if (command_line.HasSwitch(switches::kRefreshPlatformPolicy)) {
  g_browser_process->browser_policy_connector()->RefreshPlatformPolicies();
  // Return early to prevent opening a new browser window
  return;
}

The command reuses the existing browser policy connector and returns without opening another browser window.

Chrome Release

The change landed for Chrome 142. It applies to managed policies generally, not only theme colors.

Omarchy Integration

The downstream MERGED Omarchy theme integration combines the refresh flag with JSON policy updates:

# Set theme via managed policy (Linux example)
sudo mkdir -p /etc/chromium/policies/managed
echo '{
  "BrowserThemeColor": "#ff6b35"
}' | sudo tee /etc/chromium/policies/managed/theme.json

# Instantly apply to running Chrome instances
chromium --refresh-platform-policy --no-startup-window

For macOS users:

# Create policy directory
sudo mkdir -p /Library/Managed\ Preferences/com.google.Chrome

# Set theme color policy
sudo defaults write /Library/Managed\ Preferences/com.google.Chrome BrowserThemeColor -string "#ff6b35"

# Apply instantly
open -a "Google Chrome" --args --refresh-platform-policy --no-startup-window

Compared with the direct theme CLI, the policy approach:

  1. reads configuration from the existing policy files;
  2. bypasses the normal refresh interval;
  3. lets Chrome's policy and theme systems apply the update;
  4. works with existing managed deployments.

Brave Integration

Brave cherry-picked the change for its Chrome 141-based release.

Other Uses

The --refresh-platform-policy flag is not theme-specific. Managed deployments can use it to reload any platform policy without restarting the browser.

The theme use case therefore resulted in a general policy-refresh command.


The Initial Request

The work started with a request from DHH: change Chrome's theme colors dynamically from the command line.

The context was important - when Chrome uses GTK/Qt themes, this already works automatically. But when using Chrome's "Classic" theme (which many prefer for consistency across platforms), there was no CLI way to control colors. While you could manually change themes through settings for each instance, Omarchy needed scriptable control - just like it has for other applications.

The proposed interface was:

# Change theme when using Chrome's Classic theme
chrome --set-user-color="255,0,0"

For Omarchy, the requirement was consistency with its other scriptable desktop theme integrations.

Why Scriptable Theming Was Needed

The gap in Chrome's theming:

The request highlighted the difference between Classic-theme configuration and the existing GTK/Qt integration.

Existing Theme Infrastructure

Most of the required theme behavior already existed in Chromium. The direct CLI prototype connected that infrastructure to a new entry point.

The Implementation

Finding the Existing Code

Chrome's theme system already included the required primitives:

// Theme colors are defined in the ThemeService
class ThemeService : public KeyedService {
  // Material Design 3 (GM3) color generation
  ui::ColorProviderManager::Key GetColorProviderKey();

  // This notifies observers when theme changes
  void NotifyThemeChanged();
};

The Material Design 3 (GM3) theming logic was all there - it just needed a CLI entry point.

Adding Command-Line Support

The implementation added several switches that work together:

// Core theme switches in chrome_switches.cc
const char kSetDefaultTheme[] = "set-default-theme";      // Reset to system
const char kSetUserColor[] = "set-user-color";            // GM3 seed color
const char kSetColorScheme[] = "set-color-scheme";        // light/dark/system
const char kSetColorVariant[] = "set-color-variant";      // Material variants
const char kSetGrayscaleTheme[] = "set-grayscale-theme";  // Grayscale overlay

The switches can be combined:

# Dark blue vibrant theme
chrome --set-user-color="100,150,200" \
       --set-color-scheme="dark" \
       --set-color-variant="vibrant"

# Light neutral theme with custom color
chrome --set-user-color="255,107,53" \
       --set-color-scheme="light" \
       --set-color-variant="neutral"

# System theme with grayscale
chrome --set-color-scheme="system" \
       --set-grayscale-theme="true"

Leveraging Chrome's Theme System

The prototype reused:

Combined with --no-startup-window, it could update a running instance without opening another window.

Alternative: A GTK Theme Generator

A separate experiment generated GTK themes from Chrome's Material Design 3 colors: material-gtk-generator.

# Generate a GTK theme from Chrome's GM3 colors
material-gtk-generator --seed-color="#FF6B6B" --output-dir=~/.themes/

If the Chromium CL did not land, Omarchy could generate a matching GTK theme, apply it system-wide, and let Chrome consume it through the existing Linux theme integration. The tool remains useful for matching other GTK applications to the same palette.

The Omarchy Chromium Fork

While upstream review continued, Omarchy used dedicated build infrastructure to distribute the direct CLI prototype through Omarchy Chromium. DHH's video explains the downstream-fork approach.

The Patch

The direct CLI prototype is contained in one CL (ABANDONED Direct CLI approach - superseded by policy approach):
It connects the command-line switches to the existing theme service and can be rebased as a downstream patch.

Real-World Usage

For Omarchy Users

Omarchy's theme switcher writes the policy value and asks the running browser to refresh it alongside the other desktop theme updates.

For Scripts

The CLI switches can be used for automation:

# Match browser to terminal theme (Classic theme only)
chromium --set-user-color="$(get-terminal-color-rgb)"

# Different themes for different workspaces with variants
workspace-1: chromium --set-user-color="26,26,26" \
                      --set-color-variant="neutral"
workspace-2: chromium --set-user-color="0,43,54" \
                      --set-color-variant="tonal_spot"

# Time-based theming with color schemes
if [[ $(date +%H) -gt 18 ]]; then
  chromium --set-color-scheme="dark" \
           --set-user-color="0,0,0"
else
  chromium --set-color-scheme="light" \
           --set-user-color="255,255,255"
fi

# Update running instances without opening new window
chromium --no-startup-window \
         --set-user-color="100,200,150" \
         --set-color-variant="expressive"

Note: This works specifically with Chrome's Classic theme. If you're using GTK/Qt themes, Chrome already responds to system theme changes automatically.

Integration with Window Managers

Window managers can now theme browsers to match the desktop:

# Example i3wm integration
import i3ipc
import subprocess

def on_workspace_focus(i3, event):
    workspace = event.current.name
    themes = {
        "1: term": ("0,0,0", "dark", "neutral"),
        "2: web": ("26,26,46", "dark", "tonal_spot"),
        "3: code": ("15,52,96", "dark", "vibrant")
    }
    if workspace in themes:
        color, scheme, variant = themes[workspace]
        subprocess.run([
            "chromium",
            "--no-startup-window",
            f"--set-user-color={color}",
            f"--set-color-scheme={scheme}",
            f"--set-color-variant={variant}"
        ])

i3 = i3ipc.Connection()
i3.on("workspace::focus", on_workspace_focus)
i3.main()

Current State

Upstream Progress

The direct CLI approach (ABANDONED CL 6832165) was superseded by the policy-based solution (MERGED CL 6900896), which landed in Chrome 142.

Extended Features

The direct CLI prototype includes:

Other Browsers

Brave has discussed downstream use of the direct CLI patch.

Using the Downstream Build

For Arch/Omarchy Users

The AUR package is available (replaces the standard Chromium):

yay -S omarchy-chromium-bin

# Teal expressive theme
chromium --set-user-color="78,205,196" \
         --set-color-variant="expressive"

# Reset to default
chromium --set-default-theme

The upstream solution uses Chrome's existing policy system; the downstream fork retains the more direct theme CLI.

Links: