Release Clutter 1.11.4 (snapshot)
[profile/ivi/clutter.git] / clutter / clutter-binding-pool.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Copyright (C) 2008  Intel Corporation.
7  *
8  * Authored By: Emmanuele Bassi <ebassi@linux.intel.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 /**
25  * SECTION:clutter-binding-pool
26  * @short_description: Pool for key bindings
27  *
28  * #ClutterBindingPool is a data structure holding a set of key bindings.
29  * Each key binding associates a key symbol (eventually with modifiers)
30  * to an action. A callback function is associated to each action.
31  *
32  * For a given key symbol and modifier mask combination there can be only one
33  * action; for each action there can be only one callback. There can be
34  * multiple actions with the same name, and the same callback can be used
35  * to handle multiple key bindings.
36  *
37  * Actors requiring key bindings should create a new #ClutterBindingPool
38  * inside their class initialization function and then install actions
39  * like this:
40  *
41  * |[
42  * static void
43  * foo_class_init (FooClass *klass)
44  * {
45  *   ClutterBindingPool *binding_pool;
46  *
47  *   binding_pool = clutter_binding_pool_get_for_class (klass);
48  *
49  *   clutter_binding_pool_install_action (binding_pool, "move-up",
50  *                                        CLUTTER_Up, 0,
51  *                                        G_CALLBACK (foo_action_move_up),
52  *                                        NULL, NULL);
53  *   clutter_binding_pool_install_action (binding_pool, "move-up",
54  *                                        CLUTTER_KP_Up, 0,
55  *                                        G_CALLBACK (foo_action_move_up),
56  *                                        NULL, NULL);
57  * }
58  * ]|
59  *
60  * The callback has a signature of:
61  *
62  * |[
63  *    gboolean (* callback) (GObject             *instance,
64  *                           const gchar         *action_name,
65  *                           guint                key_val,
66  *                           ClutterModifierType  modifiers,
67  *                           gpointer             user_data);
68  * ]|
69  *
70  * The actor should then override the #ClutterActor::key-press-event and
71  * use clutter_binding_pool_activate() to match a #ClutterKeyEvent structure
72  * to one of the actions:
73  *
74  * |[
75  *   ClutterBindingPool *pool;
76  *
77  *   /&ast; retrieve the binding pool for the type of the actor &ast;/
78  *   pool = clutter_binding_pool_find (G_OBJECT_TYPE_NAME (actor));
79  *
80  *   /&ast; activate any callback matching the key symbol and modifiers
81  *    &ast; mask of the key event. the returned value can be directly
82  *    &ast; used to signal that the actor has handled the event.
83  *    &ast;/
84  *   return clutter_binding_pool_activate (pool,
85  *                                         key_event-&gt;keyval,
86  *                                         key_event-&gt;modifier_state,
87  *                                         G_OBJECT (actor));
88  * ]|
89  *
90  * The clutter_binding_pool_activate() function will return %FALSE if
91  * no action for the given key binding was found, if the action was
92  * blocked (using clutter_binding_pool_block_action()) or if the
93  * key binding handler returned %FALSE.
94  *
95  * #ClutterBindingPool is available since Clutter 1.0
96  */
97
98 #ifdef HAVE_CONFIG_H
99 #include "config.h"
100 #endif
101
102 #include "clutter-binding-pool.h"
103 #include "clutter-debug.h"
104 #include "clutter-enum-types.h"
105 #include "clutter-marshal.h"
106 #include "clutter-private.h"
107
108 #define CLUTTER_BINDING_POOL_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), CLUTTER_TYPE_BINDING_POOL, ClutterBindingPoolClass))
109 #define CLUTTER_IS_BINDING_POOL_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), CLUTTER_TYPE_BINDING_POOL))
110 #define CLUTTER_BINDING_POOL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CLUTTER_TYPE_BINDING_POOL, ClutterBindingPoolClass))
111
112 #define BINDING_MOD_MASK        ((CLUTTER_SHIFT_MASK   | \
113                                   CLUTTER_CONTROL_MASK | \
114                                   CLUTTER_MOD1_MASK    | \
115                                   CLUTTER_SUPER_MASK   | \
116                                   CLUTTER_HYPER_MASK   | \
117                                   CLUTTER_META_MASK)   | CLUTTER_RELEASE_MASK)
118
119 typedef struct _ClutterBindingEntry     ClutterBindingEntry;
120
121 static GSList *clutter_binding_pools = NULL;
122 static GQuark  key_class_bindings = 0;
123
124 struct _ClutterBindingPool
125 {
126   GObject parent_instance;
127
128   gchar *name; /* interned string, do not free */
129
130   GSList *entries;
131   GHashTable *entries_hash;
132 };
133
134 struct _ClutterBindingPoolClass
135 {
136   GObjectClass parent_class;
137 };
138
139 struct _ClutterBindingEntry
140 {
141   gchar *name; /* interned string, do not free */
142
143   guint key_val;
144   ClutterModifierType modifiers;
145
146   GClosure *closure;
147
148   guint is_blocked  : 1;
149 };
150
151 enum
152 {
153   PROP_0,
154
155   PROP_NAME,
156
157   PROP_LAST
158 };
159
160 static GParamSpec *obj_props[PROP_LAST];
161
162 G_DEFINE_TYPE (ClutterBindingPool, clutter_binding_pool, G_TYPE_OBJECT);
163
164 static guint
165 binding_entry_hash (gconstpointer v)
166 {
167   const ClutterBindingEntry *e = v;
168   guint h;
169
170   h = e->key_val;
171   h ^= e->modifiers;
172
173   return h;
174 }
175
176 static gint
177 binding_entry_compare (gconstpointer v1,
178                        gconstpointer v2)
179 {
180   const ClutterBindingEntry *e1 = v1;
181   const ClutterBindingEntry *e2 = v2;
182
183   return (e1->key_val == e2->key_val && e1->modifiers == e2->modifiers);
184 }
185
186 static ClutterBindingEntry *
187 binding_entry_new (const gchar         *name,
188                    guint                key_val,
189                    ClutterModifierType  modifiers)
190 {
191   ClutterBindingEntry *entry;
192
193   modifiers = modifiers & BINDING_MOD_MASK;
194
195   entry = g_slice_new (ClutterBindingEntry);
196   entry->key_val = key_val;
197   entry->modifiers = modifiers;
198   entry->name = (gchar *) g_intern_string (name);
199   entry->closure = NULL;
200   entry->is_blocked = FALSE;
201
202   return entry;
203 }
204
205 static ClutterBindingEntry *
206 binding_pool_lookup_entry (ClutterBindingPool  *pool,
207                            guint                key_val,
208                            ClutterModifierType  modifiers)
209 {
210   ClutterBindingEntry lookup_entry = { 0, };
211
212   lookup_entry.key_val = key_val;
213   lookup_entry.modifiers = modifiers;
214
215   return g_hash_table_lookup (pool->entries_hash, &lookup_entry);
216 }
217
218 static void
219 binding_entry_free (gpointer data)
220 {
221   if (G_LIKELY (data))
222     {
223       ClutterBindingEntry *entry = data;
224
225       g_closure_unref (entry->closure);
226
227       g_slice_free (ClutterBindingEntry, entry);
228     }
229 }
230
231 static void
232 clutter_binding_pool_finalize (GObject *gobject)
233 {
234   ClutterBindingPool *pool = CLUTTER_BINDING_POOL (gobject);
235
236   /* remove from the pools */
237   clutter_binding_pools = g_slist_remove (clutter_binding_pools, pool);
238
239   g_hash_table_destroy (pool->entries_hash);
240
241   g_slist_foreach (pool->entries, (GFunc) binding_entry_free, NULL);
242   g_slist_free (pool->entries);
243
244   G_OBJECT_CLASS (clutter_binding_pool_parent_class)->finalize (gobject);
245 }
246
247 static void
248 clutter_binding_pool_set_property (GObject      *gobject,
249                                    guint         prop_id,
250                                    const GValue *value,
251                                    GParamSpec   *pspec)
252 {
253   ClutterBindingPool *pool = CLUTTER_BINDING_POOL (gobject);
254
255   switch (prop_id)
256     {
257     case PROP_NAME:
258       pool->name = (gchar *) g_intern_string (g_value_get_string (value));
259       break;
260
261     default:
262       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
263       break;
264     }
265 }
266
267 static void
268 clutter_binding_pool_get_property (GObject    *gobject,
269                                    guint       prop_id,
270                                    GValue     *value,
271                                    GParamSpec *pspec)
272 {
273   ClutterBindingPool *pool = CLUTTER_BINDING_POOL (gobject);
274
275   switch (prop_id)
276     {
277     case PROP_NAME:
278       g_value_set_string (value, pool->name);
279       break;
280
281     default:
282       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
283       break;
284     }
285 }
286
287 static void
288 clutter_binding_pool_constructed (GObject *gobject)
289 {
290   ClutterBindingPool *pool = CLUTTER_BINDING_POOL (gobject);
291
292   /* bad monkey! bad, bad monkey! */
293   if (G_UNLIKELY (pool->name == NULL))
294     g_critical ("No name set for ClutterBindingPool %p", pool);
295
296   if (G_OBJECT_CLASS (clutter_binding_pool_parent_class)->constructed)
297     G_OBJECT_CLASS (clutter_binding_pool_parent_class)->constructed (gobject);
298 }
299
300 static void
301 clutter_binding_pool_class_init (ClutterBindingPoolClass *klass)
302 {
303   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
304
305   gobject_class->constructed = clutter_binding_pool_constructed;
306   gobject_class->set_property = clutter_binding_pool_set_property;
307   gobject_class->get_property = clutter_binding_pool_get_property;
308   gobject_class->finalize = clutter_binding_pool_finalize;
309
310   /**
311    * ClutterBindingPool:name:
312    *
313    * The unique name of the #ClutterBindingPool.
314    *
315    * Since: 1.0
316    */
317   obj_props[PROP_NAME] =
318     g_param_spec_string ("name",
319                          P_("Name"),
320                          P_("The unique name of the binding pool"),
321                          NULL,
322                          CLUTTER_PARAM_READWRITE |
323                          G_PARAM_CONSTRUCT_ONLY);
324
325   g_object_class_install_properties (gobject_class,
326                                      PROP_LAST,
327                                      obj_props);
328 }
329
330 static void
331 clutter_binding_pool_init (ClutterBindingPool *pool)
332 {
333   pool->name = NULL;
334   pool->entries = NULL;
335   pool->entries_hash = g_hash_table_new (binding_entry_hash,
336                                          binding_entry_compare);
337
338   clutter_binding_pools = g_slist_prepend (clutter_binding_pools, pool);
339 }
340
341 /**
342  * clutter_binding_pool_new:
343  * @name: the name of the binding pool
344  *
345  * Creates a new #ClutterBindingPool that can be used to store
346  * key bindings for an actor. The @name must be a unique identifier
347  * for the binding pool, so that clutter_binding_pool_find() will
348  * be able to return the correct binding pool.
349  *
350  * Return value: the newly created binding pool with the given
351  *   name. Use g_object_unref() when done.
352  *
353  * Since: 1.0
354  */
355 ClutterBindingPool *
356 clutter_binding_pool_new (const gchar *name)
357 {
358   ClutterBindingPool *pool;
359
360   g_return_val_if_fail (name != NULL, NULL);
361
362   pool = clutter_binding_pool_find (name);
363   if (G_UNLIKELY (pool))
364     {
365       g_warning ("A binding pool named '%s' is already present "
366                  "in the binding pools list",
367                  pool->name);
368       return NULL;
369     }
370
371   return g_object_new (CLUTTER_TYPE_BINDING_POOL, "name", name, NULL);
372 }
373
374 /**
375  * clutter_binding_pool_get_for_class:
376  * @klass: a #GObjectClass pointer
377  *
378  * Retrieves the #ClutterBindingPool for the given #GObject class
379  * and, eventually, creates it. This function is a wrapper around
380  * clutter_binding_pool_new() and uses the class type name as the
381  * unique name for the binding pool.
382  *
383  * Calling this function multiple times will return the same
384  * #ClutterBindingPool.
385  *
386  * A binding pool for a class can also be retrieved using
387  * clutter_binding_pool_find() with the class type name:
388  *
389  * |[
390  *   pool = clutter_binding_pool_find (G_OBJECT_TYPE_NAME (instance));
391  * ]|
392  *
393  * Return value: (transfer none): the binding pool for the given class.
394  *   The returned #ClutterBindingPool is owned by Clutter and should not
395  *   be freed directly
396  *
397  * Since: 1.0
398  */
399 ClutterBindingPool *
400 clutter_binding_pool_get_for_class (gpointer klass)
401 {
402   ClutterBindingPool *pool;
403
404   g_return_val_if_fail (G_IS_OBJECT_CLASS (klass), NULL);
405
406   if (G_UNLIKELY (key_class_bindings == 0))
407     key_class_bindings = g_quark_from_static_string ("clutter-bindings-set");
408
409   pool = g_dataset_id_get_data (klass, key_class_bindings);
410   if (pool)
411     return pool;
412
413   pool = clutter_binding_pool_new (G_OBJECT_CLASS_NAME (klass));
414   g_dataset_id_set_data_full (klass, key_class_bindings,
415                               pool,
416                               g_object_unref);
417
418   return pool;
419 }
420
421 /**
422  * clutter_binding_pool_find:
423  * @name: the name of the binding pool to find
424  *
425  * Finds the #ClutterBindingPool with @name.
426  *
427  * Return value: (transfer none): a pointer to the #ClutterBindingPool, or %NULL
428  *
429  * Since: 1.0
430  */
431 ClutterBindingPool *
432 clutter_binding_pool_find (const gchar *name)
433 {
434   GSList *l;
435
436   g_return_val_if_fail (name != NULL, NULL);
437
438   for (l = clutter_binding_pools; l != NULL; l = l->next)
439     {
440       ClutterBindingPool *pool = l->data;
441
442       if (g_str_equal (pool->name, (gpointer) name))
443         return pool;
444     }
445
446   return NULL;
447 }
448
449 /**
450  * clutter_binding_pool_install_action:
451  * @pool: a #ClutterBindingPool
452  * @action_name: the name of the action
453  * @key_val: key symbol
454  * @modifiers: bitmask of modifiers
455  * @callback: function to be called when the action is activated
456  * @data: data to be passed to @callback
457  * @notify: function to be called when the action is removed
458  *   from the pool
459  *
460  * Installs a new action inside a #ClutterBindingPool. The action
461  * is bound to @key_val and @modifiers.
462  *
463  * The same action name can be used for multiple @key_val, @modifiers
464  * pairs.
465  *
466  * When an action has been activated using clutter_binding_pool_activate()
467  * the passed @callback will be invoked (with @data).
468  *
469  * Actions can be blocked with clutter_binding_pool_block_action()
470  * and then unblocked using clutter_binding_pool_unblock_action().
471  *
472  * Since: 1.0
473  */
474 void
475 clutter_binding_pool_install_action (ClutterBindingPool  *pool,
476                                      const gchar         *action_name,
477                                      guint                key_val,
478                                      ClutterModifierType  modifiers,
479                                      GCallback            callback,
480                                      gpointer             data,
481                                      GDestroyNotify       notify)
482 {
483   ClutterBindingEntry *entry;
484   GClosure *closure;
485
486   g_return_if_fail (pool != NULL);
487   g_return_if_fail (action_name != NULL);
488   g_return_if_fail (key_val != 0);
489   g_return_if_fail (callback != NULL);
490
491   entry = binding_pool_lookup_entry (pool, key_val, modifiers);
492   if (G_UNLIKELY (entry))
493     {
494       g_warning ("There already is an action '%s' for the given "
495                  "key symbol of %d (modifiers: %d) installed inside "
496                  "the binding pool.",
497                  entry->name,
498                  entry->key_val, entry->modifiers);
499       return;
500     }
501   else
502     entry = binding_entry_new (action_name, key_val, modifiers);
503
504   closure = g_cclosure_new (callback, data, (GClosureNotify) notify);
505   entry->closure = g_closure_ref (closure);
506   g_closure_sink (closure);
507
508   if (G_CLOSURE_NEEDS_MARSHAL (closure))
509     {
510       GClosureMarshal marshal;
511
512       marshal = _clutter_marshal_BOOLEAN__STRING_UINT_FLAGS;
513       g_closure_set_marshal (closure, marshal);
514     }
515
516   pool->entries = g_slist_prepend (pool->entries, entry);
517   g_hash_table_insert (pool->entries_hash, entry, entry);
518 }
519
520 /**
521  * clutter_binding_pool_install_closure:
522  * @pool: a #ClutterBindingPool
523  * @action_name: the name of the action
524  * @key_val: key symbol
525  * @modifiers: bitmask of modifiers
526  * @closure: a #GClosure
527  *
528  * A #GClosure variant of clutter_binding_pool_install_action().
529  *
530  * Installs a new action inside a #ClutterBindingPool. The action
531  * is bound to @key_val and @modifiers.
532  *
533  * The same action name can be used for multiple @key_val, @modifiers
534  * pairs.
535  *
536  * When an action has been activated using clutter_binding_pool_activate()
537  * the passed @closure will be invoked.
538  *
539  * Actions can be blocked with clutter_binding_pool_block_action()
540  * and then unblocked using clutter_binding_pool_unblock_action().
541  *
542  * Since: 1.0
543  */
544 void
545 clutter_binding_pool_install_closure (ClutterBindingPool  *pool,
546                                       const gchar         *action_name,
547                                       guint                key_val,
548                                       ClutterModifierType  modifiers,
549                                       GClosure            *closure)
550 {
551   ClutterBindingEntry *entry;
552
553   g_return_if_fail (pool != NULL);
554   g_return_if_fail (action_name != NULL);
555   g_return_if_fail (key_val != 0);
556   g_return_if_fail (closure != NULL);
557
558   entry = binding_pool_lookup_entry (pool, key_val, modifiers);
559   if (G_UNLIKELY (entry))
560     {
561       g_warning ("There already is an action '%s' for the given "
562                  "key symbol of %d (modifiers: %d) installed inside "
563                  "the binding pool.",
564                  entry->name,
565                  entry->key_val, entry->modifiers);
566       return;
567     }
568   else
569     entry = binding_entry_new (action_name, key_val, modifiers);
570
571   entry->closure = g_closure_ref (closure);
572   g_closure_sink (closure);
573
574   if (G_CLOSURE_NEEDS_MARSHAL (closure))
575     {
576       GClosureMarshal marshal;
577
578       marshal = _clutter_marshal_BOOLEAN__STRING_UINT_FLAGS;
579       g_closure_set_marshal (closure, marshal);
580     }
581
582   pool->entries = g_slist_prepend (pool->entries, entry);
583   g_hash_table_insert (pool->entries_hash, entry, entry);
584 }
585
586 /**
587  * clutter_binding_pool_override_action:
588  * @pool: a #ClutterBindingPool
589  * @key_val: key symbol
590  * @modifiers: bitmask of modifiers
591  * @callback: function to be called when the action is activated
592  * @data: data to be passed to @callback
593  * @notify: function to be called when the action is removed
594  *   from the pool
595  *
596  * Allows overriding the action for @key_val and @modifiers inside a
597  * #ClutterBindingPool. See clutter_binding_pool_install_action().
598  *
599  * When an action has been activated using clutter_binding_pool_activate()
600  * the passed @callback will be invoked (with @data).
601  *
602  * Actions can be blocked with clutter_binding_pool_block_action()
603  * and then unblocked using clutter_binding_pool_unblock_action().
604  *
605  * Since: 1.0
606  */
607 void
608 clutter_binding_pool_override_action (ClutterBindingPool  *pool,
609                                       guint                key_val,
610                                       ClutterModifierType  modifiers,
611                                       GCallback            callback,
612                                       gpointer             data,
613                                       GDestroyNotify       notify)
614 {
615   ClutterBindingEntry *entry;
616   GClosure *closure;
617
618   g_return_if_fail (pool != NULL);
619   g_return_if_fail (key_val != 0);
620   g_return_if_fail (callback != NULL);
621
622   entry = binding_pool_lookup_entry (pool, key_val, modifiers);
623   if (G_UNLIKELY (entry == NULL))
624     {
625       g_warning ("There is no action for the given key symbol "
626                  "of %d (modifiers: %d) installed inside the "
627                  "binding pool.",
628                  key_val, modifiers);
629       return;
630     }
631
632   if (entry->closure)
633     {
634       g_closure_unref (entry->closure);
635       entry->closure = NULL;
636     }
637
638   closure = g_cclosure_new (callback, data, (GClosureNotify) notify);
639   entry->closure = g_closure_ref (closure);
640   g_closure_sink (closure);
641
642   if (G_CLOSURE_NEEDS_MARSHAL (closure))
643     {
644       GClosureMarshal marshal;
645
646       marshal = _clutter_marshal_BOOLEAN__STRING_UINT_FLAGS;
647       g_closure_set_marshal (closure, marshal);
648     }
649 }
650
651 /**
652  * clutter_binding_pool_override_closure:
653  * @pool: a #ClutterBindingPool
654  * @key_val: key symbol
655  * @modifiers: bitmask of modifiers
656  * @closure: a #GClosure
657  *
658  * A #GClosure variant of clutter_binding_pool_override_action().
659  *
660  * Allows overriding the action for @key_val and @modifiers inside a
661  * #ClutterBindingPool. See clutter_binding_pool_install_closure().
662  *
663  * When an action has been activated using clutter_binding_pool_activate()
664  * the passed @callback will be invoked (with @data).
665  *
666  * Actions can be blocked with clutter_binding_pool_block_action()
667  * and then unblocked using clutter_binding_pool_unblock_action().
668  *
669  * Since: 1.0
670  */
671 void
672 clutter_binding_pool_override_closure (ClutterBindingPool  *pool,
673                                        guint                key_val,
674                                        ClutterModifierType  modifiers,
675                                        GClosure            *closure)
676 {
677   ClutterBindingEntry *entry;
678
679   g_return_if_fail (pool != NULL);
680   g_return_if_fail (key_val != 0);
681   g_return_if_fail (closure != NULL);
682
683   entry = binding_pool_lookup_entry (pool, key_val, modifiers);
684   if (G_UNLIKELY (entry == NULL))
685     {
686       g_warning ("There is no action for the given key symbol "
687                  "of %d (modifiers: %d) installed inside the "
688                  "binding pool.",
689                  key_val, modifiers);
690       return;
691     }
692
693   if (entry->closure)
694     {
695       g_closure_unref (entry->closure);
696       entry->closure = NULL;
697     }
698
699   entry->closure = g_closure_ref (closure);
700   g_closure_sink (closure);
701
702   if (G_CLOSURE_NEEDS_MARSHAL (closure))
703     {
704       GClosureMarshal marshal;
705
706       marshal = _clutter_marshal_BOOLEAN__STRING_UINT_FLAGS;
707       g_closure_set_marshal (closure, marshal);
708     }
709 }
710
711 /**
712  * clutter_binding_pool_find_action:
713  * @pool: a #ClutterBindingPool
714  * @key_val: a key symbol
715  * @modifiers: a bitmask for the modifiers
716  *
717  * Retrieves the name of the action matching the given key symbol
718  * and modifiers bitmask.
719  *
720  * Return value: the name of the action, if found, or %NULL. The
721  *   returned string is owned by the binding pool and should never
722  *   be modified or freed
723  *
724  * Since: 1.0
725  */
726 const gchar *
727 clutter_binding_pool_find_action (ClutterBindingPool  *pool,
728                                   guint                key_val,
729                                   ClutterModifierType  modifiers)
730 {
731   ClutterBindingEntry *entry;
732
733   g_return_val_if_fail (pool != NULL, NULL);
734   g_return_val_if_fail (key_val != 0, NULL);
735
736   entry = binding_pool_lookup_entry (pool, key_val, modifiers);
737   if (!entry)
738     return NULL;
739
740   return entry->name;
741 }
742
743 /**
744  * clutter_binding_pool_remove_action:
745  * @pool: a #ClutterBindingPool
746  * @key_val: a key symbol
747  * @modifiers: a bitmask for the modifiers
748  *
749  * Removes the action matching the given @key_val, @modifiers pair,
750  * if any exists.
751  *
752  * Since: 1.0
753  */
754 void
755 clutter_binding_pool_remove_action (ClutterBindingPool  *pool,
756                                     guint                key_val,
757                                     ClutterModifierType  modifiers)
758 {
759   ClutterBindingEntry remove_entry = { 0, };
760   GSList *l;
761
762   g_return_if_fail (pool != NULL);
763   g_return_if_fail (key_val != 0);
764
765   modifiers = modifiers & BINDING_MOD_MASK;
766
767   remove_entry.key_val = key_val;
768   remove_entry.modifiers = modifiers;
769
770   for (l = pool->entries; l != NULL; l = l->data)
771     {
772       ClutterBindingEntry *e = l->data;
773
774       if (e->key_val == remove_entry.key_val &&
775           e->modifiers == remove_entry.modifiers)
776         {
777           pool->entries = g_slist_remove_link (pool->entries, l);
778           break;
779         }
780     }
781
782   g_hash_table_remove (pool->entries_hash, &remove_entry);
783 }
784
785 static gboolean
786 clutter_binding_entry_invoke (ClutterBindingEntry *entry,
787                               GObject             *gobject)
788 {
789   GValue params[4] = {
790     G_VALUE_INIT,
791     G_VALUE_INIT,
792     G_VALUE_INIT,
793     G_VALUE_INIT
794   };
795   GValue result = G_VALUE_INIT;
796   gboolean retval = TRUE;
797
798   g_value_init (&params[0], G_TYPE_OBJECT);
799   g_value_set_object (&params[0], gobject);
800
801   g_value_init (&params[1], G_TYPE_STRING);
802   g_value_set_static_string (&params[1], entry->name);
803
804   g_value_init (&params[2], G_TYPE_UINT);
805   g_value_set_uint (&params[2], entry->key_val);
806
807   g_value_init (&params[3], CLUTTER_TYPE_MODIFIER_TYPE);
808   g_value_set_flags (&params[3], entry->modifiers);
809
810   g_value_init (&result, G_TYPE_BOOLEAN);
811
812   g_closure_invoke (entry->closure, &result, 4, params, NULL);
813
814   retval = g_value_get_boolean (&result);
815
816   g_value_unset (&result);
817
818   g_value_unset (&params[0]);
819   g_value_unset (&params[1]);
820   g_value_unset (&params[2]);
821   g_value_unset (&params[3]);
822
823   return retval;
824 }
825
826 /**
827  * clutter_binding_pool_activate:
828  * @pool: a #ClutterBindingPool
829  * @key_val: the key symbol
830  * @modifiers: bitmask for the modifiers
831  * @gobject: a #GObject
832  *
833  * Activates the callback associated to the action that is
834  * bound to the @key_val and @modifiers pair.
835  *
836  * The callback has the following signature:
837  *
838  * |[
839  *   void (* callback) (GObject             *gobject,
840  *                      const gchar         *action_name,
841  *                      guint                key_val,
842  *                      ClutterModifierType  modifiers,
843  *                      gpointer             user_data);
844  * ]|
845  *
846  * Where the #GObject instance is @gobject and the user data
847  * is the one passed when installing the action with
848  * clutter_binding_pool_install_action().
849  *
850  * If the action bound to the @key_val, @modifiers pair has been
851  * blocked using clutter_binding_pool_block_action(), the callback
852  * will not be invoked, and this function will return %FALSE.
853  *
854  * Return value: %TRUE if an action was found and was activated
855  *
856  * Since: 1.0
857  */
858 gboolean
859 clutter_binding_pool_activate (ClutterBindingPool  *pool,
860                                guint                key_val,
861                                ClutterModifierType  modifiers,
862                                GObject             *gobject)
863 {
864   ClutterBindingEntry *entry = NULL;
865
866   g_return_val_if_fail (pool != NULL, FALSE);
867   g_return_val_if_fail (key_val != 0, FALSE);
868   g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE);
869
870   modifiers = (modifiers & BINDING_MOD_MASK);
871
872   entry = binding_pool_lookup_entry (pool, key_val, modifiers);
873   if (!entry)
874     return FALSE;
875
876   if (!entry->is_blocked)
877     return clutter_binding_entry_invoke (entry, gobject);
878
879   return FALSE;
880 }
881
882 /**
883  * clutter_binding_pool_block_action:
884  * @pool: a #ClutterBindingPool
885  * @action_name: an action name
886  *
887  * Blocks all the actions with name @action_name inside @pool.
888  *
889  * Since: 1.0
890  */
891 void
892 clutter_binding_pool_block_action (ClutterBindingPool *pool,
893                                    const gchar        *action_name)
894 {
895   GSList *l;
896
897   g_return_if_fail (pool != NULL);
898   g_return_if_fail (action_name != NULL);
899
900   for (l = pool->entries; l != NULL; l = l->next)
901     {
902       ClutterBindingEntry *entry = l->data;
903
904       if (g_str_equal (entry->name, (gpointer) action_name))
905         entry->is_blocked = TRUE;
906     }
907 }
908
909 /**
910  * clutter_binding_pool_unblock_action:
911  * @pool: a #ClutterBindingPool
912  * @action_name: an action name
913  *
914  * Unblockes all the actions with name @action_name inside @pool.
915  *
916  * Unblocking an action does not cause the callback bound to it to
917  * be invoked in case clutter_binding_pool_activate() was called on
918  * an action previously blocked with clutter_binding_pool_block_action().
919  *
920  * Since: 1.0
921  */
922 void
923 clutter_binding_pool_unblock_action (ClutterBindingPool *pool,
924                                      const gchar        *action_name)
925 {
926   GSList *l;
927
928   g_return_if_fail (pool != NULL);
929   g_return_if_fail (action_name != NULL);
930
931   for (l = pool->entries; l != NULL; l = l->next)
932     {
933       ClutterBindingEntry *entry = l->data;
934
935       if (g_str_equal (entry->name, (gpointer) action_name))
936         entry->is_blocked = FALSE;
937     }
938 }