cda67b1
From 46e387352f469e26ecedddc10ffec2cd16f11d82 Mon Sep 17 00:00:00 2001
cda67b1
From: Eric Williams
cda67b1
Date: Fri, 19 Feb 2016 15:59:12 -0500
cda67b1
Subject: Bug 488226: [GTK3] Content Assist using Table/Tree has wrong
cda67b1
 selection background colors
cda67b1
cda67b1
On GTK3.14 and above, SWT.COLOR_LIST_SELECTION was returning gray
cda67b1
instead of the default (and correct) blue. This causes bugs in
cda67b1
Table/Tree, making highlighted TableItems/TreeItems difficult to read.
cda67b1
COLOR_LIST_BACKGROUND is unaffected.
cda67b1
cda67b1
System background colors like SWT.COLOR_* are fetched using
cda67b1
gtk_style_context_get_background_color() when SWT loads. This approach
cda67b1
is no longer valid as 1) it is deprecated on the GTK side and 2) it is
cda67b1
unreliable/not guaranteed to work. This patch only changes this behavior
cda67b1
for SWT.COLOR_LIST_SELECTION, but in the future other system colors will
cda67b1
need to be changed as well.
cda67b1
cda67b1
The fix in this case is to fetch the GTK theme colors of the currently
cda67b1
running system theme from GTK. This can be done using GtkCssProvider.
cda67b1
Once the currently running theme is fetched, the correct selection
cda67b1
background color can be extracted. If there is no selection background
cda67b1
color specified in the theme, then the fall-back is to load the color
cda67b1
via SWT's COLOR_LIST_SELECTION. This ensures that the correct color is
cda67b1
chosen according to GTK, should a theme specify one.
cda67b1
cda67b1
Tested on GTK3.8, 3.14, 3.16, and 3.18. AllNonBrowser JUnit tests pass
cda67b1
on GTK3 and GTK2.
cda67b1
cda67b1
Change-Id: Ic9aeb4d35efef961be1f724a2ad7dcc852c06453
cda67b1
Signed-off-by: Eric Williams <ericwill@redhat.com>
cda67b1
---
cda67b1
 .../Eclipse SWT PI/gtk/library/os.c                |  27 ++++++
cda67b1
 .../Eclipse SWT PI/gtk/library/os_custom.h         |   1 +
cda67b1
 .../Eclipse SWT PI/gtk/library/os_stats.c          |   1 +
cda67b1
 .../Eclipse SWT PI/gtk/library/os_stats.h          |   1 +
cda67b1
 .../gtk/org/eclipse/swt/internal/gtk/OS.java       |  14 +++
cda67b1
 .../gtk/org/eclipse/swt/widgets/Control.java       |  17 +---
cda67b1
 .../gtk/org/eclipse/swt/widgets/Display.java       | 108 ++++++++++++++++++++-
cda67b1
 7 files changed, 153 insertions(+), 16 deletions(-)
cda67b1
cda67b1
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
cda67b1
index 64e39f3..02dbadd 100644
cda67b1
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c	
cda67b1
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c	
cda67b1
@@ -10056,6 +10056,33 @@ JNIEXPORT void JNICALL OS_NATIVE(_1gtk_1container_1set_1border_1width)
cda67b1
 }
cda67b1
 #endif
cda67b1
 
cda67b1
+#ifndef NO__1gtk_1css_1provider_1get_1named
cda67b1
+JNIEXPORT jintLong JNICALL OS_NATIVE(_1gtk_1css_1provider_1get_1named)
cda67b1
+	(JNIEnv *env, jclass that, jbyteArray arg0, jbyteArray arg1)
cda67b1
+{
cda67b1
+	jbyte *lparg0=NULL;
cda67b1
+	jbyte *lparg1=NULL;
cda67b1
+	jintLong rc = 0;
cda67b1
+	OS_NATIVE_ENTER(env, that, _1gtk_1css_1provider_1get_1named_FUNC);
cda67b1
+	if (arg0) if ((lparg0 = (*env)->GetByteArrayElements(env, arg0, NULL)) == NULL) goto fail;
cda67b1
+	if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail;
cda67b1
+/*
cda67b1
+	rc = (jintLong)gtk_css_provider_get_named((const gchar *)lparg0, (const gchar *)lparg1);
cda67b1
+*/
cda67b1
+	{
cda67b1
+		OS_LOAD_FUNCTION(fp, gtk_css_provider_get_named)
cda67b1
+		if (fp) {
cda67b1
+			rc = (jintLong)((jintLong (CALLING_CONVENTION*)(const gchar *, const gchar *))fp)((const gchar *)lparg0, (const gchar *)lparg1);
cda67b1
+		}
cda67b1
+	}
cda67b1
+fail:
cda67b1
+	if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, 0);
cda67b1
+	if (arg0 && lparg0) (*env)->ReleaseByteArrayElements(env, arg0, lparg0, 0);
cda67b1
+	OS_NATIVE_EXIT(env, that, _1gtk_1css_1provider_1get_1named_FUNC);
cda67b1
+	return rc;
cda67b1
+}
cda67b1
+#endif
cda67b1
+
cda67b1
 #ifndef NO__1gtk_1css_1provider_1load_1from_1data
cda67b1
 JNIEXPORT jboolean JNICALL OS_NATIVE(_1gtk_1css_1provider_1load_1from_1data)
cda67b1
 	(JNIEnv *env, jclass that, jintLong arg0, jbyteArray arg1, jintLong arg2, jintLongArray arg3)
cda67b1
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.h
cda67b1
index 7a27475..8e5844b 100644
cda67b1
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.h	
cda67b1
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.h	
cda67b1
@@ -530,6 +530,7 @@
cda67b1
 #define gtk_css_provider_load_from_data_LIB LIB_GTK
cda67b1
 #define gtk_css_provider_new_LIB LIB_GTK
cda67b1
 #define gtk_css_provider_to_string_LIB LIB_GTK
cda67b1
+#define gtk_css_provider_get_named_LIB LIB_GTK
cda67b1
 #define gtk_icon_set_render_icon_pixbuf_LIB LIB_GTK
cda67b1
 #define gtk_drag_set_icon_surface_LIB LIB_GTK
cda67b1
 #define gtk_accel_label_set_accel_LIB LIB_GTK
cda67b1
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c
cda67b1
index 5d77479..670adf8 100644
cda67b1
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c	
cda67b1
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c	
cda67b1
@@ -729,6 +729,7 @@ char * OS_nativeFunctionNames[] = {
cda67b1
 	"_1gtk_1container_1remove",
cda67b1
 	"_1gtk_1container_1resize_1children",
cda67b1
 	"_1gtk_1container_1set_1border_1width",
cda67b1
+	"_1gtk_1css_1provider_1get_1named",
cda67b1
 	"_1gtk_1css_1provider_1load_1from_1data",
cda67b1
 	"_1gtk_1css_1provider_1new",
cda67b1
 	"_1gtk_1css_1provider_1to_1string",
cda67b1
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h
cda67b1
index a0a30b7..11fdfe4 100644
cda67b1
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h	
cda67b1
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h	
cda67b1
@@ -739,6 +739,7 @@ typedef enum {
cda67b1
 	_1gtk_1container_1remove_FUNC,
cda67b1
 	_1gtk_1container_1resize_1children_FUNC,
cda67b1
 	_1gtk_1container_1set_1border_1width_FUNC,
cda67b1
+	_1gtk_1css_1provider_1get_1named_FUNC,
cda67b1
 	_1gtk_1css_1provider_1load_1from_1data_FUNC,
cda67b1
 	_1gtk_1css_1provider_1new_FUNC,
cda67b1
 	_1gtk_1css_1provider_1to_1string_FUNC,
cda67b1
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
cda67b1
index d3e52c3..353d4b7 100644
cda67b1
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java	
cda67b1
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java	
cda67b1
@@ -650,6 +650,7 @@ public class OS extends C {
cda67b1
 	public static final byte[] gtk_show_input_method_menu = ascii("gtk-show-input-method-menu");
cda67b1
 	public static final byte[] gtk_menu_bar_accel = ascii("gtk-menu-bar-accel");
cda67b1
 	public static final byte[] gtk_menu_images = ascii("gtk-menu-images");
cda67b1
+	public static final byte[] gtk_theme_name = ascii("gtk-theme-name");
cda67b1
 	public static final byte[] inner_border = ascii("inner-border");
cda67b1
 	public static final byte[] has_backward_stepper = ascii("has-backward-stepper");
cda67b1
 	public static final byte[] has_secondary_backward_stepper = ascii("has-secondary-backward-stepper");
cda67b1
@@ -9299,6 +9300,19 @@ public static final long /*int*/gtk_css_provider_to_string(long /*int*/ provider
cda67b1
 		lock.unlock();
cda67b1
 	}
cda67b1
 }
cda67b1
+/** @method flags=dynamic
cda67b1
+ *  @param name cast=(const gchar *)
cda67b1
+ *  @param variant cast=(const gchar *)
cda67b1
+ */
cda67b1
+public static final native long /*int*/ _gtk_css_provider_get_named (byte[] name, byte[] variant);
cda67b1
+public static final long /*int*/gtk_css_provider_get_named(byte[] name, byte[] variant) {
cda67b1
+	lock.lock();
cda67b1
+	try {
cda67b1
+		return _gtk_css_provider_get_named(name, variant);
cda67b1
+	} finally {
cda67b1
+		lock.unlock();
cda67b1
+	}
cda67b1
+}
cda67b1
 /**
cda67b1
  * @method flags=dynamic
cda67b1
  * @param screen cast=(GdkScreen *)
cda67b1
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
cda67b1
index d296192..741a4e2 100644
cda67b1
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java	
cda67b1
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java	
cda67b1
@@ -4178,7 +4178,7 @@ GdkColor gtk_css_parse_background (long /*int*/ provider) {
cda67b1
 		shortOutput = cssOutput.substring (startIndex + 18);
cda67b1
 		// Double check to make sure with have a valid rgb/rgba property
cda67b1
 		if (shortOutput.contains ("rgba") || shortOutput.contains ("rgb")) {
cda67b1
-			rgba = gtk_css_property_to_rgba (shortOutput);
cda67b1
+			rgba = display.gtk_css_property_to_rgba (shortOutput);
cda67b1
 		} else {
cda67b1
 			return display.COLOR_WIDGET_BACKGROUND;
cda67b1
 		}
cda67b1
@@ -4187,7 +4187,7 @@ GdkColor gtk_css_parse_background (long /*int*/ provider) {
cda67b1
 		shortOutput = cssOutput.substring (startIndex + 13);
cda67b1
 		// Double check to make sure with have a valid rgb/rgba property
cda67b1
 		if (shortOutput.contains ("rgba") || shortOutput.contains ("rgb")) {
cda67b1
-			rgba = gtk_css_property_to_rgba (shortOutput);
cda67b1
+			rgba = display.gtk_css_property_to_rgba (shortOutput);
cda67b1
 		} else {
cda67b1
 			return display.COLOR_WIDGET_BACKGROUND;
cda67b1
 		}
cda67b1
@@ -4195,18 +4195,6 @@ GdkColor gtk_css_parse_background (long /*int*/ provider) {
cda67b1
 	return color;
cda67b1
 }
cda67b1
 
cda67b1
-GdkRGBA gtk_css_property_to_rgba(String property) {
cda67b1
-	/* Here we convert rgb(...) or rgba(...) properties
cda67b1
-	 * into GdkRGBA objects using gdk_rgba_parse(). Note
cda67b1
-	 * that we still need to remove the ";" character from the
cda67b1
-	 * input string.
cda67b1
-	 */
cda67b1
-	GdkRGBA rgba = new GdkRGBA ();
cda67b1
-	String [] propertyParsed = new String [1];
cda67b1
-	propertyParsed = property.split (";");
cda67b1
-	OS.gdk_rgba_parse (rgba, Converter.wcsToMbcs (null, propertyParsed[0], true));
cda67b1
-	return rgba;
cda67b1
-}
cda67b1
 
cda67b1
 void gtk_css_provider_load_from_css (long /*int*/ context, String css) {
cda67b1
 	/* Utility function. */
cda67b1
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java
cda67b1
index 49c0e0d..7dee6d7 100644
cda67b1
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java	
cda67b1
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java	
cda67b1
@@ -1693,6 +1693,99 @@ long /*int*/ gtk_cell_renderer_toggle_get_type () {
cda67b1
 	return toggle_renderer_type;
cda67b1
 }
cda67b1
 
cda67b1
+String gtk_css_default_theme_values (int swt) {
cda67b1
+	/*
cda67b1
+	 * This method fetches GTK theme values/properties. This is accomplished
cda67b1
+	 * by determining the name of the current system theme loaded, giving that
cda67b1
+	 * name to GTK, and then parsing values from the returned theme contents.
cda67b1
+	 *
cda67b1
+	 * The idea here is that SWT variables that have corresponding GTK theme
cda67b1
+	 * elements can be fetched easily by supplying the SWT variable as an
cda67b1
+	 * parameter to this method.
cda67b1
+	 */
cda67b1
+
cda67b1
+	// Find CSS theme name
cda67b1
+	byte [] buffer;
cda67b1
+	int length;
cda67b1
+	long /*int*/ settings = OS.gtk_settings_get_default ();
cda67b1
+	long /*int*/ [] ptr = new long /*int*/ [1];
cda67b1
+	long /*int*/ str;
cda67b1
+	OS.g_object_get (settings, OS.gtk_theme_name, ptr, 0);
cda67b1
+	if (ptr [0] == 0) {
cda67b1
+		return "";
cda67b1
+	}
cda67b1
+	length = OS.strlen (ptr [0]);
cda67b1
+	if (length == 0) {
cda67b1
+		return "";
cda67b1
+	}
cda67b1
+	buffer = new byte [length];
cda67b1
+	OS.memmove (buffer, ptr [0], length);
cda67b1
+	OS.g_free (ptr [0]);
cda67b1
+
cda67b1
+	// Fetch the actual theme in char/string format
cda67b1
+	long /*int*/ themeProvider = OS.gtk_css_provider_get_named(buffer, null);
cda67b1
+	str = OS.gtk_css_provider_to_string (themeProvider);
cda67b1
+	length = OS.strlen (str);
cda67b1
+	if (length == 0) {
cda67b1
+		return "";
cda67b1
+	}
cda67b1
+	buffer = new byte [length];
cda67b1
+	OS.memmove (buffer, str, length);
cda67b1
+	String cssOutput = new String (Converter.mbcsToWcs (null, buffer));
cda67b1
+
cda67b1
+	// Parse the theme values based on the corresponding SWT value
cda67b1
+	// i.e. theme_selected_bg_color in GTK is SWT.COLOR_LIST_SELECTION in SWT
cda67b1
+	String color;
cda67b1
+	switch (swt) {
cda67b1
+		case SWT.COLOR_LIST_SELECTION:
cda67b1
+			/*
cda67b1
+			 * These strings are the GTK named colors we are looking for.
cda67b1
+			 *
cda67b1
+			 * NOTE: we need to be careful of cases where one is being assigned
cda67b1
+			 * to the other. For example we do NOT want to parse:
cda67b1
+			 * @define-color theme_selected_bg_color selected_bg_color
cda67b1
+			 * Instead we want the actual value for selected_bg_color, i.e.
cda67b1
+			 * @define-color selected_bg_color rgb(255, 255, 255)
cda67b1
+			 *
cda67b1
+			 * We also want to filter out any color formats other than #xxyyzz,
cda67b1
+			 * rgb(xxx,yyy,zzz) and rgba(www,xxx,yyy,zzz) since gdk_rgba_parse()
cda67b1
+			 * can only handle strings in this format.
cda67b1
+			 */
cda67b1
+			int tSelected = cssOutput.indexOf ("@define-color theme_selected_bg_color");
cda67b1
+			int selected = cssOutput.indexOf ("@define-color selected_bg_color");
cda67b1
+			if (tSelected != -1) {
cda67b1
+				color = cssOutput.substring(tSelected + 38);
cda67b1
+				if (color.startsWith("#") || color.startsWith("rgb")) {
cda67b1
+					return color;
cda67b1
+				}
cda67b1
+			}
cda67b1
+			if (selected != -1) {
cda67b1
+				color = cssOutput.substring(selected + 32);
cda67b1
+				if (color.startsWith("#") || color.startsWith("rgb")) {
cda67b1
+					return color;
cda67b1
+				}
cda67b1
+			}
cda67b1
+			else {
cda67b1
+				return "";
cda67b1
+			}
cda67b1
+		default:
cda67b1
+			return "";
cda67b1
+	}
cda67b1
+}
cda67b1
+
cda67b1
+GdkRGBA gtk_css_property_to_rgba(String property) {
cda67b1
+	/* Here we convert rgb(...) or rgba(...) properties
cda67b1
+	 * into GdkRGBA objects using gdk_rgba_parse(). Note
cda67b1
+	 * that we still need to remove the ";" character from the
cda67b1
+	 * input string.
cda67b1
+	 */
cda67b1
+	GdkRGBA rgba = new GdkRGBA ();
cda67b1
+	String [] propertyParsed = new String [1];
cda67b1
+	propertyParsed = property.split (";");
cda67b1
+	OS.gdk_rgba_parse (rgba, Converter.wcsToMbcs (null, propertyParsed[0], true));
cda67b1
+	return rgba;
cda67b1
+}
cda67b1
+
cda67b1
 /**
cda67b1
  * Returns the default display. One is created (making the
cda67b1
  * thread that invokes this method its user-interface thread)
cda67b1
@@ -2409,7 +2502,20 @@ void initializeSystemColors () {
cda67b1
 		COLOR_LIST_BACKGROUND = toGdkColor (rgba);
cda67b1
 		OS.gtk_style_context_restore (context);
cda67b1
 		COLOR_LIST_SELECTION_TEXT = toGdkColor (styleContextGetColor (context, OS.GTK_STATE_FLAG_SELECTED, rgba));
cda67b1
-		OS.gtk_style_context_get_background_color (context, OS.GTK_STATE_FLAG_SELECTED, rgba);
cda67b1
+
cda67b1
+		// SWT.COLOR_LIST_SELECTION will be fetched using GTK CSS for GTK3.14+.
cda67b1
+		// TODO: convert other system colors to this method and re-factor.
cda67b1
+		if (OS.GTK_VERSION >= OS.VERSION(3, 14, 0)) {
cda67b1
+			String colorListSelection = gtk_css_default_theme_values(SWT.COLOR_LIST_SELECTION);
cda67b1
+			if (!colorListSelection.isEmpty()) {
cda67b1
+				rgba = gtk_css_property_to_rgba (colorListSelection);
cda67b1
+			} else {
cda67b1
+				OS.gtk_style_context_get_background_color (context, OS.GTK_STATE_FLAG_SELECTED, rgba);
cda67b1
+			}
cda67b1
+		} else {
cda67b1
+			OS.gtk_style_context_get_background_color (context, OS.GTK_STATE_FLAG_SELECTED, rgba);
cda67b1
+		}
cda67b1
+
cda67b1
 		COLOR_LIST_SELECTION = toGdkColor (rgba);
cda67b1
 		COLOR_LIST_SELECTION_TEXT_INACTIVE = toGdkColor (styleContextGetColor (context, OS.GTK_STATE_FLAG_ACTIVE, rgba));
cda67b1
 		OS.gtk_style_context_get_background_color (context, OS.GTK_STATE_FLAG_ACTIVE, rgba);
cda67b1
-- 
cda67b1
cgit v0.11.2-4-g4a35
cda67b1
cda67b1