Bug 566222 - [Win32][Dark theme] Combos dark light in the dark theme

This patch has 2 changes:
* Use undocumented 'DarkMode_CFD::Combobox' theme for Combo.
* Apply the usual dark scrollbars theme to Combo's dropdown

Change-Id: I86a6231d13d08815a9d76f303bd20a5a0c11b94d
Signed-off-by: Alexandr Miloslavskiy <alexandr.miloslavskiy@syntevo.com>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java
index 11dd7f7..e182761 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java
@@ -2230,6 +2230,7 @@
 	display.setData("org.eclipse.swt.internal.win32.Tree.use_WS_BORDER",       isDarkTheme);
 	display.setData("org.eclipse.swt.internal.win32.Table.headerLineColor",    isDarkTheme ? new Color(display, 0x50, 0x50, 0x50) : null);
 	display.setData("org.eclipse.swt.internal.win32.Label.disabledForegroundColor", isDarkTheme ? new Color(display, 0x80, 0x80, 0x80) : null);
+	display.setData("org.eclipse.swt.internal.win32.Combo.useDarkTheme",       isDarkTheme);
 }
 
 public static final boolean SetWindowText (long hWnd, TCHAR lpString) {
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Combo.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Combo.java
index f38673a..a42e0de 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Combo.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Combo.java
@@ -724,6 +724,11 @@
 	}
 	state &= ~(CANVAS | THEME_BACKGROUND);
 
+	if (display.comboUseDarkTheme) {
+		OS.AllowDarkModeForWindow(handle, true);
+		OS.SetWindowTheme(handle, "CFD\0".toCharArray(), null);
+	}
+
 	stateFlagsUsable = stateFlagsTest();
 
 	/* Get the text and list window procs */
@@ -2485,6 +2490,18 @@
 	}
 }
 
+void updateDropDownTheme () {
+	COMBOBOXINFO pcbi = new COMBOBOXINFO ();
+	pcbi.cbSize = COMBOBOXINFO.sizeof;
+	if (!OS.GetComboBoxInfo(handle, pcbi))
+		return;
+
+	if (pcbi.hwndList == 0)
+		return;
+
+	maybeEnableDarkSystemTheme(pcbi.hwndList);
+}
+
 @Override
 boolean updateTextDirection(int textDirection) {
 	if (super.updateTextDirection(textDirection)) {
@@ -3216,6 +3233,7 @@
 		case OS.CBN_DROPDOWN:
 			setCursor ();
 			updateDropDownHeight ();
+			updateDropDownTheme ();
 			break;
 		case OS.CBN_KILLFOCUS:
 			sendFocusEvent (SWT.FocusOut);
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java
index 202fb6e..49cedcc 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java
@@ -230,6 +230,17 @@
 	 */
 	static final String LABEL_DISABLED_FOREGROUND_COLOR_KEY = "org.eclipse.swt.internal.win32.Label.disabledForegroundColor"; //$NON-NLS-1$
 	int disabledLabelForegroundPixel = -1;
+	/**
+	 * Use dark theme for Combo.
+	 * Limitations:<br>
+	 * <ul>
+	 *   <li>Only available since Win10 version 1903.</li>
+	 *   <li>Does not affect already created controls.</li>
+	 * </ul>
+	 * Expects a <code>boolean</code> value.
+	 */
+	static final String COMBO_USE_DARK_THEME = "org.eclipse.swt.internal.win32.Combo.useDarkTheme"; //$NON-NLS-1$
+	boolean comboUseDarkTheme = false;
 
 	/* Custom icons */
 	long hIconSearch;
@@ -4399,6 +4410,11 @@
 		case LABEL_DISABLED_FOREGROUND_COLOR_KEY:
 			disabledLabelForegroundPixel = disableCustomThemeTweaks ? -1 : _toColorPixel(value);
 			break;
+		case COMBO_USE_DARK_THEME:
+			comboUseDarkTheme = _toBoolean(value) &&
+				!disableCustomThemeTweaks &&
+				OS.IsDarkModeAvailable();
+			break;
 	}
 
 	/* Remove the key/value pair */
diff --git a/tests/org.eclipse.swt.tests.win32/ManualTests/org/eclipse/swt/tests/win32/snippets/Bug566222_DarkCombo.java b/tests/org.eclipse.swt.tests.win32/ManualTests/org/eclipse/swt/tests/win32/snippets/Bug566222_DarkCombo.java
new file mode 100644
index 0000000..c1798b0
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.win32/ManualTests/org/eclipse/swt/tests/win32/snippets/Bug566222_DarkCombo.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Syntevo and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Syntevo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.tests.win32.snippets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.win32.OS;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+
+public class Bug566222_DarkCombo {
+	static void setColors(Control control, Color backColor, Color foreColor) {
+		control.setBackground(backColor);
+		control.setForeground(foreColor);
+
+		if (control instanceof Composite) {
+			for (Control child : ((Composite)control).getChildren()) {
+				setColors(child, backColor, foreColor);
+			}
+		}
+	}
+
+	public static void main(String[] args) {
+		final Display display = new Display();
+		OS.setTheme(true);
+
+		final Shell shell = new Shell(display);
+		GridLayout layout = new GridLayout(1, true);
+		layout.horizontalSpacing = 10;
+		shell.setLayout(layout);
+
+		Label hint = new Label(shell, 0);
+		hint.setText("The Combo shall look good in Dark Theme");
+
+		for (int iStyle = 0; iStyle < 2; iStyle++) {
+			int style = (iStyle == 0) ? 0 : SWT.READ_ONLY;
+			Combo combo = new Combo(shell, style);
+
+			for (int iItem = 0; iItem < 100; iItem++) {
+				combo.add("Item #" + iItem);
+			}
+
+			combo.select(0);
+		}
+
+		Color backColor = new Color(display, 0x30, 0x30, 0x30);
+		Color foreColor = new Color(display, 0xD0, 0xD0, 0xD0);
+		setColors(shell, backColor, foreColor);
+
+		shell.pack();
+		shell.open();
+
+		while (!shell.isDisposed()) {
+			if (!display.readAndDispatch()) {
+				display.sleep();
+			}
+		}
+
+		display.dispose();
+	}
+}