+ arg = slist->data;
+
+ if (G_TYPE_FUNDAMENTAL (arg->arg_type) == G_TYPE_STRING)
+ g_free (arg->d.string_data);
+ g_free (arg);
+ }
+
+ g_slist_free (args);
+ g_free (signal);
+
+ return expected_token;
+}
+
+static inline guint
+gtk_binding_parse_bind (GScanner *scanner,
+ GtkBindingSet *binding_set)
+{
+ guint keyval = 0;
+ GdkModifierType modifiers = 0;
+ gboolean unbind = FALSE;
+
+ g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
+
+ g_scanner_get_next_token (scanner);
+
+ if (scanner->token != G_TOKEN_SYMBOL)
+ return G_TOKEN_SYMBOL;
+
+ if (scanner->value.v_symbol != GUINT_TO_POINTER (GTK_BINDING_TOKEN_BIND) &&
+ scanner->value.v_symbol != GUINT_TO_POINTER (GTK_BINDING_TOKEN_UNBIND))
+ return G_TOKEN_SYMBOL;
+
+ unbind = (scanner->value.v_symbol == GUINT_TO_POINTER (GTK_BINDING_TOKEN_UNBIND));
+ g_scanner_get_next_token (scanner);
+
+ if (scanner->token != (guint) G_TOKEN_STRING)
+ return G_TOKEN_STRING;
+
+ gtk_accelerator_parse (scanner->value.v_string, &keyval, &modifiers);
+ modifiers &= BINDING_MOD_MASK ();
+
+ if (keyval == 0)
+ return G_TOKEN_STRING;
+
+ if (unbind)
+ {
+ gtk_binding_entry_skip (binding_set, keyval, modifiers);
+ return G_TOKEN_NONE;
+ }
+
+ g_scanner_get_next_token (scanner);
+
+ if (scanner->token != '{')
+ return '{';
+
+ gtk_binding_entry_clear_internal (binding_set, keyval, modifiers);
+ g_scanner_peek_next_token (scanner);
+
+ while (scanner->next_token != '}')
+ {
+ guint expected_token;
+
+ switch (scanner->next_token)
+ {
+ case G_TOKEN_STRING:
+ expected_token = gtk_binding_parse_signal (scanner,
+ binding_set,
+ keyval,
+ modifiers);
+ if (expected_token != G_TOKEN_NONE)
+ return expected_token;
+ break;
+ default:
+ g_scanner_get_next_token (scanner);
+ return '}';
+ }
+
+ g_scanner_peek_next_token (scanner);
+ }
+
+ g_scanner_get_next_token (scanner);
+
+ return G_TOKEN_NONE;
+}
+
+static GScanner *
+create_signal_scanner (void)
+{
+ GScanner *scanner;
+
+ scanner = g_scanner_new (NULL);
+ scanner->config->cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "-_";
+
+ g_scanner_scope_add_symbol (scanner, 0, "bind", GUINT_TO_POINTER (GTK_BINDING_TOKEN_BIND));
+ g_scanner_scope_add_symbol (scanner, 0, "unbind", GUINT_TO_POINTER (GTK_BINDING_TOKEN_UNBIND));
+
+ g_scanner_set_scope (scanner, 0);
+
+ return scanner;
+}
+
+/**
+ * gtk_binding_entry_add_signal_from_string:
+ * @binding_set: a #GtkBindingSet
+ * @signal_desc: a signal description
+ *
+ * Parses a signal description from @signal_desc and incorporates
+ * it into @binding_set.
+ *
+ * Signal descriptions may either bind a key combination to
+ * one or more signals:
+ * <informalexample><programlisting>
+ * bind "key" {
+ * "signalname" (param, ...)
+ * ...
+ * }
+ * </programlisting></informalexample>
+ *
+ * Or they may also unbind a key combination:
+ * <informalexample><programlisting>
+ * unbind "key"
+ * </programlisting></informalexample>
+ *
+ * Key combinations must be in a format that can be parsed by
+ * gtk_accelerator_parse().
+ *
+ * Returns: %G_TOKEN_NONE if the signal was successfully parsed and added,
+ * the expected token otherwise
+ *
+ * Since: 3.0
+ */
+GTokenType
+gtk_binding_entry_add_signal_from_string (GtkBindingSet *binding_set,
+ const gchar *signal_desc)
+{
+ static GScanner *scanner = NULL;
+ GTokenType ret;
+
+ g_return_val_if_fail (binding_set != NULL, G_TOKEN_NONE);
+ g_return_val_if_fail (signal_desc != NULL, G_TOKEN_NONE);
+
+ if (G_UNLIKELY (!scanner))
+ scanner = create_signal_scanner ();
+
+ g_scanner_input_text (scanner, signal_desc,
+ (guint) strlen (signal_desc));
+
+ ret = gtk_binding_parse_bind (scanner, binding_set);
+
+ /* Reset for next use */
+ g_scanner_set_scope (scanner, 0);
+
+ return ret;
+}
+
+/**
+ * gtk_binding_set_add_path:
+ * @binding_set: a #GtkBindingSet to add a path to
+ * @path_type: path type the pattern applies to
+ * @path_pattern: the actual match pattern
+ * @priority: binding priority
+ *
+ * This function was used internally by the GtkRC parsing mechanism
+ * to assign match patterns to #GtkBindingSet structures.
+ *
+ * In GTK+ 3, these match patterns are unused.
+ *
+ * Deprecated: 3.0
+ */
+void
+gtk_binding_set_add_path (GtkBindingSet *binding_set,
+ GtkPathType path_type,
+ const gchar *path_pattern,
+ GtkPathPriorityType priority)
+{
+ PatternSpec *pspec;
+ GSList **slist_p, *slist;
+ static guint seq_id = 0;
+
+ g_return_if_fail (binding_set != NULL);
+ g_return_if_fail (path_pattern != NULL);
+ g_return_if_fail (priority <= GTK_PATH_PRIO_MASK);
+
+ priority &= GTK_PATH_PRIO_MASK;
+
+ switch (path_type)
+ {
+ case GTK_PATH_WIDGET:
+ slist_p = &binding_set->widget_path_pspecs;
+ break;
+ case GTK_PATH_WIDGET_CLASS:
+ slist_p = &binding_set->widget_class_pspecs;
+ break;
+ case GTK_PATH_CLASS:
+ slist_p = &binding_set->class_branch_pspecs;
+ break;
+ default:
+ g_assert_not_reached ();
+ slist_p = NULL;
+ break;
+ }
+
+ pspec = g_new (PatternSpec, 1);
+ pspec->type = path_type;
+ if (path_type == GTK_PATH_WIDGET_CLASS)
+ pspec->pspec = NULL;
+ else
+ pspec->pspec = g_pattern_spec_new (path_pattern);
+
+ pspec->seq_id = priority << 28;
+ pspec->user_data = binding_set;
+
+ slist = *slist_p;
+ while (slist)
+ {
+ PatternSpec *tmp_pspec;
+
+ tmp_pspec = slist->data;
+ slist = slist->next;
+
+ if (g_pattern_spec_equal (tmp_pspec->pspec, pspec->pspec))
+ {
+ GtkPathPriorityType lprio = tmp_pspec->seq_id >> 28;
+
+ pattern_spec_free (pspec);
+ pspec = NULL;
+ if (lprio < priority)
+ {
+ tmp_pspec->seq_id &= 0x0fffffff;
+ tmp_pspec->seq_id |= priority << 28;
+ }
+ break;
+ }
+ }
+ if (pspec)
+ {
+ pspec->seq_id |= seq_id++ & 0x0fffffff;
+ *slist_p = g_slist_prepend (*slist_p, pspec);
+ }
+}
+
+static gint
+find_entry_with_binding (GtkBindingEntry *entry,
+ GtkBindingSet *binding_set)
+{
+ return (entry->binding_set == binding_set) ? 0 : 1;
+}
+
+static gboolean
+binding_activate (GtkBindingSet *binding_set,
+ GSList *entries,
+ GObject *object,
+ gboolean is_release,
+ gboolean *unbound)
+{
+ GtkBindingEntry *entry;
+ GSList *elem;
+
+ elem = g_slist_find_custom (entries, binding_set,
+ (GCompareFunc) find_entry_with_binding);
+
+ if (!elem)
+ return FALSE;
+
+ entry = elem->data;
+
+ if (is_release != ((entry->modifiers & GDK_RELEASE_MASK) != 0))
+ return FALSE;
+
+ if (entry->marks_unbound)
+ {
+ *unbound = TRUE;
+ return FALSE;
+ }
+
+ if (gtk_binding_entry_activate (entry, object))
+ return TRUE;
+
+ return FALSE;
+}