[gtk+/key-themes: 1/8] Add gtk_binding_entry_add_signal_from_string()
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/key-themes: 1/8] Add gtk_binding_entry_add_signal_from_string()
- Date: Fri, 28 Jan 2011 18:41:59 +0000 (UTC)
commit 1039877af7b69cd2b4724abb5cbc02cc4db50c9c
Author: Carlos Garnacho <carlosg gnome org>
Date: Fri Jan 28 01:50:14 2011 +0100
Add gtk_binding_entry_add_signal_from_string()
This function rescues part of the old parser (which
is now standalone) to load a bind/unbind definition
string into a GtkBindingSet.
docs/reference/gtk/gtk3-sections.txt | 1 +
gtk/gtk.symbols | 1 +
gtk/gtkbindings.c | 321 ++++++++++++++++++++++++++++++++++
gtk/gtkbindings.h | 4 +
4 files changed, 327 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt
index c75d5bb..2dab319 100644
--- a/docs/reference/gtk/gtk3-sections.txt
+++ b/docs/reference/gtk/gtk3-sections.txt
@@ -6009,6 +6009,7 @@ gtk_bindings_activate
gtk_bindings_activate_event
gtk_binding_set_activate
gtk_binding_entry_add_signal
+gtk_binding_entry_add_signal_from_string
gtk_binding_entry_skip
gtk_binding_entry_remove
gtk_binding_set_add_path
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index 166539b..f29e38a 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -254,6 +254,7 @@ gtk_assistant_update_buttons_state
gtk_attach_options_get_type G_GNUC_CONST
gtk_binding_entry_add_signal
gtk_binding_entry_add_signall
+gtk_binding_entry_add_signal_from_string
gtk_binding_entry_remove
gtk_binding_entry_skip
gtk_bindings_activate
diff --git a/gtk/gtkbindings.c b/gtk/gtkbindings.c
index 70a6418..65eda70 100644
--- a/gtk/gtkbindings.c
+++ b/gtk/gtkbindings.c
@@ -53,6 +53,10 @@ typedef struct {
guint seq_id;
} PatternSpec;
+typedef enum {
+ GTK_BINDING_TOKEN_BIND,
+ GTK_BINDING_TOKEN_UNBIND
+} GtkBindingTokens;
/* --- variables --- */
static GHashTable *binding_entry_hash_table = NULL;
@@ -978,6 +982,323 @@ gtk_binding_entry_add_signal (GtkBindingSet *binding_set,
g_slist_free (free_slist);
}
+static guint
+gtk_binding_parse_signal (GScanner *scanner,
+ GtkBindingSet *binding_set,
+ guint keyval,
+ GdkModifierType modifiers)
+{
+ gchar *signal;
+ guint expected_token = 0;
+ GSList *args;
+ GSList *slist;
+ gboolean done;
+ gboolean negate;
+ gboolean need_arg;
+ gboolean seen_comma;
+
+ g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
+
+ g_scanner_get_next_token (scanner);
+
+ if (scanner->token != G_TOKEN_STRING)
+ return G_TOKEN_STRING;
+
+ g_scanner_peek_next_token (scanner);
+
+ if (scanner->next_token != '(')
+ {
+ g_scanner_get_next_token (scanner);
+ return '(';
+ }
+
+ signal = g_strdup (scanner->value.v_string);
+ g_scanner_get_next_token (scanner);
+
+ negate = FALSE;
+ args = NULL;
+ done = FALSE;
+ need_arg = TRUE;
+ seen_comma = FALSE;
+ scanner->config->scan_symbols = FALSE;
+
+ do
+ {
+ GtkBindingArg *arg;
+
+ if (need_arg)
+ expected_token = G_TOKEN_INT;
+ else
+ expected_token = ')';
+
+ g_scanner_get_next_token (scanner);
+
+ switch ((guint) scanner->token)
+ {
+ case G_TOKEN_FLOAT:
+ if (need_arg)
+ {
+ need_arg = FALSE;
+ arg = g_new (GtkBindingArg, 1);
+ arg->arg_type = G_TYPE_DOUBLE;
+ arg->d.double_data = scanner->value.v_float;
+
+ if (negate)
+ {
+ arg->d.double_data = - arg->d.double_data;
+ negate = FALSE;
+ }
+ args = g_slist_prepend (args, arg);
+ }
+ else
+ done = TRUE;
+
+ break;
+ case G_TOKEN_INT:
+ if (need_arg)
+ {
+ need_arg = FALSE;
+ arg = g_new (GtkBindingArg, 1);
+ arg->arg_type = G_TYPE_LONG;
+ arg->d.long_data = scanner->value.v_int;
+
+ if (negate)
+ {
+ arg->d.long_data = - arg->d.long_data;
+ negate = FALSE;
+ }
+ args = g_slist_prepend (args, arg);
+ }
+ else
+ done = TRUE;
+ break;
+ case G_TOKEN_STRING:
+ if (need_arg && !negate)
+ {
+ need_arg = FALSE;
+ arg = g_new (GtkBindingArg, 1);
+ arg->arg_type = G_TYPE_STRING;
+ arg->d.string_data = g_strdup (scanner->value.v_string);
+ args = g_slist_prepend (args, arg);
+ }
+ else
+ done = TRUE;
+
+ break;
+ case G_TOKEN_IDENTIFIER:
+ if (need_arg && !negate)
+ {
+ need_arg = FALSE;
+ arg = g_new (GtkBindingArg, 1);
+ arg->arg_type = GTK_TYPE_IDENTIFIER;
+ arg->d.string_data = g_strdup (scanner->value.v_identifier);
+ args = g_slist_prepend (args, arg);
+ }
+ else
+ done = TRUE;
+
+ break;
+ case '-':
+ if (!need_arg)
+ done = TRUE;
+ else if (negate)
+ {
+ expected_token = G_TOKEN_INT;
+ done = TRUE;
+ }
+ else
+ negate = TRUE;
+
+ break;
+ case ',':
+ seen_comma = TRUE;
+ if (need_arg)
+ done = TRUE;
+ else
+ need_arg = TRUE;
+
+ break;
+ case ')':
+ if (!(need_arg && seen_comma) && !negate)
+ {
+ args = g_slist_reverse (args);
+ _gtk_binding_entry_add_signall (binding_set,
+ keyval,
+ modifiers,
+ signal,
+ args);
+ expected_token = G_TOKEN_NONE;
+ }
+
+ done = TRUE;
+ break;
+ default:
+ done = TRUE;
+ break;
+ }
+ }
+ while (!done);
+
+ scanner->config->scan_symbols = TRUE;
+
+ for (slist = args; slist; slist = slist->next)
+ {
+ GtkBindingArg *arg;
+
+ 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
+ * a signal:
+ * <informalexample><programlisting>
+ * bind <replaceable>key</replaceable> {
+ * <replaceable>signalname</replaceable> (<replaceable>param</replaceable>, ...)
+ * ...
+ * }
+ * </programlisting></informalexample>
+ *
+ * Or they may also unbind a key combination:
+ * <informalexample><programlisting>
+ * unbind <replaceable>key</replaceable>
+ * </programlisting></informalexample>
+ *
+ * Key combinations must be in a format that can be parsed by
+ * gtk_accelerator_parse().
+ *
+ * Since: 3.0
+ **/
+void
+gtk_binding_entry_add_signal_from_string (GtkBindingSet *binding_set,
+ const gchar *signal_desc)
+{
+ static GScanner *scanner = NULL;
+ GTokenType ret;
+
+ g_return_if_fail (binding_set != NULL);
+ g_return_if_fail (signal_desc != NULL);
+
+ 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);
+
+ if (ret != G_TOKEN_NONE)
+ g_scanner_unexp_token (scanner, ret, NULL, NULL, NULL,
+ "Could not parse binding", FALSE);
+
+ /* Reset for next use */
+ g_scanner_set_scope (scanner, 0);
+}
+
/**
* gtk_binding_set_add_path:
* @binding_set: a #GtkBindingSet to add a path to
diff --git a/gtk/gtkbindings.h b/gtk/gtkbindings.h
index 260eeb8..4529567 100644
--- a/gtk/gtkbindings.h
+++ b/gtk/gtkbindings.h
@@ -124,6 +124,10 @@ void gtk_binding_entry_add_signall (GtkBindingSet *binding_set,
GdkModifierType modifiers,
const gchar *signal_name,
GSList *binding_args);
+
+void gtk_binding_entry_add_signal_from_string (GtkBindingSet *binding_set,
+ const gchar *signal_desc);
+
void gtk_binding_entry_remove (GtkBindingSet *binding_set,
guint keyval,
GdkModifierType modifiers);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]