forked from AuroraMiddleware/gtk
bindings: Add gtk_binding_entry_add_action()
Allows registering bindings for activating widget actions, as an alternative to signal emissions.
This commit is contained in:
parent
01be7f0666
commit
19304c1d2c
@ -5247,6 +5247,8 @@ gtk_binding_set_find
|
|||||||
gtk_bindings_activate
|
gtk_bindings_activate
|
||||||
gtk_bindings_activate_event
|
gtk_bindings_activate_event
|
||||||
gtk_binding_set_activate
|
gtk_binding_set_activate
|
||||||
|
gtk_binding_entry_add_action
|
||||||
|
gtk_binding_entry_add_action_variant
|
||||||
gtk_binding_entry_add_signal
|
gtk_binding_entry_add_signal
|
||||||
gtk_binding_entry_add_signal_from_string
|
gtk_binding_entry_add_signal_from_string
|
||||||
gtk_binding_entry_skip
|
gtk_binding_entry_skip
|
||||||
|
@ -138,6 +138,12 @@ struct _GtkBindingArg
|
|||||||
} d;
|
} d;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
GTK_BINDING_SIGNAL,
|
||||||
|
GTK_BINDING_ACTION
|
||||||
|
} GtkBindingActionType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GtkBindingSignal:
|
* GtkBindingSignal:
|
||||||
* @next: implementation detail
|
* @next: implementation detail
|
||||||
@ -153,8 +159,14 @@ struct _GtkBindingSignal
|
|||||||
{
|
{
|
||||||
GtkBindingSignal *next;
|
GtkBindingSignal *next;
|
||||||
gchar *signal_name;
|
gchar *signal_name;
|
||||||
|
GtkBindingActionType action_type;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
guint n_args;
|
guint n_args;
|
||||||
GtkBindingArg *args;
|
GtkBindingArg *args;
|
||||||
|
};
|
||||||
|
GVariant *variant;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/* --- variables --- */
|
/* --- variables --- */
|
||||||
@ -168,13 +180,14 @@ static GQuark key_id_class_binding_set = 0;
|
|||||||
/* --- functions --- */
|
/* --- functions --- */
|
||||||
|
|
||||||
static GtkBindingSignal*
|
static GtkBindingSignal*
|
||||||
binding_signal_new (const gchar *signal_name,
|
binding_signal_new_signal (const gchar *signal_name,
|
||||||
guint n_args)
|
guint n_args)
|
||||||
{
|
{
|
||||||
GtkBindingSignal *signal;
|
GtkBindingSignal *signal;
|
||||||
|
|
||||||
signal = (GtkBindingSignal *) g_slice_alloc0 (sizeof (GtkBindingSignal) + n_args * sizeof (GtkBindingArg));
|
signal = (GtkBindingSignal *) g_slice_alloc0 (sizeof (GtkBindingSignal) + n_args * sizeof (GtkBindingArg));
|
||||||
signal->next = NULL;
|
signal->next = NULL;
|
||||||
|
signal->action_type = GTK_BINDING_SIGNAL;
|
||||||
signal->signal_name = (gchar *)g_intern_string (signal_name);
|
signal->signal_name = (gchar *)g_intern_string (signal_name);
|
||||||
signal->n_args = n_args;
|
signal->n_args = n_args;
|
||||||
signal->args = (GtkBindingArg *)(signal + 1);
|
signal->args = (GtkBindingArg *)(signal + 1);
|
||||||
@ -182,17 +195,48 @@ binding_signal_new (const gchar *signal_name,
|
|||||||
return signal;
|
return signal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GtkBindingSignal*
|
||||||
|
binding_signal_new_action (const gchar *signal_name,
|
||||||
|
GVariant *variant)
|
||||||
|
{
|
||||||
|
GtkBindingSignal *signal;
|
||||||
|
|
||||||
|
signal = g_slice_new0 (GtkBindingSignal);
|
||||||
|
signal->next = NULL;
|
||||||
|
signal->action_type = GTK_BINDING_ACTION;
|
||||||
|
signal->signal_name = (gchar *)g_intern_string (signal_name);
|
||||||
|
signal->variant = variant;
|
||||||
|
if (variant)
|
||||||
|
g_variant_ref_sink (variant);
|
||||||
|
|
||||||
|
return signal;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
binding_signal_free (GtkBindingSignal *sig)
|
binding_signal_free (GtkBindingSignal *sig)
|
||||||
{
|
{
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
|
switch (sig->action_type)
|
||||||
|
{
|
||||||
|
case GTK_BINDING_SIGNAL:
|
||||||
for (i = 0; i < sig->n_args; i++)
|
for (i = 0; i < sig->n_args; i++)
|
||||||
{
|
{
|
||||||
if (G_TYPE_FUNDAMENTAL (sig->args[i].arg_type) == G_TYPE_STRING)
|
if (G_TYPE_FUNDAMENTAL (sig->args[i].arg_type) == G_TYPE_STRING)
|
||||||
g_free (sig->args[i].d.string_data);
|
g_free (sig->args[i].d.string_data);
|
||||||
}
|
}
|
||||||
g_slice_free1 (sizeof (GtkBindingSignal) + sig->n_args * sizeof (GtkBindingArg), sig);
|
g_slice_free1 (sizeof (GtkBindingSignal) + sig->n_args * sizeof (GtkBindingArg), sig);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GTK_BINDING_ACTION:
|
||||||
|
g_clear_pointer (&sig->variant, g_variant_unref);
|
||||||
|
g_slice_free (GtkBindingSignal, sig);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static guint
|
static guint
|
||||||
@ -560,39 +604,23 @@ binding_compose_params (GObject *object,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gtk_binding_entry_activate (GtkBindingEntry *entry,
|
binding_signal_activate_signal (GtkBindingSignal *sig,
|
||||||
GObject *object)
|
GObject *object)
|
||||||
{
|
{
|
||||||
GtkBindingSignal *sig;
|
|
||||||
gboolean old_emission;
|
|
||||||
gboolean handled = FALSE;
|
|
||||||
gint i;
|
|
||||||
|
|
||||||
old_emission = entry->in_emission;
|
|
||||||
entry->in_emission = TRUE;
|
|
||||||
|
|
||||||
g_object_ref (object);
|
|
||||||
|
|
||||||
for (sig = entry->signals; sig; sig = sig->next)
|
|
||||||
{
|
|
||||||
GSignalQuery query;
|
GSignalQuery query;
|
||||||
guint signal_id;
|
guint signal_id;
|
||||||
GValue *params = NULL;
|
GValue *params = NULL;
|
||||||
GValue return_val = G_VALUE_INIT;
|
GValue return_val = G_VALUE_INIT;
|
||||||
gchar *accelerator = NULL;
|
gboolean handled = FALSE;
|
||||||
|
|
||||||
signal_id = g_signal_lookup (sig->signal_name, G_OBJECT_TYPE (object));
|
signal_id = g_signal_lookup (sig->signal_name, G_OBJECT_TYPE (object));
|
||||||
if (!signal_id)
|
if (!signal_id)
|
||||||
{
|
{
|
||||||
accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
|
g_warning ("gtk_binding_entry_activate(): "
|
||||||
g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
|
|
||||||
"could not find signal \"%s\" in the '%s' class ancestry",
|
"could not find signal \"%s\" in the '%s' class ancestry",
|
||||||
entry->binding_set->set_name,
|
|
||||||
accelerator,
|
|
||||||
sig->signal_name,
|
sig->signal_name,
|
||||||
g_type_name (G_OBJECT_TYPE (object)));
|
g_type_name (G_OBJECT_TYPE (object)));
|
||||||
g_free (accelerator);
|
return FALSE;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_signal_query (signal_id, &query);
|
g_signal_query (signal_id, &query);
|
||||||
@ -600,27 +628,20 @@ gtk_binding_entry_activate (GtkBindingEntry *entry,
|
|||||||
(query.return_type != G_TYPE_NONE && query.return_type != G_TYPE_BOOLEAN) ||
|
(query.return_type != G_TYPE_NONE && query.return_type != G_TYPE_BOOLEAN) ||
|
||||||
!binding_compose_params (object, sig->args, &query, ¶ms))
|
!binding_compose_params (object, sig->args, &query, ¶ms))
|
||||||
{
|
{
|
||||||
accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
|
g_warning ("gtk_binding_entry_activate(): "
|
||||||
g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
|
|
||||||
"signature mismatch for signal \"%s\" in the '%s' class ancestry",
|
"signature mismatch for signal \"%s\" in the '%s' class ancestry",
|
||||||
entry->binding_set->set_name,
|
|
||||||
accelerator,
|
|
||||||
sig->signal_name,
|
sig->signal_name,
|
||||||
g_type_name (G_OBJECT_TYPE (object)));
|
g_type_name (G_OBJECT_TYPE (object)));
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
else if (!(query.signal_flags & G_SIGNAL_ACTION))
|
else if (!(query.signal_flags & G_SIGNAL_ACTION))
|
||||||
{
|
{
|
||||||
accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
|
g_warning ("gtk_binding_entry_activate(): "
|
||||||
g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
|
|
||||||
"signal \"%s\" in the '%s' class ancestry cannot be used for action emissions",
|
"signal \"%s\" in the '%s' class ancestry cannot be used for action emissions",
|
||||||
entry->binding_set->set_name,
|
|
||||||
accelerator,
|
|
||||||
sig->signal_name,
|
sig->signal_name,
|
||||||
g_type_name (G_OBJECT_TYPE (object)));
|
g_type_name (G_OBJECT_TYPE (object)));
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
g_free (accelerator);
|
|
||||||
if (accelerator)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (query.return_type == G_TYPE_BOOLEAN)
|
if (query.return_type == G_TYPE_BOOLEAN)
|
||||||
g_value_init (&return_val, G_TYPE_BOOLEAN);
|
g_value_init (&return_val, G_TYPE_BOOLEAN);
|
||||||
@ -638,12 +659,71 @@ gtk_binding_entry_activate (GtkBindingEntry *entry,
|
|||||||
|
|
||||||
if (params != NULL)
|
if (params != NULL)
|
||||||
{
|
{
|
||||||
|
guint i;
|
||||||
|
|
||||||
for (i = 0; i < query.n_params + 1; i++)
|
for (i = 0; i < query.n_params + 1; i++)
|
||||||
g_value_unset (¶ms[i]);
|
g_value_unset (¶ms[i]);
|
||||||
|
|
||||||
g_free (params);
|
g_free (params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
binding_signal_activate_action (GtkBindingSignal *sig,
|
||||||
|
GObject *object)
|
||||||
|
{
|
||||||
|
if (!GTK_IS_WIDGET (object))
|
||||||
|
{
|
||||||
|
g_warning ("gtk_binding_entry_activate(): "
|
||||||
|
"actions must be emitted on GtkWidget subtypes, %s is not supported",
|
||||||
|
G_OBJECT_TYPE_NAME (object));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gtk_widget_activate_action_variant (GTK_WIDGET (object), sig->signal_name, sig->variant))
|
||||||
|
{
|
||||||
|
g_warning ("gtk_binding_entry_activate(): "
|
||||||
|
"action \"%s\" does not exist on class \"%s\"",
|
||||||
|
sig->signal_name,
|
||||||
|
G_OBJECT_TYPE_NAME (object));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gtk_binding_entry_activate (GtkBindingEntry *entry,
|
||||||
|
GObject *object)
|
||||||
|
{
|
||||||
|
GtkBindingSignal *sig;
|
||||||
|
gboolean old_emission;
|
||||||
|
gboolean handled = FALSE;
|
||||||
|
|
||||||
|
old_emission = entry->in_emission;
|
||||||
|
entry->in_emission = TRUE;
|
||||||
|
|
||||||
|
g_object_ref (object);
|
||||||
|
|
||||||
|
for (sig = entry->signals; sig; sig = sig->next)
|
||||||
|
{
|
||||||
|
switch (sig->action_type)
|
||||||
|
{
|
||||||
|
case GTK_BINDING_SIGNAL:
|
||||||
|
handled = binding_signal_activate_signal (sig, object);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GTK_BINDING_ACTION:
|
||||||
|
handled = binding_signal_activate_action (sig, object);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (entry->destroyed)
|
if (entry->destroyed)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -889,7 +969,7 @@ gtk_binding_entry_add_signall (GtkBindingSet *binding_set,
|
|||||||
keyval = gdk_keyval_to_lower (keyval);
|
keyval = gdk_keyval_to_lower (keyval);
|
||||||
modifiers = modifiers & BINDING_MOD_MASK ();
|
modifiers = modifiers & BINDING_MOD_MASK ();
|
||||||
|
|
||||||
signal = binding_signal_new (signal_name, g_slist_length (binding_args));
|
signal = binding_signal_new_signal (signal_name, g_slist_length (binding_args));
|
||||||
|
|
||||||
arg = signal->args;
|
arg = signal->args;
|
||||||
for (slist = binding_args; slist; slist = slist->next)
|
for (slist = binding_args; slist; slist = slist->next)
|
||||||
@ -1060,6 +1140,92 @@ gtk_binding_entry_add_signal (GtkBindingSet *binding_set,
|
|||||||
g_slist_free (free_slist);
|
g_slist_free (free_slist);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gtk_binding_entry_add_action_variant:
|
||||||
|
* @binding_set: a #GtkBindingSet to install an entry for
|
||||||
|
* @keyval: key value of binding to install
|
||||||
|
* @modifiers: key modifier of binding to install
|
||||||
|
* @action_name: signal to execute upon activation
|
||||||
|
* @args: #GVariant of the arguments or %NULL if none
|
||||||
|
*
|
||||||
|
* Override or install a new key binding for @keyval with @modifiers on
|
||||||
|
* @binding_set. When the binding is activated, @action_name will be
|
||||||
|
* activated on the target widget, with @args used as arguments.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gtk_binding_entry_add_action_variant (GtkBindingSet *binding_set,
|
||||||
|
guint keyval,
|
||||||
|
GdkModifierType modifiers,
|
||||||
|
const gchar *action_name,
|
||||||
|
GVariant *args)
|
||||||
|
{
|
||||||
|
GtkBindingEntry *entry;
|
||||||
|
GtkBindingSignal *signal, **signal_p;
|
||||||
|
|
||||||
|
g_return_if_fail (binding_set != NULL);
|
||||||
|
g_return_if_fail (action_name != NULL);
|
||||||
|
|
||||||
|
keyval = gdk_keyval_to_lower (keyval);
|
||||||
|
modifiers = modifiers & BINDING_MOD_MASK ();
|
||||||
|
|
||||||
|
signal = binding_signal_new_action (action_name, args);
|
||||||
|
|
||||||
|
entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
|
||||||
|
if (!entry)
|
||||||
|
{
|
||||||
|
gtk_binding_entry_clear_internal (binding_set, keyval, modifiers);
|
||||||
|
entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
|
||||||
|
}
|
||||||
|
signal_p = &entry->signals;
|
||||||
|
while (*signal_p)
|
||||||
|
signal_p = &(*signal_p)->next;
|
||||||
|
*signal_p = signal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gtk_binding_entry_add_action:
|
||||||
|
* @binding_set: a #GtkBindingSet to install an entry for
|
||||||
|
* @keyval: key value of binding to install
|
||||||
|
* @modifiers: key modifier of binding to install
|
||||||
|
* @action_name: signal to execute upon activation
|
||||||
|
* @format_string: GVariant format string for arguments or %NULL
|
||||||
|
* for no arguments
|
||||||
|
* @...: arguments, as given by format string
|
||||||
|
*
|
||||||
|
* Override or install a new key binding for @keyval with @modifiers on
|
||||||
|
* @binding_set. When the binding is activated, @action_name will be
|
||||||
|
* activated on the target widget, with arguments read according to
|
||||||
|
* @format_string.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gtk_binding_entry_add_action (GtkBindingSet *binding_set,
|
||||||
|
guint keyval,
|
||||||
|
GdkModifierType modifiers,
|
||||||
|
const char *action_name,
|
||||||
|
const char *format_string,
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
GVariant *parameters = NULL;
|
||||||
|
|
||||||
|
g_return_if_fail (binding_set != NULL);
|
||||||
|
g_return_if_fail (action_name != NULL);
|
||||||
|
|
||||||
|
if (format_string != NULL)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start (args, format_string);
|
||||||
|
parameters = g_variant_new_va (format_string, NULL, &args);
|
||||||
|
va_end (args);
|
||||||
|
|
||||||
|
g_variant_ref_sink (parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_binding_entry_add_action_variant (binding_set, keyval, modifiers, action_name, parameters);
|
||||||
|
|
||||||
|
g_clear_pointer (¶meters, g_variant_unref);
|
||||||
|
}
|
||||||
|
|
||||||
static guint
|
static guint
|
||||||
gtk_binding_parse_signal (GScanner *scanner,
|
gtk_binding_parse_signal (GScanner *scanner,
|
||||||
GtkBindingSet *binding_set,
|
GtkBindingSet *binding_set,
|
||||||
|
@ -76,6 +76,20 @@ GDK_AVAILABLE_IN_ALL
|
|||||||
GTokenType gtk_binding_entry_add_signal_from_string
|
GTokenType gtk_binding_entry_add_signal_from_string
|
||||||
(GtkBindingSet *binding_set,
|
(GtkBindingSet *binding_set,
|
||||||
const gchar *signal_desc);
|
const gchar *signal_desc);
|
||||||
|
GDK_AVAILABLE_IN_ALL
|
||||||
|
void gtk_binding_entry_add_action_variant
|
||||||
|
(GtkBindingSet *binding_set,
|
||||||
|
guint keyval,
|
||||||
|
GdkModifierType modifiers,
|
||||||
|
const char *action_name,
|
||||||
|
GVariant *args);
|
||||||
|
GDK_AVAILABLE_IN_ALL
|
||||||
|
void gtk_binding_entry_add_action (GtkBindingSet *binding_set,
|
||||||
|
guint keyval,
|
||||||
|
GdkModifierType modifiers,
|
||||||
|
const char *action_name,
|
||||||
|
const char *format_string,
|
||||||
|
...);
|
||||||
|
|
||||||
GDK_AVAILABLE_IN_ALL
|
GDK_AVAILABLE_IN_ALL
|
||||||
void gtk_binding_entry_remove (GtkBindingSet *binding_set,
|
void gtk_binding_entry_remove (GtkBindingSet *binding_set,
|
||||||
|
Loading…
Reference in New Issue
Block a user