kernelshark: Allow for separate list and graph task filters

To make the task filters more like the event filters, allow the
list and graph to have their own filtering.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
diff --git a/kernel-shark.c b/kernel-shark.c
index b056420..e591657 100644
--- a/kernel-shark.c
+++ b/kernel-shark.c
@@ -64,6 +64,68 @@
 	printf("  -i	input_file, default is %s\n", default_input_file);
 }
 
+/*
+ * trace_sync_select_menu - helper function to the syncing of list and graph filters
+ *
+ * Creates a pop up dialog with the selections given. The selections will be
+ * radio buttons to the user. The keep is a value that will be set to the check
+ * box (default on) if the user wants to keep the selection persistant.
+ */
+static int trace_sync_select_menu(const gchar *title,
+				  gchar **selections, gboolean *keep)
+{
+	GtkWidget *dialog;
+	GtkWidget *radio;
+	GtkWidget *check;
+	GSList *group;
+	int result;
+	int i;
+
+	dialog = gtk_dialog_new_with_buttons(title,
+					     NULL,
+					     GTK_DIALOG_MODAL,
+					     "OK", GTK_RESPONSE_ACCEPT,
+					     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+					     NULL);
+
+	radio = gtk_radio_button_new_with_label(NULL, selections[0]);
+	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), radio, TRUE, TRUE, 0);
+	gtk_widget_show(radio);
+
+	group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio));
+
+	for (i = 1; selections[i]; i++) {
+		radio = gtk_radio_button_new_with_label(group, selections[i]);
+		gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), radio, TRUE, TRUE, 0);
+		gtk_widget_show(radio);
+	}
+
+	check = gtk_check_button_new_with_label("Keep the filters in sync?");
+	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), check, TRUE, TRUE, 0);
+	gtk_widget_show(check);
+
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
+
+	result = gtk_dialog_run(GTK_DIALOG(dialog));
+	switch (result) {
+	case GTK_RESPONSE_ACCEPT:
+		i = 0;
+		for (i = 0; group; i++, group = g_slist_next(group)) {
+			radio = group->data;
+			if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio)))
+				break;
+		}
+		result = i;
+		*keep = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check));
+		break;
+	default:
+		result = -1;
+	}
+
+	gtk_widget_destroy(dialog);
+	return result;
+}
+
 /* graph callbacks */
 
 /* convert_nano() and print_time() are copied from trace-graph.c for debugging
@@ -113,15 +175,30 @@
 	cbs = trace_graph_get_callbacks(ginfo);
 	info = container_of(cbs, struct shark_info, graph_cbs);
 
+	if (!info->sync_task_filters)
+		return;
+
 	if (info->list_filter_enabled)
 		trace_view_update_filters(info->treeview,
 					  task_filter, hide_tasks);
+
+	if (filter_task_count(task_filter) ||
+	    filter_task_count(hide_tasks))
+		info->list_filter_available = 1;
+	else {
+		info->list_filter_enabled = 0;
+		info->list_filter_available = 0;
+	}
 }
 
 static void free_info(struct shark_info *info)
 {
 	tracecmd_close(info->handle);
 	trace_graph_free_info(info->ginfo);
+
+	filter_task_hash_free(info->list_task_filter);
+	filter_task_hash_free(info->list_hide_tasks);
+
 	free(info->ginfo);
 	free(info);
 }
@@ -244,6 +321,99 @@
 
 /* Callback for the clicked signal of the Events filter button */
 static void
+sync_task_filter_clicked (GtkWidget *subitem, gpointer data)
+{
+	struct shark_info *info = data;
+	struct filter_task *task_filter;
+	struct filter_task *hide_tasks;
+	GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview);
+	GtkTreeModel *model;
+	TraceViewStore *store;
+	gboolean keep;
+	gchar *selections[] = { "Sync List Filter with Graph Filter",
+				"Sync Graph Filter with List Filter",
+				NULL };
+	int result;
+
+	if (info->sync_task_filters) {
+		/* Separate the List and Graph filters */
+
+		info->sync_task_filters = 0;
+		gtk_menu_item_set_label(GTK_MENU_ITEM(info->task_sync_menu),
+					"Sync Graph and List Task Filters");
+
+		/* The list now uses its own hash */
+		info->list_task_filter = filter_task_hash_copy(info->ginfo->task_filter);
+		info->list_hide_tasks = filter_task_hash_copy(info->ginfo->hide_tasks);
+		return;
+	}
+
+	model = gtk_tree_view_get_model(trace_tree);
+	if (!model)
+		return;
+
+	store = TRACE_VIEW_STORE(model);
+
+	/* Ask user which way to sync */
+	result = trace_sync_select_menu("Sync Task Filters",
+					selections, &keep);
+
+	switch (result) {
+	case 0:
+		/* Sync List Filter with Graph Filter */
+		filter_task_hash_free(info->list_task_filter);
+		filter_task_hash_free(info->list_hide_tasks);
+
+		info->list_task_filter = NULL;
+		info->list_hide_tasks = NULL;
+
+		task_filter = info->ginfo->task_filter;
+		hide_tasks = info->ginfo->hide_tasks;
+
+		if (!keep) {
+			info->list_task_filter = filter_task_hash_copy(task_filter);
+			info->list_hide_tasks = filter_task_hash_copy(hide_tasks);
+		}
+
+		if (info->list_filter_enabled)
+			trace_view_update_filters(info->treeview,
+						  task_filter, hide_tasks);
+
+		if (!filter_task_count(task_filter) &&
+		    !filter_task_count(hide_tasks)) {
+			info->list_filter_enabled = 0;
+			info->list_filter_available = 0;
+		} else
+			info->list_filter_available = 1;
+
+		break;
+	case 1:
+		/* Sync Graph Filter with List Filter */
+		trace_graph_update_filters(info->ginfo,
+					   info->list_task_filter,
+					   info->list_hide_tasks);
+
+		if (keep) {
+			filter_task_hash_free(info->list_task_filter);
+			filter_task_hash_free(info->list_hide_tasks);
+
+			info->list_task_filter = NULL;
+			info->list_hide_tasks = NULL;
+		}
+		break;
+	default:
+		keep = 0;
+	}
+
+	if (keep) {
+		info->sync_task_filters = 1;
+		gtk_menu_item_set_label(GTK_MENU_ITEM(info->task_sync_menu),
+					"Unsync Graph and List Task Filters");
+	}
+}
+
+/* Callback for the clicked signal of the Events filter button */
+static void
 list_events_clicked (gpointer data)
 {
 	struct shark_info *info = data;
@@ -510,26 +680,70 @@
 filter_list_enable_clicked (gpointer data)
 {
 	struct shark_info *info = data;
+	struct filter_task *task_filter;
+	struct filter_task *hide_tasks;
 
 	info->list_filter_enabled ^= 1;
 
+	if (info->sync_task_filters) {
+		task_filter = info->ginfo->task_filter;
+		hide_tasks = info->ginfo->hide_tasks;
+	} else {
+		task_filter = info->list_task_filter;
+		hide_tasks = info->list_hide_tasks;
+	}
+
 	if (info->list_filter_enabled)
 		trace_view_update_filters(info->treeview,
-					  info->ginfo->task_filter,
-					  info->ginfo->hide_tasks);
+					  task_filter, hide_tasks);
 	else
 		trace_view_update_filters(info->treeview, NULL, NULL);
 }
 
 static void
+filter_update_list_filter(struct shark_info *info,
+			  struct filter_task *filter,
+			  struct filter_task *other_filter)
+{
+	struct filter_task_item *task;
+	int pid = info->selected_task;
+
+	task = filter_task_find_pid(filter, pid);
+	if (task) {
+		filter_task_remove_pid(filter, pid);
+		if (!filter_task_count(filter) &&
+		    !filter_task_count(other_filter)) {
+			info->list_filter_enabled = 0;
+			info->list_filter_available = 0;
+		}
+	} else {
+		filter_task_add_pid(filter, pid);
+		info->list_filter_available = 1;
+	}
+}
+
+static void
 filter_add_task_clicked (gpointer data)
 {
 	struct shark_info *info = data;
+	int pid = info->selected_task;
+
+	if (info->sync_task_filters) {
+		trace_graph_filter_add_remove_task(info->ginfo, pid);
+		return;
+	}
+
+	filter_update_list_filter(info, info->list_task_filter, info->list_hide_tasks);
+	trace_view_update_filters(info->treeview,
+				  info->list_task_filter, info->list_hide_tasks);
+}
+
+static void
+filter_graph_add_task_clicked (gpointer data)
+{
+	struct shark_info *info = data;
 
 	trace_graph_filter_add_remove_task(info->ginfo, info->selected_task);
-
-	if (!filter_task_count(info->ginfo->task_filter))
-		info->list_filter_enabled = 0;
 }
 
 static void
@@ -537,11 +751,22 @@
 {
 	struct shark_info *info = data;
 
-	trace_graph_filter_hide_show_task(info->ginfo, info->selected_task);
+	if (info->sync_task_filters) {
+		trace_graph_filter_hide_show_task(info->ginfo, info->selected_task);
+		return;
+	}
 
-	if (!filter_task_count(info->ginfo->task_filter) &&
-	    !filter_task_count(info->ginfo->hide_tasks))
-		info->list_filter_enabled = 0;
+	filter_update_list_filter(info, info->list_hide_tasks, info->list_task_filter);
+	trace_view_update_filters(info->treeview,
+				  info->list_task_filter, info->list_hide_tasks);
+}
+
+static void
+filter_graph_hide_task_clicked (gpointer data)
+{
+	struct shark_info *info = data;
+
+	trace_graph_filter_hide_show_task(info->ginfo, info->selected_task);
 }
 
 static void
@@ -549,11 +774,27 @@
 {
 	struct shark_info *info = data;
 
-	trace_graph_clear_tasks(info->ginfo);
+	if (info->sync_task_filters) {
+		trace_graph_clear_tasks(info->ginfo);
+		return;
+	}
 
+	filter_task_clear(info->list_task_filter);
+	filter_task_clear(info->list_hide_tasks);
+	trace_view_update_filters(info->treeview, NULL, NULL);
+
+	info->list_filter_available = 0;
 	info->list_filter_enabled = 0;
 }
 
+static void
+filter_graph_clear_tasks_clicked (gpointer data)
+{
+	struct shark_info *info = data;
+
+	trace_graph_clear_tasks(info->ginfo);
+}
+
 static void graph_check_toggle(gpointer data, GtkWidget *widget)
 {
 	struct shark_info *info = data;
@@ -561,6 +802,17 @@
 	info->graph_follows = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
 }
 
+static void set_menu_label(GtkWidget *menu, const char *comm, int pid,
+			   const char *fmt)
+{
+	int len = strlen(comm) + strlen(fmt) + 50;
+	char text[len];
+
+	snprintf(text, len, fmt, comm, pid);
+
+	gtk_menu_item_set_label(GTK_MENU_ITEM(menu), text);
+}
+
 static gboolean
 do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data)
 {
@@ -572,11 +824,13 @@
 	static GtkWidget *menu_filter_add_task;
 	static GtkWidget *menu_filter_hide_task;
 	static GtkWidget *menu_filter_clear_tasks;
+	static GtkWidget *menu_filter_graph_add_task;
+	static GtkWidget *menu_filter_graph_hide_task;
+	static GtkWidget *menu_filter_graph_clear_tasks;
 	struct record *record;
 	TraceViewRecord *vrec;
 	GtkTreeModel *model;
 	const char *comm;
-	gchar *text;
 	gint pid;
 	gint len;
 	guint64 offset;
@@ -585,7 +839,7 @@
 
 	if (!menu) {
 		menu = gtk_menu_new();
-		menu_filter_graph_enable = gtk_menu_item_new_with_label("Enable Graph Filter");
+		menu_filter_graph_enable = gtk_menu_item_new_with_label("Enable Graph Task Filter");
 		gtk_widget_show(menu_filter_graph_enable);
 		gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_graph_enable);
 
@@ -593,7 +847,7 @@
 					  G_CALLBACK (filter_graph_enable_clicked),
 					  data);
 
-		menu_filter_list_enable = gtk_menu_item_new_with_label("Enable List Filter");
+		menu_filter_list_enable = gtk_menu_item_new_with_label("Enable List Task Filter");
 		gtk_widget_show(menu_filter_list_enable);
 		gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_list_enable);
 
@@ -609,6 +863,14 @@
 					  G_CALLBACK (filter_add_task_clicked),
 					  data);
 
+		menu_filter_graph_add_task = gtk_menu_item_new_with_label("Add Task to Graph");
+		gtk_widget_show(menu_filter_graph_add_task);
+		gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_graph_add_task);
+
+		g_signal_connect_swapped (G_OBJECT (menu_filter_graph_add_task), "activate",
+					  G_CALLBACK (filter_graph_add_task_clicked),
+					  data);
+
 		menu_filter_hide_task = gtk_menu_item_new_with_label("Hide Task");
 		gtk_widget_show(menu_filter_hide_task);
 		gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_hide_task);
@@ -617,6 +879,14 @@
 					  G_CALLBACK (filter_hide_task_clicked),
 					  data);
 
+		menu_filter_graph_hide_task = gtk_menu_item_new_with_label("Hide Task from Graph");
+		gtk_widget_show(menu_filter_graph_hide_task);
+		gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_graph_hide_task);
+
+		g_signal_connect_swapped (G_OBJECT (menu_filter_graph_hide_task), "activate",
+					  G_CALLBACK (filter_graph_hide_task_clicked),
+					  data);
+
 		menu_filter_clear_tasks = gtk_menu_item_new_with_label("Clear Task Filter");
 		gtk_widget_show(menu_filter_clear_tasks);
 		gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_clear_tasks);
@@ -625,6 +895,15 @@
 					  G_CALLBACK (filter_clear_tasks_clicked),
 					  data);
 
+		menu_filter_graph_clear_tasks =
+			gtk_menu_item_new_with_label("Clear Graph Task Filter");
+		gtk_widget_show(menu_filter_graph_clear_tasks);
+		gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_graph_clear_tasks);
+
+		g_signal_connect_swapped (G_OBJECT (menu_filter_graph_clear_tasks), "activate",
+					  G_CALLBACK (filter_graph_clear_tasks_clicked),
+					  data);
+
 	}
 
 	row = trace_view_get_selected_row(GTK_WIDGET(info->treeview));
@@ -642,29 +921,59 @@
 
 			len = strlen(comm) + 50;
 
-			text = g_malloc(len);
-			g_assert(text);
+			if (info->sync_task_filters) {
+				if (trace_graph_filter_task_find_pid(ginfo, pid))
+					set_menu_label(menu_filter_add_task, comm, pid,
+						       "Remove %s-%d from filters");
+				else
+					set_menu_label(menu_filter_add_task, comm, pid,
+						       "Add %s-%d to filters");
 
-			if (trace_graph_filter_task_find_pid(ginfo, pid))
-				snprintf(text, len, "Remove %s-%d from filter", comm, pid);
-			else
-				snprintf(text, len, "Add %s-%d to filter", comm, pid);
+				if (trace_graph_hide_task_find_pid(ginfo, pid))
+					set_menu_label(menu_filter_hide_task, comm, pid,
+						       "Show %s-%d");
+				else
+					set_menu_label(menu_filter_hide_task, comm, pid,
+						       "Hide %s-%d");
+
+				gtk_widget_hide(menu_filter_graph_add_task);
+				gtk_widget_hide(menu_filter_graph_hide_task);
+
+			} else {
+				if (filter_task_find_pid(info->list_task_filter, pid))
+					set_menu_label(menu_filter_add_task, comm, pid,
+						       "Remove %s-%d from List filter");
+				else
+					set_menu_label(menu_filter_add_task, comm, pid,
+						       "Add %s-%d to List filter");
+
+				if (filter_task_find_pid(info->list_hide_tasks, pid))
+					set_menu_label(menu_filter_hide_task, comm, pid,
+						       "Show %s-%d in List");
+				else
+					set_menu_label(menu_filter_hide_task, comm, pid,
+						       "Hide %s-%d from List");
+
+				if (trace_graph_filter_task_find_pid(ginfo, pid))
+					set_menu_label(menu_filter_graph_add_task, comm, pid,
+						       "Remove %s-%d from Graph filter");
+				else
+					set_menu_label(menu_filter_graph_add_task, comm, pid,
+						       "Add %s-%d to Graph filter");
+
+				if (trace_graph_hide_task_find_pid(ginfo, pid))
+					set_menu_label(menu_filter_graph_hide_task, comm, pid,
+						       "Show %s-%d in Graph");
+				else
+					set_menu_label(menu_filter_graph_hide_task, comm, pid,
+						       "Hide %s-%d from Graph");
+
+				gtk_widget_show(menu_filter_graph_add_task);
+				gtk_widget_show(menu_filter_graph_hide_task);
+			}
 
 			ginfo->filter_task_selected = pid;
 
-			gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_add_task),
-						text);
-
-			if (trace_graph_hide_task_find_pid(ginfo, pid))
-				snprintf(text, len, "Show %s-%d", comm, pid);
-			else
-				snprintf(text, len, "Hide %s-%d", comm, pid);
-
-			gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_hide_task),
-						text);
-
-			g_free(text);
-
 			info->selected_task = pid;
 
 			gtk_widget_show(menu_filter_add_task);
@@ -674,35 +983,62 @@
 	} else {
 		gtk_widget_hide(menu_filter_add_task);
 		gtk_widget_hide(menu_filter_hide_task);
+		gtk_widget_hide(menu_filter_graph_add_task);
+		gtk_widget_hide(menu_filter_graph_hide_task);
 	}
 
 	if (ginfo->filter_enabled)
 		gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_graph_enable),
-					"Disable Graph Filter");
+					"Disable Graph Task Filter");
 	else
 		gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_graph_enable),
-					"Enable Graph Filter");
+					"Enable Graph Task Filter");
 
 	if (info->list_filter_enabled)
 		gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_list_enable),
-					"Disable List Filter");
+					"Disable List Task Filter");
 	else
 		gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_list_enable),
-					"Enable List Filter");
+					"Enable List Task Filter");
 
-	if (ginfo->filter_available) {
+	if (ginfo->filter_available)
 		gtk_widget_set_sensitive(menu_filter_graph_enable, TRUE);
-		gtk_widget_set_sensitive(menu_filter_list_enable, TRUE);
-	} else {
-		gtk_widget_set_sensitive(menu_filter_graph_enable, FALSE);
-		gtk_widget_set_sensitive(menu_filter_list_enable, FALSE);
-	}
-
-	if (filter_task_count(ginfo->task_filter) ||
-	    filter_task_count(ginfo->hide_tasks))
-		gtk_widget_set_sensitive(menu_filter_clear_tasks, TRUE);
 	else
-		gtk_widget_set_sensitive(menu_filter_clear_tasks, FALSE);
+		gtk_widget_set_sensitive(menu_filter_graph_enable, FALSE);
+
+	if ((info->sync_task_filters && ginfo->filter_available) ||
+	    (!info->sync_task_filters && info->list_filter_available))
+		gtk_widget_set_sensitive(menu_filter_list_enable, TRUE);
+	else
+		gtk_widget_set_sensitive(menu_filter_list_enable, FALSE);
+
+	if (info->sync_task_filters) {
+		if (filter_task_count(ginfo->task_filter) ||
+		    filter_task_count(ginfo->hide_tasks))
+			gtk_widget_set_sensitive(menu_filter_clear_tasks, TRUE);
+		else
+			gtk_widget_set_sensitive(menu_filter_clear_tasks, FALSE);
+
+		set_menu_label(menu_filter_clear_tasks, comm, pid,
+			       "Clear Task Filter");
+		gtk_widget_hide(menu_filter_graph_clear_tasks);
+	} else {
+		if (filter_task_count(ginfo->task_filter) ||
+		    filter_task_count(ginfo->hide_tasks))
+			gtk_widget_set_sensitive(menu_filter_graph_clear_tasks, TRUE);
+		else
+			gtk_widget_set_sensitive(menu_filter_graph_clear_tasks, FALSE);
+
+		if (filter_task_count(info->list_task_filter) ||
+		    filter_task_count(info->list_hide_tasks))
+			gtk_widget_set_sensitive(menu_filter_clear_tasks, TRUE);
+		else
+			gtk_widget_set_sensitive(menu_filter_clear_tasks, FALSE);
+
+		set_menu_label(menu_filter_clear_tasks, comm, pid,
+			       "Clear List Task Filter");
+		gtk_widget_show(menu_filter_graph_clear_tasks);
+	}
 		
 	gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3,
 		       gtk_get_current_event_time());
@@ -785,6 +1121,7 @@
 		handle = NULL;
 
 	info->handle = handle;
+	info->sync_task_filters = TRUE;
 
 	/* --- Main window --- */
 
@@ -891,6 +1228,25 @@
 	menu = gtk_menu_new();    /* Don't need to show menus */
 
 
+
+	/* --- Filter - Sync task Option --- */
+
+	sub_item = gtk_menu_item_new_with_label("Unsync Graph and List Task Filters");
+
+	info->task_sync_menu = sub_item;
+
+	/* Add them to the menu */
+	gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item);
+
+	/* We can attach the Quit menu item to our exit function */
+	g_signal_connect (G_OBJECT (sub_item), "activate",
+			  G_CALLBACK (sync_task_filter_clicked),
+			  (gpointer) info);
+
+	/* We do need to show menu items */
+	gtk_widget_show(sub_item);
+
+
 	/* --- Filter - List Events Option --- */
 
 	sub_item = gtk_menu_item_new_with_label("list events");
diff --git a/kernel-shark.h b/kernel-shark.h
index edb3787..f931406 100644
--- a/kernel-shark.h
+++ b/kernel-shark.h
@@ -30,10 +30,15 @@
 	struct tracecmd_input  		*handle;
 	GtkWidget			*treeview;
 	GtkWidget			*spin;
+	GtkWidget			*task_sync_menu;
 	struct graph_callbacks		graph_cbs;
 	gint				selected_task;
 	gboolean			list_filter_enabled;
+	gboolean			list_filter_available;
 	gboolean			graph_follows;
+	gboolean			sync_task_filters;
+	struct filter_task		*list_task_filter;
+	struct filter_task		*list_hide_tasks;
 };
 
 #define offset_of(type, field)		(long)(&((type *)0)->field)
diff --git a/trace-graph.c b/trace-graph.c
index 9e5cd19..2bbe73f 100644
--- a/trace-graph.c
+++ b/trace-graph.c
@@ -548,6 +548,20 @@
 		redraw_graph(ginfo);
 }
 
+void trace_graph_update_filters(struct graph_info *ginfo,
+				struct filter_task *task_filter,
+				struct filter_task *hide_tasks)
+{
+	filter_task_hash_free(ginfo->task_filter);
+	filter_task_hash_free(ginfo->hide_tasks);
+
+	ginfo->task_filter = filter_task_hash_copy(task_filter);
+	ginfo->hide_tasks = filter_task_hash_copy(hide_tasks);
+
+	if (ginfo->filter_enabled)
+		redraw_graph(ginfo);
+}
+
 static void
 filter_clear_tasks_clicked (gpointer data)
 {
diff --git a/trace-graph.h b/trace-graph.h
index 916ad50..91194c1 100644
--- a/trace-graph.h
+++ b/trace-graph.h
@@ -311,6 +311,9 @@
 			     struct tracecmd_xml_handle *handle);
 int trace_graph_save_filters(struct graph_info *ginfo,
 			     struct tracecmd_xml_handle *handle);
+void trace_graph_update_filters(struct graph_info *ginfo,
+				struct filter_task *task_filter,
+				struct filter_task *hide_tasks);
 
 /* plots */
 void trace_graph_plot_free(struct graph_info *ginfo);
diff --git a/trace-view-store.c b/trace-view-store.c
index ba40aad..6f70ca5 100644
--- a/trace-view-store.c
+++ b/trace-view-store.c
@@ -1330,7 +1330,6 @@
 
 	if (store->task_filter != task_filter)
 		store->task_filter = filter_task_hash_copy(task_filter);
-
 }