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
This commit is contained in:
parent
c2b0b9aace
commit
70292672c4
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user