1 /*
2 * tpage.c
3 *
4 * Copyright 2010 Alexander Petukhov <devel(at)apetukhov.ru>
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, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 /*
23 * Contains function to manipulate target page in debug notebook.
24 */
25
26 #include <string.h>
27
28 #include <gtk/gtk.h>
29
30 #include <sys/stat.h>
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 #include <geanyplugin.h>
36 #include <gp_gtkcompat.h>
37
38 extern GeanyData *geany_data;
39
40 #include "breakpoints.h"
41 #include "utils.h"
42 #include "watch_model.h"
43 #include "wtree.h"
44 #include "debug.h"
45 #include "dconfig.h"
46 #include "tpage.h"
47 #include "tabs.h"
48 #include "envtree.h"
49 #include "gui.h"
50
51 /* boxes margins */
52 #define SPACING 7
53
54 /* root boxes border width */
55 #define ROOT_BORDER_WIDTH 10
56
57 /* root boxes border width */
58 #define BROWSE_BUTTON_WIDTH 65
59
60 /* widgets */
61
62 /* target */
63 static GtkWidget *target_label = NULL;
64 static GtkWidget *target_name = NULL;
65 static GtkWidget *target_button_browse = NULL;
66
67 /* debugger type */
68 static GtkWidget *debugger_label = NULL;
69 static GtkWidget *debugger_cmb = NULL;
70
71 /* argments */
72 static GtkWidget *args_frame = NULL;
73 static GtkWidget *args_textview = NULL;
74
75 /* environment variables */
76 static GtkWidget *env_frame = NULL;
77
78 /* widgets array for reference management when moving to another container */
79 static GtkWidget **widgets[] = {
80 &target_label, &target_name, &target_button_browse,
81 &debugger_label, &debugger_cmb,
82 &args_frame,
83 &env_frame,
84 NULL
85 };
86
87 /*
88 * tells config to update when target arguments change
89 */
on_arguments_changed(GtkTextBuffer * textbuffer,gpointer user_data)90 static void on_arguments_changed(GtkTextBuffer *textbuffer, gpointer user_data)
91 {
92 config_set_debug_changed();
93 }
94
95 /*
96 * target browse button clicked handler
97 */
on_target_browse_clicked(GtkButton * button,gpointer user_data)98 static void on_target_browse_clicked(GtkButton *button, gpointer user_data)
99 {
100 gchar *path;
101 const gchar *prevfile;
102 GtkWidget *dialog;
103 GeanyDocument *doc;
104
105 dialog = gtk_file_chooser_dialog_new (_("Choose target file"),
106 NULL,
107 GTK_FILE_CHOOSER_ACTION_OPEN,
108 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
109 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
110 NULL);
111
112 prevfile = gtk_entry_get_text(GTK_ENTRY(target_name));
113 path = g_path_get_dirname(prevfile);
114 if (strcmp(".", path) == 0 && (doc = document_get_current()) != NULL)
115 {
116 g_free(path);
117 path = g_path_get_dirname(DOC_FILENAME(doc));
118 }
119
120 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER (dialog), path);
121 g_free(path);
122
123 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
124 {
125 gchar *filename;
126 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
127 gtk_entry_set_text(GTK_ENTRY(target_name), filename);
128 g_free (filename);
129
130 config_set_debug_changed();
131 }
132 gtk_widget_destroy (dialog);
133 }
134
135 /*
136 * packs widgets into page depending one tabbed mode state
137 */
tpage_pack_widgets(gboolean tabbed)138 void tpage_pack_widgets(gboolean tabbed)
139 {
140 /* root box */
141 GtkWidget *root = NULL, *oldroot = NULL;
142 GList *children = gtk_container_get_children(GTK_CONTAINER(tab_target));
143 if (children)
144 {
145 oldroot = (GtkWidget*)children->data;
146
147 /* unparent widgets */
148 for (int i = 0; widgets[i]; i++)
149 {
150 GtkWidget **widget_ref = widgets[i];
151 g_object_ref(*widget_ref);
152 gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(*widget_ref)), *widget_ref);
153 }
154
155 g_list_free(children);
156 }
157
158 if (tabbed)
159 {
160 GtkWidget *hbox, *rbox, *lbox;
161
162 #if GTK_CHECK_VERSION(3, 0, 0)
163 root = gtk_box_new(GTK_ORIENTATION_VERTICAL, SPACING);
164 #else
165 root = gtk_vbox_new(FALSE, SPACING);
166 #endif
167 gtk_container_set_border_width(GTK_CONTAINER(root), ROOT_BORDER_WIDTH);
168
169 /* filename */
170 #if GTK_CHECK_VERSION(3, 0, 0)
171 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, SPACING);
172 #else
173 hbox = gtk_hbox_new(FALSE, SPACING);
174 #endif
175 gtk_box_pack_start(GTK_BOX(root), hbox, FALSE, FALSE, 0);
176 gtk_box_pack_start(GTK_BOX(hbox), target_label, FALSE, FALSE, 0);
177 gtk_box_pack_start(GTK_BOX(hbox), target_name, TRUE, TRUE, 0);
178 gtk_box_pack_start(GTK_BOX(hbox), target_button_browse, FALSE, FALSE, 0);
179
180 /* lower hbox */
181 #if GTK_CHECK_VERSION(3, 0, 0)
182 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, SPACING);
183 gtk_box_set_homogeneous(GTK_BOX(hbox), TRUE);
184 #else
185 hbox = gtk_hbox_new(TRUE, SPACING);
186 #endif
187 gtk_box_pack_start(GTK_BOX(root), hbox, TRUE, TRUE, 0);
188
189 /* lower left and right vboxes */
190 #if GTK_CHECK_VERSION(3, 0, 0)
191 lbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, SPACING);
192 rbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, SPACING);
193 #else
194 lbox = gtk_vbox_new(FALSE, SPACING);
195 rbox = gtk_vbox_new(FALSE, SPACING);
196 #endif
197 gtk_box_pack_start(GTK_BOX(hbox), lbox, TRUE, TRUE, 0);
198 gtk_box_pack_start(GTK_BOX(hbox), rbox, TRUE, TRUE, 0);
199
200 /* environment */
201 gtk_box_pack_start(GTK_BOX(lbox), env_frame, TRUE, TRUE, 0);
202
203 /* arguments */
204 gtk_box_pack_start(GTK_BOX(rbox), args_frame, TRUE, TRUE, 0);
205 /* debugger type */
206 #if GTK_CHECK_VERSION(3, 0, 0)
207 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, SPACING);
208 #else
209 hbox = gtk_hbox_new(FALSE, SPACING);
210 #endif
211 gtk_box_pack_start(GTK_BOX(hbox), debugger_label, FALSE, FALSE, 0);
212 gtk_box_pack_start(GTK_BOX(hbox), debugger_cmb, TRUE, TRUE, 0);
213 gtk_box_pack_start(GTK_BOX(rbox), hbox, FALSE, FALSE, 0);
214 }
215 else
216 {
217 GtkWidget *lbox, *rbox, *hbox;
218
219 #if GTK_CHECK_VERSION(3, 0, 0)
220 root = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, SPACING);
221 gtk_box_set_homogeneous(GTK_BOX(root), TRUE);
222 #else
223 root = gtk_hbox_new(TRUE, SPACING);
224 #endif
225 gtk_container_set_border_width(GTK_CONTAINER(root), ROOT_BORDER_WIDTH);
226
227 #if GTK_CHECK_VERSION(3, 0, 0)
228 lbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, SPACING);
229 rbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, SPACING);
230 #else
231 lbox = gtk_vbox_new(FALSE, SPACING);
232 rbox = gtk_vbox_new(FALSE, SPACING);
233 #endif
234 gtk_box_pack_start(GTK_BOX(root), lbox, TRUE, TRUE, 0);
235 gtk_box_pack_start(GTK_BOX(root), rbox, TRUE, TRUE, 0);
236
237 /* environment */
238 gtk_box_pack_start(GTK_BOX(lbox), env_frame, TRUE, TRUE, 0);
239
240 /* target */
241 #if GTK_CHECK_VERSION(3, 0, 0)
242 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, SPACING);
243 #else
244 hbox = gtk_hbox_new(FALSE, SPACING);
245 #endif
246 gtk_box_pack_start(GTK_BOX(hbox), target_label, FALSE, FALSE, 0);
247 gtk_box_pack_start(GTK_BOX(hbox), target_name, TRUE, TRUE, 0);
248 gtk_box_pack_start(GTK_BOX(hbox), target_button_browse, FALSE, FALSE, 0);
249 gtk_box_pack_start(GTK_BOX(rbox), hbox, FALSE, FALSE, 0);
250 /* arguments */
251 gtk_box_pack_start(GTK_BOX(rbox), args_frame, TRUE, TRUE, 0);
252 /* debugger type */
253 #if GTK_CHECK_VERSION(3, 0, 0)
254 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, SPACING);
255 #else
256 hbox = gtk_hbox_new(FALSE, SPACING);
257 #endif
258 gtk_box_pack_start(GTK_BOX(hbox), debugger_label, FALSE, FALSE, 0);
259 gtk_box_pack_start(GTK_BOX(hbox), debugger_cmb, TRUE, TRUE, 0);
260 gtk_box_pack_start(GTK_BOX(rbox), hbox, FALSE, FALSE, 0);
261 }
262
263 if (oldroot)
264 {
265 for (int i = 0; widgets[i]; i++)
266 {
267 g_object_unref(*widgets[i]);
268 }
269 gtk_container_remove(GTK_CONTAINER(tab_target), oldroot);
270 }
271
272 #if GTK_CHECK_VERSION(3, 0, 0)
273 gtk_box_pack_start(GTK_BOX(tab_target), root, TRUE, TRUE, 0);
274 #else
275 gtk_container_add(GTK_CONTAINER(tab_target), root);
276 #endif
277 gtk_widget_show_all(tab_target);
278 }
279
280 /*
281 * create widgets
282 */
tpage_create_widgets(void)283 static void tpage_create_widgets(void)
284 {
285 GList *modules, *iter;
286 GtkWidget *hbox;
287 GtkTextBuffer *buffer;
288 GtkWidget *tree;
289
290 /* target */
291 target_label = gtk_label_new(_("Target:"));
292 target_name = gtk_entry_new ();
293 #if GTK_CHECK_VERSION(3, 0, 0)
294 gtk_editable_set_editable(GTK_EDITABLE(target_name), FALSE);
295 target_button_browse = create_stock_button("document-open", _("Browse"));
296 #else
297 gtk_entry_set_editable(GTK_ENTRY(target_name), FALSE);
298 target_button_browse = create_stock_button(GTK_STOCK_OPEN, _("Browse"));
299 #endif
300 gtk_widget_set_size_request(target_button_browse, BROWSE_BUTTON_WIDTH, 0);
301 g_signal_connect(G_OBJECT(target_button_browse), "clicked", G_CALLBACK (on_target_browse_clicked), NULL);
302
303 /* debugger */
304 debugger_label = gtk_label_new(_("Debugger:"));
305 debugger_cmb = gtk_combo_box_text_new();
306 modules = debug_get_modules();
307 for (iter = modules; iter; iter = iter->next)
308 {
309 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(debugger_cmb), (gchar*)iter->data);
310 }
311 g_list_free(modules);
312 gtk_combo_box_set_active(GTK_COMBO_BOX(debugger_cmb), 0);
313
314 /* arguments */
315 args_frame = gtk_frame_new(_("Command Line Arguments"));
316 hbox = gtk_scrolled_window_new(NULL, NULL);
317 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(hbox), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
318 args_textview = gtk_text_view_new();
319 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(args_textview), GTK_WRAP_CHAR);
320 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(args_textview));
321 g_signal_connect(G_OBJECT(buffer), "changed", G_CALLBACK (on_arguments_changed), NULL);
322 gtk_container_add(GTK_CONTAINER(hbox), args_textview);
323 gtk_container_add(GTK_CONTAINER(args_frame), hbox);
324
325 /* environment */
326 env_frame = gtk_frame_new(_("Environment Variables"));
327 hbox = gtk_scrolled_window_new(NULL, NULL);
328 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(hbox), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
329 tree = envtree_init();
330 gtk_container_add(GTK_CONTAINER(hbox), tree);
331 gtk_container_add(GTK_CONTAINER(env_frame), hbox);
332 }
333
334 /*
335 * set target
336 */
tpage_set_target(const gchar * newvalue)337 void tpage_set_target(const gchar *newvalue)
338 {
339 gtk_entry_set_text(GTK_ENTRY(target_name), newvalue);
340 }
341
342 /*
343 * set debugger
344 */
tpage_set_debugger(const gchar * newvalue)345 void tpage_set_debugger(const gchar *newvalue)
346 {
347 int module = debug_get_module_index(newvalue);
348 if (-1 == module)
349 {
350 module = 0;
351 }
352 gtk_combo_box_set_active(GTK_COMBO_BOX(debugger_cmb), module);
353 }
354
355 /*
356 * set command line
357 */
tpage_set_commandline(const gchar * newvalue)358 void tpage_set_commandline(const gchar *newvalue)
359 {
360 GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(args_textview));
361 gtk_text_buffer_set_text(buffer, newvalue, -1);
362 }
363
364 /*
365 * add environment variable
366 */
tpage_add_environment(const gchar * name,const gchar * value)367 void tpage_add_environment(const gchar *name, const gchar *value)
368 {
369 envtree_add_environment(name, value);
370 }
371
372 /*
373 * removes all data (clears widgets)
374 */
tpage_clear(void)375 void tpage_clear(void)
376 {
377 GtkTextBuffer *buffer;
378
379 /* target */
380 gtk_entry_set_text(GTK_ENTRY(target_name), "");
381
382 /* reset debugger type */
383 gtk_combo_box_set_active(GTK_COMBO_BOX(debugger_cmb), 0);
384
385 /* arguments */
386 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(args_textview));
387 gtk_text_buffer_set_text(buffer, "", -1);
388
389 /* environment variables */
390 envtree_clear();
391 }
392
393 /*
394 * get target file names
395 */
tpage_get_target(void)396 gchar* tpage_get_target(void)
397 {
398 return g_strdup(gtk_entry_get_text(GTK_ENTRY(target_name)));
399 }
400
401 /*
402 * get selected debugger module index
403 */
tpage_get_debug_module_index(void)404 int tpage_get_debug_module_index(void)
405 {
406 return gtk_combo_box_get_active(GTK_COMBO_BOX(debugger_cmb));
407 }
408
409 /*
410 * get selected debugger name
411 */
tpage_get_debugger(void)412 gchar* tpage_get_debugger(void)
413 {
414 return gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(debugger_cmb));
415 }
416
417 /*
418 * get command line
419 */
tpage_get_commandline(void)420 gchar* tpage_get_commandline(void)
421 {
422 gchar *args;
423 gchar **lines;
424 GtkTextIter start, end;
425 GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(args_textview));
426
427 gtk_text_buffer_get_start_iter(buffer, &start);
428 gtk_text_buffer_get_end_iter(buffer, &end);
429
430 args = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
431 lines = g_strsplit(args, "\n", 0);
432 g_free(args);
433 args = g_strjoinv(" ", lines);
434 g_strfreev(lines);
435
436 return args;
437 }
438
439 /*
440 * get list of environment variables
441 */
tpage_get_environment(void)442 GList* tpage_get_environment(void)
443 {
444 return envpage_get_environment();
445 }
446
447 /*
448 * create target page
449 */
tpage_init(void)450 void tpage_init(void)
451 {
452 #if GTK_CHECK_VERSION(3, 0, 0)
453 tab_target = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
454 #else
455 tab_target = gtk_vbox_new(FALSE, 0);
456 #endif
457 tpage_create_widgets();
458 }
459
460 /*
461 * set the page readonly
462 */
tpage_set_readonly(gboolean readonly)463 void tpage_set_readonly(gboolean readonly)
464 {
465 gtk_text_view_set_editable (GTK_TEXT_VIEW (args_textview), !readonly);
466 gtk_widget_set_sensitive (target_button_browse, !readonly);
467 gtk_widget_set_sensitive (debugger_cmb, !readonly);
468
469 envtree_set_readonly(readonly);
470 }
471