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
35 #include <libanjuta/resources.h>
36 #include <libanjuta/anjuta-debug.h>
37 #include <libanjuta/interfaces/ianjuta-editor.h>
38 #include <libanjuta/interfaces/ianjuta-document-manager.h>
40 #include "utilities.h"
43 #define ANJUTA_PIXMAP_POINTER PACKAGE_PIXMAPS_DIR"/pointer.png"
47 DebugManagerPlugin
*plugin
;
48 DmaDebuggerQueue
*debugger
;
51 GtkWidget
*scrolledwindow
;
54 GtkActionGroup
*action_group
;
59 struct _DmaThreadPacket
{
61 GtkTreeRowReference
* reference
;
78 *---------------------------------------------------------------------------*/
81 get_current_iter (GtkTreeView
*view
, GtkTreeIter
* iter
)
83 GtkTreeSelection
*selection
;
85 selection
= gtk_tree_view_get_selection (view
);
86 return gtk_tree_selection_get_selected (selection
, NULL
, iter
);
90 * returns the current stack thread or -1 on error
93 get_current_index (DmaThreads
*self
)
97 if (get_current_iter (self
->list
, &iter
))
102 model
= gtk_tree_view_get_model (self
->list
);
103 gtk_tree_model_get (model
, &iter
, THREAD_ID_COLUMN
, &thread_no
, -1);
114 *---------------------------------------------------------------------------*/
117 dma_threads_clear (DmaThreads
*self
)
121 model
= gtk_tree_view_get_model (self
->list
);
122 gtk_list_store_clear (GTK_LIST_STORE (model
));
125 /* Callback functions
126 *---------------------------------------------------------------------------*/
129 on_threads_set_activate (GtkAction
*action
, gpointer user_data
)
131 DmaThreads
*self
= (DmaThreads
*)user_data
;
132 gint selected_thread
;
134 selected_thread
= get_current_index (self
);
136 /* No thread selected */
137 if (selected_thread
== -1)
140 /* current thread is already active */
141 if (selected_thread
== self
->current_thread
)
144 /* issue a command to switch active frame to new location */
145 dma_queue_set_thread (self
->debugger
, selected_thread
);
149 on_threads_source_activate (GtkAction
*action
, gpointer user_data
)
152 GtkTreeSelection
*selection
;
159 DmaThreads
* self
= (DmaThreads
*) user_data
;
162 selection
= gtk_tree_view_get_selection (view
);
163 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
))
166 /* get the frame info */
167 gtk_tree_model_get (model
, &iter
,
168 THREAD_URI_COLUMN
, &uri
,
169 THREAD_LINE_COLUMN
, &line
,
170 THREAD_ADDR_COLUMN
, &adr
,
173 address
= adr
!= NULL
? strtoul (adr
, NULL
, 0) : 0;
174 g_signal_emit_by_name (self
->plugin
, "location-changed", address
, uri
, line
);
180 on_threads_row_activated (GtkTreeView
*treeview
,
182 GtkTreeViewColumn
*arg2
,
185 on_threads_set_activate (NULL
, self
);
189 on_threads_button_press (GtkWidget
*widget
, GdkEventButton
*bevent
, gpointer user_data
)
191 DmaThreads
*self
= (DmaThreads
*) user_data
;
193 if ((bevent
->type
== GDK_BUTTON_PRESS
) && (bevent
->button
== 3))
195 /* Right mouse click */
196 g_return_val_if_fail (self
->menu
!= NULL
, FALSE
);
197 gtk_menu_popup (GTK_MENU (self
->menu
), NULL
, NULL
, NULL
, NULL
,
198 bevent
->button
, bevent
->time
);
200 else if ((bevent
->type
== GDK_2BUTTON_PRESS
) && (bevent
->button
== 1))
202 /* Double left mouse click */
203 on_threads_source_activate (NULL
, user_data
);
210 on_info_thread (const IAnjutaDebuggerFrame
* frame
, gpointer user_data
)
212 GtkTreeRowReference
* reference
= (GtkTreeRowReference
*)user_data
;
217 if (frame
== NULL
) return;
219 adr
= g_strdup_printf ("0x%x", frame
->address
);
223 uri
= g_strconcat ("file://", frame
->file
, NULL
);
224 file
= strrchr(uri
, '/') + 1;
229 file
= frame
->library
;
232 if (gtk_tree_row_reference_valid (reference
))
239 model
= gtk_tree_row_reference_get_model(reference
);
240 path
= gtk_tree_row_reference_get_path (reference
);
241 ok
= gtk_tree_model_get_iter (model
, &iter
, path
);
242 gtk_tree_path_free (path
);
246 gtk_list_store_set(GTK_LIST_STORE (model
), &iter
,
247 THREAD_FILE_COLUMN
, file
,
248 THREAD_LINE_COLUMN
, frame
->line
,
249 THREAD_FUNC_COLUMN
, frame
->function
,
250 THREAD_ADDR_COLUMN
, adr
,
251 THREAD_URI_COLUMN
, uri
,
254 gtk_tree_row_reference_free(reference
);
262 on_list_thread (const GList
*threads
, gpointer user_data
)
264 DmaThreads
*self
= (DmaThreads
*)user_data
;
268 dma_threads_clear (self
);
270 model
= GTK_LIST_STORE (gtk_tree_view_get_model (self
->list
));
272 for (node
= threads
; node
!= NULL
; node
= node
->next
)
276 IAnjutaDebuggerFrame
*frame
;
281 frame
= (IAnjutaDebuggerFrame
*)node
->data
;
283 gtk_list_store_append (model
, &iter
);
285 /* if we are on the current frame set iterator and pixmap correctly */
286 if (frame
->thread
== self
->current_thread
)
287 pic
= gdk_pixbuf_new_from_file (ANJUTA_PIXMAP_POINTER
, NULL
);
291 if (frame
->address
== 0)
293 /* Missing frame address, request more information */
294 GtkTreeRowReference
* reference
;
297 path
= gtk_tree_model_get_path(GTK_TREE_MODEL (model
), &iter
);
298 reference
= gtk_tree_row_reference_new (GTK_TREE_MODEL (model
), path
);
299 gtk_tree_path_free (path
);
301 dma_queue_info_thread (
302 self
->debugger
, frame
->thread
,
303 (IAnjutaDebuggerCallback
)on_info_thread
,
306 gtk_list_store_set(model
, &iter
,
307 THREAD_ACTIVE_COLUMN
, pic
,
308 THREAD_ID_COLUMN
, frame
->thread
,
313 adr
= g_strdup_printf ("0x%x", frame
->address
);
316 uri
= g_strconcat ("file://", frame
->file
, NULL
);
317 file
= strrchr(uri
, '/') + 1;
322 file
= frame
->library
;
325 gtk_list_store_set(model
, &iter
,
326 THREAD_ACTIVE_COLUMN
, pic
,
327 THREAD_ID_COLUMN
, frame
->thread
,
328 THREAD_FILE_COLUMN
, file
,
329 THREAD_LINE_COLUMN
, frame
->line
,
330 THREAD_FUNC_COLUMN
, frame
->function
,
331 THREAD_ADDR_COLUMN
, adr
,
332 THREAD_URI_COLUMN
, uri
,
340 gdk_pixbuf_unref (pic
);
345 dma_threads_update (DmaThreads
*self
)
347 dma_queue_list_thread (
349 (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_moved (DmaThreads
*self
, guint pid
, gint 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
, gint 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 (DebugManagerPlugin
*plugin
)
572 self
= g_new0 (DmaThreads
, 1);
573 g_return_val_if_fail (self
!= NULL
, NULL
);
575 self
->plugin
= plugin
;
576 self
->debugger
= dma_debug_manager_get_queue (plugin
);
578 /* Register actions */
579 ui
= anjuta_shell_get_ui (ANJUTA_PLUGIN(self
->plugin
)->shell
, NULL
);
580 DEBUG_PRINT("add actions");
582 anjuta_ui_add_action_group_entries (ui
, "ActionGroupThread",
583 _("Thread operations"),
585 G_N_ELEMENTS (actions_threads
),
586 GETTEXT_PACKAGE
, TRUE
, self
);
587 DEBUG_PRINT("add actions end");
589 g_signal_connect_swapped (self
->plugin
, "debugger-started", G_CALLBACK (on_debugger_started
), self
);
590 g_signal_connect_swapped (self
->plugin
, "debugger-stopped", G_CALLBACK (on_debugger_stopped
), self
);
591 g_signal_connect_swapped (self
->plugin
, "program-moved", G_CALLBACK (on_program_moved
), self
);
592 g_signal_connect_swapped (self
->plugin
, "frame-changed", G_CALLBACK (on_frame_changed
), self
);
598 dma_threads_free (DmaThreads
*self
)
602 g_return_if_fail (self
!= NULL
);
604 /* Disconnect from debugger */
605 if (self
->debugger
!= NULL
)
607 g_signal_handlers_disconnect_by_func (self
->plugin
, G_CALLBACK (on_debugger_started
), self
);
608 g_signal_handlers_disconnect_by_func (self
->plugin
, G_CALLBACK (on_debugger_stopped
), self
);
609 g_signal_handlers_disconnect_by_func (self
->plugin
, G_CALLBACK (on_program_moved
), self
);
610 g_signal_handlers_disconnect_by_func (self
->plugin
, G_CALLBACK (on_frame_changed
), self
);
613 /* Remove menu actions */
614 ui
= anjuta_shell_get_ui (ANJUTA_PLUGIN (self
->plugin
)->shell
, NULL
);
615 anjuta_ui_remove_action_group (ui
, self
->action_group
);
618 dma_destroy_threads_gui (self
);