diff src/gtkdebug.c @ 11033:50224ac8184d

[gaim-migrate @ 12919] Ok, this is debug window filtering. Sadrul was going to do this with a text entry, but I like this better, feel free to disagree with me. It's not the prettiest in a couple places, most notable gtkmain.c where a bunch of categories that don't currently have a home get registered. I added some plugin_(un)load functions to some plugins to place the (un)register functions. Though I didn't do that for the prpls. Comments and cleanups welcome. (Oh, I've been seeing some crashes on quit, but I haven't been able to get it to happen reliably so I'm not sure if it's my code or some transient HEAD oscar/other crash.) committer: Tailor Script <tailor@pidgin.im>
author Etan Reisner <pidgin@unreliablesource.net>
date Tue, 28 Jun 2005 06:13:07 +0000
parents 42dbc4ba1325
children ba506d2e6a8e
line wrap: on
line diff
--- a/src/gtkdebug.c	Sun Jun 26 01:14:51 2005 +0000
+++ b/src/gtkdebug.c	Tue Jun 28 06:13:07 2005 +0000
@@ -42,6 +42,9 @@
 	GtkWidget *text;
 	GtkWidget *find;
 
+	/* The category filter tree view. */
+	GtkWidget *treeview;
+
 	gboolean timestamps;
 	gboolean paused;
 
@@ -58,6 +61,9 @@
 
 static DebugWindow *debug_win = NULL;
 
+static GHashTable *debug_categories = NULL;
+static gboolean filter_enabled = FALSE;
+
 struct _find {
 	DebugWindow *window;
 	GtkWidget *entry;
@@ -220,6 +226,26 @@
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data), GPOINTER_TO_INT(value));
 }
 
+static void
+filter_cb(GtkToggleButton *button, DebugWindow *win)
+{
+	if (gtk_toggle_button_get_active(button)) {
+		filter_enabled = TRUE;
+	} else {
+		filter_enabled = FALSE;
+	}
+}
+
+static void
+debug_liststore_append(gpointer key, gpointer value, gpointer user_data)
+{
+	GtkTreeIter iter;
+	GtkListStore **liststore = (GtkListStore **)user_data;
+
+	gtk_list_store_append(*liststore, &iter);
+	gtk_list_store_set(*liststore, &iter, 0, key, -1);
+}
+
 static DebugWindow *
 debug_window_new(void)
 {
@@ -229,6 +255,10 @@
 	GtkWidget *frame;
 	GtkWidget *button;
 	GtkWidget *image;
+	GtkListStore *liststore = NULL;
+	GtkCellRenderer *renderer = NULL;
+	GtkTreeSelection *selection = NULL;
+	GtkTreeViewColumn *column = NULL;
 	int width, height;
 
 	win = g_new0(DebugWindow, 1);
@@ -238,16 +268,16 @@
 
 	GAIM_DIALOG(win->window);
 	gaim_debug_info("gtkdebug", "Setting dimensions to %d, %d\n",
-			   width, height);
+	                width, height);
 
 	gtk_window_set_default_size(GTK_WINDOW(win->window), width, height);
 	gtk_window_set_role(GTK_WINDOW(win->window), "debug");
 	gtk_window_set_title(GTK_WINDOW(win->window), _("Debug Window"));
 
 	g_signal_connect(G_OBJECT(win->window), "delete_event",
-					 G_CALLBACK(debug_window_destroy), NULL);
+	                 G_CALLBACK(debug_window_destroy), NULL);
 	g_signal_connect(G_OBJECT(win->window), "configure_event",
-					 G_CALLBACK(configure_cb), win);
+	                 G_CALLBACK(configure_cb), win);
 
 	/* Setup the vbox */
 	vbox = gtk_vbox_new(FALSE, 0);
@@ -256,45 +286,85 @@
 	if (gaim_prefs_get_bool("/gaim/gtk/debug/toolbar")) {
 		/* Setup our top button bar thingie. */
 		toolbar = gtk_toolbar_new();
-		gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH_HORIZ);
+		gtk_toolbar_set_style(GTK_TOOLBAR(toolbar),
+		                      GTK_TOOLBAR_BOTH_HORIZ);
 		gtk_toolbar_set_icon_size(GTK_TOOLBAR(toolbar),
-								  GTK_ICON_SIZE_SMALL_TOOLBAR);
+		                          GTK_ICON_SIZE_SMALL_TOOLBAR);
 
 		gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
 
 		/* Find button */
 		gtk_toolbar_insert_stock(GTK_TOOLBAR(toolbar), GTK_STOCK_FIND,
-								 NULL, NULL, G_CALLBACK(find_cb), win, -1);
+		                         NULL, NULL, G_CALLBACK(find_cb),
+		                         win, -1);
 
 		/* Save */
 		gtk_toolbar_insert_stock(GTK_TOOLBAR(toolbar), GTK_STOCK_SAVE,
-								 NULL, NULL, G_CALLBACK(save_cb), win, -1);
+		                         NULL, NULL, G_CALLBACK(save_cb),
+		                         win, -1);
 
 		/* Clear button */
 		gtk_toolbar_insert_stock(GTK_TOOLBAR(toolbar), GTK_STOCK_CLEAR,
-								 NULL, NULL, G_CALLBACK(clear_cb), win, -1);
+		                         NULL, NULL, G_CALLBACK(clear_cb),
+		                         win, -1);
 
 		gtk_toolbar_insert_space(GTK_TOOLBAR(toolbar), -1);
 
 		/* Pause */
 		image = gtk_image_new_from_stock(GAIM_STOCK_PAUSE, GTK_ICON_SIZE_MENU);
 		button = gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
-											GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
-											NULL, _("Pause"), NULL, NULL,
-											image, G_CALLBACK(pause_cb), win);
+		                                    GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
+		                                    NULL, _("Pause"), NULL,
+		                                    NULL, image,
+		                                    G_CALLBACK(pause_cb), win);
 
 		/* Timestamps */
 		button = gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
-											GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
-											NULL, _("Timestamps"), NULL, NULL,
-											NULL, G_CALLBACK(timestamps_cb),
-											win);
+		                                    GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
+		                                    NULL, _("Timestamps"),
+		                                    NULL, NULL, NULL,
+		                                    G_CALLBACK(timestamps_cb),
+		                                    win);
 
 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
-						gaim_prefs_get_bool("/core/debug/timestamps"));
+		                             gaim_prefs_get_bool("/core/debug/timestamps"));
+
+		gaim_prefs_connect_callback(gaim_gtk_debug_get_handle(),
+		                            "/core/debug/timestamps",
+		                            timestamps_pref_cb, button);
+
+		button = gtk_check_button_new_with_label(_("Filter"));
+		g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(filter_cb), win);
+		button = gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
+		                                    GTK_TOOLBAR_CHILD_WIDGET,
+						    button, NULL, NULL, NULL,
+						    NULL, NULL, NULL);
+
+		button = gtk_scrolled_window_new(NULL, NULL);
+		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(button),
+		                               GTK_POLICY_NEVER,
+		                               GTK_POLICY_AUTOMATIC);
 
-		gaim_prefs_connect_callback(gaim_gtk_debug_get_handle(), "/core/debug/timestamps",
-									timestamps_pref_cb, button);
+		liststore = gtk_list_store_new(1, G_TYPE_STRING);
+		win->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(liststore));
+		renderer = gtk_cell_renderer_text_new();
+		column = gtk_tree_view_column_new_with_attributes(_("Filter"), renderer, "text", 0, NULL);
+
+		gtk_tree_view_append_column(GTK_TREE_VIEW(win->treeview), column);
+		gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(win->treeview), FALSE);
+		gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(win->treeview), TRUE);
+		gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(liststore), 0, GTK_SORT_ASCENDING);
+
+		selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(win->treeview));
+		gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
+
+		g_hash_table_foreach(debug_categories, (GHFunc)debug_liststore_append, &liststore);
+
+		gtk_container_add(GTK_CONTAINER(button), win->treeview);
+		button = gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
+		                                    GTK_TOOLBAR_CHILD_WIDGET,
+		                                    button, NULL, NULL,
+		                                    NULL, NULL, NULL, NULL);
 	}
 
 	/* Add the gtkimhtml */
@@ -375,6 +445,8 @@
 void
 gaim_gtk_debug_init(void)
 {
+	gaim_debug_register_category("gtkdebug");
+
 	/* Debug window preferences. */
 	/*
 	 * NOTE: This must be set before prefs are loaded, and the callbacks
@@ -417,6 +489,14 @@
 }
 
 void
+gaim_gtk_debug_uninit(void)
+{
+	gaim_debug_unregister_category("gtkdebug");
+
+	gaim_debug_set_ui_ops(NULL);
+}
+
+void
 gaim_gtk_debug_window_show(void)
 {
 	if (debug_win == NULL)
@@ -437,6 +517,47 @@
 }
 
 static void
+create_debug_selected_categories(GtkTreeModel *model, GtkTreePath *path,
+                                 GtkTreeIter *iter, gpointer data)
+{
+	GHashTable **hashtable = (GHashTable **)data;
+	char *text = NULL;
+
+	gtk_tree_model_get(model, iter, 0, &text, -1);
+
+	g_hash_table_insert(*hashtable, text, NULL);
+}
+
+static gboolean
+debug_is_filtered_out(const char *category)
+{
+	GtkTreeSelection *selection = NULL;
+	GHashTable *hashtable = NULL;
+	gboolean found = FALSE;
+
+	if (category == NULL)
+		return FALSE;
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(debug_win->treeview));
+	hashtable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+	                                  NULL);
+
+	gtk_tree_selection_selected_foreach(selection,
+	                                    create_debug_selected_categories,
+	                                    &hashtable);
+
+	if (filter_enabled) {
+		if (g_hash_table_lookup_extended(hashtable, category, NULL, NULL))
+			found = FALSE;
+		else
+			found = TRUE;
+	}
+
+	g_hash_table_destroy(hashtable);
+	return found;
+}
+
+static void
 gaim_gtk_debug_print(GaimDebugLevel level, const char *category,
 					 const char *format, va_list args)
 {
@@ -445,7 +566,8 @@
 	gchar *esc_s, *cat_s, *tmp, *s;
 
 	if (!gaim_prefs_get_bool("/gaim/gtk/debug/enabled") ||
-					(debug_win == NULL) || debug_win->paused) {
+	    (debug_win == NULL) || debug_win->paused ||
+	    debug_is_filtered_out(category)) {
 		return;
 	}
 
@@ -454,8 +576,8 @@
 	arg_s = g_strdup_vprintf(format, args);
 
 	/*
- 	 * For some reason we only print the timestamp if category is
- 	 * not NULL.  Why the hell do we do that?  --Mark
+	 * For some reason we only print the timestamp if category is
+	 * not NULL.  Why the hell do we do that?  --Mark
 	 */
 	if ((category != NULL) && (timestamps)) {
 		gchar mdate[64];
@@ -498,9 +620,70 @@
 	g_free(s);
 }
 
+static void
+gaim_gtk_debug_register_category(const char *category)
+{
+	/* XXX I'd like to be able to put this creation in _init, but that
+	 * would require that this be init:ed before anything that wants to
+	 * register a category, and I'm not sure I can count on this coming
+	 * first */
+	if (debug_categories == NULL)
+		debug_categories = g_hash_table_new_full(g_str_hash,
+		                                         g_str_equal,
+		                                         g_free, NULL);
+
+	if (!g_hash_table_lookup_extended(debug_categories, category, NULL, NULL)) {
+		g_hash_table_insert(debug_categories, g_strdup(category), NULL);
+
+		if (debug_win != NULL && debug_win->treeview != NULL) {
+			GtkTreeModel *model = NULL;
+			GtkTreeIter iter;
+
+			model = gtk_tree_view_get_model(GTK_TREE_VIEW(debug_win->treeview));
+
+			gtk_list_store_append(GTK_LIST_STORE(model), &iter);
+			gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0,
+			                   category, -1);
+		}
+	}
+}
+
+static gboolean
+find_and_remove_category(GtkTreeModel *model, GtkTreePath *path,
+                         GtkTreeIter *iter, gpointer data)
+{
+	GValue value = {0};
+
+	gtk_tree_model_get_value(model, iter, 0, &value);
+
+	if (strcmp(g_value_get_string(&value), data) == 0) {
+		gtk_list_store_remove(GTK_LIST_STORE(model), iter);
+
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static void
+gaim_gtk_debug_unregister_category(const char *category)
+{
+	GtkTreeModel *model = NULL;
+
+	model = gtk_tree_view_get_model(GTK_TREE_VIEW(debug_win->treeview));
+
+	gtk_tree_model_foreach(model,
+	                       (GtkTreeModelForeachFunc)find_and_remove_category,
+	                       (char *)category);
+
+	g_hash_table_remove(debug_categories, category);
+}
+
 static GaimDebugUiOps ops =
 {
-	gaim_gtk_debug_print
+	gaim_gtk_debug_print,
+	gaim_gtk_debug_register_category,
+	gaim_gtk_debug_unregister_category
 };
 
 GaimDebugUiOps *