1 /*
2 * local.c
3 *
4 * Copyright 2012 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
5 *
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.
10 *
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.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <string.h>
21
22 #include "common.h"
23
24 enum
25 {
26 LOCAL_NAME,
27 LOCAL_DISPLAY,
28 LOCAL_VALUE,
29 LOCAL_HB_MODE,
30 LOCAL_MR_MODE,
31 LOCAL_ARG1
32 };
33
34 static ScpTreeStore *store;
35 static GtkTreeSelection *selection;
36
on_local_display_edited(G_GNUC_UNUSED GtkCellRendererText * renderer,gchar * path_str,gchar * new_text,G_GNUC_UNUSED gpointer gdata)37 static void on_local_display_edited(G_GNUC_UNUSED GtkCellRendererText *renderer,
38 gchar *path_str, gchar *new_text, G_GNUC_UNUSED gpointer gdata)
39 {
40 view_display_edited(store, thread_state >= THREAD_STOPPED && frame_id, path_str,
41 "07-gdb-set var %s=%s", new_text);
42 }
43
44 static const TreeCell local_cells[] =
45 {
46 { "local_display", G_CALLBACK(on_local_display_edited) },
47 { NULL, NULL }
48 };
49
50 typedef struct _LocalData
51 {
52 char *name;
53 gboolean entry;
54 } LocalData;
55
local_node_variable(const ParseNode * node,const LocalData * ld)56 static void local_node_variable(const ParseNode *node, const LocalData *ld)
57 {
58 iff (node->type == PT_ARRAY, "variables: contains value")
59 {
60 GArray *nodes = (GArray *) node->value;
61 ParseVariable var;
62
63 if (parse_variable(nodes, &var, NULL))
64 {
65 GtkTreeIter iter;
66 const char *arg1 = parse_find_value(nodes, "arg");
67
68 if (!arg1 || ld->entry || !g_str_has_suffix(var.name, "@entry"))
69 {
70 scp_tree_store_append_with_values(store, &iter, NULL, LOCAL_NAME,
71 var.name, LOCAL_DISPLAY, var.display, LOCAL_VALUE, var.value,
72 LOCAL_HB_MODE, var.hb_mode, LOCAL_MR_MODE, var.mr_mode,
73 LOCAL_ARG1, arg1, -1);
74
75 if (!g_strcmp0(var.name, ld->name))
76 gtk_tree_selection_select_iter(selection, &iter);
77 }
78 parse_variable_free(&var);
79 }
80 }
81 }
82
on_local_variables(GArray * nodes)83 void on_local_variables(GArray *nodes)
84 {
85 if (utils_matches_frame(parse_grab_token(nodes)))
86 {
87 GtkTreeIter iter;
88 LocalData ld = { NULL, stack_entry() };
89
90 if (gtk_tree_selection_get_selected(selection, NULL, &iter))
91 gtk_tree_model_get((GtkTreeModel *) store, &iter, LOCAL_NAME, &ld.name, -1);
92
93 locals_clear();
94 parse_foreach(parse_lead_array(nodes), (GFunc) local_node_variable, &ld);
95 g_free(ld.name);
96 }
97 }
98
locals_clear(void)99 void locals_clear(void)
100 {
101 store_clear(store);
102 }
103
locals_send_update(char token)104 static void locals_send_update(char token)
105 {
106 debug_send_format(F, "0%c%c%s%s-stack-list-variables 1", token, FRAME_ARGS);
107 }
108
locals_update(void)109 gboolean locals_update(void)
110 {
111 if (view_stack_update())
112 return FALSE;
113
114 if (frame_id)
115 locals_send_update('4');
116 else
117 locals_clear();
118
119 return TRUE;
120 }
121
122 static GObject *local_display;
123
locals_update_state(DebugState state)124 void locals_update_state(DebugState state)
125 {
126 g_object_set(local_display, "editable", (state & DS_DEBUG) != 0, NULL);
127 }
128
on_local_refresh(G_GNUC_UNUSED const MenuItem * menu_item)129 static void on_local_refresh(G_GNUC_UNUSED const MenuItem *menu_item)
130 {
131 locals_send_update('2');
132 }
133
on_local_unsorted(G_GNUC_UNUSED const MenuItem * menu_item)134 static void on_local_unsorted(G_GNUC_UNUSED const MenuItem *menu_item)
135 {
136 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store),
137 GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
138 }
139
on_local_copy(const MenuItem * menu_item)140 static void on_local_copy(const MenuItem *menu_item)
141 {
142 menu_copy(selection, menu_item);
143 }
144
on_local_modify(const MenuItem * menu_item)145 static void on_local_modify(const MenuItem *menu_item)
146 {
147 menu_modify(selection, menu_item);
148 }
149
on_local_watch(G_GNUC_UNUSED const MenuItem * menu_item)150 static void on_local_watch(G_GNUC_UNUSED const MenuItem *menu_item)
151 {
152 GtkTreeIter iter;
153 const char *name;
154
155 if (gtk_tree_selection_get_selected(selection, NULL, &iter))
156 {
157 scp_tree_store_get(store, &iter, LOCAL_NAME, &name, -1);
158 watch_add(name);
159 }
160 }
161
on_local_inspect(G_GNUC_UNUSED const MenuItem * menu_item)162 static void on_local_inspect(G_GNUC_UNUSED const MenuItem *menu_item)
163 {
164 menu_inspect(selection);
165 }
166
on_local_hbit_display(const MenuItem * menu_item)167 static void on_local_hbit_display(const MenuItem *menu_item)
168 {
169 menu_hbit_display(selection, menu_item);
170 }
171
on_local_hbit_update(const MenuItem * menu_item)172 static void on_local_hbit_update(const MenuItem *menu_item)
173 {
174 menu_hbit_update(selection, menu_item);
175 }
176
on_local_mr_mode(const MenuItem * menu_item)177 static void on_local_mr_mode(const MenuItem *menu_item)
178 {
179 menu_mber_update(selection, menu_item);
180 }
181
182 #define DS_FRESHABLE (DS_DEBUG | DS_EXTRA_2)
183 #define DS_COPYABLE (DS_BASICS | DS_EXTRA_1)
184 #define DS_MODIFYABLE (DS_DEBUG | DS_EXTRA_1)
185 #define DS_WATCHABLE (DS_BASICS | DS_EXTRA_1)
186 #define DS_INSPECTABLE (DS_NOT_BUSY | DS_EXTRA_1)
187 #define DS_REPARSABLE (DS_BASICS | DS_EXTRA_1)
188
189 static MenuItem local_menu_items[] =
190 {
191 { "local_refresh", on_local_refresh, DS_FRESHABLE, NULL, NULL },
192 { "local_unsorted", on_local_unsorted, 0, NULL, NULL },
193 { "local_copy", on_local_copy, DS_COPYABLE, NULL, NULL },
194 { "local_modify", on_local_modify, DS_MODIFYABLE, NULL, NULL },
195 { "local_watch", on_local_watch, DS_WATCHABLE, NULL, NULL },
196 { "local_inspect", on_local_inspect, DS_INSPECTABLE, NULL, NULL },
197 MENU_HBIT_ITEMS(local),
198 { "local_mr_mode", on_local_mr_mode, DS_REPARSABLE, NULL, NULL },
199 { NULL, NULL, 0, NULL, NULL }
200 };
201
local_menu_extra_state(void)202 static guint local_menu_extra_state(void)
203 {
204 return (gtk_tree_selection_get_selected(selection, NULL, NULL) << DS_INDEX_1) |
205 ((frame_id != NULL) << DS_INDEX_2);
206 }
207
208 static MenuInfo local_menu_info = { local_menu_items, local_menu_extra_state, 0 };
209
on_local_menu_show(G_GNUC_UNUSED GtkWidget * widget,G_GNUC_UNUSED gpointer gdata)210 static void on_local_menu_show(G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED gpointer gdata)
211 {
212 menu_mber_display(selection, menu_item_find(local_menu_items, "local_mr_mode"));
213 }
214
on_local_modify_button_release(GtkWidget * widget,GdkEventButton * event,GtkWidget * menu)215 static void on_local_modify_button_release(GtkWidget *widget, GdkEventButton *event,
216 GtkWidget *menu)
217 {
218 menu_shift_button_release(widget, event, menu, on_local_modify);
219 }
220
on_local_mr_mode_button_release(GtkWidget * widget,GdkEventButton * event,GtkWidget * menu)221 static void on_local_mr_mode_button_release(GtkWidget *widget, GdkEventButton *event,
222 GtkWidget *menu)
223 {
224 menu_mber_button_release(selection, widget, event, menu);
225 }
226
local_init(void)227 void local_init(void)
228 {
229 GtkWidget *menu;
230
231 view_connect("local_view", &store, &selection, local_cells, "local_window",
232 &local_display);
233 menu = menu_select("local_menu", &local_menu_info, selection);
234
235 g_signal_connect(menu, "show", G_CALLBACK(on_local_menu_show), NULL);
236 g_signal_connect(get_widget("local_modify"), "button-release-event",
237 G_CALLBACK(on_local_modify_button_release), menu);
238 g_signal_connect(get_widget("local_mr_mode"), "button-release-event",
239 G_CALLBACK(on_local_mr_mode_button_release), menu);
240 }
241