1 /*
2  *  prefs.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 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23 
24 #include <errno.h>
25 #include <string.h>
26 
27 #include "common.h"
28 
29 gchar *pref_gdb_executable;
30 gboolean pref_gdb_async_mode;
31 #ifndef G_OS_UNIX
32 gboolean pref_async_break_bugs;
33 #endif
34 gboolean pref_var_update_bug;
35 
36 gboolean pref_auto_view_source;
37 gboolean pref_keep_exec_point;
38 gint pref_visual_beep_length;
39 #ifdef G_OS_UNIX
40 gboolean pref_debug_console_vte;
41 #endif
42 
43 gint pref_sci_marker_first;
44 static gint pref_sci_marker_1st;
45 gint pref_sci_caret_policy;
46 gint pref_sci_caret_slop;
47 gboolean pref_unmark_current_line;
48 
49 gboolean pref_scope_goto_cursor;
50 gboolean pref_seek_with_navqueue;
51 gint pref_panel_tab_pos;
52 gint pref_show_recent_items;
53 gint pref_show_toolbar_items;
54 
55 gint pref_tooltips_fail_action;
56 gint pref_tooltips_send_delay;
57 gint pref_tooltips_length;
58 
59 gint pref_memory_bytes_per_line;
60 gchar *pref_memory_font;
61 
62 #ifdef G_OS_UNIX
63 static gboolean pref_terminal_save_pos;
64 gboolean pref_terminal_padding;
65 gint pref_terminal_window_x;
66 gint pref_terminal_window_y;
67 gint pref_terminal_width;
68 gint pref_terminal_height;
69 #endif  /* G_OS_UNIX */
70 
71 gboolean pref_vte_blinken;
72 gchar *pref_vte_emulation;
73 gchar *pref_vte_font;
74 gint pref_vte_scrollback;
75 
76 #if !GTK_CHECK_VERSION(3, 14, 0)
77 GdkColor pref_vte_colour_fore;
78 GdkColor pref_vte_colour_back;
79 #else
80 GdkRGBA pref_vte_colour_fore;
81 GdkRGBA pref_vte_colour_back;
82 #endif
83 
84 typedef struct _MarkerStyle
85 {
86 	const gchar *name;
87 	gint mark;
88 	gint fore;
89 	gint back;
90 	gint alpha;
91 	gint default_mark;
92 	const gchar *default_fore;
93 	const gchar *default_back;
94 	guint default_alpha;
95 } MarkerStyle;
96 
97 #define MARKER_COUNT 3
98 
99 static MarkerStyle pref_marker_styles[MARKER_COUNT] =
100 {
101 	{ "disabled_break", 0, 0, 0, 0, SC_MARK_CIRCLE,     "#008000", "#C0E0D0", 256 },
102 	{ "enabled_break",  0, 0, 0, 0, SC_MARK_CIRCLE,     "#000080", "#C0D0F0", 256 },
103 	{ "execution_line", 0, 0, 0, 0, SC_MARK_SHORTARROW, "#808000", "#F0F090", 256 }
104 };
105 
prefs_apply(GeanyDocument * doc)106 void prefs_apply(GeanyDocument *doc)
107 {
108 	gint i;
109 	ScintillaObject *sci = doc->editor->sci;
110 	MarkerStyle *style = pref_marker_styles;
111 
112 	for (i = pref_sci_marker_first; i < pref_sci_marker_first + MARKER_COUNT; i++, style++)
113 	{
114 		scintilla_send_message(sci, SCI_MARKERDEFINE, i, style->mark);
115 		scintilla_send_message(sci, SCI_MARKERSETFORE, i, style->fore);
116 		scintilla_send_message(sci, SCI_MARKERSETBACK, i, style->back);
117 		scintilla_send_message(sci, SCI_MARKERSETALPHA, i, style->alpha);
118 	}
119 }
120 
121 static StashGroup *scope_group;
122 static StashGroup *terminal_group;
123 static StashGroup *marker_group[MARKER_COUNT];
124 
load_scope_prefs(GKeyFile * config)125 static void load_scope_prefs(GKeyFile *config)
126 {
127 	guint i;
128 	MarkerStyle *style = pref_marker_styles;
129 
130 	stash_group_load_from_key_file(scope_group, config);
131 	stash_group_load_from_key_file(terminal_group, config);
132 
133 	for (i = 0; i < MARKER_COUNT; i++, style++)
134 	{
135 		gchar *tmp_string;
136 
137 		stash_group_load_from_key_file(marker_group[i], config);
138 		tmp_string = utils_get_setting_string(config, style->name, "fore",
139 			style->default_fore);
140 		style->fore = utils_parse_sci_color(tmp_string);
141 		g_free(tmp_string);
142 		tmp_string = utils_get_setting_string(config, style->name, "back",
143 			style->default_back);
144 		style->back = utils_parse_sci_color(tmp_string);
145 		g_free(tmp_string);
146 	}
147 }
148 
149 static const char *obsolete_prefs[] = { "gdb_buffer_length", "gdb_wait_death",
150 	"gdb_send_interval", NULL };
151 
save_scope_prefs(GKeyFile * config)152 static void save_scope_prefs(GKeyFile *config)
153 {
154 	guint i;
155 	MarkerStyle *style = pref_marker_styles;
156 
157 	stash_group_save_to_key_file(scope_group, config);
158 	stash_group_save_to_key_file(terminal_group, config);
159 
160 	for (i = 0; i < MARKER_COUNT; i++, style++)
161 	{
162 		gchar *tmp_string;
163 
164 		stash_group_save_to_key_file(marker_group[i], config);
165 		tmp_string = g_strdup_printf("#%02X%02X%02X", style->fore & 0xFF,
166 			(style->fore >> 8) & 0xFF, style->fore >> 16);
167 		g_key_file_set_string(config, style->name, "fore", tmp_string);
168 		g_free(tmp_string);
169 		tmp_string = g_strdup_printf("#%02X%02X%02X", style->back & 0xFF,
170 			(style->back >> 8) & 0xFF, style->back >> 16);
171 		g_key_file_set_string(config, style->name, "back", tmp_string);
172 		g_free(tmp_string);
173 	}
174 
175 	for (i = 0; obsolete_prefs[i]; i++)
176 		g_key_file_remove_key(config, "scope", obsolete_prefs[i], NULL);
177 }
178 
prefs_configure(void)179 static void prefs_configure(void)
180 {
181 	static const char *const view_source_items[] =
182 	{
183 		"thread_view_source",
184 		"break_view_source",
185 		"stack_separator1",
186 		"stack_view_source",
187 		NULL
188 	};
189 
190 	const char *const *p;
191 	guint i;
192 
193 	for (p = view_source_items; *p; p++)
194 		gtk_widget_set_visible(get_widget(*p), !pref_auto_view_source);
195 
196 	foreach_document(i)
197 		prefs_apply(documents[i]);
198 
199 	configure_panel();
200 }
201 
prefs_file_name(void)202 char *prefs_file_name(void)
203 {
204 	return g_build_filename(geany->app->configdir, "plugins", "scope", "scope.conf", NULL);
205 }
206 
on_document_save(G_GNUC_UNUSED GObject * obj,GeanyDocument * doc,G_GNUC_UNUSED gpointer gdata)207 static void on_document_save(G_GNUC_UNUSED GObject *obj, GeanyDocument *doc,
208 	G_GNUC_UNUSED gpointer gdata)
209 {
210 	char *configfile = prefs_file_name();
211 
212 	if (doc->real_path && !utils_filenamecmp(doc->real_path, configfile))
213 	{
214 		GKeyFile *config = g_key_file_new();
215 
216 		g_key_file_load_from_file(config, configfile, G_KEY_FILE_NONE, NULL);
217 		load_scope_prefs(config);
218 		prefs_configure();
219 		configure_toolbar();
220 		g_key_file_free(config);
221 	}
222 	g_free(configfile);
223 }
224 
225 static GtkWidget *config_item;
226 
prefs_init(void)227 void prefs_init(void)
228 {
229 	guint i;
230 	MarkerStyle *style = pref_marker_styles;
231 	StashGroup *group;
232 	char *configdir = g_build_filename(geany->app->configdir, "plugins", "scope", NULL);
233 	char *configfile = prefs_file_name();
234 	GKeyFile *config = g_key_file_new();
235 	gboolean obsolete = FALSE;
236 
237 	group = stash_group_new("scope");
238 	stash_group_add_string(group, &pref_gdb_executable, "gdb_executable", "gdb");
239 	stash_group_add_boolean(group, &pref_gdb_async_mode, "gdb_async_mode", FALSE);
240 #ifndef G_OS_UNIX
241 	stash_group_add_boolean(group, &pref_async_break_bugs, "async_break_bugs", TRUE);
242 #endif
243 	stash_group_add_boolean(group, &pref_var_update_bug, "var_update_bug", TRUE);
244 	stash_group_add_boolean(group, &pref_auto_view_source, "auto_view_source", FALSE);
245 	stash_group_add_boolean(group, &pref_keep_exec_point, "keep_exec_point", FALSE);
246 	stash_group_add_integer(group, &pref_visual_beep_length, "visual_beep_length", 25);
247 #ifdef G_OS_UNIX
248 	stash_group_add_boolean(group, &pref_debug_console_vte, "debug_console_vte", TRUE);
249 #endif
250 	stash_group_add_integer(group, &pref_sci_marker_1st, "sci_marker_first", 17);
251 	stash_group_add_integer(group, &pref_sci_caret_policy, "sci_caret_policy", CARET_SLOP |
252 		CARET_JUMPS | CARET_EVEN);
253 	stash_group_add_integer(group, &pref_sci_caret_slop, "sci_caret_slop", 3);
254 	stash_group_add_boolean(group, &pref_unmark_current_line, "unmark_current_line", FALSE);
255 	stash_group_add_boolean(group, &pref_scope_goto_cursor, "scope_run_to_cursor", FALSE);
256 	stash_group_add_boolean(group, &pref_seek_with_navqueue, "seek_with_navqueue", FALSE);
257 	stash_group_add_integer(group, &pref_panel_tab_pos, "panel_tab_pos", GTK_POS_TOP);
258 	stash_group_add_integer(group, &pref_show_recent_items, "show_recent_items", 10);
259 	stash_group_add_integer(group, &pref_show_toolbar_items, "show_toolbar_items", 0xFF);
260 	stash_group_add_integer(group, &pref_tooltips_fail_action, "tooltips_fail_action", 0);
261 	stash_group_add_integer(group, &pref_tooltips_send_delay, "tooltips_send_delay", 25);
262 	stash_group_add_integer(group, &pref_tooltips_length, "tooltips_length", 2048);
263 	stash_group_add_integer(group, &pref_memory_bytes_per_line, "memory_line_bytes", 16);
264 	stash_group_add_string(group, &pref_memory_font, "memory_font", "");
265 	scope_group = group;
266 
267 	config_item = ui_add_config_file_menu_item(configfile, NULL, NULL);
268 	plugin_signal_connect(geany_plugin, NULL, "document-save", FALSE,
269 		G_CALLBACK(on_document_save), NULL);
270 
271 	group = stash_group_new("terminal");
272 #ifdef G_OS_UNIX
273 	stash_group_add_boolean(group, &pref_terminal_save_pos, "save_pos", TRUE);
274 	stash_group_add_boolean(group, &pref_terminal_padding, "padding", TRUE);
275 	stash_group_add_integer(group, &pref_terminal_window_x, "window_x", 70);
276 	stash_group_add_integer(group, &pref_terminal_window_y, "window_y", 50);
277 	stash_group_add_integer(group, &pref_terminal_width, "width", 640);
278 	stash_group_add_integer(group, &pref_terminal_height, "height", 480);
279 #endif  /* G_OS_UNIX */
280 	terminal_group = group;
281 
282 	for (i = 0; i < MARKER_COUNT; i++, style++)
283 	{
284 		group = stash_group_new(style->name);
285 		stash_group_add_integer(group, &style->mark, "mark", style->default_mark);
286 		stash_group_add_integer(group, &style->alpha, "alpha", style->default_alpha);
287 		marker_group[i] = group;
288 	}
289 
290 	g_key_file_load_from_file(config, configfile, G_KEY_FILE_NONE, NULL);
291 	load_scope_prefs(config);
292 
293 	for (i = 0; obsolete_prefs[i]; i++)
294 	{
295 		GError *gerror = NULL;
296 
297 		g_key_file_get_integer(config, "scope", obsolete_prefs[i], &gerror);
298 
299 		if (gerror)
300 		{
301 			g_error_free(gerror);
302 			gerror = NULL;
303 		}
304 		else
305 		{
306 			obsolete = TRUE;
307 			break;
308 		}
309 	}
310 
311 	pref_sci_marker_first = pref_sci_marker_1st;
312 	prefs_configure();
313 	program_load_config(config);
314 
315 	if (obsolete || !g_file_test(configfile, G_FILE_TEST_IS_REGULAR))
316 	{
317 		gint error = utils_mkdir(configdir, TRUE);
318 
319 		if (error)
320 			msgwin_status_add(_("Scope: %s: %s."), configdir, g_strerror(error));
321 		else
322 		{
323 			save_scope_prefs(config);
324 			if (utils_key_file_write_to_file(config, configfile))
325 				msgwin_status_add(_("Scope: created configuration file."));
326 		}
327 	}
328 
329 	g_key_file_free(config);
330 	g_free(configfile);
331 	g_free(configdir);
332 }
333 
prefs_finalize(void)334 void prefs_finalize(void)
335 {
336 	guint i;
337 
338 #ifdef G_OS_UNIX
339 	if (pref_terminal_save_pos)
340 	{
341 		char *configfile = prefs_file_name();
342 		stash_group_save_to_file(terminal_group, configfile, G_KEY_FILE_KEEP_COMMENTS);
343 		g_free(configfile);
344 	}
345 
346 	g_free(pref_vte_font);
347 	g_free(pref_vte_emulation);
348 #endif  /* G_OS_UNIX */
349 
350 	gtk_widget_destroy(config_item);
351 	utils_stash_group_free(scope_group);
352 	utils_stash_group_free(terminal_group);
353 	for (i = 0; i < MARKER_COUNT; i++)
354 		utils_stash_group_free(marker_group[i]);
355 }
356