Skip to content

Commit 37c8419

Browse files
committed
Style workspace selection dialog with default theme setting
Read the default theme from UserScope, scoped by product or application ID (falling back to the base node for backwards compatibility), to determine whether dark mode should be applied before the workbench starts. Apply dark styling to the workspace selection dialog (ChooseWorkspaceDialog and ChooseWorkspaceWithSettingsDialog) by setting shell background/foreground colors and propagating them recursively to child controls. Link foreground is set to the same value as the default dark theme. The ExpandableComposite title bar foreground is explicitly set to match the parent composite foreground so it remains readable in both light and dark themes. After the workspace selection dialog reset early dark theme styling before the workbench starts the ThemeEngine will apply the correct theme from here on.
1 parent 357b87c commit 37c8419

6 files changed

Lines changed: 123 additions & 1 deletion

File tree

bundles/org.eclipse.e4.ui.css.swt.theme/META-INF/MANIFEST.MF

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Bundle-Name: %pluginName
66
Bundle-Vendor: %providerName
77
Bundle-Localization: plugin
88
Bundle-RequiredExecutionEnvironment: JavaSE-21
9-
Require-Bundle: org.eclipse.swt;bundle-version="[3.133.0,4.0.0)",
9+
Require-Bundle: org.eclipse.swt;bundle-version="[3.134.0,4.0.0)",
1010
org.eclipse.e4.ui.css.swt;bundle-version="0.13.100",
1111
org.eclipse.e4.ui.css.core;bundle-version="0.12.200",
1212
org.eclipse.core.runtime;bundle-version="[3.29.0,4.0.0)"

bundles/org.eclipse.e4.ui.css.swt.theme/src/org/eclipse/e4/ui/css/swt/internal/theme/ThemeEngine.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,9 @@ public void setTheme(ITheme theme, boolean restore, boolean force) {
510510
ThemeEngineManager.logError(e.getMessage(), e);
511511
}
512512
}
513+
boolean isDark = theme.getId().contains("dark"); //$NON-NLS-1$
514+
display.setDarkThemePreferred(isDark);
515+
513516
sendThemeChangeEvent(restore);
514517

515518
for (CSSEngine engine : cssEngines) {

bundles/org.eclipse.ui.ide.application/META-INF/MANIFEST.MF

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Require-Bundle: org.eclipse.ui.ide;bundle-version="[3.21.0,4.0.0)",
1818
org.eclipse.e4.core.di.extensions,
1919
org.eclipse.e4.core.services;bundle-version="2.4.0",
2020
org.eclipse.e4.core.contexts;bundle-version="[1.12.0,2.0.0)",
21+
org.eclipse.ui.forms,
2122
org.eclipse.urischeme;bundle-version="[1.3.0,2.0.0)",
2223
org.eclipse.e4.ui.di
2324
Export-Package: org.eclipse.ui.internal.ide.application;x-internal:=true,

bundles/org.eclipse.ui.ide.application/src/org/eclipse/ui/internal/ide/application/IDEApplication.java

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,15 @@
3636

3737
import org.eclipse.core.runtime.IConfigurationElement;
3838
import org.eclipse.core.runtime.IExecutableExtension;
39+
import org.eclipse.core.runtime.IProduct;
3940
import org.eclipse.core.runtime.IStatus;
4041
import org.eclipse.core.runtime.OperationCanceledException;
4142
import org.eclipse.core.runtime.Platform;
4243
import org.eclipse.core.runtime.Status;
4344
import org.eclipse.core.runtime.jobs.Job;
4445
import org.eclipse.core.runtime.preferences.ConfigurationScope;
46+
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
47+
import org.eclipse.core.runtime.preferences.UserScope;
4548
import org.eclipse.equinox.app.IApplication;
4649
import org.eclipse.equinox.app.IApplicationContext;
4750
import org.eclipse.jface.dialogs.IDialogConstants;
@@ -52,14 +55,18 @@
5255
import org.eclipse.osgi.service.datalocation.Location;
5356
import org.eclipse.osgi.util.NLS;
5457
import org.eclipse.swt.SWT;
58+
import org.eclipse.swt.graphics.Color;
5559
import org.eclipse.swt.layout.FillLayout;
5660
import org.eclipse.swt.widgets.Composite;
5761
import org.eclipse.swt.widgets.Control;
5862
import org.eclipse.swt.widgets.Display;
5963
import org.eclipse.swt.widgets.Label;
64+
import org.eclipse.swt.widgets.Link;
65+
import org.eclipse.swt.widgets.Listener;
6066
import org.eclipse.swt.widgets.Shell;
6167
import org.eclipse.ui.IWorkbench;
6268
import org.eclipse.ui.PlatformUI;
69+
import org.eclipse.ui.forms.widgets.ExpandableComposite;
6370
import org.eclipse.ui.internal.Workbench;
6471
import org.eclipse.ui.internal.WorkbenchPlugin;
6572
import org.eclipse.ui.internal.WorkspaceLock;
@@ -94,6 +101,9 @@ public class IDEApplication implements IApplication, IExecutableExtension {
94101

95102
private static final String USER_NAME = "user.name"; //$NON-NLS-1$
96103

104+
private boolean isDark;
105+
private Listener darkThemeShowListener;
106+
97107
// Use the branding plug-in of the platform feature since this is most likely
98108
// to change on an update of the IDE.
99109
private static final String WORKSPACE_CHECK_REFERENCE_BUNDLE_NAME = "org.eclipse.platform"; //$NON-NLS-1$
@@ -145,6 +155,9 @@ public Object start(IApplicationContext appContext) throws Exception {
145155
Job.getJobManager().suspend();
146156

147157
Display display = createDisplay();
158+
159+
initializeDefaultTheme(display);
160+
148161
// processor must be created before we start event loop
149162
DelayedEventsProcessor processor = new DelayedEventsProcessor(display);
150163

@@ -167,6 +180,10 @@ public Object start(IApplicationContext appContext) throws Exception {
167180
return instanceLocationCheck;
168181
}
169182

183+
// Reset early dark theme styling before the workbench starts;
184+
// the ThemeEngine will apply the correct theme from here on.
185+
resetEarlyDarkTheme(display);
186+
170187
// create the workbench with this advisor and run it until it exits
171188
// N.B. createWorkbench remembers the advisor, and also registers
172189
// the workbench globally so that all UI plug-ins can find it using
@@ -587,6 +604,14 @@ protected Shell getParentShell() {
587604
return null;
588605
}
589606

607+
@Override
608+
protected Control createContents(Composite parent) {
609+
Control contents = super.createContents(parent);
610+
if (isDark) {
611+
applyDarkStyles(getShell());
612+
}
613+
return contents;
614+
}
590615
}.prompt(force);
591616
}
592617

@@ -852,6 +877,90 @@ protected static Version toMajorMinorVersion(Version version) {
852877
return new Version(version.getMajor(), version.getMinor(), 0);
853878
}
854879

880+
protected void initializeDefaultTheme(Display display) {
881+
IEclipsePreferences themeNode = UserScope.INSTANCE.getNode("org.eclipse.e4.ui.css.swt.theme"); //$NON-NLS-1$
882+
String productOrAppId = getProductOrApplicationId();
883+
String defaultThemeId = null;
884+
if (productOrAppId != null) {
885+
defaultThemeId = themeNode.node(productOrAppId).get("themeid", null); //$NON-NLS-1$
886+
}
887+
if (defaultThemeId == null) {
888+
defaultThemeId = themeNode.get("themeid", null); //$NON-NLS-1$
889+
}
890+
isDark = defaultThemeId != null && defaultThemeId.contains("dark"); //$NON-NLS-1$
891+
if (isDark) {
892+
display.setDarkThemePreferred(true);
893+
darkThemeShowListener = event -> {
894+
if (event.widget instanceof Shell shell) {
895+
applyDarkStyles(shell);
896+
}
897+
};
898+
display.addListener(SWT.Show, darkThemeShowListener);
899+
}
900+
}
901+
902+
/**
903+
* Removes the early dark theme styling applied for the workspace selection
904+
* dialog. Must be called before the workbench starts so the ThemeEngine can
905+
* manage the theme without interference.
906+
*/
907+
protected void resetEarlyDarkTheme(Display display) {
908+
if (darkThemeShowListener != null) {
909+
display.removeListener(SWT.Show, darkThemeShowListener);
910+
darkThemeShowListener = null;
911+
}
912+
if (isDark) {
913+
display.setDarkThemePreferred(false);
914+
}
915+
}
916+
917+
/**
918+
* Returns the product ID if a product is configured, otherwise falls back to
919+
* the application ID from the system property. Returns {@code null} if neither
920+
* is available.
921+
*/
922+
private static String getProductOrApplicationId() {
923+
IProduct product = Platform.getProduct();
924+
if (product != null) {
925+
return product.getId();
926+
}
927+
return System.getProperty("eclipse.application"); //$NON-NLS-1$
928+
}
929+
930+
private void applyDarkStyles(Shell shell) {
931+
Color bg = new Color(shell.getDisplay(), 72, 72, 76); // #48484c
932+
Color fg = new Color(shell.getDisplay(), 238, 238, 238); // #eeeeee
933+
Color linkColor = new Color(shell.getDisplay(), 111, 197, 238); // #6FC5EE
934+
shell.setBackground(bg);
935+
shell.setForeground(fg);
936+
applyStylesRecursive(shell, bg, fg, linkColor);
937+
shell.addDisposeListener(e -> {
938+
bg.dispose();
939+
fg.dispose();
940+
});
941+
}
942+
943+
private void applyStylesRecursive(Control control, Color bg, Color fg, Color linkColor) {
944+
control.setBackground(bg);
945+
if (control instanceof Link link) {
946+
link.setLinkForeground(linkColor);
947+
} else {
948+
control.setForeground(fg);
949+
950+
}
951+
952+
if (control instanceof ExpandableComposite expandable) {
953+
expandable.setTitleBarForeground(fg);
954+
expandable.setToggleColor(fg);
955+
expandable.setActiveToggleColor(fg);
956+
}
957+
if (control instanceof Composite composite) {
958+
for (Control child : composite.getChildren()) {
959+
applyStylesRecursive(child, bg, fg, linkColor);
960+
}
961+
}
962+
}
963+
855964
@Override
856965
public void stop() {
857966
final IWorkbench workbench = PlatformUI.getWorkbench();

bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/ChooseWorkspaceDialog.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.eclipse.jface.dialogs.IDialogConstants;
4040
import org.eclipse.jface.dialogs.IDialogSettings;
4141
import org.eclipse.jface.dialogs.TitleAreaDialog;
42+
import org.eclipse.jface.resource.JFaceColors;
4243
import org.eclipse.jface.util.Geometry;
4344
import org.eclipse.jface.window.Window;
4445
import org.eclipse.osgi.util.NLS;
@@ -319,6 +320,10 @@ private void createRecentWorkspacesComposite(final Composite composite) {
319320
recentWorkspacesForm.getBody().setLayout(new GridLayout());
320321
ExpandableComposite recentWorkspacesExpandable = toolkit.createExpandableComposite(recentWorkspacesForm.getBody(),
321322
ExpandableComposite.TWISTIE);
323+
recentWorkspacesExpandable.setTitleBarForeground(composite.getForeground());
324+
recentWorkspacesExpandable.setForeground(composite.getForeground());
325+
recentWorkspacesExpandable.setToggleColor(composite.getForeground());
326+
recentWorkspacesExpandable.setActiveToggleColor(composite.getForeground());
322327
recentWorkspacesForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
323328
recentWorkspacesExpandable.setBackground(composite.getBackground());
324329
recentWorkspacesExpandable.setText(IDEWorkbenchMessages.ChooseWorkspaceDialog_recentWorkspaces);
@@ -352,6 +357,7 @@ public void expansionStateChanged(ExpansionEvent e) {
352357
final String recentWorkspace = uniqueWorkspaceEntry.getValue();
353358

354359
Link link = new Link(panel, SWT.WRAP);
360+
link.setForeground(JFaceColors.getHyperlinkText(composite.getDisplay()));
355361
link.setLayoutData(new RowData(SWT.DEFAULT, SWT.DEFAULT));
356362
link.setText("<a>" + uniqueWorkspaceEntry.getKey() + "</a>"); //$NON-NLS-1$ //$NON-NLS-2$
357363
link.setToolTipText(recentWorkspace);

bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/ChooseWorkspaceWithSettingsDialog.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ private void createSettingsControls(Composite workArea) {
128128

129129
copySettingsExpandable.setText(IDEWorkbenchMessages.ChooseWorkspaceWithSettingsDialog_SettingsGroupName);
130130
copySettingsExpandable.setBackground(workArea.getBackground());
131+
copySettingsExpandable.setTitleBarForeground(workArea.getForeground());
132+
copySettingsExpandable.setToggleColor(workArea.getForeground());
133+
copySettingsExpandable.setActiveToggleColor(workArea.getForeground());
131134
copySettingsExpandable.setLayout(new GridLayout());
132135
copySettingsExpandable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
133136
copySettingsExpandable.addExpansionListener(new IExpansionListener() {

0 commit comments

Comments
 (0)