Make gdk_event_apply_filters safe against changes in filter list
An event filter may add or remove filters itself. This patch does two things to address this case. The first is to take a temporary reference to the filter while it is being used. The second is to wait until after the filter function is run before determining the next node in the list to process. This guards against changes to the next node. It also does not run functions that have been marked as removed. Though I'm not sure if this case can arise. https://bugzilla.gnome.org/show_bug.cgi?id=635380
This commit is contained in:
@ -1025,7 +1025,7 @@ fill_key_event_string (GdkEvent *event)
|
||||
static GdkFilterReturn
|
||||
apply_event_filters (GdkWindow *window,
|
||||
MSG *msg,
|
||||
GList *filters)
|
||||
GList **filters)
|
||||
{
|
||||
GdkFilterReturn result = GDK_FILTER_CONTINUE;
|
||||
GdkEvent *event;
|
||||
@ -1043,13 +1043,34 @@ apply_event_filters (GdkWindow *window,
|
||||
*/
|
||||
node = _gdk_event_queue_append (_gdk_display, event);
|
||||
|
||||
tmp_list = filters;
|
||||
tmp_list = *filters;
|
||||
while (tmp_list)
|
||||
{
|
||||
GdkEventFilter *filter = (GdkEventFilter *) tmp_list->data;
|
||||
|
||||
tmp_list = tmp_list->next;
|
||||
GList *node;
|
||||
|
||||
if ((filter->flags & GDK_EVENT_FILTER_REMOVED) != 0)
|
||||
{
|
||||
tmp_list = tmp_list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
filter->ref_count++;
|
||||
result = filter->function (msg, event, filter->data);
|
||||
|
||||
/* get the next node after running the function since the
|
||||
function may add or remove a next node */
|
||||
node = tmp_list;
|
||||
tmp_list = tmp_list->next;
|
||||
|
||||
filter->ref_count--;
|
||||
if (filter->ref_count == 0)
|
||||
{
|
||||
*filters = g_list_remove_link (*filters, node);
|
||||
g_list_free_1 (node);
|
||||
g_free (filter);
|
||||
}
|
||||
|
||||
if (result != GDK_FILTER_CONTINUE)
|
||||
break;
|
||||
}
|
||||
@ -1756,7 +1777,7 @@ gdk_event_translate (MSG *msg,
|
||||
{
|
||||
/* Apply global filters */
|
||||
|
||||
GdkFilterReturn result = apply_event_filters (NULL, msg, _gdk_default_filters);
|
||||
GdkFilterReturn result = apply_event_filters (NULL, msg, &_gdk_default_filters);
|
||||
|
||||
/* If result is GDK_FILTER_CONTINUE, we continue as if nothing
|
||||
* happened. If it is GDK_FILTER_REMOVE or GDK_FILTER_TRANSLATE,
|
||||
@ -1822,7 +1843,7 @@ gdk_event_translate (MSG *msg,
|
||||
{
|
||||
/* Apply per-window filters */
|
||||
|
||||
GdkFilterReturn result = apply_event_filters (window, msg, ((GdkWindowObject *) window)->filters);
|
||||
GdkFilterReturn result = apply_event_filters (window, msg, &((GdkWindowObject *) window)->filters);
|
||||
|
||||
if (result == GDK_FILTER_REMOVE || result == GDK_FILTER_TRANSLATE)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user