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