[clutter/clutter-1.18] Add API to install an event filter



commit 70292672c4381c3039bd88255c4f57d45e142599
Author: Neil Roberts <neil linux intel com>
Date:   Thu Aug 29 17:10:56 2013 +0100

    Add API to install an event filter
    
    This adds clutter_event_add/remove_filter which adds a callback
    function which will receive all Clutter events just before the event
    signal is emitted for them. The event filter will be invoked
    regardless of any grabs or captures. This will be used by Mutter which
    wants to access the events at a lower level then the event bubbling
    mechanism. It needs to see all mouse motion events even if there is a
    grab in place.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=707560

 clutter/clutter-event-private.h            |    2 +
 clutter/clutter-event.c                    |  106 ++++++++++++++++++++++++++++
 clutter/clutter-event.h                    |   26 +++++++
 clutter/clutter-main.c                     |   22 ++++++-
 clutter/clutter-private.h                  |    4 +
 doc/reference/clutter/clutter-sections.txt |    3 +
 6 files changed, 162 insertions(+), 1 deletions(-)
---
diff --git a/clutter/clutter-event-private.h b/clutter/clutter-event-private.h
index 955db26..00d627d 100644
--- a/clutter/clutter-event-private.h
+++ b/clutter/clutter-event-private.h
@@ -11,6 +11,8 @@ void            _clutter_event_set_pointer_emulated     (ClutterEvent       *eve
 /* Reinjecting queued events for processing */
 void            _clutter_process_event                  (ClutterEvent       *event);
 
+gboolean        _clutter_event_process_filters          (ClutterEvent       *event);
+
 /* clears the event queue inside the main context */
 void            _clutter_clear_events_queue             (void);
 void            _clutter_clear_events_queue_for_stage   (ClutterStage       *stage);
diff --git a/clutter/clutter-event.c b/clutter/clutter-event.c
index 03655f6..06870c6 100644
--- a/clutter/clutter-event.c
+++ b/clutter/clutter-event.c
@@ -64,6 +64,15 @@ typedef struct _ClutterEventPrivate {
   guint is_pointer_emulated : 1;
 } ClutterEventPrivate;
 
+typedef struct _ClutterEventFilter {
+  int id;
+
+  ClutterStage *stage;
+  ClutterEventFilterFunc func;
+  GDestroyNotify notify;
+  gpointer user_data;
+} ClutterEventFilter;
+
 static GHashTable *all_events = NULL;
 
 G_DEFINE_BOXED_TYPE (ClutterEvent, clutter_event,
@@ -1720,3 +1729,100 @@ clutter_event_is_pointer_emulated (const ClutterEvent *event)
 
   return ((ClutterEventPrivate *) event)->is_pointer_emulated;
 }
+
+gboolean
+_clutter_event_process_filters (ClutterEvent *event)
+{
+  ClutterMainContext *context = _clutter_context_get_default ();
+  GList *l, *next;
+
+  /* Event filters are handled in order from least recently added to
+   * most recently added */
+
+  for (l = context->event_filters; l; l = next)
+    {
+      ClutterEventFilter *event_filter = l->data;
+
+      next = l->next;
+
+      if (event_filter->stage && event_filter->stage != event->any.stage)
+        continue;
+
+      if (event_filter->func (event, event_filter->user_data) == CLUTTER_EVENT_STOP)
+        return CLUTTER_EVENT_STOP;
+    }
+
+  return CLUTTER_EVENT_PROPAGATE;
+}
+
+/**
+ * clutter_event_add_filter:
+ * @stage: (allow-none): The #ClutterStage to capture events for
+ * @func: The callback function which will be passed all events.
+ * @notify: A #GDestroyNotify
+ * @user_data: A data pointer to pass to the function.
+ *
+ * Adds a function which will be called for all events that Clutter
+ * processes. The function will be called before any signals are
+ * emitted for the event and it will take precedence over any grabs.
+ *
+ * Return value: an identifier for the event filter, to be used
+ *   with clutter_event_remove_filter().
+ *
+ * Since: 1.18
+ */
+guint
+clutter_event_add_filter (ClutterStage          *stage,
+                          ClutterEventFilterFunc func,
+                          GDestroyNotify         notify,
+                          gpointer               user_data)
+{
+  ClutterMainContext *context = _clutter_context_get_default ();
+  ClutterEventFilter *event_filter = g_slice_new (ClutterEventFilter);
+  static guint event_filter_id = 0;
+
+  event_filter->stage = stage;
+  event_filter->id = ++event_filter_id;
+  event_filter->func = func;
+  event_filter->notify = notify;
+  event_filter->user_data = user_data;
+
+  /* The event filters are kept in order from least recently added to
+   * most recently added so we must add it to the end */
+  context->event_filters = g_list_append (context->event_filters, event_filter);
+
+  return event_filter->id;
+}
+
+/**
+ * clutter_event_remove_filter:
+ * @id: The ID of the event filter, as returned from clutter_event_add_filter()
+ *
+ * Removes an event filter that was previously added with
+ * clutter_event_add_filter().
+ *
+ * Since: 1.18
+ */
+void
+clutter_event_remove_filter (guint id)
+{
+  ClutterMainContext *context = _clutter_context_get_default ();
+  GList *l;
+
+  for (l = context->event_filters; l; l = l->next)
+    {
+      ClutterEventFilter *event_filter = l->data;
+
+      if (event_filter->id == id)
+        {
+          if (event_filter->notify)
+            event_filter->notify (event_filter->user_data);
+
+          context->event_filters = g_list_delete_link (context->event_filters, l);
+          g_slice_free (ClutterEventFilter, event_filter);
+          return;
+        }
+    }
+
+  g_warning ("No event filter found for id: %d\n", id);
+}
diff --git a/clutter/clutter-event.h b/clutter/clutter-event.h
index 30e84d9..f41375c 100644
--- a/clutter/clutter-event.h
+++ b/clutter/clutter-event.h
@@ -405,6 +405,24 @@ union _ClutterEvent
   ClutterTouchEvent touch;
 };
 
+/**
+ * ClutterEventFilterFunc:
+ * @event: the event that is going to be emitted
+ * @user_data: the data pointer passed to clutter_event_add_filter()
+ *
+ * A function pointer type used by event filters that are added with
+ * clutter_event_add_filter().
+ *
+ * Return value: %CLUTTER_EVENT_STOP to indicate that the event
+ *   has been handled or %CLUTTER_EVENT_PROPAGATE otherwise.
+ *   Returning %CLUTTER_EVENT_STOP skips any further filter
+ *   functions and prevents the signal emission for the event.
+ *
+ * Since: 1.18
+ */
+typedef gboolean (* ClutterEventFilterFunc) (const ClutterEvent *event,
+                                             gpointer            user_data);
+
 GType clutter_event_get_type (void) G_GNUC_CONST;
 
 gboolean                clutter_events_pending                  (void);
@@ -412,6 +430,14 @@ ClutterEvent *          clutter_event_get                       (void);
 ClutterEvent *          clutter_event_peek                      (void);
 void                    clutter_event_put                       (const ClutterEvent     *event);
 
+CLUTTER_AVAILABLE_IN_1_18
+guint                   clutter_event_add_filter                (ClutterStage          *stage,
+                                                                 ClutterEventFilterFunc func,
+                                                                 GDestroyNotify         notify,
+                                                                 gpointer               user_data);
+CLUTTER_AVAILABLE_IN_1_18
+void                    clutter_event_remove_filter             (guint                  id);
+
 ClutterEvent *          clutter_event_new                       (ClutterEventType        type);
 ClutterEvent *          clutter_event_copy                      (const ClutterEvent     *event);
 void                    clutter_event_free                      (ClutterEvent           *event);
diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c
index ef83665..6363ad9 100644
--- a/clutter/clutter-main.c
+++ b/clutter/clutter-main.c
@@ -2279,6 +2279,9 @@ emit_pointer_event (ClutterEvent       *event,
 {
   ClutterMainContext *context = _clutter_context_get_default ();
 
+  if (_clutter_event_process_filters (event))
+    return;
+
   if (context->pointer_grab_actor == NULL &&
       (device == NULL || device->pointer_grab_actor == NULL))
     {
@@ -2306,6 +2309,9 @@ emit_touch_event (ClutterEvent       *event,
 {
   ClutterActor *grab_actor = NULL;
 
+  if (_clutter_event_process_filters (event))
+    return;
+
   if (device->sequence_grab_actors != NULL)
     {
       grab_actor = g_hash_table_lookup (device->sequence_grab_actors,
@@ -2330,6 +2336,9 @@ emit_keyboard_event (ClutterEvent       *event,
 {
   ClutterMainContext *context = _clutter_context_get_default ();
 
+  if (_clutter_event_process_filters (event))
+    return;
+
   if (context->keyboard_grab_actor == NULL &&
       (device == NULL || device->keyboard_grab_actor == NULL))
     {
@@ -2493,6 +2502,10 @@ _clutter_process_event_details (ClutterActor        *stage,
       case CLUTTER_DESTROY_NOTIFY:
       case CLUTTER_DELETE:
         event->any.source = stage;
+
+        if (_clutter_event_process_filters (event))
+          break;
+
         /* the stage did not handle the event, so we just quit */
         clutter_stage_event (CLUTTER_STAGE (stage), event);
         break;
@@ -2505,6 +2518,9 @@ _clutter_process_event_details (ClutterActor        *stage,
             /* Only stage gets motion events */
             event->any.source = stage;
 
+            if (_clutter_event_process_filters (event))
+              break;
+
             /* global grabs */
             if (context->pointer_grab_actor != NULL)
               {
@@ -2632,6 +2648,9 @@ _clutter_process_event_details (ClutterActor        *stage,
             /* Only stage gets motion events */
             event->any.source = stage;
 
+            if (_clutter_event_process_filters (event))
+              break;
+
             /* global grabs */
             if (device->sequence_grab_actors != NULL)
               {
@@ -2735,7 +2754,8 @@ _clutter_process_event_details (ClutterActor        *stage,
       case CLUTTER_STAGE_STATE:
         /* fullscreen / focus - forward to stage */
         event->any.source = stage;
-        clutter_stage_event (CLUTTER_STAGE (stage), event);
+        if (!_clutter_event_process_filters (event))
+          clutter_stage_event (CLUTTER_STAGE (stage), event);
         break;
 
       case CLUTTER_CLIENT_MESSAGE:
diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h
index 2136efe..6515492 100644
--- a/clutter/clutter-private.h
+++ b/clutter/clutter-private.h
@@ -137,6 +137,10 @@ struct _ClutterMainContext
   /* the main event queue */
   GQueue *events_queue;
 
+  /* the event filters added via clutter_event_add_filter. these are
+   * ordered from least recently added to most recently added */
+  GList *event_filters;
+
   ClutterPickMode  pick_mode;
 
   /* mapping between reused integer ids and actors */
diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt
index 6029cef..d3c7f5b 100644
--- a/doc/reference/clutter/clutter-sections.txt
+++ b/doc/reference/clutter/clutter-sections.txt
@@ -1132,6 +1132,9 @@ clutter_event_get
 clutter_event_peek
 clutter_event_put
 clutter_events_pending
+ClutterEventFilterFunc
+clutter_event_add_filter
+clutter_event_remove_filter
 
 <SUBSECTION>
 CLUTTER_BUTTON_PRIMARY


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]