gimpmoduledb.c 13.8 KB
Newer Older
1 2
/* LIBGIMP - The GIMP Library
 * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
Michael Natterer's avatar
Michael Natterer committed
3
 *
4
 * This library is free software: you can redistribute it and/or
5 6
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
7
 * version 3 of the License, or (at your option) any later version.
Michael Natterer's avatar
Michael Natterer committed
8
 *
9
 * This library is distributed in the hope that it will be useful,
Michael Natterer's avatar
Michael Natterer committed
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
Michael Natterer's avatar
Michael Natterer committed
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15 16
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
Michael Natterer's avatar
Michael Natterer committed
17 18 19 20 21
 */

#include "config.h"

#include <string.h>
22

23
#include <gio/gio.h>
Michael Natterer's avatar
Michael Natterer committed
24 25

#include "libgimpbase/gimpbase.h"
26
#include "libgimpconfig/gimpconfig.h"
Michael Natterer's avatar
Michael Natterer committed
27

28
#include "gimpmoduletypes.h"
Michael Natterer's avatar
Michael Natterer committed
29

30 31
#include "gimpmodule.h"
#include "gimpmoduledb.h"
Michael Natterer's avatar
Michael Natterer committed
32 33


34 35 36 37 38 39 40 41 42 43
/**
 * SECTION: gimpmoduledb
 * @title: GimpModuleDB
 * @short_description: Keeps a list of #GimpModule's found in a given
 *                     searchpath.
 *
 * Keeps a list of #GimpModule's found in a given searchpath.
 **/


44 45 46 47 48 49 50 51 52
enum
{
  ADD,
  REMOVE,
  MODULE_MODIFIED,
  LAST_SIGNAL
};


53
#define DUMP_DB FALSE
54 55


56 57
static void         gimp_module_db_finalize            (GObject      *object);

58 59 60 61
static void         gimp_module_db_load_directory      (GimpModuleDB *db,
                                                        GFile        *directory);
static void         gimp_module_db_load_module         (GimpModuleDB *db,
                                                        GFile        *file);
Michael Natterer's avatar
Michael Natterer committed
62

63 64
static GimpModule * gimp_module_db_module_find_by_path (GimpModuleDB *db,
                                                        const char   *fullpath);
Michael Natterer's avatar
Michael Natterer committed
65

66
static void         gimp_module_db_module_dump_func    (gpointer      data,
67
                                                        gpointer      user_data);
68
static void         gimp_module_db_module_on_disk_func (gpointer      data,
69
                                                        gpointer      user_data);
70
static void         gimp_module_db_module_remove_func  (gpointer      data,
71
                                                        gpointer      user_data);
72

73 74
static void         gimp_module_db_module_modified     (GimpModule   *module,
                                                        GimpModuleDB *db);
Michael Natterer's avatar
Michael Natterer committed
75 76


77
G_DEFINE_TYPE (GimpModuleDB, gimp_module_db, G_TYPE_OBJECT)
78

79
#define parent_class gimp_module_db_parent_class
80

81
static guint db_signals[LAST_SIGNAL] = { 0 };
82

Michael Natterer's avatar
Michael Natterer committed
83

84 85 86
static void
gimp_module_db_class_init (GimpModuleDBClass *klass)
{
87
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
88 89 90

  db_signals[ADD] =
    g_signal_new ("add",
91 92 93 94 95 96
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GimpModuleDBClass, add),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__OBJECT,
                  G_TYPE_NONE, 1,
97 98 99 100
                  GIMP_TYPE_MODULE);

  db_signals[REMOVE] =
    g_signal_new ("remove",
101 102 103 104 105 106
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GimpModuleDBClass, remove),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__OBJECT,
                  G_TYPE_NONE, 1,
107 108 109
                  GIMP_TYPE_MODULE);

  db_signals[MODULE_MODIFIED] =
110
    g_signal_new ("module-modified",
111 112 113 114 115 116
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GimpModuleDBClass, module_modified),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__OBJECT,
                  G_TYPE_NONE, 1,
117 118 119 120 121 122 123 124 125 126
                  GIMP_TYPE_MODULE);

  object_class->finalize = gimp_module_db_finalize;

  klass->add             = NULL;
  klass->remove          = NULL;
}

static void
gimp_module_db_init (GimpModuleDB *db)
Michael Natterer's avatar
Michael Natterer committed
127
{
128 129 130 131
  db->modules      = NULL;
  db->load_inhibit = NULL;
  db->verbose      = FALSE;
}
Michael Natterer's avatar
Michael Natterer committed
132

133 134 135
static void
gimp_module_db_finalize (GObject *object)
{
136
  GimpModuleDB *db = GIMP_MODULE_DB (object);
137 138 139

  if (db->modules)
    {
140 141 142 143 144 145 146 147 148
      GList *list;

      for (list = db->modules; list; list = g_list_next (list))
        {
          g_signal_handlers_disconnect_by_func (list->data,
                                                gimp_module_db_module_modified,
                                                db);
        }

149 150 151 152 153
      g_list_free (db->modules);
      db->modules = NULL;
    }

  if (db->load_inhibit)
Michael Natterer's avatar
Michael Natterer committed
154
    {
155 156
      g_free (db->load_inhibit);
      db->load_inhibit = NULL;
Michael Natterer's avatar
Michael Natterer committed
157
    }
158 159

  G_OBJECT_CLASS (parent_class)->finalize (object);
Michael Natterer's avatar
Michael Natterer committed
160 161
}

162 163
/**
 * gimp_module_db_new:
164
 * @verbose: Pass %TRUE to enable debugging output.
165
 *
166 167
 * Creates a new #GimpModuleDB instance. The @verbose parameter will be
 * passed to the created #GimpModule instances using gimp_module_new().
168
 *
169 170
 * Return value: The new #GimpModuleDB instance.
 **/
171 172
GimpModuleDB *
gimp_module_db_new (gboolean verbose)
Michael Natterer's avatar
Michael Natterer committed
173
{
174
  GimpModuleDB *db;
Michael Natterer's avatar
Michael Natterer committed
175

176
  db = g_object_new (GIMP_TYPE_MODULE_DB, NULL);
Michael Natterer's avatar
Michael Natterer committed
177

178
  db->verbose = verbose ? TRUE : FALSE;
Michael Natterer's avatar
Michael Natterer committed
179

180 181
  return db;
}
Michael Natterer's avatar
Michael Natterer committed
182

183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
static gboolean
is_in_inhibit_list (const gchar *filename,
                    const gchar *inhibit_list)
{
  gchar       *p;
  gint         pathlen;
  const gchar *start;
  const gchar *end;

  if (! inhibit_list || ! strlen (inhibit_list))
    return FALSE;

  p = strstr (inhibit_list, filename);
  if (!p)
    return FALSE;

  /* we have a substring, but check for colons either side */
  start = p;
  while (start != inhibit_list && *start != G_SEARCHPATH_SEPARATOR)
    start--;

  if (*start == G_SEARCHPATH_SEPARATOR)
    start++;

  end = strchr (p, G_SEARCHPATH_SEPARATOR);
  if (! end)
    end = inhibit_list + strlen (inhibit_list);

  pathlen = strlen (filename);

  if ((end - start) == pathlen)
    return TRUE;

  return FALSE;
Michael Natterer's avatar
Michael Natterer committed
217 218
}

219 220 221 222 223
/**
 * gimp_module_db_set_load_inhibit:
 * @db:           A #GimpModuleDB.
 * @load_inhibit: A #G_SEARCHPATH_SEPARATOR delimited list of module
 *                filenames to exclude from auto-loading.
224
 *
225 226 227
 * Sets the @load_inhibit flag for all #GimpModule's which are kept
 * by @db (using gimp_module_set_load_inhibit()).
 **/
Michael Natterer's avatar
Michael Natterer committed
228
void
229 230
gimp_module_db_set_load_inhibit (GimpModuleDB *db,
                                 const gchar  *load_inhibit)
Michael Natterer's avatar
Michael Natterer committed
231
{
232
  GList *list;
233 234 235 236 237 238 239

  g_return_if_fail (GIMP_IS_MODULE_DB (db));

  if (db->load_inhibit)
    g_free (db->load_inhibit);

  db->load_inhibit = g_strdup (load_inhibit);
Michael Natterer's avatar
Michael Natterer committed
240

241
  for (list = db->modules; list; list = g_list_next (list))
Michael Natterer's avatar
Michael Natterer committed
242
    {
243
      GimpModule *module = list->data;
244 245 246 247

      gimp_module_set_load_inhibit (module,
                                    is_in_inhibit_list (module->filename,
                                                        load_inhibit));
Michael Natterer's avatar
Michael Natterer committed
248 249 250
    }
}

251 252 253
/**
 * gimp_module_db_get_load_inhibit:
 * @db: A #GimpModuleDB.
254
 *
255
 * Return the #G_SEARCHPATH_SEPARATOR delimited list of module filenames
256
 * which are excluded from auto-loading.
257
 *
258 259
 * Return value: the @db's @load_inhibit string.
 **/
260 261 262 263 264 265 266 267
const gchar *
gimp_module_db_get_load_inhibit (GimpModuleDB *db)
{
  g_return_val_if_fail (GIMP_IS_MODULE_DB (db), NULL);

  return db->load_inhibit;
}

268 269 270 271 272
/**
 * gimp_module_db_load:
 * @db:          A #GimpModuleDB.
 * @module_path: A #G_SEARCHPATH_SEPARATOR delimited list of directories
 *               to load modules from.
273
 *
274 275 276
 * Scans the directories contained in @module_path and creates a
 * #GimpModule instance for every loadable module contained in the
 * directories.
277
 **/
278 279 280 281 282 283 284 285
void
gimp_module_db_load (GimpModuleDB *db,
                     const gchar  *module_path)
{
  g_return_if_fail (GIMP_IS_MODULE_DB (db));
  g_return_if_fail (module_path != NULL);

  if (g_module_supported ())
286 287 288 289 290 291 292 293 294 295 296 297 298
    {
      GList *path;
      GList *list;

      path = gimp_config_path_expand_to_files (module_path, NULL);

      for (list = path; list; list = g_list_next (list))
        {
          gimp_module_db_load_directory (db, list->data);
        }

      g_list_free_full (path, (GDestroyNotify) g_object_unref);
    }
299

300 301
  if (DUMP_DB)
    g_list_foreach (db->modules, gimp_module_db_module_dump_func, NULL);
302 303
}

304 305 306 307 308
/**
 * gimp_module_db_refresh:
 * @db:          A #GimpModuleDB.
 * @module_path: A #G_SEARCHPATH_SEPARATOR delimited list of directories
 *               to load modules from.
309
 *
310 311 312 313 314 315 316
 * Does the same as gimp_module_db_load(), plus removes all #GimpModule
 * instances whose modules have been deleted from disk.
 *
 * Note that the #GimpModule's will just be removed from the internal
 * list and not freed as this is not possible with #GTypeModule
 * instances which actually implement types.
 **/
Michael Natterer's avatar
Michael Natterer committed
317
void
318 319
gimp_module_db_refresh (GimpModuleDB *db,
                        const gchar  *module_path)
Michael Natterer's avatar
Michael Natterer committed
320 321 322
{
  GList *kill_list = NULL;

323 324
  g_return_if_fail (GIMP_IS_MODULE_DB (db));
  g_return_if_fail (module_path != NULL);
Michael Natterer's avatar
Michael Natterer committed
325 326

  /* remove modules we don't have on disk anymore */
327 328 329
  g_list_foreach (db->modules,
                  gimp_module_db_module_on_disk_func,
                  &kill_list);
Michael Natterer's avatar
Michael Natterer committed
330
  g_list_foreach (kill_list,
331 332
                  gimp_module_db_module_remove_func,
                  db);
Michael Natterer's avatar
Michael Natterer committed
333 334 335
  g_list_free (kill_list);

  /* walk filesystem and add new things we find */
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
  gimp_module_db_load (db, module_path);
}

static void
gimp_module_db_load_directory (GimpModuleDB *db,
                               GFile        *directory)
{
  GFileEnumerator *enumerator;

  enumerator = g_file_enumerate_children (directory,
                                          G_FILE_ATTRIBUTE_STANDARD_NAME ","
                                          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)))
        {
          GFileType file_type = g_file_info_get_file_type (info);

         if (file_type == G_FILE_TYPE_REGULAR &&
             ! g_file_info_get_is_hidden (info))
            {
              GFile *child = g_file_enumerator_get_child (enumerator, info);

              gimp_module_db_load_module (db, child);

              g_object_unref (child);
            }

          g_object_unref (info);
        }

      g_object_unref (enumerator);
    }
Michael Natterer's avatar
Michael Natterer committed
375 376 377
}

static void
378 379
gimp_module_db_load_module (GimpModuleDB *db,
                            GFile        *file)
Michael Natterer's avatar
Michael Natterer committed
380
{
381 382 383
  GimpModule *module;
  gchar      *path;
  gboolean    load_inhibit;
Michael Natterer's avatar
Michael Natterer committed
384

385 386
  if (! gimp_file_has_extension (file, "." G_MODULE_SUFFIX))
    return;
387

388
  path = g_file_get_path (file);
Michael Natterer's avatar
Michael Natterer committed
389 390

  /* don't load if we already know about it */
391 392 393 394 395
  if (gimp_module_db_module_find_by_path (db, path))
    {
      g_free (path);
      return;
    }
Michael Natterer's avatar
Michael Natterer committed
396

397
  load_inhibit = is_in_inhibit_list (path, db->load_inhibit);
398

399
  module = gimp_module_new (path,
400 401
                            load_inhibit,
                            db->verbose);
Michael Natterer's avatar
Michael Natterer committed
402

403 404
  g_free (path);

405
  g_signal_connect (module, "modified",
406 407 408 409
                    G_CALLBACK (gimp_module_db_module_modified),
                    db);

  db->modules = g_list_append (db->modules, module);
410

411
  g_signal_emit (db, db_signals[ADD], 0, module);
Michael Natterer's avatar
Michael Natterer committed
412 413
}

414
static GimpModule *
415 416
gimp_module_db_module_find_by_path (GimpModuleDB *db,
                                    const char   *fullpath)
Michael Natterer's avatar
Michael Natterer committed
417
{
418
  GList *list;
Michael Natterer's avatar
Michael Natterer committed
419

420
  for (list = db->modules; list; list = g_list_next (list))
421
    {
422
      GimpModule *module = list->data;
Michael Natterer's avatar
Michael Natterer committed
423

424 425
      if (! strcmp (module->filename, fullpath))
        return module;
426
    }
Michael Natterer's avatar
Michael Natterer committed
427

428
  return NULL;
Michael Natterer's avatar
Michael Natterer committed
429 430 431
}

static void
432 433
gimp_module_db_module_dump_func (gpointer data,
                                 gpointer user_data)
Michael Natterer's avatar
Michael Natterer committed
434
{
435
  GimpModule *module = data;
Michael Natterer's avatar
Michael Natterer committed
436

437
  g_print ("\n%s: %s\n",
438
           gimp_filename_to_utf8 (module->filename),
439
           gimp_module_state_name (module->state));
440

441
  g_print ("  module: %p  lasterr: %s  query: %p register: %p\n",
442
           module->module,
443
           module->last_module_error ? module->last_module_error : "NONE",
444 445
           module->query_module,
           module->register_module);
446

447
  if (module->info)
448 449 450 451 452 453
    {
      g_print ("  purpose:   %s\n"
               "  author:    %s\n"
               "  version:   %s\n"
               "  copyright: %s\n"
               "  date:      %s\n",
454 455 456 457 458
               module->info->purpose   ? module->info->purpose   : "NONE",
               module->info->author    ? module->info->author    : "NONE",
               module->info->version   ? module->info->version   : "NONE",
               module->info->copyright ? module->info->copyright : "NONE",
               module->info->date      ? module->info->date      : "NONE");
459
    }
Michael Natterer's avatar
Michael Natterer committed
460 461 462
}

static void
463
gimp_module_db_module_on_disk_func (gpointer data,
464
                                    gpointer user_data)
Michael Natterer's avatar
Michael Natterer committed
465
{
466 467 468
  GimpModule  *module    = data;
  GList      **kill_list = user_data;
  gboolean     old_on_disk;
Michael Natterer's avatar
Michael Natterer committed
469

470
  old_on_disk = module->on_disk;
Michael Natterer's avatar
Michael Natterer committed
471

472
  module->on_disk = g_file_test (module->filename, G_FILE_TEST_IS_REGULAR);
Michael Natterer's avatar
Michael Natterer committed
473 474 475 476

  /* if it's not on the disk, and it isn't in memory, mark it to be
   * removed later.
   */
477
  if (! module->on_disk && ! module->module)
Michael Natterer's avatar
Michael Natterer committed
478
    {
479 480
      *kill_list = g_list_append (*kill_list, module);
      module = NULL;
Michael Natterer's avatar
Michael Natterer committed
481 482
    }

483 484
  if (module && module->on_disk != old_on_disk)
    gimp_module_modified (module);
Michael Natterer's avatar
Michael Natterer committed
485 486 487
}

static void
488
gimp_module_db_module_remove_func (gpointer data,
489
                                   gpointer user_data)
Michael Natterer's avatar
Michael Natterer committed
490
{
491 492
  GimpModule   *module = data;
  GimpModuleDB *db     = user_data;
Michael Natterer's avatar
Michael Natterer committed
493

494
  g_signal_handlers_disconnect_by_func (module,
495 496 497
                                        gimp_module_db_module_modified,
                                        db);

498 499
  db->modules = g_list_remove (db->modules, module);

500
  g_signal_emit (db, db_signals[REMOVE], 0, module);
501 502 503 504 505 506
}

static void
gimp_module_db_module_modified (GimpModule   *module,
                                GimpModuleDB *db)
{
507
  g_signal_emit (db, db_signals[MODULE_MODIFIED], 0, module);
Michael Natterer's avatar
Michael Natterer committed
508
}