diff options
author | Alexandr Miloslavskiy | 2019-04-15 14:35:55 +0000 |
---|---|---|
committer | Eric Williams | 2019-04-16 14:04:01 +0000 |
commit | f4cff7872b771fc8b6e5080b5b256b174f68de3e (patch) | |
tree | 539bdd949e539373ba43faa317dc7c7596b3469c /tests/org.eclipse.swt.tests.gtk/ManualNativeCTests/BugSnippets/Bug_545587_TooltipColor.cpp | |
parent | c64218f83b34c6936c38d867bf5bfa4cfa76fdef (diff) | |
download | eclipse.platform.swt-f4cff7872b771fc8b6e5080b5b256b174f68de3e.tar.gz eclipse.platform.swt-f4cff7872b771fc8b6e5080b5b256b174f68de3e.tar.xz eclipse.platform.swt-f4cff7872b771fc8b6e5080b5b256b174f68de3e.zip |
Bug 546252 - [GTK] Cleanup for tooltip color fixes
Fix:
----
All layers are rendered when background color is estimated. This solves
the problem for themes that utilize semi-transparent labels in tooltips,
such as 'HighContrast'.
NOTE: 'gtk_style_context_get_parent' requires 3.4. However, for Eclipse
4.12 requires at least GTK 3.10, so this can be ignored.
Code cleaning:
--------------
Deleted tooltip-related CSS parsing code that is now dead.
Tests:
------
Added snippets I developed during investigation.
Change-Id: Ic4504be60df58f32e32b90a487e28af68853977d
Signed-off-by: Alexandr Miloslavskiy <alexandr.miloslavskiy@syntevo.com>
Diffstat (limited to 'tests/org.eclipse.swt.tests.gtk/ManualNativeCTests/BugSnippets/Bug_545587_TooltipColor.cpp')
-rw-r--r-- | tests/org.eclipse.swt.tests.gtk/ManualNativeCTests/BugSnippets/Bug_545587_TooltipColor.cpp | 399 |
1 files changed, 399 insertions, 0 deletions
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; +} + |