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

#include "config.h"

#include <string.h>

26
#include <gio/gio.h>
27

28 29
#include "libgimpbase/gimpbase.h"

30
#include "gimpmodule.h"
31

32
#include "libgimp/libgimp-intl.h"
33 34


35 36 37 38 39 40 41 42 43 44 45
/**
 * SECTION: gimpmodule
 * @title: GimpModule
 * @short_description: A #GTypeModule subclass which implements module
 *                     loading using #GModule.
 * @see_also: #GModule, #GTypeModule
 *
 * A #GTypeModule subclass which implements module loading using #GModule.
 **/


46 47 48 49 50 51 52
enum
{
  MODIFIED,
  LAST_SIGNAL
};


53
static void       gimp_module_finalize       (GObject     *object);
54

55 56
static gboolean   gimp_module_load           (GTypeModule *module);
static void       gimp_module_unload         (GTypeModule *module);
57

58 59 60 61
static gboolean   gimp_module_open           (GimpModule  *module);
static gboolean   gimp_module_close          (GimpModule  *module);
static void       gimp_module_set_last_error (GimpModule  *module,
                                              const gchar *error_str);
62

63

64
G_DEFINE_TYPE (GimpModule, gimp_module, G_TYPE_TYPE_MODULE)
65

66
#define parent_class gimp_module_parent_class
67

68
static guint module_signals[LAST_SIGNAL];
69 70 71


static void
72
gimp_module_class_init (GimpModuleClass *klass)
73
{
74 75
  GObjectClass     *object_class = G_OBJECT_CLASS (klass);
  GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (klass);
76

77
  module_signals[MODIFIED] =
78
    g_signal_new ("modified",
79 80 81 82 83 84
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GimpModuleClass, modified),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);
85

86
  object_class->finalize = gimp_module_finalize;
87

88 89
  module_class->load     = gimp_module_load;
  module_class->unload   = gimp_module_unload;
90

91
  klass->modified        = NULL;
92 93 94
}

static void
95
gimp_module_init (GimpModule *module)
96
{
97 98 99 100 101 102 103 104 105 106 107 108
  module->filename          = NULL;
  module->verbose           = FALSE;
  module->state             = GIMP_MODULE_STATE_ERROR;
  module->on_disk           = FALSE;
  module->load_inhibit      = FALSE;

  module->module            = NULL;
  module->info              = NULL;
  module->last_module_error = NULL;

  module->query_module      = NULL;
  module->register_module   = NULL;
109 110 111
}

static void
112
gimp_module_finalize (GObject *object)
113
{
114
  GimpModule *module = GIMP_MODULE (object);
115

116
  if (module->info)
117
    {
118 119
      gimp_module_info_free (module->info);
      module->info = NULL;
120 121
    }

122
  if (module->last_module_error)
123
    {
124 125 126 127 128 129 130 131
      g_free (module->last_module_error);
      module->last_module_error = NULL;
    }

  if (module->filename)
    {
      g_free (module->filename);
      module->filename = NULL;
132 133 134 135 136
    }

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

137
static gboolean
138
gimp_module_load (GTypeModule *module)
139
{
140
  GimpModule *gimp_module = GIMP_MODULE (module);
141
  gpointer    func;
142

143 144
  g_return_val_if_fail (gimp_module->filename != NULL, FALSE);
  g_return_val_if_fail (gimp_module->module == NULL, FALSE);
145

146
  if (gimp_module->verbose)
147 148
    g_print ("Loading module '%s'\n",
             gimp_filename_to_utf8 (gimp_module->filename));
149

150
  if (! gimp_module_open (gimp_module))
151
    return FALSE;
152

153
  if (! gimp_module_query_module (gimp_module))
154
    return FALSE;
155 156

  /* find the gimp_module_register symbol */
157
  if (! g_module_symbol (gimp_module->module, "gimp_module_register", &func))
158
    {
159
      gimp_module_set_last_error (gimp_module,
Sven Neumann's avatar
Sven Neumann committed
160
                                  "Missing gimp_module_register() symbol");
161

162 163 164
      g_message (_("Module '%s' load error: %s"),
                 gimp_filename_to_utf8 (gimp_module->filename),
                 gimp_module->last_module_error);
165 166 167 168

      gimp_module_close (gimp_module);

      gimp_module->state = GIMP_MODULE_STATE_ERROR;
169

170 171 172
      return FALSE;
    }

173
  gimp_module->register_module = func;
174

175 176 177 178 179
  if (! gimp_module->register_module (module))
    {
      gimp_module_set_last_error (gimp_module,
                                  "gimp_module_register() returned FALSE");

180 181 182
      g_message (_("Module '%s' load error: %s"),
                 gimp_filename_to_utf8 (gimp_module->filename),
                 gimp_module->last_module_error);
183

184
      gimp_module_close (gimp_module);
185

186
      gimp_module->state = GIMP_MODULE_STATE_LOAD_FAILED;
187

188 189 190
      return FALSE;
    }

191
  gimp_module->state = GIMP_MODULE_STATE_LOADED;
192

193
  return TRUE;
194 195 196
}

static void
197
gimp_module_unload (GTypeModule *module)
198
{
199
  GimpModule *gimp_module = GIMP_MODULE (module);
200

201
  g_return_if_fail (gimp_module->module != NULL);
202

203 204 205 206
  if (gimp_module->verbose)
    g_print ("Unloading module '%s'\n",
             gimp_filename_to_utf8 (gimp_module->filename));

207
  gimp_module_close (gimp_module);
208 209
}

210 211 212

/*  public functions  */

213 214 215
/**
 * gimp_module_new:
 * @filename:     The filename of a loadable module.
216 217
 * @load_inhibit: Pass %TRUE to exclude this module from auto-loading.
 * @verbose:      Pass %TRUE to enable debugging output.
218
 *
219
 * Creates a new #GimpModule instance.
220
 *
221 222
 * Return value: The new #GimpModule object.
 **/
223 224
GimpModule *
gimp_module_new (const gchar *filename,
225
                 gboolean     load_inhibit,
226
                 gboolean     verbose)
227
{
228
  GimpModule *module;
229 230 231

  g_return_val_if_fail (filename != NULL, NULL);

232
  module = g_object_new (GIMP_TYPE_MODULE, NULL);
233

234 235 236 237
  module->filename     = g_strdup (filename);
  module->load_inhibit = load_inhibit ? TRUE : FALSE;
  module->verbose      = verbose ? TRUE : FALSE;
  module->on_disk      = TRUE;
238

239
  if (! module->load_inhibit)
240
    {
241 242
      if (gimp_module_load (G_TYPE_MODULE (module)))
        gimp_module_unload (G_TYPE_MODULE (module));
243 244 245 246
    }
  else
    {
      if (verbose)
247 248
        g_print ("Skipping module '%s'\n",
                 gimp_filename_to_utf8 (filename));
249

250
      module->state = GIMP_MODULE_STATE_NOT_LOADED;
251 252
    }

253
  return module;
254 255
}

256 257 258
/**
 * gimp_module_query_module:
 * @module: A #GimpModule.
259
 *
260 261 262
 * Queries the module without actually registering any of the types it
 * may implement. After successful query, the @info field of the
 * #GimpModule struct will be available for further inspection.
263
 *
264
 * Return value: %TRUE on success.
265
 **/
266 267 268 269 270
gboolean
gimp_module_query_module (GimpModule *module)
{
  const GimpModuleInfo *info;
  gboolean              close_module = FALSE;
271
  gpointer              func;
272 273 274 275 276 277 278 279 280 281 282 283

  g_return_val_if_fail (GIMP_IS_MODULE (module), FALSE);

  if (! module->module)
    {
      if (! gimp_module_open (module))
        return FALSE;

      close_module = TRUE;
    }

  /* find the gimp_module_query symbol */
284
  if (! g_module_symbol (module->module, "gimp_module_query", &func))
285
    {
286 287
      gimp_module_set_last_error (module,
                                  "Missing gimp_module_query() symbol");
288

289 290 291
      g_message (_("Module '%s' load error: %s"),
                 gimp_filename_to_utf8 (module->filename),
                 module->last_module_error);
292 293

      gimp_module_close (module);
294 295

      module->state = GIMP_MODULE_STATE_ERROR;
296 297 298
      return FALSE;
    }

299
  module->query_module = func;
300 301 302 303 304 305 306 307 308

  if (module->info)
    {
      gimp_module_info_free (module->info);
      module->info = NULL;
    }

  info = module->query_module (G_TYPE_MODULE (module));

309
  if (! info || info->abi_version != GIMP_MODULE_ABI_VERSION)
310
    {
311 312 313 314
      gimp_module_set_last_error (module,
                                  info ?
                                  "module ABI version does not match" :
                                  "gimp_module_query() returned NULL");
315

316 317 318
      g_message (_("Module '%s' load error: %s"),
                 gimp_filename_to_utf8 (module->filename),
                 module->last_module_error);
319 320

      gimp_module_close (module);
321 322

      module->state = GIMP_MODULE_STATE_ERROR;
323 324 325 326 327 328 329 330 331 332 333
      return FALSE;
    }

  module->info = gimp_module_info_copy (info);

  if (close_module)
    return gimp_module_close (module);

  return TRUE;
}

334 335 336
/**
 * gimp_module_modified:
 * @module: A #GimpModule.
337
 *
338 339 340
 * Emits the "modified" signal. Call it whenever you have modified the module
 * manually (which you shouldn't do).
 **/
341
void
342
gimp_module_modified (GimpModule *module)
343
{
344
  g_return_if_fail (GIMP_IS_MODULE (module));
345

346
  g_signal_emit (module, module_signals[MODIFIED], 0);
347 348
}

349 350 351
/**
 * gimp_module_set_load_inhibit:
 * @module:       A #GimpModule.
352
 * @load_inhibit: Pass %TRUE to exclude this module from auto-loading.
353
 *
354 355
 * Sets the @load_inhibit property if the module. Emits "modified".
 **/
356
void
357 358
gimp_module_set_load_inhibit (GimpModule *module,
                              gboolean    load_inhibit)
359
{
360
  g_return_if_fail (GIMP_IS_MODULE (module));
361

362 363 364 365 366 367 368 369
  if (load_inhibit != module->load_inhibit)
    {
      module->load_inhibit = load_inhibit ? TRUE : FALSE;

      gimp_module_modified (module);
    }
}

370 371 372
/**
 * gimp_module_state_name:
 * @state: A #GimpModuleState.
373
 *
374 375
 * Returns the translated textual representation of a #GimpModuleState.
 * The returned string must not be freed.
376
 *
377 378
 * Return value: The @state's name.
 **/
379 380 381 382 383 384
const gchar *
gimp_module_state_name (GimpModuleState state)
{
  static const gchar * const statenames[] =
  {
    N_("Module error"),
385
    N_("Loaded"),
386
    N_("Load failed"),
387
    N_("Not loaded")
388 389 390
  };

  g_return_val_if_fail (state >= GIMP_MODULE_STATE_ERROR &&
391
                        state <= GIMP_MODULE_STATE_NOT_LOADED, NULL);
392 393 394

  return gettext (statenames[state]);
}
395

396 397 398 399 400 401 402
/**
 * gimp_module_error_quark:
 *
 * This function is never called directly. Use GIMP_MODULE_ERROR() instead.
 *
 * Return value: the #GQuark that defines the GIMP module error domain.
 *
403
 * Since: 2.8
404 405 406 407 408 409 410
 **/
GQuark
gimp_module_error_quark (void)
{
  return g_quark_from_static_string ("gimp-module-error-quark");
}

Michael Natterer's avatar
Michael Natterer committed
411 412 413

/*  private functions  */

414 415 416
static gboolean
gimp_module_open (GimpModule *module)
{
417
  module->module = g_module_open (module->filename, 0);
418

419 420 421 422
  if (! module->module)
    {
      module->state = GIMP_MODULE_STATE_ERROR;
      gimp_module_set_last_error (module, g_module_error ());
423

424 425 426
      g_message (_("Module '%s' load error: %s"),
                 gimp_filename_to_utf8 (module->filename),
                 module->last_module_error);
427

428 429 430 431 432 433 434 435 436 437 438 439 440
      return FALSE;
    }

  return TRUE;
}

static gboolean
gimp_module_close (GimpModule *module)
{
  g_module_close (module->module); /* FIXME: error handling */
  module->module          = NULL;
  module->query_module    = NULL;
  module->register_module = NULL;
441

442
  module->state = GIMP_MODULE_STATE_NOT_LOADED;
443

444
  return TRUE;
445 446 447
}

static void
448 449 450 451 452 453 454 455 456 457 458 459
gimp_module_set_last_error (GimpModule  *module,
                            const gchar *error_str)
{
  if (module->last_module_error)
    g_free (module->last_module_error);

  module->last_module_error = g_strdup (error_str);
}


/*  GimpModuleInfo functions  */

460 461 462 463 464 465 466 467
/**
 * gimp_module_info_new:
 * @abi_version: The #GIMP_MODULE_ABI_VERSION the module was compiled against.
 * @purpose:     The module's general purpose.
 * @author:      The module's author.
 * @version:     The module's version.
 * @copyright:   The module's copyright.
 * @date:        The module's release date.
468
 *
469
 * Creates a newly allocated #GimpModuleInfo struct.
470
 *
471 472
 * Return value: The new #GimpModuleInfo struct.
 **/
473
GimpModuleInfo *
474 475 476 477 478 479
gimp_module_info_new (guint32      abi_version,
                      const gchar *purpose,
                      const gchar *author,
                      const gchar *version,
                      const gchar *copyright,
                      const gchar *date)
480
{
481
  GimpModuleInfo *info = g_slice_new0 (GimpModuleInfo);
482

483 484 485 486 487 488
  info->abi_version = abi_version;
  info->purpose     = g_strdup (purpose);
  info->author      = g_strdup (author);
  info->version     = g_strdup (version);
  info->copyright   = g_strdup (copyright);
  info->date        = g_strdup (date);
489 490 491 492

  return info;
}

493 494 495
/**
 * gimp_module_info_copy:
 * @info: The #GimpModuleInfo struct to copy.
496
 *
497
 * Copies a #GimpModuleInfo struct.
498
 *
499 500
 * Return value: The new copy.
 **/
501 502 503 504 505
GimpModuleInfo *
gimp_module_info_copy (const GimpModuleInfo *info)
{
  g_return_val_if_fail (info != NULL, NULL);

506 507
  return gimp_module_info_new (info->abi_version,
                               info->purpose,
508 509 510 511 512 513
                               info->author,
                               info->version,
                               info->copyright,
                               info->date);
}

514 515 516
/**
 * gimp_module_info_free:
 * @info: The #GimpModuleInfo struct to free
517
 *
518 519
 * Frees the passed #GimpModuleInfo.
 **/
520 521
void
gimp_module_info_free (GimpModuleInfo *info)
522
{
523 524 525 526 527 528 529
  g_return_if_fail (info != NULL);

  g_free (info->purpose);
  g_free (info->author);
  g_free (info->version);
  g_free (info->copyright);
  g_free (info->date);
530

531
  g_slice_free (GimpModuleInfo, info);
532
}