1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
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
33 #include <libgnomevfs/gnome-vfs.h>
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"
44 #define ANJUTA_PIXMAP_POINTER PACKAGE_PIXMAPS_DIR"/pointer.png"
48 DebugManagerPlugin
*plugin
;
49 DmaDebuggerQueue
*debugger
;
52 GtkWidget
*scrolledwindow
;
55 GtkActionGroup
*action_group
;
60 struct _DmaThreadPacket
{
62 GtkTreeRowReference
* reference
;
79 *---------------------------------------------------------------------------*/
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
94 get_current_index (DmaThreads
*self
)
98 if (get_current_iter (self
->list
, &iter
))
103 model
= gtk_tree_view_get_model (self
->list
);
104 gtk_tree_model_get (model
, &iter
, THREAD_ID_COLUMN
, &thread_no
, -1);
115 *---------------------------------------------------------------------------*/
118 dma_threads_clear (DmaThreads
*self
)
122 model
= gtk_tree_view_get_model (self
->list
);
123 gtk_list_store_clear (GTK_LIST_STORE (model
));
126 /* Callback functions
127 *---------------------------------------------------------------------------*/
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)
141 /* current thread is already active */
142 if (selected_thread
== self
->current_thread
)
145 /* issue a command to switch active frame to new location */
146 dma_queue_set_thread (self
->debugger
, selected_thread
);
150 on_threads_source_activate (GtkAction
*action
, gpointer user_data
)
153 GtkTreeSelection
*selection
;
160 DmaThreads
* self
= (DmaThreads
*) user_data
;
163 selection
= gtk_tree_view_get_selection (view
);
164 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
))
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
,
174 address
= adr
!= NULL
? strtoul (adr
, NULL
, 0) : 0;
175 g_signal_emit_by_name (self
->plugin
, "location-changed", address
, uri
, line
);
181 on_threads_row_activated (GtkTreeView
*treeview
,
183 GtkTreeViewColumn
*arg2
,
186 on_threads_set_activate (NULL
, self
);
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
);
211 on_info_thread (const IAnjutaDebuggerFrame
* frame
, gpointer user_data
)
213 GtkTreeRowReference
* reference
= (GtkTreeRowReference
*)user_data
;
218 if (frame
== NULL
) return;
220 adr
= g_strdup_printf ("0x%lx", frame
->address
);
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;
238 file
= frame
->library
;
241 if (gtk_tree_row_reference_valid (reference
))
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
);
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
,
263 gtk_tree_row_reference_free(reference
);
271 on_list_thread (const GList
*threads
, gpointer user_data
)
273 DmaThreads
*self
= (DmaThreads
*)user_data
;
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
)
285 IAnjutaDebuggerFrame
*frame
;
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
);
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
;
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
,
316 gtk_list_store_set(model
, &iter
,
317 THREAD_ACTIVE_COLUMN
, pic
,
318 THREAD_ID_COLUMN
, frame
->thread
,
323 adr
= g_strdup_printf ("0x%lx", frame
->address
);
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;
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
,
358 gdk_pixbuf_unref (pic
);
363 dma_threads_update (DmaThreads
*self
)
365 dma_queue_list_thread (
367 (IAnjutaDebuggerCallback
)on_list_thread
,
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 */
381 G_CALLBACK (on_threads_set_activate
) /* action callback */
384 "ActionDmaJumpToThread",
389 G_CALLBACK (on_threads_source_activate
)
394 dma_threads_create_gui(DmaThreads
*self
)
397 GtkTreeSelection
*selection
;
398 GtkTreeViewColumn
*column
;
399 GtkCellRenderer
*renderer
;
402 g_return_if_fail (self
->scrolledwindow
== NULL
);
404 /* Create tree view */
405 model
= GTK_TREE_MODEL(gtk_list_store_new (THREAD_N_COLUMNS
,
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
);
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",
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",
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",
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",
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",
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"));
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
),
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
,
509 dma_destroy_threads_gui (DmaThreads
*self
)
511 if (self
->scrolledwindow
!= NULL
)
513 gtk_widget_destroy (self
->scrolledwindow
);
514 self
->scrolledwindow
= NULL
;
519 on_program_moved (DmaThreads
*self
, guint pid
, gint thread
)
521 self
->current_thread
= thread
;
522 dma_threads_update (self
);
526 on_mark_selected_thread (GtkTreeModel
*model
, GtkTreePath
*path
, GtkTreeIter
*iter
, gpointer user_data
)
528 DmaThreads
* self
= (DmaThreads
*)user_data
;
532 gtk_tree_model_get (model
, iter
, THREAD_ACTIVE_COLUMN
, &pic
, THREAD_ID_COLUMN
, &thread
, -1);
536 /* Remove previously selected thread marker */
537 gdk_pixbuf_unref (pic
);
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);
552 gdk_pixbuf_unref (pic
);
559 on_frame_changed (DmaThreads
*self
, guint frame
, gint thread
)
561 if (thread
!= self
->current_thread
)
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
);
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
);
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 *---------------------------------------------------------------------------*/
597 dma_threads_new (DebugManagerPlugin
*plugin
)
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
);
611 anjuta_ui_add_action_group_entries (ui
, "ActionGroupThread",
612 _("Thread operations"),
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
);
623 dma_threads_free (DmaThreads
*self
)
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
);
637 dma_destroy_threads_gui (self
);