1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
3 * watch.c Copyright (C) 2000 Kh. Naba Kumar Singh
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc.,
17 * 59 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "debug_tree.h"
26 #include "utilities.h"
28 #include <glib/gi18n.h>
29 #include <libanjuta/anjuta-debug.h>
30 #include <libanjuta/interfaces/ianjuta-editor-selection.h>
31 #include <libanjuta/interfaces/ianjuta-editor.h>
32 #include <libanjuta/interfaces/ianjuta-document-manager.h>
35 *---------------------------------------------------------------------------*/
41 GtkWidget
*scrolledwindow
;
42 DebugTree
*debug_tree
;
43 DmaDebuggerQueue
*debugger
;
46 GtkActionGroup
*action_group
;
47 GtkActionGroup
*toggle_group
;
57 typedef struct _InspectDialog InspectDialog
;
59 /* Widget and signal name found in glade file
60 *---------------------------------------------------------------------------*/
62 #define ADD_WATCH_DIALOG "add_watch_dialog"
63 #define CHANGE_WATCH_DIALOG "change_watch_dialog"
64 #define INSPECT_EVALUATE_DIALOG "watch_dialog"
65 #define VALUE_TREE "watch_value_treeview"
66 #define NAME_ENTRY "add_watch_name_entry"
67 #define VALUE_ENTRY "value_entry"
68 #define AUTO_UPDATE_CHECK "auto_update_check"
76 static const GtkTargetEntry drag_targets
[] = {
77 {"application-x/anjuta", GTK_TARGET_SAME_APP
, TARGET_STRING
},
78 { "STRING", GTK_TARGET_SAME_APP
, TARGET_STRING
},
79 { "text/plain", GTK_TARGET_SAME_APP
, TARGET_STRING
},
80 { "text/uri-list", GTK_TARGET_SAME_APP
, TARGET_URL
}
84 *---------------------------------------------------------------------------*/
87 debug_tree_inspect_evaluate_dialog (ExprWatch
* ew
, const gchar
* expression
)
93 IAnjutaDebuggerVariableObject var
= {NULL
, NULL
, NULL
, NULL
, FALSE
, FALSE
, FALSE
, -1};
95 bxml
= anjuta_util_builder_new (GLADE_FILE
, NULL
);
97 anjuta_util_builder_get_objects (bxml
,
98 INSPECT_EVALUATE_DIALOG
, &dlg
.dialog
,
99 VALUE_TREE
, &dlg
.treeview
,
101 g_object_unref (bxml
);
102 gtk_window_set_transient_for (GTK_WINDOW (dlg
.dialog
), NULL
);
104 /* Create debug tree */
105 dlg
.tree
= debug_tree_new_with_view (ANJUTA_PLUGIN (ew
->plugin
), GTK_TREE_VIEW (dlg
.treeview
));
107 debug_tree_connect (dlg
.tree
, ew
->debugger
);
108 if (expression
!= NULL
)
110 var
.expression
= (gchar
*)expression
;
111 debug_tree_add_watch (dlg
.tree
, &var
, FALSE
);
115 debug_tree_add_dummy (dlg
.tree
, NULL
);
120 reply
= gtk_dialog_run (GTK_DIALOG (dlg
.dialog
));
123 case GTK_RESPONSE_OK
:
124 /* Add in watch window */
125 new_expr
= debug_tree_get_first (dlg
.tree
);
127 if ((new_expr
!= NULL
) && (strlen(new_expr
) != 0))
129 var
.expression
= new_expr
;
130 debug_tree_add_watch (ew
->debug_tree
, &var
, FALSE
);
139 debug_tree_free (dlg
.tree
);
140 gtk_widget_destroy (dlg
.dialog
);
144 debug_tree_add_watch_dialog (ExprWatch
*ew
, const gchar
* expression
)
148 GtkWidget
*name_entry
;
149 GtkWidget
*auto_update_check
;
151 IAnjutaDebuggerVariableObject var
= {NULL
, NULL
, NULL
, NULL
, FALSE
, FALSE
, FALSE
, -1};
154 bxml
= anjuta_util_builder_new (GLADE_FILE
, NULL
);
156 anjuta_util_builder_get_objects (bxml
,
157 ADD_WATCH_DIALOG
, &dialog
,
158 AUTO_UPDATE_CHECK
, &auto_update_check
,
159 NAME_ENTRY
, &name_entry
,
161 g_object_unref (bxml
);
163 gtk_window_set_transient_for (GTK_WINDOW (dialog
),
166 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (auto_update_check
), TRUE
);
167 gtk_entry_set_text (GTK_ENTRY (name_entry
), expression
== NULL
? "" : expression
);
169 reply
= gtk_dialog_run (GTK_DIALOG (dialog
));
170 if (reply
== GTK_RESPONSE_OK
)
172 var
.expression
= (gchar
*)gtk_entry_get_text (GTK_ENTRY (name_entry
));
173 debug_tree_add_watch (ew
->debug_tree
, &var
,
174 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (auto_update_check
)));
176 gtk_widget_destroy (dialog
);
180 debug_tree_change_watch_dialog (ExprWatch
*ew
, GtkTreeIter
* iter
)
185 GtkWidget
*name_entry
;
186 GtkWidget
*value_entry
;
188 TrimmableItem
*item
= NULL
;
189 GtkTreeModel
* model
= NULL
;
191 model
= gtk_tree_view_get_model(d_tree
->view
);
192 gtk_tree_model_get (model
, iter
, ITEM_COLUMN
, &item
, -1);
194 gxml
= glade_xml_new (GLADE_FILE
, CHANGE_WATCH_DIALOG
, NULL
);
195 dialog
= glade_xml_get_widget (gxml
, CHANGE_WATCH_DIALOG
);
196 gtk_window_set_transient_for (GTK_WINDOW (dialog
),
198 name_entry
= glade_xml_get_widget (gxml
, NAME_ENTRY
);
199 value_entry
= glade_xml_get_widget (gxml
, VALUE_ENTRY
);
200 g_object_unref (gxml
);
202 gtk_widget_grab_focus (value_entry
);
203 gtk_entry_set_text (GTK_ENTRY (name_entry
), &item
->name
[1]);
204 gtk_entry_set_text (GTK_ENTRY (value_entry
), item
->value
);
206 reply
= gtk_dialog_run (GTK_DIALOG (dialog
));
207 if (reply
== GTK_RESPONSE_APPLY
)
209 debug_tree_evaluate (d_tree
, iter
, gtk_entry_get_text (GTK_ENTRY (value_entry
)));
211 gtk_widget_destroy (dialog
);
216 on_program_exited (ExprWatch
*ew
)
218 debug_tree_disconnect (ew
->debug_tree
);
220 /* Disconnect to other debugger signal */
221 g_signal_handlers_disconnect_by_func (ew
->plugin
, G_CALLBACK (on_program_exited
), ew
);
225 on_program_started (ExprWatch
*ew
)
227 if (!dma_debugger_queue_is_supported (ew
->debugger
, HAS_VARIABLE
)) return;
229 debug_tree_connect (ew
->debug_tree
, ew
->debugger
);
231 /* Connect to other debugger signal */
232 g_signal_connect_swapped (ew
->plugin
, "program-exited", G_CALLBACK (on_program_exited
), ew
);
236 *---------------------------------------------------------------------------*/
239 on_debug_tree_inspect (GtkAction
*action
, gpointer user_data
)
241 ExprWatch
* ew
= (ExprWatch
*)user_data
;
242 IAnjutaEditor
*te
= NULL
;
243 gchar
*expression
= NULL
;
245 /* Get current editor and line */
246 te
= dma_get_current_editor (ANJUTA_PLUGIN (ew
->plugin
));
247 if (te
== NULL
) return;
249 expression
= ianjuta_editor_selection_get (IANJUTA_EDITOR_SELECTION (te
), NULL
);
250 if (expression
== NULL
)
252 expression
= ianjuta_editor_get_current_word (IANJUTA_EDITOR (te
), NULL
);
254 if (g_regex_match_simple("^\\s*$", expression
,G_REGEX_MULTILINE
| G_REGEX_DOLLAR_ENDONLY
, G_REGEX_MATCH_ANCHORED
))
259 debug_tree_inspect_evaluate_dialog (ew
, expression
);
264 on_debug_tree_add_watch (GtkAction
*action
, gpointer user_data
)
266 ExprWatch
* ew
= (ExprWatch
*)user_data
;
268 debug_tree_add_watch_dialog (ew
, NULL
);
272 on_debug_tree_remove_watch (GtkAction
*action
, gpointer user_data
)
274 ExprWatch
* ew
= (ExprWatch
*)user_data
;
277 if (debug_tree_get_current (ew
->debug_tree
, &iter
))
279 debug_tree_remove (ew
->debug_tree
, &iter
);
284 on_debug_tree_update_watch (GtkAction
*action
, gpointer user_data
)
286 ExprWatch
* ew
= (ExprWatch
*)user_data
;
289 if (debug_tree_get_current (ew
->debug_tree
, &iter
))
291 debug_tree_update (ew
->debug_tree
, &iter
, TRUE
);
296 on_debug_tree_auto_update_watch (GtkAction
*action
, gpointer user_data
)
298 ExprWatch
* ew
= (ExprWatch
*)user_data
;
301 if (debug_tree_get_current (ew
->debug_tree
, &iter
))
305 state
= gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action
));
306 debug_tree_set_auto_update (ew
->debug_tree
, &iter
, state
);
311 on_debug_tree_edit_watch (GtkAction
*action
, gpointer user_data
)
313 ExprWatch
* ew
= (ExprWatch
*)user_data
;
316 if (debug_tree_get_current (ew
->debug_tree
, &iter
))
318 debug_tree_change_watch_dialog (ew
, &iter
);
323 on_debug_tree_update_all_watch (GtkAction
*action
, gpointer user_data
)
325 ExprWatch
* ew
= (ExprWatch
*)user_data
;
327 debug_tree_update_tree (ew
->debug_tree
);
331 on_debug_tree_remove_all_watch (GtkAction
*action
, gpointer user_data
)
333 ExprWatch
* ew
= (ExprWatch
*)user_data
;
335 debug_tree_remove_all (ew
->debug_tree
);
339 on_debug_tree_button_press (GtkWidget
*widget
, GdkEventButton
*bevent
, gpointer user_data
)
341 ExprWatch
* ew
= (ExprWatch
*)user_data
;
343 if (bevent
->button
== 3)
348 GtkWidget
*middle_click_menu
;
350 ui
= anjuta_shell_get_ui (ew
->plugin
->shell
, NULL
);
351 action
= anjuta_ui_get_action (ui
, "ActionGroupWatchToggle", "ActionDmaAutoUpdateWatch");
352 if (debug_tree_get_current (ew
->debug_tree
, &iter
))
354 gtk_action_set_sensitive (GTK_ACTION (action
), TRUE
);
355 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action
), debug_tree_get_auto_update (ew
->debug_tree
, &iter
));
359 gtk_action_set_sensitive (GTK_ACTION (action
), FALSE
);
362 action
= anjuta_ui_get_action (ui
, "ActionGroupWatch", "ActionDmaEditWatch");
363 gtk_action_set_sensitive (GTK_ACTION (action
), FALSE
); // FIXME: Not implemented
365 middle_click_menu
= gtk_ui_manager_get_widget (GTK_UI_MANAGER (ui
), "/PopupWatch");
366 g_return_val_if_fail (middle_click_menu
!= NULL
, FALSE
);
367 gtk_menu_popup (GTK_MENU (middle_click_menu
), NULL
, NULL
, NULL
, NULL
,
368 bevent
->button
, bevent
->time
);
375 on_debug_tree_drag_data_received (GtkWidget
*widget
,
376 GdkDragContext
*context
,
379 GtkSelectionData
*selection_data
,
384 const gchar
* signal_data
= (gchar
*) gtk_selection_data_get_data (selection_data
);
385 IAnjutaDebuggerVariableObject var
= {NULL
, NULL
, NULL
, NULL
, FALSE
, FALSE
, FALSE
, -1};
387 if (signal_data
!= NULL
)
389 var
.expression
= (gchar
*)signal_data
;
390 debug_tree_add_watch (((ExprWatch
*)user_data
)->debug_tree
, &var
, FALSE
);
393 gtk_drag_finish (context
, FALSE
, FALSE
, timestamp
);
400 *---------------------------------------------------------------------------*/
402 static GtkActionEntry actions_watch
[] = {
404 "ActionDmaInspect", /* Action name */
405 GTK_STOCK_DIALOG_INFO
, /* Stock icon, if any */
406 N_("Ins_pect/Evaluate…"), /* Display label */
407 NULL
, /* short-cut */
408 N_("Inspect or evaluate an expression or variable"), /* Tooltip */
409 G_CALLBACK (on_debug_tree_inspect
) /* action callback */
417 G_CALLBACK (on_debug_tree_add_watch
)
420 "ActionDmaRemoveWatch",
425 G_CALLBACK (on_debug_tree_remove_watch
)
428 "ActionDmaUpdateWatch",
433 G_CALLBACK (on_debug_tree_update_watch
)
436 "ActionDmaEditWatch",
441 G_CALLBACK (on_debug_tree_edit_watch
)
444 "ActionDmaUpdateAllWatch",
449 G_CALLBACK (on_debug_tree_update_all_watch
)
452 "ActionDmaRemoveAllWatch",
457 G_CALLBACK (on_debug_tree_remove_all_watch
)
461 static GtkToggleActionEntry toggle_watch
[] = {
463 "ActionDmaAutoUpdateWatch", /* Action name */
464 NULL
, /* Stock icon, if any */
465 N_("Automatic update"), /* Display label */
466 NULL
, /* short-cut */
468 G_CALLBACK (on_debug_tree_auto_update_watch
), /* action callback */
469 FALSE
/* Initial state */
474 create_expr_watch_gui (ExprWatch
* ew
)
478 ew
->debug_tree
= debug_tree_new (ew
->plugin
);
479 ew
->scrolledwindow
= gtk_scrolled_window_new (NULL
, NULL
);
480 gtk_widget_show (ew
->scrolledwindow
);
481 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (ew
->scrolledwindow
),
482 GTK_POLICY_AUTOMATIC
,
483 GTK_POLICY_AUTOMATIC
);
484 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (ew
->scrolledwindow
),
486 gtk_container_add (GTK_CONTAINER (ew
->scrolledwindow
), debug_tree_get_tree_widget (ew
->debug_tree
));
488 ui
= anjuta_shell_get_ui (ew
->plugin
->shell
, NULL
);
490 anjuta_ui_add_action_group_entries (ui
, "ActionGroupWatch",
491 _("Watch operations"),
493 G_N_ELEMENTS (actions_watch
),
494 GETTEXT_PACKAGE
, TRUE
, ew
);
496 anjuta_ui_add_toggle_action_group_entries (ui
, "ActionGroupWatchToggle",
497 _("Watch operations"),
499 G_N_ELEMENTS (toggle_watch
),
500 GETTEXT_PACKAGE
, TRUE
, ew
);
501 g_signal_connect (debug_tree_get_tree_widget (ew
->debug_tree
), "button-press-event", G_CALLBACK (on_debug_tree_button_press
), ew
);
503 gtk_drag_dest_set(debug_tree_get_tree_widget (ew
->debug_tree
), GTK_DEST_DEFAULT_ALL
, drag_targets
, sizeof (drag_targets
) / sizeof (drag_targets
[0]), GDK_ACTION_COPY
|GDK_ACTION_MOVE
|GDK_ACTION_LINK
);
504 g_signal_connect (debug_tree_get_tree_widget (ew
->debug_tree
), "drag_data_received", G_CALLBACK (on_debug_tree_drag_data_received
), ew
);
506 gtk_widget_show_all (ew
->scrolledwindow
);
510 *---------------------------------------------------------------------------*/
513 expr_watch_find_variable_value (ExprWatch
*ew
, const gchar
*name
)
515 return debug_tree_find_variable_value (ew
->debug_tree
, name
);
518 /* Callback for saving session
519 *---------------------------------------------------------------------------*/
522 on_session_save (AnjutaShell
*shell
, AnjutaSessionPhase phase
, AnjutaSession
*session
, ExprWatch
*ew
)
526 if (phase
!= ANJUTA_SESSION_PHASE_NORMAL
)
529 list
= debug_tree_get_full_watch_list (ew
->debug_tree
);
531 anjuta_session_set_string_list (session
, "Debugger", "Watch", list
);
532 g_list_foreach (list
, (GFunc
)g_free
, NULL
);
537 on_session_load (AnjutaShell
*shell
, AnjutaSessionPhase phase
, AnjutaSession
*session
, ExprWatch
*ew
)
541 if (phase
!= ANJUTA_SESSION_PHASE_NORMAL
)
544 debug_tree_remove_all (ew
->debug_tree
);
545 list
= anjuta_session_get_string_list (session
, "Debugger", "Watch");
547 debug_tree_add_full_watch_list (ew
->debug_tree
, list
);
550 /* Constructor & Destructor
551 *---------------------------------------------------------------------------*/
554 expr_watch_new (AnjutaPlugin
*plugin
)
558 ew
= g_new0 (ExprWatch
, 1);
560 create_expr_watch_gui (ew
);
561 ew
->debugger
= dma_debug_manager_get_queue (ANJUTA_PLUGIN_DEBUG_MANAGER (plugin
));
563 /* Connect to Load and Save event */
564 g_signal_connect (ew
->plugin
->shell
, "save-session",
565 G_CALLBACK (on_session_save
), ew
);
566 g_signal_connect (ew
->plugin
->shell
, "load-session",
567 G_CALLBACK (on_session_load
), ew
);
569 /* Add watch window */
570 anjuta_shell_add_widget (ew
->plugin
->shell
,
572 "AnjutaDebuggerWatch", _("Watches"),
573 "gdb-watch-icon", ANJUTA_SHELL_PLACEMENT_BOTTOM
,
576 /* Connect to debugger */
577 g_signal_connect_swapped (ew
->plugin
, "program-started", G_CALLBACK (on_program_started
), ew
);
583 expr_watch_destroy (ExprWatch
* ew
)
587 g_return_if_fail (ew
!= NULL
);
589 /* Disconnect from Load and Save event */
590 g_signal_handlers_disconnect_matched (ew
->plugin
->shell
, G_SIGNAL_MATCH_DATA
, 0, 0, NULL
, NULL
, ew
);
591 g_signal_handlers_disconnect_matched (ew
->plugin
, G_SIGNAL_MATCH_DATA
, 0, 0, NULL
, NULL
, ew
);
593 ui
= anjuta_shell_get_ui (ew
->plugin
->shell
, NULL
);
594 anjuta_ui_remove_action_group (ui
, ew
->action_group
);
595 anjuta_ui_remove_action_group (ui
, ew
->toggle_group
);
597 debug_tree_free (ew
->debug_tree
);
598 gtk_widget_destroy (ew
->scrolledwindow
);