1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3     debug_tree.c
4     Copyright (C) 2006  Sébastien Granjoux
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19 */
20 
21 // TODO:
22 //   Alloc string in DmaVariableData object, so treeview can use POINTER
23 //     => no need to free data after getting the value
24 //     => value can be access more easily if we have the tree viex
25 //     => do the same for variable name
26 //
27 //   Add a function to get all arguments
28 
29 #ifdef HAVE_CONFIG_H
30 #  include <config.h>
31 #endif
32 
33 #include "debug_tree.h"
34 
35 #include "plugin.h"
36 #include "memory.h"
37 
38 /*#define DEBUG*/
39 #include <libanjuta/anjuta-debug.h>
40 
41 #include <glib/gi18n.h>
42 
43 #include <stdlib.h>
44 #include <string.h>
45 #include <ctype.h>
46 #include <assert.h>
47 
48 /* Types
49  *---------------------------------------------------------------------------*/
50 
51 enum _DataType
52 {
53 	TYPE_ROOT,
54 	TYPE_UNKNOWN,
55 	TYPE_POINTER,
56 	TYPE_ARRAY,
57 	TYPE_STRUCT,
58 	TYPE_VALUE,
59 	TYPE_REFERENCE,
60 	TYPE_NAME
61 };
62 
63 typedef enum _DataType DataType;
64 
65 enum {AUTO_UPDATE_WATCH = 1 << 0};
66 
67 /* Common data */
68 typedef struct _CommonDebugTree CommonDebugTree;
69 typedef struct _DmaVariablePacket DmaVariablePacket;
70 typedef struct _DmaVariableData DmaVariableData;
71 
72 struct _CommonDebugTree {
73 	guint initialized;
74 	DebugTree* current;
75 	DebugTree* user;
76 	GList *tree_list;
77 };
78 
79 /* The debug tree object */
80 struct _DebugTree {
81 	DmaDebuggerQueue *debugger;
82 	AnjutaPlugin *plugin;
83 	GtkWidget* view;        /* the tree widget */
84 	gboolean auto_expand;
85 };
86 
87 struct _DmaVariablePacket {
88 	DmaVariableData *data;
89 	GtkTreeModel *model;
90 	guint from;
91 	GtkTreeRowReference* reference;
92 	DmaDebuggerQueue *debugger;
93 	DmaVariablePacket* next;
94 };
95 
96 struct _DmaVariableData {
97 	gboolean modified;	/* Set by tree update */
98 
99 	/* Value from debugger */
100 	gboolean changed;	/* Set by global update */
101 	gboolean exited;	/* variable outside scope */
102 	gboolean deleted;	/* variable should be deleted */
103 
104 	gboolean auto_update;
105 
106 	DmaVariablePacket* packet;
107 
108 	gchar* name;
109 };
110 
111 /* Constant
112  *---------------------------------------------------------------------------*/
113 
114 #define UNKNOWN_VALUE "???"
115 #define UNKNOWN_TYPE "?"
116 #define AUTO_UPDATE 'U'
117 
118 enum {
119 	VARIABLE_COLUMN,
120 	VALUE_COLUMN,
121 	TYPE_COLUMN,
122 	ROOT_COLUMN,
123 	DTREE_ENTRY_COLUMN,
124 	N_COLUMNS
125 };
126 
127 static gchar *tree_title[] = {
128 	N_("Variable"), N_("Value"), N_("Type")
129 };
130 
131 /* Global variable
132  *---------------------------------------------------------------------------*/
133 
134 static GList* gTreeList = NULL;
135 
136 /* Helper functions
137  *---------------------------------------------------------------------------*/
138 
139 static void
my_gtk_tree_model_foreach_child(GtkTreeModel * const model,GtkTreeIter * const parent,GtkTreeModelForeachFunc func,gpointer user_data)140 my_gtk_tree_model_foreach_child (GtkTreeModel *const model,
141                            GtkTreeIter *const parent,
142                            GtkTreeModelForeachFunc func,
143                            gpointer user_data)
144 {
145   GtkTreeIter iter;
146   gboolean success = gtk_tree_model_iter_children(model, &iter, parent);
147 
148   while(success)
149   {
150     	success = (!func(model, NULL, &iter, user_data) &&
151                gtk_tree_model_iter_next (model, &iter));
152   }
153 }
154 
155 static gint
my_gtk_tree_model_child_position(GtkTreeModel * model,GtkTreeIter * iter)156 my_gtk_tree_model_child_position (GtkTreeModel *model,
157 								GtkTreeIter *iter)
158 {
159 	GtkTreePath *path;
160 	gint pos;
161 
162 	path = gtk_tree_model_get_path (model, iter);
163 	if (path == NULL) return -1;
164 
165 	for (pos = 0; gtk_tree_path_prev (path); pos++);
166 	gtk_tree_path_free (path);
167 
168 	return pos;
169 }
170 
171 static gboolean
get_current_iter(GtkTreeView * view,GtkTreeIter * iter)172 get_current_iter (GtkTreeView *view, GtkTreeIter* iter)
173 {
174 	GtkTreeSelection *selection;
175 
176 	selection = gtk_tree_view_get_selection (view);
177 	return gtk_tree_selection_get_selected (selection, NULL, iter);
178 }
179 
180 static DmaVariableData *
dma_variable_data_new(const gchar * const name,gboolean auto_update)181 dma_variable_data_new(const gchar *const name, gboolean auto_update)
182 {
183 	DmaVariableData *data;
184 
185 	data = g_new0 (DmaVariableData, 1);
186 	if (name != NULL)
187 	{
188 		data->name = g_strdup (name);
189 	}
190 
191 	data->auto_update = auto_update;
192 
193 	return data;
194 }
195 
196 static void
dma_variable_data_free(DmaVariableData * data)197 dma_variable_data_free(DmaVariableData * data)
198 {
199 	DmaVariablePacket* pack;
200 
201 	/* Mark the data as invalid, the packet structure will
202 	 * be free later in the callback */
203 	for (pack = data->packet; pack != NULL; pack = pack->next)
204 	{
205 		pack->data= NULL;
206 	}
207 
208 	if (data->name != NULL)
209 	{
210 		g_free (data->name);
211 	}
212 
213 	g_free(data);
214 }
215 
216 /* ------------------------------------------------------------------ */
217 
218 static DmaVariablePacket *
dma_variable_packet_new(GtkTreeModel * model,GtkTreeIter * iter,DmaDebuggerQueue * debugger,DmaVariableData * data,guint from)219 dma_variable_packet_new(GtkTreeModel *model,
220                      GtkTreeIter *iter,
221 					 DmaDebuggerQueue *debugger,
222 					 DmaVariableData *data,
223 					 guint from)
224 {
225 	GtkTreePath *path;
226 
227 	g_return_val_if_fail (model, NULL);
228 	g_return_val_if_fail (iter, NULL);
229 
230 	DmaVariablePacket *pack = g_new (DmaVariablePacket, 1);
231 
232 	pack->data = data;
233 	pack->from = from;
234 	pack->model = GTK_TREE_MODEL (model);
235 	path = gtk_tree_model_get_path(model, iter);
236 	pack->reference = gtk_tree_row_reference_new (model, path);
237 	gtk_tree_path_free (path);
238 	pack->debugger = debugger;
239 	pack->next = data->packet;
240 	data->packet = pack;
241 
242 	return pack;
243 }
244 
245 static void
dma_variable_packet_free(DmaVariablePacket * pack)246 dma_variable_packet_free (DmaVariablePacket* pack)
247 {
248 	if (pack->data != NULL)
249 	{
250 		/* Remove from packet data list */
251 		DmaVariablePacket **find;
252 
253 		for (find = &pack->data->packet; *find != NULL; find = &(*find)->next)
254 		{
255 			if (*find == pack)
256 			{
257 				*find = pack->next;
258 				break;
259 			}
260 		}
261 	}
262 
263 	gtk_tree_row_reference_free (pack->reference);
264 
265 	g_free (pack);
266 }
267 
268 static gboolean
dma_variable_packet_get_iter(DmaVariablePacket * pack,GtkTreeIter * iter)269 dma_variable_packet_get_iter (DmaVariablePacket* pack, GtkTreeIter *iter)
270 {
271 	GtkTreePath *path;
272 	gboolean ok;
273 
274 	path = gtk_tree_row_reference_get_path (pack->reference);
275 	ok = gtk_tree_model_get_iter (pack->model, iter, path);
276 	gtk_tree_path_free (path);
277 
278 	return ok;
279 }
280 
281 /* DebugTree private functions
282  *---------------------------------------------------------------------------*/
283 
284 static void
debug_tree_cell_data_func(GtkTreeViewColumn * tree_column,GtkCellRenderer * cell,GtkTreeModel * tree_model,GtkTreeIter * iter,gpointer data)285 debug_tree_cell_data_func (GtkTreeViewColumn *tree_column,
286 				GtkCellRenderer *cell, GtkTreeModel *tree_model,
287 					GtkTreeIter *iter, gpointer data)
288 {
289 	gchar *value;
290 	static const gchar *colors[] = {"black", "red"};
291 	GValue gvalue = {0, };
292 	DmaVariableData *node = NULL;
293 
294 	gtk_tree_model_get (tree_model, iter, VALUE_COLUMN, &value, -1);
295 	g_value_init (&gvalue, G_TYPE_STRING);
296 	g_value_set_static_string (&gvalue, value);
297 	g_object_set_property (G_OBJECT (cell), "text", &gvalue);
298 
299 	gtk_tree_model_get (tree_model, iter, DTREE_ENTRY_COLUMN, &node, -1);
300 
301 	if (node)
302 	{
303 		g_value_reset (&gvalue);
304 		g_value_set_static_string (&gvalue,
305                         colors[(node && node->modified ? 1 : 0)]);
306 
307 		g_object_set_property (G_OBJECT (cell), "foreground", &gvalue);
308 	}
309 	g_free (value);
310 }
311 
312 static gboolean
delete_child(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer user_data)313 delete_child(GtkTreeModel *model, GtkTreePath* path,
314 			GtkTreeIter* iter, gpointer user_data)
315 {
316 	DmaVariableData *data;
317 	DmaDebuggerQueue *debugger = (DmaDebuggerQueue *)user_data;
318 
319 	g_return_val_if_fail (model,TRUE);
320 	g_return_val_if_fail (iter,TRUE);
321 
322 	gtk_tree_model_get(model, iter, DTREE_ENTRY_COLUMN, &data, -1);
323 
324 	/* Dummy node (data == NULL) are used when child are not known */
325 	if (data != NULL)
326 	{
327 		dma_variable_data_free(data);
328 	  	my_gtk_tree_model_foreach_child (model, iter, delete_child, debugger);
329 	}
330 
331 	return FALSE;
332 }
333 
334 static gboolean
delete_parent(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer user_data)335 delete_parent(GtkTreeModel *model, GtkTreePath* path,
336 			GtkTreeIter* iter, gpointer user_data)
337 {
338 	DmaVariableData *data;
339 	DmaDebuggerQueue *debugger = (DmaDebuggerQueue *)user_data;
340 
341 	g_return_val_if_fail (model,TRUE);
342 	g_return_val_if_fail (iter,TRUE);
343 
344 	gtk_tree_model_get(model, iter, DTREE_ENTRY_COLUMN, &data, -1);
345 
346 	/* Dummy node (data == NULL) are used as a place holder in watch box */
347 	if (data != NULL)
348 	{
349 		if (debugger)
350 		{
351 			if (data->name)
352 			{
353 				/* Object has been created in debugger and is not a child
354 			 	* (destroyed with their parent) */
355 				dma_queue_delete_variable (debugger, data->name);
356 			}
357 		}
358 
359 		dma_variable_data_free(data);
360 
361   		my_gtk_tree_model_foreach_child (model, iter, delete_child, debugger);
362 	}
363 
364 	return FALSE;
365 }
366 
367 static void
debug_tree_remove_children(GtkTreeModel * model,DmaDebuggerQueue * debugger,GtkTreeIter * parent,GtkTreeIter * first)368 debug_tree_remove_children (GtkTreeModel *model, DmaDebuggerQueue *debugger, GtkTreeIter* parent, GtkTreeIter* first)
369 {
370 	gboolean child;
371  	GtkTreeIter iter;
372 
373 	if (first != NULL)
374 	{
375 		/* Start with first child */
376 		child = TRUE;
377 		iter = *first;
378 	}
379 	else
380 	{
381 		/* Remove all children */
382 		child  = gtk_tree_model_iter_children(model, &iter, parent);
383 	}
384 
385 	while (child)
386 	{
387 		delete_child (model, NULL, &iter, debugger);
388 
389 		child = gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
390 	}
391 }
392 
393 static void
debug_tree_model_add_dummy_children(GtkTreeModel * model,GtkTreeIter * parent)394 debug_tree_model_add_dummy_children (GtkTreeModel *model, GtkTreeIter *parent)
395 {
396 	GtkTreeIter iter;
397 
398 	gtk_tree_store_append(GTK_TREE_STORE(model), &iter, parent);
399 	gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
400 					   VARIABLE_COLUMN, "",
401 					   VALUE_COLUMN, "",
402 					   TYPE_COLUMN, "",
403 					   ROOT_COLUMN, parent == NULL ? TRUE : FALSE,
404 					   DTREE_ENTRY_COLUMN, NULL, -1);
405 }
406 
407 static void
debug_tree_add_children(GtkTreeModel * model,DmaDebuggerQueue * debugger,GtkTreeIter * parent,guint from,const GList * children)408 debug_tree_add_children (GtkTreeModel *model, DmaDebuggerQueue *debugger, GtkTreeIter* parent, guint from, const GList *children)
409 {
410 	GList *child;
411 	GtkTreeIter iter;
412 	gboolean valid;
413 
414 	valid = gtk_tree_model_iter_nth_child (model, &iter, parent, from);
415 
416 	/* Add new children */
417 	for (child = g_list_first ((GList *)children); child != NULL; child = g_list_next (child))
418 	{
419 		IAnjutaDebuggerVariableObject *var = (IAnjutaDebuggerVariableObject *)child->data;
420 		DmaVariableData *data;
421 
422 		if (!valid)
423 		{
424 			/* Add new tree node */
425 			gtk_tree_store_append(GTK_TREE_STORE(model), &iter, parent);
426 
427 			gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
428 				TYPE_COLUMN, var->type == NULL ? UNKNOWN_TYPE : var->type,
429 				VALUE_COLUMN, var->value == NULL ? UNKNOWN_VALUE : var->value,
430 				VARIABLE_COLUMN, var->expression,
431 				ROOT_COLUMN, FALSE,
432 				DTREE_ENTRY_COLUMN, NULL,-1);
433 			data = NULL;
434 		}
435 		else
436 		{
437 			/* Update tree node */
438 			if (var->type != NULL)
439 				gtk_tree_store_set(GTK_TREE_STORE(model), &iter, TYPE_COLUMN, var->type, -1);
440 			if (var->value != NULL)
441 				gtk_tree_store_set(GTK_TREE_STORE(model), &iter, VALUE_COLUMN, var->value, -1);
442 			if (var->expression != NULL)
443 				gtk_tree_store_set(GTK_TREE_STORE(model), &iter, VARIABLE_COLUMN, var->expression, -1);
444 			gtk_tree_model_get(model, &iter, DTREE_ENTRY_COLUMN, &data, -1);
445 
446 			if (var->name == NULL)
447 			{
448 				/* Dummy node representing additional children */
449 				if (data != NULL)
450 				{
451 					dma_variable_data_free (data);
452 					gtk_tree_store_set(GTK_TREE_STORE (model), &iter, DTREE_ENTRY_COLUMN, NULL, -1);
453 					data = NULL;
454 				}
455 			}
456 		}
457 
458 		if ((var->name != NULL) && (data == NULL))
459 		{
460 			/* Create new data */
461 			data = dma_variable_data_new(var->name, TRUE);
462 			gtk_tree_store_set(GTK_TREE_STORE(model), &iter, DTREE_ENTRY_COLUMN, data, -1);
463 		}
464 
465 		/* Clear all children if they exist */
466 		debug_tree_remove_children (model, debugger, &iter, NULL);
467 		if ((var->children != 0) || var->has_more || (var->name == NULL))
468 		{
469 			/* Add dummy children */
470 			debug_tree_model_add_dummy_children (model, &iter);
471 		}
472 
473 		valid = gtk_tree_model_iter_next (model, &iter);
474 	}
475 
476 	/* Clear remaining old children */
477 	if (valid) debug_tree_remove_children (model, debugger, parent, &iter);
478 }
479 
480 /*---------------------------------------------------------------------------*/
481 
482 static void
gdb_var_evaluate_expression(const gchar * value,gpointer user_data,GError * err)483 gdb_var_evaluate_expression (const gchar *value,
484                         gpointer user_data, GError* err)
485 {
486 	DmaVariablePacket *pack = (DmaVariablePacket *) user_data;
487 	GtkTreeIter iter;
488 
489 	g_return_if_fail (pack != NULL);
490 
491 	if ((err != NULL)
492 		|| (pack->data == NULL)
493 		|| !dma_variable_packet_get_iter (pack, &iter))
494 	{
495 		/* Command failed or item has been deleted */
496 		dma_variable_packet_free (pack);
497 
498 		return;
499 	}
500 
501 	pack->data->changed = FALSE;
502 	gtk_tree_store_set(GTK_TREE_STORE (pack->model), &iter, VALUE_COLUMN, value, -1);
503 	dma_variable_packet_free (pack);
504 }
505 
506 static void
gdb_var_list_children(const GList * children,gpointer user_data,GError * err)507 gdb_var_list_children (const GList *children, gpointer user_data, GError *err)
508 {
509 	DmaVariablePacket *pack = (DmaVariablePacket *) user_data;
510 	GtkTreeIter iter;
511 
512 	g_return_if_fail (pack != NULL);
513 
514 	if ((err != NULL)
515 		|| (pack->data == NULL)
516 		|| !dma_variable_packet_get_iter (pack, &iter))
517 	{
518 		/* Command failed or item has been deleted */
519 		dma_variable_packet_free (pack);
520 
521 		return;
522 	}
523 
524 	debug_tree_add_children (pack->model, pack->debugger, &iter, pack->from, children);
525 
526 	dma_variable_packet_free (pack);
527 }
528 
529 static void
gdb_var_create(IAnjutaDebuggerVariableObject * variable,gpointer user_data,GError * err)530 gdb_var_create (IAnjutaDebuggerVariableObject *variable, gpointer user_data, GError *err)
531 {
532 	DmaVariablePacket *pack = (DmaVariablePacket *) user_data;
533 	GtkTreeIter iter;
534 
535 	g_return_if_fail (pack != NULL);
536 
537 	if (err != NULL)
538 	{
539 		/* Command failed */
540 		dma_variable_packet_free (pack);
541 
542 		return;
543 	}
544 	if ((pack->data == NULL)
545 		|| !dma_variable_packet_get_iter (pack, &iter))
546 	{
547 		/* Item has been deleted, but not removed from debugger as it was not
548 		 * created at this time, so remove it now */
549 		if ((pack->debugger) && (variable->name))
550 		{
551 			dma_queue_delete_variable (pack->debugger, variable->name);
552 		}
553 		dma_variable_packet_free (pack);
554 
555 		return;
556 	}
557 
558 	DmaVariableData *data = pack->data;
559 
560 	if ((variable->name != NULL) && (data->name == NULL))
561 	{
562 		data->name = strdup (variable->name);
563 	}
564 	data->changed = TRUE;
565 	data->deleted = FALSE;
566 	data->exited = FALSE;
567 
568 	gtk_tree_store_set(GTK_TREE_STORE(pack->model), &iter,
569 					   TYPE_COLUMN, variable->type,
570 					   VALUE_COLUMN, variable->value, -1);
571 
572 
573 	if ((variable->children == 0) && !variable->has_more)
574 	{
575 		debug_tree_remove_children (pack->model, pack->debugger, &iter, NULL);
576 	}
577 	else
578 	{
579 		debug_tree_model_add_dummy_children (pack->model, &iter);
580 	}
581 
582 
583 	/* Request value and/or children if they are missing
584 	 * reusing same packet if possible */
585 	if (variable->value == NULL)
586 	{
587 		dma_queue_evaluate_variable (
588 				pack->debugger,
589 				variable->name,
590 				(IAnjutaDebuggerCallback)gdb_var_evaluate_expression,
591 				pack);
592 	}
593 	else
594 	{
595 		dma_variable_packet_free (pack);
596 	}
597 }
598 
599 /* ------------------------------------------------------------------ */
600 
601 static void
on_treeview_row_expanded(GtkTreeView * treeview,GtkTreeIter * iter,GtkTreePath * path,gpointer user_data)602 on_treeview_row_expanded       (GtkTreeView     *treeview,
603                                  GtkTreeIter     *iter,
604                                  GtkTreePath     *path,
605                                  gpointer         user_data)
606 {
607 	DebugTree *tree = (DebugTree *)user_data;
608 
609 	if (tree->debugger != NULL)
610 	{
611 		GtkTreeModel *const model = gtk_tree_view_get_model (treeview);
612 		DmaVariableData *data;
613 
614 		gtk_tree_model_get (model, iter, DTREE_ENTRY_COLUMN, &data, -1);
615 
616 		if ((data != NULL) && (data->name != NULL))
617 		{
618 			/* Expand variable node */
619 			GtkTreeIter child;
620 
621 			if (gtk_tree_model_iter_children (model, &child, iter))
622 			{
623 				DmaVariableData *child_data;
624 
625 				gtk_tree_model_get (model, &child, DTREE_ENTRY_COLUMN, &child_data, -1);
626 				if ((child_data == NULL) || (child_data->name == NULL))
627 				{
628 					/* Dummy children, get the real children */
629 					DmaVariablePacket *pack;
630 
631 					pack = dma_variable_packet_new(model, iter, tree->debugger, data, 0);
632 					dma_queue_list_children (
633 								tree->debugger,
634 								data->name,
635 								0,
636 								(IAnjutaDebuggerCallback)gdb_var_list_children,
637 								pack);
638 				}
639 			}
640 		}
641 		else
642 		{
643 			/* Dummy node representing additional children */
644 			GtkTreeIter parent;
645 
646 			if (gtk_tree_model_iter_parent (model, &parent, iter))
647 			{
648 				gtk_tree_model_get (model, &parent, DTREE_ENTRY_COLUMN, &data, -1);
649 				if ((data != NULL) && (data->name != NULL))
650 				{
651 					DmaVariablePacket *pack;
652 					guint from;
653 					gint pos;
654 
655 					pos = my_gtk_tree_model_child_position (model, iter);
656 					from = pos < 0 ? 0 : pos;
657 
658 					pack = dma_variable_packet_new(model, &parent, tree->debugger, data, from);
659 					dma_queue_list_children (
660 									tree->debugger,
661 									data->name,
662 									from,
663 									(IAnjutaDebuggerCallback)gdb_var_list_children,
664 									pack);
665 				}
666 			}
667 		}
668 	}
669 
670 	return;
671 }
672 
673 static void
on_debug_tree_variable_changed(GtkCellRendererText * cell,gchar * path_string,gchar * text,gpointer user_data)674 on_debug_tree_variable_changed (GtkCellRendererText *cell,
675 						  gchar *path_string,
676                           gchar *text,
677                           gpointer user_data)
678 {
679 	DebugTree *tree = (DebugTree *)user_data;
680 	GtkTreeIter iter;
681 	GtkTreeModel * model;
682 
683 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree->view));
684 	if (gtk_tree_model_get_iter_from_string (model, &iter, path_string))
685 	{
686 		debug_tree_remove (tree, &iter);
687 
688 		if ((text != NULL) && (*text != '\0'))
689 		{
690 		    IAnjutaDebuggerVariableObject var = {NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE, -1};
691 
692 			var.expression = text;
693 			debug_tree_add_watch (tree, &var, TRUE);
694 		}
695 		else
696 		{
697 			debug_tree_add_dummy (tree, NULL);
698 		}
699 	}
700 }
701 
702 static void
on_debug_tree_value_changed(GtkCellRendererText * cell,gchar * path_string,gchar * text,gpointer user_data)703 on_debug_tree_value_changed (GtkCellRendererText *cell,
704 						  gchar *path_string,
705                           gchar *text,
706                           gpointer user_data)
707 {
708 	DebugTree *tree = (DebugTree *)user_data;
709 	GtkTreeIter iter;
710 	GtkTreeModel * model;
711 
712     model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree->view));
713 
714 	if (gtk_tree_model_get_iter_from_string (model, &iter, path_string))
715 	{
716 		DmaVariableData *item;
717 		DmaVariablePacket *tran;
718 
719 		gtk_tree_model_get (model, &iter, DTREE_ENTRY_COLUMN, &item, -1);
720 		if ((item != NULL) && (item->name != NULL) && (tree->debugger != NULL))
721 		{
722 			/* Variable is valid */
723 			dma_queue_assign_variable (tree->debugger, item->name, text);
724 			tran = dma_variable_packet_new(model, &iter, tree->debugger, item, 0);
725 			dma_queue_evaluate_variable (
726 					tree->debugger,
727 					item->name,
728 					(IAnjutaDebuggerCallback) gdb_var_evaluate_expression,
729 					tran);
730 		}
731 	}
732 }
733 
734 static GtkWidget *
debug_tree_create(DebugTree * tree,GtkTreeView * view)735 debug_tree_create (DebugTree *tree, GtkTreeView *view)
736 {
737 	GtkCellRenderer *renderer;
738 	GtkTreeViewColumn *column;
739 	GtkTreeModel * model = GTK_TREE_MODEL (gtk_tree_store_new
740 			                     (N_COLUMNS,
741 	                                          G_TYPE_STRING,
742 	                                          G_TYPE_STRING,
743                                               G_TYPE_STRING,
744 								              G_TYPE_BOOLEAN,
745 			                      G_TYPE_POINTER));
746 
747 	if (view == NULL)
748 	{
749 		view = GTK_TREE_VIEW (gtk_tree_view_new ());
750 	}
751 
752 	gtk_tree_view_set_model (view, GTK_TREE_MODEL (model));
753 
754 	GtkTreeSelection *selection = gtk_tree_view_get_selection (view);
755 	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
756 	g_object_unref (G_OBJECT (model));
757 
758 	/* Columns */
759 	column = gtk_tree_view_column_new ();
760 	renderer = gtk_cell_renderer_text_new ();
761 	gtk_tree_view_column_pack_start (column, renderer, TRUE);
762 	gtk_tree_view_column_add_attribute (column, renderer, "text", VARIABLE_COLUMN);
763 	gtk_tree_view_column_add_attribute (column, renderer, "editable", ROOT_COLUMN);
764 	g_signal_connect(renderer, "edited", (GCallback) on_debug_tree_variable_changed, tree);
765 	gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
766 	gtk_tree_view_column_set_resizable (column, TRUE);
767 	gtk_tree_view_column_set_title (column, _(tree_title[0]));
768 	gtk_tree_view_append_column (view, column);
769 	gtk_tree_view_set_expander_column (view, column);
770 
771 	column = gtk_tree_view_column_new ();
772 	renderer = gtk_cell_renderer_text_new ();
773 	gtk_tree_view_column_pack_start (column, renderer, TRUE);
774 	gtk_tree_view_column_set_cell_data_func (column, renderer,
775                                debug_tree_cell_data_func, NULL, NULL);
776 	gtk_tree_view_column_add_attribute (column, renderer, "text", VALUE_COLUMN);
777 	g_object_set(renderer, "editable", TRUE, NULL);
778 	g_signal_connect(renderer, "edited", (GCallback) on_debug_tree_value_changed, tree);
779 	gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
780 	gtk_tree_view_column_set_resizable (column, TRUE);
781 	gtk_tree_view_column_set_title (column, _(tree_title[1]));
782 	gtk_tree_view_append_column (view, column);
783 
784 
785     column = gtk_tree_view_column_new ();
786 	renderer = gtk_cell_renderer_text_new ();
787 	gtk_tree_view_column_pack_start (column, renderer, TRUE);
788 	gtk_tree_view_column_add_attribute (column, renderer, "text", TYPE_COLUMN);
789 	gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
790 	gtk_tree_view_column_set_resizable (column, TRUE);
791 	gtk_tree_view_column_set_title (column, _(tree_title[2]));
792 	gtk_tree_view_append_column (view, column);
793 
794     return GTK_WIDGET (view);
795 }
796 
797 /* Public functions
798  *---------------------------------------------------------------------------*/
799 
800 /* clear the display of the debug tree and reset the title */
801 void
debug_tree_remove_all(DebugTree * tree)802 debug_tree_remove_all (DebugTree *tree)
803 {
804 	GtkTreeModel *model;
805 
806 	g_return_if_fail (tree);
807 	g_return_if_fail (tree->view);
808 
809 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree->view));
810 	debug_tree_remove_model (tree, model);
811 }
812 
813 static gboolean
debug_tree_find_name(const GtkTreeModel * model,GtkTreeIter * iter,const gchar * name)814 debug_tree_find_name (const GtkTreeModel *model, GtkTreeIter *iter, const gchar *name)
815 {
816 	size_t len = 0;
817 	GtkTreeIter parent_iter;
818 	GtkTreeIter* parent = NULL;
819 
820 	for (;;)
821 	{
822 		const gchar *ptr;
823 
824 		/* Check if we look for a child variable */
825 		ptr = strchr(name + len + 1, '.');
826 		if (ptr != NULL)
827 		{
828 			/* Child variable */
829 			gboolean search;
830 
831 			len = ptr - name;
832 			for (search = gtk_tree_model_iter_children (GTK_TREE_MODEL (model), iter, parent);
833 				search != FALSE;
834 	    		search = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), iter))
835 			{
836 				DmaVariableData *iData;
837         		gtk_tree_model_get (GTK_TREE_MODEL (model), iter, DTREE_ENTRY_COLUMN, &iData, -1);
838 
839 				if ((iData != NULL) && (iData->name != NULL) && (name[len] == '.') && (strncmp (name, iData->name, len) == 0))
840 				{
841 					break;
842 				}
843 			}
844 
845 			if (search == TRUE)
846 			{
847 				parent_iter = *iter;
848 				parent = &parent_iter;
849 				continue;
850 			}
851 			else
852 			{
853 				return FALSE;
854 			}
855 		}
856 		else
857 		{
858 			/* Variable without any child */
859 			gboolean search;
860 
861 			for (search = gtk_tree_model_iter_children (GTK_TREE_MODEL (model), iter, parent);
862 				search != FALSE;
863 				search = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), iter))
864 			{
865 				DmaVariableData *iData;
866 				gtk_tree_model_get (GTK_TREE_MODEL (model), iter, DTREE_ENTRY_COLUMN, &iData, -1);
867 
868 				if ((iData != NULL) && (iData->name != NULL) && (strcmp (name, iData->name) == 0))
869 				{
870 					return TRUE;
871 				}
872 			}
873 
874 			return FALSE;
875 		}
876 	}
877 }
878 
879 void
debug_tree_replace_list(DebugTree * tree,const GList * expressions)880 debug_tree_replace_list (DebugTree *tree, const GList *expressions)
881 {
882 	GtkTreeModel* model = gtk_tree_view_get_model (GTK_TREE_VIEW(tree->view));
883 	GtkTreeIter iter;
884 	gboolean valid;
885 	GList *list = g_list_copy ((GList *)expressions);
886 
887 	/* Keep in the tree only the variable in the list */
888 	valid = gtk_tree_model_get_iter_first (model, &iter);
889 	while (valid)
890 	{
891 		GList *find = NULL;
892 		gchar *exp;
893 		DmaVariableData *node;
894 
895 		gtk_tree_model_get (model, &iter,
896 							VARIABLE_COLUMN, &exp,
897 							DTREE_ENTRY_COLUMN, &node, -1);
898 
899 		if ((node->deleted == FALSE) && (node->exited == FALSE) && (exp != NULL))
900 		{
901 			find = g_list_find_custom (list, exp, (GCompareFunc)strcmp);
902 		}
903 
904 		if (find)
905 		{
906 			/* Keep variable in tree, remove in add list */
907 			list = g_list_delete_link (list, find);
908 			valid = gtk_tree_model_iter_next (model, &iter);
909 		}
910 		else
911 		{
912 			/* Remove variable from the tree */
913 			delete_parent(model, NULL, &iter, tree->debugger);
914 			valid = gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
915 		}
916 	}
917 
918 	/* Create new variable */
919 	while (list)
920 	{
921 		IAnjutaDebuggerVariableObject var = {NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE, -1};
922 
923 		var.expression = (gchar *)(list->data);
924 		debug_tree_add_watch (tree, &var, TRUE);
925 
926 		list = g_list_delete_link (list, list);
927 	}
928 }
929 
930 void
debug_tree_add_dummy(DebugTree * tree,GtkTreeIter * parent)931 debug_tree_add_dummy (DebugTree *tree, GtkTreeIter *parent)
932 {
933 	GtkTreeModel* model = gtk_tree_view_get_model (GTK_TREE_VIEW(tree->view));
934 
935 	debug_tree_model_add_dummy_children (model, parent);
936 }
937 
938 /* Get a IAnjutaVariable as argument in order to use the same function without
939  * variable object, currently only the expression field is set */
940 
941 void
debug_tree_add_watch(DebugTree * tree,const IAnjutaDebuggerVariableObject * var,gboolean auto_update)942 debug_tree_add_watch (DebugTree *tree, const IAnjutaDebuggerVariableObject* var, gboolean auto_update)
943 {
944 	GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree->view));
945 	GtkTreeIter iter;
946 	DmaVariableData *data;
947 
948 	/* Allocate data */
949 	data = dma_variable_data_new(var->name, auto_update);
950 
951 	/* Add node in tree */
952 	gtk_tree_store_append(GTK_TREE_STORE(model), &iter, NULL);
953 	gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
954 					   TYPE_COLUMN, var->type == NULL ? UNKNOWN_TYPE : var->type,
955 					   VALUE_COLUMN, var->value == NULL ? UNKNOWN_VALUE : var->value,
956 					   VARIABLE_COLUMN, var->expression,
957 					   ROOT_COLUMN, TRUE,
958 					   DTREE_ENTRY_COLUMN, data, -1);
959 
960 	if (tree->debugger != NULL)
961 	{
962 		if ((var->value == NULL) || (var->children == -1))
963 		{
964 			if (var->name == NULL)
965 			{
966 				/* Need to create variable before to get value */
967 				DmaVariablePacket *pack;
968 
969 				pack = dma_variable_packet_new(model, &iter, tree->debugger, data, 0);
970 				dma_queue_create_variable (
971 						tree->debugger,
972 						var->expression,
973 						(IAnjutaDebuggerCallback)gdb_var_create,
974 						pack);
975 			}
976 			else
977 			{
978 				DEBUG_PRINT("%s", "You shouldn't read this, debug_tree_add_watch");
979 				if (var->value == NULL)
980 				{
981 					/* Get value */
982 					DmaVariablePacket *pack =
983 
984 					pack = dma_variable_packet_new(model, &iter, tree->debugger, data, 0);
985 					dma_queue_evaluate_variable (
986 							tree->debugger,
987 							var->name,
988 							(IAnjutaDebuggerCallback)gdb_var_evaluate_expression,
989 							pack);
990 				}
991 			}
992 		}
993 	}
994 }
995 
996 static void
on_add_watch(gpointer data,gpointer user_data)997 on_add_watch (gpointer data, gpointer user_data)
998 {
999 	DebugTree* this = (DebugTree *)user_data;
1000 	gboolean auto_update = ((const gchar *)data)[0] & AUTO_UPDATE_WATCH ? TRUE : FALSE;
1001 	IAnjutaDebuggerVariableObject var = {NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE, -1};
1002 
1003 	var.expression = &((gchar *)data)[1];
1004 	debug_tree_add_watch (this, &var, auto_update);
1005 }
1006 
1007 void
debug_tree_add_full_watch_list(DebugTree * this,GList * expressions)1008 debug_tree_add_full_watch_list (DebugTree *this, GList *expressions)
1009 {
1010 	g_list_foreach (expressions, on_add_watch, this);
1011 }
1012 
1013 static void
on_add_manual_watch(gpointer data,gpointer user_data)1014 on_add_manual_watch (gpointer data, gpointer user_data)
1015 {
1016 	DebugTree* this = (DebugTree *)user_data;
1017 	IAnjutaDebuggerVariableObject var = {NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE, -1};
1018 
1019 	var.expression = &((gchar *)data)[0];
1020 	debug_tree_add_watch (this, &var, FALSE);
1021 }
1022 
1023 static void
on_add_auto_watch(gpointer data,gpointer user_data)1024 on_add_auto_watch (gpointer data, gpointer user_data)
1025 {
1026 	DebugTree* this = (DebugTree *)user_data;
1027 	IAnjutaDebuggerVariableObject var = {NULL, NULL, NULL, NULL, FALSE, FALSE, -1};
1028 
1029 	var.expression = &((gchar *)data)[0];
1030 	debug_tree_add_watch (this, &var, TRUE);
1031 }
1032 
1033 void
debug_tree_add_watch_list(DebugTree * this,GList * expressions,gboolean auto_update)1034 debug_tree_add_watch_list (DebugTree *this, GList *expressions, gboolean auto_update)
1035 {
1036 	g_list_foreach (expressions, auto_update ? on_add_auto_watch : on_add_manual_watch, this);
1037 }
1038 
1039 static void
on_debug_tree_changed(gpointer data,gpointer user_data)1040 on_debug_tree_changed (gpointer data, gpointer user_data)
1041 {
1042 	IAnjutaDebuggerVariableObject *var = (IAnjutaDebuggerVariableObject *)data;
1043 
1044 	if (var->name != NULL)
1045 	{
1046 		/* Search corresponding variable in one tree */
1047 		GList *list;
1048 
1049 		for (list = g_list_first (gTreeList); list != NULL; list = g_list_next (list))
1050 		{
1051 			DebugTree *tree = (DebugTree *)list->data;
1052 
1053 			GtkTreeIter iter;
1054 			GtkTreeModel *model;
1055 
1056 			model = debug_tree_get_model (tree);
1057 
1058 			if (debug_tree_find_name (model, &iter, var->name))
1059 			{
1060 				DmaVariableData *data;
1061 				gtk_tree_model_get (model, &iter, DTREE_ENTRY_COLUMN, &data, -1);
1062 
1063 				if (data != NULL)
1064 				{
1065 					data->changed = var->changed;
1066 					data->exited = var->exited;
1067 					data->deleted = var->deleted;
1068 				}
1069 
1070 				return;
1071 			}
1072 		}
1073 	}
1074 }
1075 
1076 static gboolean
debug_tree_update_real(GtkTreeModel * model,DmaDebuggerQueue * debugger,GtkTreeIter * iter,gboolean force)1077 debug_tree_update_real (GtkTreeModel *model, DmaDebuggerQueue *debugger, GtkTreeIter* iter, gboolean force)
1078 {
1079 	DmaVariableData *data = NULL;
1080 	GtkTreeIter child;
1081 	gboolean search;
1082 	gboolean refresh = TRUE;
1083 
1084 	gtk_tree_model_get (model, iter, DTREE_ENTRY_COLUMN, &data, -1);
1085 	if (data == NULL) return FALSE;
1086 
1087 
1088 	if ((data->deleted) && (data->name != NULL) && (force || data->auto_update))
1089 	{
1090 		/* Variable deleted (by example if type change), try to recreate it */
1091 		dma_queue_delete_variable (debugger, data->name);
1092 		g_free (data->name);
1093 		data->name = NULL;
1094 	}
1095 
1096 	if (data->name == NULL)
1097 	{
1098 		/* Check is the variable creation is not pending */
1099 		if (data->packet == NULL)
1100 		{
1101 			/* Variable need to be created first */
1102 			gchar *exp;
1103 			DmaVariablePacket *pack;
1104 
1105 			gtk_tree_model_get (model, iter, VARIABLE_COLUMN, &exp, -1);
1106 			pack = dma_variable_packet_new(model, iter, debugger, data, 0);
1107 			dma_queue_create_variable (
1108 					debugger,
1109 					exp,
1110 					(IAnjutaDebuggerCallback)gdb_var_create,
1111 					pack);
1112 			g_free (exp);
1113 		}
1114 
1115 		return FALSE;
1116 	}
1117 	else if (force || (data->auto_update && data->changed))
1118 	{
1119 		DmaVariablePacket *pack = dma_variable_packet_new(model, iter, debugger, data, 0);
1120 		refresh = data->modified != (data->changed != FALSE);
1121 		data->modified = (data->changed != FALSE);
1122 		dma_queue_evaluate_variable (
1123 				debugger,
1124 				data->name,
1125 				(IAnjutaDebuggerCallback)gdb_var_evaluate_expression,
1126 				pack);
1127 		data->changed = FALSE;
1128 	}
1129 	else
1130 	{
1131 		refresh = data->modified;
1132 		data->modified = FALSE;
1133 	}
1134 
1135 	/* update children */
1136 	for (search = gtk_tree_model_iter_children(model, &child, iter);
1137 		search == TRUE;
1138 	    search = gtk_tree_model_iter_next (model, &child))
1139 	{
1140 		if (debug_tree_update_real (model, debugger, &child, force))
1141 		{
1142 			refresh = data->modified == TRUE;
1143 			data->modified = TRUE;
1144 		}
1145 	}
1146 
1147 	if (refresh)
1148 	{
1149 		GtkTreePath *path;
1150 		path = gtk_tree_model_get_path (model, iter);
1151 		gtk_tree_model_row_changed (model, path, iter);
1152 		gtk_tree_path_free (path);
1153 	}
1154 
1155 	return data->modified;
1156 }
1157 
1158 
1159 /* Get information from debugger and update variable with automatic update */
1160 static void
on_debug_tree_update_all(const GList * change,gpointer user_data,GError * err)1161 on_debug_tree_update_all (const GList *change, gpointer user_data, GError* err)
1162 {
1163 	DmaDebuggerQueue *debugger = (DmaDebuggerQueue *)user_data;
1164 	GList *list;
1165 
1166 	if (err != NULL) return;
1167 
1168 	// Update all variables information from debugger data
1169 	g_list_foreach ((GList *)change, on_debug_tree_changed, NULL);
1170 
1171 	// Update all tree models
1172 	for (list = g_list_first (gTreeList); list != NULL; list = g_list_next (list))
1173 	{
1174 		DebugTree* tree = (DebugTree*)list->data;
1175 
1176 		GtkTreeModel* model;
1177 		GtkTreeIter iter;
1178 		gboolean valid;
1179 
1180 		model = debug_tree_get_model (tree);
1181 
1182 		// Update this tree
1183 		for (valid = gtk_tree_model_get_iter_first (model, &iter);
1184 			valid;
1185 			valid = gtk_tree_model_iter_next (model, &iter))
1186 		{
1187 			debug_tree_update_real (model, debugger, &iter, FALSE);
1188 		}
1189 	}
1190 }
1191 
1192 void
debug_tree_update_all(DmaDebuggerQueue * debugger)1193 debug_tree_update_all (DmaDebuggerQueue *debugger)
1194 {
1195 	dma_queue_update_variable (debugger,
1196 			(IAnjutaDebuggerCallback)on_debug_tree_update_all,
1197 			debugger);
1198 }
1199 
1200 /* Update all variables in the specified tree */
1201 void
debug_tree_update_tree(DebugTree * this)1202 debug_tree_update_tree (DebugTree *this)
1203 {
1204 	GtkTreeModel *model;
1205 	GtkTreeIter iter;
1206 	gboolean valid;
1207 
1208 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (this->view));
1209 
1210 	// Update this tree
1211 	for (valid = gtk_tree_model_get_iter_first (model, &iter);
1212 		valid;
1213 		valid = gtk_tree_model_iter_next (model, &iter))
1214 	{
1215 		debug_tree_update_real (model, this->debugger, &iter, TRUE);
1216 	}
1217 }
1218 
1219 GList*
debug_tree_get_full_watch_list(DebugTree * this)1220 debug_tree_get_full_watch_list (DebugTree *this)
1221 {
1222 	GtkTreeIter iter;
1223 	GtkTreeModel *model;
1224 	GList* list = NULL;
1225 
1226 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (this->view));
1227 
1228 	if (gtk_tree_model_get_iter_first (model, &iter) == TRUE)
1229 	{
1230 		do
1231 		{
1232 			DmaVariableData *data;
1233 			gchar *exp;
1234 			gchar *exp_with_flag;
1235 
1236 			gtk_tree_model_get(model, &iter, DTREE_ENTRY_COLUMN, &data,
1237 							                 VARIABLE_COLUMN, &exp, -1);
1238 
1239 			if (data != NULL)
1240 			{
1241 				exp_with_flag = g_strconcat (" ", exp, NULL);
1242 				exp_with_flag[0] = data->auto_update ? AUTO_UPDATE_WATCH : ' ';
1243 				list = g_list_prepend (list, exp_with_flag);
1244 			}
1245 			g_free (exp);
1246 		} while (gtk_tree_model_iter_next (model, &iter) == TRUE);
1247 	}
1248 
1249 	list = g_list_reverse (list);
1250 
1251 	return list;
1252 }
1253 
1254 
1255 GtkWidget *
debug_tree_get_tree_widget(DebugTree * this)1256 debug_tree_get_tree_widget (DebugTree *this)
1257 {
1258 	return this->view;
1259 }
1260 
1261 gboolean
debug_tree_get_current(DebugTree * tree,GtkTreeIter * iter)1262 debug_tree_get_current (DebugTree *tree, GtkTreeIter* iter)
1263 {
1264 	return get_current_iter (GTK_TREE_VIEW (tree->view), iter);
1265 }
1266 
1267 /* Return TRUE if iter is still valid (point to next item) */
1268 gboolean
debug_tree_remove(DebugTree * tree,GtkTreeIter * iter)1269 debug_tree_remove (DebugTree *tree, GtkTreeIter* iter)
1270 {
1271 	GtkTreeModel *model;
1272 
1273 	g_return_val_if_fail (tree, FALSE);
1274 	g_return_val_if_fail (tree->view, FALSE);
1275 	g_return_val_if_fail (iter, FALSE);
1276 
1277 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree->view));
1278 
1279 	delete_parent (model, NULL, iter, tree->debugger);
1280 	return gtk_tree_store_remove (GTK_TREE_STORE (model), iter);
1281 }
1282 
1283 gboolean
debug_tree_update(DebugTree * tree,GtkTreeIter * iter,gboolean force)1284 debug_tree_update (DebugTree* tree, GtkTreeIter* iter, gboolean force)
1285 {
1286 	if (tree->debugger != NULL)
1287 	{
1288 		GtkTreeModel *model;
1289 
1290 		model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree->view));
1291 		return debug_tree_update_real (model, tree->debugger, iter, force);
1292 	}
1293 	else
1294 	{
1295 		return FALSE;
1296 	}
1297 }
1298 
1299 void
debug_tree_set_auto_update(DebugTree * this,GtkTreeIter * iter,gboolean state)1300 debug_tree_set_auto_update (DebugTree* this, GtkTreeIter* iter, gboolean state)
1301 {
1302 	GtkTreeModel *model;
1303 	DmaVariableData *data;
1304 
1305 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (this->view));
1306 	gtk_tree_model_get(model, iter, DTREE_ENTRY_COLUMN, &data, -1);
1307 	if (data != NULL)
1308 	{
1309 		data->auto_update = state;
1310 	}
1311 }
1312 
1313 gboolean
debug_tree_get_auto_update(DebugTree * this,GtkTreeIter * iter)1314 debug_tree_get_auto_update (DebugTree* this, GtkTreeIter* iter)
1315 {
1316 	GtkTreeModel *model;
1317 	DmaVariableData *data;
1318 
1319 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (this->view));
1320 	gtk_tree_model_get(model, iter, DTREE_ENTRY_COLUMN, &data, -1);
1321 
1322 	if (data != NULL)
1323 	{
1324 		return data->auto_update;
1325 	}
1326 	else
1327 	{
1328 		return FALSE;
1329 	}
1330 }
1331 
1332 void
debug_tree_connect(DebugTree * this,DmaDebuggerQueue * debugger)1333 debug_tree_connect (DebugTree *this, DmaDebuggerQueue* debugger)
1334 {
1335 	this->debugger = debugger;
1336 }
1337 
1338 static gboolean
on_disconnect_variable(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer user_data)1339 on_disconnect_variable (GtkTreeModel *model,
1340 						GtkTreePath *path,
1341 						GtkTreeIter *iter,
1342 						gpointer user_data)
1343 {
1344 	DmaVariableData *data;
1345 
1346 	gtk_tree_model_get (model, iter, DTREE_ENTRY_COLUMN, &data, -1);
1347 
1348 	if (data != NULL)
1349 	{
1350 		g_free (data->name);
1351 		data->name = NULL;
1352 	}
1353 
1354 	return FALSE;
1355 }
1356 
1357 void
debug_tree_disconnect(DebugTree * this)1358 debug_tree_disconnect (DebugTree *this)
1359 {
1360 	GtkTreeModel *model;
1361 
1362 	this->debugger = NULL;
1363 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (this->view));
1364 
1365 	/* Remove all variable name */
1366 	gtk_tree_model_foreach (model, on_disconnect_variable, NULL);
1367 }
1368 
1369 GtkTreeModel *
debug_tree_get_model(DebugTree * tree)1370 debug_tree_get_model (DebugTree *tree)
1371 {
1372 	return gtk_tree_view_get_model (GTK_TREE_VIEW (tree->view));
1373 }
1374 
1375 void
debug_tree_set_model(DebugTree * tree,GtkTreeModel * model)1376 debug_tree_set_model (DebugTree *tree, GtkTreeModel *model)
1377 {
1378 	gtk_tree_view_set_model (GTK_TREE_VIEW (tree->view), model);
1379 }
1380 
1381 void
debug_tree_new_model(DebugTree * tree)1382 debug_tree_new_model (DebugTree *tree)
1383 {
1384 	GtkTreeModel * model = GTK_TREE_MODEL (gtk_tree_store_new
1385 		                     (N_COLUMNS,
1386 	                          G_TYPE_STRING,
1387 	                          G_TYPE_STRING,
1388                               G_TYPE_STRING,
1389 				              G_TYPE_BOOLEAN,
1390 			                  G_TYPE_POINTER));
1391 
1392 	gtk_tree_view_set_model (GTK_TREE_VIEW (tree->view), model);
1393 }
1394 
1395 void
debug_tree_remove_model(DebugTree * tree,GtkTreeModel * model)1396 debug_tree_remove_model (DebugTree *tree, GtkTreeModel *model)
1397 {
1398 	my_gtk_tree_model_foreach_child (model, NULL, delete_parent, tree->debugger);
1399 	gtk_tree_store_clear (GTK_TREE_STORE (model));
1400 }
1401 
1402 gchar *
debug_tree_get_selected(DebugTree * tree)1403 debug_tree_get_selected (DebugTree *tree)
1404 {
1405 	GtkTreeIter iter;
1406 	gchar *exp = NULL;
1407 
1408 	if (get_current_iter (GTK_TREE_VIEW (tree->view), &iter))
1409 	{
1410 		GtkTreeModel *model;
1411 
1412 		model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree->view));
1413 		if (model != NULL)
1414 		{
1415 			gtk_tree_model_get(model, &iter, VARIABLE_COLUMN, &exp, -1);
1416 		}
1417 	}
1418 
1419 	return exp;
1420 }
1421 
1422 gchar *
debug_tree_get_first(DebugTree * tree)1423 debug_tree_get_first (DebugTree *tree)
1424 {
1425 	GtkTreeIter iter;
1426 	gchar *exp = NULL;
1427 	GtkTreeModel *model;
1428 
1429 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree->view));
1430 	if (model != NULL)
1431 	{
1432 		if (gtk_tree_model_get_iter_first (model, &iter))
1433 		{
1434 			gtk_tree_model_get(model, &iter, VARIABLE_COLUMN, &exp, -1);
1435 		}
1436 	}
1437 
1438 	return exp;
1439 }
1440 
1441 gchar*
debug_tree_find_variable_value(DebugTree * tree,const gchar * name)1442 debug_tree_find_variable_value (DebugTree *tree, const gchar *name)
1443 {
1444 	GtkTreeModel *model;
1445 	GtkTreeIter iter;
1446 
1447 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree->view));
1448 
1449 	if (gtk_tree_model_get_iter_first (model, &iter))
1450 	{
1451 		gchar *exp;
1452 		gchar *value;
1453 		do
1454 		{
1455 			gtk_tree_model_get(model, &iter, VARIABLE_COLUMN, &exp,
1456 							                 VALUE_COLUMN, &value, -1);
1457 
1458 			if (strcmp (exp, name) == 0)
1459 			{
1460 				return value;
1461 			}
1462 		} while (gtk_tree_model_iter_next (model, &iter));
1463 	}
1464 
1465 	return NULL;
1466 }
1467 
1468 /* Debugging functions
1469  *---------------------------------------------------------------------------*/
1470 
1471 static void
debug_tree_dump_iter(GtkTreeModel * model,GtkTreeIter * iter,guint indent)1472 debug_tree_dump_iter (GtkTreeModel *model, GtkTreeIter *iter, guint indent)
1473 {
1474 	gchar *expression;
1475 	gchar *value;
1476 	gchar *type;
1477 	DmaVariableData *node;
1478 	GtkTreeIter child;
1479 	gboolean valid;
1480 
1481 	gtk_tree_model_get (model, iter,
1482 						VARIABLE_COLUMN, &expression,
1483 						VALUE_COLUMN, &value,
1484 						TYPE_COLUMN, &type,
1485 						DTREE_ENTRY_COLUMN, &node,
1486 						-1);
1487 	if (node != NULL)
1488 	{
1489 		g_message ("%*s %s | %s | %s | %s | %d%d%d%d%d", indent, "",
1490 					expression, value, type, node->name,
1491 					node->modified, node->changed, node->exited, node->deleted, node->auto_update);
1492 	}
1493 	else
1494 	{
1495 		g_message ("%*s %s | %s | %s | %s | %c%c%c%c%c", indent, "",
1496 					expression, value, type, "???",
1497 					'?','?','?','?','?');
1498 	}
1499 	g_free (expression);
1500 	g_free (value);
1501 	g_free (type);
1502 
1503 	for (valid = gtk_tree_model_iter_children (model, &child, iter);
1504 		valid;
1505 		valid = gtk_tree_model_iter_next (model, &child))
1506 	{
1507 		debug_tree_dump_iter (model, &child, indent + 4);
1508 	}
1509 }
1510 
1511 void
debug_tree_dump(void)1512 debug_tree_dump (void)
1513 {
1514 	GList *list;
1515 
1516 	for (list = g_list_first (gTreeList); list != NULL; list = g_list_next (list))
1517 	{
1518 		DebugTree* tree = (DebugTree*)list->data;
1519 
1520 		GtkTreeModel* model;
1521 		GtkTreeIter iter;
1522 		gboolean valid;
1523 
1524 		model = debug_tree_get_model (tree);
1525 		g_message ("Tree model %p   MCEDU", model);
1526 		for (valid = gtk_tree_model_get_iter_first (model, &iter);
1527 			valid;
1528 			valid = gtk_tree_model_iter_next (model, &iter))
1529 		{
1530 			debug_tree_dump_iter (model, &iter, 4);
1531 		}
1532 	}
1533 }
1534 
1535 /* Constructor & Destructor
1536  *---------------------------------------------------------------------------*/
1537 
1538 /* return a pointer to a newly allocated DebugTree object */
1539 DebugTree *
debug_tree_new_with_view(AnjutaPlugin * plugin,GtkTreeView * view)1540 debug_tree_new_with_view (AnjutaPlugin *plugin, GtkTreeView *view)
1541 {
1542 	DebugTree *tree = g_new0 (DebugTree, 1);
1543 
1544 	tree->plugin = plugin;
1545 	tree->view = debug_tree_create(tree, view);
1546 	tree->auto_expand = FALSE;
1547 
1548 	/* Add this tree in list */
1549 	gTreeList = g_list_prepend (gTreeList, tree);
1550 
1551 	/* Connect signal */
1552     g_signal_connect(GTK_TREE_VIEW (tree->view), "row_expanded", G_CALLBACK (on_treeview_row_expanded), tree);
1553 
1554 
1555 	return tree;
1556 }
1557 
1558 
1559 /* return a pointer to a newly allocated DebugTree object */
1560 DebugTree *
debug_tree_new(AnjutaPlugin * plugin)1561 debug_tree_new (AnjutaPlugin* plugin)
1562 {
1563 	return debug_tree_new_with_view (plugin, NULL);
1564 }
1565 
1566 /* DebugTree destructor */
1567 void
debug_tree_free(DebugTree * tree)1568 debug_tree_free (DebugTree * tree)
1569 {
1570 	g_return_if_fail (tree);
1571 
1572 	debug_tree_remove_all (tree);
1573 
1574 	/* Remove from list */
1575 	gTreeList = g_list_remove (gTreeList, tree);
1576 
1577 	g_signal_handlers_disconnect_by_func (GTK_TREE_VIEW (tree->view),
1578 				  G_CALLBACK (on_treeview_row_expanded), tree);
1579 
1580 	gtk_widget_destroy (tree->view);
1581 
1582 
1583 	g_free (tree);
1584 }
1585