[geany/geany-plugins] 07aa19: Merge pull request #349 from b4n/debugger/master

Frank Lanitz git-noreply at xxxxx
Sat Feb 13 16:29:16 UTC 2016


Branch:      refs/heads/master
Author:      Frank Lanitz <frank at frank.uvena.de>
Committer:   Frank Lanitz <frank at frank.uvena.de>
Date:        Sat, 13 Feb 2016 16:29:16 UTC
Commit:      07aa19294b9e2d5a37dbec5d371d09bf541fbec0
             https://github.com/geany/geany-plugins/commit/07aa19294b9e2d5a37dbec5d371d09bf541fbec0

Log Message:
-----------
Merge pull request #349 from b4n/debugger/master

debugger: Various stuff


Modified Paths:
--------------
    debugger/src/breakpoints.c
    debugger/src/breakpoints.h
    debugger/src/dbm_gdb.c
    debugger/src/debug.c
    debugger/src/debug_module.c
    debugger/src/debug_module.h
    debugger/src/envtree.c
    debugger/src/gdb_mi.c
    debugger/src/gdb_mi.h
    debugger/src/markers.c
    debugger/src/stree.c
    debugger/src/stree.h
    debugger/src/watch_model.c

Modified: debugger/src/breakpoints.c
6 lines changed, 3 insertions(+), 3 deletions(-)
===================================================================
@@ -70,7 +70,7 @@ static void hash_table_foreach_call_function(gpointer key, gpointer value, gpoin
 static gboolean tree_foreach_add_to_list(gpointer key, gpointer value, gpointer data)
 {
 	GList **list = (GList**)data;
-	*list = g_list_append(*list, value);
+	*list = g_list_prepend(*list, value);
 	return FALSE;
 }
 
@@ -675,7 +675,7 @@ GList* breaks_get_for_document(const char* file)
 	{
 		g_tree_foreach(tree, tree_foreach_add_to_list, &breaks);
 	}
-	return breaks;
+	return g_list_reverse(breaks);
 }
 
 /*
@@ -702,5 +702,5 @@ GList* breaks_get_all(void)
 {
 	GList *breaks  = NULL;
 	g_hash_table_foreach(files, hash_table_foreach_add_to_list, &breaks);
-	return breaks;
+	return g_list_reverse(breaks);
 }


Modified: debugger/src/breakpoints.h
1 lines changed, 1 insertions(+), 0 deletions(-)
===================================================================
@@ -33,6 +33,7 @@ typedef enum _break_state {
 } break_state;
 
 typedef void	(*move_to_line_cb)(const char* file, int line);
+typedef void	(*select_thread_cb)(int thread_id);
 typedef void	(*select_frame_cb)(int frame_number);
 
 gboolean		breaks_init(move_to_line_cb callback);


Modified: debugger/src/dbm_gdb.c
226 lines changed, 129 insertions(+), 97 deletions(-)
===================================================================
@@ -60,9 +60,9 @@ typedef enum _result_class {
 
 /* structure to keep async command data (command line, messages) */
 typedef struct _queue_item {
-	GString *message;
-	GString *command;
-	GString *error_message;
+	gchar *message;
+	gchar *command;
+	gchar *error_message;
 	gboolean format_error_message;
 } queue_item;
 
@@ -213,10 +213,10 @@ static GList* read_until_prompt(void)
 			break;
 
 		line[terminator] = '\0';
-		lines = g_list_append (lines, line);
+		lines = g_list_prepend (lines, line);
 	}
 	
-	return lines;
+	return g_list_reverse(lines);
 }
 
 /*
@@ -261,11 +261,9 @@ static void gdb_input_write_line(const gchar *line)
  */
 static void free_queue_item(queue_item *item)
 {
-	if (item->message)
-		g_string_free(item->message, TRUE);
-	g_string_free(item->command, TRUE);
-	if (item->error_message)
-		g_string_free(item->error_message, TRUE);
+	g_free(item->message);
+	g_free(item->command);
+	g_free(item->error_message);
 	g_free(item);
 }
 
@@ -289,15 +287,9 @@ static GList* add_to_queue(GList* queue, const gchar *message, const gchar *comm
 
 	memset((void*)item, 0, sizeof(queue_item));
 
-	if (message)
-	{
-		item->message = g_string_new(message);
-	}
-	item->command = g_string_new(command);
-	if (error_message)
-	{
-		item->error_message = g_string_new(error_message);
-	}
+	item->message = g_strdup(message);
+	item->command = g_strdup(command);
+	item->error_message = g_strdup(error_message);
 	item->format_error_message = format_error_message;
 
 	return g_list_append(queue, (gpointer)item);
@@ -351,10 +343,10 @@ static gboolean on_read_async_output(GIOChannel * src, GIOCondition cond, gpoint
 				/* send message to debugger messages window */
 				if (item->message)
 				{
-					dbg_cbs->send_message(item->message->str, "grey");
+					dbg_cbs->send_message(item->message, "grey");
 				}
 
-				gdb_input_write_line(item->command->str);
+				gdb_input_write_line(item->command);
 
 				gdb_id_out = g_io_add_watch(gdb_ch_out, G_IO_IN, on_read_async_output, commands);
 			}
@@ -385,16 +377,14 @@ static gboolean on_read_async_output(GIOChannel * src, GIOCondition cond, gpoint
 				if (item->format_error_message)
 				{
 					const gchar* gdb_msg = gdb_mi_result_var(record->first, "msg", GDB_MI_VAL_STRING);
+					gchar *msg = g_strdup_printf(item->error_message, gdb_msg);
 
-					GString *msg = g_string_new("");
-					g_string_printf(msg, item->error_message->str, gdb_msg);
-					dbg_cbs->report_error(msg->str);
-
-					g_string_free(msg, FALSE);
+					dbg_cbs->report_error(msg);
+					g_free(msg);
 				}
 				else
 				{
-					dbg_cbs->report_error(item->error_message->str);
+					dbg_cbs->report_error(item->error_message);
 				}
 			}
 			
@@ -529,7 +519,14 @@ static gboolean on_read_from_gdb(GIOChannel * src, GIOCondition cond, gpointer d
 			else
 			{
 				if (!requested_interrupt)
-					dbg_cbs->report_error(_("Program received a signal"));
+				{
+					gchar *msg = g_strdup_printf(_("Program received signal %s (%s)"),
+					                             (gchar *) gdb_mi_result_var(record->first, "signal-name", GDB_MI_VAL_STRING),
+					                             (gchar *) gdb_mi_result_var(record->first, "signal-meaning", GDB_MI_VAL_STRING));
+
+					dbg_cbs->report_error(msg);
+					g_free(msg);
+				}
 				else
 					requested_interrupt = FALSE;
 			}
@@ -696,7 +693,8 @@ static gboolean run(const gchar* file, const gchar* commandline, GList* env, GLi
 	gchar *working_directory = g_path_get_dirname(file);
 	GList *lines, *iter;
 	GList *commands = NULL;
-	GString *command;
+	gchar *command;
+	gchar *escaped;
 	int bp_index;
 	queue_item *item;
 
@@ -752,10 +750,11 @@ static gboolean run(const gchar* file, const gchar* commandline, GList* env, GLi
 	/* collect commands */
 
 	/* loading file */
-	command = g_string_new("");
-	g_string_printf(command, "-file-exec-and-symbols \"%s\"", file);
-	commands = add_to_queue(commands, _("~\"Loading target file.\\n\""), command->str, _("Error loading file"), FALSE);
-	g_string_free(command, TRUE);
+	escaped = g_strescape(file, NULL);
+	command = g_strdup_printf("-file-exec-and-symbols \"%s\"", escaped);
+	commands = add_to_queue(commands, _("~\"Loading target file.\\n\""), command, _("Error loading file"), FALSE);
+	g_free(command);
+	g_free(escaped);
 
 	/* setting asyncronous mode */
 	commands = add_to_queue(commands, NULL, "-gdb-set target-async 1", _("Error configuring GDB"), FALSE);
@@ -767,16 +766,14 @@ static gboolean run(const gchar* file, const gchar* commandline, GList* env, GLi
 	commands = add_to_queue(commands, NULL, "-enable-pretty-printing", _("Error configuring GDB"), FALSE);
 
 	/* set locale */
-	command = g_string_new("");
-	g_string_printf(command, "-gdb-set environment LANG=%s", g_getenv("LANG"));
-	commands = add_to_queue(commands, NULL, command->str, NULL, FALSE);
-	g_string_free(command, TRUE);
+	command = g_strdup_printf("-gdb-set environment LANG=%s", g_getenv("LANG"));
+	commands = add_to_queue(commands, NULL, command, NULL, FALSE);
+	g_free(command);
 
 	/* set arguments */
-	command = g_string_new("");
-	g_string_printf(command, "-exec-arguments %s", commandline);
-	commands = add_to_queue(commands, NULL, command->str, NULL, FALSE);
-	g_string_free(command, TRUE);
+	command = g_strdup_printf("-exec-arguments %s", commandline);
+	commands = add_to_queue(commands, NULL, command, NULL, FALSE);
+	g_free(command);
 
 	/* set passed evironment */
 	iter = env;
@@ -788,11 +785,9 @@ static gboolean run(const gchar* file, const gchar* commandline, GList* env, GLi
 		iter = iter->next;
 		value = (gchar*)iter->data;
 
-		command = g_string_new("");
-		g_string_printf(command, "-gdb-set environment %s=%s", name, value);
-
-		commands = add_to_queue(commands, NULL, command->str, NULL, FALSE);
-		g_string_free(command, TRUE);
+		command = g_strdup_printf("-gdb-set environment %s=%s", name, value);
+		commands = add_to_queue(commands, NULL, command, NULL, FALSE);
+		g_free(command);
 
 		iter = iter->next;
 	}
@@ -802,50 +797,47 @@ static gboolean run(const gchar* file, const gchar* commandline, GList* env, GLi
 	while (biter)
 	{
 		breakpoint *bp = (breakpoint*)biter->data;
-		GString *error_message = g_string_new("");
+		gchar *error_message;
 
-		command = g_string_new("");
-		g_string_printf(command, "-break-insert -f \"\\\"%s\\\":%i\"", bp->file, bp->line);
+		escaped = g_strescape(bp->file, NULL);
+		command = g_strdup_printf("-break-insert -f \"\\\"%s\\\":%i\"", escaped, bp->line);
+		g_free(escaped);
 
-		g_string_printf(error_message, _("Breakpoint at %s:%i cannot be set\nDebugger message: %s"), bp->file, bp->line, "%s");
-		
-		commands = add_to_queue(commands, NULL, command->str, error_message->str, TRUE);
+		error_message = g_strdup_printf(_("Breakpoint at %s:%i cannot be set\nDebugger message: %s"), bp->file, bp->line, "%s");
+
+		commands = add_to_queue(commands, NULL, command, error_message, TRUE);
 
-		g_string_free(command, TRUE);
+		g_free(command);
 
 		if (bp->hitscount)
 		{
-			command = g_string_new("");
-			g_string_printf(command, "-break-after %i %i", bp_index, bp->hitscount);
-			commands = add_to_queue(commands, NULL, command->str, error_message->str, TRUE);
-			g_string_free(command, TRUE);
+			command = g_strdup_printf("-break-after %i %i", bp_index, bp->hitscount);
+			commands = add_to_queue(commands, NULL, command, error_message, TRUE);
+			g_free(command);
 		}
 		if (strlen(bp->condition))
 		{
-			command = g_string_new("");
-			g_string_printf (command, "-break-condition %i %s", bp_index, bp->condition);
-			commands = add_to_queue(commands, NULL, command->str, error_message->str, TRUE);
-			g_string_free(command, TRUE);
+			command = g_strdup_printf ("-break-condition %i %s", bp_index, bp->condition);
+			commands = add_to_queue(commands, NULL, command, error_message, TRUE);
+			g_free(command);
 		}
 		if (!bp->enabled)
 		{
-			command = g_string_new("");
-			g_string_printf (command, "-break-disable %i", bp_index);
-			commands = add_to_queue(commands, NULL, command->str, error_message->str, TRUE);
-			g_string_free(command, TRUE);
+			command = g_strdup_printf ("-break-disable %i", bp_index);
+			commands = add_to_queue(commands, NULL, command, error_message, TRUE);
+			g_free(command);
 		}
 
-		g_string_free(error_message, TRUE);
+		g_free(error_message);
 
 		bp_index++;
 		biter = biter->next;
 	}
 
 	/* set debugging terminal */
-	command = g_string_new("-inferior-tty-set ");
-	g_string_append(command, terminal_device);
-	commands = add_to_queue(commands, NULL, command->str, NULL, FALSE);
-	g_string_free(command, TRUE);
+	command = g_strconcat("-inferior-tty-set ", terminal_device, NULL);
+	commands = add_to_queue(commands, NULL, command, NULL, FALSE);
+	g_free(command);
 
 	/* connect read callback to the output chanel */
 	gdb_id_out = g_io_add_watch(gdb_ch_out, G_IO_IN, on_read_async_output, commands);
@@ -855,11 +847,11 @@ static gboolean run(const gchar* file, const gchar* commandline, GList* env, GLi
 	/* send message to debugger messages window */
 	if (item->message)
 	{
-		dbg_cbs->send_message(item->message->str, "grey");
+		dbg_cbs->send_message(item->message, "grey");
 	}
 
 	/* send first command */
-	gdb_input_write_line(item->command->str);
+	gdb_input_write_line(item->command);
 
 	return TRUE;
 }
@@ -930,6 +922,7 @@ static int get_break_number(char* file, int line)
 {
 	struct gdb_mi_record *record;
 	const struct gdb_mi_result *table, *body, *bkpt;
+	int break_number = -1;
 
 	exec_sync_command("-break-list", TRUE, &record);
 	if (! record)
@@ -939,8 +932,8 @@ static int get_break_number(char* file, int line)
 	body = gdb_mi_result_var(table, "body", GDB_MI_VAL_LIST);
 	gdb_mi_result_foreach_matched (bkpt, body, "bkpt", GDB_MI_VAL_LIST)
 	{
-		const gchar *number = gdb_mi_result_var(bkpt->val->list, "number", GDB_MI_VAL_STRING);
-		const gchar *location = gdb_mi_result_var(bkpt->val->list, "original-location", GDB_MI_VAL_STRING);
+		const gchar *number = gdb_mi_result_var(bkpt->val->v.list, "number", GDB_MI_VAL_STRING);
+		const gchar *location = gdb_mi_result_var(bkpt->val->v.list, "original-location", GDB_MI_VAL_STRING);
 		const gchar *colon;
 		gboolean break_found = FALSE;
 
@@ -950,21 +943,26 @@ static int get_break_number(char* file, int line)
 		colon = strrchr(location, ':');
 		if (colon && atoi(colon + 1) == line)
 		{
-			gchar *fname = g_strndup(location, colon - location);
-			/* FIXME: the check used to be made against \"file\" (e.g. file surrounded
-			 * by backslash-quote), but that's not at least how GDB 7.7 does it */
+			gchar *fname;
+
+			/* quotes around filename (location not found or something?) */
+			if (*location == '"' && colon - location > 2)
+				fname = g_strndup(location + 1, colon - location - 2);
+			else
+				fname = g_strndup(location, colon - location);
 			break_found = strcmp(fname, file) == 0;
 			g_free(fname);
 		}
 		if (break_found)
 		{
-			return atoi(number);
+			break_number = atoi(number);
+			break;
 		}
 	}
 	
 	gdb_mi_record_free(record);
 	
-	return -1;
+	return break_number;
 }
 
 /*
@@ -979,18 +977,21 @@ static gboolean set_break(breakpoint* bp, break_set_activity bsa)
 		struct gdb_mi_record *record;
 		const struct gdb_mi_result *bkpt;
 		const gchar *number;
+		gchar *escaped;
 		int num = 0;
 
 		/* 1. insert breakpoint */
-		g_snprintf(command, sizeof command, "-break-insert \"\\\"%s\\\":%i\"", bp->file, bp->line);
+		escaped = g_strescape(bp->file, NULL);
+		g_snprintf(command, sizeof command, "-break-insert \"\\\"%s\\\":%i\"", escaped, bp->line);
 		if (RC_DONE != exec_sync_command(command, TRUE, &record) || !record)
 		{
 			gdb_mi_record_free(record);
 			record = NULL;
-			g_snprintf(command, sizeof command, "-break-insert -f \"\\\"%s\\\":%i\"", bp->file, bp->line);
+			g_snprintf(command, sizeof command, "-break-insert -f \"\\\"%s\\\":%i\"", escaped, bp->line);
 			if (RC_DONE != exec_sync_command(command, TRUE, &record) || !record)
 			{
 				gdb_mi_record_free(record);
+				g_free(escaped);
 				return FALSE;
 			}
 		}
@@ -999,6 +1000,7 @@ static gboolean set_break(breakpoint* bp, break_set_activity bsa)
 		if ((number = gdb_mi_result_var(bkpt, "number", GDB_MI_VAL_STRING)))
 			num = atoi(number);
 		gdb_mi_record_free(record);
+		g_free(escaped);
 		/* 2. set hits count if differs from 0 */
 		if (bp->hitscount)
 		{
@@ -1084,6 +1086,34 @@ static void set_active_frame(int frame_number)
 	g_free(command);
 }
 
+static int get_active_thread(void)
+{
+	struct gdb_mi_record *record = NULL;
+	int current_thread = 0;
+
+	if (RC_DONE == exec_sync_command("-thread-info", TRUE, &record))
+	{
+		const gchar *id = gdb_mi_result_var(record->first, "current-thread-id", GDB_MI_VAL_STRING);
+		current_thread = id ? atoi(id) : 0;
+	}
+	gdb_mi_record_free(record);
+
+	return current_thread;
+}
+
+static gboolean set_active_thread(int thread_id)
+{
+	gchar *command = g_strdup_printf("-thread-select %i", thread_id);
+	gboolean success = (RC_DONE == exec_sync_command(command, TRUE, NULL));
+
+	if (success)
+		set_active_frame(0);
+
+	g_free(command);
+
+	return success;
+}
+
 /*
  * gets stack
  */
@@ -1102,9 +1132,9 @@ static GList* get_stack(void)
 	stack_node = gdb_mi_result_var(record->first, "stack", GDB_MI_VAL_LIST);
 	gdb_mi_result_foreach_matched (frame_node, stack_node, "frame", GDB_MI_VAL_LIST)
 	{
-		const gchar *addr = gdb_mi_result_var(frame_node->val->list, "addr", GDB_MI_VAL_STRING);
-		const gchar *func = gdb_mi_result_var(frame_node->val->list, "func", GDB_MI_VAL_STRING);
-		const gchar *line = gdb_mi_result_var(frame_node->val->list, "line", GDB_MI_VAL_STRING);
+		const gchar *addr = gdb_mi_result_var(frame_node->val->v.list, "addr", GDB_MI_VAL_STRING);
+		const gchar *func = gdb_mi_result_var(frame_node->val->v.list, "func", GDB_MI_VAL_STRING);
+		const gchar *line = gdb_mi_result_var(frame_node->val->v.list, "line", GDB_MI_VAL_STRING);
 		const gchar *file, *fullname;
 		frame *f = frame_new();
 
@@ -1112,9 +1142,9 @@ static GList* get_stack(void)
 		f->function = g_strdup(func);
 
 		/* file: fullname | file | from */
-		if ((fullname = file = gdb_mi_result_var(frame_node->val->list, "fullname", GDB_MI_VAL_STRING)) ||
-			(file = gdb_mi_result_var(frame_node->val->list, "file", GDB_MI_VAL_STRING)) ||
-			(file = gdb_mi_result_var(frame_node->val->list, "from", GDB_MI_VAL_STRING)))
+		if ((fullname = file = gdb_mi_result_var(frame_node->val->v.list, "fullname", GDB_MI_VAL_STRING)) ||
+			(file = gdb_mi_result_var(frame_node->val->v.list, "file", GDB_MI_VAL_STRING)) ||
+			(file = gdb_mi_result_var(frame_node->val->v.list, "from", GDB_MI_VAL_STRING)))
 		{
 			f->file = g_strdup(file);
 		}
@@ -1129,11 +1159,11 @@ static GList* get_stack(void)
 		/* line */
 		f->line = line ? atoi(line) : 0;
 
-		stack = g_list_append(stack, f);
+		stack = g_list_prepend(stack, f);
 	}
 	gdb_mi_record_free(record);
 	
-	return stack;
+	return g_list_reverse(stack);
 }
 
 /*
@@ -1224,7 +1254,7 @@ static void update_files(void)
 	files_node = gdb_mi_result_var(record->first, "files", GDB_MI_VAL_LIST);
 	gdb_mi_result_foreach_matched (files_node, files_node, NULL, GDB_MI_VAL_LIST)
 	{
-		const gchar *fullname = gdb_mi_result_var(files_node->val->list, "fullname", GDB_MI_VAL_STRING);
+		const gchar *fullname = gdb_mi_result_var(files_node->val->v.list, "fullname", GDB_MI_VAL_STRING);
 
 		if (fullname && !g_hash_table_lookup(ht, fullname))
 		{
@@ -1293,8 +1323,9 @@ static void update_watches(void)
 		var->evaluated = name != NULL;
 
 		/* add to updating list */
-		updating = g_list_append(updating, var);
+		updating = g_list_prepend(updating, var);
 	}
+	updating = g_list_reverse(updating);
 	
 	/* update watches */
 	get_variables(updating);
@@ -1335,11 +1366,11 @@ static void update_autos(void)
 
 		gdb_mi_result_foreach_matched (stack_args, stack_args, "frame", GDB_MI_VAL_LIST)
 		{
-			const struct gdb_mi_result *args = gdb_mi_result_var(stack_args->val->list, "args", GDB_MI_VAL_LIST);
+			const struct gdb_mi_result *args = gdb_mi_result_var(stack_args->val->v.list, "args", GDB_MI_VAL_LIST);
 
 			gdb_mi_result_foreach_matched (args, args, "name", GDB_MI_VAL_STRING)
 			{
-				variable *var = variable_new(args->val->string, VT_ARGUMENT);
+				variable *var = variable_new(args->val->v.string, VT_ARGUMENT);
 				vars = g_list_append(vars, var);
 			}
 		}
@@ -1352,7 +1383,7 @@ static void update_autos(void)
 
 		gdb_mi_result_foreach_matched (locals, locals, "name", GDB_MI_VAL_STRING)
 		{
-			variable *var = variable_new(locals->val->string, VT_LOCAL);
+			variable *var = variable_new(locals->val->v.string, VT_LOCAL);
 			vars = g_list_append(vars, var);
 		}
 	}
@@ -1455,8 +1486,8 @@ static GList* get_children (gchar* path)
 
 		gdb_mi_result_foreach_matched (child_node, child_node, "child", GDB_MI_VAL_LIST)
 		{
-			const gchar *internal = gdb_mi_result_var(child_node->val->list, "name", GDB_MI_VAL_STRING);
-			const gchar *name = gdb_mi_result_var(child_node->val->list, "exp", GDB_MI_VAL_STRING);
+			const gchar *internal = gdb_mi_result_var(child_node->val->v.list, "name", GDB_MI_VAL_STRING);
+			const gchar *name = gdb_mi_result_var(child_node->val->v.list, "exp", GDB_MI_VAL_STRING);
 			variable *var;
 
 			if (! name || ! internal)
@@ -1465,11 +1496,12 @@ static GList* get_children (gchar* path)
 			var = variable_new2(name, internal, VT_CHILD);
 			var->evaluated = TRUE;
 
-			children = g_list_append(children, var);
+			children = g_list_prepend(children, var);
 		}
 	}
 	gdb_mi_record_free(record);
 	
+	children = g_list_reverse(children);
 	get_variables(children);
 
 	return children;


Modified: debugger/src/debug.c
71 lines changed, 51 insertions(+), 20 deletions(-)
===================================================================
@@ -399,7 +399,7 @@ static gboolean on_watch_key_pressed_callback(GtkWidget *widget, GdkEvent  *even
 
 	/* check whether only empty row was selected */
 	if (1 != gtk_tree_selection_count_selected_rows(selection) ||
-	    gtk_tree_path_compare((GtkTreePath*)rows->data, empty_path))
+	    (rows && gtk_tree_path_compare((GtkTreePath*)rows->data, empty_path)))
 	{
 		/* path reference to select after deleteing finishes */
 		GtkTreeRowReference *reference_to_select = NULL;
@@ -418,13 +418,13 @@ static gboolean on_watch_key_pressed_callback(GtkWidget *widget, GdkEvent  *even
 
 			/* add path reference if it's not an empty row*/
 			if (gtk_tree_path_compare(path, empty_path))
-				references = g_list_append(references, gtk_tree_row_reference_new(wmodel, path));
+				references = g_list_prepend(references, gtk_tree_row_reference_new(wmodel, path));
 
 			iter = iter->next;
 		}
 
 		/* iterate through references and remove */
-		iter = references;
+		iter = g_list_reverse(references);
 		while (iter)
 		{
 			GtkTreeRowReference *reference = (GtkTreeRowReference*)iter->data;
@@ -640,7 +640,7 @@ static void on_debugger_run (void)
 	if (stack)
 	{
 		remove_stack_markers();
-		g_list_foreach(stack, (GFunc)frame_free, NULL);
+		g_list_foreach(stack, (GFunc)frame_unref, NULL);
 		g_list_free(stack);
 		stack = NULL;
 
@@ -700,11 +700,7 @@ static void on_debugger_stopped (int thread_id)
 
 	/* get current stack trace and put in the tree view */
 	stack = active_module->get_stack();
-	for (iter = stack; iter; iter = iter->next)
-	{
-		frame *f = (frame*)iter->data;
-		stree_add(f);
-	}
+	stree_add (stack);
 	stree_select_first_frame(TRUE);
 
 	/* files */
@@ -799,7 +795,7 @@ static void on_debugger_exited (int code)
 	if (stack)
 	{
 		remove_stack_markers();
-		g_list_foreach(stack, (GFunc)frame_free, NULL);
+		g_list_foreach(stack, (GFunc)frame_unref, NULL);
 		g_list_free(stack);
 		stack = NULL;
 	}
@@ -934,9 +930,12 @@ dbg_callbacks callbacks = {
 static void on_select_frame(int frame_number)
 {
 	GList *autos, *watches;
-	frame *f = (frame*)g_list_nth(stack, active_module->get_active_frame())->data;
-	markers_remove_current_instruction(f->file, f->line);
-	markers_add_frame(f->file, f->line);
+	frame *f = (frame*)g_list_nth_data(stack, active_module->get_active_frame());
+	if (f)
+	{
+		markers_remove_current_instruction(f->file, f->line);
+		markers_add_frame(f->file, f->line);
+	}
 
 	active_module->set_active_frame(frame_number);
 	
@@ -952,9 +951,41 @@ static void on_select_frame(int frame_number)
 	watches = active_module->get_watches();
 	update_variables(GTK_TREE_VIEW(wtree), NULL, watches);
 
-	f = (frame*)g_list_nth(stack, frame_number)->data;
-	markers_remove_frame(f->file, f->line);
-	markers_add_current_instruction(f->file, f->line);
+	f = (frame*)g_list_nth_data(stack, frame_number);
+	if (f)
+	{
+		markers_remove_frame(f->file, f->line);
+		markers_add_current_instruction(f->file, f->line);
+	}
+}
+
+/*
+ * called when a thread should been selected
+ */
+static void on_select_thread(int thread_id)
+{
+	gboolean success;
+
+	if (stack)
+		remove_stack_markers();
+
+	if ((success = active_module->set_active_thread(thread_id)))
+	{
+		g_list_free_full(stack, (GDestroyNotify)frame_unref);
+		stack = active_module->get_stack();
+
+		/* update the stack tree */
+		stree_remove_frames();
+		stree_set_active_thread_id(thread_id);
+		stree_add(stack);
+		stree_select_first_frame(TRUE);
+	}
+
+	if (stack)
+		add_stack_markers();
+
+	if (success)
+		on_select_frame(0);
 }
 
 /*
@@ -1000,7 +1031,7 @@ void debug_init(void)
 	gtk_container_add(GTK_CONTAINER(tab_autos), atree);
 	
 	/* create stack trace page */
-	stree = stree_init(editor_open_position, on_select_frame);
+	stree = stree_init(editor_open_position, on_select_thread, on_select_frame);
 	tab_call_stack = gtk_scrolled_window_new(
 		gtk_tree_view_get_hadjustment(GTK_TREE_VIEW(stree )),
 		gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(stree ))
@@ -1075,7 +1106,7 @@ void debug_destroy(void)
 	if (stack)
 	{
 		remove_stack_markers();
-		g_list_foreach(stack, (GFunc)frame_free, NULL);
+		g_list_foreach(stack, (GFunc)frame_unref, NULL);
 		g_list_free(stack);
 		stack = NULL;
 	}
@@ -1126,11 +1157,11 @@ GList* debug_get_modules(void)
 	module_description *desc = modules;
 	while (desc->title)
 	{
-		mods = g_list_append(mods, (gpointer)desc->title);
+		mods = g_list_prepend(mods, (gpointer)desc->title);
 		desc++;
 	}
 	
-	return mods;
+	return g_list_reverse(mods);
 }
 
 /*


Modified: debugger/src/debug_module.c
28 lines changed, 15 insertions(+), 13 deletions(-)
===================================================================
@@ -79,26 +79,28 @@ void variable_reset(variable *var)
 /* creates new frame */
 frame* frame_new(void)
 {
-	frame *f = (frame*)malloc(sizeof(frame));
-	memset((void*)f, 0, sizeof(frame));
+	frame *f = g_malloc0(sizeof *f);
+	f->ref_count = 1;
 	return f;
 }
 
-/* frees a frame */
-void frame_free(frame* f)
+/* refs a frame */
+frame* frame_ref(frame* f)
 {
-	if (f->address)
+	f->ref_count++;
+	return f;
+}
+
+/* unrefs a frame */
+void frame_unref(frame* f)
+{
+	if (f->ref_count > 1)
+		f->ref_count--;
+	else
 	{
 		g_free(f->address);
-	}
-	if (f->function)
-	{
 		g_free(f->function);
-	}
-	if (f->file)
-	{
 		g_free(f->file);
+		g_free(f);
 	}
-	
-	g_free(f);
 }


Modified: debugger/src/debug_module.h
13 lines changed, 10 insertions(+), 3 deletions(-)
===================================================================
@@ -79,6 +79,7 @@ typedef struct _variable {
 
 /* type to hold information about a stack frame */
 typedef struct _frame {
+	gint ref_count;
 	gchar *address;
 	gchar *function;
 	gchar *file;
@@ -120,7 +121,10 @@ typedef struct _dbg_module {
 
 	void (*set_active_frame)(int frame_number);
 	int (*get_active_frame)(void);
-		
+
+	gboolean (*set_active_thread)(int thread_id);
+	int (*get_active_thread)(void);
+
 	GList* (*get_autos) (void);
 	GList* (*get_watches) (void);
 	
@@ -154,6 +158,8 @@ typedef struct _dbg_module {
 	get_stack, \
 	set_active_frame, \
 	get_active_frame, \
+	set_active_thread, \
+	get_active_thread, \
 	get_autos, \
 	get_watches, \
 	get_files, \
@@ -170,7 +176,8 @@ variable*	variable_new(const gchar *name, variable_type vt);
 variable*	variable_new2(const gchar *name, const gchar *internal, variable_type vt);
 void		variable_reset(variable *var);
 
-frame*	frame_new(void);
-void		frame_free(frame* f);
+frame*		frame_new(void);
+frame*		frame_ref(frame* f);
+void		frame_unref(frame* f);
 
 #endif /* guard */


Modified: debugger/src/envtree.c
6 lines changed, 3 insertions(+), 3 deletions(-)
===================================================================
@@ -110,7 +110,7 @@ static void delete_selected_rows(void)
 
 	/* check whether only empty row was selected */
 	if (1 != gtk_tree_selection_count_selected_rows(selection) ||
-	    gtk_tree_path_compare((GtkTreePath*)rows->data, empty_path))
+	    (rows && gtk_tree_path_compare((GtkTreePath*)rows->data, empty_path)))
 	{
 		GtkTreePath *path;
 		/* get references to the selected rows and find out what to
@@ -135,7 +135,7 @@ static void delete_selected_rows(void)
 			}
 			
 			if (gtk_tree_path_compare(path, empty_path))
-				references = g_list_append(references, gtk_tree_row_reference_new(model, path));
+				references = g_list_prepend(references, gtk_tree_row_reference_new(model, path));
 			
 			iter = iter->next;
 		}
@@ -145,7 +145,7 @@ static void delete_selected_rows(void)
 		if (!reference_to_select)
 			reference_to_select = gtk_tree_row_reference_copy (empty_row);
 
-		iter = references;
+		iter = g_list_reverse(references);
 		while (iter)
 		{
 			GtkTreeIter titer;


Modified: debugger/src/gdb_mi.c
71 lines changed, 45 insertions(+), 26 deletions(-)
===================================================================
@@ -47,13 +47,11 @@ void gdb_mi_value_free(struct gdb_mi_value *val)
 	switch (val->type)
 	{
 		case GDB_MI_VAL_STRING:
-			g_free(val->string);
-			g_warn_if_fail(val->list == NULL);
+			g_free(val->v.string);
 			break;
 
 		case GDB_MI_VAL_LIST:
-			gdb_mi_result_free(val->list, TRUE);
-			g_warn_if_fail(val->string == NULL);
+			gdb_mi_result_free(val->v.list, TRUE);
 			break;
 	}
 	g_free(val);
@@ -98,13 +96,17 @@ static gchar *parse_cstring(const gchar **p)
 
 	if (**p == '"')
 	{
+		const gchar *base;
+
 		(*p)++;
+		base = *p;
 		while (**p != '"')
 		{
 			gchar c = **p;
 			/* TODO: check expansions here */
 			if (c == '\\')
 			{
+				g_string_append_len(str, base, (*p) - base);
 				(*p)++;
 				c = **p;
 				switch (g_ascii_tolower(c))
@@ -159,12 +161,14 @@ static gchar *parse_cstring(const gchar **p)
 						}
 						break;
 				}
+				g_string_append_c(str, c);
+				base = (*p) + 1;
 			}
-			if (**p == '\0')
+			else if (**p == '\0')
 				break;
-			g_string_append_c(str, c);
 			(*p)++;
 		}
+		g_string_append_len(str, base, (*p) - base);
 		if (**p == '"')
 			(*p)++;
 	}
@@ -176,15 +180,15 @@ static gchar *parse_cstring(const gchar **p)
  *        the docs aren't clear on this */
 static gchar *parse_string(const gchar **p)
 {
-	GString *str = g_string_new(NULL);
+	const gchar *base = *p;
 
 	if (g_ascii_isalpha(**p) || strchr("-_.", **p))
 	{
-		g_string_append_c(str, **p);
 		for ((*p)++; g_ascii_isalnum(**p) || strchr("-_.", **p); (*p)++)
-			g_string_append_c(str, **p);
+			;
 	}
-	return g_string_free(str, FALSE);
+
+	return g_strndup (base, *p - base);
 }
 
 /* parses: string "=" value */
@@ -205,15 +209,17 @@ static gboolean parse_result(struct gdb_mi_result *result, const gchar **p)
  * Actually, this is more permissive and allows mixed tuples/lists */
 static struct gdb_mi_value *parse_value(const gchar **p)
 {
-	struct gdb_mi_value *val = g_malloc0(sizeof *val);
+	struct gdb_mi_value *val = NULL;
 	if (**p == '"')
 	{
+		val = g_malloc0(sizeof *val);
 		val->type = GDB_MI_VAL_STRING;
-		val->string = parse_cstring(p);
+		val->v.string = parse_cstring(p);
 	}
 	else if (**p == '{' || **p == '[')
 	{
 		struct gdb_mi_result *prev = NULL;
+		val = g_malloc0(sizeof *val);
 		val->type = GDB_MI_VAL_LIST;
 		gchar end = **p == '{' ? '}' : ']';
 		(*p)++;
@@ -227,7 +233,7 @@ static struct gdb_mi_value *parse_value(const gchar **p)
 				if (prev)
 					prev->next = item;
 				else
-					val->list = item;
+					val->v.list = item;
 				prev = item;
 			}
 			else
@@ -242,11 +248,6 @@ static struct gdb_mi_value *parse_value(const gchar **p)
 		if (**p == end)
 			(*p)++;
 	}
-	else
-	{
-		gdb_mi_value_free(val);
-		val = NULL;
-	}
 	return val;
 }
 
@@ -393,9 +394,9 @@ const void *gdb_mi_result_var(const struct gdb_mi_result *result, const gchar *n
 	if (! val || val->type != type)
 		return NULL;
 	else if (val->type == GDB_MI_VAL_STRING)
-		return val->string;
+		return val->v.string;
 	else if (val->type == GDB_MI_VAL_LIST)
-		return val->list;
+		return val->v.list;
 	return NULL;
 }
 
@@ -449,12 +450,12 @@ static void gdb_mi_value_dump(const struct gdb_mi_value *v, gint indent)
 	switch (v->type)
 	{
 		case GDB_MI_VAL_STRING:
-			fprintf(stderr, "%*sstring = %s\n", indent * 2, "", v->string);
+			fprintf(stderr, "%*sstring = %s\n", indent * 2, "", v->v.string);
 			break;
 		case GDB_MI_VAL_LIST:
 			fprintf(stderr, "%*slist =>\n", indent * 2, "");
-			if (v->list)
-				gdb_mi_result_dump(v->list, TRUE, indent + 1);
+			if (v->v.list)
+				gdb_mi_result_dump(v->v.list, TRUE, indent + 1);
 			break;
 	}
 }
@@ -479,17 +480,35 @@ static void gdb_mi_record_dump(const struct gdb_mi_record *record)
 		gdb_mi_result_dump(record->first, TRUE, 2);
 }
 
-int main(void)
+static gchar *read_line(FILE *fp)
 {
 	char buf[1024] = {0};
+	GString *line = g_string_new(NULL);
+
+	while (fgets(buf, sizeof buf, fp))
+	{
+		g_string_append(line, buf);
+		if (line->len < 1 || line->str[line->len - 1] == '\n')
+			break;
+	}
+
+	return g_string_free(line, line->len < 1);
+}
 
-	while (fgets(buf, sizeof buf, stdin))
+int main(int argc, char **argv)
+{
+	gchar *line;
+
+	while ((line = read_line(stdin)) != NULL)
 	{
-		struct gdb_mi_record *record = gdb_mi_record_parse(buf);
+		struct gdb_mi_record *record = gdb_mi_record_parse(line);
 
 		gdb_mi_record_dump(record);
 		gdb_mi_record_free(record);
+
+		g_free(line);
 	}
+
 	return 0;
 }
 


Modified: debugger/src/gdb_mi.h
6 lines changed, 4 insertions(+), 2 deletions(-)
===================================================================
@@ -34,8 +34,10 @@ struct gdb_mi_result;
 struct gdb_mi_value
 {
 	enum gdb_mi_value_type type;
-	gchar *string;
-	struct gdb_mi_result *list;
+	union {
+		gchar *string;
+		struct gdb_mi_result *list;
+	} v;
 };
 
 struct gdb_mi_result


Modified: debugger/src/markers.c
19 lines changed, 10 insertions(+), 9 deletions(-)
===================================================================
@@ -40,15 +40,16 @@ extern GeanyData		*geany_data;
 #include "xpm/frame_current.xpm"
 
 /* markers identifiers */
-#define M_FIRST									12
-#define M_BP_ENABLED						M_FIRST
-#define M_BP_DISABLED						(M_FIRST + 1)
-#define M_BP_CONDITIONAL					(M_FIRST + 2)
-#define M_CI_BACKGROUND					(M_FIRST + 3)
-#define M_CI_ARROW							(M_FIRST + 4)
-#define M_FRAME								(M_FIRST + 5)
-
-#define MARKER_PRESENT(mask, marker) (mask && (0x01 << marker))
+#define M_FIRST			12
+enum
+{
+	M_BP_ENABLED		= M_FIRST,
+	M_BP_DISABLED,
+	M_BP_CONDITIONAL,
+	M_FRAME,
+	M_CI_BACKGROUND,
+	M_CI_ARROW
+};
 
 /* markers colors */
 #define RGB(R,G,B)	(R | (G << 8) | (B << 16))


Modified: debugger/src/stree.c
357 lines changed, 174 insertions(+), 183 deletions(-)
===================================================================
@@ -42,26 +42,19 @@
 /* Tree view columns */
 enum
 {
-   S_ADRESS,
-   S_FUNCTION,
-   S_FILEPATH,
-   S_LINE,
-   S_LAST_VISIBLE,
-   S_HAVE_SOURCE,
+   S_FRAME, /* the frame if it's a frame, or NULL if it's a thread */
    S_THREAD_ID,
    S_ACTIVE,
    S_N_COLUMNS
 };
 
-/* hash table to keep thread nodes in the tree */
-static GHashTable *threads;
-
 /* active thread and frame */
 static glong active_thread_id = 0;
 static int active_frame_index = 0;
 
 /* callbacks */
 static select_frame_cb select_frame = NULL;
+static select_thread_cb select_thread = NULL;
 static move_to_line_cb move_to_line = NULL;
 
 /* tree view, model and store handles */
@@ -69,9 +62,37 @@ static GtkWidget *tree = NULL;
 static GtkTreeModel *model = NULL;
 static GtkTreeStore *store = NULL;
 
+static GtkTreeViewColumn *column_filepath = NULL;
+static GtkTreeViewColumn *column_address = NULL;
+
 /* cell renderer for a frame arrow */
 static GtkCellRenderer *renderer_arrow = NULL;
 
+static GType frame_get_type (void);
+G_DEFINE_BOXED_TYPE(frame, frame, frame_ref, frame_unref)
+#define STREE_TYPE_FRAME (frame_get_type ())
+
+/* finds the iter for thread @thread_id */
+static gboolean find_thread_iter (gint thread_id, GtkTreeIter *iter)
+{
+	gboolean found = FALSE;
+
+	if (gtk_tree_model_get_iter_first(model, iter))
+	{
+		do
+		{
+			gint existing_thread_id;
+
+			gtk_tree_model_get(model, iter, S_THREAD_ID, &existing_thread_id, -1);
+			if (existing_thread_id == thread_id)
+				found = TRUE;
+		}
+		while (! found && gtk_tree_model_iter_next(model, iter));
+	}
+
+	return found;
+}
+
 /* 
  * frame arrow clicked callback
  */
@@ -80,10 +101,13 @@ static void on_frame_arrow_clicked(CellRendererFrameIcon *cell_renderer, gchar *
     GtkTreePath *new_active_frame = gtk_tree_path_new_from_string (path);
     if (gtk_tree_path_get_indices(new_active_frame)[1] != active_frame_index)
 	{
+		GtkTreeIter thread_iter;
 		GtkTreeIter iter;
+		GtkTreePath *old_active_frame;
+
+		find_thread_iter (active_thread_id, &thread_iter);
+		old_active_frame = gtk_tree_model_get_path (model, &thread_iter);
 
-		GtkTreeRowReference *reference = (GtkTreeRowReference*)g_hash_table_lookup(threads, (gpointer)active_thread_id);
-		GtkTreePath *old_active_frame = gtk_tree_row_reference_get_path(reference);
 		gtk_tree_path_append_index(old_active_frame, active_frame_index);
 
 		gtk_tree_model_get_iter(model, &iter, old_active_frame);
@@ -119,23 +143,23 @@ static gboolean on_query_tooltip(GtkWidget *widget, gint x, gint y, gboolean key
 			gint start_pos, width;
 			gtk_tree_view_column_cell_get_position(column, renderer_arrow, &start_pos, &width);
 			 
-			if (column == gtk_tree_view_get_column(GTK_TREE_VIEW(widget), S_FILEPATH))
+			if (column == column_filepath)
 			{
-				gchar *path = NULL;
+				frame *f;
 				GtkTreeIter iter;
 				gtk_tree_model_get_iter(model, &iter, tpath);
 				
-				gtk_tree_model_get(model, &iter, S_FILEPATH, &path, -1);
+				gtk_tree_model_get(model, &iter, S_FRAME, &f, -1);
 		
-				gtk_tooltip_set_text(tooltip, path);
+				gtk_tooltip_set_text(tooltip, f->file);
 				
 				gtk_tree_view_set_tooltip_row(GTK_TREE_VIEW(widget), tooltip, tpath);
 		
 				show = TRUE;
 
-				g_free(path);
+				frame_unref(f);
 			}
-			else if (column == gtk_tree_view_get_column(GTK_TREE_VIEW(widget), S_ADRESS && bx >= start_pos && bx < start_pos + width))
+			else if (column == column_address && bx >= start_pos && bx < start_pos + width)
 			{
 				gtk_tooltip_set_text(tooltip, gtk_tree_path_get_indices(tpath)[1] == active_frame_index ? _("Active frame") : _("Click an arrow to switch to a frame"));
 				gtk_tree_view_set_tooltip_row(GTK_TREE_VIEW(widget), tooltip, tpath);
@@ -165,14 +189,23 @@ static void on_render_arrow(GtkTreeViewColumn *tree_column, GtkCellRenderer *cel
 static void on_render_line(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model,
 	GtkTreeIter *iter, gpointer data)
 {
-	GtkTreePath *tpath = gtk_tree_model_get_path(model, iter);
+	frame *f;
 
-	if (1 == gtk_tree_path_get_depth(tpath))
-	{
+	gtk_tree_model_get (model, iter, S_FRAME, &f, -1);
+
+	if (! f)
 		g_object_set(cell, "text", "", NULL);
-	}
+	else
+	{
+		GValue value = {0};
 
-	gtk_tree_path_free(tpath);
+		g_value_init(&value, G_TYPE_INT);
+		g_value_set_int (&value, f->line);
+		g_object_set_property (G_OBJECT (cell), "text", &value);
+
+		g_value_unset (&value);
+		frame_unref (f);
+	}
 }
 
 /* 
@@ -181,28 +214,22 @@ static void on_render_line(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell
 static void on_render_filename(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model,
 	GtkTreeIter *iter, gpointer data)
 {
-	GtkTreePath *tpath = gtk_tree_model_get_path(model, iter);
-	
-	if (1 != gtk_tree_path_get_depth(tpath))
-	{
-		gchar *path = NULL, *name;
-		gtk_tree_model_get(model, iter, S_FILEPATH, &path, -1);
+	frame *f;
 
-		name = path ? g_path_get_basename(path) : NULL;
-		g_object_set(cell, "text", name ? name : path, NULL);
+	gtk_tree_model_get(model, iter, S_FRAME, &f, -1);
 
-		g_free(name);
-		if (path)
-		{
-			g_free(path);
-		}
-	}
+	if (! f)
+		g_object_set(cell, "text", "", NULL);
 	else
 	{
-		g_object_set(cell, "text", "", NULL);
-	}
+		gchar *name;
 
-	gtk_tree_path_free(tpath);
+		name = f->file ? g_path_get_basename(f->file) : NULL;
+		g_object_set(cell, "text", name ? name : f->file, NULL);
+
+		g_free(name);
+		frame_unref (f);
+	}
 }
 
 /*
@@ -218,44 +245,31 @@ static gboolean on_msgwin_button_press(GtkWidget *widget, GdkEventButton *event,
 		{
 			if (2 == gtk_tree_path_get_depth(pressed_path))
 			{
-				GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
-				GList *rows = gtk_tree_selection_get_selected_rows(selection, &model);
-				GtkTreePath *selected_path = (GtkTreePath*)rows->data;
+				GtkTreePath *selected_path;
+				gtk_tree_view_get_cursor(GTK_TREE_VIEW(tree), &selected_path, NULL);
 
-				if (!gtk_tree_path_compare(pressed_path, selected_path))
+				if (selected_path && !gtk_tree_path_compare(pressed_path, selected_path))
 				{
-					gboolean have_source;
+					frame *f;
 					GtkTreeIter iter;
 					gtk_tree_model_get_iter (
 						 model,
 						 &iter,
 						 pressed_path);
 
-					gtk_tree_model_get (
-						model,
-						&iter,
-						S_HAVE_SOURCE, &have_source,
-						-1);
+					gtk_tree_model_get (model, &iter, S_FRAME, &f, -1);
 					
 					/* check if file name is not empty and we have source files for the frame */
-					if (have_source)
+					if (f->have_source)
 					{
-						gchar *file;
-						gint line;
-						gtk_tree_model_get (
-							model,
-							&iter,
-							S_FILEPATH, &file,
-							S_LINE, &line,
-							-1);
-						move_to_line(file, line);
-
-						g_free(file);
+						move_to_line(f->file, f->line);
 					}
+
+					frame_unref(f);
 				}
 
-				g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
-				g_list_free (rows);
+				if (selected_path)
+					gtk_tree_path_free(selected_path);
 			}
 
 			gtk_tree_path_free(pressed_path);
@@ -266,79 +280,97 @@ static gboolean on_msgwin_button_press(GtkWidget *widget, GdkEventButton *event,
 }
 
 /*
- *  Tree view selection changed callback
+ *  Tree view cursor changed callback
  */
-static void on_selection_changed(GtkTreeSelection *treeselection, gpointer user_data)
+static void on_cursor_changed(GtkTreeView *treeview, gpointer user_data)
 {
-	GList *rows;
 	GtkTreePath *path;
+	GtkTreeIter iter;
+	frame *f;
+	int thread_id;
 
-	if (!gtk_tree_selection_count_selected_rows(treeselection))
-	{
+	gtk_tree_view_get_cursor(treeview, &path, NULL);
+	if (! path)
 		return;
-	}
-	
-	rows = gtk_tree_selection_get_selected_rows(treeselection, &model);
-	path = (GtkTreePath*)rows->data;
 
-	if (2 == gtk_tree_path_get_depth(path))
-	{
-		gboolean have_source;
-		GtkTreeIter iter;
+	gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_model_get (model, &iter,
+	                    S_FRAME, &f, S_THREAD_ID, &thread_id, -1);
 
-		gtk_tree_model_get_iter (
-			 model,
-			 &iter,
-			 path);
-		gtk_tree_model_get (
-			gtk_tree_view_get_model(GTK_TREE_VIEW(tree)),
-			&iter,
-			S_HAVE_SOURCE, &have_source,
-			-1);
-		
+	if (f) /* frame */
+	{
 		/* check if file name is not empty and we have source files for the frame */
-		if (have_source)
+		if (f->have_source)
 		{
-			gchar *file;
-			gint line;
-			gtk_tree_model_get (
-				model,
-				&iter,
-				S_FILEPATH, &file,
-				S_LINE, &line,
-				-1);
-
-			move_to_line(file, line);
-			g_free(file);
+			move_to_line(f->file, f->line);
 		}
+		frame_unref(f);
+	}
+	else /* thread */
+	{
+		if (thread_id != active_thread_id)
+			select_thread(thread_id);
+	}
+
+	gtk_tree_path_free(path);
+}
+
+static void on_render_function (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
+                                GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
+{
+	frame *f;
+
+	gtk_tree_model_get (tree_model, iter, S_FRAME, &f, -1);
+	if (! f)
+		g_object_set (cell, "text", "", NULL);
+	else
+	{
+		g_object_set (cell, "text", f->function, NULL);
+		frame_unref (f);
+	}
+}
+
+static void on_render_address (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
+                               GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
+{
+	frame *f;
+
+	gtk_tree_model_get (tree_model, iter, S_FRAME, &f, -1);
+	if (f)
+	{
+		g_object_set (cell, "text", f->address, NULL);
+		frame_unref (f);
 	}
+	else
+	{
+		gint thread_id;
+		gchar *thread_label;
 
-	g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL);
-	g_list_free(rows);
+		gtk_tree_model_get (model, iter, S_THREAD_ID, &thread_id, -1);
+		thread_label = g_strdup_printf(_("Thread %i"), thread_id);
+		g_object_set (cell, "text", thread_label, NULL);
+		g_free(thread_label);
+	}
 }
 
 /*
  *	inits stack trace tree
  */
-GtkWidget* stree_init(move_to_line_cb ml, select_frame_cb sf)
+GtkWidget* stree_init(move_to_line_cb ml, select_thread_cb st, select_frame_cb sf)
 {
 	GtkTreeViewColumn *column;
 	GtkCellRenderer *renderer;
 
 	move_to_line = ml;
+	select_thread = st;
 	select_frame = sf;
 
 	/* create tree view */
 	store = gtk_tree_store_new (
 		S_N_COLUMNS,
-		G_TYPE_STRING,
-		G_TYPE_STRING,
-		G_TYPE_STRING,
-		G_TYPE_INT,
-		G_TYPE_STRING,
-		G_TYPE_INT,
-		G_TYPE_INT,
-		G_TYPE_INT);
+		STREE_TYPE_FRAME, /* frame */
+		G_TYPE_INT /* thread ID */,
+		G_TYPE_BOOLEAN /* active */);
 		
 	model = GTK_TREE_MODEL(store);
 	tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL(store));
@@ -350,7 +382,7 @@ GtkWidget* stree_init(move_to_line_cb ml, select_frame_cb sf)
 	gtk_tree_view_set_show_expanders(GTK_TREE_VIEW(tree), FALSE);
 	
 	/* connect signals */
-	g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree))), "changed", G_CALLBACK (on_selection_changed), NULL);
+	g_signal_connect(G_OBJECT(tree), "cursor-changed", G_CALLBACK (on_cursor_changed), NULL);
 
 	/* for clicking on already selected frame */
 	g_signal_connect(G_OBJECT(tree), "button-press-event", G_CALLBACK(on_msgwin_button_press), NULL);
@@ -359,7 +391,7 @@ GtkWidget* stree_init(move_to_line_cb ml, select_frame_cb sf)
 
 	/* creating columns */
 	/* address */
-	column = gtk_tree_view_column_new();
+	column_address = column = gtk_tree_view_column_new();
 	gtk_tree_view_column_set_title(column, _("Address"));
 
 	renderer_arrow = cell_renderer_frame_icon_new ();
@@ -372,67 +404,59 @@ GtkWidget* stree_init(move_to_line_cb ml, select_frame_cb sf)
 
 	renderer = gtk_cell_renderer_text_new ();
 	gtk_tree_view_column_pack_start(column, renderer, TRUE);
-	gtk_tree_view_column_set_attributes(column, renderer, "text", S_ADRESS, NULL);
+	gtk_tree_view_column_set_cell_data_func(column, renderer, on_render_address, NULL, NULL);
 
 	gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
 
 	/* function */
 	renderer = gtk_cell_renderer_text_new ();
-	column = gtk_tree_view_column_new_with_attributes (_("Function"), renderer, "text", S_FUNCTION, NULL);
+	column = gtk_tree_view_column_new_with_attributes (_("Function"), renderer, NULL);
+	gtk_tree_view_column_set_cell_data_func(column, renderer, on_render_function, NULL, NULL);
 	gtk_tree_view_column_set_resizable (column, TRUE);
 	gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
 	
 	/* file */
 	renderer = gtk_cell_renderer_text_new ();
-	column = gtk_tree_view_column_new_with_attributes (_("File"), renderer, NULL);
+	column_filepath = column = gtk_tree_view_column_new_with_attributes (_("File"), renderer, NULL);
 	gtk_tree_view_column_set_resizable (column, TRUE);
 	gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
 	gtk_tree_view_column_set_cell_data_func(column, renderer, on_render_filename, NULL, NULL);
 	
 	/* line */
 	renderer = gtk_cell_renderer_text_new ();
-	column = gtk_tree_view_column_new_with_attributes (_("Line"), renderer, "text", S_LINE, NULL);
+	column = gtk_tree_view_column_new_with_attributes (_("Line"), renderer, NULL);
 	gtk_tree_view_column_set_cell_data_func(column, renderer, on_render_line, NULL, NULL);
 	gtk_tree_view_column_set_resizable (column, TRUE);
 	gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
 
 	/* Last invisible column */
-	renderer = gtk_cell_renderer_text_new ();
-	column = gtk_tree_view_column_new_with_attributes ("", renderer, "text", S_LAST_VISIBLE, NULL);
+	column = gtk_tree_view_column_new ();
 	gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
 
-	/* create threads hash table */
-	threads =  g_hash_table_new_full(
-		g_direct_hash,
-		g_direct_equal,
-		NULL,
-		(GDestroyNotify)gtk_tree_row_reference_free
-	);
-		
 	return tree;
 }
 
 /*
- *	add frame to the tree view
+ *	add frames to the tree view
  */
-void stree_add(frame *f)
+void stree_add(GList *frames)
 {
-	GtkTreeRowReference *reference = (GtkTreeRowReference*)g_hash_table_lookup(threads, (gpointer)active_thread_id);
-	GtkTreeIter frame_iter;
 	GtkTreeIter thread_iter;
-	GtkTreePath *path = gtk_tree_row_reference_get_path(reference);
-	gtk_tree_model_get_iter(model, &thread_iter, path);
-	gtk_tree_path_free(path);
+	GList *item;
 
-	gtk_tree_store_insert_before(store, &frame_iter, &thread_iter, 0);
+	g_object_ref (model);
+	gtk_tree_view_set_model (GTK_TREE_VIEW (tree), NULL);
 
-	gtk_tree_store_set (store, &frame_iter,
-                    S_ADRESS, f->address,
-                    S_FUNCTION, f->function,
-                    S_FILEPATH, f->file,
-                    S_LINE, f->line,
-                    S_HAVE_SOURCE, f->have_source,
-                    -1);
+	find_thread_iter (active_thread_id, &thread_iter);
+	/* prepending is a *lot* faster than appending, so prepend with a reversed data set */
+	for (item = g_list_last (frames); item; item = item->prev)
+	{
+		gtk_tree_store_insert_with_values (store, NULL, &thread_iter, 0,
+		                                   S_FRAME, item->data, -1);
+	}
+
+	gtk_tree_view_set_model (GTK_TREE_VIEW (tree), model);
+	g_object_unref (model);
 }
 
 /*
@@ -441,7 +465,6 @@ void stree_add(frame *f)
 void stree_clear(void)
 {
 	gtk_tree_store_clear(store);
-	g_hash_table_remove_all(threads);
 }
 
 /*
@@ -449,17 +472,12 @@ void stree_clear(void)
  */
 void stree_select_first_frame(gboolean make_active)
 {
-	GtkTreeRowReference *reference;
 	GtkTreeIter thread_iter, frame_iter;
-	GtkTreePath *active_path;
 
 	gtk_tree_view_expand_all(GTK_TREE_VIEW(tree));
-	
-	reference = (GtkTreeRowReference*)g_hash_table_lookup(threads, (gpointer)active_thread_id);
-	active_path = gtk_tree_row_reference_get_path(reference);
-	gtk_tree_model_get_iter(model, &thread_iter, active_path);
-	gtk_tree_path_free(active_path);
-	if(gtk_tree_model_iter_children(model, &frame_iter, &thread_iter))
+
+	if (find_thread_iter (active_thread_id, &thread_iter) &&
+	    gtk_tree_model_iter_children(model, &frame_iter, &thread_iter))
 	{
 		GtkTreePath* path;
 
@@ -471,9 +489,7 @@ void stree_select_first_frame(gboolean make_active)
 
 		path = gtk_tree_model_get_path(model, &frame_iter);
 
-		gtk_tree_selection_select_path (
-			gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)),
-			path);
+		gtk_tree_view_set_cursor(GTK_TREE_VIEW(tree), path, NULL, FALSE);
 
 		gtk_tree_path_free(path);
 	}
@@ -484,11 +500,6 @@ void stree_select_first_frame(gboolean make_active)
  */
 void stree_destroy(void)
 {
-	if (threads)
-	{
-		g_hash_table_destroy(threads);
-		threads = NULL;
-	}
 }
 
 /*
@@ -496,9 +507,6 @@ void stree_destroy(void)
  */
 void stree_add_thread(int thread_id)
 {
-	gchar *thread_label;
-	GtkTreePath *tpath;
-	GtkTreeRowReference *reference;
 	GtkTreeIter thread_iter, new_thread_iter;
 
 	if (gtk_tree_model_get_iter_first(model, &thread_iter))
@@ -507,7 +515,7 @@ void stree_add_thread(int thread_id)
 		do
 		{
 			int existing_thread_id;
-			gtk_tree_model_get(model, &thread_iter, S_THREAD_ID, &existing_thread_id);
+			gtk_tree_model_get(model, &thread_iter, S_THREAD_ID, &existing_thread_id, -1);
 			if (existing_thread_id > thread_id)
 			{
 				consecutive = &thread_iter;
@@ -530,17 +538,10 @@ void stree_add_thread(int thread_id)
 		gtk_tree_store_append (store, &new_thread_iter, NULL);
 	}
 
-	thread_label = g_strdup_printf(_("Thread %i"), thread_id);
 	gtk_tree_store_set (store, &new_thread_iter,
-					S_ADRESS, thread_label,
+					S_FRAME, NULL,
 					S_THREAD_ID, thread_id,
 					-1);
-	g_free(thread_label);
-
-	tpath = gtk_tree_model_get_path(model, &new_thread_iter);
-	reference = gtk_tree_row_reference_new(model, tpath);
-	g_hash_table_insert(threads, (gpointer)(long)thread_id,(gpointer)reference);
-	gtk_tree_path_free(tpath);
 }
 
 /*
@@ -548,17 +549,10 @@ void stree_add_thread(int thread_id)
  */
 void stree_remove_thread(int thread_id)
 {
-	GtkTreeRowReference *reference = (GtkTreeRowReference*)g_hash_table_lookup(threads, (gpointer)(glong)thread_id);
-	GtkTreePath *tpath = gtk_tree_row_reference_get_path(reference);
-
 	GtkTreeIter iter;
-	gtk_tree_model_get_iter(model, &iter, tpath);
-
-	gtk_tree_store_remove(store, &iter);
-
-	g_hash_table_remove(threads, (gpointer)(glong)thread_id);
 
-	gtk_tree_path_free(tpath);
+	if (find_thread_iter (thread_id, &iter))
+		gtk_tree_store_remove(store, &iter);
 }
 
 /*
@@ -566,14 +560,11 @@ void stree_remove_thread(int thread_id)
  */
 void stree_remove_frames(void)
 {
-	GtkTreeRowReference *reference = (GtkTreeRowReference*)g_hash_table_lookup(threads, (gpointer)active_thread_id);
 	GtkTreeIter child;
 	GtkTreeIter thread_iter;
-	GtkTreePath *tpath = gtk_tree_row_reference_get_path(reference);
-	gtk_tree_model_get_iter(model, &thread_iter, tpath);
-	gtk_tree_path_free(tpath);
 
-	if (gtk_tree_model_iter_children(model, &child, &thread_iter))
+	if (find_thread_iter (active_thread_id, &thread_iter) &&
+	    gtk_tree_model_iter_children(model, &child, &thread_iter))
 	{
 		while(gtk_tree_store_remove(GTK_TREE_STORE(model), &child))
 			;


Modified: debugger/src/stree.h
4 lines changed, 2 insertions(+), 2 deletions(-)
===================================================================
@@ -28,10 +28,10 @@
 #include "breakpoints.h"
 #include "debug_module.h"
 
-GtkWidget*		stree_init(move_to_line_cb ml, select_frame_cb sf);
+GtkWidget*		stree_init(move_to_line_cb ml, select_thread_cb st, select_frame_cb sf);
 void			stree_destroy(void);
 
-void 			stree_add(frame *f);
+void 			stree_add(GList *frames);
 void 			stree_clear(void);
 
 void 			stree_add_thread(int thread_id);


Modified: debugger/src/watch_model.c
4 lines changed, 2 insertions(+), 2 deletions(-)
===================================================================
@@ -476,9 +476,9 @@ GList *get_root_items(GtkTreeView *tree)
 			-1);
 		
 		if (strlen(name))
-			names = g_list_append(names, name);
+			names = g_list_prepend(names, name);
 	}
 	while (gtk_tree_model_iter_next(model, &child));
 	
-	return names;
+	return g_list_reverse(names);
 }



--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Plugins-Commits mailing list