1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) Massimo Cora' 2005 <maxcvs@gmail.com>
6 * plugin.c is free software.
8 * You may redistribute it and/or modify it under the terms of the
9 * GNU General Public License, as published by the Free Software
10 * Foundation; either version 2, or (at your option) any later version.
12 * plugin.c is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 * See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with plugin.c. See the file "COPYING". If not,
19 * write to: The Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
25 #include <libgnomevfs/gnome-vfs-utils.h>
26 #include <glib/gi18n.h>
27 #include <libgnomevfs/gnome-vfs.h>
28 #include <libgnome/gnome-util.h>
29 #include <libgnomeui/gnome-about.h>
30 #include <libanjuta/anjuta-shell.h>
31 #include <libanjuta/anjuta-debug.h>
32 #include <libanjuta/interfaces/ianjuta-document-manager.h>
33 #include <libanjuta/interfaces/ianjuta-project-manager.h>
34 #include <libanjuta/interfaces/ianjuta-preferences.h>
36 #include "vgdefaultview.h"
41 #define UI_FILE PACKAGE_DATA_DIR"/ui/anjuta-valgrind.ui"
42 #define GLADE_FILE PACKAGE_DATA_DIR"/glade/anjuta-valgrind.glade"
43 #define ICON_FILE "anjuta-valgrind-plugin-48.png"
53 static gpointer parent_class
;
56 register_stock_icons (AnjutaPlugin
*plugin
)
58 static gboolean registered
= FALSE
;
64 /* Register stock icons */
65 BEGIN_REGISTER_ICON (plugin
);
66 REGISTER_ICON (ICON_FILE
, "valgrind-knight");
71 project_root_added (AnjutaPlugin
*plugin
, const gchar
*name
,
72 const GValue
*value
, gpointer user_data
)
74 AnjutaValgrindPlugin
*val_plugin
;
75 const gchar
*root_uri
;
77 val_plugin
= ANJUTA_PLUGIN_VALGRIND (plugin
);
78 root_uri
= g_value_get_string (value
);
82 gchar
*root_dir
= gnome_vfs_get_local_path_from_uri (root_uri
);
84 val_plugin
->project_root_uri
= g_strdup(root_dir
);
86 val_plugin
->project_root_uri
= NULL
;
90 val_plugin
->project_root_uri
= NULL
;
94 project_root_removed (AnjutaPlugin
*plugin
, const gchar
*name
,
97 AnjutaValgrindPlugin
*val_plugin
;
98 val_plugin
= ANJUTA_PLUGIN_VALGRIND (plugin
);
100 if (val_plugin
->project_root_uri
)
101 g_free(val_plugin
->project_root_uri
);
102 val_plugin
->project_root_uri
= NULL
;
106 load_symtab (const char *progname
)
111 if (!(filename
= vg_tool_view_scan_path (progname
)))
114 symtab
= symtab_new (filename
);
120 /*---------------------------------------------------------------------------
121 * Perform some actions on select_and_run_dialog options button clicked.
122 * In particular it displays the option window for the selected [via combobox] valgrind
126 on_options_button_clicked (GtkButton
*button
, GladeXML
*gxml
)
128 GtkWidget
*tool_combobox
, *vgtool
;
133 tool_combobox
= glade_xml_get_widget (gxml
, "val_tool");
135 active_option
= gtk_combo_box_get_active (GTK_COMBO_BOX (tool_combobox
));
137 dlg
= GTK_DIALOG (gtk_dialog_new_with_buttons ( _("Options"), NULL
, GTK_DIALOG_MODAL
,
138 GTK_STOCK_CLOSE
, GTK_RESPONSE_CANCEL
,
140 g_signal_connect_swapped (dlg
, "response",
141 G_CALLBACK (gtk_widget_destroy
), dlg
);
143 switch (active_option
) {
144 case MEMCHECK_OPTION
:
145 case ADDRCHECK_OPTION
:
146 vgtool
= valgrind_plugin_prefs_get_memcheck_widget ();
149 case CACHEGRIND_OPTION:
150 vgtool = valgrind_plugin_prefs_get_cachegrind_widget ();
153 case HELGRIND_OPTION
:
154 vgtool
= valgrind_plugin_prefs_get_helgrind_widget ();
158 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dlg
)->vbox
), 3);
159 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg
)->vbox
), vgtool
, TRUE
, TRUE
, 0);
161 gtk_widget_show_all (GTK_WIDGET (dlg
));
162 gtk_dialog_run (dlg
);
166 on_menu_editrules_activate (GtkAction
*action
, AnjutaValgrindPlugin
*plugin
)
168 vg_tool_view_show_rules (VG_TOOL_VIEW (plugin
->valgrind_widget
));
172 on_menu_kill_activate (GtkAction
*action
, AnjutaValgrindPlugin
*plugin
)
174 vg_actions_kill (plugin
->val_actions
);
178 on_menu_run_activate (GtkAction
*action
, AnjutaValgrindPlugin
*plugin
)
180 IAnjutaProjectManager
*pm
;
183 pm
= anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin
)->shell
,
184 IAnjutaProjectManager
, NULL
);
185 g_return_if_fail (pm
!= NULL
);
188 ianjuta_project_manager_get_targets (pm
,
189 IANJUTA_PROJECT_MANAGER_TARGET_EXECUTABLE
,
194 GtkWidget
*dlg
, *treeview
, *tool_combobox
;
195 GtkTreeViewColumn
*column
;
196 GtkCellRenderer
*renderer
;
197 GtkButton
*options_button
;
199 gint response
, tool_selected
;
202 gchar
*project_root_uri
;
203 size_t project_root_uri_len
;
204 gchar
*sel_target
= NULL
;
207 gxml
= glade_xml_new (GLADE_FILE
, "select_and_run_dialog",
209 dlg
= glade_xml_get_widget (gxml
, "select_and_run_dialog");
210 treeview
= glade_xml_get_widget (gxml
, "programs_treeview");
212 tool_combobox
= glade_xml_get_widget (gxml
, "val_tool");
213 gtk_combo_box_set_active (GTK_COMBO_BOX (tool_combobox
), 0);
215 options_button
= GTK_BUTTON (glade_xml_get_widget (gxml
, "options_button"));
217 /* connect the signal to grab any click on it */
218 g_signal_connect (G_OBJECT (options_button
), "clicked",
219 G_CALLBACK (on_options_button_clicked
), gxml
);
221 gtk_window_set_transient_for (GTK_WINDOW (dlg
),
222 GTK_WINDOW (ANJUTA_PLUGIN(plugin
)->shell
));
223 store
= gtk_list_store_new (2, G_TYPE_STRING
, G_TYPE_STRING
);
226 anjuta_shell_get (ANJUTA_PLUGIN (plugin
)->shell
,
227 "project_root_uri", G_TYPE_STRING
,
228 &project_root_uri
, NULL
);
229 project_root_uri_len
= strlen(project_root_uri
) + 1;
232 const gchar
*rel_path
;
233 rel_path
= (gchar
*)node
->data
+ project_root_uri_len
;
234 gtk_list_store_append (store
, &iter
);
235 gtk_list_store_set (store
, &iter
, 0, rel_path
, 1,
238 node
= g_list_next (node
);
240 g_list_free (exec_targets
);
242 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview
),
243 GTK_TREE_MODEL (store
));
244 g_object_unref (store
);
246 column
= gtk_tree_view_column_new ();
247 gtk_tree_view_column_set_sizing (column
,
248 GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
249 gtk_tree_view_column_set_title (column
,
250 _("Select debugging target"));
252 renderer
= gtk_cell_renderer_text_new ();
253 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
254 gtk_tree_view_column_add_attribute (column
, renderer
, "text",
256 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
257 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (treeview
),
261 response
= gtk_dialog_run (GTK_DIALOG (dlg
));
262 if (response
== GTK_RESPONSE_OK
) {
263 GtkTreeSelection
*sel
;
266 sel
= gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview
));
267 if (gtk_tree_selection_get_selected (sel
, &model
, &iter
)) {
268 gtk_tree_model_get (model
, &iter
, 1, &sel_target
, -1);
271 /* get the selected tool before destroying the dialog */
272 tool_selected
= gtk_combo_box_get_active (GTK_COMBO_BOX (tool_combobox
));
275 gtk_widget_destroy (dlg
);
281 VgToolView
*vg_tool_view
;
283 prgname
= gnome_vfs_format_uri_for_display (sel_target
);
284 DEBUG_PRINT ("target program selected is %s", prgname
);
286 /* lets set some infos */
287 program_dir
= g_path_get_dirname (prgname
);
288 DEBUG_PRINT ("target a basedir: %s", program_dir
);
290 vg_tool_view
= VG_TOOL_VIEW (plugin
->valgrind_widget
);
292 vg_tool_view_set_argv (vg_tool_view
, sel_target
, NULL
);
293 vg_tool_view_set_srcdir (vg_tool_view
, program_dir
, NULL
);
296 g_free (program_dir
);
298 symtab
= load_symtab (prgname
);
299 vg_tool_view_set_symtab (vg_tool_view
, symtab
);
301 if (plugin
->valgrind_displayed
== FALSE
) {
302 /* Add the widget to the shell */
303 anjuta_shell_add_widget (ANJUTA_PLUGIN (plugin
)->shell
, plugin
->valgrind_widget
,
304 "AnjutaValgrindPluginWidget", _("Valgrind"), "valgrind-knight",
305 ANJUTA_SHELL_PLACEMENT_BOTTOM
, NULL
);
306 plugin
->valgrind_displayed
= TRUE
;
309 switch (tool_selected
) {
310 case MEMCHECK_OPTION
:
311 /* this is not a blocking call. The process will fork */
312 vg_actions_run (plugin
->val_actions
,
313 prgname
, "memcheck", NULL
);
316 case ADDRCHECK_OPTION
:
317 /* this is not a blocking call. The process will fork */
318 vg_actions_run (plugin
->val_actions
,
319 prgname
, "addrcheck", NULL
);
322 case HELGRIND_OPTION
:
323 /* this is not a blocking call. The process will fork */
324 vg_actions_run (plugin
->val_actions
,
325 prgname
, "helgrind", NULL
);
330 if ( response
== GTK_RESPONSE_OK
) {
331 anjuta_util_dialog_error (GTK_WINDOW (ANJUTA_PLUGIN (plugin
)->shell
),
332 _("No executable target selected for debugging with Valgrind. "
333 "Please select one."));
337 g_object_unref (gxml
);
340 anjuta_util_dialog_error (GTK_WINDOW (ANJUTA_PLUGIN (plugin
)->shell
),
341 _("There aren't any available executable targets for this project.\n"
342 "Please create one first."));
347 on_menu_save_log_activate (GtkAction
*action
, AnjutaValgrindPlugin
*plugin
)
351 GnomeVFSURI
* vfs_uri
;
353 dialog
= gtk_file_chooser_dialog_new (_("Choose file where to save Valgrind log"),
354 NULL
, GTK_FILE_CHOOSER_ACTION_SAVE
, GTK_STOCK_SAVE
,
355 GTK_RESPONSE_ACCEPT
, GTK_STOCK_CANCEL
,
356 GTK_RESPONSE_CANCEL
, NULL
);
358 if(gtk_dialog_run(GTK_DIALOG(dialog
)) == GTK_RESPONSE_ACCEPT
) {
359 uri
= gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog
));
365 gtk_widget_destroy(dialog
);
367 vfs_uri
= gnome_vfs_uri_new(uri
);
368 if (gnome_vfs_uri_exists (vfs_uri
))
371 dialog
= gtk_message_dialog_new (NULL
,
372 GTK_DIALOG_DESTROY_WITH_PARENT
,
373 GTK_MESSAGE_QUESTION
,
375 _("The file '%s' already exists.\n"
376 "Do you want to replace it with the one you are saving?"),
379 gtk_dialog_add_button (GTK_DIALOG(dialog
),
381 GTK_RESPONSE_CANCEL
);
382 anjuta_util_dialog_add_button (GTK_DIALOG (dialog
),
386 if (gtk_dialog_run (GTK_DIALOG (dialog
)) == GTK_RESPONSE_YES
)
387 vg_tool_view_save_log (VG_TOOL_VIEW (plugin
->valgrind_widget
), uri
);
388 gtk_widget_destroy (dialog
);
391 vg_tool_view_save_log (VG_TOOL_VIEW (plugin
->valgrind_widget
), uri
);
399 on_menu_load_log_activate (GtkAction
*action
, AnjutaValgrindPlugin
*plugin
)
403 gtk_file_chooser_dialog_new (_("Open Valgrind log file"),
405 GTK_FILE_CHOOSER_ACTION_OPEN
,
406 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
407 GTK_STOCK_OPEN
, GTK_RESPONSE_ACCEPT
,
410 if(gtk_dialog_run(GTK_DIALOG(dialog
)) == GTK_RESPONSE_ACCEPT
) {
411 uri
= gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog
));
417 gtk_widget_destroy(dialog
);
419 vg_tool_view_load_log (VG_TOOL_VIEW (plugin
->valgrind_widget
),
420 plugin
->val_actions
, uri
);
422 if (plugin
->valgrind_displayed
== FALSE
) {
423 /* Add the widget to the shell */
424 anjuta_shell_add_widget (ANJUTA_PLUGIN (plugin
)->shell
, plugin
->valgrind_widget
,
425 "AnjutaValgrindPluginWidget", _("Valgrind"), "valgrind-knight",
426 ANJUTA_SHELL_PLACEMENT_BOTTOM
, NULL
);
427 plugin
->valgrind_displayed
= TRUE
;
433 static GtkActionEntry actions_file
[] = {
435 "ActionMenuDebug", /* Action name */
436 NULL
, /* Stock icon, if any */
437 N_("_Debug"), /* Display label */
438 NULL
, /* short-cut */
440 NULL
/* action callback */
443 "ActionMenuValgrind", /* Action name */
444 "valgrind-knight", /* Stock icon, if any */
445 N_("_Valgrind"), /* Display label */
446 NULL
, /* short-cut */
448 NULL
/* action callback */
451 "ActionValgrindRun", /* Action name */
452 GTK_STOCK_EXECUTE
, /* Stock icon, if any */
453 N_("_Select Tool and Run..."), /* Display label */
454 NULL
, /* short-cut */
456 G_CALLBACK(on_menu_run_activate
) /* action callback */
459 "ActionValgrindKill", /* Action name */
460 GTK_STOCK_CANCEL
, /* Stock icon, if any */
461 N_("_Kill Execution"), /* Display label */
462 NULL
, /* short-cut */
464 G_CALLBACK(on_menu_kill_activate
) /* action callback */
467 "ActionValgrindLoad", /* Action name */
468 NULL
, /* Stock icon, if any */
469 N_("_Load Log"), /* Display label */
470 NULL
, /* short-cut */
472 G_CALLBACK(on_menu_load_log_activate
) /* action callback */
475 "ActionValgrindSave", /* Action name */
476 NULL
, /* Stock icon, if any */
477 N_("S_ave Log"), /* Display label */
478 NULL
, /* short-cut */
480 G_CALLBACK(on_menu_save_log_activate
) /* action callback */
483 "ActionValgrindEditRules", /* Action name */
484 NULL
, /* Stock icon, if any */
485 N_("Edit Rules"), /* Display label */
486 NULL
, /* short-cut */
488 G_CALLBACK(on_menu_editrules_activate
) /* action callback */
494 valgrind_set_busy_status (AnjutaValgrindPlugin
*plugin
, gboolean status
) {
495 plugin
->is_busy
= status
;
499 /*-----------------------------------------------------------------------------
500 * we adjourn the Debug->Valgrind->* menu status [i.e. sensitive or not].
503 valgrind_update_ui (AnjutaValgrindPlugin
*plugin
)
508 ui
= anjuta_shell_get_ui (ANJUTA_PLUGIN (plugin
)->shell
, NULL
);
510 action
= anjuta_ui_get_action (ui
, "ActionGroupValgrind",
511 "ActionValgrindRun");
512 g_object_set (G_OBJECT (action
), "sensitive",
513 !plugin
->is_busy
, NULL
);
515 action
= anjuta_ui_get_action (ui
, "ActionGroupValgrind",
516 "ActionValgrindKill");
517 g_object_set (G_OBJECT (action
), "sensitive",
518 plugin
->is_busy
, NULL
);
520 action
= anjuta_ui_get_action (ui
, "ActionGroupValgrind",
521 "ActionValgrindLoad");
522 g_object_set (G_OBJECT (action
), "sensitive",
523 !plugin
->is_busy
, NULL
);
525 action
= anjuta_ui_get_action (ui
, "ActionGroupValgrind",
526 "ActionValgrindSave");
527 g_object_set (G_OBJECT (action
), "sensitive",
528 !plugin
->is_busy
, NULL
);
533 valgrind_activate (AnjutaPlugin
*plugin
)
536 static gboolean initialized
= FALSE
;
537 AnjutaValgrindPlugin
*valgrind
;
539 DEBUG_PRINT ("AnjutaValgrindPlugin: Activating AnjutaValgrindPlugin plugin ...");
540 valgrind
= ANJUTA_PLUGIN_VALGRIND (plugin
);
543 register_stock_icons (plugin
);
546 /* Add all UI actions and merge UI */
547 ui
= anjuta_shell_get_ui (plugin
->shell
, NULL
);
548 valgrind
->action_group
=
549 anjuta_ui_add_action_group_entries (ui
, "ActionGroupValgrind",
550 _("Use Valgrind debug tool"),
552 G_N_ELEMENTS (actions_file
),
553 GETTEXT_PACKAGE
, TRUE
, plugin
);
554 valgrind
->uiid
= anjuta_ui_merge (ui
, UI_FILE
);
556 /* Create the main valgrind widget [a VgToolView object...]. Do NOT add it now,
557 * but only after a call to run () is made
559 valgrind
->valgrind_widget
= vg_default_view_new (valgrind
);
561 /* And the VgActions */
562 valgrind
->val_actions
= vg_actions_new (valgrind
, &valgrind
->val_prefs
,
563 valgrind
->valgrind_widget
);
565 /* set up project directory watch */
566 valgrind
->project_root_uri
= NULL
;
567 valgrind
->root_watch_id
= anjuta_plugin_add_watch (plugin
,
568 IANJUTA_PROJECT_MANAGER_PROJECT_ROOT_URI
,
570 project_root_removed
, NULL
);
572 /* set busy status to FALSE: while initializing the plugin we're surely not
574 valgrind_set_busy_status (valgrind
, FALSE
);
575 valgrind_update_ui (valgrind
);
578 valgrind
->general_prefs
= valgrind_plugin_prefs_get_anj_prefs ();
579 valgrind
->val_prefs
= valgrind_plugin_prefs_new ();
586 valgrind_deactivate (AnjutaPlugin
*plugin
)
589 AnjutaValgrindPlugin
* valgrind
;
591 valgrind
= ANJUTA_PLUGIN_VALGRIND (plugin
);
593 DEBUG_PRINT ("AnjutaValgrindPlugin: Dectivating AnjutaValgrindPlugin plugin ...");
595 if ( valgrind
->valgrind_displayed
) {
596 valgrind
->valgrind_displayed
= FALSE
;
597 anjuta_shell_remove_widget (plugin
->shell
, valgrind
->valgrind_widget
, NULL
);
600 ui
= anjuta_shell_get_ui (plugin
->shell
, NULL
);
602 anjuta_plugin_remove_watch (plugin
, valgrind
->root_watch_id
, TRUE
);
603 anjuta_ui_unmerge (ui
, valgrind
->uiid
);
604 anjuta_ui_remove_action_group (ui
, valgrind
->action_group
);
606 /* unref VgToolView object */
607 g_object_unref (valgrind
->val_actions
);
613 valgrind_finalize (GObject
*obj
)
615 /* Finalization codes here */
616 G_OBJECT_CLASS (parent_class
)->finalize (obj
);
620 valgrind_dispose (GObject
*obj
)
622 /* Disposition codes */
623 G_OBJECT_CLASS (parent_class
)->dispose (obj
);
627 anjuta_valgrind_plugin_instance_init (GObject
*obj
)
629 AnjutaValgrindPlugin
*plugin
= ANJUTA_PLUGIN_VALGRIND (obj
);
633 plugin
->valgrind_widget
= NULL
;
634 plugin
->general_prefs
= NULL
;
635 plugin
->valgrind_displayed
= FALSE
;
639 anjuta_valgrind_plugin_class_init (GObjectClass
*klass
)
641 AnjutaPluginClass
*plugin_class
= ANJUTA_PLUGIN_CLASS (klass
);
643 parent_class
= g_type_class_peek_parent (klass
);
645 plugin_class
->activate
= valgrind_activate
;
646 plugin_class
->deactivate
= valgrind_deactivate
;
647 klass
->finalize
= valgrind_finalize
;
648 klass
->dispose
= valgrind_dispose
;
652 ipreferences_merge(IAnjutaPreferences
* ipref
, AnjutaPreferences
* prefs
, GError
** e
)
655 AnjutaValgrindPlugin
* valgrind
= ANJUTA_PLUGIN_VALGRIND (ipref
);
657 pixbuf
= gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR
"/"ICON_FILE
, NULL
);
659 gtk_widget_show (valgrind
->general_prefs
);
660 anjuta_preferences_dialog_add_page (ANJUTA_PREFERENCES_DIALOG (anjuta_preferences_get_dialog (prefs
)),
661 "Valgrind", _("Valgrind"), pixbuf
, valgrind
->general_prefs
);
662 g_object_unref (pixbuf
);
666 ipreferences_unmerge(IAnjutaPreferences
* ipref
, AnjutaPreferences
* prefs
, GError
** e
)
668 AnjutaValgrindPlugin
* valgrind
= ANJUTA_PLUGIN_VALGRIND (ipref
);
669 anjuta_preferences_dialog_remove_page(ANJUTA_PREFERENCES_DIALOG (anjuta_preferences_get_dialog (prefs
)),
671 /* Recreate object as it gets destroyed in the remove_page method */
672 valgrind
->general_prefs
= valgrind_plugin_prefs_get_anj_prefs ();
676 ipreferences_iface_init(IAnjutaPreferencesIface
* iface
)
678 iface
->merge
= ipreferences_merge
;
679 iface
->unmerge
= ipreferences_unmerge
;
682 ANJUTA_PLUGIN_BEGIN (AnjutaValgrindPlugin
, anjuta_valgrind_plugin
);
683 ANJUTA_PLUGIN_ADD_INTERFACE(ipreferences
, IANJUTA_TYPE_PREFERENCES
);
686 ANJUTA_SIMPLE_PLUGIN (AnjutaValgrindPlugin
, anjuta_valgrind_plugin
);