From 30411ff58e8c495953d09b5b796ce129056c20fb Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Wed, 17 Oct 2018 20:52:51 +0200
Subject: Written a better version of CSS definitions loading.

---
 src/gui/core/theme.c | 205 +++++++++++++++++++++++++++++++++++----------------
 1 file changed, 141 insertions(+), 64 deletions(-)

diff --git a/src/gui/core/theme.c b/src/gui/core/theme.c
index 4b097d0..be060be 100644
--- a/src/gui/core/theme.c
+++ b/src/gui/core/theme.c
@@ -25,13 +25,14 @@
 #include "theme.h"
 
 
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <assert.h>
 #include <dirent.h>
 #include <fcntl.h>
 #include <malloc.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 
 #include <config.h>
@@ -46,10 +47,16 @@
 
 
 /* Parcourt tous les répertoires connus pour trouver un thème. */
-static bool browse_themes_directories(GdkScreen *, const char *, gboolean);
+static char *browse_themes_directories(const char *, gboolean);
 
 /* Parcourt un répertoire donné à la recherche d'un thème. */
-static bool look_for_named_theme(GdkScreen *, const char *, const char *, gboolean);
+static char *look_for_named_theme(const char *, const char *, gboolean);
+
+/* Ajoute les définitions CSS à partir d'un chemin donné. */
+static void load_css_partial_content(char **, const char *, gboolean);
+
+/* Etend le thème courant de GTK. */
+static void activate_css_content(GdkScreen *, const char *);
 
 
 /* Répertoires de recherche */
@@ -82,6 +89,7 @@ bool load_extra_gtk_theme(void)
     GdkScreen *screen;                      /* Ecran(s) concerné(s)        */
     GtkSettings *settings;                  /* Propriétés du système       */
     gboolean dark;                          /* Envie d'un thème sombre ?   */
+    char *content;                          /* Définitions CSS à charger   */
 
     result = false;
 
@@ -94,11 +102,16 @@ bool load_extra_gtk_theme(void)
 
     g_object_get(settings, "gtk-application-prefer-dark-theme", &dark, NULL);
 
-    if (dark)
-        result = browse_themes_directories(screen, name, true);
+    content = browse_themes_directories(name, dark);
 
-    if (!result)
-        result = browse_themes_directories(screen, name, false);
+    if (content != NULL)
+    {
+        activate_css_content(screen, content);
+        free(content);
+
+        result = true;
+
+    }
 
  legt_done:
 
@@ -109,26 +122,25 @@ bool load_extra_gtk_theme(void)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : screen  = écran concerné par les éventuels chargements.      *
-*                name    = nom du thème recherché, et donc de son répertoire. *
+*  Paramètres  : name    = nom du thème recherché, et donc de son répertoire. *
 *                dark    = indique une préférence pour la variante foncée.    *
 *                                                                             *
 *  Description : Parcourt tous les répertoires connus pour trouver un thème.  *
 *                                                                             *
-*  Retour      : true si un élément de thème a pu être chargé, false sinon.   *
+*  Retour      : Contenu CSS chargé ou NULL si aucun.                         *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static bool browse_themes_directories(GdkScreen *screen, const char *name, gboolean dark)
+static char *browse_themes_directories(const char *name, gboolean dark)
 {
-    bool result;                            /* Bilan à faire remonter      */
+    char *result;                           /* Défintions CSS à renvoyer   */
     char *suffix;                           /* Fin du répertoire personnel */
     char *owndir;                           /* Thèmes personnels ?         */
     const char **iter;                      /* Boucle de parcours          */
 
-    result = false;
+    result = NULL;
 
     /* Répertoire de l'utilisateur en premier ! */
 
@@ -142,7 +154,7 @@ static bool browse_themes_directories(GdkScreen *screen, const char *name, gbool
 
     if (owndir != NULL)
     {
-        result = look_for_named_theme(screen, owndir, name, dark);
+        result = look_for_named_theme(owndir, name, dark);
 
         free(owndir);
 
@@ -150,8 +162,8 @@ static bool browse_themes_directories(GdkScreen *screen, const char *name, gbool
 
     /* Parcours des autres répertoires classiques au besoin */
 
-    for (iter = _themes_directories; *iter != NULL && !result; iter++)
-        result = look_for_named_theme(screen, *iter, name, dark);
+    for (iter = _themes_directories; *iter != NULL && result == NULL; iter++)
+        result = look_for_named_theme(*iter, name, dark);
 
     return result;
 
@@ -160,35 +172,30 @@ static bool browse_themes_directories(GdkScreen *screen, const char *name, gbool
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : screen  = écran concerné par les éventuels chargements.      *
-*                dirname = chemin du répertoire où effectuer des recherches.  *
+*  Paramètres  : dirname = chemin du répertoire où effectuer des recherches.  *
 *                name    = nom du thème recherché, et donc de son répertoire. *
 *                dark    = indique une préférence pour la variante foncée.    *
 *                                                                             *
 *  Description : Parcourt un répertoire donné à la recherche d'un thème.      *
 *                                                                             *
-*  Retour      : true si un élément de thème a pu être chargé, false sinon.   *
+*  Retour      : Contenu CSS chargé ou NULL si aucun.                         *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static bool look_for_named_theme(GdkScreen *screen, const char *dirname, const char *name, gboolean dark)
+static char *look_for_named_theme(const char *dirname, const char *name, gboolean dark)
 {
-    bool result;                            /* Bilan à faire remonter      */
+    char *result;                           /* Défintions CSS à renvoyer   */
     char *path;                             /* Chemin d'accès à essayer    */
     int ret;                                /* Bilan d'un appel            */
     int dirfd;                              /* Canal de lecture            */
     struct dirent **namelist;               /* Liste des trouvailles       */
-    char *css_content;                      /* Contenu de style cumulé     */
     int count;                              /* Nombre de fichiers trouvés  */
     int i;                                  /* Boucle de parcours          */
     char *filename;                         /* Chemin d'accès constitué    */
-    GtkCssProvider *provider;               /* Nouveau fournisseur CSS     */
-    GError *error;                          /* Relevé d'éventuelles erreurs*/
-    char *content;                          /* Contenu d'une feuille       */
 
-    result = false;
+    result = NULL;
 
     ret = asprintf(&path, "%s" G_DIR_SEPARATOR_S "%s", dirname, name);
     if (ret == -1) goto lfnt_done;
@@ -196,13 +203,6 @@ static bool look_for_named_theme(GdkScreen *screen, const char *dirname, const c
     dirfd = open(path, O_RDONLY | O_DIRECTORY);
     if (dirfd == -1) goto lfnt_not_found;
 
-    int keep_dark_css_only(const struct dirent *entry)
-    {
-        return (entry->d_type == DT_REG
-                && endswith(entry->d_name, "-dark.css") ? 1 : 0);
-
-    }
-
     int keep_css_only(const struct dirent *entry)
     {
         return (entry->d_type == DT_REG
@@ -211,83 +211,160 @@ static bool look_for_named_theme(GdkScreen *screen, const char *dirname, const c
 
     }
 
-    css_content = NULL;
-
-    count = scandirat(dirfd, ".", &namelist, dark ? keep_dark_css_only : keep_css_only, alphasort);
+    count = scandirat(dirfd, ".", &namelist, keep_css_only, alphasort);
 
     for (i = 0; i < count; i++)
     {
         ret = asprintf(&filename, "%s%s%s", path, G_DIR_SEPARATOR_S, namelist[i]->d_name);
         if (ret == -1) continue;
 
+        load_css_partial_content(&result, filename, dark);
+
+        free(filename);
+
+    }
+
+    if (count > 0)
+        free(namelist);
+
+    close(dirfd);
+
+ lfnt_not_found:
+
+    free(path);
+
+ lfnt_done:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : content = définitions CSS à compléter. [OUT]                 *
+*                path    = chemin vers la nouvelle définition à ajouter.      *
+*                dark    = indique une préférence pour la variante foncée.    *
+*                                                                             *
+*  Description : Ajoute les définitions CSS à partir d'un chemin donné.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void load_css_partial_content(char **content, const char *path, gboolean dark)
+{
+    bool got_it;                            /* Version sombre présente ?   */
+    char *dark_path;                        /* Version sombre du chemin    */
+    GtkCssProvider *provider;               /* Nouveau fournisseur CSS     */
+    GError *error;                          /* Relevé d'éventuelles erreurs*/
+    char *extra;                            /* Contenu d'une feuille       */
+
+    got_it = false;
+
+    if (dark)
+    {
+        dark_path = strdup(path);
+        dark_path = strrpl(dark_path, ".css", "-dark.css");
+
         provider = gtk_css_provider_new();
 
         error = NULL;
 
-        gtk_css_provider_load_from_path(provider, filename, &error);
+        gtk_css_provider_load_from_path(provider, dark_path, &error);
 
         if (error == NULL)
         {
-            log_variadic_message(LMT_INFO, _("Loaded CSS definitions from '%s'"), filename);
+            log_variadic_message(LMT_INFO, _("Loaded CSS definitions from '%s'"), dark_path);
+
+            extra = gtk_css_provider_to_string(provider);
 
-            content = gtk_css_provider_to_string(provider);
+            *content = stradd(*content, extra);
 
-            css_content = stradd(css_content, content);
+            free(extra);
 
-            free(content);
+            got_it = true;
 
         }
         else
-        {
-            log_variadic_message(LMT_ERROR, _("Failed to load CSS definitions from '%s'"), filename);
             g_error_free(error);
-        }
 
         g_object_unref(G_OBJECT(provider));
 
-        free(filename);
-
     }
 
-    if (count > 0)
-        free(namelist);
-
-    close(dirfd);
-
-    if (css_content != NULL)
+    if (!got_it)
     {
         provider = gtk_css_provider_new();
 
         error = NULL;
 
-        gtk_css_provider_load_from_data(provider, css_content, -1, &error);
+        gtk_css_provider_load_from_path(provider, path, &error);
 
         if (error == NULL)
         {
-            gtk_style_context_add_provider_for_screen(screen, GTK_STYLE_PROVIDER(provider),
-                                                      GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+            log_variadic_message(LMT_INFO, _("Loaded CSS definitions from '%s'"), path);
+
+            extra = gtk_css_provider_to_string(provider);
+
+            *content = stradd(*content, extra);
 
-            result = true;
+            free(extra);
 
         }
         else
         {
-            log_variadic_message(LMT_ERROR, _("Failed to load CSS definitions"));
+            log_variadic_message(LMT_ERROR, _("Failed to load CSS definitions from '%s'"), path);
             g_error_free(error);
         }
 
-        free(css_content);
-
         g_object_unref(G_OBJECT(provider));
 
     }
 
- lfnt_not_found:
+}
 
-    free(path);
 
- lfnt_done:
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : screen  = écran concerné par les éventuels chargements.      *
+*                content = contenu CSS reconstitué à charger.                 *
+*                                                                             *
+*  Description : Etend le thème courant de GTK.                               *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-    return result;
+static void activate_css_content(GdkScreen *screen, const char *content)
+{
+    GtkCssProvider *provider;               /* Nouveau fournisseur CSS     */
+    GError *error;                          /* Relevé d'éventuelles erreurs*/
+
+    provider = gtk_css_provider_new();
+
+    error = NULL;
+
+    gtk_css_provider_load_from_data(provider, content, -1, &error);
+
+    if (error == NULL)
+    {
+        gtk_style_context_add_provider_for_screen(screen, GTK_STYLE_PROVIDER(provider),
+                                                  GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+    }
+    else
+    {
+        assert(false);
+
+        log_variadic_message(LMT_ERROR, _("Failed to load the global CSS extra definition"));
+        g_error_free(error);
+
+    }
+
+    g_object_unref(G_OBJECT(provider));
 
 }
-- 
cgit v0.11.2-87-g4458