diff -Nru gtk+2.0-2.24.10/debian/changelog gtk+2.0-2.24.10/debian/changelog --- gtk+2.0-2.24.10/debian/changelog 2014-02-06 19:22:45.000000000 +0400 +++ gtk+2.0-2.24.10/debian/changelog 2015-02-25 12:09:54.000000000 +0300 @@ -1,3 +1,12 @@ +gtk+2.0 (2.24.10-0ubuntu6.2) precise; urgency=low + + * Non-maintainer upload. + * debian/patches/fix_gdk_event_apply_filters.patch: new patch. + Makes gdk_event_apply_filters function safe against changes in the + filter list, and so prevents weird crashes in various apps. + + -- Vlad Orlov Wed, 25 Feb 2015 12:09:22 +0300 + gtk+2.0 (2.24.10-0ubuntu6.1) precise; urgency=low * debian/patches/backport_search_printer_location.patch: diff -Nru gtk+2.0-2.24.10/debian/patches/fix_gdk_event_apply_filters.patch gtk+2.0-2.24.10/debian/patches/fix_gdk_event_apply_filters.patch --- gtk+2.0-2.24.10/debian/patches/fix_gdk_event_apply_filters.patch 1970-01-01 03:00:00.000000000 +0300 +++ gtk+2.0-2.24.10/debian/patches/fix_gdk_event_apply_filters.patch 2015-02-25 12:11:00.000000000 +0300 @@ -0,0 +1,319 @@ +Index: gtk+2.0-2.24.10/gdk/gdkinternals.h +=================================================================== +--- gtk+2.0-2.24.10.orig/gdk/gdkinternals.h 2011-12-20 22:32:29.000000000 +0400 ++++ gtk+2.0-2.24.10/gdk/gdkinternals.h 2015-02-25 12:10:56.838158414 +0300 +@@ -59,9 +59,15 @@ + guint ref_count; + }; + ++typedef enum { ++ GDK_EVENT_FILTER_REMOVED = 1 << 0 ++} GdkEventFilterFlags; ++ + struct _GdkEventFilter { + GdkFilterFunc function; + gpointer data; ++ GdkEventFilterFlags flags; ++ guint ref_count; + }; + + struct _GdkClientFilter { +Index: gtk+2.0-2.24.10/gdk/gdkwindow.c +=================================================================== +--- gtk+2.0-2.24.10.orig/gdk/gdkwindow.c 2011-11-08 21:20:20.000000000 +0400 ++++ gtk+2.0-2.24.10/gdk/gdkwindow.c 2015-02-25 12:10:56.842158414 +0300 +@@ -2545,13 +2545,18 @@ + { + filter = (GdkEventFilter *)tmp_list->data; + if ((filter->function == function) && (filter->data == data)) +- return; ++ { ++ filter->ref_count++; ++ return; ++ } + tmp_list = tmp_list->next; + } + + filter = g_new (GdkEventFilter, 1); + filter->function = function; + filter->data = data; ++ filter->ref_count = 1; ++ filter->flags = 0; + + if (private) + private->filters = g_list_append (private->filters, filter); +@@ -2593,16 +2598,21 @@ + tmp_list = tmp_list->next; + + if ((filter->function == function) && (filter->data == data)) +- { +- if (private) +- private->filters = g_list_remove_link (private->filters, node); +- else +- _gdk_default_filters = g_list_remove_link (_gdk_default_filters, node); +- g_list_free_1 (node); +- g_free (filter); ++ { ++ filter->flags |= GDK_EVENT_FILTER_REMOVED; ++ filter->ref_count--; ++ if (filter->ref_count != 0) ++ return; ++ ++ if (private) ++ private->filters = g_list_remove_link (private->filters, node); ++ else ++ _gdk_default_filters = g_list_remove_link (_gdk_default_filters, node); ++ g_list_free_1 (node); ++ g_free (filter); + +- return; +- } ++ return; ++ } + } + } + +Index: gtk+2.0-2.24.10/gdk/quartz/gdkevents-quartz.c +=================================================================== +--- gtk+2.0-2.24.10.orig/gdk/quartz/gdkevents-quartz.c 2012-02-06 17:48:55.000000000 +0400 ++++ gtk+2.0-2.24.10/gdk/quartz/gdkevents-quartz.c 2015-02-25 12:10:56.846158414 +0300 +@@ -200,21 +200,42 @@ + static gint + gdk_event_apply_filters (NSEvent *nsevent, + GdkEvent *event, +- GList *filters) ++ GList **filters) + { + GList *tmp_list; + GdkFilterReturn result; + +- 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 (nsevent, event, filter->data); +- if (result != GDK_FILTER_CONTINUE) +- return result; ++ ++ /* 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) ++ return result; + } + + return GDK_FILTER_CONTINUE; +@@ -1199,7 +1220,7 @@ + /* Apply global filters */ + GdkFilterReturn result; + +- result = gdk_event_apply_filters (nsevent, event, _gdk_default_filters); ++ result = gdk_event_apply_filters (nsevent, event, &_gdk_default_filters); + if (result != GDK_FILTER_CONTINUE) + { + return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE; +@@ -1264,19 +1285,19 @@ + GdkFilterReturn result; + + if (filter_private->filters) +- { +- g_object_ref (window); ++ { ++ g_object_ref (window); + +- result = gdk_event_apply_filters (nsevent, event, filter_private->filters); ++ result = gdk_event_apply_filters (nsevent, event, &filter_private->filters); + +- g_object_unref (window); ++ g_object_unref (window); + +- if (result != GDK_FILTER_CONTINUE) +- { +- return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE; +- goto done; +- } +- } ++ if (result != GDK_FILTER_CONTINUE) ++ { ++ return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE; ++ goto done; ++ } ++ } + } + + /* If the app is not active leave the event to AppKit so the window gets +Index: gtk+2.0-2.24.10/gdk/win32/gdkevents-win32.c +=================================================================== +--- gtk+2.0-2.24.10.orig/gdk/win32/gdkevents-win32.c 2011-11-08 21:20:20.000000000 +0400 ++++ gtk+2.0-2.24.10/gdk/win32/gdkevents-win32.c 2015-02-25 12:10:56.846158414 +0300 +@@ -1069,7 +1069,7 @@ + static GdkFilterReturn + apply_event_filters (GdkWindow *window, + MSG *msg, +- GList *filters) ++ GList **filters) + { + GdkFilterReturn result = GDK_FILTER_CONTINUE; + GdkEvent *event; +@@ -1087,15 +1087,36 @@ + */ + 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); +- if (result != GDK_FILTER_CONTINUE) +- break; ++ ++ /* 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; + } + + if (result == GDK_FILTER_CONTINUE || result == GDK_FILTER_REMOVE) +@@ -2075,7 +2096,7 @@ + { + /* 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, +@@ -2121,7 +2142,7 @@ + { + /* 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) + { +Index: gtk+2.0-2.24.10/gdk/x11/gdkevents-x11.c +=================================================================== +--- gtk+2.0-2.24.10.orig/gdk/x11/gdkevents-x11.c 2011-08-16 06:30:52.000000000 +0400 ++++ gtk+2.0-2.24.10/gdk/x11/gdkevents-x11.c 2015-02-25 12:10:56.846158414 +0300 +@@ -96,7 +96,7 @@ + + static gint gdk_event_apply_filters (XEvent *xevent, + GdkEvent *event, +- GList *filters); ++ GList **filters); + static gboolean gdk_event_translate (GdkDisplay *display, + GdkEvent *event, + XEvent *xevent, +@@ -341,21 +341,42 @@ + static gint + gdk_event_apply_filters (XEvent *xevent, + GdkEvent *event, +- GList *filters) ++ GList **filters) + { + GList *tmp_list; + GdkFilterReturn result; + +- tmp_list = filters; ++ tmp_list = *filters; + + while (tmp_list) + { + GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data; ++ GList *node; + +- tmp_list = tmp_list->next; ++ if ((filter->flags & GDK_EVENT_FILTER_REMOVED) != 0) ++ { ++ tmp_list = tmp_list->next; ++ continue; ++ } ++ ++ filter->ref_count++; + result = filter->function (xevent, event, filter->data); +- if (result != GDK_FILTER_CONTINUE) +- return result; ++ ++ /* 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) ++ return result; + } + + return GDK_FILTER_CONTINUE; +@@ -925,7 +946,7 @@ + /* Apply global filters */ + GdkFilterReturn result; + result = gdk_event_apply_filters (xevent, event, +- _gdk_default_filters); ++ &_gdk_default_filters); + + if (result != GDK_FILTER_CONTINUE) + { +@@ -1031,7 +1052,7 @@ + g_object_ref (filter_window); + + result = gdk_event_apply_filters (xevent, event, +- filter_private->filters); ++ &filter_private->filters); + + g_object_unref (filter_window); + diff -Nru gtk+2.0-2.24.10/debian/patches/series gtk+2.0-2.24.10/debian/patches/series --- gtk+2.0-2.24.10/debian/patches/series 2014-02-06 19:22:14.000000000 +0400 +++ gtk+2.0-2.24.10/debian/patches/series 2015-02-25 12:10:53.000000000 +0300 @@ -26,3 +26,4 @@ 099_printer_filename_fix.patch 100_overlay_scrollbar_loading.patch backport_search_printer_location.patch +fix_gdk_event_apply_filters.patch