Added byline
[anjuta.git] / plugins / debug-manager / stack_trace.c
blobffdd1728391ad04bf3b372af1c3d279ac9a6187e
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 stack_trace.c
4 Copyright (C) 2000 Kh. Naba Kumar Singh
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.
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.
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
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
24 #include "stack_trace.h"
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <stdlib.h>
31 #include <glib/gi18n.h>
32 #include <gio/gio.h>
34 /*#define DEBUG*/
35 #include <libanjuta/resources.h>
36 #include <libanjuta/anjuta-debug.h>
37 #include <libanjuta/interfaces/ianjuta-editor.h>
38 #include <libanjuta/interfaces/ianjuta-document-manager.h>
40 #include "utilities.h"
41 #include "info.h"
42 #include "queue.h"
44 #define ANJUTA_PIXMAP_POINTER PACKAGE_PIXMAPS_DIR"/pointer.png"
46 struct _StackTrace
48 DebugManagerPlugin *plugin;
49 DmaDebuggerQueue *debugger;
51 GtkActionGroup *action_group;
53 gint current_thread;
54 guint current_frame;
56 gulong changed_handler;
58 GtkTreeView *treeview;
59 GtkMenu *menu;
60 GtkWidget *scrolledwindow;
63 typedef struct _StackPacket StackPacket;
65 struct _StackPacket {
66 StackTrace* self;
67 guint thread;
68 gboolean scroll;
69 gboolean unblock;
72 enum {
73 STACK_TRACE_ACTIVE_COLUMN,
74 STACK_TRACE_THREAD_COLUMN,
75 STACK_TRACE_FRAME_COLUMN,
76 STACK_TRACE_FILE_COLUMN,
77 STACK_TRACE_LINE_COLUMN,
78 STACK_TRACE_FUNC_COLUMN,
79 STACK_TRACE_ADDR_COLUMN,
80 STACK_TRACE_ARGS_COLUMN,
81 STACK_TRACE_DIRTY_COLUMN,
82 STACK_TRACE_URI_COLUMN,
83 STACK_TRACE_COLOR_COLUMN,
84 STACK_TRACE_N_COLUMNS
87 /* Helpers functions
88 *---------------------------------------------------------------------------*/
90 static gboolean
91 get_current_iter (GtkTreeView *view, GtkTreeIter* iter)
93 GtkTreeSelection *selection;
95 selection = gtk_tree_view_get_selection (view);
96 return gtk_tree_selection_get_selected (selection, NULL, iter);
100 * returns TRUE if a frame is selected
102 static gboolean
103 get_current_frame_and_thread (StackTrace* st, guint *frame, gint *thread)
105 GtkTreeIter iter;
107 if (get_current_iter (st->treeview, &iter))
109 GtkTreeModel *model;
110 GtkTreeIter parent;
111 gchar *str;
113 model = gtk_tree_view_get_model (st->treeview);
114 *frame = 0;
115 if (gtk_tree_model_iter_parent (model, &parent, &iter))
117 gtk_tree_model_get (model, &iter, STACK_TRACE_FRAME_COLUMN, &str, -1);
118 if (str != NULL)
120 *frame = strtoul (str, NULL, 10);
121 g_free (str);
123 gtk_tree_model_get (model, &parent, STACK_TRACE_THREAD_COLUMN, &str, -1);
125 else
127 gtk_tree_model_get (model, &iter, STACK_TRACE_THREAD_COLUMN, &str, -1);
129 *thread = (str != NULL) ? strtoul (str, NULL, 10) : 0;
130 g_free (str);
132 return thread != 0 ? TRUE : FALSE;
134 else
136 return FALSE;
140 static gboolean
141 my_gtk_tree_model_get_iter_last(GtkTreeModel *model, GtkTreeIter *parent, GtkTreeIter *last)
143 gboolean exist;
144 GtkTreeIter iter;
146 exist = gtk_tree_model_iter_children(model, &iter, parent);
147 if (!exist) return FALSE;
151 *last = iter;
152 exist = gtk_tree_model_iter_next(model, &iter);
154 while (exist);
156 return TRUE;
159 static gboolean
160 my_gtk_tree_model_iter_prev(GtkTreeModel *model, GtkTreeIter *iter)
162 GtkTreePath* path;
163 gboolean exist;
165 path = gtk_tree_model_get_path (model, iter);
166 exist = gtk_tree_path_prev (path);
167 if (exist)
169 exist = gtk_tree_model_get_iter (model, iter, path);
171 gtk_tree_path_free (path);
173 return exist;
176 static gint
177 my_gtk_tree_iter_compare(GtkTreeModel *model, GtkTreeIter *itera, GtkTreeIter *iterb)
179 GtkTreePath* patha;
180 GtkTreePath* pathb;
181 gint comp;
183 patha = gtk_tree_model_get_path (model, itera);
184 pathb = gtk_tree_model_get_path (model, iterb);
186 comp = gtk_tree_path_compare (patha, pathb);
188 gtk_tree_path_free (patha);
189 gtk_tree_path_free (pathb);
191 return comp;
194 static gboolean
195 find_thread (GtkTreeModel *model, GtkTreeIter *iter, guint thread)
197 gboolean found;
199 for (found = gtk_tree_model_get_iter_first (model, iter); found; found = gtk_tree_model_iter_next (model, iter))
201 gchar *str;
202 guint id;
204 gtk_tree_model_get (model, iter, STACK_TRACE_THREAD_COLUMN, &str, -1);
205 if (str != NULL)
207 id = strtoul (str, NULL, 10);
208 g_free (str);
209 if (id == thread) break;
213 return found;
216 /* Private functions
217 *---------------------------------------------------------------------------*/
219 static void
220 set_stack_frame (StackTrace *self, guint frame, gint thread)
222 GtkTreeIter parent;
223 GtkTreeIter iter;
224 GtkTreeModel *model;
225 gboolean valid;
227 model = gtk_tree_view_get_model (self->treeview);
229 /* Clear old pointer */
230 valid = find_thread (model, &parent, self->current_thread);
231 if (valid)
233 if (gtk_tree_model_iter_nth_child (model, &iter, &parent, self->current_frame))
235 /* clear pixmap on the previous active frame */
236 gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
237 STACK_TRACE_ACTIVE_COLUMN, NULL, -1);
241 if (self->current_thread != thread)
243 self->current_thread = thread;
244 valid = find_thread (model, &parent, self->current_thread);
247 /* Set pointer on current frame if possible */
248 self->current_frame = frame;
249 if (valid)
251 if (gtk_tree_model_iter_nth_child (model, &iter, &parent, self->current_frame))
253 GdkPixbuf *pointer_pix = gdk_pixbuf_new_from_file (ANJUTA_PIXMAP_POINTER, NULL);
255 gtk_tree_store_set (GTK_TREE_STORE(model), &iter,
256 STACK_TRACE_ACTIVE_COLUMN, pointer_pix,
257 -1);
258 g_object_unref (pointer_pix);
263 static void
264 on_stack_trace_updated (const GList *stack, gpointer user_data, GError *error)
266 StackPacket *packet = (StackPacket *)user_data;
267 StackTrace *self;
268 guint thread;
269 GtkTreeModel *model;
270 GtkTreeIter iter;
271 GtkTreeIter parent;
272 const GList *node;
273 gboolean exist;
274 GtkTreePath *path;
276 g_return_if_fail (packet != NULL);
278 self = packet->self;
279 thread = packet->thread;
280 if (packet->unblock) g_signal_handler_unblock (self->plugin, self->changed_handler);
281 g_slice_free (StackPacket, packet);
283 if (error != NULL) return;
285 model = gtk_tree_view_get_model (self->treeview);
287 if (!find_thread (model, &parent, thread)) return;
289 /* Check if there are already some data */
290 exist = my_gtk_tree_model_get_iter_last (GTK_TREE_MODEL (model), &parent, &iter);
291 if (exist)
293 GValue val = {0};
295 gtk_tree_model_get_value(model, &iter, STACK_TRACE_FRAME_COLUMN, &val);
296 if (!G_IS_VALUE (&val))
298 /* Remove dummy child */
299 gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
301 exist = FALSE;
305 for (node = (const GList *)g_list_last((GList *)stack); node != NULL; node = node->prev)
307 IAnjutaDebuggerFrame *frame;
308 gchar *frame_str;
309 gchar *adr_str;
310 gchar *line_str;
311 gchar *uri;
312 gchar *file;
314 frame = (IAnjutaDebuggerFrame *)node->data;
316 if (exist)
318 /* Check if it's the same stack frame */
319 gchar *args;
320 gulong address;
321 guint line;
322 gboolean same;
324 gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
325 STACK_TRACE_ADDR_COLUMN, &adr_str,
326 STACK_TRACE_LINE_COLUMN, &line_str,
327 STACK_TRACE_ARGS_COLUMN, &args,
328 -1);
329 address = adr_str != NULL ? strtoul (adr_str, NULL, 0) : 0;
330 line = line_str != NULL ? strtoul (line_str, NULL, 10) : 0;
331 same = (address == frame->address) && (line == frame->line);
332 if ((args == NULL) || (frame->args == NULL))
334 same = same && (args == frame->args);
336 else
338 same = same && (strcmp (args, frame->args) == 0);
340 g_free (adr_str);
341 g_free (args);
343 if (same)
345 /* Same frame, just change the color */
346 frame_str = g_strdup_printf ("%d", frame->level);
347 gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
348 STACK_TRACE_ACTIVE_COLUMN, NULL,
349 STACK_TRACE_FRAME_COLUMN, frame_str,
350 STACK_TRACE_COLOR_COLUMN, "black", -1);
351 g_free (frame_str);
353 /* Check previous frame */
354 exist = my_gtk_tree_model_iter_prev (model, &iter);
355 if (!exist || (node->prev != NULL))
357 /* Last frame or Upper frame still exist */
358 continue;
360 /* Upper frame do not exist, remove all them */
363 /* New frame, remove all previous frame */
364 GtkTreeIter first;
366 gtk_tree_model_iter_children (model, &first, &parent);
367 while (my_gtk_tree_iter_compare (model, &first, &iter) < 0)
369 gtk_tree_store_remove (GTK_TREE_STORE (model), &first);
371 gtk_tree_store_remove (GTK_TREE_STORE (model), &first);
373 if (same)
375 break;
377 else
379 exist = FALSE;
383 gtk_tree_store_prepend (GTK_TREE_STORE (model), &iter, &parent);
385 frame_str = g_strdup_printf ("%d", frame->level);
386 adr_str = g_strdup_printf ("0x%lx", frame->address);
387 if (frame->file)
389 if (g_path_is_absolute (frame->file))
391 GFile *gio_file = g_file_new_for_path (frame->file);
392 uri = g_file_get_uri (gio_file);
393 file = strrchr(frame->file, G_DIR_SEPARATOR) + 1;
394 g_object_unref (gio_file);
396 else
398 uri = NULL;
399 file = frame->file;
401 line_str = g_strdup_printf ("%d", frame->line);
403 else
405 uri = NULL;
406 file = frame->library;
407 line_str = NULL;
410 gtk_tree_store_set(GTK_TREE_STORE (model), &iter,
411 STACK_TRACE_ACTIVE_COLUMN, NULL,
412 STACK_TRACE_FRAME_COLUMN, frame_str,
413 STACK_TRACE_FILE_COLUMN, file,
414 STACK_TRACE_LINE_COLUMN, line_str,
415 STACK_TRACE_FUNC_COLUMN, frame->function,
416 STACK_TRACE_ADDR_COLUMN, adr_str,
417 STACK_TRACE_ARGS_COLUMN, frame->args,
418 STACK_TRACE_URI_COLUMN, uri,
419 STACK_TRACE_COLOR_COLUMN, "red",
420 -1);
421 g_free (uri);
422 g_free (line_str);
423 g_free (adr_str);
424 g_free (frame_str);
426 gtk_tree_store_set(GTK_TREE_STORE (model), &parent,
427 STACK_TRACE_DIRTY_COLUMN, FALSE,
428 -1);
430 /* Expand and show new path */
431 path = gtk_tree_model_get_path (model, &parent);
432 gtk_tree_view_expand_row (self->treeview, path, FALSE);
433 if (self->current_thread == thread)
435 set_stack_frame (self, self->current_frame, self->current_thread);
436 gtk_tree_view_scroll_to_cell (self->treeview, path, NULL, FALSE, 0, 0);
438 gtk_tree_path_free (path);
442 static void
443 list_stack_frame (StackTrace *self, guint thread, gboolean update)
445 GtkTreeModel *model;
446 GtkTreeIter iter;
447 gboolean found;
448 gboolean dirty;
450 model = gtk_tree_view_get_model (self->treeview);
452 if (!update)
454 /* Search thread */
455 found = find_thread (model, &iter, thread);
456 if (found)
458 /* Check if stack trace need to be updated */
459 gtk_tree_model_get(model, &iter, STACK_TRACE_DIRTY_COLUMN, &dirty, -1);
463 /* Update stack trace */
464 if (update || !found || dirty)
466 StackPacket *packet;
468 if (thread != self->current_thread)
470 /* Change current thread temporarily */
471 dma_queue_set_thread (self->debugger, thread);
472 g_signal_handler_block (self->plugin, self->changed_handler);
474 packet = g_slice_new (StackPacket);
475 packet->thread = thread;
476 packet->self = self;
477 packet->scroll = update;
478 packet->unblock = thread != self->current_thread;
479 dma_queue_list_frame (self->debugger,
480 (IAnjutaDebuggerCallback)on_stack_trace_updated,
481 packet);
482 if (thread != self->current_thread) dma_queue_set_thread (self->debugger, self->current_thread);
486 static void
487 on_thread_updated (const GList *threads, gpointer user_data)
489 StackTrace *self = (StackTrace *)user_data;
490 GList *node;
491 GtkTreeModel *model;
492 GtkTreeIter iter;
493 gboolean valid;
494 GList *new_threads;
496 model = gtk_tree_view_get_model (self->treeview);
498 /* Remove completed threads */
499 new_threads = g_list_copy ((GList *)threads);
500 valid = gtk_tree_model_get_iter_first (model, &iter);
501 while (valid)
503 gchar *str;
504 gint thread;
506 gtk_tree_model_get(model, &iter, STACK_TRACE_THREAD_COLUMN, &str, -1);
507 thread = (str != NULL) ? strtoul (str, NULL, 10) : 0;
508 g_free (str);
510 for (node = new_threads; node != NULL; node = node->next)
512 if (((IAnjutaDebuggerFrame *)node->data)->thread == thread) break;
515 if (node != NULL)
517 GtkTreePath *path;
519 /* Thread still existing */
520 new_threads = g_list_delete_link (new_threads, node);
521 /* Set content as dirty */
522 gtk_tree_store_set(GTK_TREE_STORE (model), &iter,
523 STACK_TRACE_DIRTY_COLUMN, TRUE,
524 STACK_TRACE_COLOR_COLUMN, "black",
525 -1);
527 /* Update stack frame if it is visible */
528 path = gtk_tree_model_get_path (model, &iter);
529 if (gtk_tree_view_row_expanded (self->treeview, path))
531 list_stack_frame (self, thread, TRUE);
533 gtk_tree_path_free (path);
535 valid = gtk_tree_model_iter_next (model, &iter);
537 else
539 /* Thread completed */
540 valid = gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
545 /* Add new threads */
546 while (new_threads != NULL)
548 GtkTreeIter child;
549 gchar *str;
551 str = g_strdup_printf ("%d", ((IAnjutaDebuggerFrame *)new_threads->data)->thread);
552 gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
553 gtk_tree_store_set(GTK_TREE_STORE (model), &iter,
554 STACK_TRACE_THREAD_COLUMN, str,
555 STACK_TRACE_DIRTY_COLUMN, TRUE,
556 STACK_TRACE_COLOR_COLUMN, "red",
557 -1);
558 g_free (str);
560 /* Add a dummy child, to get the row expander */
561 gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
563 new_threads = g_list_delete_link (new_threads, new_threads);
567 static void
568 list_threads (StackTrace *self)
570 dma_queue_list_thread (
571 self->debugger,
572 (IAnjutaDebuggerCallback)on_thread_updated,
573 self);
578 /* Callback functions
579 *---------------------------------------------------------------------------*/
581 static void
582 on_stack_frame_set_activate (GtkAction *action, gpointer user_data)
584 StackTrace *self;
585 gint thread;
586 guint frame;
588 self = (StackTrace*) user_data;
590 if (get_current_frame_and_thread (self, &frame, &thread))
592 if (thread != self->current_thread)
594 dma_queue_set_thread (self->debugger, thread);
595 dma_queue_set_frame (self->debugger, frame);
596 set_stack_frame (self, frame, thread);
597 list_stack_frame (self, thread, FALSE);
599 else if (frame != self->current_frame)
601 dma_queue_set_frame (self->debugger, frame);
602 set_stack_frame (self, frame, thread);
603 list_stack_frame (self, thread, FALSE);
608 static void
609 on_stack_view_source_activate (GtkAction *action, gpointer user_data)
611 GtkTreeModel *model;
612 GtkTreeSelection *selection;
613 GtkTreeIter iter;
614 GtkTreeView *view;
615 gchar *uri;
616 gchar *line_str;
617 guint line;
618 gchar *adr_str;
619 gulong address;
621 StackTrace* st = (StackTrace*) user_data;
623 view = st->treeview;
624 selection = gtk_tree_view_get_selection (view);
625 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
626 return;
628 /* get the frame info */
629 gtk_tree_model_get (model, &iter,
630 STACK_TRACE_URI_COLUMN, &uri,
631 STACK_TRACE_LINE_COLUMN, &line_str,
632 STACK_TRACE_ADDR_COLUMN, &adr_str,
633 -1);
635 address = adr_str != NULL ? strtoul (adr_str, NULL, 0) : 0;
636 line = line_str != NULL ? strtoul (line_str, NULL, 0) : 0;
637 g_signal_emit_by_name (st->plugin, "location-changed", address, uri, line);
638 g_free (uri);
639 g_free (line_str);
640 g_free (adr_str);
643 static void
644 on_got_stack_trace (const gchar *trace, gpointer user_data, GError *error)
646 StackTrace* st = (StackTrace*) user_data;
647 IAnjutaDocumentManager *docman;
649 docman = anjuta_shell_get_interface (ANJUTA_PLUGIN (st->plugin)->shell, IAnjutaDocumentManager, NULL);
650 if (docman != NULL)
652 ianjuta_document_manager_add_buffer (docman, "Stack Trace", trace, NULL);
656 static void
657 on_stack_get_trace (GtkAction *action, gpointer user_data)
659 StackTrace* st = (StackTrace*) user_data;
661 /* Ask debugger to get all frame data */
662 dma_queue_dump_stack_trace (
663 st->debugger,
664 (IAnjutaDebuggerCallback)on_got_stack_trace,
665 st);
668 static void
669 on_stack_trace_row_activated (GtkTreeView *treeview,
670 GtkTreePath *arg1,
671 GtkTreeViewColumn *arg2,
672 StackTrace *st)
674 on_stack_frame_set_activate (NULL, st);
677 static void
678 on_stack_trace_row_expanded (GtkTreeView *treeview,
679 GtkTreeIter *iter,
680 GtkTreePath *path,
681 StackTrace *st)
683 GtkTreeModel *model;
684 gchar *str;
685 guint thread;
687 model = gtk_tree_view_get_model (treeview);
689 gtk_tree_model_get (model, iter, STACK_TRACE_THREAD_COLUMN, &str, -1);
690 thread = (str != NULL) ? strtoul (str, NULL, 10) : 0;
691 g_free (str);
693 list_stack_frame (st, thread, FALSE);
696 static gboolean
697 on_stack_trace_button_press (GtkWidget *widget, GdkEventButton *bevent, gpointer user_data)
699 StackTrace *st = (StackTrace*) user_data;
701 if ((bevent->type == GDK_BUTTON_PRESS) && (bevent->button == 3))
703 /* Right mouse click */
704 g_return_val_if_fail (st->menu != NULL, FALSE);
705 gtk_menu_popup (GTK_MENU (st->menu), NULL, NULL, NULL, NULL,
706 bevent->button, bevent->time);
708 else if ((bevent->type == GDK_2BUTTON_PRESS) && (bevent->button == 1))
710 /* Double left mouse click */
711 on_stack_view_source_activate (NULL, user_data);
714 return FALSE;
717 /* Actions table
718 *---------------------------------------------------------------------------*/
720 static GtkActionEntry actions_stack_trace[] = {
722 "ActionDmaSetCurrentFrame", /* Action name */
723 NULL, /* Stock icon, if any */
724 N_("Set current frame"), /* Display label */
725 NULL, /* short-cut */
726 NULL, /* Tooltip */
727 G_CALLBACK (on_stack_frame_set_activate) /* action callback */
730 "ActionDmaJumpToFrame",
731 NULL,
732 N_("View Source"),
733 NULL,
734 NULL,
735 G_CALLBACK (on_stack_view_source_activate)
738 "ActionDmaDumpStackTrace",
739 NULL,
740 N_("Get Stack trace"),
741 NULL,
742 NULL,
743 G_CALLBACK (on_stack_get_trace)
747 static void
748 create_stack_trace_gui(StackTrace *st)
750 GtkTreeModel* model;
751 GtkTreeSelection *selection;
752 GtkTreeViewColumn *column;
753 GtkCellRenderer *renderer;
754 AnjutaUI *ui;
756 g_return_if_fail (st->scrolledwindow == NULL);
758 /* Create tree view */
759 model = GTK_TREE_MODEL(gtk_tree_store_new (STACK_TRACE_N_COLUMNS,
760 GDK_TYPE_PIXBUF,
761 G_TYPE_STRING,
762 G_TYPE_STRING,
763 G_TYPE_STRING,
764 G_TYPE_STRING,
765 G_TYPE_STRING,
766 G_TYPE_STRING,
767 G_TYPE_STRING,
768 G_TYPE_BOOLEAN,
769 G_TYPE_STRING,
770 G_TYPE_STRING));
771 st->treeview = GTK_TREE_VIEW (gtk_tree_view_new_with_model (model));
772 g_object_unref (G_OBJECT (model));
774 selection = gtk_tree_view_get_selection (st->treeview);
775 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
777 /* Columns */
778 column = gtk_tree_view_column_new ();
779 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
780 gtk_tree_view_column_set_title (column, _("Active"));
781 renderer = gtk_cell_renderer_pixbuf_new ();
782 gtk_tree_view_column_pack_start (column, renderer, TRUE);
783 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf",
784 STACK_TRACE_ACTIVE_COLUMN);
785 gtk_tree_view_append_column (st->treeview, column);
787 column = gtk_tree_view_column_new ();
788 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
789 gtk_tree_view_column_set_title (column, _("Thread"));
790 renderer = gtk_cell_renderer_text_new ();
791 gtk_tree_view_column_pack_start (column, renderer, TRUE);
792 gtk_tree_view_column_add_attribute (column, renderer, "text",
793 STACK_TRACE_THREAD_COLUMN);
794 gtk_tree_view_column_add_attribute (column, renderer, "foreground",
795 STACK_TRACE_COLOR_COLUMN);
796 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
797 gtk_tree_view_append_column (st->treeview, column);
798 gtk_tree_view_set_expander_column (st->treeview,
799 column);
801 column = gtk_tree_view_column_new ();
802 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
803 gtk_tree_view_column_set_title (column, _("Frame"));
804 renderer = gtk_cell_renderer_text_new ();
805 gtk_tree_view_column_pack_start (column, renderer, TRUE);
806 gtk_tree_view_column_add_attribute (column, renderer, "text",
807 STACK_TRACE_FRAME_COLUMN);
808 gtk_tree_view_column_add_attribute (column, renderer, "foreground",
809 STACK_TRACE_COLOR_COLUMN);
810 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
811 gtk_tree_view_append_column (st->treeview, column);
813 column = gtk_tree_view_column_new ();
814 renderer = gtk_cell_renderer_text_new ();
815 gtk_tree_view_column_pack_start (column, renderer, TRUE);
816 gtk_tree_view_column_add_attribute (column, renderer, "text",
817 STACK_TRACE_FILE_COLUMN);
818 gtk_tree_view_column_add_attribute (column, renderer, "foreground",
819 STACK_TRACE_COLOR_COLUMN);
820 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
821 gtk_tree_view_column_set_title (column, _("File"));
822 gtk_tree_view_append_column (st->treeview, column);
824 column = gtk_tree_view_column_new ();
825 renderer = gtk_cell_renderer_text_new ();
826 gtk_tree_view_column_pack_start (column, renderer, TRUE);
827 gtk_tree_view_column_add_attribute (column, renderer, "text",
828 STACK_TRACE_LINE_COLUMN);
829 gtk_tree_view_column_add_attribute (column, renderer, "foreground",
830 STACK_TRACE_COLOR_COLUMN);
831 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
832 gtk_tree_view_column_set_title (column, _("Line"));
833 gtk_tree_view_append_column (st->treeview, column);
835 column = gtk_tree_view_column_new ();
836 renderer = gtk_cell_renderer_text_new ();
837 gtk_tree_view_column_pack_start (column, renderer, TRUE);
838 gtk_tree_view_column_add_attribute (column, renderer, "text",
839 STACK_TRACE_FUNC_COLUMN);
840 gtk_tree_view_column_add_attribute (column, renderer, "foreground",
841 STACK_TRACE_COLOR_COLUMN);
842 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
843 gtk_tree_view_column_set_title (column, _("Function"));
844 gtk_tree_view_append_column (st->treeview, column);
846 if (dma_debugger_queue_is_supported (st->debugger, HAS_MEMORY))
848 /* Display address only if debugger has such concept */
849 column = gtk_tree_view_column_new ();
850 renderer = gtk_cell_renderer_text_new ();
851 gtk_tree_view_column_pack_start (column, renderer, TRUE);
852 gtk_tree_view_column_add_attribute (column, renderer, "text",
853 STACK_TRACE_ADDR_COLUMN);
854 gtk_tree_view_column_add_attribute (column, renderer, "foreground",
855 STACK_TRACE_COLOR_COLUMN);
856 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
857 gtk_tree_view_column_set_title (column, _("Address"));
858 gtk_tree_view_append_column (st->treeview, column);
861 column = gtk_tree_view_column_new ();
862 renderer = gtk_cell_renderer_text_new ();
863 gtk_tree_view_column_pack_start (column, renderer, TRUE);
864 gtk_tree_view_column_add_attribute (column, renderer, "text",
865 STACK_TRACE_ARGS_COLUMN);
866 gtk_tree_view_column_add_attribute (column, renderer, "foreground",
867 STACK_TRACE_COLOR_COLUMN);
868 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
869 gtk_tree_view_column_set_title (column, _("Arguments"));
870 gtk_tree_view_append_column (st->treeview, column);
872 /* Create popup menu */
873 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN(st->plugin)->shell, NULL);
874 st->menu = GTK_MENU (gtk_ui_manager_get_widget (GTK_UI_MANAGER (ui), "/PopupStack"));
876 /* Connect signal */
877 g_signal_connect (st->treeview, "button-press-event", G_CALLBACK (on_stack_trace_button_press), st);
878 g_signal_connect (st->treeview, "row-activated", G_CALLBACK (on_stack_trace_row_activated), st);
879 g_signal_connect (st->treeview, "row-expanded", G_CALLBACK (on_stack_trace_row_expanded), st);
881 /* Add stack window */
882 st->scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
883 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (st->scrolledwindow),
884 GTK_POLICY_AUTOMATIC,
885 GTK_POLICY_AUTOMATIC);
886 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (st->scrolledwindow),
887 GTK_SHADOW_IN);
888 gtk_container_add (GTK_CONTAINER (st->scrolledwindow),
889 GTK_WIDGET (st->treeview));
890 gtk_widget_show_all (st->scrolledwindow);
892 anjuta_shell_add_widget (ANJUTA_PLUGIN(st->plugin)->shell,
893 st->scrolledwindow,
894 "AnjutaDebuggerStack", _("Stack"),
895 "gdb-stack-icon", ANJUTA_SHELL_PLACEMENT_BOTTOM,
896 NULL);
900 static void
901 destroy_stack_trace_gui (StackTrace *st)
903 if (st->scrolledwindow != NULL)
905 gtk_widget_destroy (st->scrolledwindow);
906 st->scrolledwindow = NULL;
910 static void
911 on_frame_changed (StackTrace *self, guint frame, gint thread)
913 set_stack_frame (self, frame, thread);
914 list_stack_frame (self, thread, FALSE);
917 static void
918 on_program_moved (StackTrace *self, guint pid, gint thread)
920 set_stack_frame (self, 0, thread);
922 list_threads (self);
923 list_stack_frame (self, thread, TRUE);
926 static void
927 on_program_exited (StackTrace *self)
929 g_signal_handlers_disconnect_by_func (self->plugin, G_CALLBACK (on_program_exited), self);
930 g_signal_handlers_disconnect_by_func (self->plugin, G_CALLBACK (on_program_moved), self);
931 g_signal_handlers_disconnect_by_func (self->plugin, G_CALLBACK (on_frame_changed), self);
933 destroy_stack_trace_gui (self);
936 static void
937 on_program_started (StackTrace *self)
939 create_stack_trace_gui (self);
940 self->current_thread = 0;
941 self->current_frame = 0;
943 g_signal_connect_swapped (self->plugin, "program-exited", G_CALLBACK (on_program_exited), self);
944 g_signal_connect_swapped (self->plugin, "program-moved", G_CALLBACK (on_program_moved), self);
945 self->changed_handler = g_signal_connect_swapped (self->plugin, "frame-changed", G_CALLBACK (on_frame_changed), self);
948 /* Public functions
949 *---------------------------------------------------------------------------*/
951 /* Constructor & Destructor
952 *---------------------------------------------------------------------------*/
954 StackTrace *
955 stack_trace_new (DebugManagerPlugin *plugin)
957 StackTrace *st;
958 AnjutaUI *ui;
960 st = g_new0 (StackTrace, 1);
961 if (st == NULL) return NULL;
963 st->plugin = plugin;
964 st->debugger = dma_debug_manager_get_queue (plugin);
966 /* Register actions */
967 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN(st->plugin)->shell, NULL);
968 st->action_group =
969 anjuta_ui_add_action_group_entries (ui, "ActionGroupStack",
970 _("Stack frame operations"),
971 actions_stack_trace,
972 G_N_ELEMENTS (actions_stack_trace),
973 GETTEXT_PACKAGE, TRUE, st);
975 g_signal_connect_swapped (st->plugin, "program-started", G_CALLBACK (on_program_started), st);
977 return st;
980 void
981 stack_trace_free (StackTrace * st)
983 AnjutaUI *ui;
985 g_return_if_fail (st != NULL);
987 /* Disconnect from debugger */
988 g_signal_handlers_disconnect_matched (st->plugin, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, st);
990 /* Remove menu actions */
991 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN (st->plugin)->shell, NULL);
992 anjuta_ui_remove_action_group (ui, st->action_group);
994 /* Destroy menu */
995 destroy_stack_trace_gui (st);
997 g_free (st);