[gnome-todo] Rework themes support



commit 6ae24711730d907011952bcdec0def8278507ff4
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Sun May 3 18:11:29 2020 -0300

    Rework themes support
    
    Copy Builder's layout of a custom CSS provider, a
    theme manager watching for theme changes, and an
    application-level instance. Plugins also have their
    themes automatically loaded.

 src/engine/gtd-plugin-manager.c                |  16 ++
 src/gtd-application.c                          |  39 ++--
 src/gtd-css-provider.c                         | 307 +++++++++++++++++++++++++
 src/gtd-css-provider.h                         |  34 +++
 src/gtd-theme-manager.c                        | 187 +++++++++++++++
 src/gtd-theme-manager.h                        |  38 +++
 src/meson.build                                |   2 +
 src/{theme => themes}/Adwaita-omniarea.css     |   0
 src/{theme => themes}/Adwaita-tasklistview.css |   0
 src/{theme => themes}/Adwaita-taskrow.css      |   0
 src/{theme => themes}/Adwaita-widgets.css      |   8 +-
 src/{theme => themes}/Adwaita.css              |   8 +-
 src/todo.gresource.xml                         |  10 +-
 13 files changed, 618 insertions(+), 31 deletions(-)
---
diff --git a/src/engine/gtd-plugin-manager.c b/src/engine/gtd-plugin-manager.c
index e6d86c0..cac918b 100644
--- a/src/engine/gtd-plugin-manager.c
+++ b/src/engine/gtd-plugin-manager.c
@@ -23,6 +23,7 @@
 #include "interfaces/gtd-provider.h"
 #include "gtd-manager.h"
 #include "gtd-plugin-manager.h"
+#include "gtd-theme-manager.h"
 
 #include <libpeas/peas.h>
 
@@ -31,6 +32,7 @@ struct _GtdPluginManager
   GtdObject           parent;
 
   GHashTable         *info_to_extension;
+  GtdThemeManager    *theme_manager;
 };
 
 G_DEFINE_TYPE (GtdPluginManager, gtd_plugin_manager, GTD_TYPE_OBJECT)
@@ -129,6 +131,12 @@ on_plugin_unloaded_cb (PeasEngine       *engine,
                        GtdPluginManager *self)
 {
   GtdActivatable *activatable;
+  const gchar *data_dir;
+
+  data_dir = peas_plugin_info_get_data_dir (info);
+
+  if (g_str_has_prefix (data_dir, "resource://"))
+    gtd_theme_manager_remove_resources (self->theme_manager, data_dir);
 
   activatable = g_hash_table_lookup (self->info_to_extension, info);
 
@@ -152,6 +160,13 @@ on_plugin_loaded_cb (PeasEngine       *engine,
                      PeasPluginInfo   *info,
                      GtdPluginManager *self)
 {
+  const gchar *data_dir;
+
+  data_dir = peas_plugin_info_get_data_dir (info);
+
+  if (g_str_has_prefix (data_dir, "resource://"))
+    gtd_theme_manager_add_resources (self->theme_manager, data_dir);
+
   if (peas_engine_provides_extension (engine, info, GTD_TYPE_ACTIVATABLE))
     {
       GtdActivatable *activatable;
@@ -269,6 +284,7 @@ static void
 gtd_plugin_manager_init (GtdPluginManager *self)
 {
   self->info_to_extension = g_hash_table_new (g_direct_hash, g_direct_equal);
+  self->theme_manager = gtd_theme_manager_new ();
 
   gtd_object_push_loading (GTD_OBJECT (self));
 
diff --git a/src/gtd-application.c b/src/gtd-application.c
index cbd4954..a136e04 100644
--- a/src/gtd-application.c
+++ b/src/gtd-application.c
@@ -27,6 +27,7 @@
 #include "gtd-manager.h"
 #include "gtd-manager-protected.h"
 #include "gtd-plugin-dialog.h"
+#include "gtd-theme-manager.h"
 #include "gtd-vcs.h"
 #include "gtd-window.h"
 #include "gtd-window-private.h"
@@ -42,6 +43,8 @@ struct _GtdApplication
 {
   GtkApplication         application;
 
+  GtdThemeManager       *theme_manager;
+
   GtkWidget             *window;
   GtkWidget             *plugin_dialog;
   GtkWidget             *initial_setup;
@@ -217,6 +220,16 @@ run_initial_setup (GtdApplication *application)
 }
 */
 
+static void
+gtd_application_finalize (GObject *object)
+{
+  GtdApplication *self = (GtdApplication *)object;
+
+  g_clear_object (&self->theme_manager);
+
+  G_OBJECT_CLASS (gtd_application_parent_class)->finalize (object);
+}
+
 static void
 gtd_application_activate (GApplication *application)
 {
@@ -234,9 +247,6 @@ static void
 gtd_application_startup (GApplication *application)
 {
   GtdApplication *self;
-  g_autoptr (GtkCssProvider) css_provider;
-  g_autoptr (GFile) css_file;
-  g_autofree gchar *theme_name, *theme_uri;
 
   GTD_ENTRY;
 
@@ -250,25 +260,13 @@ gtd_application_startup (GApplication *application)
 
   G_APPLICATION_CLASS (gtd_application_parent_class)->startup (application);
 
+  /* CSS provider */
+  gtd_theme_manager_add_resources (self->theme_manager, "resource:///org/gnome/todo");
+
   /* window */
   gtk_window_set_default_icon_name (APPLICATION_ID);
   self->window = gtd_window_new (self);
 
-  /* CSS provider */
-  css_provider = gtk_css_provider_new ();
-  gtk_style_context_add_provider_for_display (gdk_display_get_default (),
-                                              GTK_STYLE_PROVIDER (css_provider),
-                                              GTK_STYLE_PROVIDER_PRIORITY_APPLICATION + 1);
-
-  g_object_get (gtk_settings_get_default (), "gtk-theme-name", &theme_name, NULL);
-  theme_uri = g_strconcat ("resource:///org/gnome/todo/theme/", theme_name, ".css", NULL);
-  css_file = g_file_new_for_uri (theme_uri);
-
-  if (g_file_query_exists (css_file, NULL))
-    gtk_css_provider_load_from_file (css_provider, css_file);
-  else
-    gtk_css_provider_load_from_resource (css_provider, "/org/gnome/todo/theme/Adwaita.css");
-
   /* plugin dialog */
   self->plugin_dialog = gtd_plugin_dialog_new ();
 
@@ -331,8 +329,11 @@ gtd_application_handle_local_options (GApplication *application,
 static void
 gtd_application_class_init (GtdApplicationClass *klass)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GApplicationClass *application_class = G_APPLICATION_CLASS (klass);
 
+  object_class->finalize = gtd_application_finalize;
+
   application_class->activate = gtd_application_activate;
   application_class->startup = gtd_application_startup;
   application_class->command_line = gtd_application_command_line;
@@ -343,5 +344,7 @@ gtd_application_class_init (GtdApplicationClass *klass)
 static void
 gtd_application_init (GtdApplication *self)
 {
+  self->theme_manager = gtd_theme_manager_new ();
+
   g_application_add_main_option_entries (G_APPLICATION (self), cmd_options);
 }
diff --git a/src/gtd-css-provider.c b/src/gtd-css-provider.c
new file mode 100644
index 0000000..8a358bd
--- /dev/null
+++ b/src/gtd-css-provider.c
@@ -0,0 +1,307 @@
+/* gtd-css-provider.c
+ *
+ * Copyright 2020 Georges Basile Stavracas Neto <georges stavracas gmail com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "GtdCssProvider"
+
+#include "gtd-css-provider.h"
+
+struct _GtdCssProvider
+{
+  GObject             parent_instance;
+
+  GtkCssProvider     *provider;
+  gchar              *base_path;
+  guint               queued_update;
+};
+
+G_DEFINE_TYPE (GtdCssProvider, gtd_css_provider, G_TYPE_OBJECT)
+
+enum
+{
+  PROP_0,
+  PROP_BASE_PATH,
+  N_PROPS,
+};
+
+static GParamSpec *properties [N_PROPS];
+
+static gboolean
+resource_exists (const gchar *resource_path)
+{
+  g_assert (resource_path != NULL);
+
+  if (g_str_has_prefix (resource_path, "resource://"))
+    {
+      gsize len = 0;
+      guint32 flags = 0;
+
+      resource_path += strlen ("resource://");
+
+      return g_resources_get_info (resource_path, G_RESOURCE_LOOKUP_FLAGS_NONE, &len, &flags, NULL);
+    }
+
+  return g_file_test (resource_path, G_FILE_TEST_IS_REGULAR);
+}
+
+static void
+load_resource (GtdCssProvider *self,
+               const gchar    *resource_path)
+{
+  g_assert (resource_path != NULL);
+
+  if (g_str_has_prefix (resource_path, "resource://"))
+    {
+      resource_path += strlen ("resource://");
+      gtk_css_provider_load_from_resource (self->provider, resource_path);
+    }
+  else
+    {
+      gtk_css_provider_load_from_path (self->provider, resource_path);
+    }
+
+}
+
+static void
+update_css_provider (GtdCssProvider *self)
+{
+  g_autofree gchar *theme_name = NULL;
+  g_autofree gchar *resource_path = NULL;
+  GtkSettings *settings;
+  gboolean prefer_dark_theme = FALSE;
+
+  settings = gtk_settings_get_default ();
+  theme_name = g_strdup (g_getenv ("GTK_THEME"));
+
+  if (theme_name != NULL)
+    {
+      char *p;
+
+      /* 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;
+        }
+    }
+  else
+    {
+      g_object_get (settings,
+                    "gtk-theme-name", &theme_name,
+                    "gtk-application-prefer-dark-theme", &prefer_dark_theme,
+                    NULL);
+    }
+
+  /* First check with full path to theme+variant */
+  resource_path = g_strdup_printf ("%s/%s%s.css",
+                                   self->base_path,
+                                   theme_name, prefer_dark_theme ? "-dark" : "");
+
+  if (!resource_exists (resource_path))
+    {
+      /* Now try without the theme variant */
+      g_free (resource_path);
+      resource_path = g_strdup_printf ("%s/%s.css", self->base_path, theme_name);
+
+      /* Now fallback to shared styling */
+      if (!resource_exists (resource_path))
+        {
+          g_free (resource_path);
+          resource_path = g_strdup_printf ("%s/shared.css", self->base_path);
+
+          if (!resource_exists (resource_path))
+            return;
+        }
+    }
+
+  g_debug ("Loading css overrides \"%s\"", resource_path);
+
+  load_resource (self, resource_path);
+}
+
+static gboolean
+do_update_cb (gpointer user_data)
+{
+  GtdCssProvider *self = user_data;
+
+  g_assert (GTD_IS_CSS_PROVIDER (self));
+
+  self->queued_update = 0;
+  update_css_provider (self);
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+dzl_css_provider_queue_update (GtdCssProvider *self)
+{
+  if (self->queued_update > 0)
+    return;
+
+
+  self->queued_update = g_idle_add_full (G_PRIORITY_LOW,
+                                         do_update_cb,
+                                         g_object_ref (self),
+                                         g_object_unref);
+}
+
+static void
+on_settings_notify_gtk_theme_name_cb (GtdCssProvider *self,
+                                      GParamSpec     *pspec,
+                                      GtkSettings    *settings)
+{
+  dzl_css_provider_queue_update (self);
+}
+
+static void
+on_settings_notify_gtk_application_prefer_dark_theme_cb (GtdCssProvider *self,
+                                                         GParamSpec     *pspec,
+                                                         GtkSettings    *settings)
+{
+  dzl_css_provider_queue_update (self);
+}
+
+static void
+gtd_css_provider_constructed (GObject *object)
+{
+  GtdCssProvider *self = (GtdCssProvider *)object;
+  GtkSettings *settings;
+
+  G_OBJECT_CLASS (gtd_css_provider_parent_class)->constructed (object);
+
+  settings = gtk_settings_get_default ();
+
+  g_signal_connect_object (settings,
+                           "notify::gtk-theme-name",
+                           G_CALLBACK (on_settings_notify_gtk_theme_name_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (settings,
+                           "notify::gtk-application-prefer-dark-theme",
+                           G_CALLBACK (on_settings_notify_gtk_application_prefer_dark_theme_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  update_css_provider (self);
+}
+
+static void
+gtd_css_provider_finalize (GObject *object)
+{
+  GtdCssProvider *self = (GtdCssProvider *)object;
+
+  g_clear_handle_id (&self->queued_update, g_source_remove);
+  g_clear_pointer (&self->base_path, g_free);
+  g_clear_object (&self->provider);
+
+  G_OBJECT_CLASS (gtd_css_provider_parent_class)->finalize (object);
+}
+
+static void
+gtd_css_provider_get_property (GObject    *object,
+                               guint       prop_id,
+                               GValue     *value,
+                               GParamSpec *pspec)
+{
+  GtdCssProvider *self = GTD_CSS_PROVIDER(object);
+
+  switch (prop_id)
+    {
+    case PROP_BASE_PATH:
+      g_value_set_string (value, self->base_path);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    }
+}
+
+static void
+gtd_css_provider_set_property (GObject      *object,
+                               guint         prop_id,
+                               const GValue *value,
+                               GParamSpec   *pspec)
+{
+  GtdCssProvider *self = GTD_CSS_PROVIDER(object);
+
+  switch (prop_id)
+    {
+    case PROP_BASE_PATH:
+      {
+        const gchar *str = g_value_get_string (value);
+        gsize len = str ? strlen (str) : 0;
+
+        /* Ignore trailing slash to simplify building paths */
+        if (str && len && str[len-1] == '/')
+          self->base_path = g_strndup (str, len - 1);
+        else
+          self->base_path = g_strdup (str);
+
+        break;
+      }
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    }
+}
+
+static void
+gtd_css_provider_class_init (GtdCssProviderClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->constructed = gtd_css_provider_constructed;
+  object_class->finalize = gtd_css_provider_finalize;
+  object_class->get_property = gtd_css_provider_get_property;
+  object_class->set_property = gtd_css_provider_set_property;
+
+  properties [PROP_BASE_PATH] =
+    g_param_spec_string ("base-path",
+                         "Base Path",
+                         "The base resource path to discover themes",
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+gtd_css_provider_init (GtdCssProvider *self)
+{
+  self->provider = gtk_css_provider_new ();
+}
+
+GtdCssProvider *
+gtd_css_provider_new (const gchar *base_path)
+{
+  return g_object_new (GTD_TYPE_CSS_PROVIDER,
+                       "base-path", base_path,
+                       NULL);
+}
+
+GtkCssProvider*
+gtd_css_provider_get_provider (GtdCssProvider *self)
+{
+  g_return_val_if_fail (GTD_IS_CSS_PROVIDER (self), NULL);
+
+  return self->provider;
+}
diff --git a/src/gtd-css-provider.h b/src/gtd-css-provider.h
new file mode 100644
index 0000000..2570b60
--- /dev/null
+++ b/src/gtd-css-provider.h
@@ -0,0 +1,34 @@
+/* gtd-css-provider.h
+ *
+ * Copyright 2020 Georges Basile Stavracas Neto <georges stavracas gmail com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTD_TYPE_CSS_PROVIDER (gtd_css_provider_get_type())
+G_DECLARE_FINAL_TYPE (GtdCssProvider, gtd_css_provider, GTD, CSS_PROVIDER, GObject)
+
+GtdCssProvider*      gtd_css_provider_new                        (const gchar        *base_path);
+
+GtkCssProvider*      gtd_css_provider_get_provider               (GtdCssProvider     *self);
+
+G_END_DECLS
diff --git a/src/gtd-theme-manager.c b/src/gtd-theme-manager.c
new file mode 100644
index 0000000..6f1006e
--- /dev/null
+++ b/src/gtd-theme-manager.c
@@ -0,0 +1,187 @@
+/* gtd-theme-manager.c
+ *
+ * Copyright 2020 Georges Basile Stavracas Neto <georges stavracas gmail com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "GtdThemeManager"
+
+#include "gtd-theme-manager.h"
+
+#include "gtd-css-provider.h"
+
+#include <gtk/gtk.h>
+
+struct _GtdThemeManager
+{
+  GObject             parent_instance;
+
+  GHashTable         *providers_by_path;
+};
+
+G_DEFINE_TYPE (GtdThemeManager, gtd_theme_manager, G_TYPE_OBJECT)
+
+
+/*
+ * Auxiliary methods
+ */
+
+static gboolean
+has_child_resources (const gchar *path)
+{
+  g_auto(GStrv) children = NULL;
+
+  if (g_str_has_prefix (path, "resource://"))
+    path += strlen ("resource://");
+
+  children = g_resources_enumerate_children (path, 0, NULL);
+
+  return children != NULL && children[0] != NULL;
+}
+
+
+/*
+ * GObject overrides
+ */
+
+static void
+gtd_theme_manager_finalize (GObject *object)
+{
+  GtdThemeManager *self = (GtdThemeManager *)object;
+
+  g_clear_pointer (&self->providers_by_path, g_hash_table_unref);
+
+  G_OBJECT_CLASS (gtd_theme_manager_parent_class)->finalize (object);
+}
+
+static void
+gtd_theme_manager_class_init (GtdThemeManagerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gtd_theme_manager_finalize;
+}
+
+static void
+gtd_theme_manager_init (GtdThemeManager *self)
+{
+  self->providers_by_path = g_hash_table_new_full (g_str_hash,
+                                                   g_str_equal,
+                                                   g_free,
+                                                   g_object_unref);
+}
+
+GtdThemeManager*
+gtd_theme_manager_new (void)
+{
+  return g_object_new (GTD_TYPE_THEME_MANAGER, NULL);
+}
+
+void
+gtd_theme_manager_add_resources (GtdThemeManager *self,
+                                 const gchar     *resource_path)
+{
+  g_autofree gchar *css_dir = NULL;
+  g_autofree gchar *icons_dir = NULL;
+  const gchar *real_path = resource_path;
+  GtkIconTheme *theme;
+
+  g_return_if_fail (GTD_IS_THEME_MANAGER (self));
+  g_return_if_fail (resource_path != NULL);
+
+  theme = gtk_icon_theme_get_for_display (gdk_display_get_default ());
+
+  if (g_str_has_prefix (real_path, "resource://"))
+    real_path += strlen ("resource://");
+
+  /*
+   * Create a CSS provider that will load the proper variant based on the
+   * current application theme, using @resource_path/css as the base directory
+   * to locate theming files.
+   */
+  css_dir = g_build_path ("/", resource_path, "themes/", NULL);
+
+  g_debug ("Including CSS overrides from %s", css_dir);
+
+  if (has_child_resources (css_dir))
+    {
+      GtdCssProvider *css_provider;
+      GtkCssProvider *provider;
+
+      css_provider = gtd_css_provider_new (css_dir);
+      provider = gtd_css_provider_get_provider (css_provider);
+
+      g_hash_table_insert (self->providers_by_path,
+                           g_strdup (resource_path),
+                           g_object_ref (css_provider));
+      gtk_style_context_add_provider_for_display (gdk_display_get_default (),
+                                                  GTK_STYLE_PROVIDER (provider),
+                                                  GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+    }
+
+  /*
+   * Add the icons sub-directory so that Gtk can locate the themed
+   * icons (svg, png, etc).
+   */
+  icons_dir = g_build_path ("/", real_path, "icons/", NULL);
+
+  g_debug ("Loading icon resources from %s", icons_dir);
+
+  if (!g_str_equal (real_path, resource_path))
+    {
+      g_auto (GStrv) children = NULL;
+
+      /* Okay, this is a resource-based path. Make sure the
+       * path contains children so we don't slow down the
+       * theme loading code with tons of useless directories.
+       */
+      children = g_resources_enumerate_children (icons_dir, 0, NULL);
+      if (children != NULL && children[0] != NULL)
+        gtk_icon_theme_add_resource_path (theme, icons_dir);
+    }
+  else
+    {
+      /* Make sure the directory exists so that we don't needlessly
+       * slow down the icon loading paths.
+       */
+      if (g_file_test (icons_dir, G_FILE_TEST_IS_DIR))
+        gtk_icon_theme_add_search_path (theme, icons_dir);
+    }
+}
+
+void
+gtd_theme_manager_remove_resources (GtdThemeManager *self,
+                                    const gchar     *resource_path)
+{
+  GtdCssProvider *css_provider;
+
+  g_return_if_fail (GTD_IS_THEME_MANAGER (self));
+  g_return_if_fail (resource_path != NULL);
+
+  css_provider = g_hash_table_lookup (self->providers_by_path, resource_path);
+
+  if (css_provider)
+    {
+      GtkCssProvider *provider = gtd_css_provider_get_provider (css_provider);
+
+      g_debug ("Removing CSS overrides from %s", resource_path);
+
+      gtk_style_context_remove_provider_for_display (gdk_display_get_default (),
+                                                     GTK_STYLE_PROVIDER (provider));
+      g_hash_table_remove (self->providers_by_path, resource_path);
+    }
+}
diff --git a/src/gtd-theme-manager.h b/src/gtd-theme-manager.h
new file mode 100644
index 0000000..7265f2f
--- /dev/null
+++ b/src/gtd-theme-manager.h
@@ -0,0 +1,38 @@
+/* gtd-theme-manager.h
+ *
+ * Copyright 2020 Georges Basile Stavracas Neto <georges stavracas gmail com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GTD_TYPE_THEME_MANAGER (gtd_theme_manager_get_type())
+G_DECLARE_FINAL_TYPE (GtdThemeManager, gtd_theme_manager, GTD, THEME_MANAGER, GObject)
+
+GtdThemeManager*     gtd_theme_manager_new                       (void);
+
+void                 gtd_theme_manager_add_resources             (GtdThemeManager    *self,
+                                                                  const gchar        *resource_path);
+
+void                 gtd_theme_manager_remove_resources          (GtdThemeManager    *self,
+                                                                  const gchar        *resource_path);
+
+G_END_DECLS
diff --git a/src/meson.build b/src/meson.build
index 13ec873..d18aff1 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -114,6 +114,7 @@ sources += files(
   'gtd-application.c',
   'gtd-initial-setup-window.c',
   'gtd-clock.c',
+  'gtd-css-provider.c',
   'gtd-object.c',
   'gtd-omni-area.c',
   'gtd-omni-area-addin.c',
@@ -123,6 +124,7 @@ sources += files(
   'gtd-task.c',
   'gtd-task-list.c',
   'gtd-text-width-layout.c',
+  'gtd-theme-manager.c',
   'gtd-utils.c',
   'gtd-window.c',
   'main.c'
diff --git a/src/theme/Adwaita-omniarea.css b/src/themes/Adwaita-omniarea.css
similarity index 100%
rename from src/theme/Adwaita-omniarea.css
rename to src/themes/Adwaita-omniarea.css
diff --git a/src/theme/Adwaita-tasklistview.css b/src/themes/Adwaita-tasklistview.css
similarity index 100%
rename from src/theme/Adwaita-tasklistview.css
rename to src/themes/Adwaita-tasklistview.css
diff --git a/src/theme/Adwaita-taskrow.css b/src/themes/Adwaita-taskrow.css
similarity index 100%
rename from src/theme/Adwaita-taskrow.css
rename to src/themes/Adwaita-taskrow.css
diff --git a/src/theme/Adwaita-widgets.css b/src/themes/Adwaita-widgets.css
similarity index 80%
rename from src/theme/Adwaita-widgets.css
rename to src/themes/Adwaita-widgets.css
index e608752..3f09c0f 100644
--- a/src/theme/Adwaita-widgets.css
+++ b/src/themes/Adwaita-widgets.css
@@ -1,10 +1,10 @@
 /* Star Widget */
 
 @keyframes wiggle {
-  12.5% { transform: rotate(15deg) }
-  37.5% { transform: rotate(-15deg) }
-  62.5% { transform: rotate(15deg) }
-  87.5% { transform: rotate(-15deg) }
+  12.5% { transform: rotate(15deg); }
+  37.5% { transform: rotate(-15deg); }
+  62.5% { transform: rotate(15deg); }
+  87.5% { transform: rotate(-15deg); }
 }
 
 star {
diff --git a/src/theme/Adwaita.css b/src/themes/Adwaita.css
similarity index 75%
rename from src/theme/Adwaita.css
rename to src/themes/Adwaita.css
index 938035d..c2d8c90 100644
--- a/src/theme/Adwaita.css
+++ b/src/themes/Adwaita.css
@@ -1,7 +1,7 @@
-@import url("resource:///org/gnome/todo/theme/Adwaita-omniarea.css");
-@import url("resource:///org/gnome/todo/theme/Adwaita-tasklistview.css");
-@import url("resource:///org/gnome/todo/theme/Adwaita-taskrow.css");
-@import url("resource:///org/gnome/todo/theme/Adwaita-widgets.css");
+@import url("resource:///org/gnome/todo/themes/Adwaita-omniarea.css");
+@import url("resource:///org/gnome/todo/themes/Adwaita-tasklistview.css");
+@import url("resource:///org/gnome/todo/themes/Adwaita-taskrow.css");
+@import url("resource:///org/gnome/todo/themes/Adwaita-widgets.css");
 
 .transparent {
     background-color: transparent;
diff --git a/src/todo.gresource.xml b/src/todo.gresource.xml
index 0f69c49..046ce38 100644
--- a/src/todo.gresource.xml
+++ b/src/todo.gresource.xml
@@ -20,10 +20,10 @@
   </gresource>
 
   <gresource prefix="/org/gnome/todo">
-    <file compressed="true">theme/Adwaita.css</file>
-    <file compressed="true">theme/Adwaita-omniarea.css</file>
-    <file compressed="true">theme/Adwaita-tasklistview.css</file>
-    <file compressed="true">theme/Adwaita-taskrow.css</file>
-    <file compressed="true">theme/Adwaita-widgets.css</file>
+    <file compressed="true">themes/Adwaita.css</file>
+    <file compressed="true">themes/Adwaita-omniarea.css</file>
+    <file compressed="true">themes/Adwaita-tasklistview.css</file>
+    <file compressed="true">themes/Adwaita-taskrow.css</file>
+    <file compressed="true">themes/Adwaita-widgets.css</file>
   </gresource>
 </gresources>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]