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 uri
= gnome_vfs_get_uri_from_local_path(frame
->file
);
225 file
= strrchr(uri
, '/') + 1;
230 file
= frame
->library
;
233 if (gtk_tree_row_reference_valid (reference
))
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
);
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
,
255 gtk_tree_row_reference_free(reference
);
263 on_list_thread (const GList
*threads
, gpointer user_data
)
265 DmaThreads
*self
= (DmaThreads
*)user_data
;
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
)
277 IAnjutaDebuggerFrame
*frame
;
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
);
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
;
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
,
308 gtk_list_store_set(model
, &iter
,
309 THREAD_ACTIVE_COLUMN
, pic
,
310 THREAD_ID_COLUMN
, frame
->thread
,
315 adr
= g_strdup_printf ("0x%lx", frame
->address
);
318 uri
= gnome_vfs_get_uri_from_local_path(frame
->file
);
319 file
= strrchr(uri
, '/') + 1;
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
,
342 gdk_pixbuf_unref (pic
);
347 dma_threads_update (DmaThreads
*self
)
349 dma_queue_list_thread (
351 (IAnjutaDebuggerCallback
)on_list_thread
,
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 */
365 G_CALLBACK (on_threads_set_activate
) /* action callback */
368 "ActionDmaJumpToThread",
373 G_CALLBACK (on_threads_source_activate
)
378 dma_threads_create_gui(DmaThreads
*self
)
381 GtkTreeSelection
*selection
;
382 GtkTreeViewColumn
*column
;
383 GtkCellRenderer
*renderer
;
386 g_return_if_fail (self
->scrolledwindow
== NULL
);
388 /* Create tree view */
389 model
= GTK_TREE_MODEL(gtk_list_store_new (THREAD_N_COLUMNS
,
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
);
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",
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",
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",
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",
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",
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"));
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
),
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
,
493 dma_destroy_threads_gui (DmaThreads
*self
)
495 if (self
->scrolledwindow
!= NULL
)
497 gtk_widget_destroy (self
->scrolledwindow
);
498 self
->scrolledwindow
= NULL
;
503 on_program_moved (DmaThreads
*self
, guint pid
, gint thread
)
505 self
->current_thread
= thread
;
506 dma_threads_update (self
);
510 on_mark_selected_thread (GtkTreeModel
*model
, GtkTreePath
*path
, GtkTreeIter
*iter
, gpointer user_data
)
512 DmaThreads
* self
= (DmaThreads
*)user_data
;
516 gtk_tree_model_get (model
, iter
, THREAD_ACTIVE_COLUMN
, &pic
, THREAD_ID_COLUMN
, &thread
, -1);
520 /* Remove previously selected thread marker */
521 gdk_pixbuf_unref (pic
);
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);
536 gdk_pixbuf_unref (pic
);
543 on_frame_changed (DmaThreads
*self
, guint frame
, gint thread
)
545 if (thread
!= self
->current_thread
)
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
);
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
);
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 *---------------------------------------------------------------------------*/
581 dma_threads_new (DebugManagerPlugin
*plugin
)
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
);
595 anjuta_ui_add_action_group_entries (ui
, "ActionGroupThread",
596 _("Thread operations"),
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
);
607 dma_threads_free (DmaThreads
*self
)
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
);
621 dma_destroy_threads_gui (self
);