From ef950781a5ae29109646bcf174a2959907720da6 Mon Sep 17 00:00:00 2001 From: Lars Vogel Date: Wed, 8 Apr 2026 20:05:23 +0200 Subject: [PATCH 1/2] Scope default theme preference by product or application The default theme preference is now stored under a product-specific (or application-specific) sub-node in user scope. This allows different Eclipse-based products sharing the same user preferences location to maintain independent theme defaults. When reading the preference, the product ID (from Platform.getProduct()) is used as the sub-node key. If no product is configured, the application ID (eclipse.application system property) is used as fallback. If neither is available, the preference is stored at the base node level. This also migrates the 'Manage default theme' dialog from ConfigurationScope to UserScope to be consistent with the rest of the theme preference handling. --- .../internal/workbench/swt/E4Application.java | 24 ++++++++++- .../internal/dialogs/ViewsPreferencePage.java | 43 ++++++++++++++----- 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/internal/workbench/swt/E4Application.java b/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/internal/workbench/swt/E4Application.java index ae478696d50..c673386b635 100644 --- a/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/internal/workbench/swt/E4Application.java +++ b/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/internal/workbench/swt/E4Application.java @@ -317,9 +317,16 @@ private void setCSSContextVariables(IApplicationContext applicationContext, IEcl : getArgValue(E4Application.THEME_ID, applicationContext, false); if (!themeId.isPresent() && !cssURI.isPresent()) { - IEclipsePreferences userScopeNode = UserScope.INSTANCE + IEclipsePreferences themeNode = UserScope.INSTANCE .getNode("org.eclipse.e4.ui.css.swt.theme"); - String defaultThemeId = userScopeNode.get("themeid", DEFAULT_THEME_ID); + String productOrAppId = getProductOrApplicationId(); + String defaultThemeId = null; + if (productOrAppId != null) { + defaultThemeId = themeNode.node(productOrAppId).get("themeid", null); + } + if (defaultThemeId == null) { + defaultThemeId = DEFAULT_THEME_ID; + } context.set(E4Application.THEME_ID, defaultThemeId); } else { context.set(E4Application.THEME_ID, themeId.orElseGet(() -> null)); @@ -403,6 +410,19 @@ private URI determineApplicationModelURI(IApplicationContext appContext) { } + /** + * Returns the product ID if a product is configured, otherwise falls back to + * the application ID from the system property. Returns {@code null} if + * neither is available. + */ + private static String getProductOrApplicationId() { + IProduct product = Platform.getProduct(); + if (product != null) { + return product.getId(); + } + return System.getProperty("eclipse.application"); //$NON-NLS-1$ + } + /** * Finds an argument's value in the app's command line arguments, branding, * and system properties diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/dialogs/ViewsPreferencePage.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/dialogs/ViewsPreferencePage.java index 2194cc629bd..87f2d963a21 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/dialogs/ViewsPreferencePage.java +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/dialogs/ViewsPreferencePage.java @@ -35,6 +35,7 @@ import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.IProduct; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Platform.OS; import org.eclipse.core.runtime.RegistryFactory; @@ -339,8 +340,11 @@ private ITheme getSelectedTheme() { } private void openManageDefaultThemeDialog() { - IEclipsePreferences configNode = ConfigurationScope.INSTANCE.getNode(E4_THEME_EXTENSION_POINT); - String currentDefaultId = configNode.get("themeid", null); //$NON-NLS-1$ + String productOrAppId = getProductOrApplicationId(); + IEclipsePreferences baseNode = UserScope.INSTANCE.getNode(E4_THEME_EXTENSION_POINT); + IEclipsePreferences scopedNode = productOrAppId != null ? (IEclipsePreferences) baseNode.node(productOrAppId) + : baseNode; + String currentDefaultId = scopedNode.get("themeid", null); //$NON-NLS-1$ String currentDefaultLabel = null; if (currentDefaultId != null) { @@ -377,23 +381,36 @@ private void openManageDefaultThemeDialog() { int result = dialog.open(); if (result == 0 && selectedTheme != null) { // Set as default - configNode.put("themeid", selectedTheme.getId()); //$NON-NLS-1$ + scopedNode.put("themeid", selectedTheme.getId()); //$NON-NLS-1$ try { - configNode.flush(); + scopedNode.flush(); } catch (BackingStoreException e) { - WorkbenchPlugin.log("Failed to set default theme in configuration scope", e); //$NON-NLS-1$ + WorkbenchPlugin.log("Failed to set default theme in user scope", e); //$NON-NLS-1$ } } else if (currentDefaultId != null && result == 1) { // Remove default - configNode.remove("themeid"); //$NON-NLS-1$ + scopedNode.remove("themeid"); //$NON-NLS-1$ try { - configNode.flush(); + scopedNode.flush(); } catch (BackingStoreException e) { - WorkbenchPlugin.log("Failed to remove default theme from configuration scope", e); //$NON-NLS-1$ + WorkbenchPlugin.log("Failed to remove default theme from user scope", e); //$NON-NLS-1$ } } } + /** + * Returns the product ID if a product is configured, otherwise falls back to + * the application ID from the system property. Returns {@code null} if + * neither is available. + */ + private static String getProductOrApplicationId() { + IProduct product = Platform.getProduct(); + if (product != null) { + return product.getId(); + } + return System.getProperty("eclipse.application"); //$NON-NLS-1$ + } + @Override public void init(IWorkbench workbench) { MApplication application = workbench.getService(MApplication.class); @@ -521,11 +538,15 @@ protected Control createCustomArea(Composite parent) { int result = dialog.open(); if (result == 0 || result == 1) { // 0: Restart, 1: Don't Restart if (themeId != null && useAsDefault[0]) { - IEclipsePreferences userScopeNode = UserScope.INSTANCE + IEclipsePreferences baseNode = UserScope.INSTANCE .getNode(E4_THEME_EXTENSION_POINT); - userScopeNode.put("themeid", themeId); //$NON-NLS-1$ + String productOrAppId = getProductOrApplicationId(); + IEclipsePreferences scopedNode = productOrAppId != null + ? (IEclipsePreferences) baseNode.node(productOrAppId) + : baseNode; + scopedNode.put("themeid", themeId); //$NON-NLS-1$ try { - userScopeNode.flush(); + scopedNode.flush(); } catch (BackingStoreException e) { WorkbenchPlugin.log("Failed to set default theme in user scope", e); //$NON-NLS-1$ } From 215b38eccd9debc574ae0058db2fb544ae071759 Mon Sep 17 00:00:00 2001 From: Lars Vogel Date: Fri, 10 Apr 2026 11:38:00 +0200 Subject: [PATCH 2/2] Show product/application info in Manage Default Theme dialog The dialog now displays which product or application the default theme applies to, making it transparent that theme defaults are scoped. Examples: - With product: 'Current default theme for Eclipse SDK (org.eclipse.sdk.ide): Dark' - Without product: 'Current default theme for org.eclipse.ui.ide.workbench (org.eclipse.ui.ide.workbench): Dark' - Without either: falls back to unscoped messages --- .../internal/workbench/swt/E4Application.java | 37 +++++++++++++------ .../ui/internal/WorkbenchMessages.java | 2 + .../internal/dialogs/ViewsPreferencePage.java | 29 ++++++++++++++- .../eclipse/ui/internal/messages.properties | 6 ++- 4 files changed, 59 insertions(+), 15 deletions(-) diff --git a/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/internal/workbench/swt/E4Application.java b/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/internal/workbench/swt/E4Application.java index c673386b635..e544e7744b9 100644 --- a/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/internal/workbench/swt/E4Application.java +++ b/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/internal/workbench/swt/E4Application.java @@ -317,19 +317,20 @@ private void setCSSContextVariables(IApplicationContext applicationContext, IEcl : getArgValue(E4Application.THEME_ID, applicationContext, false); if (!themeId.isPresent() && !cssURI.isPresent()) { - IEclipsePreferences themeNode = UserScope.INSTANCE - .getNode("org.eclipse.e4.ui.css.swt.theme"); - String productOrAppId = getProductOrApplicationId(); - String defaultThemeId = null; - if (productOrAppId != null) { - defaultThemeId = themeNode.node(productOrAppId).get("themeid", null); - } - if (defaultThemeId == null) { - defaultThemeId = DEFAULT_THEME_ID; + String defaultThemeId = getProductScopedThemeId(); + if (defaultThemeId != null) { + context.set(E4Application.THEME_ID, defaultThemeId); + } else { + context.set(E4Application.THEME_ID, DEFAULT_THEME_ID); } - context.set(E4Application.THEME_ID, defaultThemeId); } else { - context.set(E4Application.THEME_ID, themeId.orElseGet(() -> null)); + // Check if user has overridden the branding/command-line theme + String userThemeId = getProductScopedThemeId(); + if (userThemeId != null) { + context.set(E4Application.THEME_ID, userThemeId); + } else { + context.set(E4Application.THEME_ID, themeId.orElseGet(() -> null)); + } } @@ -423,6 +424,20 @@ private static String getProductOrApplicationId() { return System.getProperty("eclipse.application"); //$NON-NLS-1$ } + /** + * Returns the user's product-scoped theme preference, or {@code null} if + * none is set. + */ + private static String getProductScopedThemeId() { + String productOrAppId = getProductOrApplicationId(); + if (productOrAppId != null) { + IEclipsePreferences themeNode = UserScope.INSTANCE + .getNode("org.eclipse.e4.ui.css.swt.theme"); + return themeNode.node(productOrAppId).get("themeid", null); + } + return null; + } + /** * Finds an argument's value in the app's command line arguments, branding, * and system properties diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchMessages.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchMessages.java index 42cfe5c445a..474ec54624e 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchMessages.java +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchMessages.java @@ -55,7 +55,9 @@ public class WorkbenchMessages extends NLS { public static String ThemeDefault_dialogTitle; public static String ThemeDefault_description; public static String ThemeDefault_currentDefault; + public static String ThemeDefault_currentDefaultUnscoped; public static String ThemeDefault_noDefault; + public static String ThemeDefault_noDefaultUnscoped; public static String ThemeDefault_setDefault; public static String ThemeDefault_removeDefault; diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/dialogs/ViewsPreferencePage.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/dialogs/ViewsPreferencePage.java index 87f2d963a21..4e9fd9e12f4 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/dialogs/ViewsPreferencePage.java +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/dialogs/ViewsPreferencePage.java @@ -359,11 +359,24 @@ private void openManageDefaultThemeDialog() { } } + String productDisplayName = getProductDisplayName(); + String message; if (currentDefaultLabel != null) { - message = NLS.bind(WorkbenchMessages.ThemeDefault_currentDefault, currentDefaultLabel); + if (productOrAppId != null) { + String displayName = productDisplayName != null ? productDisplayName : productOrAppId; + message = NLS.bind(WorkbenchMessages.ThemeDefault_currentDefault, new Object[] { currentDefaultLabel, + displayName, productOrAppId }); + } else { + message = NLS.bind(WorkbenchMessages.ThemeDefault_currentDefaultUnscoped, currentDefaultLabel); + } } else { - message = WorkbenchMessages.ThemeDefault_noDefault; + if (productOrAppId != null) { + String displayName = productDisplayName != null ? productDisplayName : productOrAppId; + message = NLS.bind(WorkbenchMessages.ThemeDefault_noDefault, displayName, productOrAppId); + } else { + message = WorkbenchMessages.ThemeDefault_noDefaultUnscoped; + } } message = WorkbenchMessages.ThemeDefault_description + "\n\n" + message; //$NON-NLS-1$ @@ -411,6 +424,18 @@ private static String getProductOrApplicationId() { return System.getProperty("eclipse.application"); //$NON-NLS-1$ } + /** + * Returns the product name if a product is configured, or {@code null} + * otherwise. + */ + private static String getProductDisplayName() { + IProduct product = Platform.getProduct(); + if (product != null) { + return product.getName(); + } + return null; + } + @Override public void init(IWorkbench workbench) { MApplication application = workbench.getService(MApplication.class); diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/messages.properties b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/messages.properties index 8f9bf3483dc..ea70986c041 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/messages.properties +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/messages.properties @@ -503,8 +503,10 @@ ThemeChangeWarningTitle = Theme Changed ThemeDefault_manageButton = Manage &default... ThemeDefault_dialogTitle = Manage Default Theme ThemeDefault_description = The default theme is used for new workspaces and workspaces in which no explicit theme has been set. -ThemeDefault_currentDefault = Current default theme: {0} -ThemeDefault_noDefault = No default theme configured. The product default will be used. +ThemeDefault_currentDefault = Current default theme for {1} ({2}): {0} +ThemeDefault_currentDefaultUnscoped = Current default theme: {0} +ThemeDefault_noDefault = No default theme configured for {0} ({1}). The product default will be used. +ThemeDefault_noDefaultUnscoped = No default theme configured. The product default will be used. ThemeDefault_setDefault = &Set current theme as default ThemeDefault_removeDefault = &Remove default RescaleAtRuntimeSettingChangeWarningTitle = DPI Setting Changed