From e04cdce680b9a1bef3837c6f18eed5e4320c3509 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 3 Jun 2024 23:18:48 -0400 Subject: [PATCH] css: Implement light-dark() This function returns one of two colors, depending on the colorscheme that is in use. --- gtk/gtkcsscolorvalue.c | 113 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-) diff --git a/gtk/gtkcsscolorvalue.c b/gtk/gtkcsscolorvalue.c index 2ecf9d5c62..eecb958b96 100644 --- a/gtk/gtkcsscolorvalue.c +++ b/gtk/gtkcsscolorvalue.c @@ -46,6 +46,7 @@ typedef enum { COLOR_TYPE_ALPHA, COLOR_TYPE_MIX, COLOR_TYPE_CURRENT_COLOR, + COLOR_TYPE_LIGHT_DARK, } ColorType; struct _GtkCssValue @@ -90,6 +91,12 @@ struct _GtkCssValue gboolean legacy_srgb; GtkCssValue *values[1]; } relative; + + struct + { + GtkCssValue *color1; + GtkCssValue *color2; + } light_dark; }; }; @@ -129,7 +136,11 @@ gtk_css_value_color_free (GtkCssValue *color) if (color->relative.values[i]) gtk_css_value_unref (color->relative.values[i]); } + break; + case COLOR_TYPE_LIGHT_DARK: + gtk_css_value_unref (color->light_dark.color1); + gtk_css_value_unref (color->light_dark.color2); break; case COLOR_TYPE_COLOR: @@ -270,6 +281,12 @@ gtk_css_value_color_equal (const GtkCssValue *value1, case COLOR_TYPE_CURRENT_COLOR: return TRUE; + case COLOR_TYPE_LIGHT_DARK: + return gtk_css_value_equal (value1->light_dark.color1, + value2->light_dark.color1) && + gtk_css_value_equal (value1->light_dark.color2, + value2->light_dark.color2); + default: g_assert_not_reached (); return FALSE; @@ -494,6 +511,14 @@ gtk_css_value_color_print (const GtkCssValue *value, g_string_append (string, "currentcolor"); break; + case COLOR_TYPE_LIGHT_DARK: + g_string_append (string, "light-dark("); + gtk_css_value_print (value->light_dark.color1, string); + g_string_append (string, ", "); + gtk_css_value_print (value->light_dark.color2, string); + g_string_append_c (string, ')'); + break; + default: g_assert_not_reached (); } @@ -752,6 +777,30 @@ gtk_css_color_value_do_resolve (GtkCssValue *color, value = gtk_css_value_ref (current); break; + case COLOR_TYPE_LIGHT_DARK: + { + GtkSettings *settings = gtk_style_provider_get_settings (provider); + int color_scheme; + + g_object_get (settings, "gtk-color-scheme", &color_scheme, NULL); + + switch (color_scheme) + { + case GTK_COLOR_SCHEME_LIGHT: + value = gtk_css_color_value_do_resolve (color->light_dark.color1, property_id, context, current, cycle_list); + break; + + case GTK_COLOR_SCHEME_DARK: + value = gtk_css_color_value_do_resolve (color->light_dark.color2, property_id, context, current, cycle_list); + break; + + default: + g_assert_not_reached (); + + } + } + break; + default: value = NULL; g_assert_not_reached (); @@ -1007,6 +1056,20 @@ gtk_css_color_value_new_current_color (void) return gtk_css_value_ref (¤t_color); } +static GtkCssValue * +gtk_css_color_value_new_light_dark (GtkCssValue *color1, + GtkCssValue *color2) +{ + GtkCssValue *value; + + value = gtk_css_value_new (GtkCssValue, >K_CSS_VALUE_COLOR); + value->type = COLOR_TYPE_LIGHT_DARK; + value->light_dark.color1 = gtk_css_value_ref (color1); + value->light_dark.color2 = gtk_css_value_ref (color2); + + return value; +} + /* }}} */ /* {{{ Parsing */ @@ -1031,7 +1094,8 @@ gtk_css_color_value_can_parse (GtkCssParser *parser) || gtk_css_parser_has_function (parser, "oklab") || gtk_css_parser_has_function (parser, "oklch") || gtk_css_parser_has_function (parser, "color") - || gtk_css_parser_has_function (parser, "color-mix"); + || gtk_css_parser_has_function (parser, "color-mix") + || gtk_css_parser_has_function (parser, "light-dark"); } typedef struct @@ -1179,6 +1243,39 @@ parse_color_number (GtkCssParser *parser, } } +static guint +parse_color_color (GtkCssParser *parser, + guint arg, + gpointer data_) +{ + ColorFunctionData *data = data_; + + switch (arg) + { + case 0: + data->color = gtk_css_color_value_parse (parser); + if (data->color == NULL) + return 0; + return 1; + + case 1: + data->color2 = gtk_css_color_value_parse (parser); + if (data->color2 == NULL) + return 0; + return 1; + + default: + g_return_val_if_reached (0); + } +} + +typedef struct +{ + GdkRGBA *rgba; + gboolean use_percentages; + gboolean missing[4]; +} ParseRGBAData; + typedef enum { COLOR_SYNTAX_DETECTING, @@ -1916,6 +2013,20 @@ gtk_css_color_value_parse (GtkCssParser *parser) g_clear_pointer (&data.color1, gtk_css_value_unref); g_clear_pointer (&data.color2, gtk_css_value_unref); + return value; + } + else if (gtk_css_parser_has_function (parser, "light-dark")) + { + ColorFunctionData data = { NULL, }; + + if (gtk_css_parser_consume_function (parser, 2, 2, parse_color_color, &data)) + value = gtk_css_color_value_new_light_dark (data.color, data.color2); + else + value = NULL; + + g_clear_pointer (&data.color, gtk_css_value_unref); + g_clear_pointer (&data.color2, gtk_css_value_unref); + return value; } else if (gtk_css_parser_has_function (parser, "lighter"))