mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-03-10 16:00:18 +00:00
341 lines
10 KiB
C
341 lines
10 KiB
C
#include "theme-css.h"
|
|
|
|
#include "theme-runtime.h"
|
|
#include "theme-gtk3.h"
|
|
#include "theme-access.h"
|
|
#include "../gtkutil.h"
|
|
#include <string.h>
|
|
|
|
static const char *theme_css_selector_input = "#zoitechat-inputbox";
|
|
static const char *theme_css_selector_input_text = "#zoitechat-inputbox text";
|
|
static const char *theme_css_selector_palette_class = "zoitechat-palette";
|
|
static const char *theme_css_selector_dark_class = "zoitechat-dark";
|
|
static const char *theme_css_selector_light_class = "zoitechat-light";
|
|
static const char *theme_css_palette_provider_key = "zoitechat-palette-provider";
|
|
static const guint theme_css_provider_priority = GTK_STYLE_PROVIDER_PRIORITY_USER;
|
|
|
|
typedef struct
|
|
{
|
|
char *theme_name;
|
|
char *font;
|
|
gboolean enabled;
|
|
gboolean dark;
|
|
gboolean colors_set;
|
|
guint16 fg_red;
|
|
guint16 fg_green;
|
|
guint16 fg_blue;
|
|
guint16 bg_red;
|
|
guint16 bg_green;
|
|
guint16 bg_blue;
|
|
} ThemeCssInputFingerprint;
|
|
|
|
static GtkCssProvider *theme_css_input_provider;
|
|
static ThemeCssInputFingerprint theme_css_input_fp;
|
|
|
|
void
|
|
theme_css_apply_app_provider (GtkStyleProvider *provider)
|
|
{
|
|
GdkScreen *screen;
|
|
|
|
if (!provider)
|
|
return;
|
|
|
|
screen = gdk_screen_get_default ();
|
|
if (!screen)
|
|
return;
|
|
|
|
gtk_style_context_add_provider_for_screen (screen, provider, theme_css_provider_priority);
|
|
}
|
|
|
|
void
|
|
theme_css_remove_app_provider (GtkStyleProvider *provider)
|
|
{
|
|
GdkScreen *screen;
|
|
|
|
if (!provider)
|
|
return;
|
|
|
|
screen = gdk_screen_get_default ();
|
|
if (!screen)
|
|
return;
|
|
|
|
gtk_style_context_remove_provider_for_screen (screen, provider);
|
|
}
|
|
|
|
void
|
|
theme_css_apply_widget_provider (GtkWidget *widget, GtkStyleProvider *provider)
|
|
{
|
|
GtkStyleContext *context;
|
|
|
|
if (!widget || !provider)
|
|
return;
|
|
|
|
context = gtk_widget_get_style_context (widget);
|
|
if (!context)
|
|
return;
|
|
|
|
gtk_style_context_add_provider (context, provider, theme_css_provider_priority);
|
|
}
|
|
|
|
static gboolean
|
|
theme_css_input_fingerprint_matches (const ThemeCssInputFingerprint *next)
|
|
{
|
|
if (theme_css_input_fp.enabled != next->enabled)
|
|
return FALSE;
|
|
if (theme_css_input_fp.dark != next->dark)
|
|
return FALSE;
|
|
if (theme_css_input_fp.colors_set != next->colors_set)
|
|
return FALSE;
|
|
if (theme_css_input_fp.fg_red != next->fg_red || theme_css_input_fp.fg_green != next->fg_green
|
|
|| theme_css_input_fp.fg_blue != next->fg_blue)
|
|
return FALSE;
|
|
if (theme_css_input_fp.bg_red != next->bg_red || theme_css_input_fp.bg_green != next->bg_green
|
|
|| theme_css_input_fp.bg_blue != next->bg_blue)
|
|
return FALSE;
|
|
if (g_strcmp0 (theme_css_input_fp.theme_name, next->theme_name) != 0)
|
|
return FALSE;
|
|
if (g_strcmp0 (theme_css_input_fp.font, next->font) != 0)
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
theme_css_input_fingerprint_replace (ThemeCssInputFingerprint *next)
|
|
{
|
|
g_free (theme_css_input_fp.theme_name);
|
|
g_free (theme_css_input_fp.font);
|
|
theme_css_input_fp = *next;
|
|
next->theme_name = NULL;
|
|
next->font = NULL;
|
|
}
|
|
|
|
static void
|
|
theme_css_input_fingerprint_clear (void)
|
|
{
|
|
g_free (theme_css_input_fp.theme_name);
|
|
g_free (theme_css_input_fp.font);
|
|
memset (&theme_css_input_fp, 0, sizeof (theme_css_input_fp));
|
|
}
|
|
|
|
static char *
|
|
theme_css_build_input (const char *theme_name, guint16 fg_red, guint16 fg_green, guint16 fg_blue,
|
|
guint16 bg_red, guint16 bg_green, guint16 bg_blue)
|
|
{
|
|
GString *css = g_string_new ("");
|
|
|
|
if (g_str_has_prefix (theme_name, "Adwaita") || g_str_has_prefix (theme_name, "Yaru"))
|
|
{
|
|
g_string_append_printf (css, "%s { background-image: none; }", theme_css_selector_input);
|
|
}
|
|
|
|
g_string_append_printf (css,
|
|
"%s {"
|
|
"background-color: #%02x%02x%02x;"
|
|
"color: #%02x%02x%02x;"
|
|
"caret-color: #%02x%02x%02x;"
|
|
"}"
|
|
"%s {"
|
|
"color: #%02x%02x%02x;"
|
|
"caret-color: #%02x%02x%02x;"
|
|
"}",
|
|
theme_css_selector_input,
|
|
(bg_red >> 8), (bg_green >> 8), (bg_blue >> 8),
|
|
(fg_red >> 8), (fg_green >> 8), (fg_blue >> 8),
|
|
(fg_red >> 8), (fg_green >> 8), (fg_blue >> 8),
|
|
theme_css_selector_input_text,
|
|
(fg_red >> 8), (fg_green >> 8), (fg_blue >> 8),
|
|
(fg_red >> 8), (fg_green >> 8), (fg_blue >> 8));
|
|
|
|
return g_string_free (css, FALSE);
|
|
}
|
|
|
|
void
|
|
theme_css_reload_input_style (gboolean enabled, const PangoFontDescription *font_desc)
|
|
{
|
|
ThemeCssInputFingerprint next = {0};
|
|
|
|
next.enabled = enabled;
|
|
next.dark = theme_runtime_is_dark_active ();
|
|
next.theme_name = NULL;
|
|
next.font = font_desc ? pango_font_description_to_string (font_desc) : NULL;
|
|
|
|
if (enabled)
|
|
{
|
|
GtkSettings *settings = gtk_settings_get_default ();
|
|
char *theme_name = NULL;
|
|
char *css;
|
|
|
|
if (settings)
|
|
g_object_get (settings, "gtk-theme-name", &theme_name, NULL);
|
|
|
|
next.theme_name = g_strdup (theme_name);
|
|
{
|
|
ThemeWidgetStyleValues style_values;
|
|
|
|
theme_get_widget_style_values_for_widget (NULL, &style_values);
|
|
theme_palette_color_get_rgb16 (&style_values.foreground,
|
|
&next.fg_red, &next.fg_green, &next.fg_blue);
|
|
theme_palette_color_get_rgb16 (&style_values.background,
|
|
&next.bg_red, &next.bg_green, &next.bg_blue);
|
|
next.colors_set = TRUE;
|
|
}
|
|
|
|
if (theme_css_input_fingerprint_matches (&next))
|
|
{
|
|
g_free (theme_name);
|
|
g_free (next.theme_name);
|
|
g_free (next.font);
|
|
return;
|
|
}
|
|
|
|
if (!theme_css_input_provider)
|
|
theme_css_input_provider = gtk_css_provider_new ();
|
|
|
|
css = theme_css_build_input (theme_name ? theme_name : "",
|
|
next.fg_red, next.fg_green, next.fg_blue,
|
|
next.bg_red, next.bg_green, next.bg_blue);
|
|
gtk_css_provider_load_from_data (theme_css_input_provider, css, -1, NULL);
|
|
g_free (css);
|
|
theme_css_apply_app_provider (GTK_STYLE_PROVIDER (theme_css_input_provider));
|
|
|
|
g_free (theme_name);
|
|
theme_css_input_fingerprint_replace (&next);
|
|
return;
|
|
}
|
|
|
|
if (theme_css_input_provider)
|
|
theme_css_remove_app_provider (GTK_STYLE_PROVIDER (theme_css_input_provider));
|
|
g_clear_object (&theme_css_input_provider);
|
|
theme_css_input_fingerprint_clear ();
|
|
g_free (next.theme_name);
|
|
g_free (next.font);
|
|
}
|
|
|
|
void
|
|
theme_css_apply_palette_widget (GtkWidget *widget, const GdkRGBA *bg, const GdkRGBA *fg,
|
|
const PangoFontDescription *font_desc)
|
|
{
|
|
GtkCssProvider *provider;
|
|
gboolean new_provider = FALSE;
|
|
GString *css;
|
|
gchar *bg_color = NULL;
|
|
gchar *fg_color = NULL;
|
|
gchar *sel_bg_color = NULL;
|
|
gchar *sel_fg_color = NULL;
|
|
|
|
if (!widget)
|
|
return;
|
|
|
|
provider = g_object_get_data (G_OBJECT (widget), theme_css_palette_provider_key);
|
|
|
|
if (!bg && !fg && !font_desc)
|
|
{
|
|
gtk_style_context_remove_class (gtk_widget_get_style_context (widget), theme_css_selector_palette_class);
|
|
if (provider)
|
|
{
|
|
gtk_style_context_remove_provider (gtk_widget_get_style_context (widget), GTK_STYLE_PROVIDER (provider));
|
|
g_object_set_data (G_OBJECT (widget), theme_css_palette_provider_key, NULL);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!provider)
|
|
{
|
|
provider = gtk_css_provider_new ();
|
|
g_object_set_data_full (G_OBJECT (widget), theme_css_palette_provider_key,
|
|
provider, g_object_unref);
|
|
new_provider = TRUE;
|
|
}
|
|
|
|
css = g_string_new (".");
|
|
g_string_append (css, theme_css_selector_palette_class);
|
|
g_string_append (css, " {");
|
|
if (bg)
|
|
{
|
|
bg_color = gdk_rgba_to_string (bg);
|
|
g_string_append_printf (css, " background-color: %s;", bg_color);
|
|
}
|
|
if (fg)
|
|
{
|
|
fg_color = gdk_rgba_to_string (fg);
|
|
g_string_append_printf (css, " color: %s;", fg_color);
|
|
}
|
|
{
|
|
GdkRGBA selection_bg;
|
|
GdkRGBA selection_fg;
|
|
if (theme_runtime_get_color (THEME_TOKEN_SELECTION_BACKGROUND, &selection_bg))
|
|
sel_bg_color = gdk_rgba_to_string (&selection_bg);
|
|
if (theme_runtime_get_color (THEME_TOKEN_SELECTION_FOREGROUND, &selection_fg))
|
|
sel_fg_color = gdk_rgba_to_string (&selection_fg);
|
|
}
|
|
gtkutil_append_font_css (css, font_desc);
|
|
g_string_append (css, " }");
|
|
g_string_append_printf (css, ".%s, .%s *, .%s treeview, .%s treeview.view, .%s treeview.view text, .%s treeview.view cell, .%s treeview.view row, .%s list, .%s list row, .%s text {", theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class);
|
|
if (bg)
|
|
g_string_append_printf (css, " background-color: %s;", bg_color);
|
|
if (fg)
|
|
g_string_append_printf (css, " color: %s;", fg_color);
|
|
g_string_append (css, " }");
|
|
g_string_append_printf (css, ".%s *:selected, .%s *:selected:focus, .%s *:selected:hover, .%s treeview.view:selected, .%s treeview.view:selected:focus, .%s treeview.view:selected:hover, .%s row:selected, .%s row:selected:focus, .%s row:selected:hover {", theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class);
|
|
if (sel_bg_color)
|
|
g_string_append_printf (css, " background-color: %s;", sel_bg_color);
|
|
else if (bg)
|
|
g_string_append (css, " background-color: @theme_selected_bg_color;");
|
|
if (sel_fg_color)
|
|
g_string_append_printf (css, " color: %s;", sel_fg_color);
|
|
else if (fg)
|
|
g_string_append (css, " color: @theme_selected_fg_color;");
|
|
g_string_append (css, " }");
|
|
|
|
gtk_css_provider_load_from_data (provider, css->str, -1, NULL);
|
|
if (new_provider)
|
|
theme_css_apply_widget_provider (widget, GTK_STYLE_PROVIDER (provider));
|
|
gtk_style_context_add_class (gtk_widget_get_style_context (widget), theme_css_selector_palette_class);
|
|
|
|
g_string_free (css, TRUE);
|
|
g_free (bg_color);
|
|
g_free (fg_color);
|
|
g_free (sel_bg_color);
|
|
g_free (sel_fg_color);
|
|
}
|
|
|
|
char *
|
|
theme_css_build_toplevel_classes (void)
|
|
{
|
|
return g_strdup_printf (
|
|
"window.%s, window.%s:backdrop, .%s {"
|
|
"background-color: #202020;"
|
|
"color: #f0f0f0;"
|
|
"border-color: #202020;"
|
|
"}"
|
|
"window.%s menubar, window.%s menubar:backdrop, window.%s menuitem, window.%s menuitem:backdrop {"
|
|
"background-color: #202020;"
|
|
"color: #f0f0f0;"
|
|
"border-color: #202020;"
|
|
"}"
|
|
"window.%s, window.%s:backdrop, .%s {"
|
|
"background-color: #f6f6f6;"
|
|
"color: #101010;"
|
|
"border-color: #f6f6f6;"
|
|
"}"
|
|
"window.%s menubar, window.%s menubar:backdrop, window.%s menuitem, window.%s menuitem:backdrop {"
|
|
"background-color: #f6f6f6;"
|
|
"color: #101010;"
|
|
"border-color: #f6f6f6;"
|
|
"}",
|
|
theme_css_selector_dark_class,
|
|
theme_css_selector_dark_class,
|
|
theme_css_selector_dark_class,
|
|
theme_css_selector_dark_class,
|
|
theme_css_selector_dark_class,
|
|
theme_css_selector_dark_class,
|
|
theme_css_selector_dark_class,
|
|
theme_css_selector_light_class,
|
|
theme_css_selector_light_class,
|
|
theme_css_selector_light_class,
|
|
theme_css_selector_light_class,
|
|
theme_css_selector_light_class,
|
|
theme_css_selector_light_class,
|
|
theme_css_selector_light_class);
|
|
}
|