Integrate adding files with the file manager
[anjuta-git-plugin.git] / plugins / debug-manager / threads.c
blob7db8e8e76168b34ca0fbb9b41867912474b0d242
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 if (g_path_is_absolute (frame->file))
226 uri = gnome_vfs_get_uri_from_local_path(frame->file);
227 file = strrchr(frame->file, G_DIR_SEPARATOR) + 1;
229 else
231 uri = NULL;
232 file = frame->file;
235 else
237 uri = NULL;
238 file = frame->library;
241 if (gtk_tree_row_reference_valid (reference))
243 GtkTreeIter iter;
244 GtkTreeModel *model;
245 GtkTreePath *path;
246 gboolean ok;
248 model = gtk_tree_row_reference_get_model(reference);
249 path = gtk_tree_row_reference_get_path (reference);
250 ok = gtk_tree_model_get_iter (model, &iter, path);
251 gtk_tree_path_free (path);
253 if (ok)
255 gtk_list_store_set(GTK_LIST_STORE (model), &iter,
256 THREAD_FILE_COLUMN, file,
257 THREAD_LINE_COLUMN, frame->line,
258 THREAD_FUNC_COLUMN, frame->function,
259 THREAD_ADDR_COLUMN, adr,
260 THREAD_URI_COLUMN, uri,
261 -1);
263 gtk_tree_row_reference_free(reference);
266 g_free (uri);
267 g_free (adr);
270 static void
271 on_list_thread (const GList *threads, gpointer user_data)
273 DmaThreads *self = (DmaThreads *)user_data;
274 const GList *node;
275 GtkListStore *model;
277 dma_threads_clear (self);
279 model = GTK_LIST_STORE (gtk_tree_view_get_model (self->list));
281 for (node = threads; node != NULL; node = node->next)
283 GdkPixbuf *pic;
284 GtkTreeIter iter;
285 IAnjutaDebuggerFrame *frame;
286 gchar *adr;
287 gchar *uri;
288 gchar *file;
290 frame = (IAnjutaDebuggerFrame *)node->data;
292 gtk_list_store_append (model, &iter);
294 /* if we are on the current frame set iterator and pixmap correctly */
295 if (frame->thread == self->current_thread)
296 pic = gdk_pixbuf_new_from_file (ANJUTA_PIXMAP_POINTER, NULL);
297 else
298 pic = NULL;
300 if ((dma_debugger_queue_is_supported (self->debugger, HAS_MEMORY) && (frame->address == 0))
301 || (frame->function == NULL))
303 /* Missing frame address, request more information */
304 GtkTreeRowReference* reference;
305 GtkTreePath *path;
307 path = gtk_tree_model_get_path(GTK_TREE_MODEL (model), &iter);
308 reference = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), path);
309 gtk_tree_path_free (path);
311 dma_queue_info_thread (
312 self->debugger, frame->thread,
313 (IAnjutaDebuggerCallback)on_info_thread,
314 reference);
316 gtk_list_store_set(model, &iter,
317 THREAD_ACTIVE_COLUMN, pic,
318 THREAD_ID_COLUMN, frame->thread,
319 -1);
321 else
323 adr = g_strdup_printf ("0x%lx", frame->address);
324 if (frame->file)
326 if (g_path_is_absolute (frame->file))
328 uri = gnome_vfs_get_uri_from_local_path(frame->file);
329 file = strrchr(frame->file, G_DIR_SEPARATOR) + 1;
331 else
333 uri = NULL;
334 file = frame->file;
337 else
339 uri = NULL;
340 file = frame->library;
343 gtk_list_store_set(model, &iter,
344 THREAD_ACTIVE_COLUMN, pic,
345 THREAD_ID_COLUMN, frame->thread,
346 THREAD_FILE_COLUMN, file,
347 THREAD_LINE_COLUMN, frame->line,
348 THREAD_FUNC_COLUMN, frame->function,
349 THREAD_ADDR_COLUMN, adr,
350 THREAD_URI_COLUMN, uri,
351 -1);
353 g_free (uri);
354 g_free (adr);
357 if (pic)
358 gdk_pixbuf_unref (pic);
362 static void
363 dma_threads_update (DmaThreads *self)
365 dma_queue_list_thread (
366 self->debugger,
367 (IAnjutaDebuggerCallback)on_list_thread,
368 self);
371 /* Actions table
372 *---------------------------------------------------------------------------*/
374 static GtkActionEntry actions_threads[] = {
376 "ActionDmaSetCurrentThread", /* Action name */
377 NULL, /* Stock icon, if any */
378 N_("Set current thread"), /* Display label */
379 NULL, /* short-cut */
380 NULL, /* Tooltip */
381 G_CALLBACK (on_threads_set_activate) /* action callback */
384 "ActionDmaJumpToThread",
385 NULL,
386 N_("View Source"),
387 NULL,
388 NULL,
389 G_CALLBACK (on_threads_source_activate)
393 static void
394 dma_threads_create_gui(DmaThreads *self)
396 GtkTreeModel* model;
397 GtkTreeSelection *selection;
398 GtkTreeViewColumn *column;
399 GtkCellRenderer *renderer;
400 AnjutaUI *ui;
402 g_return_if_fail (self->scrolledwindow == NULL);
404 /* Create tree view */
405 model = GTK_TREE_MODEL(gtk_list_store_new (THREAD_N_COLUMNS,
406 GDK_TYPE_PIXBUF,
407 G_TYPE_UINT,
408 G_TYPE_STRING,
409 G_TYPE_UINT,
410 G_TYPE_STRING,
411 G_TYPE_STRING,
412 G_TYPE_STRING));
413 self->list = GTK_TREE_VIEW (gtk_tree_view_new_with_model (model));
414 g_object_unref (G_OBJECT (model));
416 selection = gtk_tree_view_get_selection (self->list);
417 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
419 /* Columns */
420 column = gtk_tree_view_column_new ();
421 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
422 gtk_tree_view_column_set_title (column, _("Active"));
423 renderer = gtk_cell_renderer_pixbuf_new ();
424 gtk_tree_view_column_pack_start (column, renderer, TRUE);
425 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf",
426 THREAD_ACTIVE_COLUMN);
427 gtk_tree_view_append_column (self->list, column);
428 gtk_tree_view_set_expander_column (self->list, column);
430 column = gtk_tree_view_column_new ();
431 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
432 gtk_tree_view_column_set_title (column, _("Id"));
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_ID_COLUMN);
437 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
438 gtk_tree_view_append_column (self->list, column);
439 gtk_tree_view_set_expander_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_FILE_COLUMN);
446 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
447 gtk_tree_view_column_set_title (column, _("File"));
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_LINE_COLUMN);
455 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
456 gtk_tree_view_column_set_title (column, _("Line"));
457 gtk_tree_view_append_column (self->list, column);
459 column = gtk_tree_view_column_new ();
460 renderer = gtk_cell_renderer_text_new ();
461 gtk_tree_view_column_pack_start (column, renderer, TRUE);
462 gtk_tree_view_column_add_attribute (column, renderer, "text",
463 THREAD_FUNC_COLUMN);
464 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
465 gtk_tree_view_column_set_title (column, _("Function"));
466 gtk_tree_view_append_column (self->list, column);
468 if (dma_debugger_queue_is_supported (self->debugger, HAS_MEMORY))
470 /* Display address only if debugger has such concept */
471 column = gtk_tree_view_column_new ();
472 renderer = gtk_cell_renderer_text_new ();
473 gtk_tree_view_column_pack_start (column, renderer, TRUE);
474 gtk_tree_view_column_add_attribute (column, renderer, "text",
475 THREAD_ADDR_COLUMN);
476 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
477 gtk_tree_view_column_set_title (column, _("Address"));
478 gtk_tree_view_append_column (self->list, column);
481 /* Create popup menu */
482 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN(self->plugin)->shell, NULL);
483 self->menu = GTK_MENU (gtk_ui_manager_get_widget (GTK_UI_MANAGER (ui), "/PopupThread"));
485 /* Connect signal */
486 g_signal_connect (self->list, "button-press-event", G_CALLBACK (on_threads_button_press), self);
487 g_signal_connect (self->list, "row-activated", G_CALLBACK (on_threads_row_activated), self);
489 /* Add stack window */
490 self->scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
491 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (self->scrolledwindow),
492 GTK_POLICY_AUTOMATIC,
493 GTK_POLICY_AUTOMATIC);
494 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (self->scrolledwindow),
495 GTK_SHADOW_IN);
496 gtk_container_add (GTK_CONTAINER (self->scrolledwindow),
497 GTK_WIDGET (self->list));
498 gtk_widget_show_all (self->scrolledwindow);
500 anjuta_shell_add_widget (ANJUTA_PLUGIN(self->plugin)->shell,
501 self->scrolledwindow,
502 "AnjutaDebuggerThread", _("Thread"),
503 "gdb-stack-icon", ANJUTA_SHELL_PLACEMENT_BOTTOM,
504 NULL);
508 static void
509 dma_destroy_threads_gui (DmaThreads *self)
511 if (self->scrolledwindow != NULL)
513 gtk_widget_destroy (self->scrolledwindow);
514 self->scrolledwindow = NULL;
518 static void
519 on_program_moved (DmaThreads *self, guint pid, gint thread)
521 self->current_thread = thread;
522 dma_threads_update (self);
525 static gboolean
526 on_mark_selected_thread (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
528 DmaThreads* self = (DmaThreads *)user_data;
529 GdkPixbuf *pic;
530 gint thread;
532 gtk_tree_model_get (model, iter, THREAD_ACTIVE_COLUMN, &pic, THREAD_ID_COLUMN, &thread, -1);
534 if (pic != NULL)
536 /* Remove previously selected thread marker */
537 gdk_pixbuf_unref (pic);
538 pic = NULL;
541 if (self->current_thread == thread)
543 /* Create marker if needed */
544 pic = gdk_pixbuf_new_from_file (ANJUTA_PIXMAP_POINTER, NULL);
547 gtk_list_store_set (GTK_LIST_STORE (model), iter,
548 THREAD_ACTIVE_COLUMN, pic, -1);
550 if (pic != NULL)
552 gdk_pixbuf_unref (pic);
555 return FALSE;
558 static void
559 on_frame_changed (DmaThreads *self, guint frame, gint thread)
561 if (thread != self->current_thread)
563 GtkTreeModel *model;
565 self->current_thread = thread;
566 model = gtk_tree_view_get_model (self->list);
568 gtk_tree_model_foreach (model, on_mark_selected_thread, self);
572 static void
573 on_program_exited (DmaThreads *self)
575 g_signal_handlers_disconnect_by_func (self->plugin, G_CALLBACK (on_program_exited), self);
576 g_signal_handlers_disconnect_by_func (self->plugin, G_CALLBACK (on_program_moved), self);
577 g_signal_handlers_disconnect_by_func (self->plugin, G_CALLBACK (on_frame_changed), self);
579 dma_threads_clear (self);
580 dma_destroy_threads_gui (self);
583 static void
584 on_program_started (DmaThreads *self)
586 dma_threads_create_gui (self);
588 g_signal_connect_swapped (self->plugin, "program-exited", G_CALLBACK (on_program_exited), self);
589 g_signal_connect_swapped (self->plugin, "program-moved", G_CALLBACK (on_program_moved), self);
590 g_signal_connect_swapped (self->plugin, "frame-changed", G_CALLBACK (on_frame_changed), self);
593 /* Constructor & Destructor
594 *---------------------------------------------------------------------------*/
596 DmaThreads*
597 dma_threads_new (DebugManagerPlugin *plugin)
599 DmaThreads* self;
600 AnjutaUI *ui;
602 self = g_new0 (DmaThreads, 1);
603 g_return_val_if_fail (self != NULL, NULL);
605 self->plugin = plugin;
606 self->debugger = dma_debug_manager_get_queue (plugin);
608 /* Register actions */
609 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN(self->plugin)->shell, NULL);
610 self->action_group =
611 anjuta_ui_add_action_group_entries (ui, "ActionGroupThread",
612 _("Thread operations"),
613 actions_threads,
614 G_N_ELEMENTS (actions_threads),
615 GETTEXT_PACKAGE, TRUE, self);
617 g_signal_connect_swapped (self->plugin, "program-started", G_CALLBACK (on_program_started), self);
619 return self;
622 void
623 dma_threads_free (DmaThreads *self)
625 AnjutaUI *ui;
627 g_return_if_fail (self != NULL);
629 /* Disconnect from debugger */
630 g_signal_handlers_disconnect_matched (self->plugin, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
632 /* Remove menu actions */
633 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN (self->plugin)->shell, NULL);
634 anjuta_ui_remove_action_group (ui, self->action_group);
636 /* Destroy menu */
637 dma_destroy_threads_gui (self);
639 g_free (self);