Example #1
0
static void
offset_start_element (GMarkupParseContext  *context,
                      const gchar          *element_name,
                      const gchar         **names,
                      const gchar         **values,
                      gpointer              user_data,
                      GError              **error)
{
  OffsetsParserData *data = user_data;

  if (strcmp (element_name, "offsets") == 0)
    {
      if (!_gtk_builder_check_parent (data->builder, context, "object", error))
        return;

      if (!g_markup_collect_attributes (element_name, names, values, error,
                                        G_MARKUP_COLLECT_INVALID, NULL, NULL,
                                        G_MARKUP_COLLECT_INVALID))
        _gtk_builder_prefix_error (data->builder, context, error);
    }
  else if (strcmp (element_name, "offset") == 0)
    {
      const gchar *name;
      const gchar *value;
      GValue gvalue = G_VALUE_INIT;
      GtkLevelBarOffset *offset;

      if (!_gtk_builder_check_parent (data->builder, context, "offsets", error))
        return;

      if (!g_markup_collect_attributes (element_name, names, values, error,
                                        G_MARKUP_COLLECT_STRING, "name", &name,
                                        G_MARKUP_COLLECT_STRING, "value", &value,
                                        G_MARKUP_COLLECT_INVALID))
        {
          _gtk_builder_prefix_error (data->builder, context, error);
          return;
        }

      if (!gtk_builder_value_from_string_type (data->builder, G_TYPE_DOUBLE, value, &gvalue, error))
        {
          _gtk_builder_prefix_error (data->builder, context, error);
          return;
        }

      offset = gtk_level_bar_offset_new (name, g_value_get_double (&gvalue));
      data->offsets = g_list_prepend (data->offsets, offset);
    }
  else
    {
      _gtk_builder_error_unhandled_tag (data->builder, context,
                                        "GtkLevelBar", element_name,
                                        error);
    }
}
Example #2
0
static void
item_start_element (GMarkupParseContext  *context,
                    const gchar          *element_name,
                    const gchar         **names,
                    const gchar         **values,
                    gpointer              user_data,
                    GError              **error)
{
  ItemParserData *data = (ItemParserData*)user_data;

  if (strcmp (element_name, "items") == 0)
    {
      if (!_gtk_builder_check_parent (data->builder, context, "object", error))
        return;

      if (!g_markup_collect_attributes (element_name, names, values, error,
                                        G_MARKUP_COLLECT_INVALID, NULL, NULL,
                                        G_MARKUP_COLLECT_INVALID))
        _gtk_builder_prefix_error (data->builder, context, error);
    }
  else if (strcmp (element_name, "item") == 0)
    {
      const gchar *id = NULL;
      gboolean translatable = FALSE;
      const gchar *msg_context = NULL;

      if (!_gtk_builder_check_parent (data->builder, context, "items", error))
        return;

      if (!g_markup_collect_attributes (element_name, names, values, error,
                                        G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "id", &id,
                                        G_MARKUP_COLLECT_BOOLEAN|G_MARKUP_COLLECT_OPTIONAL, "translatable", &translatable,
                                        G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "comments", NULL,
                                        G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "context", &msg_context,
                                        G_MARKUP_COLLECT_INVALID))
        {
          _gtk_builder_prefix_error (data->builder, context, error);
          return;
        }

      data->is_text = TRUE;
      data->translatable = translatable;
      data->context = g_strdup (msg_context);
      data->id = g_strdup (id);
    }
  else
    {
      _gtk_builder_error_unhandled_tag (data->builder, context,
                                        "GtkComboBoxText", element_name,
                                        error);
    }
}
Example #3
0
static void
cell_packing_start_element (GMarkupParseContext *context,
			    const gchar         *element_name,
			    const gchar        **names,
			    const gchar        **values,
			    gpointer             user_data,
			    GError             **error)
{
  CellPackingSubParserData *data = (CellPackingSubParserData*)user_data;

  if (strcmp (element_name, "property") == 0)
    {
      const gchar *name;
      gboolean translatable = FALSE;
      const gchar *ctx = NULL;

      if (!_gtk_builder_check_parent (data->builder, context, "cell-packing", error))
        return;

      if (!g_markup_collect_attributes (element_name, names, values, error,
                                        G_MARKUP_COLLECT_STRING, "name", &name,
                                        G_MARKUP_COLLECT_BOOLEAN|G_MARKUP_COLLECT_OPTIONAL, "translatable", &translatable,
                                        G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "comments", NULL,
                                        G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "context", &ctx,
                                        G_MARKUP_COLLECT_INVALID))
       {
         _gtk_builder_prefix_error (data->builder, context, error);
         return;
       }

      data->cell_prop_name = g_strdup (name);
      data->translatable = translatable;
      data->context = g_strdup (ctx);
    }
  else if (strcmp (element_name, "cell-packing") == 0)
    {
      if (!_gtk_builder_check_parent (data->builder, context, "child", error))
        return;

      if (!g_markup_collect_attributes (element_name, names, values, error,
                                        G_MARKUP_COLLECT_INVALID, NULL, NULL,
                                        G_MARKUP_COLLECT_INVALID))
        _gtk_builder_prefix_error (data->builder, context, error);
    }
  else
    {
      _gtk_builder_error_unhandled_tag (data->builder, context,
                                        "GtkCellLayout", element_name,
                                        error);
    }
}
Example #4
0
static void
parse_interface (ParserData   *data,
                 const gchar  *element_name,
                 const gchar **names,
                 const gchar **values,
                 GError      **error)
{
  const gchar *domain = NULL;

  if (!g_markup_collect_attributes (element_name, names, values, error,
                                    G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "domain", &domain,
                                    G_MARKUP_COLLECT_INVALID))
    {
      _gtk_builder_prefix_error (data->builder, data->ctx, error);
      return;
    }

  if (domain)
    {
      if (data->domain && strcmp (data->domain, domain) != 0)
        {
          g_warning ("%s: interface domain '%s' overrides programmatic value '%s'",
                     data->filename, domain, data->domain);
          g_free (data->domain);
        }

      data->domain = g_strdup (domain);
      gtk_builder_set_translation_domain (data->builder, data->domain);
    }
}
Example #5
0
static void
attributes_start_element (GMarkupParseContext *context,
			  const gchar         *element_name,
			  const gchar        **names,
			  const gchar        **values,
			  gpointer             user_data,
			  GError             **error)
{
  AttributesSubParserData *data = (AttributesSubParserData*)user_data;

  if (strcmp (element_name, "attribute") == 0)
    {
      const gchar *name;

      if (!_gtk_builder_check_parent (data->builder, context, "attributes", error))
        return;

      if (!g_markup_collect_attributes (element_name, names, values, error,
                                        G_MARKUP_COLLECT_STRING, "name", &name,
                                        G_MARKUP_COLLECT_INVALID))
        {
          _gtk_builder_prefix_error (data->builder, context, error);
          return;
        }

      data->attr_name = g_strdup (name);
    }
  else if (strcmp (element_name, "attributes") == 0)
    {
      if (!_gtk_builder_check_parent (data->builder, context, "child", error))
        return;

      if (!g_markup_collect_attributes (element_name, names, values, error,
                                        G_MARKUP_COLLECT_INVALID, NULL, NULL,
                                        G_MARKUP_COLLECT_INVALID))
        _gtk_builder_prefix_error (data->builder, context, error);
    }
  else
    {
      _gtk_builder_error_unhandled_tag (data->builder, context,
                                        "GtkCellLayout", element_name,
                                        error);
    }
}
Example #6
0
static void
parse_requires (ParserData   *data,
                const gchar  *element_name,
                const gchar **names,
                const gchar **values,
                GError      **error)
{
  RequiresInfo *req_info;
  const gchar  *library = NULL;
  const gchar  *version = NULL;
  gchar **split;
  gint version_major = 0;
  gint version_minor = 0;

  if (!g_markup_collect_attributes (element_name, names, values, error,
                                    G_MARKUP_COLLECT_STRING, "lib", &library,
                                    G_MARKUP_COLLECT_STRING, "version", &version,
                                    G_MARKUP_COLLECT_INVALID))
    {
      _gtk_builder_prefix_error (data->builder, data->ctx, error);
      return;
    }

  if (!(split = g_strsplit (version, ".", 2)) || !split[0] || !split[1])
    {
      g_set_error (error,
                   GTK_BUILDER_ERROR,
                   GTK_BUILDER_ERROR_INVALID_VALUE,
                   "'version' attribute has malformed value '%s'", version);
      _gtk_builder_prefix_error (data->builder, data->ctx, error);
      return;
    }
  version_major = g_ascii_strtoll (split[0], NULL, 10);
  version_minor = g_ascii_strtoll (split[1], NULL, 10);
  g_strfreev (split);

  req_info = g_slice_new0 (RequiresInfo);
  req_info->library = g_strdup (library);
  req_info->major = version_major;
  req_info->minor = version_minor;
  state_push (data, req_info);
  req_info->tag.name = element_name;
}
Example #7
0
static void
parse_child (ParserData   *data,
             const gchar  *element_name,
             const gchar **names,
             const gchar **values,
             GError      **error)

{
  ObjectInfo* object_info;
  ChildInfo *child_info;
  const gchar *type = NULL;
  const gchar *internal_child = NULL;

  object_info = state_peek_info (data, ObjectInfo);
  if (!object_info ||
      !(strcmp (object_info->tag.name, "object") == 0 ||
        strcmp (object_info->tag.name, "template") == 0))
    {
      error_invalid_tag (data, element_name, NULL, error);
      return;
    }

  if (!g_markup_collect_attributes (element_name, names, values, error,
                                    G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "type", &type,
                                    G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "internal-child", &internal_child,
                                    G_MARKUP_COLLECT_INVALID))
    {
      _gtk_builder_prefix_error (data->builder, data->ctx, error);
      return;
    }

  child_info = g_slice_new0 (ChildInfo);
  child_info->tag.name = element_name;
  child_info->type = g_strdup (type);
  child_info->internal_child = g_strdup (internal_child);
  child_info->parent = (CommonInfo*)object_info;
  state_push (data, child_info);

  object_info->object = builder_construct (data, object_info, error);
}
Example #8
0
void KeyConfig::start_element(GMarkupParseContext *context,
    const char *element_name, const char **attribute_names,
    const char **attribute_values, GError **error)
{
  const GSList *stack = g_markup_parse_context_get_element_stack(context);
  guint size = g_slist_length(const_cast<GSList*>(stack));
  if (size == 1) {
    if (strcmp(element_name, "keyconfig")) {
      *error = g_error_new(g_markup_error_quark(), G_MARKUP_ERROR_PARSE,
          _("Expected 'keyconfig' element, found '%s'"), element_name);
    }
  }
  else if (size == 2) {
    if (strcmp(element_name, "bind")) {
      *error = g_error_new(g_markup_error_quark(), G_MARKUP_ERROR_PARSE,
          _("Expected 'bind' element, found '%s'"), element_name);
      return;
    }

    const char *context;
    const char *action;
    const char *key;
    if (!g_markup_collect_attributes (element_name, attribute_names,
          attribute_values, error,
          G_MARKUP_COLLECT_STRING, "context", &context,
          G_MARKUP_COLLECT_STRING, "action", &action,
          G_MARKUP_COLLECT_STRING, "key", &key,
          G_MARKUP_COLLECT_INVALID))
      return;

    if (!BindKey(context, action, key)) {
      *error = g_error_new(g_markup_error_quark(), G_MARKUP_ERROR_INVALID_CONTENT,
          _("Unrecognized key '%s'"), key);
      return;
    }
  }
  else
    *error = g_error_new(g_markup_error_quark(), G_MARKUP_ERROR_PARSE,
        _("Unexpected element '%s'"), element_name);
}
Example #9
0
static void
parse_signal (ParserData   *data,
              const gchar  *element_name,
              const gchar **names,
              const gchar **values,
              GError      **error)
{
  SignalInfo *info;
  const gchar *name;
  const gchar *handler = NULL;
  const gchar *object = NULL;
  gboolean after = FALSE;
  gboolean swapped = -1;
  ObjectInfo *object_info;
  guint id = 0;
  GQuark detail = 0;

  object_info = state_peek_info (data, ObjectInfo);
  if (!object_info ||
      !(strcmp (object_info->tag.name, "object") == 0 ||
        strcmp (object_info->tag.name, "template") == 0))
    {
      error_invalid_tag (data, element_name, NULL, error);
      return;
    }

  if (!g_markup_collect_attributes (element_name, names, values, error,
                                    G_MARKUP_COLLECT_STRING, "name", &name,
                                    G_MARKUP_COLLECT_STRING, "handler", &handler,
                                    G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "object", &object,
                                    G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "last_modification_time", NULL,
                                    G_MARKUP_COLLECT_BOOLEAN|G_MARKUP_COLLECT_OPTIONAL, "after", &after,
                                    G_MARKUP_COLLECT_TRISTATE|G_MARKUP_COLLECT_OPTIONAL, "swapped", &swapped,
                                    G_MARKUP_COLLECT_INVALID))
    {
      _gtk_builder_prefix_error (data->builder, data->ctx, error);
      return;
    }

  if (!g_signal_parse_name (name, object_info->type, &id, &detail, FALSE))
    {
      g_set_error (error,
                   GTK_BUILDER_ERROR,
                   GTK_BUILDER_ERROR_INVALID_SIGNAL,
                   "Invalid signal '%s' for type '%s'",
                   name, g_type_name (object_info->type));
      _gtk_builder_prefix_error (data->builder, data->ctx, error);
      return;
    }

  /* Swapped defaults to FALSE except when object is set */
  if (swapped == -1)
    {
      if (object)
        swapped = TRUE;
      else
        swapped = FALSE;
    }

  info = g_slice_new0 (SignalInfo);
  info->id = id;
  info->detail = detail;
  info->handler = g_strdup (handler);
  if (after)
    info->flags |= G_CONNECT_AFTER;
  if (swapped)
    info->flags |= G_CONNECT_SWAPPED;
  info->connect_object_name = g_strdup (object);
  state_push (data, info);

  info->tag.name = element_name;
}
Example #10
0
static void
parse_property (ParserData   *data,
                const gchar  *element_name,
                const gchar **names,
                const gchar **values,
                GError      **error)
{
  PropertyInfo *info;
  const gchar *name = NULL;
  const gchar *context = NULL;
  const gchar *bind_source = NULL;
  const gchar *bind_property = NULL;
  const gchar *bind_flags_str = NULL;
  GBindingFlags bind_flags = G_BINDING_DEFAULT;
  gboolean translatable = FALSE;
  ObjectInfo *object_info;
  GParamSpec *pspec = NULL;
  gint line, col;

  object_info = state_peek_info (data, ObjectInfo);
  if (!object_info ||
      !(strcmp (object_info->tag.name, "object") == 0 ||
        strcmp (object_info->tag.name, "template") == 0))
    {
      error_invalid_tag (data, element_name, NULL, error);
      return;
    }

  if (!g_markup_collect_attributes (element_name, names, values, error,
                                    G_MARKUP_COLLECT_STRING, "name", &name,
                                    G_MARKUP_COLLECT_BOOLEAN|G_MARKUP_COLLECT_OPTIONAL, "translatable", &translatable,
                                    G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "comments", NULL,
                                    G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "context", &context,
                                    G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "bind-source", &bind_source,
                                    G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "bind-property", &bind_property,
                                    G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "bind-flags", &bind_flags_str,
                                    G_MARKUP_COLLECT_INVALID))
    {
      _gtk_builder_prefix_error (data->builder, data->ctx, error);
      return;
    }

  pspec = g_object_class_find_property (object_info->oclass, name);

  if (!pspec)
    {
      g_set_error (error,
                   GTK_BUILDER_ERROR,
                   GTK_BUILDER_ERROR_INVALID_PROPERTY,
                   "Invalid property: %s.%s",
                   g_type_name (object_info->type), name);
      _gtk_builder_prefix_error (data->builder, data->ctx, error);
      return;
    }

  if (bind_flags_str)
    {
      if (!_gtk_builder_flags_from_string (G_TYPE_BINDING_FLAGS, NULL, bind_flags_str, &bind_flags, error))
        {
          _gtk_builder_prefix_error (data->builder, data->ctx, error);
          return;
        }
    }

  g_markup_parse_context_get_position (data->ctx, &line, &col);

  if (bind_source && bind_property)
    {
      BindingInfo *binfo;

      binfo = g_slice_new (BindingInfo);
      binfo->target = NULL;
      binfo->target_pspec = pspec;
      binfo->source = g_strdup (bind_source);
      binfo->source_property = g_strdup (bind_property);
      binfo->flags = bind_flags;
      binfo->line = line;
      binfo->col = col;

      object_info->bindings = g_slist_prepend (object_info->bindings, binfo);
    }
  else if (bind_source || bind_property)
    {
      error_missing_attribute (data, element_name,
                               (bind_source) ? "bind-property" : "bind-source",
                               error);
      return;
    }

  info = g_slice_new (PropertyInfo);
  info->tag.name = element_name;
  info->pspec = pspec;
  info->text = g_string_new ("");
  info->translatable = translatable;
  info->bound = (bind_source && bind_property);
  info->context = g_strdup (context);
  info->line = line;
  info->col = col;

  state_push (data, info);
}
Example #11
0
static void
parse_template (GMarkupParseContext  *context,
                ParserData           *data,
                const gchar          *element_name,
                const gchar         **names,
                const gchar         **values,
                GError              **error)
{
  ObjectInfo *object_info;
  const gchar *object_class = NULL;
  const gchar *parent_class = NULL;
  gint line;
  GType template_type;
  GType parsed_type;

  template_type = _gtk_builder_get_template_type (data->builder);

  if (!g_markup_collect_attributes (element_name, names, values, error,
                                    G_MARKUP_COLLECT_STRING, "class", &object_class,
                                    G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "parent", &parent_class,
                                    G_MARKUP_COLLECT_INVALID))
    {
      _gtk_builder_prefix_error (data->builder, data->ctx, error);
      return;
    }

  if (template_type == 0)
    {
      g_set_error (error,
                   GTK_BUILDER_ERROR,
                   GTK_BUILDER_ERROR_UNHANDLED_TAG,
                   "Not expecting to handle a template (class '%s', parent '%s')",
                   object_class, parent_class ? parent_class : "GtkWidget");
      _gtk_builder_prefix_error (data->builder, context, error);
      return;
    }
  else if (state_peek (data) != NULL)
    {
      error_invalid_tag (data, "template", NULL, error);
      return;
    }

  parsed_type = g_type_from_name (object_class);
  if (template_type != parsed_type)
    {
      g_set_error (error,
                   GTK_BUILDER_ERROR,
                   GTK_BUILDER_ERROR_TEMPLATE_MISMATCH,
                   "Parsed template definition for type '%s', expected type '%s'",
                   object_class, g_type_name (template_type));
      _gtk_builder_prefix_error (data->builder, context, error);
      return;
    }

  if (parent_class)
    {
      GType parent_type = g_type_from_name (parent_class);
      GType expected_type = g_type_parent (parsed_type);

      if (parent_type == G_TYPE_INVALID)
        {
          g_set_error (error, GTK_BUILDER_ERROR,
                       GTK_BUILDER_ERROR_INVALID_VALUE,
                       "Invalid template parent type '%s'", parent_class);
          _gtk_builder_prefix_error (data->builder, context, error);
          return;
        }
      if (parent_type != expected_type)
        {
          g_set_error (error, GTK_BUILDER_ERROR,
                       GTK_BUILDER_ERROR_TEMPLATE_MISMATCH,
                       "Template parent type '%s' does not match instance parent type '%s'.",
                       parent_class, g_type_name (expected_type));
          _gtk_builder_prefix_error (data->builder, context, error);
          return;
        }
    }

  ++data->cur_object_level;

  object_info = g_slice_new0 (ObjectInfo);
  object_info->tag.name = element_name;
  object_info->type = parsed_type;
  object_info->oclass = g_type_class_ref (parsed_type);
  object_info->id = g_strdup (object_class);
  object_info->object = gtk_builder_get_object (data->builder, object_class);
  state_push (data, object_info);

  line = GPOINTER_TO_INT (g_hash_table_lookup (data->object_ids, object_class));
  if (line != 0)
    {
      g_set_error (error,
                   GTK_BUILDER_ERROR,
                   GTK_BUILDER_ERROR_DUPLICATE_ID,
                   "Duplicate object ID '%s' (previously on line %d)",
                   object_class, line);
      _gtk_builder_prefix_error (data->builder, context, error);
      return;
    }

  g_markup_parse_context_get_position (context, &line, NULL);
  g_hash_table_insert (data->object_ids, g_strdup (object_class), GINT_TO_POINTER (line));
}
Example #12
0
static void
parse_object (GMarkupParseContext  *context,
              ParserData           *data,
              const gchar          *element_name,
              const gchar         **names,
              const gchar         **values,
              GError              **error)
{
  ObjectInfo *object_info;
  ChildInfo* child_info;
  GType object_type = G_TYPE_INVALID;
  const gchar *object_class = NULL;
  const gchar *constructor = NULL;
  const gchar *type_func = NULL;
  const gchar *object_id = NULL;
  gchar *internal_id = NULL;
  gint line;

  child_info = state_peek_info (data, ChildInfo);
  if (child_info && strcmp (child_info->tag.name, "object") == 0)
    {
      error_invalid_tag (data, element_name, NULL, error);
      return;
    }

  if (!g_markup_collect_attributes (element_name, names, values, error,
                                    G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "class", &object_class,
                                    G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "constructor", &constructor,
                                    G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "type-func", &type_func,
                                    G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "id", &object_id,
                                    G_MARKUP_COLLECT_INVALID))
    {
      _gtk_builder_prefix_error (data->builder, data->ctx, error);
      return;
    }

  if (type_func)
    {
      /* Call the GType function, and return the GType, it's guaranteed afterwards
       * that g_type_from_name on the name will return our GType
       */
      object_type = _get_type_by_symbol (type_func);
      if (object_type == G_TYPE_INVALID)
        {
          g_set_error (error,
                       GTK_BUILDER_ERROR,
                       GTK_BUILDER_ERROR_INVALID_TYPE_FUNCTION,
                       "Invalid type function '%s'", type_func);
          _gtk_builder_prefix_error (data->builder, context, error);
          return;
        }
    }
  else if (object_class)
    {
      object_type = gtk_builder_get_type_from_name (data->builder, object_class);
      if (object_type == G_TYPE_INVALID)
        {
          g_set_error (error,
                       GTK_BUILDER_ERROR,
                       GTK_BUILDER_ERROR_INVALID_VALUE,
                       "Invalid object type '%s'", object_class);
          _gtk_builder_prefix_error (data->builder, context, error);
          return;
       }
    }
  else
    {
      error_missing_attribute (data, element_name, "class", error);
      return;
    }

  if (!object_id)
    {
      internal_id = g_strdup_printf ("___object_%d___", ++data->object_counter);
      object_id = internal_id;
    }

  ++data->cur_object_level;

  /* check if we reached a requested object (if it is specified) */
  if (data->requested_objects && !data->inside_requested_object)
    {
      if (is_requested_object (object_id, data))
        {
          data->requested_object_level = data->cur_object_level;

          GTK_NOTE (BUILDER,
                    g_message ("requested object \"%s\" found at level %d",
                               object_id, data->requested_object_level));

          data->inside_requested_object = TRUE;
        }
      else
        {
          g_free (internal_id);
          return;
        }
    }

  object_info = g_slice_new0 (ObjectInfo);
  object_info->tag.name = element_name;
  object_info->type = object_type;
  object_info->oclass = g_type_class_ref (object_type);
  object_info->id = (internal_id) ? internal_id : g_strdup (object_id);
  object_info->constructor = g_strdup (constructor);
  object_info->parent = (CommonInfo*)child_info;
  state_push (data, object_info);

  line = GPOINTER_TO_INT (g_hash_table_lookup (data->object_ids, object_id));
  if (line != 0)
    {
      g_set_error (error,
                   GTK_BUILDER_ERROR,
                   GTK_BUILDER_ERROR_DUPLICATE_ID,
                   "Duplicate object ID '%s' (previously on line %d)",
                   object_id, line);
      _gtk_builder_prefix_error (data->builder, context, error);
      return;
    }

  g_markup_parse_context_get_position (context, &line, NULL);
  g_hash_table_insert (data->object_ids, g_strdup (object_id), GINT_TO_POINTER (line));
}
static void
views_parser_start_element (GMarkupParseContext  *context,
                            const gchar          *element_name,
                            const gchar         **attribute_names,
                            const gchar         **attribute_values,
                            gpointer              user_data,
                            GError              **error)
{
  ViewsParserData *parser_data = user_data;
  GtkWidget *item;

  g_assert (context != NULL);
  g_assert (element_name != NULL);
  g_assert (parser_data != NULL);

  if (g_strcmp0 (element_name, "views") == 0)
    {
    }
  else if (g_strcmp0 (element_name, "view") == 0)
    {
      const gchar *name = NULL;

      if (!check_parent (context, "views", error))
        return;

      if (!g_markup_collect_attributes (element_name, attribute_names, attribute_values, error,
                                        G_MARKUP_COLLECT_STRING, "name", &name,
                                        G_MARKUP_COLLECT_INVALID))
        return;

      item = g_object_new (GB_TYPE_SHORTCUTS_VIEW,
                           "view-name", name,
                           "visible", TRUE,
                           NULL);

      g_queue_push_head (parser_data->stack, g_object_ref_sink (item));
    }
  else if (g_strcmp0 (element_name, "page") == 0)
    {
      if (!check_parent (context, "view", error))
        return;

      item = g_object_new (GB_TYPE_SHORTCUTS_PAGE,
                           "visible", TRUE,
                           NULL);
      g_queue_push_head (parser_data->stack, g_object_ref_sink (item));
    }
  else if (g_strcmp0 (element_name, "column") == 0)
    {
      GtkSizeGroup *size_group;

      if (!check_parent (context, "page", error))
        return;

      size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
      g_queue_push_head (parser_data->column_image_size_groups, size_group);

      size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
      g_queue_push_head (parser_data->column_desc_size_groups, size_group);

      item = g_object_new (GB_TYPE_SHORTCUTS_COLUMN,
                           "visible", TRUE,
                           NULL);
      g_queue_push_head (parser_data->stack, g_object_ref_sink (item));
    }
  else if (g_strcmp0 (element_name, "group") == 0)
    {
      if (!check_parent (context, "column", error))
        return;

      item = g_object_new (GB_TYPE_SHORTCUTS_GROUP,
                           "visible", TRUE,
                           NULL);
      g_queue_push_head (parser_data->stack, g_object_ref_sink (item));
    }
  else if (g_strcmp0 (element_name, "shortcut") == 0)
    {
      GtkSizeGroup *accel_size_group;
      GtkSizeGroup *desc_size_group;

      if (!check_parent (context, "group", error))
        return;

      accel_size_group = g_queue_peek_head (parser_data->column_image_size_groups);
      desc_size_group = g_queue_peek_head (parser_data->column_desc_size_groups);

      parser_data->search_item = g_object_new (GB_TYPE_SHORTCUTS_SHORTCUT,
                                               "visible", TRUE,
                                               NULL);

      item = g_object_new (GB_TYPE_SHORTCUTS_SHORTCUT,
                           "accelerator-size-group", accel_size_group,
                           "title-size-group", desc_size_group,
                           "visible", TRUE,
                           NULL);
      g_queue_push_head (parser_data->stack, g_object_ref_sink (item));
    }
  else if (g_strcmp0 (element_name, "gesture") == 0)
    {
      GtkSizeGroup *accel_size_group;
      GtkSizeGroup *desc_size_group;

      if (!check_parent (context, "group", error))
        return;

      accel_size_group = g_queue_peek_head (parser_data->column_image_size_groups);
      desc_size_group = g_queue_peek_head (parser_data->column_desc_size_groups);

      parser_data->search_item = g_object_new (GB_TYPE_SHORTCUTS_GESTURE,
                                               "visible", TRUE,
                                               NULL);

      item = g_object_new (GB_TYPE_SHORTCUTS_GESTURE,
                           "desc-size-group", desc_size_group,
                           "icon-size-group", accel_size_group,
                           "visible", TRUE,
                           NULL);
      g_queue_push_head (parser_data->stack, g_object_ref_sink (item));
    }
  else if (g_strcmp0 (element_name, "property") == 0)
    {
      const gchar *name = NULL;
      const gchar *translatable = NULL;

      item = g_queue_peek_head (parser_data->stack);

      if (item == NULL)
        {
          g_set_error (error,
                       GTK_BUILDER_ERROR,
                       GTK_BUILDER_ERROR_INVALID_TAG,
                       "Property called without a parent object");
          return;
        }

      if (!g_markup_collect_attributes (element_name, attribute_names, attribute_values, error,
                                        G_MARKUP_COLLECT_STRING, "name", &name,
                                        G_MARKUP_COLLECT_OPTIONAL | G_MARKUP_COLLECT_STRING, "translatable", &translatable,
                                        G_MARKUP_COLLECT_INVALID))
        return;

      g_free (parser_data->property_name);
      parser_data->property_name = g_strdup (name);
      parser_data->translatable = (g_strcmp0 (translatable, "yes") == 0);
    }
  else
    {
      const GSList *stack;
      const gchar *parent_name;
      const gchar *our_name;
      gint line;
      gint col;

      stack = g_markup_parse_context_get_element_stack (context);
      our_name = stack->data;
      parent_name = stack->next ? stack->next->data : "";

      g_markup_parse_context_get_position (context, &line, &col);
      g_set_error (error,
                   GTK_BUILDER_ERROR,
                   GTK_BUILDER_ERROR_INVALID_TAG,
                   "%d:%d: Unknown element <%s> found in <%s>.",
                   line, col, our_name, parent_name);
    }
}
static void
parse_start_element (GMarkupParseContext  *context,
                     const gchar          *element_name,
                     const gchar         **attribute_names,
                     const gchar         **attribute_values,
                     gpointer              data,
                     GError              **error)
{
  GnomeXkbInfoPrivate *priv = GNOME_XKB_INFO (data)->priv;

  if (priv->current_parser_text)
    {
      g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
                   "Expected character data but got element '%s'", element_name);
      return;
    }

  if (strcmp (element_name, "name") == 0)
    {
      if (priv->current_parser_variant)
        priv->current_parser_text = &priv->current_parser_variant->xkb_name;
      else if (priv->current_parser_layout)
        priv->current_parser_text = &priv->current_parser_layout->xkb_name;
      else if (priv->current_parser_option)
        priv->current_parser_text = &priv->current_parser_option->id;
      else if (priv->current_parser_group)
        priv->current_parser_text = &priv->current_parser_group->id;
    }
  else if (strcmp (element_name, "description") == 0)
    {
      if (priv->current_parser_variant)
        priv->current_parser_text = &priv->current_parser_variant->description;
      else if (priv->current_parser_layout)
        priv->current_parser_text = &priv->current_parser_layout->description;
      else if (priv->current_parser_option)
        priv->current_parser_text = &priv->current_parser_option->description;
      else if (priv->current_parser_group)
        priv->current_parser_text = &priv->current_parser_group->description;
    }
  else if (strcmp (element_name, "shortDescription") == 0)
    {
      if (priv->current_parser_variant)
        priv->current_parser_text = &priv->current_parser_variant->short_desc;
      else if (priv->current_parser_layout)
        priv->current_parser_text = &priv->current_parser_layout->short_desc;
    }
  else if (strcmp (element_name, "iso639Id") == 0)
    {
      priv->current_parser_text = &priv->current_parser_iso639Id;
    }
  else if (strcmp (element_name, "layout") == 0)
    {
      if (priv->current_parser_layout)
        {
          g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
                       "'layout' elements can't be nested");
          return;
        }

      priv->current_parser_layout = g_slice_new0 (Layout);
    }
  else if (strcmp (element_name, "variant") == 0)
    {
      Layout *layout;

      if (priv->current_parser_variant)
        {
          g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
                       "'variant' elements can't be nested");
          return;
        }

      if (!priv->current_parser_layout)
        {
          g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
                       "'variant' elements must be inside 'layout' elements");
          return;
        }

      if (!priv->current_parser_layout->xkb_name)
        {
          g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
                       "'variant' elements must be inside named 'layout' elements");
          return;
        }

      layout = g_hash_table_lookup (priv->layouts_table, priv->current_parser_layout->xkb_name);
      if (!layout)
        layout = priv->current_parser_layout;

      priv->current_parser_variant = g_slice_new0 (Layout);
      priv->current_parser_variant->is_variant = TRUE;
      priv->current_parser_variant->main_layout = layout;
    }
  else if (strcmp (element_name, "group") == 0)
    {
      if (priv->current_parser_group)
        {
          g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
                       "'group' elements can't be nested");
          return;
        }

      priv->current_parser_group = g_slice_new0 (XkbOptionGroup);
      /* Maps option ids to XkbOption structs. Owns the XkbOption structs. */
      priv->current_parser_group->options_table = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                                         NULL, free_option);
      g_markup_collect_attributes (element_name,
                                   attribute_names,
                                   attribute_values,
                                   error,
                                   G_MARKUP_COLLECT_BOOLEAN | G_MARKUP_COLLECT_OPTIONAL,
                                   "allowMultipleSelection",
                                   &priv->current_parser_group->allow_multiple_selection,
                                   G_MARKUP_COLLECT_INVALID);
    }
  else if (strcmp (element_name, "option") == 0)
    {
      if (priv->current_parser_option)
        {
          g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
                       "'option' elements can't be nested");
          return;
        }

      if (!priv->current_parser_group)
        {
          g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
                       "'option' elements must be inside 'group' elements");
          return;
        }

      priv->current_parser_option = g_slice_new0 (XkbOption);
    }
}
static void
parse_start (GMarkupParseContext * ctx, const gchar * element_name,
    const gchar ** attr_names, const gchar ** attr_vals,
    gpointer user_data, GError ** err)
{
  License *license = user_data;
  const gchar *ref = NULL;
  int i;

  for (i = 0; i < G_N_ELEMENTS (tag_map); ++i) {
    if (strcmp (element_name, tag_map[i].element_name) == 0)
      break;
  }

  if (i == G_N_ELEMENTS (tag_map))
    g_error ("Unexpected tag '%s'\n", element_name);

  if (tag_map[i].attribute == NULL)
    return;

  if (!g_markup_collect_attributes (element_name, attr_names, attr_vals,
          err, G_MARKUP_COLLECT_STRING, tag_map[i].attribute, &ref,
          G_MARKUP_COLLECT_INVALID)) {
    return;
  }

  switch (tag_map[i].element_tag) {
    case TAG_CC_LICENSE:
      if (!g_str_has_prefix (ref, "http://creativecommons.org/licenses/"))
        g_error ("Unexpected license reference: %s\n", ref);
      /* we assume one license per file, and CC license ref */
      g_assert (license->ref == NULL);
      license->ref = g_strdup (ref);
      break;
    case TAG_CC_JURISDICTION:
      if (!g_str_has_prefix (ref, "http://creativecommons.org/international/"))
        g_error ("Unknown license jurisdiction: %s\n", ref);
      /* we assume one jurisdiction per license */
      g_assert (license->jurisdiction == JURISDICTION_GENERIC);
      license->jurisdiction = ref_to_jurisdiction (ref);
      license->jurisdiction_suffix =
          g_strdup (ref + strlen ("http://creativecommons.org/international/"));
      break;
    case TAG_CC_LEGALCODE:
      if (!g_str_has_prefix (ref, "http://creativecommons.org/licenses/"))
        g_error ("Unexpected legalcode reference: %s\n", ref);
      /* we assume one legalcode per license */
      g_assert (license->legalcode == NULL);
      license->legalcode = g_strdup (ref);
      break;
    case TAG_DC_CREATOR:
      if (strcmp (ref, "http://creativecommons.org") == 0) {
        license->flags |= GST_TAG_LICENSE_CREATIVE_COMMONS_LICENSE;
      } else if (strcmp (ref, "http://fsf.org") == 0) {
        license->flags |= GST_TAG_LICENSE_FREE_SOFTWARE_FOUNDATION_LICENSE;
      } else {
        g_error ("Unknown license creator: %s\n", ref);
      }
      break;
    case TAG_CC_DEPRECATED_ON:
      break;
    case TAG_CC_PROHIBITS:
    case TAG_CC_REQUIRES:
    case TAG_CC_PERMITS:
      license->flags |= ref_to_flag (ref);
      break;
    case TAG_DC_TITLE:{
      gchar *cur_lang;

      cur_lang = g_strdelimit (g_strdup (ref), "-", '_');
      license->cur_lang = g_intern_string (cur_lang);
      if (!g_list_find_custom (langs, cur_lang, (GCompareFunc) strcmp))
        langs = g_list_prepend (langs, (gpointer) license->cur_lang);

      g_free (cur_lang);
      break;
    }
    case TAG_DC_DESCRIPTION:{
      gchar *cur_lang;

      cur_lang = g_strdelimit (g_strdup (ref), "-", '_');
      license->cur_lang = g_intern_string (cur_lang);
      if (!g_list_find_custom (langs, cur_lang, (GCompareFunc) strcmp))
        langs = g_list_prepend (langs, (gpointer) license->cur_lang);

      g_free (cur_lang);
      break;
    }
    case TAG_DCQ_IS_REPLACED_BY:
      /* we assume one replacer per license for now */
      g_assert (license->replaced_by == NULL);
      license->replaced_by = g_strdup (ref);
      break;
    case TAG_RDF_DESCRIPTION:
      if (!g_str_has_prefix (ref, "http://creativecommons.org/licenses/"))
        g_error ("Unexpected license reference: %s\n", ref);
      if (license->ref != NULL && strcmp (license->ref, ref) != 0) {
        gchar *f, *r = g_strdup (ref);

        /* work around bug in some of the RDFs ... */
        if ((f = strstr (r, "by-nc-nd"))) {
          memcpy (f, "by-nd-nc", 8);
        }
        if (strcmp (license->ref, r) != 0) {
          g_error ("rdf:Description chunk for other than current license");
        }
        g_free (r);
      }
      break;
    case TAG_DC_SOURCE:
      if (!g_str_has_prefix (ref, "http://creativecommons.org/licenses/"))
        g_error ("Unexpected source reference: %s\n", ref);
      /* we assume one source (for jurisdiction-specific versions) */
      g_assert (license->source == NULL);
      license->source = g_strdup (ref);
      break;
    default:
      g_printerr ("unhandled start tag: %s\n", element_name);
      break;
  }
}