diff options
Diffstat (limited to 'subprojects/libhandy/src/hdy-main.c')
-rw-r--r-- | subprojects/libhandy/src/hdy-main.c | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/subprojects/libhandy/src/hdy-main.c b/subprojects/libhandy/src/hdy-main.c new file mode 100644 index 0000000..6c5df7b --- /dev/null +++ b/subprojects/libhandy/src/hdy-main.c @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2018-2020 Purism SPC + * + * SPDX-License-Identifier: LGPL-2.1+ + */ +#include "config.h" +#include "hdy-main-private.h" +#include <gio/gio.h> +#include <glib/gi18n-lib.h> +#include <gtk/gtk.h> + +static gint hdy_initialized = FALSE; + +/** + * SECTION:hdy-main + * @short_description: Library initialization. + * @Title: hdy-main + * + * Before using the Handy library you should initialize it by calling the + * hdy_init() function. + * This makes sure translations, types, themes, and icons for the Handy library + * are set up properly. + */ + +/* The style provider priority to use for libhandy widgets custom styling. It is + * higher than themes and settings, allowing to override theme defaults, but + * lower than applications and user provided styles, so application developers + * can nonetheless apply custom styling on top of it. */ +#define HDY_STYLE_PROVIDER_PRIORITY_OVERRIDE (GTK_STYLE_PROVIDER_PRIORITY_SETTINGS + 1) + +#define HDY_THEMES_PATH "/sm/puri/handy/themes/" + +static inline gboolean +hdy_resource_exists (const gchar *resource_path) +{ + return g_resources_get_info (resource_path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL, NULL, NULL); +} + +static gchar * +hdy_themes_get_theme_name (gboolean *prefer_dark_theme) +{ + gchar *theme_name = NULL; + gchar *p; + + g_assert (prefer_dark_theme); + + theme_name = g_strdup (g_getenv ("GTK_THEME")); + + if (theme_name == NULL) { + g_object_get (gtk_settings_get_default (), + "gtk-theme-name", &theme_name, + "gtk-application-prefer-dark-theme", prefer_dark_theme, + NULL); + + return theme_name; + } + + /* Theme variants are specified with the syntax + * "<theme>:<variant>" e.g. "Adwaita:dark" */ + if (NULL != (p = strrchr (theme_name, ':'))) { + *p = '\0'; + p++; + *prefer_dark_theme = g_strcmp0 (p, "dark") == 0; + } + + return theme_name; +} + +static void +hdy_themes_update (GtkCssProvider *css_provider) +{ + g_autofree gchar *theme_name = NULL; + g_autofree gchar *resource_path = NULL; + gboolean prefer_dark_theme = FALSE; + + g_assert (GTK_IS_CSS_PROVIDER (css_provider)); + + theme_name = hdy_themes_get_theme_name (&prefer_dark_theme); + + /* First check with full path to theme+variant */ + resource_path = g_strdup_printf (HDY_THEMES_PATH"%s%s.css", + theme_name, prefer_dark_theme ? "-dark" : ""); + + if (!hdy_resource_exists (resource_path)) { + /* Now try without the theme variant */ + g_free (resource_path); + resource_path = g_strdup_printf (HDY_THEMES_PATH"%s.css", theme_name); + + if (!hdy_resource_exists (resource_path)) { + /* Now fallback to shared styling */ + g_free (resource_path); + resource_path = g_strdup (HDY_THEMES_PATH"shared.css"); + + g_assert (hdy_resource_exists (resource_path)); + } + } + + gtk_css_provider_load_from_resource (css_provider, resource_path); +} + +static void +load_fallback_style (void) +{ + g_autoptr (GtkCssProvider) css_provider = NULL; + + css_provider = gtk_css_provider_new (); + gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), + GTK_STYLE_PROVIDER (css_provider), + GTK_STYLE_PROVIDER_PRIORITY_FALLBACK); + + gtk_css_provider_load_from_resource (css_provider, HDY_THEMES_PATH"fallback.css"); +} + +/** + * hdy_style_init: + * + * Initializes the style classes. This must be called once GTK has been + * initialized. + * + * Since: 1.0 + */ +static void +hdy_style_init (void) +{ + static volatile gsize guard = 0; + g_autoptr (GtkCssProvider) css_provider = NULL; + GtkSettings *settings; + + if (!g_once_init_enter (&guard)) + return; + + css_provider = gtk_css_provider_new (); + gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), + GTK_STYLE_PROVIDER (css_provider), + HDY_STYLE_PROVIDER_PRIORITY_OVERRIDE); + + settings = gtk_settings_get_default (); + g_signal_connect_swapped (settings, + "notify::gtk-theme-name", + G_CALLBACK (hdy_themes_update), + css_provider); + g_signal_connect_swapped (settings, + "notify::gtk-application-prefer-dark-theme", + G_CALLBACK (hdy_themes_update), + css_provider); + + hdy_themes_update (css_provider); + + load_fallback_style (); + + g_once_init_leave (&guard, 1); +} + +/** + * hdy_icons_init: + * + * Initializes the embedded icons. This must be called once GTK has been + * initialized. + * + * Since: 1.0 + */ +static void +hdy_icons_init (void) +{ + static volatile gsize guard = 0; + + if (!g_once_init_enter (&guard)) + return; + + gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (), + "/sm/puri/handy/icons"); + + g_once_init_leave (&guard, 1); +} + +/** + * hdy_init: + * + * Call this function just after initializing GTK, if you are using + * #GtkApplication it means it must be called when the #GApplication::startup + * signal is emitted. If libhandy has already been initialized, the function + * will simply return. + * + * This makes sure translations, types, themes, and icons for the Handy library + * are set up properly. + */ +void +hdy_init (void) +{ + if (hdy_initialized) + return; + + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + hdy_init_public_types (); + + hdy_style_init (); + hdy_icons_init (); + + hdy_initialized = TRUE; +} |