Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c12
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c1
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h1
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java12
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java102
-rw-r--r--tests/org.eclipse.swt.tests.gtk/Bug Snippets/org/eclipse/swt/tests/gtk/snippets/Bug545587_TooltipColor.java77
-rw-r--r--tests/org.eclipse.swt.tests.gtk/ManualNativeCTests/BugSnippets/Bug_545587_TooltipColor.cpp399
7 files changed, 528 insertions, 76 deletions
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
index b23c90c278..90815ab001 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
@@ -9483,6 +9483,18 @@ fail:
}
#endif
+#ifndef NO__1gtk_1style_1context_1get_1parent
+JNIEXPORT jlong JNICALL GTK_NATIVE(_1gtk_1style_1context_1get_1parent)
+ (JNIEnv *env, jclass that, jlong arg0)
+{
+ jlong rc = 0;
+ GTK_NATIVE_ENTER(env, that, _1gtk_1style_1context_1get_1parent_FUNC);
+ rc = (jlong)gtk_style_context_get_parent((GtkStyleContext *)arg0);
+ GTK_NATIVE_EXIT(env, that, _1gtk_1style_1context_1get_1parent_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO__1gtk_1style_1context_1invalidate
JNIEXPORT void JNICALL GTK_NATIVE(_1gtk_1style_1context_1invalidate)
(JNIEnv *env, jclass that, jlong arg0)
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
index 1e05d046e6..d863e2af8f 100644
--- 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
@@ -759,6 +759,7 @@ char * GTK_nativeFunctionNames[] = {
"_1gtk_1style_1context_1get_1margin",
"_1gtk_1style_1context_1get_1padding__JILorg_eclipse_swt_internal_gtk_GtkBorder_2",
"_1gtk_1style_1context_1get_1padding__JLorg_eclipse_swt_internal_gtk_GtkBorder_2",
+ "_1gtk_1style_1context_1get_1parent",
"_1gtk_1style_1context_1invalidate",
"_1gtk_1style_1context_1remove_1class",
"_1gtk_1style_1context_1restore",
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
index 3e2cf733ab..cbb6566264 100644
--- 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
@@ -757,6 +757,7 @@ typedef enum {
_1gtk_1style_1context_1get_1margin_FUNC,
_1gtk_1style_1context_1get_1padding__JILorg_eclipse_swt_internal_gtk_GtkBorder_2_FUNC,
_1gtk_1style_1context_1get_1padding__JLorg_eclipse_swt_internal_gtk_GtkBorder_2_FUNC,
+ _1gtk_1style_1context_1get_1parent_FUNC,
_1gtk_1style_1context_1invalidate_FUNC,
_1gtk_1style_1context_1remove_1class_FUNC,
_1gtk_1style_1context_1restore_FUNC,
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java
index 163906e608..399aa54052 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java
@@ -6100,6 +6100,18 @@ public class GTK extends OS {
}
}
/**
+ * @param context cast=(GtkStyleContext *)
+ */
+ public static final native long _gtk_style_context_get_parent(long context);
+ public static final long gtk_style_context_get_parent(long context) {
+ lock.lock();
+ try {
+ return _gtk_style_context_get_parent(context);
+ } finally {
+ lock.unlock();
+ }
+ }
+ /**
* @method flags=dynamic
* @param context cast=(GtkStyleContext *)
* @param padding cast=(GtkBorder *),flags=no_in
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
index 3de6839d6b..506106abeb 100644
--- 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
@@ -1994,10 +1994,6 @@ String gtk_css_default_theme_values (int swt, String cssOutput) {
*/
String color = "";
switch (swt) {
- case SWT.COLOR_INFO_FOREGROUND:
- return gtk_css_default_theme_values_irregular(swt, cssOutput);
- case SWT.COLOR_INFO_BACKGROUND:
- return gtk_css_default_theme_values_irregular(swt, cssOutput);
case SWT.COLOR_LINK_FOREGROUND:
return gtk_css_default_theme_values_irregular(swt, cssOutput);
case SWT.COLOR_LIST_BACKGROUND:
@@ -2151,50 +2147,6 @@ String gtk_css_default_theme_values_irregular(int swt, String cssOutput) {
int tSelected, selected, classDef;
String color = "";
switch (swt) {
- case SWT.COLOR_INFO_FOREGROUND:
- selected = cssOutput.indexOf ("@define-color tooltip_fg_color");
- tSelected = cssOutput.indexOf ("@define-color theme_tooltip_fg_color");
- if (GTK.GTK_VERSION >= OS.VERSION(3, 20, 0)) {
- classDef = cssOutput.indexOf ("tooltip * {");
- } else {
- classDef = cssOutput.indexOf (".tooltip {");
- }
- if (selected != -1 || tSelected != -1) {
- if (selected != -1) {
- color = simple_color_parser(cssOutput, "@define-color tooltip_fg_color", selected);
- } else if (tSelected != -1) {
- color = simple_color_parser(cssOutput, "@define-color theme_tooltip_fg_color", tSelected);
- }
- if (!color.isEmpty()) {
- break;
- }
- } else if (classDef != -1){
- if (GTK.GTK_VERSION >= OS.VERSION(3, 20, 0)) {
- COLOR_INFO_FOREGROUND_RGBA = gtk_css_parse_foreground(cssOutput, "tooltip * {");
- } else {
- COLOR_INFO_FOREGROUND_RGBA = gtk_css_parse_foreground(cssOutput, ".tooltip {");
- }
- return "parsed";
- }
- break;
- case SWT.COLOR_INFO_BACKGROUND:
- selected = cssOutput.indexOf ("@define-color tooltip_bg_color");
- tSelected = cssOutput.indexOf ("@define-color theme_tooltip_bg_color");
- classDef = cssOutput.indexOf ("tooltip.background {");
- if (selected != -1 || tSelected != -1) {
- if (selected != -1) {
- color = simple_color_parser(cssOutput, "@define-color tooltip_bg_color", selected);
- } else if (tSelected != -1) {
- color = simple_color_parser(cssOutput, "@define-color theme_tooltip_bg_color", tSelected);
- }
- if (!color.isEmpty()) {
- break;
- }
- } else if (classDef != -1) {
- COLOR_INFO_BACKGROUND_RGBA = gtk_css_parse_background(cssOutput, "tooltip.background {");
- return "parsed";
- }
- break;
case SWT.COLOR_LINK_FOREGROUND:
selected = cssOutput.indexOf("@define-color link_color");
tSelected = cssOutput.indexOf("@define-color theme_link_color");
@@ -3186,19 +3138,33 @@ static int inversePremultipliedColor(int color, int alpha) {
return (255*color + alpha-1) / alpha;
}
-GdkRGBA styleContextGetBackgroundColor(long context, int state) {
- /*
- * Background in GTK theme can be more complex then just solid color:
- * it can have 'background-image', 'background-position', 'background-repeat', etc.
- * One example is 'tooltip' in 'Ambiance' theme, which doesn't have 'background-color'.
- * The workaround is to draw the context background to a temporary image and
- * get the color of the pixel in the middle.
- */
+/**
+ * What user sees is a combination of multiple layers.
+ * This is only important when top layer is semi-transparent.
+ */
+private static void renderAllBackgrounds(long styleContext, long cairo) {
+ long parentStyleContext = GTK.gtk_style_context_get_parent (styleContext);
+ if (parentStyleContext != 0) renderAllBackgrounds (parentStyleContext, cairo);
+
+ GTK.gtk_render_background (styleContext, cairo, -50, -50, 100, 100);
+}
+
+/**
+ * Background in GTK theme can be more complex then just solid color:
+ * 1) Due to 'background-image', 'background-position', 'background-repeat', etc.
+ * Example: 'tooltip' in 'Ambiance' theme uses 'background-image'.
+ * 2) If background is semi-transparent, user actually sees a combination of layers.
+ * Example: 'tooltip' in 'HighContrast' theme has transparent label.
+ * Both problems are solved by drawing to a temporary image and getting
+ * the color of the pixel in the middle.
+ */
+GdkRGBA styleContextEstimateBackgroundColor(long context, int state) {
+ // Render to a temporary image
GTK.gtk_style_context_save (context);
GTK.gtk_style_context_set_state (context, state);
long surface = Cairo.cairo_image_surface_create (Cairo.CAIRO_FORMAT_ARGB32, 1, 1);
long cairo = Cairo.cairo_create (surface);
- GTK.gtk_render_background (context, cairo, -50, -50, 100, 100);
+ renderAllBackgrounds (context, cairo);
Cairo.cairo_fill (cairo);
Cairo.cairo_surface_flush (surface);
byte[] buffer = new byte[4];
@@ -3207,24 +3173,14 @@ GdkRGBA styleContextGetBackgroundColor(long context, int state) {
Cairo.cairo_destroy (cairo);
GTK.gtk_style_context_restore (context);
+ // CAIRO_FORMAT_ARGB32 means a-r-g-b order, 1 byte per value.
int a = Byte.toUnsignedInt(buffer[3]);
int r = Byte.toUnsignedInt(buffer[2]);
int g = Byte.toUnsignedInt(buffer[1]);
int b = Byte.toUnsignedInt(buffer[0]);
- GdkRGBA rgba = new GdkRGBA ();
-
- if (a == 0) {
- // 'HighContrast' theme has a transparent label in tooltip.
- // For whatever reason, rendering tooltip also renders children,
- // and children are not alpha-blended on parent. This is a dirty
- // workaround for it. It will not work in case of partial
- // transparency.
- GTK.gtk_style_context_get_background_color (context, GTK.GTK_STATE_FLAG_NORMAL, rgba);
- return rgba;
- }
-
// NOTE: cairo uses premultiplied alpha (see CAIRO_FORMAT_ARGB32)
+ GdkRGBA rgba = new GdkRGBA ();
rgba.alpha = a / 255f;
rgba.red = inversePremultipliedColor(r, a) / 255f;
rgba.green = inversePremultipliedColor(g, a) / 255f;
@@ -3472,16 +3428,10 @@ void initializeSystemColorsTooltip() {
long customLabel = OS.g_object_new(GTK.gtk_label_get_type(), 0);
GTK.gtk_tooltip_set_custom(tooltip, customLabel);
- // Find tooltip window, using custom widget as entry point
- long tooltipBox = GTK.gtk_widget_get_parent(customLabel);
- long tooltipWindow = GTK.gtk_widget_get_parent(tooltipBox);
-
// Just use temporary label; this is easier then finding the original label
long styleContextLabel = GTK.gtk_widget_get_style_context(customLabel);
COLOR_INFO_FOREGROUND_RGBA = styleContextGetColor(styleContextLabel, GTK.GTK_STATE_FLAG_NORMAL);
-
- long styleContextTooltipWindow = GTK.gtk_widget_get_style_context(tooltipWindow);
- COLOR_INFO_BACKGROUND_RGBA = styleContextGetBackgroundColor(styleContextTooltipWindow, GTK.GTK_STATE_FLAG_NORMAL);
+ COLOR_INFO_BACKGROUND_RGBA = styleContextEstimateBackgroundColor(styleContextLabel, GTK.GTK_STATE_FLAG_NORMAL);
// Cleanup
// customLabel is owned by tooltip and will be destroyed automatically
diff --git a/tests/org.eclipse.swt.tests.gtk/Bug Snippets/org/eclipse/swt/tests/gtk/snippets/Bug545587_TooltipColor.java b/tests/org.eclipse.swt.tests.gtk/Bug Snippets/org/eclipse/swt/tests/gtk/snippets/Bug545587_TooltipColor.java
new file mode 100644
index 0000000000..c123889d75
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/Bug Snippets/org/eclipse/swt/tests/gtk/snippets/Bug545587_TooltipColor.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Syntevo and others. All rights reserved.
+ * The contents of this file are made available under the terms
+ * of the GNU Lesser General Public License (LGPL) Version 2.1 that
+ * accompanies this distribution (lgpl-v21.txt). The LGPL is also
+ * available at http://www.gnu.org/licenses/lgpl.html. If the version
+ * of the LGPL at http://www.gnu.org is different to the version of
+ * the LGPL accompanying this distribution and there is any conflict
+ * between the two license versions, the terms of the LGPL accompanying
+ * this distribution shall govern.
+ *
+ * Contributors:
+ * Syntevo - initial implementation
+ *******************************************************************************/
+package org.eclipse.swt.tests.gtk.snippets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+
+import java.lang.reflect.Method;
+
+public class Bug545587_TooltipColor {
+ static void updateLabel(Label a_Label) {
+ Display display = a_Label.getDisplay();
+
+ // Force recalculate colors
+ // Can be used with setting custom CSS in GTK inspector
+ try {
+ final Method setBackground = Display.class.getDeclaredMethod("initializeSystemColors");
+ setBackground.setAccessible(true);
+ setBackground.invoke(display);
+ } catch (Throwable ex) {
+ ex.printStackTrace();
+ }
+
+ Color backColor = display.getSystemColor(SWT.COLOR_INFO_BACKGROUND);
+ Color foreColor = display.getSystemColor(SWT.COLOR_INFO_FOREGROUND);
+
+ a_Label.setBackground(backColor);
+ a_Label.setForeground(foreColor);
+
+ String labelText = String.format(
+ "\n\nThese are expected tooltip's colors:\nback=%s\nfore=%s\n\nNow see tooltip and compare.",
+ backColor.toString(),
+ foreColor.toString()
+ );
+ a_Label.setText(labelText);
+ }
+
+ public static void main(String[] args) {
+ final Display display = new Display();
+
+ final Shell shell = new Shell(display, SWT.SHELL_TRIM);
+ shell.setLayout(new FillLayout());
+ shell.setSize(300, 200);
+
+ final Label label = new Label(shell, SWT.WRAP | SWT.CENTER);
+ label.addListener(SWT.MouseDown, event -> updateLabel(label));
+ updateLabel(label);
+
+ final ToolTip tooltip = new ToolTip (shell, 0);
+ tooltip.setText("Example tooltip text");
+ tooltip.setVisible(true);
+
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+
+ display.dispose();
+ }
+}
diff --git a/tests/org.eclipse.swt.tests.gtk/ManualNativeCTests/BugSnippets/Bug_545587_TooltipColor.cpp b/tests/org.eclipse.swt.tests.gtk/ManualNativeCTests/BugSnippets/Bug_545587_TooltipColor.cpp
new file mode 100644
index 0000000000..69cc8f4852
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/ManualNativeCTests/BugSnippets/Bug_545587_TooltipColor.cpp
@@ -0,0 +1,399 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Syntevo and others. All rights reserved.
+ * The contents of this file are made available under the terms
+ * of the GNU Lesser General Public License (LGPL) Version 2.1 that
+ * accompanies this distribution (lgpl-v21.txt). The LGPL is also
+ * available at http://www.gnu.org/licenses/lgpl.html. If the version
+ * of the LGPL at http://www.gnu.org is different to the version of
+ * the LGPL accompanying this distribution and there is any conflict
+ * between the two license versions, the terms of the LGPL accompanying
+ * this distribution shall govern.
+ *
+ * Contributors:
+ * Syntevo - initial implementation
+ *******************************************************************************/
+#include <gtk/gtk.h>
+#include <cstring>
+#include <string>
+#include <string.h>
+
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+std::string format_GdkRGBA(GdkRGBA a_Color)
+{
+ char buffer[64];
+
+ sprintf
+ (
+ buffer,
+ "{%3d,%3d,%3d,%3d}",
+ (unsigned char)(255 * a_Color.red),
+ (unsigned char)(255 * a_Color.green),
+ (unsigned char)(255 * a_Color.blue),
+ (unsigned char)(255 * a_Color.alpha)
+ );
+
+ return buffer;
+}
+
+void testColors()
+{
+ for (int testBits = 0; testBits < (1 << 4); testBits++)
+ {
+ GdkRGBA colorFore;
+ {
+ GtkWidgetPath* widgetPath = gtk_widget_path_new();
+ gint pathPos = gtk_widget_path_append_type(widgetPath, gtk_tooltip_get_type());
+
+ #if GTK_CHECK_VERSION(3,20,0)
+ if (testBits & 1)
+ gtk_widget_path_iter_set_object_name(widgetPath, pathPos, "tooltip");
+ #else
+ // Silence the warning
+ (void)pathPos;
+ #endif
+
+ if (testBits & 2)
+ gtk_widget_path_append_type(widgetPath, gtk_label_get_type());
+
+ GtkStyleContext* styleContext = gtk_style_context_new();
+ gtk_style_context_set_path(styleContext, widgetPath);
+ gtk_widget_path_free(widgetPath);
+
+ if (testBits & 4)
+ gtk_style_context_add_class(styleContext, GTK_STYLE_CLASS_BACKGROUND);
+
+ if (testBits & 8)
+ gtk_style_context_add_class(styleContext, GTK_STYLE_CLASS_TOOLTIP);
+
+ gtk_style_context_get_color(styleContext, GTK_STATE_FLAG_NORMAL, &colorFore);
+
+ g_object_unref(styleContext);
+ }
+
+ GdkRGBA colorBack;
+ {
+ GtkWidgetPath* widgetPath = gtk_widget_path_new();
+ gint pathPos = gtk_widget_path_append_type(widgetPath, gtk_tooltip_get_type());
+
+ #if GTK_CHECK_VERSION(3,20,0)
+ if (testBits & 1)
+ gtk_widget_path_iter_set_object_name(widgetPath, pathPos, "tooltip");
+ #else
+ // Silence the warning
+ (void)pathPos;
+ #endif
+
+ if (testBits & 2)
+ gtk_widget_path_append_type(widgetPath, gtk_label_get_type());
+
+ GtkStyleContext* styleContext = gtk_style_context_new();
+ gtk_style_context_set_path(styleContext, widgetPath);
+ gtk_widget_path_free(widgetPath);
+
+ if (testBits & 4)
+ gtk_style_context_add_class(styleContext, GTK_STYLE_CLASS_BACKGROUND);
+
+ if (testBits & 8)
+ gtk_style_context_add_class(styleContext, GTK_STYLE_CLASS_TOOLTIP);
+
+ gtk_style_context_get_background_color(styleContext, GTK_STATE_FLAG_NORMAL, &colorBack);
+
+ g_object_unref(styleContext);
+ }
+
+ printf
+ (
+ "%c%c%c%c fore=%s back=%s\n",
+ (testBits & 1) ? '1' : '-',
+ (testBits & 2) ? '2' : '-',
+ (testBits & 4) ? '3' : '-',
+ (testBits & 8) ? '4' : '-',
+ format_GdkRGBA(colorFore).c_str(),
+ format_GdkRGBA(colorBack).c_str()
+ );
+ }
+}
+
+void styleContext_getForeColor(GtkStyleContext* a_StyleContext, GdkRGBA* a_ForeColor)
+{
+ // gtk_style_context_save(a_StyleContext);
+ // gtk_style_context_set_state(a_StyleContext, GTK_STATE_FLAG_NORMAL);
+ gtk_style_context_get_color(a_StyleContext, GTK_STATE_FLAG_NORMAL, a_ForeColor);
+ // gtk_style_context_restore(a_StyleContext);
+}
+
+bool styleContext_hasBackgroundImage(GtkStyleContext* a_StyleContext)
+{
+ GValue valueBackgroundImage = G_VALUE_INIT;
+ gtk_style_context_get_property(a_StyleContext, GTK_STYLE_PROPERTY_BACKGROUND_IMAGE, GTK_STATE_FLAG_NORMAL, &valueBackgroundImage);
+
+ const bool result = (NULL != g_value_get_boxed(&valueBackgroundImage));
+
+ g_value_unset(&valueBackgroundImage);
+
+ return result;
+}
+
+int inversePremultipliedColor(int color, int alpha) {
+ if (alpha == 0) return 0;
+ return (255*color + alpha-1) / alpha;
+}
+
+void renderAllBackgrounds(GtkStyleContext* a_StyleContext, cairo_t* a_Cairo)
+{
+ GtkStyleContext* parentStyleContext = gtk_style_context_get_parent(a_StyleContext);
+ if (parentStyleContext)
+ renderAllBackgrounds(parentStyleContext, a_Cairo);
+
+ gtk_render_background(a_StyleContext, a_Cairo, -50, -50, 100, 100);
+}
+
+void styleContext_estimateBackColor(GtkStyleContext* a_StyleContext, GdkRGBA* a_BackColor)
+{
+ GtkStateFlags state = GTK_STATE_FLAG_NORMAL;
+
+ unsigned char imageBytes[4];
+ {
+ gtk_style_context_save(a_StyleContext);
+ gtk_style_context_set_state(a_StyleContext, state);
+ cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1);
+ cairo_t* cairo = cairo_create(surface);
+
+ renderAllBackgrounds(a_StyleContext, cairo);
+ cairo_surface_flush(surface);
+ memcpy(imageBytes, cairo_image_surface_get_data(surface), sizeof(imageBytes));
+
+ cairo_surface_destroy(surface);
+ cairo_destroy(cairo);
+ gtk_style_context_restore(a_StyleContext);
+ }
+
+ const unsigned char a = imageBytes[3];
+ const unsigned char r = imageBytes[2];
+ const unsigned char g = imageBytes[1];
+ const unsigned char b = imageBytes[0];
+
+ a_BackColor->alpha = a / 255.0;
+ a_BackColor->red = inversePremultipliedColor(r, a) / 255.0;
+ a_BackColor->green = inversePremultipliedColor(g, a) / 255.0;
+ a_BackColor->blue = inversePremultipliedColor(b, a) / 255.0;
+}
+
+void styleContext_getBackColor(GtkStyleContext* a_StyleContext, GdkRGBA* a_BackColor)
+{
+ gtk_style_context_get_background_color(a_StyleContext, GTK_STATE_FLAG_NORMAL, a_BackColor);
+}
+
+std::string dumpStyleContext(GtkStyleContext* a_StyleContext)
+{
+ // char* contextDump = gtk_style_context_to_string(a_StyleContext, GTK_STYLE_CONTEXT_PRINT_RECURSE);
+
+ const GtkWidgetPath* widgetPath = gtk_style_context_get_path(a_StyleContext);
+ char* contextDump = gtk_widget_path_to_string(widgetPath);
+ std::string result = contextDump;
+ g_free(contextDump);
+
+ return result;
+}
+
+void printTooltipColors(GtkStyleContext* a_StyleContextLabel, GtkStyleContext* a_StyleContextTooltip, const char* a_Caption)
+{
+ const std::string dumpFore = dumpStyleContext(a_StyleContextLabel);
+ const std::string dumpBack = dumpStyleContext(a_StyleContextTooltip);
+
+ GdkRGBA colorFore;
+ styleContext_getForeColor(a_StyleContextLabel, &colorFore);
+
+ const bool hasBackgroundImage = styleContext_hasBackgroundImage(a_StyleContextTooltip);
+
+ GdkRGBA colorBackEstim;
+ styleContext_estimateBackColor(a_StyleContextLabel, &colorBackEstim);
+
+ GdkRGBA colorBackValue;
+ styleContext_getBackColor(a_StyleContextTooltip, &colorBackValue);
+
+ printf
+ (
+ "With %s:\n"
+ "\tlabel = %s\n"
+ "\ttooltip = %s\n"
+ "\t%s = Fore color (via gtk_style_context_get_color(label))\n"
+ "\t%s = Back color (via gtk_render_background(label))\n"
+ "\t%s = Back color (via gtk_style_context_get_background_color(tooltip))\n"
+ "\tbackground-image=%c\n",
+ a_Caption,
+ dumpFore.c_str(),
+ dumpBack.c_str(),
+ format_GdkRGBA(colorFore).c_str(),
+ format_GdkRGBA(colorBackEstim).c_str(),
+ format_GdkRGBA(colorBackValue).c_str(),
+ hasBackgroundImage ? 'Y' : 'N'
+ );
+}
+
+void getTooltipColors_GtkWidgetPath()
+{
+#if GTK_CHECK_VERSION(3,20,0)
+ if (0 != gtk_check_version(3, 20, 0))
+ {
+ // 'gtk_widget_path_iter_set_object_name' was introduced in 3.20.0
+ printf("With GtkWidgetPath: Requires 3.20.0\n");
+ return;
+ }
+
+ // Foreground color is taken from 'tooltip label' css node
+ GtkStyleContext* styleContextLabel = gtk_style_context_new();
+ {
+ GtkWidgetPath* widgetPath = gtk_widget_path_new();
+ gtk_widget_path_append_type(widgetPath, 0);
+ gtk_widget_path_iter_set_object_name(widgetPath, -1, "tooltip");
+ gtk_widget_path_iter_add_class(widgetPath, -1, GTK_STYLE_CLASS_BACKGROUND);
+ gtk_widget_path_append_type(widgetPath, GTK_TYPE_LABEL);
+ gtk_style_context_set_path(styleContextLabel, widgetPath);
+ gtk_widget_path_free(widgetPath);
+ }
+
+ // Background color is taken from 'tooltip.background' css node
+ GtkStyleContext* styleContextTooltip = gtk_style_context_new();
+ {
+ GtkWidgetPath* widgetPath = gtk_widget_path_new();
+ gtk_widget_path_append_type(widgetPath, 0);
+ gtk_widget_path_iter_set_object_name(widgetPath, -1, "tooltip");
+ gtk_widget_path_iter_add_class(widgetPath, -1, GTK_STYLE_CLASS_BACKGROUND);
+ gtk_style_context_set_path(styleContextTooltip, widgetPath);
+ gtk_widget_path_free(widgetPath);
+ }
+
+ // Print
+ printTooltipColors(styleContextLabel, styleContextTooltip, "GtkWidgetPath");
+
+ // Destroy temporary style contexts
+ g_object_unref(styleContextLabel);
+ g_object_unref(styleContextTooltip);
+#endif // GTK_CHECK_VERSION(3,20,0)
+}
+
+void getTooltipColors_GtkTooltipWindow()
+{
+#if GTK_CHECK_VERSION(3,19,2)
+ if (0 != gtk_check_version(3, 19, 2))
+ {
+ // 'GtkTooltipWindow' was introduced in 3.19.2
+ printf("With GtkTooltipWindow: Requires 3.19.2\n");
+ return;
+ }
+
+ // Force 'GtkTooltip' to register 'GtkTooltipWindow' class
+ {
+ GType typeTooltip = gtk_tooltip_get_type();
+ GObject* tooltip = (GObject*)g_object_new(typeTooltip, NULL);
+ g_object_unref(tooltip);
+ }
+
+ // Obtain GType of non-exported type 'GtkTooltipWindow'
+ GType typeTooltipWindow = g_type_from_name("GtkTooltipWindow");
+ if (0 == typeTooltipWindow)
+ {
+ printf("With GtkTooltipWindow: g_type_from_name() failed\n");
+ return;
+ }
+
+ // Create temporary tooltip
+ GtkWidget* tooltip = (GtkWidget*)g_object_new(typeTooltipWindow, NULL);
+
+ // Create temporary label in tooltip
+ GtkWidget* tooltipLabel = (GtkWidget*)g_object_new(GTK_TYPE_LABEL, NULL);
+ gtk_widget_set_parent(tooltipLabel, tooltip);
+
+ // Obtain style contexts
+ GtkStyleContext* styleContextLabel = gtk_widget_get_style_context(tooltipLabel);
+ GtkStyleContext* styleContextTooltip = gtk_widget_get_style_context(tooltip);
+
+ // Print
+ printTooltipColors(styleContextLabel, styleContextTooltip, "GtkTooltipWindow");
+
+ // Also destroys child label
+ gtk_widget_destroy(tooltip);
+#endif // GTK_CHECK_VERSION(3,19,2)
+}
+
+void getTooltipColors_TooltipSetCustom()
+{
+ // Create a temporary tooltip
+ GType typeTooltip = gtk_tooltip_get_type();
+ GtkTooltip* tooltip = (GtkTooltip*)g_object_new(typeTooltip, NULL);
+
+ // Add temporary label as custom control into tooltip
+ GtkWidget* customLabel = (GtkWidget*)g_object_new(GTK_TYPE_LABEL, NULL);
+ gtk_tooltip_set_custom(tooltip, customLabel);
+
+ // Find tooltip window, using custom widget as entry point
+ GtkWidget* tooltipBox = gtk_widget_get_parent(customLabel);
+ GtkWidget* tooltipWindow = gtk_widget_get_parent(tooltipBox);
+
+ // Obtain style contexts
+ // For label, just use temporary label; this is easier then finding the original label
+ GtkStyleContext* styleContextLabel = gtk_widget_get_style_context(customLabel);
+ GtkStyleContext* styleContextTooltip = gtk_widget_get_style_context(tooltipWindow);
+
+ // Print
+ printTooltipColors(styleContextLabel, styleContextTooltip, "TooltipSetCustom");
+
+ // Cleanup
+ // customLabel is owned by tooltip and will be destroyed automatically
+ g_object_unref(tooltip);
+}
+
+bool isThemeAvailable()
+{
+ const char* themeName = g_getenv("GTK_THEME");
+
+ if (!themeName)
+ return true;
+
+ if (0 == strcasecmp(themeName, "Adwaita"))
+ return true;
+
+ // When GTK doesn't find a theme, it simply loads Adwaita.
+ GtkCssProvider* selectedTheme = gtk_css_provider_get_named(themeName, NULL);
+ GtkCssProvider* adwaitaTheme = gtk_css_provider_get_named("Adwaita", NULL);
+
+ char* selectedThemeString = gtk_css_provider_to_string(selectedTheme);
+ char* adwaitaThemeString = gtk_css_provider_to_string(adwaitaTheme);
+ const bool isAdwaita =(0 == strcmp(selectedThemeString, adwaitaThemeString));
+ g_free(selectedThemeString);
+ g_free(adwaitaThemeString);
+
+ if (isAdwaita)
+ {
+ printf("Error: Theme %s not found\n", themeName);
+ return false;
+ }
+
+ return true;
+}
+
+int main(int argc, char* argv[])
+{
+ gtk_init(&argc, &argv);
+
+ if (!isThemeAvailable())
+ return 0;
+
+ printf
+ (
+ "GTK version: %d.%d.%d\n",
+ gtk_get_major_version(),
+ gtk_get_minor_version(),
+ gtk_get_micro_version()
+ );
+
+ // testColors();
+ getTooltipColors_GtkWidgetPath();
+ getTooltipColors_GtkTooltipWindow();
+ getTooltipColors_TooltipSetCustom();
+
+ return 0;
+}
+

Back to the top