themes.c 9.72 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program
2 3
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7 8 9 10 11 12 13 14
 * (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
15
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 17 18 19
 */

#include "config.h"

20
#include <stdlib.h>
21

22 23 24
#include <gtk/gtk.h>

#include "libgimpbase/gimpbase.h"
25
#include "libgimpconfig/gimpconfig.h"
26 27 28 29 30 31 32 33 34 35 36 37 38 39

#include "gui-types.h"

#include "config/gimpguiconfig.h"

#include "core/gimp.h"

#include "themes.h"

#include "gimp-intl.h"


/*  local function prototypes  */

40 41
static void   themes_apply_theme         (Gimp                   *gimp,
                                          const gchar            *theme_name);
42 43 44
static void   themes_list_themes_foreach (gpointer                key,
                                          gpointer                value,
                                          gpointer                data);
45 46
static gint   themes_name_compare        (const void             *p1,
                                          const void             *p2);
47 48 49
static void   themes_theme_change_notify (GimpGuiConfig          *config,
                                          GParamSpec             *pspec,
                                          Gimp                   *gimp);
50 51 52 53 54 55 56 57 58 59 60 61 62


/*  private variables  */

static GHashTable *themes_hash = NULL;


/*  public functions  */

void
themes_init (Gimp *gimp)
{
  GimpGuiConfig *config;
63
  gchar         *themerc;
64 65 66 67 68 69

  g_return_if_fail (GIMP_IS_GIMP (gimp));

  config = GIMP_GUI_CONFIG (gimp->config);

  themes_hash = g_hash_table_new_full (g_str_hash,
70 71
                                       g_str_equal,
                                       g_free,
72
                                       g_object_unref);
73 74 75

  if (config->theme_path)
    {
76 77
      GList *path;
      GList *list;
78

79
      path = gimp_config_path_expand_to_files (config->theme_path, NULL);
80

81 82 83 84 85 86 87
      for (list = path; list; list = g_list_next (list))
        {
          GFile           *dir = list->data;
          GFileEnumerator *enumerator;

          enumerator =
            g_file_enumerate_children (dir,
88
                                       G_FILE_ATTRIBUTE_STANDARD_NAME ","
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
                                       G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN ","
                                       G_FILE_ATTRIBUTE_STANDARD_TYPE,
                                       G_FILE_QUERY_INFO_NONE,
                                       NULL, NULL);

          if (enumerator)
            {
              GFileInfo *info;

              while ((info = g_file_enumerator_next_file (enumerator,
                                                          NULL, NULL)))
                {
                  if (! g_file_info_get_is_hidden (info) &&
                      g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
                    {
                      GFile       *file;
                      const gchar *name;
                      gchar       *basename;

                      file = g_file_enumerator_get_child (enumerator, info);
                      name = gimp_file_get_utf8_name (file);

                      basename = g_path_get_basename (name);

                      if (gimp->be_verbose)
                        g_print ("Adding theme '%s' (%s)\n",
                                 basename, name);

                      g_hash_table_insert (themes_hash, basename, file);
                    }

                  g_object_unref (info);
                }

              g_object_unref (enumerator);
            }
        }
126

127
      g_list_free_full (path, (GDestroyNotify) g_object_unref);
128 129
    }

130 131
  themes_apply_theme (gimp, config->theme);

132
  themerc = gimp_personal_rc_file ("themerc");
133
  gtk_rc_parse (themerc);
134 135
  g_free (themerc);

136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
  g_signal_connect (config, "notify::theme",
                    G_CALLBACK (themes_theme_change_notify),
                    gimp);
}

void
themes_exit (Gimp *gimp)
{
  g_return_if_fail (GIMP_IS_GIMP (gimp));

  if (themes_hash)
    {
      g_signal_handlers_disconnect_by_func (gimp->config,
                                            themes_theme_change_notify,
                                            gimp);

      g_hash_table_destroy (themes_hash);
      themes_hash = NULL;
    }
}

gchar **
themes_list_themes (Gimp *gimp,
                    gint *n_themes)
{

  g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
  g_return_val_if_fail (n_themes != NULL, NULL);

  *n_themes = g_hash_table_size (themes_hash);

  if (*n_themes > 0)
    {
      gchar **themes;
      gchar **index;

      themes = g_new0 (gchar *, *n_themes + 1);

      index = themes;

      g_hash_table_foreach (themes_hash, themes_list_themes_foreach, &index);

178 179
      qsort (themes, *n_themes, sizeof (gchar *), themes_name_compare);

180 181 182 183 184 185
      return themes;
    }

  return NULL;
}

186
GFile *
187 188 189 190 191 192
themes_get_theme_dir (Gimp        *gimp,
                      const gchar *theme_name)
{
  g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);

  if (! theme_name)
193
    theme_name = GIMP_CONFIG_DEFAULT_THEME;
194 195 196 197

  return g_hash_table_lookup (themes_hash, theme_name);
}

198
GFile *
199 200 201 202 203
themes_get_theme_file (Gimp        *gimp,
                       const gchar *first_component,
                       ...)
{
  GimpGuiConfig *gui_config;
204 205
  GFile         *file;
  const gchar   *component;
206 207 208 209 210
  va_list        args;

  g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
  g_return_val_if_fail (first_component != NULL, NULL);

211 212 213 214
  gui_config = GIMP_GUI_CONFIG (gimp->config);

  file      = g_object_ref (themes_get_theme_dir (gimp, gui_config->theme));
  component = first_component;
215 216 217

  va_start (args, first_component);

218
  do
219
    {
220 221
      GFile *tmp = g_file_get_child (file, component);
      g_object_unref (file);
222 223
      file = tmp;
    }
224
  while ((component = va_arg (args, gchar *)));
225 226 227

  va_end (args);

228 229 230
  if (! g_file_query_exists (file, NULL))
    {
      g_object_unref (file);
231

232 233
      file      = g_object_ref (themes_get_theme_dir (gimp, NULL));
      component = first_component;
234

235
      va_start (args, first_component);
236

237 238 239 240 241 242 243
      do
        {
          GFile *tmp = g_file_get_child (file, component);
          g_object_unref (file);
          file = tmp;
        }
      while ((component = va_arg (args, gchar *)));
244

245 246
      va_end (args);
    }
247

248
  return file;
249 250
}

251 252 253 254

/*  private functions  */

static void
255 256 257
themes_apply_theme (Gimp        *gimp,
                    const gchar *theme_name)
{
258 259 260
  GFile         *themerc;
  GOutputStream *output;
  GError        *error = NULL;
261 262 263

  g_return_if_fail (GIMP_IS_GIMP (gimp));

264
  themerc = gimp_directory_file ("themerc", NULL);
265

266
  if (gimp->be_verbose)
267
    g_print ("Writing '%s'\n", gimp_file_get_utf8_name (themerc));
268

269 270 271 272
  output = G_OUTPUT_STREAM (g_file_replace (themerc,
                                            NULL, FALSE, G_FILE_CREATE_NONE,
                                            NULL, &error));
  if (! output)
273
    {
274
      gimp_message_literal (gimp, NULL, GIMP_MESSAGE_ERROR, error->message);
275
      g_clear_error (&error);
276
    }
277 278
  else
    {
279 280 281 282 283 284
      GFile *theme_dir = themes_get_theme_dir (gimp, theme_name);
      GFile *gtkrc_theme;
      GFile *gtkrc_user;
      gchar *esc_gtkrc_theme;
      gchar *esc_gtkrc_user;
      gchar *tmp;
285 286 287

      if (theme_dir)
        {
288
          gtkrc_theme = g_file_get_child (theme_dir, "gtkrc");
289 290 291 292
        }
      else
        {
          /*  get the hardcoded default theme gtkrc  */
293
          gtkrc_theme = g_file_new_for_path (gimp_gtkrc ());
294 295
        }

296
      gtkrc_user = gimp_directory_file ("gtkrc", NULL);
297 298 299 300

      tmp = g_file_get_path (gtkrc_theme);
      esc_gtkrc_theme = g_strescape (tmp, NULL);
      g_free (tmp);
301

302 303 304
      tmp = g_file_get_path (gtkrc_user);
      esc_gtkrc_user = g_strescape (tmp, NULL);
      g_free (tmp);
305

306
      if (! g_output_stream_printf
307
            (output, NULL, NULL, &error,
308 309 310 311 312 313 314 315 316 317
             "# GIMP themerc\n"
             "#\n"
             "# This file is written on GIMP startup and on every theme change.\n"
             "# It is NOT supposed to be edited manually. Edit your personal\n"
             "# gtkrc file instead (%s).\n"
             "\n"
             "include \"%s\"\n"
             "include \"%s\"\n"
             "\n"
             "# end of themerc\n",
318
             gimp_file_get_utf8_name (gtkrc_user),
319
             esc_gtkrc_theme,
320 321
             esc_gtkrc_user) ||
          ! g_output_stream_close (output, NULL, &error))
322 323 324 325 326 327 328 329 330
        {
          gimp_message (gimp, NULL, GIMP_MESSAGE_ERROR,
                        _("Error writing '%s': %s"),
                        gimp_file_get_utf8_name (themerc), error->message);
          g_clear_error (&error);
        }

      g_free (esc_gtkrc_theme);
      g_free (esc_gtkrc_user);
331 332
      g_object_unref (gtkrc_theme);
      g_object_unref (gtkrc_user);
333 334
      g_object_unref (output);
    }
335

336
  g_object_unref (themerc);
337 338
}

339 340 341 342 343 344
static void
themes_list_themes_foreach (gpointer key,
                            gpointer value,
                            gpointer data)
{
  gchar ***index = data;
345

346 347
  **index = g_strdup ((gchar *) key);

348
  (*index)++;
349
}
350

351 352 353 354 355 356 357
static gint
themes_name_compare (const void *p1,
                     const void *p2)
{
  return strcmp (* (char **) p1, * (char **) p2);
}

358
static void
359 360 361
themes_theme_change_notify (GimpGuiConfig *config,
                            GParamSpec    *pspec,
                            Gimp          *gimp)
362
{
363
  themes_apply_theme (gimp, config->theme);
364

365
  gtk_rc_reparse_all ();
366
}