diff --git a/shell/platform/linux/fl_settings_plugin.cc b/shell/platform/linux/fl_settings_plugin.cc index 446ae9751c96c..db1896108aad1 100644 --- a/shell/platform/linux/fl_settings_plugin.cc +++ b/shell/platform/linux/fl_settings_plugin.cc @@ -4,7 +4,9 @@ #include "flutter/shell/platform/linux/fl_settings_plugin.h" -#include +#include +#include +#include #include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" @@ -17,11 +19,12 @@ static constexpr char kPlatformBrightnessLight[] = "light"; static constexpr char kPlatformBrightnessDark[] = "dark"; static constexpr char kDesktopInterfaceSchema[] = "org.gnome.desktop.interface"; -static constexpr char kDesktopGtkThemeKey[] = "gtk-theme"; static constexpr char kDesktopTextScalingFactorKey[] = "text-scaling-factor"; static constexpr char kDesktopClockFormatKey[] = "clock-format"; static constexpr char kClockFormat24Hour[] = "24h"; +enum class Brightness { Light, Dark }; + struct _FlSettingsPlugin { GObject parent_instance; @@ -32,6 +35,51 @@ struct _FlSettingsPlugin { G_DEFINE_TYPE(FlSettingsPlugin, fl_settings_plugin, G_TYPE_OBJECT) +// The color brightness calculation has been adapted from theme_data.dart: +// https://github.com/flutter/flutter/blob/8fe4cc79648a952f9c7e49a5248756c2ff98fa3b/packages/flutter/lib/src/material/theme_data.dart#L1470-L1488 + +// See . +static gdouble linearize_color_component(gdouble component) { + if (component <= 0.03928) + return component / 12.92; + return pow((component + 0.055) / 1.055, 2.4); +} + +// See . +gdouble compute_luminance(GdkRGBA* color) { + gdouble r = linearize_color_component(color->red); + gdouble g = linearize_color_component(color->green); + gdouble b = linearize_color_component(color->blue); + return 0.2126 * r + 0.7152 * g + 0.0722 * b; +} + +static Brightness estimate_brightness_for_color(GdkRGBA* color) { + gdouble relative_luminance = compute_luminance(color); + + // See and + // . + const gdouble kThreshold = 0.15; + if ((relative_luminance + 0.05) * (relative_luminance + 0.05) > kThreshold) + return Brightness::Light; + return Brightness::Dark; +} + +static bool is_dark_theme() { + // GTK doesn't have a specific flag for dark themes, so we check if the + // style text color is light or dark + GList* windows = gtk_window_list_toplevels(); + if (windows == nullptr) + return false; + + GtkWidget* window = GTK_WIDGET(windows->data); + g_list_free(windows); + + GdkRGBA text_color; + GtkStyleContext* style = gtk_widget_get_style_context(window); + gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &text_color); + return estimate_brightness_for_color(&text_color) == Brightness::Light; +} + // Sends the current settings to the Flutter engine. static void update_settings(FlSettingsPlugin* self) { gdouble scaling_factor = 1.0; @@ -44,15 +92,10 @@ static void update_settings(FlSettingsPlugin* self) { g_autofree gchar* clock_format = g_settings_get_string(self->interface_settings, kDesktopClockFormatKey); always_use_24hr = g_strcmp0(clock_format, kClockFormat24Hour) == 0; + } - // GTK doesn't have a specific flag for dark themes, so we have some - // hard-coded themes for Ubuntu (Yaru) and GNOME (Adwaita). - g_autofree gchar* gtk_theme = - g_settings_get_string(self->interface_settings, kDesktopGtkThemeKey); - if (g_strcmp0(gtk_theme, "Yaru-dark") == 0 || - g_strcmp0(gtk_theme, "Adwaita-dark") == 0) { - platform_brightness = kPlatformBrightnessDark; - } + if (is_dark_theme()) { + platform_brightness = kPlatformBrightnessDark; } g_autoptr(FlValue) message = fl_value_new_map();