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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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"
41 #define ANJUTA_PIXMAP_POINTER PACKAGE_PIXMAPS_DIR"/pointer.png"
45 DebugManagerPlugin
*plugin
;
46 IAnjutaDebugger
*debugger
;
49 GtkWidget
*scrolledwindow
;
52 GtkActionGroup
*action_group
;
57 struct _DmaThreadPacket
{
59 GtkTreeRowReference
* reference
;
76 *---------------------------------------------------------------------------*/
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
91 get_current_index (DmaThreads
*self
)
95 if (get_current_iter (self
->list
, &iter
))
100 model
= gtk_tree_view_get_model (self
->list
);
101 gtk_tree_model_get (model
, &iter
, THREAD_ID_COLUMN
, &thread_no
, -1);
112 *---------------------------------------------------------------------------*/
115 dma_threads_clear (DmaThreads
*self
)
119 model
= gtk_tree_view_get_model (self
->list
);
120 gtk_list_store_clear (GTK_LIST_STORE (model
));
123 /* Callback functions
124 *---------------------------------------------------------------------------*/
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)
138 /* current thread is already active */
139 if (selected_thread
== self
->current_thread
)
142 /* issue a command to switch active frame to new location */
143 ianjuta_debugger_set_thread (self
->debugger
, selected_thread
, NULL
);
147 on_threads_source_activate (GtkAction
*action
, gpointer user_data
)
150 GtkTreeSelection
*selection
;
157 DmaThreads
* self
= (DmaThreads
*) user_data
;
160 selection
= gtk_tree_view_get_selection (view
);
161 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
))
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
,
171 address
= adr
!= NULL
? strtoul (adr
, NULL
, 0) : 0;
172 dma_debug_manager_goto_code (self
->plugin
, uri
, line
, address
);
178 on_threads_row_activated (GtkTreeView
*treeview
,
180 GtkTreeViewColumn
*arg2
,
183 on_threads_set_activate (NULL
, self
);
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
);
208 on_info_thread (const IAnjutaDebuggerFrame
* frame
, gpointer user_data
)
210 GtkTreeRowReference
* reference
= (GtkTreeRowReference
*)user_data
;
215 if (frame
== NULL
) return;
217 adr
= g_strdup_printf ("0x%x", frame
->address
);
221 uri
= g_strconcat ("file://", frame
->file
, NULL
);
222 file
= strrchr(uri
, '/') + 1;
227 file
= frame
->library
;
230 if (gtk_tree_row_reference_valid (reference
))
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
);
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
,
252 gtk_tree_row_reference_free(reference
);
260 on_list_thread (const GList
*threads
, gpointer user_data
)
262 DmaThreads
*self
= (DmaThreads
*)user_data
;
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
)
274 IAnjutaDebuggerFrame
*frame
;
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
);
289 if (frame
->address
== 0)
291 /* Missing frame address, request more information */
292 GtkTreeRowReference
* reference
;
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
,
305 gtk_list_store_set(model
, &iter
,
306 THREAD_ACTIVE_COLUMN
, pic
,
307 THREAD_ID_COLUMN
, frame
->thread
,
312 adr
= g_strdup_printf ("0x%x", frame
->address
);
315 uri
= g_strconcat ("file://", frame
->file
, NULL
);
316 file
= strrchr(uri
, '/') + 1;
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
,
339 gdk_pixbuf_unref (pic
);
344 dma_threads_update (DmaThreads
*self
)
346 ianjuta_debugger_list_thread (
348 (IAnjutaDebuggerCallback
)on_list_thread
,
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 */
363 G_CALLBACK (on_threads_set_activate
) /* action callback */
366 "ActionDmaJumpToThread",
371 G_CALLBACK (on_threads_source_activate
)
376 dma_threads_create_gui(DmaThreads
*self
)
379 GtkTreeSelection
*selection
;
380 GtkTreeViewColumn
*column
;
381 GtkCellRenderer
*renderer
;
384 g_return_if_fail (self
->scrolledwindow
== NULL
);
386 /* Create tree view */
387 model
= GTK_TREE_MODEL(gtk_list_store_new (THREAD_N_COLUMNS
,
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
);
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",
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",
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",
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",
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",
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"));
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
),
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
,
487 dma_destroy_threads_gui (DmaThreads
*self
)
489 if (self
->scrolledwindow
!= NULL
)
491 gtk_widget_destroy (self
->scrolledwindow
);
492 self
->scrolledwindow
= NULL
;
497 on_program_stopped (DmaThreads
*self
, guint thread
)
499 self
->current_thread
= thread
;
500 dma_threads_update (self
);
504 on_debugger_started (DmaThreads
*self
)
506 dma_threads_create_gui (self
);
510 on_debugger_stopped (DmaThreads
*self
)
512 dma_threads_clear (self
);
513 dma_destroy_threads_gui (self
);
517 on_mark_selected_thread (GtkTreeModel
*model
, GtkTreePath
*path
, GtkTreeIter
*iter
, gpointer user_data
)
519 DmaThreads
* self
= (DmaThreads
*)user_data
;
523 gtk_tree_model_get (model
, iter
, THREAD_ACTIVE_COLUMN
, &pic
, THREAD_ID_COLUMN
, &thread
, -1);
527 /* Remove previously selected thread marker */
528 gdk_pixbuf_unref (pic
);
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);
543 gdk_pixbuf_unref (pic
);
550 on_frame_changed (DmaThreads
*self
, guint frame
, guint thread
)
552 if (thread
!= self
->current_thread
)
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 *---------------------------------------------------------------------------*/
567 dma_threads_new (IAnjutaDebugger
*debugger
, DebugManagerPlugin
*plugin
)
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");
583 anjuta_ui_add_action_group_entries (ui
, "ActionGroupThread",
584 _("Thread operations"),
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
);
599 dma_threads_free (DmaThreads
*self
)
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
);
620 dma_destroy_threads_gui (self
);