Blame gladeui/glade-catalog.c

Packit 1e8aac
/*
Packit 1e8aac
 * Copyright (C) 2001 Ximian, Inc.
Packit 1e8aac
 * Copyright (C) 2004 Imendio AB
Packit 1e8aac
 *
Packit 1e8aac
 * This program is free software; you can redistribute it and/or modify
Packit 1e8aac
 * it under the terms of the GNU General Public License as
Packit 1e8aac
 * published by the Free Software Foundation; either version 2 of the
Packit 1e8aac
 * License, or (at your option) any later version.
Packit 1e8aac
 *
Packit 1e8aac
 * This program is distributed in the hope that it will be useful,
Packit 1e8aac
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 1e8aac
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 1e8aac
 * GNU General Public License for more details.
Packit 1e8aac
 *
Packit 1e8aac
 * You should have received a copy of the GNU General Public License
Packit 1e8aac
 * along with this program; if not, write to the Free Software
Packit 1e8aac
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Packit 1e8aac
 *
Packit 1e8aac
 * Authors:
Packit 1e8aac
 *   Chema Celorio <chema@celorio.com>
Packit 1e8aac
 */
Packit 1e8aac
Packit 1e8aac
#include <config.h>
Packit 1e8aac
Packit 1e8aac
#include "glade.h"
Packit 1e8aac
#include "glade-catalog.h"
Packit 1e8aac
#include "glade-widget-adaptor.h"
Packit 1e8aac
#include "glade-private.h"
Packit 1e8aac
#include "glade-tsort.h"
Packit 1e8aac
Packit 1e8aac
#include <string.h>
Packit 1e8aac
#include <sys/types.h>
Packit 1e8aac
#include <sys/stat.h>
Packit 1e8aac
#include <glib.h>
Packit 1e8aac
#include <glib/gi18n-lib.h>
Packit 1e8aac
Packit 1e8aac
struct _GladeCatalog
Packit 1e8aac
{
Packit 1e8aac
  guint16 major_version;        /* The catalog version               */
Packit 1e8aac
  guint16 minor_version;
Packit 1e8aac
Packit 1e8aac
  GList *targetable_versions;   /* list of suitable version targets */
Packit 1e8aac
Packit 1e8aac
  gchar *library;               /* Library name for backend support  */
Packit 1e8aac
Packit 1e8aac
  gchar *name;                  /* Symbolic catalog name             */
Packit 1e8aac
Packit 1e8aac
  gchar *dep_catalog;           /* Symbolic name of the catalog that
Packit 1e8aac
                                 * this catalog depends on           */
Packit 1e8aac
Packit 1e8aac
  gchar *domain;                /* The domain to be used to translate
Packit 1e8aac
                                 * strings from this catalog (otherwise this 
Packit 1e8aac
                                 * defaults to the library name)
Packit 1e8aac
                                 */
Packit 1e8aac
Packit 1e8aac
  gchar *book;                  /* Devhelp search domain */
Packit 1e8aac
Packit 1e8aac
  gchar *icon_prefix;           /* the prefix for icons */
Packit 1e8aac
Packit 1e8aac
  GList *widget_groups;         /* List of widget groups (palette)   */
Packit 1e8aac
  GList *adaptors;              /* List of widget class adaptors (all)  */
Packit 1e8aac
Packit 1e8aac
  GladeXmlContext *context;     /* Xml context is stored after open
Packit 1e8aac
                                 * before classes are loaded         */
Packit 1e8aac
Packit 1e8aac
  GModule *module;
Packit 1e8aac
Packit 1e8aac
  gchar *init_function_name;    /* Catalog's init function name */
Packit 1e8aac
  GladeCatalogInitFunc init_function;
Packit 1e8aac
};
Packit 1e8aac
Packit 1e8aac
struct _GladeWidgetGroup
Packit 1e8aac
{
Packit 1e8aac
  gchar *name;                  /* Group name */
Packit 1e8aac
  gchar *title;                 /* Group name in the palette */
Packit 1e8aac
Packit 1e8aac
  gboolean expanded;            /* Whether group is expanded in the palette */
Packit 1e8aac
Packit 1e8aac
  GList *adaptors;              /* List of class adaptors in the palette    */
Packit 1e8aac
};
Packit 1e8aac
Packit 1e8aac
/* List of catalogs successfully loaded. */
Packit 1e8aac
static GList *loaded_catalogs = NULL;
Packit 1e8aac
Packit 1e8aac
/* Extra paths to load catalogs from */
Packit 1e8aac
static GList *catalog_paths = NULL;
Packit 1e8aac
Packit 1e8aac
static gboolean
Packit 1e8aac
catalog_get_function (GladeCatalog *catalog,
Packit 1e8aac
                      const gchar  *symbol_name,
Packit 1e8aac
                      gpointer     *symbol_ptr)
Packit 1e8aac
{
Packit 1e8aac
  if (catalog->module == NULL)
Packit 1e8aac
    catalog->module = glade_util_load_library (catalog->library);
Packit 1e8aac
Packit 1e8aac
  if (catalog->module)
Packit 1e8aac
    return g_module_symbol (catalog->module, symbol_name, symbol_ptr);
Packit 1e8aac
Packit 1e8aac
  return FALSE;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static GladeCatalog *
Packit 1e8aac
catalog_allocate (void)
Packit 1e8aac
{
Packit 1e8aac
  GladeCatalog *catalog;
Packit 1e8aac
Packit 1e8aac
  catalog = g_slice_new0 (GladeCatalog);
Packit 1e8aac
Packit 1e8aac
  catalog->library = NULL;
Packit 1e8aac
  catalog->name = NULL;
Packit 1e8aac
  catalog->dep_catalog = NULL;
Packit 1e8aac
  catalog->domain = NULL;
Packit 1e8aac
  catalog->book = NULL;
Packit 1e8aac
  catalog->icon_prefix = NULL;
Packit 1e8aac
  catalog->init_function_name = NULL;
Packit 1e8aac
  catalog->module = NULL;
Packit 1e8aac
Packit 1e8aac
  catalog->context = NULL;
Packit 1e8aac
  catalog->adaptors = NULL;
Packit 1e8aac
  catalog->widget_groups = NULL;
Packit 1e8aac
Packit 1e8aac
  return catalog;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
widget_group_destroy (GladeWidgetGroup *group)
Packit 1e8aac
{
Packit 1e8aac
  g_return_if_fail (GLADE_IS_WIDGET_GROUP (group));
Packit 1e8aac
Packit 1e8aac
  g_free (group->name);
Packit 1e8aac
  g_free (group->title);
Packit 1e8aac
  g_list_free (group->adaptors);
Packit 1e8aac
Packit 1e8aac
  g_slice_free (GladeWidgetGroup, group);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
catalog_destroy (GladeCatalog *catalog)
Packit 1e8aac
{
Packit 1e8aac
  g_return_if_fail (GLADE_IS_CATALOG (catalog));
Packit 1e8aac
Packit 1e8aac
  g_free (catalog->name);
Packit 1e8aac
  g_free (catalog->library);
Packit 1e8aac
  g_free (catalog->dep_catalog);
Packit 1e8aac
  g_free (catalog->domain);
Packit 1e8aac
  g_free (catalog->book);
Packit 1e8aac
  g_free (catalog->icon_prefix);
Packit 1e8aac
  g_free (catalog->init_function_name);
Packit 1e8aac
Packit 1e8aac
  if (catalog->adaptors)
Packit 1e8aac
    {
Packit 1e8aac
      g_list_free (catalog->adaptors);
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  if (catalog->widget_groups)
Packit 1e8aac
    {
Packit 1e8aac
      g_list_foreach (catalog->widget_groups, (GFunc) widget_group_destroy,
Packit 1e8aac
                      NULL);
Packit 1e8aac
      g_list_free (catalog->widget_groups);
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  if (catalog->context)
Packit 1e8aac
    glade_xml_context_free (catalog->context);
Packit 1e8aac
Packit 1e8aac
  g_slice_free (GladeCatalog, catalog);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static GladeCatalog *
Packit 1e8aac
catalog_open (const gchar *filename)
Packit 1e8aac
{
Packit 1e8aac
  GladeTargetableVersion *version;
Packit 1e8aac
  GladeCatalog *catalog;
Packit 1e8aac
  GladeXmlContext *context;
Packit 1e8aac
  GladeXmlDoc *doc;
Packit 1e8aac
  GladeXmlNode *root;
Packit 1e8aac
  gchar *name;
Packit 1e8aac
Packit 1e8aac
  /* get the context & root node of the catalog file */
Packit 1e8aac
  context = glade_xml_context_new_from_path (filename,
Packit 1e8aac
                                             NULL, GLADE_TAG_GLADE_CATALOG);
Packit 1e8aac
  if (!context)
Packit 1e8aac
    {
Packit 1e8aac
      g_warning ("Couldn't open catalog [%s].", filename);
Packit 1e8aac
      return NULL;
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  doc = glade_xml_context_get_doc (context);
Packit 1e8aac
  root = glade_xml_doc_get_root (doc);
Packit 1e8aac
Packit 1e8aac
  if (!glade_xml_node_verify (root, GLADE_TAG_GLADE_CATALOG))
Packit 1e8aac
    {
Packit 1e8aac
      g_warning ("Catalog root node is not '%s', skipping %s",
Packit 1e8aac
                 GLADE_TAG_GLADE_CATALOG, filename);
Packit 1e8aac
      glade_xml_context_free (context);
Packit 1e8aac
      return NULL;
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  if (!(name = glade_xml_get_property_string_required (root, GLADE_TAG_NAME, NULL)))
Packit 1e8aac
    return NULL;
Packit 1e8aac
Packit 1e8aac
  catalog = catalog_allocate ();
Packit 1e8aac
  catalog->context = context;
Packit 1e8aac
  catalog->name = name;
Packit 1e8aac
Packit 1e8aac
  glade_xml_get_property_version (root, GLADE_TAG_VERSION,
Packit 1e8aac
                                  &catalog->major_version,
Packit 1e8aac
                                  &catalog->minor_version);
Packit 1e8aac
Packit 1e8aac
  /* Make one default suitable target */
Packit 1e8aac
  version = g_new (GladeTargetableVersion, 1);
Packit 1e8aac
  version->major = catalog->major_version;
Packit 1e8aac
  version->minor = catalog->minor_version;
Packit 1e8aac
Packit 1e8aac
  catalog->targetable_versions =
Packit 1e8aac
      glade_xml_get_property_targetable_versions (root, GLADE_TAG_TARGETABLE);
Packit 1e8aac
Packit 1e8aac
  catalog->targetable_versions =
Packit 1e8aac
      g_list_prepend (catalog->targetable_versions, version);
Packit 1e8aac
Packit 1e8aac
  catalog->library = glade_xml_get_property_string (root, GLADE_TAG_LIBRARY);
Packit 1e8aac
  catalog->dep_catalog =
Packit 1e8aac
      glade_xml_get_property_string (root, GLADE_TAG_DEPENDS);
Packit 1e8aac
  catalog->domain = glade_xml_get_property_string (root, GLADE_TAG_DOMAIN);
Packit 1e8aac
  catalog->book = glade_xml_get_property_string (root, GLADE_TAG_BOOK);
Packit 1e8aac
  catalog->icon_prefix =
Packit 1e8aac
      glade_xml_get_property_string (root, GLADE_TAG_ICON_PREFIX);
Packit 1e8aac
  catalog->init_function_name =
Packit 1e8aac
      glade_xml_get_value_string (root, GLADE_TAG_INIT_FUNCTION);
Packit 1e8aac
Packit 1e8aac
  if (!catalog->domain)
Packit 1e8aac
    catalog->domain = g_strdup (catalog->library);
Packit 1e8aac
Packit 1e8aac
  /* catalog->icon_prefix defaults to catalog->name */
Packit 1e8aac
  if (!catalog->icon_prefix)
Packit 1e8aac
    catalog->icon_prefix = g_strdup (catalog->name);
Packit 1e8aac
Packit 1e8aac
  if (catalog->init_function_name)
Packit 1e8aac
    {
Packit 1e8aac
      if (!catalog_get_function (catalog, catalog->init_function_name,
Packit 1e8aac
                                 (gpointer) & catalog->init_function))
Packit 1e8aac
        g_warning ("Failed to find and execute catalog '%s' init function '%s'",
Packit 1e8aac
                   glade_catalog_get_name (catalog),
Packit 1e8aac
                   catalog->init_function_name);
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  return catalog;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static GHashTable *modules = NULL;
Packit 1e8aac
Packit 1e8aac
static GModule *
Packit 1e8aac
catalog_load_library (GladeCatalog *catalog)
Packit 1e8aac
{
Packit 1e8aac
  GModule *module;
Packit 1e8aac
Packit 1e8aac
  if (modules == NULL)
Packit 1e8aac
    modules = g_hash_table_new_full (g_str_hash,
Packit 1e8aac
                                     g_str_equal,
Packit 1e8aac
                                     (GDestroyNotify) g_free,
Packit 1e8aac
                                     (GDestroyNotify) g_module_close);
Packit 1e8aac
Packit 1e8aac
  if (catalog->library == NULL)
Packit 1e8aac
    return NULL;
Packit 1e8aac
Packit 1e8aac
  if ((module = g_hash_table_lookup (modules, catalog->library)))
Packit 1e8aac
    return module;
Packit 1e8aac
Packit 1e8aac
  if ((module = glade_util_load_library (catalog->library)))
Packit 1e8aac
    g_hash_table_insert (modules, g_strdup (catalog->library), module);
Packit 1e8aac
  else
Packit 1e8aac
    g_warning ("Failed to load external library '%s' for catalog '%s'",
Packit 1e8aac
               catalog->library,
Packit 1e8aac
               glade_catalog_get_name (catalog));
Packit 1e8aac
Packit 1e8aac
  return module;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static gboolean
Packit 1e8aac
catalog_load_classes (GladeCatalog *catalog, GladeXmlNode *widgets_node)
Packit 1e8aac
{
Packit 1e8aac
  GladeXmlNode *node;
Packit 1e8aac
  GModule *module = catalog_load_library (catalog);
Packit 1e8aac
Packit 1e8aac
  node = glade_xml_node_get_children (widgets_node);
Packit 1e8aac
  for (; node; node = glade_xml_node_next (node))
Packit 1e8aac
    {
Packit 1e8aac
      const gchar *node_name;
Packit 1e8aac
      GladeWidgetAdaptor *adaptor;
Packit 1e8aac
Packit 1e8aac
      node_name = glade_xml_node_get_name (node);
Packit 1e8aac
      if (strcmp (node_name, GLADE_TAG_GLADE_WIDGET_CLASS) != 0)
Packit 1e8aac
        continue;
Packit 1e8aac
Packit 1e8aac
      adaptor = glade_widget_adaptor_from_catalog (catalog, node, module);
Packit 1e8aac
Packit 1e8aac
      catalog->adaptors = g_list_prepend (catalog->adaptors, adaptor);
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  return TRUE;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static gboolean
Packit 1e8aac
catalog_load_group (GladeCatalog *catalog, GladeXmlNode *group_node)
Packit 1e8aac
{
Packit 1e8aac
  GladeWidgetGroup *group;
Packit 1e8aac
  GladeXmlNode *node;
Packit 1e8aac
  char *title, *translated_title;
Packit 1e8aac
Packit 1e8aac
  group = g_slice_new0 (GladeWidgetGroup);
Packit 1e8aac
Packit 1e8aac
  group->name = glade_xml_get_property_string (group_node, GLADE_TAG_NAME);
Packit 1e8aac
Packit 1e8aac
  if (!group->name)
Packit 1e8aac
    {
Packit 1e8aac
      g_warning ("Required property 'name' not found in group node");
Packit 1e8aac
      widget_group_destroy (group);
Packit 1e8aac
      return FALSE;
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  title = glade_xml_get_property_string (group_node, GLADE_TAG_TITLE);
Packit 1e8aac
  if (!title)
Packit 1e8aac
    {
Packit 1e8aac
      g_warning ("Required property 'title' not found in group node");
Packit 1e8aac
      widget_group_destroy (group);
Packit 1e8aac
      return FALSE;
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  /* by default, group is expanded in palette  */
Packit 1e8aac
  group->expanded = TRUE;
Packit 1e8aac
Packit 1e8aac
  /* Translate it */
Packit 1e8aac
  translated_title = dgettext (catalog->domain, title);
Packit 1e8aac
  if (translated_title != title)
Packit 1e8aac
    {
Packit 1e8aac
      group->title = g_strdup (translated_title);
Packit 1e8aac
      g_free (title);
Packit 1e8aac
    }
Packit 1e8aac
  else
Packit 1e8aac
    {
Packit 1e8aac
      group->title = title;
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  group->adaptors = NULL;
Packit 1e8aac
Packit 1e8aac
  node = glade_xml_node_get_children (group_node);
Packit 1e8aac
  for (; node; node = glade_xml_node_next (node))
Packit 1e8aac
    {
Packit 1e8aac
      const gchar *node_name;
Packit 1e8aac
      GladeWidgetAdaptor *adaptor;
Packit 1e8aac
      gchar *name;
Packit 1e8aac
Packit 1e8aac
      node_name = glade_xml_node_get_name (node);
Packit 1e8aac
Packit 1e8aac
      if (strcmp (node_name, GLADE_TAG_GLADE_WIDGET_CLASS_REF) == 0)
Packit 1e8aac
        {
Packit 1e8aac
          if ((name =
Packit 1e8aac
               glade_xml_get_property_string (node, GLADE_TAG_NAME)) == NULL)
Packit 1e8aac
            {
Packit 1e8aac
              g_warning ("Couldn't find required property on %s",
Packit 1e8aac
                         GLADE_TAG_GLADE_WIDGET_CLASS);
Packit 1e8aac
              continue;
Packit 1e8aac
            }
Packit 1e8aac
Packit 1e8aac
          if ((adaptor = glade_widget_adaptor_get_by_name (name)) == NULL)
Packit 1e8aac
            {
Packit 1e8aac
              g_warning ("Tried to include undefined widget "
Packit 1e8aac
                         "class '%s' in a widget group", name);
Packit 1e8aac
              g_free (name);
Packit 1e8aac
              continue;
Packit 1e8aac
            }
Packit 1e8aac
          g_free (name);
Packit 1e8aac
Packit 1e8aac
          group->adaptors = g_list_prepend (group->adaptors, adaptor);
Packit 1e8aac
Packit 1e8aac
        }
Packit 1e8aac
      else if (strcmp (node_name, GLADE_TAG_DEFAULT_PALETTE_STATE) == 0)
Packit 1e8aac
        {
Packit 1e8aac
          group->expanded =
Packit 1e8aac
              glade_xml_get_property_boolean
Packit 1e8aac
              (node, GLADE_TAG_EXPANDED, group->expanded);
Packit 1e8aac
        }
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  group->adaptors = g_list_reverse (group->adaptors);
Packit 1e8aac
Packit 1e8aac
  catalog->widget_groups = g_list_prepend (catalog->widget_groups, group);
Packit 1e8aac
Packit 1e8aac
  return TRUE;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
catalog_load (GladeCatalog *catalog)
Packit 1e8aac
{
Packit 1e8aac
  GladeXmlDoc *doc;
Packit 1e8aac
  GladeXmlNode *root;
Packit 1e8aac
  GladeXmlNode *node;
Packit 1e8aac
Packit 1e8aac
  g_return_if_fail (catalog->context != NULL);
Packit 1e8aac
Packit 1e8aac
  doc = glade_xml_context_get_doc (catalog->context);
Packit 1e8aac
  root = glade_xml_doc_get_root (doc);
Packit 1e8aac
  node = glade_xml_node_get_children (root);
Packit 1e8aac
Packit 1e8aac
  for (; node; node = glade_xml_node_next (node))
Packit 1e8aac
    {
Packit 1e8aac
      const gchar *node_name;
Packit 1e8aac
Packit 1e8aac
      node_name = glade_xml_node_get_name (node);
Packit 1e8aac
      if (strcmp (node_name, GLADE_TAG_GLADE_WIDGET_CLASSES) == 0)
Packit 1e8aac
        {
Packit 1e8aac
          catalog_load_classes (catalog, node);
Packit 1e8aac
        }
Packit 1e8aac
      else if (strcmp (node_name, GLADE_TAG_GLADE_WIDGET_GROUP) == 0)
Packit 1e8aac
        {
Packit 1e8aac
          catalog_load_group (catalog, node);
Packit 1e8aac
        }
Packit 1e8aac
      else
Packit 1e8aac
        continue;
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  catalog->widget_groups = g_list_reverse (catalog->widget_groups);
Packit 1e8aac
  catalog->context = (glade_xml_context_free (catalog->context), NULL);
Packit 1e8aac
Packit 1e8aac
  return;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static GladeCatalog *
Packit 1e8aac
catalog_find_by_name (GList *catalogs, const gchar *name)
Packit 1e8aac
{
Packit 1e8aac
  if (name)
Packit 1e8aac
    {
Packit 1e8aac
      GList *l;
Packit 1e8aac
      for (l = catalogs; l; l = g_list_next (l))
Packit 1e8aac
        {
Packit 1e8aac
          GladeCatalog *catalog = l->data;
Packit 1e8aac
          if (g_strcmp0 (catalog->name, name) == 0)
Packit 1e8aac
            return catalog;
Packit 1e8aac
        }
Packit 1e8aac
    }
Packit 1e8aac
  
Packit 1e8aac
  return NULL;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static gint
Packit 1e8aac
catalog_name_cmp (gconstpointer a, gconstpointer b)
Packit 1e8aac
{
Packit 1e8aac
  return (a && b) ? g_strcmp0 (GLADE_CATALOG(a)->name, GLADE_CATALOG(b)->name) : 0;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static GList *
Packit 1e8aac
glade_catalog_tsort (GList *catalogs, gboolean loading)
Packit 1e8aac
{
Packit 1e8aac
  GList *l, *sorted = NULL;
Packit 1e8aac
  GList *deps = NULL;
Packit 1e8aac
Packit 1e8aac
  /* Sort alphabetically first */
Packit 1e8aac
  catalogs = g_list_sort (catalogs, catalog_name_cmp);
Packit 1e8aac
Packit 1e8aac
  /* Generate dependency graph edges */
Packit 1e8aac
  for (l = catalogs; l; l = g_list_next (l))
Packit 1e8aac
    {
Packit 1e8aac
      GladeCatalog *catalog = l->data, *dep;
Packit 1e8aac
Packit 1e8aac
      if (!catalog->dep_catalog)
Packit 1e8aac
        continue;
Packit 1e8aac
Packit 1e8aac
      if ((dep = catalog_find_by_name ((loading) ? catalogs : loaded_catalogs,
Packit 1e8aac
                                       catalog->dep_catalog)))
Packit 1e8aac
        deps = _node_edge_prepend (deps, dep, catalog);
Packit 1e8aac
      else
Packit 1e8aac
        g_critical ("Catalog %s depends on catalog %s, not found",
Packit 1e8aac
                    catalog->name, catalog->dep_catalog);
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  sorted = _glade_tsort (&catalogs, &deps);
Packit 1e8aac
Packit 1e8aac
  if (deps)
Packit 1e8aac
    {
Packit 1e8aac
      GList *l, *cycles = NULL;
Packit 1e8aac
      
Packit 1e8aac
      g_warning ("Circular dependency detected loading catalogs, they will be ignored");
Packit 1e8aac
Packit 1e8aac
      for (l = deps; l; l = g_list_next (l))
Packit 1e8aac
        {
Packit 1e8aac
          _NodeEdge *edge = l->data;
Packit 1e8aac
Packit 1e8aac
          g_message ("\t%s depends on %s",
Packit 1e8aac
                     GLADE_CATALOG (edge->successor)->name,
Packit 1e8aac
                     GLADE_CATALOG (edge->successor)->dep_catalog);
Packit 1e8aac
          
Packit 1e8aac
          if (loading && !g_list_find (cycles, edge->successor))
Packit 1e8aac
            cycles = g_list_prepend (cycles, edge->successor);
Packit 1e8aac
        }
Packit 1e8aac
Packit 1e8aac
      if (cycles)
Packit 1e8aac
        g_list_free_full (cycles, (GDestroyNotify) catalog_destroy);
Packit 1e8aac
Packit 1e8aac
      _node_edge_list_free (deps);
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  return sorted;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static GList *
Packit 1e8aac
catalogs_from_path (GList *catalogs, const gchar *path)
Packit 1e8aac
{
Packit 1e8aac
  GladeCatalog *catalog;
Packit 1e8aac
  GDir *dir;
Packit 1e8aac
  GError *error = NULL;
Packit 1e8aac
  const gchar *filename;
Packit 1e8aac
Packit 1e8aac
  /* Silent return if the directory didn't exist */
Packit 1e8aac
  if (!g_file_test (path, G_FILE_TEST_IS_DIR))
Packit 1e8aac
    return catalogs;
Packit 1e8aac
Packit 1e8aac
  if ((dir = g_dir_open (path, 0, &error)) != NULL)
Packit 1e8aac
    {
Packit 1e8aac
      while ((filename = g_dir_read_name (dir)))
Packit 1e8aac
        {
Packit 1e8aac
          gchar *catalog_filename;
Packit 1e8aac
Packit 1e8aac
          if (!g_str_has_suffix (filename, ".xml"))
Packit 1e8aac
            continue;
Packit 1e8aac
Packit 1e8aac
	  /* Special case, ignore gresource files (which are present
Packit 1e8aac
	   * while running tests)
Packit 1e8aac
	   */
Packit 1e8aac
	  if (g_str_has_suffix (filename, ".gresource.xml"))
Packit 1e8aac
	    continue;
Packit 1e8aac
Packit 1e8aac
	  /* If we're running in the bundle, don't ever try to load
Packit 1e8aac
	   * anything except the GTK+ catalog
Packit 1e8aac
	   */
Packit 1e8aac
	  if (g_getenv (GLADE_ENV_BUNDLED) != NULL &&
Packit 1e8aac
	      strcmp (filename, "gtk+.xml") != 0)
Packit 1e8aac
	    continue;
Packit 1e8aac
Packit 1e8aac
          catalog_filename = g_build_filename (path, filename, NULL);
Packit 1e8aac
          catalog = catalog_open (catalog_filename);
Packit 1e8aac
          g_free (catalog_filename);
Packit 1e8aac
Packit 1e8aac
          if (catalog)
Packit 1e8aac
            {
Packit 1e8aac
              /* Verify that we are not loading the same catalog twice !
Packit 1e8aac
               */
Packit 1e8aac
              if (catalog_find_by_name (catalogs, catalog->name))
Packit 1e8aac
                catalog_destroy (catalog);
Packit 1e8aac
              else
Packit 1e8aac
                catalogs = g_list_prepend (catalogs, catalog);
Packit 1e8aac
            }
Packit 1e8aac
          else
Packit 1e8aac
            g_warning ("Unable to open the catalog file %s.\n", filename);
Packit 1e8aac
        }
Packit 1e8aac
Packit 1e8aac
      g_dir_close (dir);
Packit 1e8aac
    }
Packit 1e8aac
  else
Packit 1e8aac
    g_warning ("Failed to open catalog directory '%s': %s", path,
Packit 1e8aac
               error->message);
Packit 1e8aac
Packit 1e8aac
Packit 1e8aac
  return catalogs;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_catalog_add_path:
Packit 1e8aac
 * @path:
Packit 1e8aac
 * 
Packit 1e8aac
 * Adds a new path to the list of path to look catalogs for.
Packit 1e8aac
 */
Packit 1e8aac
void
Packit 1e8aac
glade_catalog_add_path (const gchar *path)
Packit 1e8aac
{
Packit 1e8aac
  g_return_if_fail (path != NULL);
Packit 1e8aac
Packit 1e8aac
  if (g_list_find_custom (catalog_paths, path, (GCompareFunc) g_strcmp0) == NULL)
Packit 1e8aac
	catalog_paths = g_list_append (catalog_paths, g_strdup (path));
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_catalog_remove_path:
Packit 1e8aac
 * @path:
Packit 1e8aac
 * 
Packit 1e8aac
 * Remove path from the list of path to look catalogs for.
Packit 1e8aac
 * NULL to remove all paths.
Packit 1e8aac
 */
Packit 1e8aac
void
Packit 1e8aac
glade_catalog_remove_path (const gchar *path)
Packit 1e8aac
{
Packit 1e8aac
  GList *l;
Packit 1e8aac
  
Packit 1e8aac
  if (path == NULL)
Packit 1e8aac
	{
Packit 1e8aac
	  g_list_free_full (catalog_paths, g_free);
Packit 1e8aac
	  catalog_paths = NULL;
Packit 1e8aac
	}
Packit 1e8aac
  else if ((l = g_list_find_custom (catalog_paths, path, (GCompareFunc) g_strcmp0)))
Packit 1e8aac
	{
Packit 1e8aac
	  catalog_paths = g_list_remove_link (catalog_paths, l); 
Packit 1e8aac
	}
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_catalog_get_extra_paths:
Packit 1e8aac
 *
Packit 1e8aac
 * Returns a list paths added by glade_catalog_add_path()
Packit 1e8aac
 */
Packit 1e8aac
const GList *
Packit 1e8aac
glade_catalog_get_extra_paths (void)
Packit 1e8aac
{
Packit 1e8aac
  return catalog_paths;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_catalog_load_all:
Packit 1e8aac
 * 
Packit 1e8aac
 * Loads all available catalogs in the system.
Packit 1e8aac
 * First loads catalogs from GLADE_ENV_CATALOG_PATH,
Packit 1e8aac
 * then from glade_app_get_catalogs_dir() and finally from paths specified with
Packit 1e8aac
 * glade_catalog_add_path()
Packit 1e8aac
 *
Packit 1e8aac
 * Returns: the list of loaded GladeCatalog *
Packit 1e8aac
 */
Packit 1e8aac
const GList *
Packit 1e8aac
glade_catalog_load_all (void)
Packit 1e8aac
{
Packit 1e8aac
  GList *catalogs = NULL, *l, *adaptors;
Packit 1e8aac
  GladeCatalog *catalog;
Packit 1e8aac
  const gchar *search_path;
Packit 1e8aac
  gchar **split;
Packit 1e8aac
  GString *icon_warning = NULL;
Packit 1e8aac
  gint i;
Packit 1e8aac
Packit 1e8aac
Packit 1e8aac
  /* Make sure we don't init the catalogs twice */
Packit 1e8aac
  if (loaded_catalogs)
Packit 1e8aac
    return loaded_catalogs;
Packit 1e8aac
Packit 1e8aac
  /* First load catalogs from user specified directories ... */
Packit 1e8aac
  if ((search_path = g_getenv (GLADE_ENV_CATALOG_PATH)) != NULL)
Packit 1e8aac
    {
Packit 1e8aac
      if ((split = g_strsplit (search_path, ":", 0)) != NULL)
Packit 1e8aac
        {
Packit 1e8aac
          for (i = 0; split[i] != NULL; i++)
Packit 1e8aac
            catalogs = catalogs_from_path (catalogs, split[i]);
Packit 1e8aac
Packit 1e8aac
          g_strfreev (split);
Packit 1e8aac
        }
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  /* ... Then load catalogs from standard install directory */
Packit 1e8aac
  if (g_getenv (GLADE_ENV_TESTING) == NULL)
Packit 1e8aac
    catalogs = catalogs_from_path (catalogs, glade_app_get_catalogs_dir ());
Packit 1e8aac
Packit 1e8aac
  /* And then load catalogs from extra paths */
Packit 1e8aac
  for (l = catalog_paths; l; l = g_list_next (l))
Packit 1e8aac
    catalogs = catalogs_from_path (catalogs, l->data);
Packit 1e8aac
  
Packit 1e8aac
  /* Catalogs need dependancies, most catalogs depend on
Packit 1e8aac
   * the gtk+ catalog, but some custom toolkits may depend
Packit 1e8aac
   * on the gnome catalog for instance.
Packit 1e8aac
   */
Packit 1e8aac
  catalogs = glade_catalog_tsort (catalogs, TRUE);
Packit 1e8aac
Packit 1e8aac
  /* After sorting, execute init function and then load */
Packit 1e8aac
  for (l = catalogs; l; l = g_list_next (l))
Packit 1e8aac
    {
Packit 1e8aac
      catalog = l->data;
Packit 1e8aac
      if (catalog->init_function)
Packit 1e8aac
        catalog->init_function (catalog->name);
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  for (l = catalogs; l; l = g_list_next (l))
Packit 1e8aac
    {
Packit 1e8aac
      catalog = l->data;
Packit 1e8aac
      catalog_load (catalog);
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  /* Print a summery of widget adaptors missing icons.
Packit 1e8aac
   */
Packit 1e8aac
  adaptors = glade_widget_adaptor_list_adaptors ();
Packit 1e8aac
  for (l = adaptors; l; l = g_list_next (l))
Packit 1e8aac
    {
Packit 1e8aac
      GladeWidgetAdaptor *adaptor = l->data;
Packit 1e8aac
Packit 1e8aac
      /* Dont print missing icons in unit tests */
Packit 1e8aac
      if (glade_widget_adaptor_get_missing_icon (adaptor) &&
Packit 1e8aac
	  g_getenv (GLADE_ENV_TESTING) == NULL)
Packit 1e8aac
        {
Packit 1e8aac
          if (!icon_warning)
Packit 1e8aac
            icon_warning = g_string_new ("Glade needs artwork; "
Packit 1e8aac
                                         "a default icon will be used for "
Packit 1e8aac
                                         "the following classes:");
Packit 1e8aac
Packit 1e8aac
	  g_string_append_printf (icon_warning,
Packit 1e8aac
				  "\n\t%s\tneeds an icon named '%s'",
Packit 1e8aac
				  glade_widget_adaptor_get_name (adaptor), 
Packit 1e8aac
				  glade_widget_adaptor_get_missing_icon (adaptor));
Packit 1e8aac
        }
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  g_list_free (adaptors);
Packit 1e8aac
Packit 1e8aac
  if (icon_warning)
Packit 1e8aac
    {
Packit 1e8aac
      g_message ("%s", icon_warning->str);
Packit 1e8aac
      g_string_free (icon_warning, TRUE);
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  loaded_catalogs = catalogs;
Packit 1e8aac
Packit 1e8aac
  return loaded_catalogs;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_catalog_get_name:
Packit 1e8aac
 * @catalog: a catalog object
Packit 1e8aac
 * 
Packit 1e8aac
 * Returns: The symbolic catalog name.
Packit 1e8aac
 */
Packit 1e8aac
G_CONST_RETURN gchar *
Packit 1e8aac
glade_catalog_get_name (GladeCatalog *catalog)
Packit 1e8aac
{
Packit 1e8aac
  g_return_val_if_fail (GLADE_IS_CATALOG (catalog), NULL);
Packit 1e8aac
Packit 1e8aac
  return catalog->name;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_catalog_get_book:
Packit 1e8aac
 * @catalog: a catalog object
Packit 1e8aac
 * 
Packit 1e8aac
 * Returns: The Devhelp search domain.
Packit 1e8aac
 */
Packit 1e8aac
G_CONST_RETURN gchar *
Packit 1e8aac
glade_catalog_get_book (GladeCatalog *catalog)
Packit 1e8aac
{
Packit 1e8aac
  g_return_val_if_fail (GLADE_IS_CATALOG (catalog), NULL);
Packit 1e8aac
Packit 1e8aac
  return catalog->book;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_catalog_get_domain:
Packit 1e8aac
 * @catalog: a catalog object
Packit 1e8aac
 * 
Packit 1e8aac
 * Returns: The domain to be used to translate strings from this catalog
Packit 1e8aac
 */
Packit 1e8aac
G_CONST_RETURN gchar *
Packit 1e8aac
glade_catalog_get_domain (GladeCatalog *catalog)
Packit 1e8aac
{
Packit 1e8aac
  g_return_val_if_fail (GLADE_IS_CATALOG (catalog), NULL);
Packit 1e8aac
Packit 1e8aac
  return catalog->domain;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_catalog_get_icon_prefix:
Packit 1e8aac
 * @catalog: a catalog object
Packit 1e8aac
 * 
Packit 1e8aac
 * Returns: The prefix for icons.
Packit 1e8aac
 */
Packit 1e8aac
G_CONST_RETURN gchar *
Packit 1e8aac
glade_catalog_get_icon_prefix (GladeCatalog *catalog)
Packit 1e8aac
{
Packit 1e8aac
  g_return_val_if_fail (GLADE_IS_CATALOG (catalog), NULL);
Packit 1e8aac
Packit 1e8aac
  return catalog->icon_prefix;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_catalog_get_major_version:
Packit 1e8aac
 * @catalog: a catalog object
Packit 1e8aac
 * 
Packit 1e8aac
 * Returns: The catalog version
Packit 1e8aac
 */
Packit 1e8aac
guint16
Packit 1e8aac
glade_catalog_get_major_version (GladeCatalog *catalog)
Packit 1e8aac
{
Packit 1e8aac
  g_return_val_if_fail (GLADE_IS_CATALOG (catalog), 0);
Packit 1e8aac
Packit 1e8aac
  return catalog->major_version;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_catalog_get_minor_version:
Packit 1e8aac
 * @catalog: a catalog object
Packit 1e8aac
 * 
Packit 1e8aac
 * Returns: The catalog minor version
Packit 1e8aac
 */
Packit 1e8aac
guint16
Packit 1e8aac
glade_catalog_get_minor_version (GladeCatalog *catalog)
Packit 1e8aac
{
Packit 1e8aac
  g_return_val_if_fail (GLADE_IS_CATALOG (catalog), 0);
Packit 1e8aac
Packit 1e8aac
  return catalog->minor_version;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_catalog_get_targets:
Packit 1e8aac
 * @catalog: a catalog object
Packit 1e8aac
 * 
Packit 1e8aac
 * Returns: the list of suitable version targets.
Packit 1e8aac
 */
Packit 1e8aac
GList *
Packit 1e8aac
glade_catalog_get_targets (GladeCatalog *catalog)
Packit 1e8aac
{
Packit 1e8aac
  g_return_val_if_fail (GLADE_IS_CATALOG (catalog), NULL);
Packit 1e8aac
Packit 1e8aac
  return catalog->targetable_versions;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_catalog_get_widget_groups:
Packit 1e8aac
 * @catalog: a catalog object
Packit 1e8aac
 * 
Packit 1e8aac
 * Returns: the list of widget groups (palette)
Packit 1e8aac
 */
Packit 1e8aac
GList *
Packit 1e8aac
glade_catalog_get_widget_groups (GladeCatalog *catalog)
Packit 1e8aac
{
Packit 1e8aac
  g_return_val_if_fail (GLADE_IS_CATALOG (catalog), NULL);
Packit 1e8aac
Packit 1e8aac
  return catalog->widget_groups;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_catalog_get_adaptors:
Packit 1e8aac
 * @catalog: a catalog object
Packit 1e8aac
 * 
Packit 1e8aac
 * Returns: the list of widget class adaptors
Packit 1e8aac
 */
Packit 1e8aac
GList *
Packit 1e8aac
glade_catalog_get_adaptors (GladeCatalog *catalog)
Packit 1e8aac
{
Packit 1e8aac
  g_return_val_if_fail (GLADE_IS_CATALOG (catalog), NULL);
Packit 1e8aac
Packit 1e8aac
  return catalog->adaptors;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_catalog_is_loaded:
Packit 1e8aac
 * @name: a catalog object
Packit 1e8aac
 * 
Packit 1e8aac
 * Returns: Whether @name is loaded or not
Packit 1e8aac
 */
Packit 1e8aac
gboolean
Packit 1e8aac
glade_catalog_is_loaded (const gchar *name)
Packit 1e8aac
{
Packit 1e8aac
  g_return_val_if_fail (name != NULL, FALSE);
Packit 1e8aac
  g_assert (loaded_catalogs != NULL);
Packit 1e8aac
  return catalog_find_by_name (loaded_catalogs, name) != NULL;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_catalog_destroy_all:
Packit 1e8aac
 * 
Packit 1e8aac
 * Destroy and free all resources related with every loaded catalog.
Packit 1e8aac
 */
Packit 1e8aac
void
Packit 1e8aac
glade_catalog_destroy_all (void)
Packit 1e8aac
{
Packit 1e8aac
  /* close catalogs */
Packit 1e8aac
  if (loaded_catalogs)
Packit 1e8aac
    {
Packit 1e8aac
      GList *l;
Packit 1e8aac
      for (l = loaded_catalogs; l; l = l->next)
Packit 1e8aac
        catalog_destroy (GLADE_CATALOG (l->data));
Packit 1e8aac
      g_list_free (loaded_catalogs);
Packit 1e8aac
      loaded_catalogs = NULL;
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  /* close plugin modules */
Packit 1e8aac
  if (modules)
Packit 1e8aac
    {
Packit 1e8aac
      g_hash_table_destroy (modules);
Packit 1e8aac
      modules = NULL;
Packit 1e8aac
    }
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_widget_group_get_name:
Packit 1e8aac
 * @group: a widget group
Packit 1e8aac
 * 
Packit 1e8aac
 * Returns: the widget group name
Packit 1e8aac
 */
Packit 1e8aac
const gchar *
Packit 1e8aac
glade_widget_group_get_name (GladeWidgetGroup *group)
Packit 1e8aac
{
Packit 1e8aac
  g_return_val_if_fail (group != NULL, NULL);
Packit 1e8aac
Packit 1e8aac
  return group->name;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_widget_group_get_title:
Packit 1e8aac
 * @group: a widget group
Packit 1e8aac
 * 
Packit 1e8aac
 * Returns: the widget group name used in the palette
Packit 1e8aac
 */
Packit 1e8aac
const gchar *
Packit 1e8aac
glade_widget_group_get_title (GladeWidgetGroup *group)
Packit 1e8aac
{
Packit 1e8aac
  g_return_val_if_fail (group != NULL, NULL);
Packit 1e8aac
Packit 1e8aac
  return group->title;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_widget_group_get_expanded:
Packit 1e8aac
 * @group: a widget group
Packit 1e8aac
 * 
Packit 1e8aac
 * Returns: Whether group is expanded in the palette
Packit 1e8aac
 */
Packit 1e8aac
gboolean
Packit 1e8aac
glade_widget_group_get_expanded (GladeWidgetGroup *group)
Packit 1e8aac
{
Packit 1e8aac
  g_return_val_if_fail (group != NULL, FALSE);
Packit 1e8aac
Packit 1e8aac
  return group->expanded;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_widget_group_get_adaptors:
Packit 1e8aac
 * @group: a widget group
Packit 1e8aac
 * 
Packit 1e8aac
 * Returns: a list of class adaptors in the palette
Packit 1e8aac
 */
Packit 1e8aac
const GList *
Packit 1e8aac
glade_widget_group_get_adaptors (GladeWidgetGroup *group)
Packit 1e8aac
{
Packit 1e8aac
  g_return_val_if_fail (group != NULL, NULL);
Packit 1e8aac
Packit 1e8aac
  return group->adaptors;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/* Private API */
Packit 1e8aac
Packit 1e8aac
GladeCatalog *
Packit 1e8aac
_glade_catalog_get_catalog (const gchar *name)
Packit 1e8aac
{
Packit 1e8aac
  g_return_val_if_fail (name != NULL, NULL);
Packit 1e8aac
  g_assert (loaded_catalogs != NULL);
Packit 1e8aac
Packit 1e8aac
  return catalog_find_by_name (loaded_catalogs, name);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
GList *
Packit 1e8aac
_glade_catalog_tsort (GList *catalogs)
Packit 1e8aac
{
Packit 1e8aac
  return glade_catalog_tsort (catalogs, FALSE);
Packit 1e8aac
}