* plugins/debug-manager/anjuta-debug-manager.ui,
[anjuta-git-plugin.git] / plugins / debug-manager / stack_trace.c
blobf8a8b5649ab0b20e3cdd970c0de0ab6ba590b020
1 /*
2 stack_trace.c
3 Copyright (C) 2000 Kh. Naba Kumar Singh
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 #include "stack_trace.h"
25 #include "plugin.h"
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <gnome.h>
33 /*#define DEBUG*/
34 #include <libanjuta/resources.h>
35 #include <libanjuta/anjuta-debug.h>
36 #include <libanjuta/interfaces/ianjuta-editor.h>
37 #include <libanjuta/interfaces/ianjuta-document-manager.h>
39 #include "utilities.h"
40 #include "info.h"
42 #define ANJUTA_PIXMAP_POINTER PACKAGE_PIXMAPS_DIR"/pointer.png"
44 typedef struct _StackTraceGui StackTraceGui;
45 struct _StackTraceGui
47 GtkWidget *scrolledwindow;
48 GtkTreeView *clist;
49 GtkMenu *menu;
50 GtkWidget *menu_set;
51 GtkWidget *menu_info;
52 GtkWidget *menu_update;
53 GtkWidget *menu_view;
56 struct _StackTrace
58 AnjutaPlugin *plugin;
59 IAnjutaDebugger *debugger;
60 GtkActionGroup *action_group;
61 StackTraceGui widgets;
62 gint current_frame;
65 enum {
66 STACK_TRACE_ACTIVE_COLUMN,
67 STACK_TRACE_FRAME_COLUMN,
68 STACK_TRACE_FILE_COLUMN,
69 STACK_TRACE_LINE_COLUMN,
70 STACK_TRACE_FUNC_COLUMN,
71 STACK_TRACE_ADDR_COLUMN,
72 STACK_TRACE_ARGS_COLUMN,
73 STACK_TRACE_URI_COLUMN,
74 STACK_TRACE_N_COLUMNS
77 /* Helpers functions
78 *---------------------------------------------------------------------------*/
80 static gboolean
81 get_current_iter (GtkTreeView *view, GtkTreeIter* iter)
83 GtkTreeSelection *selection;
85 selection = gtk_tree_view_get_selection (view);
86 return gtk_tree_selection_get_selected (selection, NULL, iter);
90 * returns the current stack frame or -1 on error
92 static gint
93 get_current_index (StackTrace* st)
95 GtkTreeIter iter;
97 if (get_current_iter (st->widgets.clist, &iter))
99 GtkTreeModel *model;
100 gint frame_no;
102 model = gtk_tree_view_get_model (st->widgets.clist);
103 gtk_tree_model_get (model, &iter, STACK_TRACE_FRAME_COLUMN, &frame_no, -1);
105 return frame_no;
107 else
109 return -1;
113 /* Private functions
114 *---------------------------------------------------------------------------*/
116 static void
117 stack_trace_clear (StackTrace * st)
119 GtkTreeModel* model;
121 model = gtk_tree_view_get_model (st->widgets.clist);
122 gtk_list_store_clear (GTK_LIST_STORE (model));
125 /* Callback functions
126 *---------------------------------------------------------------------------*/
128 static void
129 on_stack_trace_updated (const GList *stack, gpointer data)
131 StackTrace *st;
132 const GList *node;
133 GtkListStore *model;
135 st = (StackTrace *) data;
136 stack_trace_clear (st);
138 model = GTK_LIST_STORE (gtk_tree_view_get_model (st->widgets.clist));
140 for (node = stack; node != NULL; node = node->next)
142 GdkPixbuf *pic;
143 GtkTreeIter iter;
144 IAnjutaDebuggerFrame *frame;
145 gchar *adr;
146 gchar *uri;
147 gchar *file;
149 frame = (IAnjutaDebuggerFrame *)node->data;
151 gtk_list_store_append (model, &iter);
153 /* if we are on the current frame set iterator and pixmap correctly */
154 if (frame->level == st->current_frame)
155 pic = gdk_pixbuf_new_from_file (ANJUTA_PIXMAP_POINTER, NULL);
156 else
157 pic = NULL;
159 adr = g_strdup_printf ("0x%x", frame->address);
160 if (frame->file)
162 uri = g_strconcat ("file://", frame->file, NULL);
163 file = strrchr(uri, '/') + 1;
165 else
167 uri = NULL;
168 file = frame->library;
171 gtk_list_store_set(model, &iter,
172 STACK_TRACE_ACTIVE_COLUMN, pic,
173 STACK_TRACE_FRAME_COLUMN, frame->level,
174 STACK_TRACE_FILE_COLUMN, file,
175 STACK_TRACE_LINE_COLUMN, frame->line,
176 STACK_TRACE_FUNC_COLUMN, frame->function,
177 STACK_TRACE_ADDR_COLUMN, adr,
178 STACK_TRACE_ARGS_COLUMN, frame->args,
179 STACK_TRACE_URI_COLUMN, uri,
180 -1);
181 g_free (uri);
182 g_free (adr);
183 if (pic)
184 gdk_pixbuf_unref (pic);
188 static void
189 on_stack_trace_frame_changed (StackTrace *st, guint frame, guint thread)
191 GtkTreeIter iter;
192 GtkTreeModel *model;
194 st->current_frame = frame;
196 model = gtk_tree_view_get_model (st->widgets.clist);
198 /* Clear old pointer */
199 if(gtk_tree_model_get_iter_first (model, &iter))
203 /* clear pixmap on the previous active frame */
204 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
205 STACK_TRACE_ACTIVE_COLUMN, NULL, -1);
206 } while (gtk_tree_model_iter_next (model, &iter));
209 /* Set pointer to current frame */
210 if (gtk_tree_model_iter_nth_child (model, &iter, NULL, st->current_frame))
212 GdkPixbuf *pointer_pix = gdk_pixbuf_new_from_file (ANJUTA_PIXMAP_POINTER, NULL);
214 /* set pointer on this frame */
215 gtk_list_store_set (GTK_LIST_STORE(model), &iter,
216 STACK_TRACE_ACTIVE_COLUMN, pointer_pix,
217 -1);
218 gdk_pixbuf_unref (pointer_pix);
222 static void
223 on_stack_frame_set_activate (GtkAction *action, gpointer user_data)
225 StackTrace *st;
226 guint selected_frame;
228 st = (StackTrace*) user_data;
230 selected_frame = get_current_index (st);
232 /* No frame selected */
233 if (selected_frame == -1)
234 return;
236 /* current frame is already active */
237 if (selected_frame == st->current_frame)
238 return;
240 /* issue a command to switch active frame to new location */
241 ianjuta_debugger_set_frame (st->debugger, selected_frame, NULL);
244 static void
245 on_stack_view_src_activate (GtkAction *action, gpointer user_data)
247 GtkTreeModel *model;
248 GtkTreeSelection *selection;
249 GtkTreeIter iter;
250 GtkTreeView *view;
251 gchar *uri;
252 guint line;
254 StackTrace* st = (StackTrace*) user_data;
256 view = st->widgets.clist;
257 selection = gtk_tree_view_get_selection (view);
258 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
259 return;
261 /* get the frame info */
262 gtk_tree_model_get (model, &iter,
263 STACK_TRACE_URI_COLUMN, &uri,
264 STACK_TRACE_LINE_COLUMN, &line,
265 -1);
267 goto_location_in_editor (st->plugin, uri, line);
268 g_free (uri);
271 static void
272 on_stack_trace_row_activated (GtkTreeView *treeview,
273 GtkTreePath *arg1,
274 GtkTreeViewColumn *arg2,
275 StackTrace *st)
277 on_stack_frame_set_activate (NULL, st);
280 static gboolean
281 on_stack_trace_button_press (GtkWidget *widget, GdkEventButton *bevent, gpointer user_data)
283 StackTrace *st = (StackTrace*) user_data;
285 if ((bevent->type == GDK_BUTTON_PRESS) && (bevent->button == 3))
287 /* Right mouse click */
288 g_return_val_if_fail (st->widgets.menu != NULL, FALSE);
289 gtk_menu_popup (GTK_MENU (st->widgets.menu), NULL, NULL, NULL, NULL,
290 bevent->button, bevent->time);
292 else if ((bevent->type == GDK_2BUTTON_PRESS) && (bevent->button == 1))
294 /* Double left mouse click */
295 on_stack_view_src_activate (NULL, user_data);
298 return FALSE;
301 static void
302 stack_trace_update (StackTrace *st)
304 st->current_frame = 0;
305 ianjuta_debugger_list_frame (
306 st->debugger,
307 (IAnjutaDebuggerCallback)on_stack_trace_updated,
309 NULL);
312 /* Actions table
313 *---------------------------------------------------------------------------*/
315 static GtkActionEntry actions_stack_trace[] = {
317 "ActionDmaSetCurrentFrame", /* Action name */
318 NULL, /* Stock icon, if any */
319 N_("Set current frame"), /* Display label */
320 NULL, /* short-cut */
321 NULL, /* Tooltip */
322 G_CALLBACK (on_stack_frame_set_activate) /* action callback */
325 "ActionDmaJumpToFrame",
326 NULL,
327 N_("View Source"),
328 NULL,
329 NULL,
330 G_CALLBACK (on_stack_view_src_activate)
334 static void
335 create_stack_trace_gui(StackTrace *st)
337 GtkTreeModel* model;
338 GtkTreeSelection *selection;
339 GtkTreeViewColumn *column;
340 GtkCellRenderer *renderer;
341 AnjutaUI *ui;
343 g_return_if_fail (st->widgets.scrolledwindow == NULL);
345 /* Create tree view */
346 model = GTK_TREE_MODEL(gtk_list_store_new (STACK_TRACE_N_COLUMNS,
347 GDK_TYPE_PIXBUF,
348 G_TYPE_UINT,
349 G_TYPE_STRING,
350 G_TYPE_UINT,
351 G_TYPE_STRING,
352 G_TYPE_STRING,
353 G_TYPE_STRING,
354 G_TYPE_STRING));
355 st->widgets.clist = GTK_TREE_VIEW (gtk_tree_view_new_with_model (model));
356 g_object_unref (G_OBJECT (model));
358 selection = gtk_tree_view_get_selection (st->widgets.clist);
359 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
361 /* Columns */
362 column = gtk_tree_view_column_new ();
363 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
364 gtk_tree_view_column_set_title (column, _("Active"));
365 renderer = gtk_cell_renderer_pixbuf_new ();
366 gtk_tree_view_column_pack_start (column, renderer, TRUE);
367 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf",
368 STACK_TRACE_ACTIVE_COLUMN);
369 gtk_tree_view_append_column (st->widgets.clist, column);
370 gtk_tree_view_set_expander_column (st->widgets.clist,
371 column);
373 column = gtk_tree_view_column_new ();
374 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
375 gtk_tree_view_column_set_title (column, _("Frame"));
376 renderer = gtk_cell_renderer_text_new ();
377 gtk_tree_view_column_pack_start (column, renderer, TRUE);
378 gtk_tree_view_column_add_attribute (column, renderer, "text",
379 STACK_TRACE_FRAME_COLUMN);
380 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
381 gtk_tree_view_append_column (st->widgets.clist, column);
382 gtk_tree_view_set_expander_column (st->widgets.clist,
383 column);
385 column = gtk_tree_view_column_new ();
386 renderer = gtk_cell_renderer_text_new ();
387 gtk_tree_view_column_pack_start (column, renderer, TRUE);
388 gtk_tree_view_column_add_attribute (column, renderer, "text",
389 STACK_TRACE_FILE_COLUMN);
390 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
391 gtk_tree_view_column_set_title (column, _("File"));
392 gtk_tree_view_append_column (st->widgets.clist, column);
394 column = gtk_tree_view_column_new ();
395 renderer = gtk_cell_renderer_text_new ();
396 gtk_tree_view_column_pack_start (column, renderer, TRUE);
397 gtk_tree_view_column_add_attribute (column, renderer, "text",
398 STACK_TRACE_LINE_COLUMN);
399 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
400 gtk_tree_view_column_set_title (column, _("Line"));
401 gtk_tree_view_append_column (st->widgets.clist, column);
403 column = gtk_tree_view_column_new ();
404 renderer = gtk_cell_renderer_text_new ();
405 gtk_tree_view_column_pack_start (column, renderer, TRUE);
406 gtk_tree_view_column_add_attribute (column, renderer, "text",
407 STACK_TRACE_FUNC_COLUMN);
408 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
409 gtk_tree_view_column_set_title (column, _("Function"));
410 gtk_tree_view_append_column (st->widgets.clist, column);
412 column = gtk_tree_view_column_new ();
413 renderer = gtk_cell_renderer_text_new ();
414 gtk_tree_view_column_pack_start (column, renderer, TRUE);
415 gtk_tree_view_column_add_attribute (column, renderer, "text",
416 STACK_TRACE_ADDR_COLUMN);
417 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
418 gtk_tree_view_column_set_title (column, _("Address"));
419 gtk_tree_view_append_column (st->widgets.clist, column);
421 column = gtk_tree_view_column_new ();
422 renderer = gtk_cell_renderer_text_new ();
423 gtk_tree_view_column_pack_start (column, renderer, TRUE);
424 gtk_tree_view_column_add_attribute (column, renderer, "text",
425 STACK_TRACE_ARGS_COLUMN);
426 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
427 gtk_tree_view_column_set_title (column, _("Arguments"));
428 gtk_tree_view_append_column (st->widgets.clist, column);
430 /* Create popup menu */
431 ui = anjuta_shell_get_ui (st->plugin->shell, NULL);
432 st->widgets.menu = GTK_MENU (gtk_ui_manager_get_widget (GTK_UI_MANAGER (ui), "/PopupStack"));
434 /* Connect signal */
435 g_signal_connect (st->widgets.clist, "button-press-event", G_CALLBACK (on_stack_trace_button_press), st);
436 g_signal_connect (st->widgets.clist, "row-activated", G_CALLBACK (on_stack_trace_row_activated), st);
438 /* Add stack window */
439 st->widgets.scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
440 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (st->widgets.scrolledwindow),
441 GTK_POLICY_AUTOMATIC,
442 GTK_POLICY_AUTOMATIC);
443 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (st->widgets.scrolledwindow),
444 GTK_SHADOW_IN);
445 gtk_container_add (GTK_CONTAINER (st->widgets.scrolledwindow),
446 GTK_WIDGET (st->widgets.clist));
447 gtk_widget_show_all (st->widgets.scrolledwindow);
449 anjuta_shell_add_widget (st->plugin->shell,
450 st->widgets.scrolledwindow,
451 "AnjutaDebuggerStack", _("Stack"),
452 "gdb-stack-icon", ANJUTA_SHELL_PLACEMENT_BOTTOM,
453 NULL);
457 static void
458 destroy_stack_trace_gui (StackTrace *st)
460 if (st->widgets.scrolledwindow != NULL)
462 gtk_widget_destroy (st->widgets.scrolledwindow);
463 st->widgets.scrolledwindow = NULL;
467 static void
468 on_program_stopped (StackTrace *st)
470 stack_trace_update (st);
473 static void
474 on_debugger_started (StackTrace *st)
476 create_stack_trace_gui (st);
479 static void
480 on_debugger_stopped (StackTrace *st)
482 stack_trace_clear (st);
483 destroy_stack_trace_gui (st);
486 /* Public functions
487 *---------------------------------------------------------------------------*/
489 /* Constructor & Destructor
490 *---------------------------------------------------------------------------*/
492 StackTrace *
493 stack_trace_new (IAnjutaDebugger *debugger, AnjutaPlugin *plugin)
495 StackTrace *st;
496 AnjutaUI *ui;
498 st = g_new0 (StackTrace, 1);
499 if (st == NULL) return NULL;
501 st->plugin = plugin;
502 st->debugger = debugger;
503 if (debugger != NULL) g_object_ref (debugger);
505 /* Register actions */
506 ui = anjuta_shell_get_ui (st->plugin->shell, NULL);
507 st->action_group =
508 anjuta_ui_add_action_group_entries (ui, "ActionGroupStack",
509 _("Stack frame operations"),
510 actions_stack_trace,
511 G_N_ELEMENTS (actions_stack_trace),
512 GETTEXT_PACKAGE, TRUE, st);
514 g_signal_connect_swapped (st->debugger, "debugger-started", G_CALLBACK (on_debugger_started), st);
515 g_signal_connect_swapped (st->debugger, "debugger-stopped", G_CALLBACK (on_debugger_stopped), st);
516 g_signal_connect_swapped (st->debugger, "program-stopped", G_CALLBACK (on_program_stopped), st);
517 g_signal_connect_swapped (st->debugger, "frame-changed", G_CALLBACK (on_stack_trace_frame_changed), st);
519 return st;
522 void
523 stack_trace_free (StackTrace * st)
525 AnjutaUI *ui;
527 g_return_if_fail (st != NULL);
529 /* Disconnect from debugger */
530 if (st->debugger != NULL)
532 g_signal_handlers_disconnect_by_func (st->debugger, G_CALLBACK (on_debugger_started), st);
533 g_signal_handlers_disconnect_by_func (st->debugger, G_CALLBACK (on_debugger_stopped), st);
534 g_signal_handlers_disconnect_by_func (st->debugger, G_CALLBACK (on_program_stopped), st);
535 g_signal_handlers_disconnect_by_func (st->debugger, G_CALLBACK (on_stack_trace_frame_changed), st);
536 g_object_unref (st->debugger);
539 /* Remove menu actions */
540 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN (st->plugin)->shell, NULL);
541 anjuta_ui_remove_action_group (ui, st->action_group);
543 /* Destroy menu */
544 destroy_stack_trace_gui (st);
546 g_free (st);