1 /*
2 *
3 * dconfig.c
4 *
5 * Copyright 2011 Alexander Petukhov <devel(at)apetukhov.ru>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20 * MA 02110-1301, USA.
21 */
22
23 /*
24 * Plugin panel and debug session configs
25 */
26
27 #include <unistd.h>
28 #include <sys/stat.h>
29
30 #include <glib/gstdio.h>
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 #include <geanyplugin.h>
36 extern GeanyData *geany_data;
37
38 #include "dconfig.h"
39 #include "tabs.h"
40 #include "breakpoints.h"
41 #include "debug.h"
42 #include "watch_model.h"
43 #include "wtree.h"
44 #include "tpage.h"
45 #include "bptree.h"
46
47 /* keyfile debug group name */
48 #define DEBUGGER_GROUP "debugger"
49 /* saving interval */
50 #define SAVING_INTERVAL 2000000
51
52 /* check button for a configure dialog */
53 static GtkWidget *save_to_project_btn = NULL;
54
55 /* plugin config file path */
56 static gchar *plugin_config_path = NULL;
57
58 /* current debug session store */
59 static debug_store dstore = DEBUG_STORE_PLUGIN;
60
61 /* GKeyFile's for a project and plugin config */
62 static GKeyFile *keyfile_plugin = NULL;
63 static GKeyFile *keyfile_project = NULL;
64
65 /* flag that indicates that debug session is being loaded to controls
66 * to prevent change state to modified from GUI callbacks */
67 static gboolean debug_config_loading = FALSE;
68
69 /* saving thread staff */
70 static GMutex change_config_mutex;
71 static GCond cond;
72 static GThread *saving_thread;
73
74 /* flags that indicate that part of a config has been changed and
75 * is going to be saved on the savng thread */
76 static gboolean debug_config_changed = FALSE;
77 static gboolean panel_config_changed = FALSE;
78
79 /*
80 * creates a copy of a specified keyfile
81 */
create_copy_keyfile(GKeyFile * keyfile)82 static GKeyFile *create_copy_keyfile(GKeyFile *keyfile)
83 {
84 GKeyFile *copy;
85 gchar *data;
86 gsize length;
87
88 data = g_key_file_to_data(keyfile, &length, NULL);
89 copy = g_key_file_new();
90 g_key_file_load_from_data(copy, data, length, G_KEY_FILE_NONE, NULL);
91 g_free(data);
92
93 return copy;
94 }
95
96 /*
97 * loads debug session from a keyfile and updates GUI
98 */
debug_load_from_keyfile(GKeyFile * keyfile)99 static void debug_load_from_keyfile(GKeyFile *keyfile)
100 {
101 gchar *value;
102 int i, count;
103
104 debug_config_loading = TRUE;
105
106 /* target */
107 tpage_set_target(value = g_key_file_get_string(keyfile, DEBUGGER_GROUP, "target", NULL));
108 g_free(value);
109 /* debugger */
110 tpage_set_debugger(value = g_key_file_get_string(keyfile, DEBUGGER_GROUP, "debugger", NULL));
111 g_free(value);
112 /* arguments */
113 tpage_set_commandline(value = g_key_file_get_string(keyfile, DEBUGGER_GROUP, "arguments", NULL));
114 g_free(value);
115
116 /* environment */
117 count = g_key_file_get_integer(keyfile, DEBUGGER_GROUP, "envvar_count", NULL);
118 for (i = 0; i < count; i++)
119 {
120 gchar *env_name_id = g_strdup_printf("envvar_%i_name", i);
121 gchar *env_value_id = g_strdup_printf("envvar_%i_value", i);
122 gchar *name = g_key_file_get_string(keyfile, DEBUGGER_GROUP, env_name_id, NULL);
123
124 value = g_key_file_get_string(keyfile, DEBUGGER_GROUP, env_value_id, NULL);
125
126 tpage_add_environment(name, value);
127
128 g_free(name);
129 g_free(value);
130
131 g_free(env_name_id);
132 g_free(env_value_id);
133 }
134
135 /* watches */
136 count = g_key_file_get_integer(keyfile, DEBUGGER_GROUP, "watches_count", NULL);
137 for (i = 0; i < count; i++)
138 {
139 gchar *watch_id = g_strdup_printf("watch_%i", i);
140 wtree_add_watch(value = g_key_file_get_string(keyfile, DEBUGGER_GROUP, watch_id, NULL));
141 g_free(value);
142 g_free(watch_id);
143 }
144
145 /* breakpoints */
146 count = g_key_file_get_integer(keyfile, DEBUGGER_GROUP, "breaks_count", NULL);
147 for (i = 0; i < count; i++)
148 {
149 gchar *break_file_id = g_strdup_printf("break_%i_file", i);
150 gchar *break_line_id = g_strdup_printf("break_%i_line", i);
151 gchar *break_condition_id = g_strdup_printf("break_%i_condition", i);
152 gchar *break_hits_id = g_strdup_printf("break_%i_hits_count", i);
153 gchar *break_enabled_id = g_strdup_printf("break_%i_enabled", i);
154
155 gchar *file = g_key_file_get_string(keyfile, DEBUGGER_GROUP, break_file_id, NULL);
156 int line = g_key_file_get_integer(keyfile, DEBUGGER_GROUP, break_line_id, NULL);
157 gchar *condition = g_key_file_get_string(keyfile, DEBUGGER_GROUP, break_condition_id, NULL);
158 int hits_count = g_key_file_get_integer(keyfile, DEBUGGER_GROUP, break_hits_id, NULL);
159 gboolean enabled = g_key_file_get_boolean(keyfile, DEBUGGER_GROUP, break_enabled_id, NULL);
160
161 breaks_add(file, line, condition, enabled, hits_count);
162
163 g_free(break_file_id);
164 g_free(break_line_id);
165 g_free(break_condition_id);
166 g_free(break_hits_id);
167 g_free(break_enabled_id);
168
169 g_free(file);
170 g_free(condition);
171 }
172 bptree_update_file_nodes();
173
174 debug_config_loading = FALSE;
175 }
176
177 /*
178 * saves debug session to a keyfile using values from GUI
179 */
save_to_keyfile(GKeyFile * keyfile)180 static void save_to_keyfile(GKeyFile *keyfile)
181 {
182 GList *_env, *watches, *_breaks, *iter;
183 int env_index, watch_index, bp_index;
184
185 g_key_file_remove_group(keyfile, DEBUGGER_GROUP, NULL);
186
187 g_key_file_set_string(keyfile, DEBUGGER_GROUP, "target", tpage_get_target());
188 g_key_file_set_string(keyfile, DEBUGGER_GROUP, "debugger", tpage_get_debugger());
189 g_key_file_set_string(keyfile, DEBUGGER_GROUP, "arguments", tpage_get_commandline());
190
191 /* environment */
192 _env = tpage_get_environment();
193 g_key_file_set_integer(keyfile, DEBUGGER_GROUP, "envvar_count", g_list_length(_env) / 2);
194 iter = _env;
195 env_index = 0;
196 while(iter)
197 {
198 gchar *name, *value;
199 gchar *env_name_id = g_strdup_printf("envvar_%i_name", env_index);
200 gchar *env_value_id = g_strdup_printf("envvar_%i_value", env_index);
201
202 name = (gchar*)iter->data;
203 iter = iter->next;
204 value = (gchar*)iter->data;
205
206 g_key_file_set_string(keyfile, DEBUGGER_GROUP, env_name_id, name);
207 g_key_file_set_string(keyfile, DEBUGGER_GROUP, env_value_id, value);
208
209 g_free(env_name_id);
210 g_free(env_value_id);
211
212 env_index++;
213 iter = iter->next;
214 }
215 g_list_foreach(_env, (GFunc)g_free, NULL);
216 g_list_free(_env);
217
218 /* watches */
219 watches = wtree_get_watches();
220 g_key_file_set_integer(keyfile, DEBUGGER_GROUP, "watches_count", g_list_length(watches));
221 watch_index = 0;
222 for (iter = watches; iter; iter = iter->next)
223 {
224 gchar *watch = (gchar*)iter->data;
225 gchar *watch_id = g_strdup_printf("watch_%i", watch_index);
226
227 g_key_file_set_string(keyfile, DEBUGGER_GROUP, watch_id, watch);
228
229 g_free(watch_id);
230
231 watch_index++;
232 }
233 g_list_foreach(watches, (GFunc)g_free, NULL);
234 g_list_free(watches);
235
236 /* breakpoints */
237 _breaks = breaks_get_all();
238 g_key_file_set_integer(keyfile, DEBUGGER_GROUP, "breaks_count", g_list_length(_breaks));
239 bp_index = 0;
240 for (iter = _breaks; iter; iter = iter->next)
241 {
242 breakpoint *bp = (breakpoint*)iter->data;
243
244 gchar *break_file_id = g_strdup_printf("break_%i_file", bp_index);
245 gchar *break_line_id = g_strdup_printf("break_%i_line", bp_index);
246 gchar *break_condition_id = g_strdup_printf("break_%i_condition", bp_index);
247 gchar *break_hits_id = g_strdup_printf("break_%i_hits_count", bp_index);
248 gchar *break_enabled_id = g_strdup_printf("break_%i_enabled", bp_index);
249
250 g_key_file_set_string(keyfile, DEBUGGER_GROUP, break_file_id, bp->file);
251 g_key_file_set_integer(keyfile, DEBUGGER_GROUP, break_line_id, bp->line);
252 g_key_file_set_string(keyfile, DEBUGGER_GROUP, break_condition_id, bp->condition);
253 g_key_file_set_integer(keyfile, DEBUGGER_GROUP, break_hits_id, bp->hitscount);
254 g_key_file_set_boolean(keyfile, DEBUGGER_GROUP, break_enabled_id, bp->enabled);
255
256 g_free(break_file_id);
257 g_free(break_line_id);
258 g_free(break_condition_id);
259 g_free(break_hits_id);
260 g_free(break_enabled_id);
261
262 bp_index++;
263 }
264 g_list_free(_breaks);
265 }
266
267 /*
268 * function for config files background saving
269 */
saving_thread_func(gpointer data)270 static gpointer saving_thread_func(gpointer data)
271 {
272 gint64 interval;
273 g_mutex_lock(&change_config_mutex);
274 do
275 {
276 if (
277 panel_config_changed ||
278 (debug_config_changed && DEBUG_STORE_PLUGIN == dstore)
279 )
280 {
281 gchar *config_data;
282
283 /* if all saving is going to be done to a plugin keyfile */
284 if (debug_config_changed)
285 {
286 save_to_keyfile(keyfile_plugin);
287 debug_config_changed = FALSE;
288 }
289
290 config_data = g_key_file_to_data(keyfile_plugin, NULL, NULL);
291 g_file_set_contents(plugin_config_path, config_data, -1, NULL);
292 g_free(config_data);
293
294 panel_config_changed = FALSE;
295 }
296
297 if (debug_config_changed && DEBUG_STORE_PROJECT == dstore)
298 {
299 gchar *config_data;
300
301 /* if debug is saved into a project and has been changed */
302 save_to_keyfile(keyfile_project);
303
304 config_data = g_key_file_to_data(keyfile_project, NULL, NULL);
305 g_file_set_contents(geany_data->app->project->file_name, config_data, -1, NULL);
306 g_free(config_data);
307
308 debug_config_changed = FALSE;
309 }
310
311 interval = g_get_monotonic_time() + SAVING_INTERVAL;
312 }
313 while (!g_cond_wait_until(&cond, &change_config_mutex, interval));
314 g_mutex_unlock(&change_config_mutex);
315
316 return NULL;
317 }
318
319 /*
320 * set "debug changed" flag to save it on "saving_thread" thread
321 */
config_set_debug_changed(void)322 void config_set_debug_changed(void)
323 {
324 if (!debug_config_loading)
325 {
326 g_mutex_lock(&change_config_mutex);
327 debug_config_changed = TRUE;
328 g_mutex_unlock(&change_config_mutex);
329 }
330 }
331
332 /*
333 * set one or several panel config values
334 */
config_set_panel(int config_part,gpointer config_value,...)335 void config_set_panel(int config_part, gpointer config_value, ...)
336 {
337 va_list ap;
338
339 g_mutex_lock(&change_config_mutex);
340
341 va_start(ap, config_value);
342
343 while(config_part)
344 {
345 switch (config_part)
346 {
347 case CP_TABBED_MODE:
348 {
349 g_key_file_set_boolean(keyfile_plugin, "tabbed_mode", "enabled", *((gboolean*)config_value));
350 break;
351 }
352 case CP_OT_TABS:
353 {
354 int *array = (int*)config_value;
355 g_key_file_set_integer_list(keyfile_plugin, "one_panel_mode", "tabs", array + 1, array[0]);
356 break;
357 }
358 case CP_OT_SELECTED:
359 {
360 g_key_file_set_integer(keyfile_plugin, "one_panel_mode", "selected_tab_index", *((int*)config_value));
361 break;
362 }
363 case CP_TT_LTABS:
364 {
365 int *array = (int*)config_value;
366 g_key_file_set_integer_list(keyfile_plugin, "two_panels_mode", "left_tabs", array + 1, array[0]);
367 break;
368 }
369 case CP_TT_LSELECTED:
370 {
371 g_key_file_set_integer(keyfile_plugin, "two_panels_mode", "left_selected_tab_index", *((int*)config_value));
372 break;
373 }
374 case CP_TT_RTABS:
375 {
376 int *array = (int*)config_value;
377 g_key_file_set_integer_list(keyfile_plugin, "two_panels_mode", "right_tabs", array + 1, array[0]);
378 break;
379 }
380 case CP_TT_RSELECTED:
381 {
382 g_key_file_set_integer(keyfile_plugin, "two_panels_mode", "right_selected_tab_index", *((int*)config_value));
383 break;
384 }
385 }
386
387 config_part = va_arg(ap, int);
388 if (config_part)
389 {
390 config_value = va_arg(ap, gpointer);
391 }
392 }
393
394 va_end(ap);
395
396 panel_config_changed = TRUE;
397 g_mutex_unlock(&change_config_mutex);
398 }
399
400 /*
401 * set default debug session values to a keyfile
402 */
config_set_debug_defaults(GKeyFile * keyfile)403 static void config_set_debug_defaults(GKeyFile *keyfile)
404 {
405 g_key_file_set_string(keyfile, DEBUGGER_GROUP, "target", "");
406 g_key_file_set_string(keyfile, DEBUGGER_GROUP, "debugger", "");
407 g_key_file_set_string(keyfile, DEBUGGER_GROUP, "arguments", "");
408
409 g_key_file_set_integer(keyfile, DEBUGGER_GROUP, "envvar_count", 0);
410 g_key_file_set_integer(keyfile, DEBUGGER_GROUP, "watches_count", 0);
411 g_key_file_set_integer(keyfile, DEBUGGER_GROUP, "breaks_count", 0);
412 }
413
414 /*
415 * set default panel config values in a GKeyFile
416 */
config_set_panel_defaults(GKeyFile * keyfile)417 static void config_set_panel_defaults(GKeyFile *keyfile)
418 {
419 int all_tabs[] = { TID_TARGET, TID_BREAKS, TID_AUTOS, TID_WATCH, TID_STACK, TID_TERMINAL, TID_MESSAGES };
420 int left_tabs[] = { TID_TARGET, TID_BREAKS, TID_AUTOS, TID_WATCH };
421 int right_tabs[] = { TID_STACK, TID_TERMINAL, TID_MESSAGES };
422
423 g_key_file_set_boolean(keyfile_plugin, "tabbed_mode", "enabled", FALSE);
424 /* all tabs */
425 g_key_file_set_integer_list(keyfile, "one_panel_mode", "tabs", all_tabs, sizeof(all_tabs) / sizeof(int));
426 g_key_file_set_integer(keyfile, "one_panel_mode", "selected_tab_index", 0);
427 /* left tabs */
428 g_key_file_set_integer_list(keyfile, "two_panels_mode", "left_tabs", left_tabs, sizeof(left_tabs) / sizeof(int));
429 g_key_file_set_integer(keyfile, "two_panels_mode", "left_selected_tab_index", 0);
430 /* right tabs */
431 g_key_file_set_integer_list(keyfile, "two_panels_mode", "right_tabs", right_tabs, sizeof(right_tabs) / sizeof(int));
432 g_key_file_set_integer(keyfile, "two_panels_mode", "right_selected_tab_index", 0);
433
434 g_key_file_set_boolean(keyfile, "saving_settings", "save_to_project", FALSE);
435 }
436
437 /*
438 * initialize
439 */
config_init(void)440 void config_init(void)
441 {
442 /* read config */
443 gchar *config_dir = g_build_path(G_DIR_SEPARATOR_S, geany_data->app->configdir, "plugins", "debugger", NULL);
444 plugin_config_path = g_build_path(G_DIR_SEPARATOR_S, config_dir, "debugger.conf", NULL);
445
446 g_mkdir_with_parents(config_dir, S_IRUSR | S_IWUSR | S_IXUSR);
447 g_free(config_dir);
448
449 keyfile_plugin = g_key_file_new();
450 if (!g_key_file_load_from_file(keyfile_plugin, plugin_config_path, G_KEY_FILE_NONE, NULL))
451 {
452 gchar *data;
453
454 config_set_panel_defaults(keyfile_plugin);
455 data = g_key_file_to_data(keyfile_plugin, NULL, NULL);
456 g_file_set_contents(plugin_config_path, data, -1, NULL);
457 g_free(data);
458 }
459
460 g_mutex_init(&change_config_mutex);
461 g_cond_init(&cond);
462 saving_thread = g_thread_new(NULL, saving_thread_func, NULL);
463 }
464
465 /*
466 * destroy
467 */
config_destroy(void)468 void config_destroy(void)
469 {
470 g_cond_signal(&cond);
471 g_thread_join(saving_thread);
472
473 g_mutex_clear(&change_config_mutex);
474 g_cond_clear(&cond);
475
476 g_free(plugin_config_path);
477
478 g_key_file_free(keyfile_plugin);
479 if(keyfile_project)
480 {
481 g_key_file_free(keyfile_project);
482 keyfile_project = NULL;
483 }
484 }
485
486 /*
487 * config parts getters
488 */
489 /* saving option */
config_get_save_to_project(void)490 gboolean config_get_save_to_project(void)
491 {
492 return g_key_file_get_boolean(keyfile_plugin, "saving_settings", "save_to_project", NULL);
493 }
494 /* panel config */
config_get_tabbed(void)495 gboolean config_get_tabbed(void)
496 {
497 return g_key_file_get_boolean(keyfile_plugin, "tabbed_mode", "enabled", NULL);
498 }
config_get_tabs(gsize * length)499 int* config_get_tabs(gsize *length)
500 {
501 return g_key_file_get_integer_list(keyfile_plugin, "one_panel_mode", "tabs", length, NULL);
502 }
config_get_selected_tab_index(void)503 int config_get_selected_tab_index(void)
504 {
505 return g_key_file_get_integer(keyfile_plugin, "one_panel_mode", "selected_tab_index", NULL);
506 }
config_get_left_tabs(gsize * length)507 int* config_get_left_tabs(gsize *length)
508 {
509 return g_key_file_get_integer_list(keyfile_plugin, "two_panels_mode", "left_tabs", length, NULL);
510 }
config_get_left_selected_tab_index(void)511 int config_get_left_selected_tab_index(void)
512 {
513 return g_key_file_get_integer(keyfile_plugin, "two_panels_mode", "left_selected_tab_index", NULL);
514 }
config_get_right_tabs(gsize * length)515 int* config_get_right_tabs(gsize *length)
516 {
517 return g_key_file_get_integer_list(keyfile_plugin, "two_panels_mode", "right_tabs", length, NULL);
518 }
config_get_right_selected_tab_index(void)519 int config_get_right_selected_tab_index(void)
520 {
521 return g_key_file_get_integer(keyfile_plugin, "two_panels_mode", "right_selected_tab_index", NULL);
522 }
523
524 /*
525 * update GUI fron the store specified
526 * also handles default values insertion in a keyfile if debug section doesn't exist
527 */
config_set_debug_store(debug_store store)528 void config_set_debug_store(debug_store store)
529 {
530 GKeyFile *keyfile;
531
532 dstore = store;
533
534 tpage_clear();
535 wtree_remove_all();
536 breaks_remove_all();
537
538 keyfile = DEBUG_STORE_PROJECT == dstore ? keyfile_project : keyfile_plugin;
539 if (!g_key_file_has_group(keyfile, DEBUGGER_GROUP))
540 {
541 gchar *data, *file;
542
543 config_set_debug_defaults(keyfile);
544 data = g_key_file_to_data(keyfile, NULL, NULL);
545
546 file = DEBUG_STORE_PROJECT == dstore ? geany_data->app->project->file_name : plugin_config_path;
547 g_file_set_contents(file, data, -1, NULL);
548
549 g_free(data);
550 }
551
552 debug_load_from_keyfile(keyfile);
553 }
554
555 /*
556 * updates keyfile_project from a current geany project path
557 */
config_update_project_keyfile(void)558 void config_update_project_keyfile(void)
559 {
560 if (keyfile_project)
561 {
562 g_key_file_free(keyfile_project);
563 }
564 keyfile_project = g_key_file_new();
565 g_key_file_load_from_file(keyfile_project, geany_data->app->project->file_name, G_KEY_FILE_NONE, NULL);
566 }
567
568 /*
569 * project open handler
570 */
config_on_project_open(GObject * obj,GKeyFile * config,gpointer user_data)571 void config_on_project_open(GObject *obj, GKeyFile *config, gpointer user_data)
572 {
573 config_update_project_keyfile();
574
575 if (config_get_save_to_project())
576 {
577 config_set_debug_store(DEBUG_STORE_PROJECT);
578 }
579 }
580
581 /*
582 * project close handler
583 */
config_on_project_close(GObject * obj,gpointer user_data)584 void config_on_project_close(GObject *obj, gpointer user_data)
585 {
586 if (config_get_save_to_project())
587 {
588 if (DBS_IDLE != debug_get_state())
589 {
590 /* stop a debugger and ait for it to be stopped */
591 debug_stop();
592
593 while (DBS_IDLE != debug_get_state())
594 {
595 g_main_context_iteration(NULL, FALSE);
596 }
597 }
598
599 config_set_debug_store(DEBUG_STORE_PLUGIN);
600 }
601 }
602
603 /*
604 * project save handler
605 * handles ne project creation and updatng a project using project properties dialog
606 */
config_on_project_save(GObject * obj,GKeyFile * config,gpointer user_data)607 void config_on_project_save(GObject *obj, GKeyFile *config, gpointer user_data)
608 {
609 if (config_get_save_to_project())
610 {
611 if (!g_key_file_has_group(config, DEBUGGER_GROUP))
612 {
613 /* no debug group, creating a new project */
614 dstore = DEBUG_STORE_PROJECT;
615
616 /* clear values taken from a plugin */
617 tpage_clear();
618 wtree_remove_all();
619 breaks_remove_all();
620
621 /* set default debug values */
622 config_set_debug_defaults(config);
623 }
624
625 /* update local keyfile */
626 if (keyfile_project)
627 {
628 g_key_file_free(keyfile_project);
629 }
630 keyfile_project = create_copy_keyfile(config);
631 }
632 }
633
634 /*
635 * a configure dialog has been closed
636 */
on_configure_response(GtkDialog * dialog,gint response,gpointer user_data)637 static void on_configure_response(GtkDialog* dialog, gint response, gpointer user_data)
638 {
639 gboolean newvalue = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(save_to_project_btn));
640 if (newvalue ^ config_get_save_to_project())
641 {
642 g_key_file_set_boolean(keyfile_plugin, "saving_settings", "save_to_project", newvalue);
643
644 g_mutex_lock(&change_config_mutex);
645 panel_config_changed = TRUE;
646 g_mutex_unlock(&change_config_mutex);
647
648 if (geany_data->app->project)
649 {
650 if (DBS_IDLE != debug_get_state())
651 {
652 debug_stop();
653
654 while (DBS_IDLE != debug_get_state())
655 {
656 g_main_context_iteration(NULL, FALSE);
657 }
658 }
659
660 config_set_debug_store(newvalue ? DEBUG_STORE_PROJECT : DEBUG_STORE_PLUGIN);
661 }
662 }
663 }
664
665 /*
666 * "plugin_configure" signal handler
667 */
config_plugin_configure(GtkDialog * dialog)668 GtkWidget *config_plugin_configure(GtkDialog *dialog)
669 {
670 #if GTK_CHECK_VERSION(3, 0, 0)
671 GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
672 GtkWidget *_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
673 #else
674 GtkWidget *vbox = gtk_vbox_new(FALSE, 6);
675 GtkWidget *_hbox = gtk_hbox_new(FALSE, 6);
676 #endif
677
678 save_to_project_btn = gtk_check_button_new_with_label(_("Save debug session data to a project"));
679 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(save_to_project_btn), config_get_save_to_project());
680
681 gtk_box_pack_start(GTK_BOX(_hbox), save_to_project_btn, TRUE, TRUE, 0);
682 gtk_box_pack_start(GTK_BOX(vbox), _hbox, FALSE, FALSE, 0);
683
684 gtk_widget_show_all(vbox);
685
686 g_signal_connect(dialog, "response", G_CALLBACK(on_configure_response), NULL);
687
688 return vbox;
689 }
690