* plugins/debug-manager/disassemble.c,
[anjuta-git-plugin.git] / plugins / debug-manager / threads.c
bloba9671bd1d60487fd2677fb63cdf40d195d8993b2
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 threads.c
4 Copyright (C) 2007 Sébastien Granjoux
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 "threads.h"
26 #include "queue.h"
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <gnome.h>
33 #include <libgnomevfs/gnome-vfs.h>
35 /*#define DEBUG*/
36 #include <libanjuta/resources.h>
37 #include <libanjuta/anjuta-debug.h>
38 #include <libanjuta/interfaces/ianjuta-editor.h>
39 #include <libanjuta/interfaces/ianjuta-document-manager.h>
41 #include "utilities.h"
42 #include "info.h"
44 #define ANJUTA_PIXMAP_POINTER PACKAGE_PIXMAPS_DIR"/pointer.png"
46 struct _DmaThreads
48 DebugManagerPlugin *plugin;
49 DmaDebuggerQueue *debugger;
51 /* GUI */
52 GtkWidget *scrolledwindow;
53 GtkTreeView *list;
54 GtkMenu *menu;
55 GtkActionGroup *action_group;
57 gint current_thread;
60 struct _DmaThreadPacket {
61 GtkTreeModel *model;
62 GtkTreeRowReference* reference;
63 DmaThreads* self;
66 enum {
67 THREAD_ACTIVE_COLUMN,
68 THREAD_ID_COLUMN,
69 THREAD_FILE_COLUMN,
70 THREAD_LINE_COLUMN,
71 THREAD_FUNC_COLUMN,
72 THREAD_ADDR_COLUMN,
73 THREAD_URI_COLUMN,
74 THREAD_N_COLUMNS
78 /* Helpers functions
79 *---------------------------------------------------------------------------*/
81 static gboolean
82 get_current_iter (GtkTreeView *view, GtkTreeIter* iter)
84 GtkTreeSelection *selection;
86 selection = gtk_tree_view_get_selection (view);
87 return gtk_tree_selection_get_selected (selection, NULL, iter);
91 * returns the current stack thread or -1 on error
93 static gint
94 get_current_index (DmaThreads *self)
96 GtkTreeIter iter;
98 if (get_current_iter (self->list, &iter))
100 GtkTreeModel *model;
101 gint thread_no;
103 model = gtk_tree_view_get_model (self->list);
104 gtk_tree_model_get (model, &iter, THREAD_ID_COLUMN, &thread_no, -1);
106 return thread_no;
108 else
110 return -1;
114 /* Private functions
115 *---------------------------------------------------------------------------*/
117 static void
118 dma_threads_clear (DmaThreads *self)
120 GtkTreeModel* model;
122 model = gtk_tree_view_get_model (self->list);
123 gtk_list_store_clear (GTK_LIST_STORE (model));
126 /* Callback functions
127 *---------------------------------------------------------------------------*/
129 static void
130 on_threads_set_activate (GtkAction *action, gpointer user_data)
132 DmaThreads *self = (DmaThreads *)user_data;
133 gint selected_thread;
135 selected_thread = get_current_index (self);
137 /* No thread selected */
138 if (selected_thread == -1)
139 return;
141 /* current thread is already active */
142 if (selected_thread == self->current_thread)
143 return;
145 /* issue a command to switch active frame to new location */
146 dma_queue_set_thread (self->debugger, selected_thread);
149 static void
150 on_threads_source_activate (GtkAction *action, gpointer user_data)
152 GtkTreeModel *model;
153 GtkTreeSelection *selection;
154 GtkTreeIter iter;
155 GtkTreeView *view;
156 gchar *uri;
157 guint line;
158 gchar *adr;
159 gulong address;
160 DmaThreads* self = (DmaThreads*) user_data;
162 view = self->list;
163 selection = gtk_tree_view_get_selection (view);
164 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
165 return;
167 /* get the frame info */
168 gtk_tree_model_get (model, &iter,
169 THREAD_URI_COLUMN, &uri,
170 THREAD_LINE_COLUMN, &line,
171 THREAD_ADDR_COLUMN, &adr,
172 -1);
174 address = adr != NULL ? strtoul (adr, NULL, 0) : 0;
175 g_signal_emit_by_name (self->plugin, "location-changed", address, uri, line);
176 g_free (uri);
177 g_free (adr);
180 static void
181 on_threads_row_activated (GtkTreeView *treeview,
182 GtkTreePath *arg1,
183 GtkTreeViewColumn *arg2,
184 DmaThreads* self)
186 on_threads_set_activate (NULL, self);
189 static gboolean
190 on_threads_button_press (GtkWidget *widget, GdkEventButton *bevent, gpointer user_data)
192 DmaThreads *self = (DmaThreads*) user_data;
194 if ((bevent->type == GDK_BUTTON_PRESS) && (bevent->button == 3))
196 /* Right mouse click */
197 g_return_val_if_fail (self->menu != NULL, FALSE);
198 gtk_menu_popup (GTK_MENU (self->menu), NULL, NULL, NULL, NULL,
199 bevent->button, bevent->time);
201 else if ((bevent->type == GDK_2BUTTON_PRESS) && (bevent->button == 1))
203 /* Double left mouse click */
204 on_threads_source_activate (NULL, user_data);
207 return FALSE;
210 static void
211 on_info_thread (const IAnjutaDebuggerFrame* frame, gpointer user_data)
213 GtkTreeRowReference* reference = (GtkTreeRowReference*)user_data;
214 gchar* adr;
215 gchar* uri;
216 gchar* file;
218 if (frame == NULL) return;
220 adr = g_strdup_printf ("0x%lx", frame->address);
222 if (frame->file)
224 uri = gnome_vfs_get_uri_from_local_path(frame->file);
225 file = strrchr(uri, '/') + 1;
227 else
229 uri = NULL;
230 file = frame->library;
233 if (gtk_tree_row_reference_valid (reference))
235 GtkTreeIter iter;
236 GtkTreeModel *model;
237 GtkTreePath *path;
238 gboolean ok;
240 model = gtk_tree_row_reference_get_model(reference);
241 path = gtk_tree_row_reference_get_path (reference);
242 ok = gtk_tree_model_get_iter (model, &iter, path);
243 gtk_tree_path_free (path);
245 if (ok)
247 gtk_list_store_set(GTK_LIST_STORE (model), &iter,
248 THREAD_FILE_COLUMN, file,
249 THREAD_LINE_COLUMN, frame->line,
250 THREAD_FUNC_COLUMN, frame->function,
251 THREAD_ADDR_COLUMN, adr,
252 THREAD_URI_COLUMN, uri,
253 -1);
255 gtk_tree_row_reference_free(reference);
258 g_free (uri);
259 g_free (adr);
262 static void
263 on_list_thread (const GList *threads, gpointer user_data)
265 DmaThreads *self = (DmaThreads *)user_data;
266 const GList *node;
267 GtkListStore *model;
269 dma_threads_clear (self);
271 model = GTK_LIST_STORE (gtk_tree_view_get_model (self->list));
273 for (node = threads; node != NULL; node = node->next)
275 GdkPixbuf *pic;
276 GtkTreeIter iter;
277 IAnjutaDebuggerFrame *frame;
278 gchar *adr;
279 gchar *uri;
280 gchar *file;
282 frame = (IAnjutaDebuggerFrame *)node->data;
284 gtk_list_store_append (model, &iter);
286 /* if we are on the current frame set iterator and pixmap correctly */
287 if (frame->thread == self->current_thread)
288 pic = gdk_pixbuf_new_from_file (ANJUTA_PIXMAP_POINTER, NULL);
289 else
290 pic = NULL;
292 if ((dma_debugger_queue_is_supported (self->debugger, HAS_MEMORY) && (frame->address == 0))
293 || (frame->function == NULL))
295 /* Missing frame address, request more information */
296 GtkTreeRowReference* reference;
297 GtkTreePath *path;
299 path = gtk_tree_model_get_path(GTK_TREE_MODEL (model), &iter);
300 reference = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), path);
301 gtk_tree_path_free (path);
303 dma_queue_info_thread (
304 self->debugger, frame->thread,
305 (IAnjutaDebuggerCallback)on_info_thread,
306 reference);
308 gtk_list_store_set(model, &iter,
309 THREAD_ACTIVE_COLUMN, pic,
310 THREAD_ID_COLUMN, frame->thread,
311 -1);
313 else
315 adr = g_strdup_printf ("0x%lx", frame->address);
316 if (frame->file)
318 uri = gnome_vfs_get_uri_from_local_path(frame->file);
319 file = strrchr(uri, '/') + 1;
321 else
323 uri = NULL;
324 file = frame->library;
327 gtk_list_store_set(model, &iter,
328 THREAD_ACTIVE_COLUMN, pic,
329 THREAD_ID_COLUMN, frame->thread,
330 THREAD_FILE_COLUMN, file,
331 THREAD_LINE_COLUMN, frame->line,
332 THREAD_FUNC_COLUMN, frame->function,
333 THREAD_ADDR_COLUMN, adr,
334 THREAD_URI_COLUMN, uri,
335 -1);
337 g_free (uri);
338 g_free (adr);
341 if (pic)
342 gdk_pixbuf_unref (pic);
346 static void
347 dma_threads_update (DmaThreads *self)
349 dma_queue_list_thread (
350 self->debugger,
351 (IAnjutaDebuggerCallback)on_list_thread,
352 self);
355 /* Actions table
356 *---------------------------------------------------------------------------*/
358 static GtkActionEntry actions_threads[] = {
360 "ActionDmaSetCurrentThread", /* Action name */
361 NULL, /* Stock icon, if any */
362 N_("Set current thread"), /* Display label */
363 NULL, /* short-cut */
364 NULL, /* Tooltip */
365 G_CALLBACK (on_threads_set_activate) /* action callback */
368 "ActionDmaJumpToThread",
369 NULL,
370 N_("View Source"),
371 NULL,
372 NULL,
373 G_CALLBACK (on_threads_source_activate)
377 static void
378 dma_threads_create_gui(DmaThreads *self)
380 GtkTreeModel* model;
381 GtkTreeSelection *selection;
382 GtkTreeViewColumn *column;
383 GtkCellRenderer *renderer;
384 AnjutaUI *ui;
386 g_return_if_fail (self->scrolledwindow == NULL);
388 /* Create tree view */
389 model = GTK_TREE_MODEL(gtk_list_store_new (THREAD_N_COLUMNS,
390 GDK_TYPE_PIXBUF,
391 G_TYPE_UINT,
392 G_TYPE_STRING,
393 G_TYPE_UINT,
394 G_TYPE_STRING,
395 G_TYPE_STRING,
396 G_TYPE_STRING));
397 self->list = GTK_TREE_VIEW (gtk_tree_view_new_with_model (model));
398 g_object_unref (G_OBJECT (model));
400 selection = gtk_tree_view_get_selection (self->list);
401 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
403 /* Columns */
404 column = gtk_tree_view_column_new ();
405 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
406 gtk_tree_view_column_set_title (column, _("Active"));
407 renderer = gtk_cell_renderer_pixbuf_new ();
408 gtk_tree_view_column_pack_start (column, renderer, TRUE);
409 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf",
410 THREAD_ACTIVE_COLUMN);
411 gtk_tree_view_append_column (self->list, column);
412 gtk_tree_view_set_expander_column (self->list, column);
414 column = gtk_tree_view_column_new ();
415 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
416 gtk_tree_view_column_set_title (column, _("Id"));
417 renderer = gtk_cell_renderer_text_new ();
418 gtk_tree_view_column_pack_start (column, renderer, TRUE);
419 gtk_tree_view_column_add_attribute (column, renderer, "text",
420 THREAD_ID_COLUMN);
421 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
422 gtk_tree_view_append_column (self->list, column);
423 gtk_tree_view_set_expander_column (self->list, column);
425 column = gtk_tree_view_column_new ();
426 renderer = gtk_cell_renderer_text_new ();
427 gtk_tree_view_column_pack_start (column, renderer, TRUE);
428 gtk_tree_view_column_add_attribute (column, renderer, "text",
429 THREAD_FILE_COLUMN);
430 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
431 gtk_tree_view_column_set_title (column, _("File"));
432 gtk_tree_view_append_column (self->list, column);
434 column = gtk_tree_view_column_new ();
435 renderer = gtk_cell_renderer_text_new ();
436 gtk_tree_view_column_pack_start (column, renderer, TRUE);
437 gtk_tree_view_column_add_attribute (column, renderer, "text",
438 THREAD_LINE_COLUMN);
439 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
440 gtk_tree_view_column_set_title (column, _("Line"));
441 gtk_tree_view_append_column (self->list, column);
443 column = gtk_tree_view_column_new ();
444 renderer = gtk_cell_renderer_text_new ();
445 gtk_tree_view_column_pack_start (column, renderer, TRUE);
446 gtk_tree_view_column_add_attribute (column, renderer, "text",
447 THREAD_FUNC_COLUMN);
448 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
449 gtk_tree_view_column_set_title (column, _("Function"));
450 gtk_tree_view_append_column (self->list, column);
452 if (dma_debugger_queue_is_supported (self->debugger, HAS_MEMORY))
454 /* Display address only if debugger has such concept */
455 column = gtk_tree_view_column_new ();
456 renderer = gtk_cell_renderer_text_new ();
457 gtk_tree_view_column_pack_start (column, renderer, TRUE);
458 gtk_tree_view_column_add_attribute (column, renderer, "text",
459 THREAD_ADDR_COLUMN);
460 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
461 gtk_tree_view_column_set_title (column, _("Address"));
462 gtk_tree_view_append_column (self->list, column);
465 /* Create popup menu */
466 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN(self->plugin)->shell, NULL);
467 self->menu = GTK_MENU (gtk_ui_manager_get_widget (GTK_UI_MANAGER (ui), "/PopupThread"));
469 /* Connect signal */
470 g_signal_connect (self->list, "button-press-event", G_CALLBACK (on_threads_button_press), self);
471 g_signal_connect (self->list, "row-activated", G_CALLBACK (on_threads_row_activated), self);
473 /* Add stack window */
474 self->scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
475 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (self->scrolledwindow),
476 GTK_POLICY_AUTOMATIC,
477 GTK_POLICY_AUTOMATIC);
478 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (self->scrolledwindow),
479 GTK_SHADOW_IN);
480 gtk_container_add (GTK_CONTAINER (self->scrolledwindow),
481 GTK_WIDGET (self->list));
482 gtk_widget_show_all (self->scrolledwindow);
484 anjuta_shell_add_widget (ANJUTA_PLUGIN(self->plugin)->shell,
485 self->scrolledwindow,
486 "AnjutaDebuggerThread", _("Thread"),
487 "gdb-stack-icon", ANJUTA_SHELL_PLACEMENT_BOTTOM,
488 NULL);
492 static void
493 dma_destroy_threads_gui (DmaThreads *self)
495 if (self->scrolledwindow != NULL)
497 gtk_widget_destroy (self->scrolledwindow);
498 self->scrolledwindow = NULL;
502 static void
503 on_program_moved (DmaThreads *self, guint pid, gint thread)
505 self->current_thread = thread;
506 dma_threads_update (self);
509 static gboolean
510 on_mark_selected_thread (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
512 DmaThreads* self = (DmaThreads *)user_data;
513 GdkPixbuf *pic;
514 gint thread;
516 gtk_tree_model_get (model, iter, THREAD_ACTIVE_COLUMN, &pic, THREAD_ID_COLUMN, &thread, -1);
518 if (pic != NULL)
520 /* Remove previously selected thread marker */
521 gdk_pixbuf_unref (pic);
522 pic = NULL;
525 if (self->current_thread == thread)
527 /* Create marker if needed */
528 pic = gdk_pixbuf_new_from_file (ANJUTA_PIXMAP_POINTER, NULL);
531 gtk_list_store_set (GTK_LIST_STORE (model), iter,
532 THREAD_ACTIVE_COLUMN, pic, -1);
534 if (pic != NULL)
536 gdk_pixbuf_unref (pic);
539 return FALSE;
542 static void
543 on_frame_changed (DmaThreads *self, guint frame, gint thread)
545 if (thread != self->current_thread)
547 GtkTreeModel *model;
549 self->current_thread = thread;
550 model = gtk_tree_view_get_model (self->list);
552 gtk_tree_model_foreach (model, on_mark_selected_thread, self);
556 static void
557 on_program_exited (DmaThreads *self)
559 g_signal_handlers_disconnect_by_func (self->plugin, G_CALLBACK (on_program_exited), self);
560 g_signal_handlers_disconnect_by_func (self->plugin, G_CALLBACK (on_program_moved), self);
561 g_signal_handlers_disconnect_by_func (self->plugin, G_CALLBACK (on_frame_changed), self);
563 dma_threads_clear (self);
564 dma_destroy_threads_gui (self);
567 static void
568 on_program_started (DmaThreads *self)
570 dma_threads_create_gui (self);
572 g_signal_connect_swapped (self->plugin, "program-exited", G_CALLBACK (on_program_exited), self);
573 g_signal_connect_swapped (self->plugin, "program-moved", G_CALLBACK (on_program_moved), self);
574 g_signal_connect_swapped (self->plugin, "frame-changed", G_CALLBACK (on_frame_changed), self);
577 /* Constructor & Destructor
578 *---------------------------------------------------------------------------*/
580 DmaThreads*
581 dma_threads_new (DebugManagerPlugin *plugin)
583 DmaThreads* self;
584 AnjutaUI *ui;
586 self = g_new0 (DmaThreads, 1);
587 g_return_val_if_fail (self != NULL, NULL);
589 self->plugin = plugin;
590 self->debugger = dma_debug_manager_get_queue (plugin);
592 /* Register actions */
593 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN(self->plugin)->shell, NULL);
594 self->action_group =
595 anjuta_ui_add_action_group_entries (ui, "ActionGroupThread",
596 _("Thread operations"),
597 actions_threads,
598 G_N_ELEMENTS (actions_threads),
599 GETTEXT_PACKAGE, TRUE, self);
601 g_signal_connect_swapped (self->plugin, "program-started", G_CALLBACK (on_program_started), self);
603 return self;
606 void
607 dma_threads_free (DmaThreads *self)
609 AnjutaUI *ui;
611 g_return_if_fail (self != NULL);
613 /* Disconnect from debugger */
614 g_signal_handlers_disconnect_matched (self->plugin, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
616 /* Remove menu actions */
617 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN (self->plugin)->shell, NULL);
618 anjuta_ui_remove_action_group (ui, self->action_group);
620 /* Destroy menu */
621 dma_destroy_threads_gui (self);
623 g_free (self);