void _gdk_events_queue (GdkDisplay *display);
GdkEvent* _gdk_event_unqueue (GdkDisplay *display);
+void _gdk_event_filter_unref (GdkWindow *window,
+ GdkEventFilter *filter);
+
void _gdk_event_emit (GdkEvent *event);
GList* _gdk_event_queue_find_first (GdkDisplay *display);
void _gdk_event_queue_remove_link (GdkDisplay *display,
return TRUE;
}
-static void
-window_remove_filters (GdkWindow *window)
+/**
+ * _gdk_event_filter_unref:
+ * @window: A #GdkWindow, or %NULL to be the global window
+ * @filter: A window filter
+ *
+ * Release a reference to @filter. Note this function may
+ * mutate the list storage, so you need to handle this
+ * if iterating over a list of filters.
+ */
+void
+_gdk_event_filter_unref (GdkWindow *window,
+ GdkEventFilter *filter)
{
- if (window->filters)
+ GList **filters;
+ GList *tmp_list;
+
+ if (window == NULL)
+ filters = &_gdk_default_filters;
+ else
+ filters = &window->filters;
+
+ for (tmp_list = *filters; tmp_list; tmp_list = tmp_list->next)
{
- GList *tmp_list;
+ GdkEventFilter *iter_filter = tmp_list->data;
+ GList *node;
+
+ if (iter_filter != filter)
+ continue;
- for (tmp_list = window->filters; tmp_list; tmp_list = tmp_list->next)
- g_free (tmp_list->data);
+ g_assert (iter_filter->ref_count > 0);
- g_list_free (window->filters);
- window->filters = NULL;
+ filter->ref_count--;
+ if (filter->ref_count != 0)
+ continue;
+
+ node = tmp_list;
+ tmp_list = tmp_list->next;
+
+ *filters = g_list_remove_link (*filters, node);
+ g_free (filter);
+ g_list_free_1 (node);
}
}
+static void
+window_remove_filters (GdkWindow *window)
+{
+ while (window->filters)
+ _gdk_event_filter_unref (window, window->filters->data);
+}
+
static void
update_pointer_info_foreach (GdkDisplay *display,
GdkDevice *device,
if ((filter->function == function) && (filter->data == data))
{
filter->flags |= GDK_EVENT_FILTER_REMOVED;
- filter->ref_count--;
- if (filter->ref_count != 0)
- return;
- if (window)
- window->filters = g_list_remove_link (window->filters, node);
- else
- _gdk_default_filters = g_list_remove_link (_gdk_default_filters, node);
- g_list_free_1 (node);
- g_free (filter);
+ _gdk_event_filter_unref (window, filter);
return;
}
static GList *event_sources = NULL;
static gint
-gdk_event_apply_filters (XEvent *xevent,
- GdkEvent *event,
- GList **filters)
+gdk_event_apply_filters (XEvent *xevent,
+ GdkEvent *event,
+ GdkWindow *window)
{
GList *tmp_list;
GdkFilterReturn result;
- tmp_list = *filters;
+ if (window == NULL)
+ tmp_list = _gdk_default_filters;
+ else
+ tmp_list = window->filters;
while (tmp_list)
{
filter->ref_count++;
result = filter->function (xevent, 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;
+ /* Protect against unreffing the filter mutating the list */
+ node = 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);
- }
+ _gdk_event_filter_unref (window, filter);
+
+ tmp_list = node;
if (result != GDK_FILTER_CONTINUE)
return result;
{
/* Apply global filters */
- result = gdk_event_apply_filters (xevent, event,
- &_gdk_default_filters);
+ result = gdk_event_apply_filters (xevent, event, NULL);
if (result == GDK_FILTER_REMOVE)
{
if (filter_window->filters)
{
result = gdk_event_apply_filters (xevent, event,
- &filter_window->filters);
+ filter_window);
if (result == GDK_FILTER_REMOVE)
{