Updated Spanish translation
[anjuta-git-plugin.git] / plugins / debug-manager / threads.c
blob83e0dda6bda4caece1b1862643f14ba7e3c5cf53
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
24 #include "threads.h"
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <gnome.h>
32 /*#define DEBUG*/
33 #include <libanjuta/resources.h>
34 #include <libanjuta/anjuta-debug.h>
35 #include <libanjuta/interfaces/ianjuta-editor.h>
36 #include <libanjuta/interfaces/ianjuta-document-manager.h>
38 #include "utilities.h"
39 #include "info.h"
41 #define ANJUTA_PIXMAP_POINTER PACKAGE_PIXMAPS_DIR"/pointer.png"
43 struct _DmaThreads
45 DebugManagerPlugin *plugin;
46 IAnjutaDebugger *debugger;
48 /* GUI */
49 GtkWidget *scrolledwindow;
50 GtkTreeView *list;
51 GtkMenu *menu;
52 GtkActionGroup *action_group;
54 gint current_thread;
57 struct _DmaThreadPacket {
58 GtkTreeModel *model;
59 GtkTreeRowReference* reference;
60 DmaThreads* self;
63 enum {
64 THREAD_ACTIVE_COLUMN,
65 THREAD_ID_COLUMN,
66 THREAD_FILE_COLUMN,
67 THREAD_LINE_COLUMN,
68 THREAD_FUNC_COLUMN,
69 THREAD_ADDR_COLUMN,
70 THREAD_URI_COLUMN,
71 THREAD_N_COLUMNS
75 /* Helpers functions
76 *---------------------------------------------------------------------------*/
78 static gboolean
79 get_current_iter (GtkTreeView *view, GtkTreeIter* iter)
81 GtkTreeSelection *selection;
83 selection = gtk_tree_view_get_selection (view);
84 return gtk_tree_selection_get_selected (selection, NULL, iter);
88 * returns the current stack thread or -1 on error
90 static gint
91 get_current_index (DmaThreads *self)
93 GtkTreeIter iter;
95 if (get_current_iter (self->list, &iter))
97 GtkTreeModel *model;
98 gint thread_no;
100 model = gtk_tree_view_get_model (self->list);
101 gtk_tree_model_get (model, &iter, THREAD_ID_COLUMN, &thread_no, -1);
103 return thread_no;
105 else
107 return -1;
111 /* Private functions
112 *---------------------------------------------------------------------------*/
114 static void
115 dma_threads_clear (DmaThreads *self)
117 GtkTreeModel* model;
119 model = gtk_tree_view_get_model (self->list);
120 gtk_list_store_clear (GTK_LIST_STORE (model));
123 /* Callback functions
124 *---------------------------------------------------------------------------*/
126 static void
127 on_threads_set_activate (GtkAction *action, gpointer user_data)
129 DmaThreads *self = (DmaThreads *)user_data;
130 guint selected_thread;
132 selected_thread = get_current_index (self);
134 /* No thread selected */
135 if (selected_thread == -1)
136 return;
138 /* current thread is already active */
139 if (selected_thread == self->current_thread)
140 return;
142 /* issue a command to switch active frame to new location */
143 ianjuta_debugger_set_thread (self->debugger, selected_thread, NULL);
146 static void
147 on_threads_source_activate (GtkAction *action, gpointer user_data)
149 GtkTreeModel *model;
150 GtkTreeSelection *selection;
151 GtkTreeIter iter;
152 GtkTreeView *view;
153 gchar *uri;
154 guint line;
155 gchar *adr;
156 guint address;
157 DmaThreads* self = (DmaThreads*) user_data;
159 view = self->list;
160 selection = gtk_tree_view_get_selection (view);
161 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
162 return;
164 /* get the frame info */
165 gtk_tree_model_get (model, &iter,
166 THREAD_URI_COLUMN, &uri,
167 THREAD_LINE_COLUMN, &line,
168 THREAD_ADDR_COLUMN, &adr,
169 -1);
171 address = adr != NULL ? strtoul (adr, NULL, 0) : 0;
172 dma_debug_manager_goto_code (self->plugin, uri, line, address);
173 g_free (uri);
174 g_free (adr);
177 static void
178 on_threads_row_activated (GtkTreeView *treeview,
179 GtkTreePath *arg1,
180 GtkTreeViewColumn *arg2,
181 DmaThreads* self)
183 on_threads_set_activate (NULL, self);
186 static gboolean
187 on_threads_button_press (GtkWidget *widget, GdkEventButton *bevent, gpointer user_data)
189 DmaThreads *self = (DmaThreads*) user_data;
191 if ((bevent->type == GDK_BUTTON_PRESS) && (bevent->button == 3))
193 /* Right mouse click */
194 g_return_val_if_fail (self->menu != NULL, FALSE);
195 gtk_menu_popup (GTK_MENU (self->menu), NULL, NULL, NULL, NULL,
196 bevent->button, bevent->time);
198 else if ((bevent->type == GDK_2BUTTON_PRESS) && (bevent->button == 1))
200 /* Double left mouse click */
201 on_threads_source_activate (NULL, user_data);
204 return FALSE;
207 static void
208 on_info_thread (const IAnjutaDebuggerFrame* frame, gpointer user_data)
210 GtkTreeRowReference* reference = (GtkTreeRowReference*)user_data;
211 gchar* adr;
212 gchar* uri;
213 gchar* file;
215 if (frame == NULL) return;
217 adr = g_strdup_printf ("0x%x", frame->address);
219 if (frame->file)
221 uri = g_strconcat ("file://", frame->file, NULL);
222 file = strrchr(uri, '/') + 1;
224 else
226 uri = NULL;
227 file = frame->library;
230 if (gtk_tree_row_reference_valid (reference))
232 GtkTreeIter iter;
233 GtkTreeModel *model;
234 GtkTreePath *path;
235 gboolean ok;
237 model = gtk_tree_row_reference_get_model(reference);
238 path = gtk_tree_row_reference_get_path (reference);
239 ok = gtk_tree_model_get_iter (model, &iter, path);
240 gtk_tree_path_free (path);
242 if (ok)
244 gtk_list_store_set(GTK_LIST_STORE (model), &iter,
245 THREAD_FILE_COLUMN, file,
246 THREAD_LINE_COLUMN, frame->line,
247 THREAD_FUNC_COLUMN, frame->function,
248 THREAD_ADDR_COLUMN, adr,
249 THREAD_URI_COLUMN, uri,
250 -1);
252 gtk_tree_row_reference_free(reference);
255 g_free (uri);
256 g_free (adr);
259 static void
260 on_list_thread (const GList *threads, gpointer user_data)
262 DmaThreads *self = (DmaThreads *)user_data;
263 const GList *node;
264 GtkListStore *model;
266 dma_threads_clear (self);
268 model = GTK_LIST_STORE (gtk_tree_view_get_model (self->list));
270 for (node = threads; node != NULL; node = node->next)
272 GdkPixbuf *pic;
273 GtkTreeIter iter;
274 IAnjutaDebuggerFrame *frame;
275 gchar *adr;
276 gchar *uri;
277 gchar *file;
279 frame = (IAnjutaDebuggerFrame *)node->data;
281 gtk_list_store_append (model, &iter);
283 /* if we are on the current frame set iterator and pixmap correctly */
284 if (frame->thread == self->current_thread)
285 pic = gdk_pixbuf_new_from_file (ANJUTA_PIXMAP_POINTER, NULL);
286 else
287 pic = NULL;
289 if (frame->address == 0)
291 /* Missing frame address, request more information */
292 GtkTreeRowReference* reference;
293 GtkTreePath *path;
295 path = gtk_tree_model_get_path(GTK_TREE_MODEL (model), &iter);
296 reference = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), path);
297 gtk_tree_path_free (path);
299 ianjuta_debugger_info_thread (
300 self->debugger, frame->thread,
301 (IAnjutaDebuggerCallback)on_info_thread,
302 reference,
303 NULL);
305 gtk_list_store_set(model, &iter,
306 THREAD_ACTIVE_COLUMN, pic,
307 THREAD_ID_COLUMN, frame->thread,
308 -1);
310 else
312 adr = g_strdup_printf ("0x%x", frame->address);
313 if (frame->file)
315 uri = g_strconcat ("file://", frame->file, NULL);
316 file = strrchr(uri, '/') + 1;
318 else
320 uri = NULL;
321 file = frame->library;
324 gtk_list_store_set(model, &iter,
325 THREAD_ACTIVE_COLUMN, pic,
326 THREAD_ID_COLUMN, frame->thread,
327 THREAD_FILE_COLUMN, file,
328 THREAD_LINE_COLUMN, frame->line,
329 THREAD_FUNC_COLUMN, frame->function,
330 THREAD_ADDR_COLUMN, adr,
331 THREAD_URI_COLUMN, uri,
332 -1);
334 g_free (uri);
335 g_free (adr);
338 if (pic)
339 gdk_pixbuf_unref (pic);
343 static void
344 dma_threads_update (DmaThreads *self)
346 ianjuta_debugger_list_thread (
347 self->debugger,
348 (IAnjutaDebuggerCallback)on_list_thread,
349 self,
350 NULL);
353 /* Actions table
354 *---------------------------------------------------------------------------*/
356 static GtkActionEntry actions_threads[] = {
358 "ActionDmaSetCurrentThread", /* Action name */
359 NULL, /* Stock icon, if any */
360 N_("Set current thread"), /* Display label */
361 NULL, /* short-cut */
362 NULL, /* Tooltip */
363 G_CALLBACK (on_threads_set_activate) /* action callback */
366 "ActionDmaJumpToThread",
367 NULL,
368 N_("View Source"),
369 NULL,
370 NULL,
371 G_CALLBACK (on_threads_source_activate)
375 static void
376 dma_threads_create_gui(DmaThreads *self)
378 GtkTreeModel* model;
379 GtkTreeSelection *selection;
380 GtkTreeViewColumn *column;
381 GtkCellRenderer *renderer;
382 AnjutaUI *ui;
384 g_return_if_fail (self->scrolledwindow == NULL);
386 /* Create tree view */
387 model = GTK_TREE_MODEL(gtk_list_store_new (THREAD_N_COLUMNS,
388 GDK_TYPE_PIXBUF,
389 G_TYPE_UINT,
390 G_TYPE_STRING,
391 G_TYPE_UINT,
392 G_TYPE_STRING,
393 G_TYPE_STRING,
394 G_TYPE_STRING));
395 self->list = GTK_TREE_VIEW (gtk_tree_view_new_with_model (model));
396 g_object_unref (G_OBJECT (model));
398 selection = gtk_tree_view_get_selection (self->list);
399 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
401 /* Columns */
402 column = gtk_tree_view_column_new ();
403 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
404 gtk_tree_view_column_set_title (column, _("Active"));
405 renderer = gtk_cell_renderer_pixbuf_new ();
406 gtk_tree_view_column_pack_start (column, renderer, TRUE);
407 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf",
408 THREAD_ACTIVE_COLUMN);
409 gtk_tree_view_append_column (self->list, column);
410 gtk_tree_view_set_expander_column (self->list, column);
412 column = gtk_tree_view_column_new ();
413 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
414 gtk_tree_view_column_set_title (column, _("Id"));
415 renderer = gtk_cell_renderer_text_new ();
416 gtk_tree_view_column_pack_start (column, renderer, TRUE);
417 gtk_tree_view_column_add_attribute (column, renderer, "text",
418 THREAD_ID_COLUMN);
419 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
420 gtk_tree_view_append_column (self->list, column);
421 gtk_tree_view_set_expander_column (self->list, column);
423 column = gtk_tree_view_column_new ();
424 renderer = gtk_cell_renderer_text_new ();
425 gtk_tree_view_column_pack_start (column, renderer, TRUE);
426 gtk_tree_view_column_add_attribute (column, renderer, "text",
427 THREAD_FILE_COLUMN);
428 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
429 gtk_tree_view_column_set_title (column, _("File"));
430 gtk_tree_view_append_column (self->list, column);
432 column = gtk_tree_view_column_new ();
433 renderer = gtk_cell_renderer_text_new ();
434 gtk_tree_view_column_pack_start (column, renderer, TRUE);
435 gtk_tree_view_column_add_attribute (column, renderer, "text",
436 THREAD_LINE_COLUMN);
437 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
438 gtk_tree_view_column_set_title (column, _("Line"));
439 gtk_tree_view_append_column (self->list, column);
441 column = gtk_tree_view_column_new ();
442 renderer = gtk_cell_renderer_text_new ();
443 gtk_tree_view_column_pack_start (column, renderer, TRUE);
444 gtk_tree_view_column_add_attribute (column, renderer, "text",
445 THREAD_FUNC_COLUMN);
446 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
447 gtk_tree_view_column_set_title (column, _("Function"));
448 gtk_tree_view_append_column (self->list, column);
450 column = gtk_tree_view_column_new ();
451 renderer = gtk_cell_renderer_text_new ();
452 gtk_tree_view_column_pack_start (column, renderer, TRUE);
453 gtk_tree_view_column_add_attribute (column, renderer, "text",
454 THREAD_ADDR_COLUMN);
455 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
456 gtk_tree_view_column_set_title (column, _("Address"));
457 gtk_tree_view_append_column (self->list, column);
459 /* Create popup menu */
460 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN(self->plugin)->shell, NULL);
461 self->menu = GTK_MENU (gtk_ui_manager_get_widget (GTK_UI_MANAGER (ui), "/PopupThread"));
463 /* Connect signal */
464 g_signal_connect (self->list, "button-press-event", G_CALLBACK (on_threads_button_press), self);
465 g_signal_connect (self->list, "row-activated", G_CALLBACK (on_threads_row_activated), self);
467 /* Add stack window */
468 self->scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
469 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (self->scrolledwindow),
470 GTK_POLICY_AUTOMATIC,
471 GTK_POLICY_AUTOMATIC);
472 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (self->scrolledwindow),
473 GTK_SHADOW_IN);
474 gtk_container_add (GTK_CONTAINER (self->scrolledwindow),
475 GTK_WIDGET (self->list));
476 gtk_widget_show_all (self->scrolledwindow);
478 anjuta_shell_add_widget (ANJUTA_PLUGIN(self->plugin)->shell,
479 self->scrolledwindow,
480 "AnjutaDebuggerThread", _("Thread"),
481 "gdb-stack-icon", ANJUTA_SHELL_PLACEMENT_BOTTOM,
482 NULL);
486 static void
487 dma_destroy_threads_gui (DmaThreads *self)
489 if (self->scrolledwindow != NULL)
491 gtk_widget_destroy (self->scrolledwindow);
492 self->scrolledwindow = NULL;
496 static void
497 on_program_stopped (DmaThreads *self, guint thread)
499 self->current_thread = thread;
500 dma_threads_update (self);
503 static void
504 on_debugger_started (DmaThreads *self)
506 dma_threads_create_gui (self);
509 static void
510 on_debugger_stopped (DmaThreads *self)
512 dma_threads_clear (self);
513 dma_destroy_threads_gui (self);
516 static gboolean
517 on_mark_selected_thread (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
519 DmaThreads* self = (DmaThreads *)user_data;
520 GdkPixbuf *pic;
521 guint thread;
523 gtk_tree_model_get (model, iter, THREAD_ACTIVE_COLUMN, &pic, THREAD_ID_COLUMN, &thread, -1);
525 if (pic != NULL)
527 /* Remove previously selected thread marker */
528 gdk_pixbuf_unref (pic);
529 pic = NULL;
532 if (self->current_thread == thread)
534 /* Create marker if needed */
535 pic = gdk_pixbuf_new_from_file (ANJUTA_PIXMAP_POINTER, NULL);
538 gtk_list_store_set (GTK_LIST_STORE (model), iter,
539 THREAD_ACTIVE_COLUMN, pic, -1);
541 if (pic != NULL)
543 gdk_pixbuf_unref (pic);
546 return FALSE;
549 static void
550 on_frame_changed (DmaThreads *self, guint frame, guint thread)
552 if (thread != self->current_thread)
554 GtkTreeModel *model;
556 self->current_thread = thread;
557 model = gtk_tree_view_get_model (self->list);
559 gtk_tree_model_foreach (model, on_mark_selected_thread, self);
563 /* Constructor & Destructor
564 *---------------------------------------------------------------------------*/
566 DmaThreads*
567 dma_threads_new (IAnjutaDebugger *debugger, DebugManagerPlugin *plugin)
569 DmaThreads* self;
570 AnjutaUI *ui;
572 self = g_new0 (DmaThreads, 1);
573 g_return_val_if_fail (self != NULL, NULL);
575 self->plugin = plugin;
576 self->debugger = debugger;
577 if (debugger != NULL) g_object_ref (debugger);
579 /* Register actions */
580 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN(self->plugin)->shell, NULL);
581 DEBUG_PRINT("add actions");
582 self->action_group =
583 anjuta_ui_add_action_group_entries (ui, "ActionGroupThread",
584 _("Thread operations"),
585 actions_threads,
586 G_N_ELEMENTS (actions_threads),
587 GETTEXT_PACKAGE, TRUE, self);
588 DEBUG_PRINT("add actions end");
590 g_signal_connect_swapped (self->debugger, "debugger-started", G_CALLBACK (on_debugger_started), self);
591 g_signal_connect_swapped (self->debugger, "debugger-stopped", G_CALLBACK (on_debugger_stopped), self);
592 g_signal_connect_swapped (self->debugger, "program-stopped", G_CALLBACK (on_program_stopped), self);
593 g_signal_connect_swapped (self->debugger, "frame-changed", G_CALLBACK (on_frame_changed), self);
595 return self;
598 void
599 dma_threads_free (DmaThreads *self)
601 AnjutaUI *ui;
603 g_return_if_fail (self != NULL);
605 /* Disconnect from debugger */
606 if (self->debugger != NULL)
608 g_signal_handlers_disconnect_by_func (self->debugger, G_CALLBACK (on_debugger_started), self);
609 g_signal_handlers_disconnect_by_func (self->debugger, G_CALLBACK (on_debugger_stopped), self);
610 g_signal_handlers_disconnect_by_func (self->debugger, G_CALLBACK (on_program_stopped), self);
611 g_signal_handlers_disconnect_by_func (self->debugger, G_CALLBACK (on_frame_changed), self);
612 g_object_unref (self->debugger);
615 /* Remove menu actions */
616 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN (self->plugin)->shell, NULL);
617 anjuta_ui_remove_action_group (ui, self->action_group);
619 /* Destroy menu */
620 dma_destroy_threads_gui (self);
622 g_free (self);