/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ /* * watch.c Copyright (C) 2000 Kh. Naba Kumar Singh * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include "watch.h" #include "debug_tree.h" #include "plugin.h" /*#define DEBUG*/ #include <libanjuta/anjuta-debug.h> #include <libanjuta/interfaces/ianjuta-editor-selection.h> #include <libanjuta/interfaces/ianjuta-editor.h> #include <libanjuta/interfaces/ianjuta-document-manager.h> /* Type *---------------------------------------------------------------------------*/ struct _ExprWatch { AnjutaPlugin *plugin; GtkWidget *scrolledwindow; DebugTree *debug_tree; IAnjutaDebugger *debugger; /* Menu action */ GtkActionGroup *action_group; GtkActionGroup *toggle_group; }; struct _InspectDialog { DebugTree *tree; GtkWidget *treeview; GtkWidget *dialog; }; typedef struct _InspectDialog InspectDialog; /* Widget and signal name found in glade file *---------------------------------------------------------------------------*/ #define ADD_WATCH_DIALOG "add_watch_dialog" #define CHANGE_WATCH_DIALOG "change_watch_dialog" #define INSPECT_EVALUATE_DIALOG "watch_dialog" #define NAME_ENTRY "name_entry" #define VALUE_ENTRY "value_entry" #define VALUE_TREE "value_treeview" #define AUTO_UPDATE_CHECK "auto_update_check" /* Private functions *---------------------------------------------------------------------------*/ #if 0 static void on_entry_updated (const gchar *value, gpointer user_data, GError *err) { GtkWidget *entry = GTK_WIDGET (user_data); gtk_entry_set_text (GTK_ENTRY (entry), value); gtk_widget_unref (entry); } #endif static void debug_tree_inspect_evaluate_dialog (ExprWatch * ew, const gchar* expression) { GladeXML *gxml; gint reply; gchar *new_expr; // const gchar *value; InspectDialog dlg; IAnjutaDebuggerVariable var = {NULL, NULL, NULL, NULL, FALSE, -1}; gxml = glade_xml_new (GLADE_FILE, INSPECT_EVALUATE_DIALOG, NULL); dlg.dialog = glade_xml_get_widget (gxml, INSPECT_EVALUATE_DIALOG); gtk_window_set_transient_for (GTK_WINDOW (dlg.dialog), NULL); dlg.treeview = glade_xml_get_widget (gxml, VALUE_TREE); g_object_unref (gxml); /* Create debug tree */ dlg.tree = debug_tree_new_with_view (ANJUTA_PLUGIN (ew->plugin), GTK_TREE_VIEW (dlg.treeview)); if (ew->debugger) debug_tree_connect (dlg.tree, ew->debugger); if (expression != NULL) { var.expression = (gchar *)expression; debug_tree_add_watch (dlg.tree, &var, FALSE); } else { debug_tree_add_dummy (dlg.tree, NULL); } for(;;) { reply = gtk_dialog_run (GTK_DIALOG (dlg.dialog)); switch (reply) { case GTK_RESPONSE_OK: /* Add in watch window */ new_expr = debug_tree_get_first (dlg.tree); if (new_expr != NULL) { var.expression = new_expr; debug_tree_add_watch (ew->debug_tree, &var, FALSE); g_free (new_expr); } break; default: break; } break; } debug_tree_free (dlg.tree); gtk_widget_destroy (dlg.dialog); } static void debug_tree_add_watch_dialog (ExprWatch *ew, const gchar* expression) { GladeXML *gxml; GtkWidget *dialog; GtkWidget *name_entry; GtkWidget *auto_update_check; gint reply; IAnjutaDebuggerVariable var = {NULL, NULL, NULL, NULL, FALSE, -1}; gxml = glade_xml_new (GLADE_FILE, ADD_WATCH_DIALOG, NULL); dialog = glade_xml_get_widget (gxml, ADD_WATCH_DIALOG); gtk_window_set_transient_for (GTK_WINDOW (dialog), NULL); auto_update_check = glade_xml_get_widget (gxml, AUTO_UPDATE_CHECK); name_entry = glade_xml_get_widget (gxml, NAME_ENTRY); g_object_unref (gxml); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (auto_update_check), TRUE); gtk_entry_set_text (GTK_ENTRY (name_entry), expression == NULL ? "" : expression); reply = gtk_dialog_run (GTK_DIALOG (dialog)); if (reply == GTK_RESPONSE_OK) { var.expression = (gchar *)gtk_entry_get_text (GTK_ENTRY (name_entry)); debug_tree_add_watch (ew->debug_tree, &var, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (auto_update_check))); } gtk_widget_destroy (dialog); } static void debug_tree_change_watch_dialog (ExprWatch *ew, GtkTreeIter* iter) { #if 0 GladeXML *gxml; GtkWidget *dialog; GtkWidget *name_entry; GtkWidget *value_entry; gint reply; TrimmableItem *item = NULL; GtkTreeModel* model = NULL; model = gtk_tree_view_get_model(d_tree->view); gtk_tree_model_get (model, iter, ITEM_COLUMN, &item, -1); gxml = glade_xml_new (GLADE_FILE, CHANGE_WATCH_DIALOG, NULL); dialog = glade_xml_get_widget (gxml, CHANGE_WATCH_DIALOG); gtk_window_set_transient_for (GTK_WINDOW (dialog), NULL); name_entry = glade_xml_get_widget (gxml, NAME_ENTRY); value_entry = glade_xml_get_widget (gxml, VALUE_ENTRY); g_object_unref (gxml); gtk_widget_grab_focus (value_entry); gtk_entry_set_text (GTK_ENTRY (name_entry), &item->name[1]); gtk_entry_set_text (GTK_ENTRY (value_entry), item->value); reply = gtk_dialog_run (GTK_DIALOG (dialog)); if (reply == GTK_RESPONSE_APPLY) { debug_tree_evaluate (d_tree, iter, gtk_entry_get_text (GTK_ENTRY (value_entry))); } gtk_widget_destroy (dialog); #endif } /* Menu call backs *---------------------------------------------------------------------------*/ static void on_debug_tree_inspect (GtkAction *action, gpointer user_data) { ExprWatch * ew = (ExprWatch *)user_data; GObject *obj; IAnjutaDocumentManager *docman = NULL; IAnjutaEditor *te = NULL; gchar *expression = NULL; /* Get current editor and line */ obj = anjuta_shell_get_object (ANJUTA_PLUGIN (ew->plugin)->shell, "IAnjutaDocumentManager", NULL /* TODO */); docman = IANJUTA_DOCUMENT_MANAGER (obj); if (docman != NULL) { te = ianjuta_document_manager_get_current_editor (docman, NULL); expression = ianjuta_editor_selection_get (IANJUTA_EDITOR_SELECTION (te), NULL); if (expression == NULL) { expression = ianjuta_editor_get_current_word (IANJUTA_EDITOR (te), NULL); } } debug_tree_inspect_evaluate_dialog (ew, expression); g_free (expression); } static void on_debug_tree_add_watch (GtkAction *action, gpointer user_data) { ExprWatch * ew = (ExprWatch *)user_data; debug_tree_add_watch_dialog (ew, NULL); } static void on_debug_tree_remove_watch (GtkAction *action, gpointer user_data) { ExprWatch * ew = (ExprWatch *)user_data; GtkTreeIter iter; if (debug_tree_get_current (ew->debug_tree, &iter)) { debug_tree_remove (ew->debug_tree, &iter); } } static void on_debug_tree_update_watch (GtkAction *action, gpointer user_data) { ExprWatch * ew = (ExprWatch *)user_data; GtkTreeIter iter; if (debug_tree_get_current (ew->debug_tree, &iter)) { debug_tree_update (ew->debug_tree, &iter, TRUE); } } static void on_debug_tree_auto_update_watch (GtkAction *action, gpointer user_data) { ExprWatch * ew = (ExprWatch *)user_data; GtkTreeIter iter; if (debug_tree_get_current (ew->debug_tree, &iter)) { gboolean state; state = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); debug_tree_set_auto_update (ew->debug_tree, &iter, state); } } static void on_debug_tree_edit_watch (GtkAction *action, gpointer user_data) { ExprWatch * ew = (ExprWatch *)user_data; GtkTreeIter iter; if (debug_tree_get_current (ew->debug_tree, &iter)) { debug_tree_change_watch_dialog (ew, &iter); } } static void on_debug_tree_update_all_watch (GtkAction *action, gpointer user_data) { ExprWatch * ew = (ExprWatch *)user_data; debug_tree_update_all (ew->debug_tree); } static void on_debug_tree_remove_all_watch (GtkAction *action, gpointer user_data) { ExprWatch * ew = (ExprWatch *)user_data; debug_tree_remove_all (ew->debug_tree); } static gboolean on_debug_tree_button_press (GtkWidget *widget, GdkEventButton *bevent, gpointer user_data) { ExprWatch * ew = (ExprWatch *)user_data; if (bevent->button == 3) { GtkAction *action; AnjutaUI *ui; GtkTreeIter iter; GtkWidget *middle_click_menu; ui = anjuta_shell_get_ui (ew->plugin->shell, NULL); action = anjuta_ui_get_action (ui, "ActionGroupWatchToggle", "ActionDmaAutoUpdateWatch"); if (debug_tree_get_current (ew->debug_tree, &iter)) { gtk_action_set_sensitive (GTK_ACTION (action), TRUE); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), debug_tree_get_auto_update (ew->debug_tree, &iter)); } else { gtk_action_set_sensitive (GTK_ACTION (action), FALSE); } action = anjuta_ui_get_action (ui, "ActionGroupWatch", "ActionDmaEditWatch"); gtk_action_set_sensitive (GTK_ACTION (action), FALSE); // FIXME: Not implemented middle_click_menu = gtk_ui_manager_get_widget (GTK_UI_MANAGER (ui), "/PopupWatch"); g_return_val_if_fail (middle_click_menu != NULL, FALSE); gtk_menu_popup (GTK_MENU (middle_click_menu), NULL, NULL, NULL, NULL, bevent->button, bevent->time); } return FALSE; } /* Actions table *---------------------------------------------------------------------------*/ static GtkActionEntry actions_watch[] = { { "ActionDmaInspect", /* Action name */ GTK_STOCK_DIALOG_INFO, /* Stock icon, if any */ N_("Ins_pect/Evaluate..."), /* Display label */ NULL, /* short-cut */ N_("Inspect or evaluate an expression or variable"), /* Tooltip */ G_CALLBACK (on_debug_tree_inspect) /* action callback */ }, { "ActionDmaAddWatch", NULL, N_("Add Watch..."), NULL, NULL, G_CALLBACK (on_debug_tree_add_watch) }, { "ActionDmaRemoveWatch", NULL, N_("Remove Watch"), NULL, NULL, G_CALLBACK (on_debug_tree_remove_watch) }, { "ActionDmaUpdateWatch", NULL, N_("Update Watch"), NULL, NULL, G_CALLBACK (on_debug_tree_update_watch) }, { "ActionDmaEditWatch", NULL, N_("Change Value"), NULL, NULL, G_CALLBACK (on_debug_tree_edit_watch) }, { "ActionDmaUpdateAllWatch", NULL, N_("Update all"), NULL, NULL, G_CALLBACK (on_debug_tree_update_all_watch) }, { "ActionDmaRemoveAllWatch", NULL, N_("Remove all"), NULL, NULL, G_CALLBACK (on_debug_tree_remove_all_watch) } }; static GtkToggleActionEntry toggle_watch[] = { { "ActionDmaAutoUpdateWatch", /* Action name */ NULL, /* Stock icon, if any */ N_("Automatic update"), /* Display label */ NULL, /* short-cut */ NULL, /* Tooltip */ G_CALLBACK (on_debug_tree_auto_update_watch), /* action callback */ FALSE /* Initial state */ } }; static void create_expr_watch_gui (ExprWatch * ew) { AnjutaUI *ui; ew->debug_tree = debug_tree_new (ew->plugin); ew->scrolledwindow = gtk_scrolled_window_new (NULL, NULL); gtk_widget_show (ew->scrolledwindow); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (ew->scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (ew->scrolledwindow), GTK_SHADOW_IN); gtk_container_add (GTK_CONTAINER (ew->scrolledwindow), debug_tree_get_tree_widget (ew->debug_tree)); ui = anjuta_shell_get_ui (ew->plugin->shell, NULL); ew->action_group = anjuta_ui_add_action_group_entries (ui, "ActionGroupWatch", _("Watch operations"), actions_watch, G_N_ELEMENTS (actions_watch), GETTEXT_PACKAGE, TRUE, ew); ew->toggle_group = anjuta_ui_add_toggle_action_group_entries (ui, "ActionGroupWatchToggle", _("Watch operations"), toggle_watch, G_N_ELEMENTS (toggle_watch), GETTEXT_PACKAGE, TRUE, ew); g_signal_connect (debug_tree_get_tree_widget (ew->debug_tree), "button-press-event", G_CALLBACK (on_debug_tree_button_press), ew); gtk_widget_show_all (ew->scrolledwindow); } /* Public function *---------------------------------------------------------------------------*/ void expr_watch_cmd_queqe (ExprWatch *ew) { debug_tree_update_all (ew->debug_tree); } void expr_watch_connect (ExprWatch *ew, IAnjutaDebugger *debugger) { ew->debugger = debugger; debug_tree_connect (ew->debug_tree, debugger); } /* Callback for saving session *---------------------------------------------------------------------------*/ static void on_session_save (AnjutaShell *shell, AnjutaSessionPhase phase, AnjutaSession *session, ExprWatch *ew) { GList *list; if (phase != ANJUTA_SESSION_PHASE_NORMAL) return; list = debug_tree_get_full_watch_list (ew->debug_tree); if (list != NULL) anjuta_session_set_string_list (session, "Debugger", "Watch", list); g_list_foreach (list, (GFunc)g_free, NULL); g_list_free (list); } static void on_session_load (AnjutaShell *shell, AnjutaSessionPhase phase, AnjutaSession *session, ExprWatch *ew) { GList *list; if (phase != ANJUTA_SESSION_PHASE_NORMAL) return; /* debug_tree_remove_all (ew->debug_tree); */ list = anjuta_session_get_string_list (session, "Debugger", "Watch"); if (list != NULL) debug_tree_add_full_watch_list (ew->debug_tree, list); } /* Constructor & Destructor *---------------------------------------------------------------------------*/ ExprWatch * expr_watch_new (AnjutaPlugin *plugin, IAnjutaDebugger *debugger) { ExprWatch *ew; ew = g_new0 (ExprWatch, 1); ew->plugin = plugin; create_expr_watch_gui (ew); g_object_ref (debugger); ew->debugger = debugger; /* Connect to Load and Save event */ g_signal_connect (plugin->shell, "save-session", G_CALLBACK (on_session_save), ew); g_signal_connect (plugin->shell, "load-session", G_CALLBACK (on_session_load), ew); /* Add watch window */ anjuta_shell_add_widget (plugin->shell, ew->scrolledwindow, "AnjutaDebuggerWatch", _("Watches"), "gdb-watch-icon", ANJUTA_SHELL_PLACEMENT_BOTTOM, NULL); return ew; } void expr_watch_destroy (ExprWatch * ew) { AnjutaUI *ui; g_return_if_fail (ew != NULL); /* Disconnect from Load and Save event */ g_signal_handlers_disconnect_by_func (ew->plugin->shell, G_CALLBACK (on_session_save), ew); g_signal_handlers_disconnect_by_func (ew->plugin->shell, G_CALLBACK (on_session_load), ew); ui = anjuta_shell_get_ui (ew->plugin->shell, NULL); anjuta_ui_remove_action_group (ui, ew->action_group); anjuta_ui_remove_action_group (ui, ew->toggle_group); debug_tree_free (ew->debug_tree); gtk_widget_destroy (ew->scrolledwindow); g_free (ew); }