1 /*
2  *  KCemu -- The emulator for the KC85 homecomputer series and much more.
3  *  Copyright (C) 1997-2010 Torsten Paul
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 /*
21  * Enable Sound
22  * Joystick Device
23  * Enable V24-Module
24  * Custom ROM Module
25  * Custom ROM Module (Name)
26  * Custom ROM Module (Id)
27  * Custom ROM Module (File)
28  * Custom ROM Module (Size)
29  * V24-Baudrate
30  * V24-Device
31  * Flash Offset
32  * Foreground Saturation
33  * Foreground Brightness
34  * Background Saturation
35  * Background Brightness
36  * Black Value
37  * White Value
38  * Max Auto Skip
39  * DEBUG UI_Gtk Color Add
40  * DEBUG UI_Gtk Frame Delay
41  */
42 
43 #include <stdlib.h>
44 
45 #include <list>
46 #include <string>
47 
48 #include "kc/system.h"
49 #include "kc/prefs/types.h"
50 #include "kc/prefs/prefs.h"
51 #include "kc/prefs/strlist.h"
52 
53 #include "kc/kc.h"
54 
55 #include "kc/mod_list.h"
56 
57 #include "sys/sysdep.h"
58 
59 #include "ui/gtk/cmd.h"
60 #include "ui/gtk/dialog.h"
61 #include "ui/gtk/options.h"
62 
63 class CMD_options_window_toggle : public CMD {
64 private:
65     OptionsWindow *_w;
66 
67 public:
CMD_options_window_toggle(OptionsWindow * w)68     CMD_options_window_toggle(OptionsWindow *w) : CMD("ui-options-window-toggle") {
69         _w = w;
70         register_cmd("ui-options-window-toggle");
71     }
72 
execute(CMD_Args * args,CMD_Context context)73     void execute(CMD_Args *args, CMD_Context context) {
74         _w->toggle();
75     }
76 };
77 
78 class CMD_options_window_dialog : public CMD {
79 private:
80     OptionsWindow *_w;
81 
82 public:
CMD_options_window_dialog(OptionsWindow * w)83     CMD_options_window_dialog(OptionsWindow *w) : CMD("ui-options-window-dialog") {
84         _w = w;
85         register_cmd("ui-options-window-dialog");
86     }
87 
execute(CMD_Args * args,CMD_Context context)88     void execute(CMD_Args *args, CMD_Context context) {
89         if (args == NULL)
90             args = new CMD_Args();
91 
92         switch (context) {
93         case 0:
94             args->set_string_arg("ui-dialog-title", _("Save profiles?"));
95             args->set_string_arg("ui-dialog-text",
96                                _("Some profiles were changed!\n\n"
97                                  "'Yes' will save changes to disk, 'No' will reject all changes.\n"
98                                  "'Cancel': will allow to continue editing."));
99             args->set_string_arg("ui-dialog-text-arg", "filename");
100             args->add_callback("ui-dialog-cancel-CB", this, 1);
101             args->add_callback("ui-dialog-yes-no-CB-no", this, 2);
102             args->add_callback("ui-dialog-yes-no-CB-yes", this, 3);
103             CMD_EXEC_ARGS("ui-dialog-yes-no-cancel", args);
104             break;
105         case 1: // cancel
106             break;
107         case 2: // no
108             _w->reject();
109             break;
110         case 3: // yes
111             _w->save();
112             break;
113         }
114     }
115 };
116 
117 const char * OptionsWindow::FILE_CHOOSER_BUTTON_KEY = "filechooser_button";
118 const char * OptionsWindow::FILE_CHOOSER_CLEAR_BUTTON_KEY = "filechooser_clear_button";
119 const char * OptionsWindow::DATA_KEY_CHECK_BUTTON = "key_check_button";
120 const char * OptionsWindow::PREFERENCES_KEY = "preferences_key";
121 const char * OptionsWindow::DEFAULT_DIR_KEY = "default_dir_key";
122 const char * OptionsWindow::TARGET_WIDGET1_KEY = "target_widget1_key";
123 const char * OptionsWindow::TARGET_WIDGET2_KEY = "target_widget2_key";
124 const char * OptionsWindow::TARGET_WIDGET3_KEY = "target_widget3_key";
125 
OptionsWindow(const char * ui_xml_file)126 OptionsWindow::OptionsWindow(const char *ui_xml_file) : UI_Gtk_Window(ui_xml_file) {
127     _current_profile = NULL;
128     _current_kc_type = KC_TYPE_NONE;
129     _open_rom_last_path = NULL;
130     _w.liststore_modules = NULL;
131 
132     _cmd = new CMD_options_window_toggle(this);
133     _cmd_dialog = new CMD_options_window_dialog(this);
134 }
135 
~OptionsWindow(void)136 OptionsWindow::~OptionsWindow(void) {
137     delete _cmd;
138     delete _cmd_dialog;
139 }
140 
141 void
on_button_up_clicked(GtkButton * button,gpointer user_data)142 OptionsWindow::on_button_up_clicked(GtkButton *button, gpointer user_data) {
143     OptionsWindow *self = (OptionsWindow *)user_data;
144     self->move_row((GtkPathMoveFunc)gtk_tree_path_prev, gtk_tree_store_move_before);
145 }
146 
147 void
on_button_down_clicked(GtkButton * button,gpointer user_data)148 OptionsWindow::on_button_down_clicked(GtkButton *button, gpointer user_data) {
149     OptionsWindow *self = (OptionsWindow *)user_data;
150     self->move_row(gtk_tree_path_next, gtk_tree_store_move_after);
151 }
152 
153 void
on_button_expand_clicked(GtkButton * button,gpointer user_data)154 OptionsWindow::on_button_expand_clicked(GtkButton *button, gpointer user_data) {
155     OptionsWindow *self = (OptionsWindow *)user_data;
156     self->expand_tree();
157 }
158 
159 void
on_button_collapse_clicked(GtkButton * button,gpointer user_data)160 OptionsWindow::on_button_collapse_clicked(GtkButton *button, gpointer user_data) {
161     OptionsWindow *self = (OptionsWindow *)user_data;
162     self->collapse_tree();
163 }
164 
165 
166 void
expand_tree(void)167 OptionsWindow::expand_tree(void) {
168     gtk_tree_view_expand_all(GTK_TREE_VIEW(_w.treeview));
169 }
170 
171 void
collapse_tree(void)172 OptionsWindow::collapse_tree(void) {
173     gtk_tree_view_collapse_all(GTK_TREE_VIEW(_w.treeview));
174 
175     GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(_w.treeview));
176     GtkTreePath *path = gtk_tree_path_new_first();
177     gtk_tree_view_expand_to_path(GTK_TREE_VIEW(_w.treeview), path);
178     gtk_tree_selection_select_path(select, path);
179     gtk_tree_path_free(path);
180 }
181 
182 void
on_button_new_clicked(GtkButton * button,gpointer user_data)183 OptionsWindow::on_button_new_clicked(GtkButton *button, gpointer user_data) {
184     OptionsWindow *self = (OptionsWindow *)user_data;
185     Profile *profile = Preferences::instance()->create_user_profile(self->_current_profile);
186     if (profile == NULL)
187         return;
188 
189     GtkTreeIter iter;
190     GtkTreeModel *model = self->get_selected_tree_iter(&iter);
191     if (model == NULL)
192         return;
193 
194     GtkTreeIter iter_child;
195     gtk_tree_store_append(GTK_TREE_STORE(model), &iter_child, &iter);
196     gtk_tree_store_set(GTK_TREE_STORE(model), &iter_child,
197             TREE_INT_COLUMN, 2,
198             TREE_TEXT_COLUMN, profile->get_name(),
199             TREE_CONFIG_NAME_COLUMN, profile->get_config_name(),
200             TREE_ICON_COLUMN, self->_w.pixbuf_default,
201             -1);
202 
203     self->expand_and_select(GTK_TREE_VIEW(self->_w.treeview), model, &iter_child);
204     gtk_notebook_set_current_page(self->_w.notebook, 0);
205 }
206 
207 void
expand_and_select(GtkTreeView * treeview,GtkTreeModel * model,GtkTreeIter * iter)208 OptionsWindow::expand_and_select(GtkTreeView *treeview, GtkTreeModel *model, GtkTreeIter *iter)
209 {
210     GtkTreePath *path = gtk_tree_model_get_path(model, iter);
211     gtk_tree_view_expand_to_path(treeview, path);
212     gtk_tree_path_free(path);
213     gtk_tree_selection_select_iter(gtk_tree_view_get_selection(treeview), iter);
214 }
215 
216 void
on_button_copy_clicked(GtkButton * button,gpointer user_data)217 OptionsWindow::on_button_copy_clicked(GtkButton *button, gpointer user_data) {
218     OptionsWindow *self = (OptionsWindow *)user_data;
219     Profile *profile = Preferences::instance()->copy_user_profile(self->_current_profile);
220     if (profile == NULL)
221         return;
222 
223     GtkTreeIter iter;
224     GtkTreeModel *model = self->get_selected_tree_iter(&iter);
225     if (model == NULL)
226         return;
227 
228     GtkTreeIter parent;
229     if (!gtk_tree_model_iter_parent(model, &parent, &iter))
230         return;
231 
232     GtkTreeIter copy;
233     gtk_tree_store_insert_after(GTK_TREE_STORE(model), &copy, &parent, &iter);
234     gtk_tree_store_set(GTK_TREE_STORE(model), &copy,
235             TREE_INT_COLUMN, 2,
236             TREE_TEXT_COLUMN, profile->get_name(),
237             TREE_CONFIG_NAME_COLUMN, profile->get_config_name(),
238             TREE_ICON_COLUMN, self->_w.pixbuf_default,
239             -1);
240 
241     self->expand_and_select(GTK_TREE_VIEW(self->_w.treeview), model, &copy);
242     gtk_notebook_set_current_page(self->_w.notebook, 0);
243 }
244 
245 void
on_button_delete_clicked(GtkButton * button,gpointer user_data)246 OptionsWindow::on_button_delete_clicked(GtkButton *button, gpointer user_data) {
247     OptionsWindow *self = (OptionsWindow *)user_data;
248     GtkTreeIter iter;
249     GtkTreeModel *model = self->get_selected_tree_iter(&iter);
250     if (model == NULL)
251         return;
252 
253     gtk_tree_store_set(GTK_TREE_STORE(model), &iter, TREE_ICON_COLUMN, self->_w.pixbuf_deleted, -1);
254     self->_current_profile->set_deleted(true);
255 }
256 
257 gboolean
tree_model_foreach_func_delete(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer user_data)258 OptionsWindow::tree_model_foreach_func_delete(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
259 {
260     OptionsWindow *self = (OptionsWindow *)user_data;
261 
262     gchar *config_name;
263     gtk_tree_model_get(model, iter, TREE_CONFIG_NAME_COLUMN, &config_name, -1);
264 
265     if (Preferences::instance()->find_profile(config_name) == NULL) {
266         gchar *path_string = gtk_tree_path_to_string(path);
267         self->_delete_path.push_back(path_string);
268         g_free(path_string);
269     }
270 
271     g_free(config_name);
272     return FALSE;
273 }
274 
275 void
on_button_ok_clicked(GtkButton * button,gpointer user_data)276 OptionsWindow::on_button_ok_clicked(GtkButton *button, gpointer user_data) {
277     OptionsWindow *self = (OptionsWindow *)user_data;
278     self->save();
279 }
280 
281 void
on_button_close_clicked(GtkButton * button,gpointer user_data)282 OptionsWindow::on_button_close_clicked(GtkButton *button, gpointer user_data) {
283     OptionsWindow *self = (OptionsWindow *)user_data;
284 
285     if (Preferences::instance()->has_changed_profiles()) {
286         CMD_EXEC("ui-options-window-dialog");
287     } else {
288         self->hide();
289     }
290 }
291 
292 void
on_tree_selection_changed(GtkTreeSelection * selection,gpointer user_data)293 OptionsWindow::on_tree_selection_changed(GtkTreeSelection *selection, gpointer user_data) {
294     OptionsWindow *self = (OptionsWindow *)user_data;
295 
296     GtkTreeIter iter;
297     GtkTreeModel *model;
298 
299     if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
300         gchar *key;
301         gtk_tree_model_get(model, &iter, TREE_CONFIG_NAME_COLUMN, &key, -1);
302 
303         self->_current_profile = Preferences::instance()->find_profile(key);
304         self->apply_profile();
305         g_free(key);
306 
307         profile_level_t level = self->_current_profile->get_level();
308         gtk_widget_set_sensitive(self->_w.b_new, level == PROFILE_LEVEL_SYSTEM_USER);
309         gtk_widget_set_sensitive(self->_w.b_copy, level == PROFILE_LEVEL_USER);
310         gtk_widget_set_sensitive(self->_w.b_delete, level == PROFILE_LEVEL_USER);
311         gtk_widget_set_sensitive(self->_w.b_up, level == PROFILE_LEVEL_USER);
312         gtk_widget_set_sensitive(self->_w.b_down, level == PROFILE_LEVEL_USER);
313     }
314 }
315 
316 void
on_media_check_button_toggled(GtkToggleButton * togglebutton,gpointer user_data)317 OptionsWindow::on_media_check_button_toggled(GtkToggleButton *togglebutton, gpointer user_data) {
318     OptionsWindow *self = (OptionsWindow *)user_data;
319 
320     GtkWidget *filechooser_button = GTK_WIDGET(g_object_get_data(G_OBJECT(togglebutton), FILE_CHOOSER_BUTTON_KEY));
321     GtkWidget *filechooser_clear_button = GTK_WIDGET(g_object_get_data(G_OBJECT(togglebutton), FILE_CHOOSER_CLEAR_BUTTON_KEY));
322     gtk_widget_set_sensitive(filechooser_button, togglebutton->active);
323     gtk_widget_set_sensitive(filechooser_clear_button, togglebutton->active);
324     if (!togglebutton->active) {
325         const char * key = (const char *)g_object_get_data(G_OBJECT(filechooser_button), PREFERENCES_KEY);
326         self->_current_profile->remove_value(key);
327         self->apply_filechooserbutton(GTK_FILE_CHOOSER(filechooser_button)); // apply parent value
328     }
329 }
330 
331 void
on_media_clear_button_clicked(GtkButton * button,gpointer user_data)332 OptionsWindow::on_media_clear_button_clicked(GtkButton *button, gpointer user_data) {
333     OptionsWindow *self = (OptionsWindow *)user_data;
334 
335     GtkFileChooser *filechooser = GTK_FILE_CHOOSER(g_object_get_data(G_OBJECT(button), FILE_CHOOSER_BUTTON_KEY));
336     gtk_file_chooser_unselect_all(filechooser);
337     const char * key = (const char *)g_object_get_data(G_OBJECT(filechooser), PREFERENCES_KEY);
338     self->_current_profile->set_null_value(key);
339 }
340 
341 void
on_media_filechooser_file_set(GtkFileChooserButton * filechooserbutton,gpointer user_data)342 OptionsWindow::on_media_filechooser_file_set(GtkFileChooserButton *filechooserbutton, gpointer user_data) {
343     OptionsWindow *self = (OptionsWindow *)user_data;
344 
345     const char * key = (const char *)g_object_get_data(G_OBJECT(filechooserbutton), PREFERENCES_KEY);
346     gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooserbutton));
347     if (filename == NULL) {
348         self->_current_profile->set_null_value(key);
349     } else {
350         self->_current_profile->set_string_value(key, filename);
351     }
352     g_free(filename);
353 }
354 
355 void
set_widget_sensitive_by_key(GObject * object,const gchar * key,bool sensitive)356 OptionsWindow::set_widget_sensitive_by_key(GObject *object, const gchar *key, bool sensitive) {
357     gpointer widget = g_object_get_data(object, key);
358     if (widget == NULL)
359         return;
360 
361     gtk_widget_set_sensitive(GTK_WIDGET(widget), sensitive);
362 }
363 
364 /**
365  *  Returns true if the profile value was removed. In this case the display value
366  *  need to be applied again to fetch the now valid parent value.
367  */
368 bool
check_button_toggled(GtkToggleButton * togglebutton)369 OptionsWindow::check_button_toggled(GtkToggleButton *togglebutton) {
370     set_widget_sensitive_by_key(G_OBJECT(togglebutton), TARGET_WIDGET1_KEY, togglebutton->active);
371     set_widget_sensitive_by_key(G_OBJECT(togglebutton), TARGET_WIDGET2_KEY, togglebutton->active);
372     set_widget_sensitive_by_key(G_OBJECT(togglebutton), TARGET_WIDGET3_KEY, togglebutton->active);
373 
374     const char * key = (const char *)g_object_get_data(G_OBJECT(togglebutton), PREFERENCES_KEY);
375     if (togglebutton->active) {
376         ProfileValue *value = _current_profile->get_value(key);
377         if (value != NULL)
378           _current_profile->set_value(key, new ProfileValue(value));
379         //_current_profile->set_int_value(key, _current_profile->get_int_value(key, 0));
380     } else {
381         _current_profile->remove_value(key);
382     }
383 
384     return !togglebutton->active;
385 }
386 
387 void
on_display_check_button_toggled(GtkToggleButton * togglebutton,gpointer user_data)388 OptionsWindow::on_display_check_button_toggled(GtkToggleButton *togglebutton, gpointer user_data) {
389     OptionsWindow *self = (OptionsWindow *)user_data;
390     if (self->check_button_toggled(togglebutton))
391         self->apply_display_settings();
392 }
393 
394 void
on_display_scale_value_changed(GtkSpinButton * spin_button,gpointer user_data)395 OptionsWindow::on_display_scale_value_changed(GtkSpinButton *spin_button, gpointer user_data) {
396     OptionsWindow *self = (OptionsWindow *)user_data;
397     int display_scale = gtk_spin_button_get_value_as_int(spin_button);
398     self->_current_profile->set_int_value("display_scale", display_scale);
399 }
400 
401 void
on_display_effects_changed(GtkComboBox * combobox,gpointer user_data)402 OptionsWindow::on_display_effects_changed(GtkComboBox *combobox, gpointer user_data) {
403     OptionsWindow *self = (OptionsWindow *)user_data;
404     int display_effects = gtk_combo_box_get_active(combobox);
405     self->_current_profile->set_int_value("display_effects", display_effects);
406 }
407 
408 void
on_display_debug_changed(GtkComboBox * combobox,gpointer user_data)409 OptionsWindow::on_display_debug_changed(GtkComboBox *combobox, gpointer user_data) {
410     OptionsWindow *self = (OptionsWindow *)user_data;
411     int display_debug = gtk_combo_box_get_active(combobox);
412     self->_current_profile->set_int_value("display_debug", display_debug);
413 }
414 
415 void
on_display_mem_access_changed(GtkComboBox * combobox,gpointer user_data)416 OptionsWindow::on_display_mem_access_changed(GtkComboBox *combobox, gpointer user_data) {
417     OptionsWindow *self = (OptionsWindow *)user_data;
418     int display_mem_access = gtk_combo_box_get_active(combobox);
419     self->_current_profile->set_int_value("display_mem_access", display_mem_access);
420 }
421 
422 void
on_profile_name_changed(GtkEditable * editable,gpointer user_data)423 OptionsWindow::on_profile_name_changed(GtkEditable *editable, gpointer user_data) {
424     OptionsWindow *self = (OptionsWindow *)user_data;
425     const char *name = gtk_entry_get_text(GTK_ENTRY(editable));
426 
427     GtkTreeIter iter;
428     GtkTreeModel *model;
429     GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->_w.treeview));
430     if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
431         gtk_tree_store_set(self->_w.treestore, &iter, TREE_TEXT_COLUMN, name, -1);
432     }
433 
434     self->_current_profile->set_name(name);
435     self->_current_profile->set_string_value("name", name);
436 }
437 
438 void
on_comment_changed(GtkTextBuffer * textbuffer,gpointer user_data)439 OptionsWindow::on_comment_changed(GtkTextBuffer *textbuffer, gpointer user_data) {
440     OptionsWindow *self = (OptionsWindow *)user_data;
441 
442     GtkTextIter start, end;
443 
444     gtk_text_buffer_get_iter_at_offset(textbuffer, &start, 0);
445     gtk_text_buffer_get_iter_at_offset(textbuffer, &end, 0);
446     gtk_text_iter_forward_to_end(&end);
447 
448     gchar *text = gtk_text_buffer_get_text(textbuffer, &start, &end, FALSE);
449 
450     const char *key = "comment";
451     if (strlen(text) == 0) {
452         self->_current_profile->remove_value(key);
453     } else {
454         self->_current_profile->set_string_value(key, text);
455     }
456 
457     g_free(text);
458 }
459 
460 void
on_system_type_changed(GtkComboBox * combobox,gpointer user_data)461 OptionsWindow::on_system_type_changed(GtkComboBox *combobox, gpointer user_data) {
462     OptionsWindow *self = (OptionsWindow *)user_data;
463 
464     GtkTreeIter iter;
465     if (!gtk_combo_box_get_active_iter(self->_w.combobox_system_type, &iter))
466         return;
467 
468     int kc_type;
469     gtk_tree_model_get(GTK_TREE_MODEL(self->_w.liststore_system), &iter, 1, &kc_type, -1);
470 
471     self->_current_profile->set_int_value("system", kc_type);
472     self->apply_system_variant((kc_type_t)kc_type, KC_VARIANT_NONE);
473     self->apply_modules_settings((kc_type_t)kc_type);
474     self->apply_roms_settings((kc_type_t)kc_type, KC_VARIANT_NONE);
475 }
476 
477 void
on_system_variant_check_button_toggled(GtkToggleButton * togglebutton,gpointer user_data)478 OptionsWindow::on_system_variant_check_button_toggled(GtkToggleButton *togglebutton, gpointer user_data) {
479     const char *key = "variant";
480     OptionsWindow *self = (OptionsWindow *)user_data;
481 
482     gtk_widget_set_sensitive(GTK_WIDGET(self->_w.combobox_system_variant), togglebutton->active);
483 
484     if (togglebutton->active) {
485         self->_current_profile->set_int_value(key, self->_current_profile->get_int_value(key, KC_VARIANT_NONE));
486     } else {
487         self->_current_profile->remove_value(key);
488         self->apply_system_variant(self->_current_kc_type, (kc_variant_t)self->_current_profile->get_int_value(key, KC_VARIANT_NONE));
489     }
490 }
491 
492 void
on_system_variant_changed(GtkComboBox * combobox,gpointer user_data)493 OptionsWindow::on_system_variant_changed(GtkComboBox *combobox, gpointer user_data) {
494     OptionsWindow *self = (OptionsWindow *)user_data;
495 
496     GtkTreeIter iter;
497     if (!gtk_combo_box_get_active_iter(self->_w.combobox_system_variant, &iter))
498         return;
499 
500     int kc_variant;
501     GtkTreeModel *model = gtk_combo_box_get_model(self->_w.combobox_system_variant);
502     gtk_tree_model_get(model, &iter, 1, &kc_variant, -1);
503 
504     self->_current_profile->set_int_value("variant", kc_variant);
505     self->apply_roms_settings(self->_current_kc_type, (kc_variant_t)kc_variant);
506 }
507 
508 void
on_module_changed(GtkComboBox * combobox,gpointer user_data)509 OptionsWindow::on_module_changed(GtkComboBox *combobox, gpointer user_data) {
510     OptionsWindow *self = (OptionsWindow *)user_data;
511 
512     string list;
513     const char *ptr = "";
514     for (int a = 0;a < NR_OF_MODULES;a++) {
515         GtkTreeIter iter;
516         if (gtk_combo_box_get_active_iter(self->_w.combobox_module[a], &iter)) {
517             gchar *modif;
518             GtkTreeModel *model = gtk_combo_box_get_model(self->_w.combobox_module[a]);
519             gtk_tree_model_get(model, &iter, MODULES_MODIF_COLUMN, &modif, -1);
520             if (modif != NULL) {
521                 list += ptr;
522                 list += modif;
523                 ptr = ",";
524                 g_free(modif);
525             }
526         }
527     }
528     self->_current_profile->set_string_value("modules", list.c_str());
529 }
530 
531 void
on_modules_check_button_toggled(GtkToggleButton * togglebutton,gpointer user_data)532 OptionsWindow::on_modules_check_button_toggled(GtkToggleButton *togglebutton, gpointer user_data) {
533     const char *key = "modules";
534     OptionsWindow *self = (OptionsWindow *)user_data;
535 
536     for (int a = 0;a < NR_OF_MODULES;a++) {
537         gtk_widget_set_sensitive(GTK_WIDGET(self->_w.combobox_module[a]), togglebutton->active);
538     }
539 
540     if (togglebutton->active) {
541         self->_current_profile->set_string_value(key, self->_current_profile->get_string_value(key, ""));
542     } else {
543         self->_current_profile->remove_value(key);
544         self->apply_modules_settings(self->_current_kc_type);
545     }
546 }
547 
548 void
on_kc85_settings_check_button_toggled(GtkToggleButton * togglebutton,gpointer user_data)549 OptionsWindow::on_kc85_settings_check_button_toggled(GtkToggleButton *togglebutton, gpointer user_data) {
550     OptionsWindow *self = (OptionsWindow *)user_data;
551     if (self->check_button_toggled(togglebutton))
552         self->apply_kc85_settings();
553 }
554 
555 void
on_kc85_d004_changed(GtkComboBox * combobox,gpointer user_data)556 OptionsWindow::on_kc85_d004_changed(GtkComboBox *combobox, gpointer user_data) {
557     OptionsWindow *self = (OptionsWindow *)user_data;
558     int d004 = gtk_combo_box_get_active(combobox);
559     self->_current_profile->set_int_value("d004", d004);
560 }
561 
562 void
on_kc85_f8_rom_changed(GtkComboBox * combobox,gpointer user_data)563 OptionsWindow::on_kc85_f8_rom_changed(GtkComboBox *combobox, gpointer user_data) {
564     OptionsWindow *self = (OptionsWindow *)user_data;
565     int d004_f8 = gtk_combo_box_get_active(combobox);
566     self->_current_profile->set_int_value("d004_f8", d004_f8);
567 }
568 
569 void
on_kc85_busdrivers_changed(GtkSpinButton * spin_button,gpointer user_data)570 OptionsWindow::on_kc85_busdrivers_changed(GtkSpinButton *spin_button, gpointer user_data) {
571     OptionsWindow *self = (OptionsWindow *)user_data;
572     int busdrivers = gtk_spin_button_get_value_as_int(spin_button);
573     self->_current_profile->set_int_value("busdrivers", busdrivers);
574 }
575 
576 void
on_roms_settings_check_button_toggled(GtkToggleButton * togglebutton,gpointer user_data)577 OptionsWindow::on_roms_settings_check_button_toggled(GtkToggleButton *togglebutton, gpointer user_data) {
578     OptionsWindow *self = (OptionsWindow *)user_data;
579     if (self->check_button_toggled(togglebutton))
580         self->apply_system_type();
581 }
582 
583 void
on_rom_changed(GtkComboBoxEntry * comboboxentry,gpointer user_data)584 OptionsWindow::on_rom_changed(GtkComboBoxEntry *comboboxentry, gpointer user_data) {
585     OptionsWindow *self = (OptionsWindow *)user_data;
586 
587     GtkTreeIter iter;
588     if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(comboboxentry), &iter))
589         return;
590 
591     gchar *rom;
592     GtkTreeModel *model = gtk_combo_box_get_model(GTK_COMBO_BOX(comboboxentry));
593     gtk_tree_model_get(model, &iter, 1, &rom, -1);
594 
595     const char *key = self->get_preferences_key(G_OBJECT(g_object_get_data(G_OBJECT(comboboxentry), DATA_KEY_CHECK_BUTTON)));
596     self->_current_profile->set_string_value(key, rom);
597 
598     self->apply_system_type(); // let apply_roms_settings change the tooltip text for the combobox!
599 }
600 
601 void
on_rom_open_clicked(GtkButton * button,gpointer user_data)602 OptionsWindow::on_rom_open_clicked(GtkButton *button, gpointer user_data) {
603   OptionsWindow *self = (OptionsWindow *)user_data;
604 
605   GtkWidget *filechooser = gtk_file_chooser_dialog_new(_("Open ROM Image..."),
606                                                        GTK_WINDOW(self->_window),
607                                                        GTK_FILE_CHOOSER_ACTION_OPEN,
608                                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
609                                                        GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
610                                                        NULL);
611 
612   if (self->_open_rom_last_path == NULL)
613       self->_open_rom_last_path = sys_gethome();
614 
615   gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechooser), self->_open_rom_last_path);
616   free(self->_open_rom_last_path);
617 
618   const char *key = self->get_preferences_key(G_OBJECT(g_object_get_data(G_OBJECT(button), DATA_KEY_CHECK_BUTTON)));
619   if (gtk_dialog_run(GTK_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT)
620     {
621       char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
622       self->_current_profile->set_string_value(key, filename);
623       g_free(filename);
624     }
625 
626   self->_open_rom_last_path = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(filechooser));
627 
628   gtk_widget_destroy(filechooser);
629 
630   self->apply_system_type(); // let apply_roms_settings add the filename from profile to combobox model!
631 }
632 
633 void
apply_entry_value(GtkEntry * entry,gint signal_id)634 OptionsWindow::apply_entry_value(GtkEntry *entry, gint signal_id)
635 {
636   const char * key = get_preferences_key(G_OBJECT(entry));
637   ProfileValue *value = get_current_profile_value(key);
638   g_signal_handler_block(entry, signal_id);
639   gtk_entry_set_text(entry, value == NULL ? "" : value->get_string_value());
640   g_signal_handler_unblock(entry, signal_id);
641 
642   GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON(g_object_get_data(G_OBJECT(entry), DATA_KEY_CHECK_BUTTON));
643   gtk_toggle_button_set_active(toggle_button, _current_profile->contains_key(key));
644 }
645 
646 void
apply_network_settings(void)647 OptionsWindow::apply_network_settings(void)
648 {
649   apply_entry_value(_w.entry_network_ip_address, _w.on_network_changed_id[0]);
650   apply_entry_value(_w.entry_network_netmask, _w.on_network_changed_id[1]);
651   apply_entry_value(_w.entry_network_gateway, _w.on_network_changed_id[2]);
652   apply_entry_value(_w.entry_network_dns_server, _w.on_network_changed_id[3]);
653 }
654 
655 void
on_network_settings_check_button_toggled(GtkToggleButton * togglebutton,gpointer user_data)656 OptionsWindow::on_network_settings_check_button_toggled(GtkToggleButton *togglebutton, gpointer user_data)
657 {
658     OptionsWindow *self = (OptionsWindow *)user_data;
659     if (self->check_button_toggled(togglebutton))
660         self->apply_network_settings();
661 }
662 
663 void
on_network_changed(GtkEntry * entry,gpointer user_data)664 OptionsWindow::on_network_changed(GtkEntry *entry, gpointer user_data)
665 {
666   OptionsWindow *self = (OptionsWindow *)user_data;
667   const char * key = self->get_preferences_key(G_OBJECT(entry));
668   gchar *text = pango_trim_string(gtk_entry_get_text(entry));
669   gtk_entry_set_icon_from_stock(entry, GTK_ENTRY_ICON_PRIMARY, *text && !self->is_ip_address(text) ? GTK_STOCK_DIALOG_WARNING : NULL);
670   gtk_entry_set_icon_activatable(entry, GTK_ENTRY_ICON_PRIMARY, FALSE);
671   self->_current_profile->set_string_value(key, text);
672   g_free(text);
673 }
674 
675 GtkTreeModel *
get_selected_tree_iter(GtkTreeIter * iter)676 OptionsWindow::get_selected_tree_iter(GtkTreeIter *iter) {
677     GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(_w.treeview));
678 
679     GtkTreeModel *model;
680     if (gtk_tree_selection_get_selected(selection, &model, iter))
681         return model;
682 
683     return NULL;
684 }
685 
686 /**
687  * FreeBSD 8 still uses glib 2.20 as default version. That does
688  * not include g_hostname_is_ip_address() which has the good point
689  * to be available in MinGW environment too.
690  * I'm not going to to create a wrapper just for the GUI check, so
691  * there's no nice warning icon until glib is upgraded to at least 2.22.
692  */
693 bool
is_ip_address(const char * addr)694 OptionsWindow::is_ip_address(const char *addr)
695 {
696 #if GLIB_CHECK_VERSION(2, 22, 0)
697   return g_hostname_is_ip_address(addr);
698 #else
699   return true;
700 #endif
701 }
702 
703 ProfileValue *
get_current_profile_value(const char * key)704 OptionsWindow::get_current_profile_value(const char *key) {
705     if (_current_profile == NULL)
706         return NULL;
707 
708     return _current_profile->get_value(key);
709 }
710 
711 const char *
get_preferences_key(GObject * object)712 OptionsWindow::get_preferences_key(GObject *object) {
713     const char * key = (const char *)g_object_get_data(object, PREFERENCES_KEY);
714     g_assert(key != NULL);
715     return key;
716 }
717 
718 void
set_preferences_key(GObject * object,const char * key)719 OptionsWindow::set_preferences_key(GObject *object, const char *key)
720 {
721     g_assert(object != NULL);
722     g_assert(key != NULL);
723     g_object_set_data(object, PREFERENCES_KEY, strdup(key));
724 }
725 
726 /**
727  *  Apply the profile value to the given spinbutton. The key of the value to apply will
728  *  be fetched from the data set on the checkbutton that enables/disables this spinbutton.
729  *
730  *  While setting the value the signal handler is blocked to prevent loops with the
731  *  handler writing changes back to the profile.
732  */
733 void
apply_spin_button_value(GtkCheckButton * check_button,GtkSpinButton * spin_button,gint signal_id,int default_value)734 OptionsWindow::apply_spin_button_value(GtkCheckButton *check_button, GtkSpinButton *spin_button, gint signal_id, int default_value) {
735     const char *key = get_preferences_key(G_OBJECT(check_button));
736     ProfileValue *value = get_current_profile_value(key);
737     int spin_value = value == NULL ? default_value : value->get_int_value();
738 
739     g_signal_handler_block(spin_button, signal_id);
740     gtk_spin_button_set_value(spin_button, spin_value);
741     g_signal_handler_unblock(spin_button, signal_id);
742 
743     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), _current_profile->contains_key(key));
744 }
745 
746 /**
747  *  Apply the profile value to the given combobox. The key of the value to apply will
748  *  be fetched from the data set on the checkbutton that enables/disables this combobox.
749  *
750  *  While setting the value the signal handler is blocked to prevent loops with the
751  *  handler writing changes back to the profile.
752  *
753  *  The value for the combobox is currently limited to be 0 or 1.
754  */
755 void
apply_combobox_value(GtkCheckButton * check_button,GtkComboBox * combobox,gint handler_id)756 OptionsWindow::apply_combobox_value(GtkCheckButton *check_button, GtkComboBox *combobox, gint handler_id) {
757     const char *key = get_preferences_key(G_OBJECT(check_button));
758     ProfileValue *value = get_current_profile_value(key);
759     int val = value == NULL ? 0 : value->get_int_value();
760 
761     g_signal_handler_block(combobox, handler_id);
762     gtk_combo_box_set_active(combobox, val ? 1 : 0);
763     g_signal_handler_unblock(combobox, handler_id);
764 
765     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), _current_profile->contains_key(key));
766 }
767 
768 void
apply_profile(void)769 OptionsWindow::apply_profile(void) {
770     g_signal_handler_block(_w.entry_profile_name, _w.on_profile_name_changed_id);
771     gtk_entry_set_text(_w.entry_profile_name, _current_profile->get_name());
772     g_signal_handler_unblock(_w.entry_profile_name, _w.on_profile_name_changed_id);
773     gtk_widget_set_sensitive(GTK_WIDGET(_w.entry_profile_name), _current_profile->get_level() == PROFILE_LEVEL_USER);
774 
775     apply_comment();
776     apply_system_type();
777     apply_display_settings();
778     apply_kc85_settings();
779     apply_network_settings();
780 
781     apply_filechooserbutton(GTK_FILE_CHOOSER(get_widget("media_filechooserbutton_tape")));
782     apply_filechooserbutton(GTK_FILE_CHOOSER(get_widget("media_filechooserbutton_audio")));
783     apply_filechooserbutton(GTK_FILE_CHOOSER(get_widget("media_filechooserbutton_disk1")));
784     apply_filechooserbutton(GTK_FILE_CHOOSER(get_widget("media_filechooserbutton_disk2")));
785     apply_filechooserbutton(GTK_FILE_CHOOSER(get_widget("media_filechooserbutton_disk3")));
786     apply_filechooserbutton(GTK_FILE_CHOOSER(get_widget("media_filechooserbutton_disk4")));
787     apply_filechooserbutton(GTK_FILE_CHOOSER(get_widget("media_filechooserbutton_hd1")));
788     apply_filechooserbutton(GTK_FILE_CHOOSER(get_widget("media_filechooserbutton_hd2")));
789 }
790 
791 void
apply_comment(void)792 OptionsWindow::apply_comment(void) {
793     g_signal_handler_block(_w.textbuffer_comment, _w.on_comment_changed_id);
794     gtk_text_buffer_set_text(_w.textbuffer_comment, _current_profile->get_comment(), -1);
795     g_signal_handler_unblock(_w.textbuffer_comment, _w.on_comment_changed_id);
796 
797     gtk_widget_set_sensitive(GTK_WIDGET(_w.textview_comment), _current_profile->get_level() == PROFILE_LEVEL_USER);
798 }
799 
800 void
apply_system_type(void)801 OptionsWindow::apply_system_type(void) {
802     gtk_widget_set_sensitive(GTK_WIDGET(_w.combobox_system_type), _current_profile->get_level() == PROFILE_LEVEL_DEFAULT);
803 
804     ProfileValue *system = get_current_profile_value("system");
805     ProfileValue *variant = get_current_profile_value("variant");
806 
807     g_signal_handler_block(_w.combobox_system_type, _w.on_system_type_changed_id);
808 
809     GtkTreeIter iter;
810     bool valid = system != NULL;
811     if (valid)
812         valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(_w.liststore_system), &iter);
813     while (valid) {
814         int kc_type;
815         gtk_tree_model_get(GTK_TREE_MODEL(_w.liststore_system), &iter, 1, &kc_type, -1);
816         if (system->get_int_value() == kc_type) {
817             gtk_combo_box_set_active_iter(_w.combobox_system_type, &iter);
818             apply_system_variant((kc_type_t)kc_type, variant == NULL ? KC_VARIANT_NONE : (kc_variant_t)variant->get_int_value());
819             apply_roms_settings((kc_type_t)kc_type, variant == NULL ? KC_VARIANT_NONE : (kc_variant_t)variant->get_int_value());
820             apply_modules_settings((kc_type_t)kc_type);
821             break;
822         }
823         valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(_w.liststore_system), &iter);
824     }
825     if (!valid) {
826         gtk_combo_box_set_active(_w.combobox_system_type, -1);
827         apply_system_variant(KC_TYPE_NONE, KC_VARIANT_NONE);
828         apply_roms_settings(KC_TYPE_NONE, KC_VARIANT_NONE);
829         apply_modules_settings(KC_TYPE_NONE);
830     }
831 
832     g_signal_handler_unblock(_w.combobox_system_type, _w.on_system_type_changed_id);
833 }
834 
835 void
set_roms_liststore(int idx,const char * rom_key,SystemROM * rom)836 OptionsWindow::set_roms_liststore(int idx, const char *rom_key, SystemROM *rom) {
837     ProfileValue *profile_value = get_current_profile_value(rom_key);
838     const char *profile_rom_filename = (profile_value == NULL) ? NULL : profile_value->get_string_value();
839 
840     GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(_w.roms_comboboxentry[idx])));
841     gtk_list_store_clear(store);
842 
843     int active = -1;
844     int list_entry = 0;
845     ROMEntry *active_entry = NULL;
846     const rom_entry_list_t roms = rom->get_roms();
847     for (rom_entry_list_t::const_iterator it2 = roms.begin();it2 != roms.end();it2++) {
848         ROMEntry *entry = (*it2);
849         GtkTreeIter iter;
850         gtk_list_store_append(store, &iter);
851         gtk_list_store_set(store, &iter,
852                            ROMS_DESCRIPTION_COLUMN, entry->get_description().c_str(),
853                            ROMS_FILENAME_COLUMN, entry->get_filename().c_str(),
854                            ROMS_TYPE_COLUMN, 1,
855                            -1);
856 
857         if ((profile_rom_filename != NULL) && (entry->get_filename().compare(profile_rom_filename) == 0)) {
858             active = list_entry;
859             active_entry = entry;
860         }
861         list_entry++;
862     }
863 
864     if ((active < 0) && (profile_rom_filename != NULL)) {
865         GtkTreeIter iter;
866         gtk_list_store_append(store, &iter);
867         gtk_list_store_set(store, &iter,
868                            ROMS_DESCRIPTION_COLUMN, sys_basename(profile_rom_filename),
869                            ROMS_FILENAME_COLUMN, profile_rom_filename,
870                            ROMS_TYPE_COLUMN, 2,
871                            -1);
872         active = list_entry;
873     }
874 
875     if (active < 0) {
876         active = 0;
877         active_entry = *roms.begin();
878 
879         int idx = 0;
880         for (rom_entry_list_t::const_iterator it = roms.begin();it != roms.end();it++) {
881             ROMEntry *entry = (*it);
882             if (entry->is_default()) {
883                 active = idx;
884                 active_entry = entry;
885                 break;
886             }
887             idx++;
888         }
889     }
890 
891     char tooltip[128];
892     snprintf(tooltip, sizeof(tooltip), _("ROM image is '%s'. The ROM size needs to be %04xh (%d) bytes."),
893              active_entry != NULL ? active_entry->get_filename().c_str() : profile_rom_filename,
894              rom->get_size(),
895              rom->get_size());
896     gtk_widget_set_tooltip_text(GTK_WIDGET(_w.roms_comboboxentry[idx]), tooltip);
897 
898     g_signal_handler_block(_w.roms_comboboxentry[idx], _w.on_rom_changed_id[idx]);
899     gtk_combo_box_set_model(GTK_COMBO_BOX(_w.roms_comboboxentry[idx]), GTK_TREE_MODEL(store));
900     gtk_combo_box_set_active(GTK_COMBO_BOX(_w.roms_comboboxentry[idx]), active);
901     g_signal_handler_unblock(_w.roms_comboboxentry[idx], _w.on_rom_changed_id[idx]);
902 }
903 
904 void
apply_roms_settings(kc_type_t kc_type,kc_variant_t kc_variant)905 OptionsWindow::apply_roms_settings(kc_type_t kc_type, kc_variant_t kc_variant) {
906     const SystemType *type = SystemInformation::instance()->get_system_type(kc_type, kc_variant);
907     if (type == NULL)
908       return;
909 
910     system_rom_list_t rom_list = type->get_rom_list();
911     int idx = 0;
912     for (system_rom_list_t::const_iterator it = rom_list.begin();(it != rom_list.end()) && (idx < NR_OF_ROMS);it++) {
913         SystemROM *rom = (*it);
914         const char *rom_key = rom->get_name().c_str();
915 
916         set_roms_liststore(idx, rom_key, rom);
917 
918         string text = string(gettext(rom_key)) + ":";
919         gtk_label_set_text(_w.roms_label[idx], text.c_str());
920 
921         gpointer val = g_object_get_data(G_OBJECT(_w.roms_check_button[idx]), PREFERENCES_KEY);
922         g_object_set_data(G_OBJECT(_w.roms_check_button[idx]), PREFERENCES_KEY, strdup(rom_key));
923         free(val);
924 
925         gtk_widget_show(GTK_WIDGET(_w.roms_label[idx]));
926         gtk_widget_show(GTK_WIDGET(_w.roms_comboboxentry[idx]));
927         gtk_widget_show(GTK_WIDGET(_w.roms_open_button[idx]));
928         gtk_widget_show(GTK_WIDGET(_w.roms_check_button[idx]));
929 
930         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_w.roms_check_button[idx]), _current_profile->contains_key(rom_key));
931         gtk_widget_set_sensitive(GTK_WIDGET(_w.roms_check_button[idx]), _current_profile->get_level() != PROFILE_LEVEL_DEFAULT);
932 
933         idx++;
934     }
935 
936     for (;idx < NR_OF_ROMS;idx++) {
937         gtk_widget_hide(GTK_WIDGET(_w.roms_label[idx]));
938         gtk_widget_hide(GTK_WIDGET(_w.roms_comboboxentry[idx]));
939         gtk_widget_hide(GTK_WIDGET(_w.roms_open_button[idx]));
940         gtk_widget_hide(GTK_WIDGET(_w.roms_check_button[idx]));
941     }
942 }
943 
944 void
apply_system_variant(kc_type_t kc_type,kc_variant_t kc_variant)945 OptionsWindow::apply_system_variant(kc_type_t kc_type, kc_variant_t kc_variant) {
946     _current_kc_type = kc_type;
947 
948     system_type_list_t list = SystemInformation::instance()->get_system_types();
949 
950     GtkListStore *store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
951     for (system_type_list_t::iterator it = list.begin();it != list.end();it++) {
952         SystemType *type = (*it);
953         if (type->get_kc_type() != kc_type)
954           continue;
955 
956         GtkTreeIter iter;
957         gtk_list_store_append(store, &iter);
958         gtk_list_store_set(store, &iter, 0, type->get_display_name(), 1, type->get_kc_variant(), -1);
959     }
960 
961     g_signal_handler_block(_w.combobox_system_variant, _w.on_system_variant_changed_id);
962 
963     gtk_combo_box_set_model(_w.combobox_system_variant, GTK_TREE_MODEL(store));
964     g_object_unref(store);
965 
966     if (kc_variant == KC_VARIANT_NONE) {
967         gtk_combo_box_set_active(_w.combobox_system_variant, 0);
968     } else {
969         GtkTreeIter iter;
970         bool valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
971         while (valid) {
972             int v;
973             gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 1, &v, -1);
974             if (kc_variant == v) {
975                 gtk_combo_box_set_active_iter(_w.combobox_system_variant, &iter);
976                 break;
977             }
978             valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
979         }
980         if (!valid) {
981             gtk_combo_box_set_active(_w.combobox_system_variant, 0);
982         }
983     }
984 
985     g_signal_handler_unblock(_w.combobox_system_variant, _w.on_system_variant_changed_id);
986 
987     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_w.check_button_system_variant), _current_profile->contains_key("variant"));
988 }
989 
990 void
apply_display_settings(void)991 OptionsWindow::apply_display_settings(void) {
992     apply_spin_button_value(_w.check_button_display_scale, _w.spin_button_display_scale, _w.on_display_scale_value_changed_id, 1);
993 
994     apply_combobox_value(_w.check_button_display_effects, _w.combobox_display_effects, _w.on_display_effects_changed_id);
995     apply_combobox_value(_w.check_button_display_mem_access, _w.combobox_display_mem_access, _w.on_display_mem_access_changed_id);
996     apply_combobox_value(_w.check_button_display_debug, _w.combobox_display_debug, _w.on_display_debug_changed_id);
997 }
998 
999 void
apply_kc85_settings(void)1000 OptionsWindow::apply_kc85_settings(void) {
1001     apply_spin_button_value(_w.check_button_busdrivers, _w.spin_button_busdrivers, _w.on_kc85_busdrivers_changed_id, 0);
1002 
1003     apply_combobox_value(_w.check_button_d004, _w.combobox_d004, _w.on_kc85_d004_changed_id);
1004     apply_combobox_value(_w.check_button_f8_rom, _w.combobox_f8_rom, _w.on_kc85_f8_rom_changed_id);
1005 }
1006 
1007 void
apply_modules_settings(kc_type_t kc_type)1008 OptionsWindow::apply_modules_settings(kc_type_t kc_type) {
1009     const char *key = "modules";
1010     ProfileValue *modules = get_current_profile_value(key);
1011     string modules_list = modules == NULL ? "" : modules->get_string_value();
1012 
1013     StringList list(modules == NULL ? "" : modules->get_string_value());
1014 
1015     for (int a = 0;a < NR_OF_MODULES;a++) {
1016         g_signal_handler_block(_w.combobox_module[a], _w.on_module_changed_id[a]);
1017     }
1018 
1019     if (_w.liststore_modules != NULL) {
1020         gtk_list_store_clear(_w.liststore_modules);
1021         // FIXME: gtk_list_store_free() ???
1022     }
1023     _w.liststore_modules = get_modules_list_model(kc_type);
1024     for (int a = 0;a < NR_OF_MODULES;a++) {
1025         gtk_combo_box_set_model(_w.combobox_module[a], GTK_TREE_MODEL(_w.liststore_modules));
1026         gtk_combo_box_set_active(_w.combobox_module[a], 0);
1027     }
1028 
1029     int a = 0;
1030     for (StringList::iterator it = list.begin();(it != list.end()) && (a < NR_OF_MODULES);it++) {
1031         GtkTreeIter iter;
1032         GtkTreeModel *model = gtk_combo_box_get_model(_w.combobox_module[a]);
1033         bool valid = gtk_tree_model_get_iter_first(model, &iter);
1034         while (valid) {
1035             gchar *modif;
1036             gtk_tree_model_get(model, &iter, MODULES_MODIF_COLUMN, &modif, -1);
1037             if ((modif != NULL) && (strcmp((*it).c_str(), modif) == 0)) {
1038                 gtk_combo_box_set_active_iter(_w.combobox_module[a], &iter);
1039                 break;
1040             }
1041             g_free(modif);
1042             valid = gtk_tree_model_iter_next(model, &iter);
1043         }
1044         a++;
1045     }
1046 
1047     for (int a = 0;a < NR_OF_MODULES;a++) {
1048         g_signal_handler_unblock(_w.combobox_module[a], _w.on_module_changed_id[a]);
1049     }
1050 
1051     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_w.check_button_modules), _current_profile->contains_key(key));
1052 }
1053 
1054 void
apply_filechooserbutton(GtkFileChooser * filechooser)1055 OptionsWindow::apply_filechooserbutton(GtkFileChooser *filechooser) {
1056     const char * key = (const char *)g_object_get_data(G_OBJECT(filechooser), PREFERENCES_KEY);
1057     const char * dir = (const char *)g_object_get_data(G_OBJECT(filechooser), DEFAULT_DIR_KEY);
1058 
1059     ProfileValue *value = get_current_profile_value(key);
1060 
1061     const char *filename = value == NULL ? NULL : value->get_string_value();
1062 
1063     if (filename == NULL) {
1064         gtk_file_chooser_unselect_all(filechooser);
1065     } else {
1066         if (!sys_isabsolutepath(filename) && (dir != NULL)) {
1067             string path = string(kcemu_datadir) + dir + filename;
1068             gtk_file_chooser_select_filename(filechooser, path.c_str());
1069         } else {
1070             gtk_file_chooser_select_filename(filechooser, filename);
1071         }
1072     }
1073 
1074     GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON(g_object_get_data(G_OBJECT(filechooser), DATA_KEY_CHECK_BUTTON));
1075     gtk_toggle_button_set_active(toggle_button, _current_profile->contains_key(key));
1076 }
1077 
1078 void
move_row(GtkPathMoveFunc path_func,GtkIterMoveFunc move_func)1079 OptionsWindow::move_row(GtkPathMoveFunc path_func, GtkIterMoveFunc move_func) {
1080     GtkTreeIter iter;
1081     GtkTreeModel *model;
1082 
1083     GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(_w.treeview));
1084     if (!gtk_tree_selection_get_selected(selection, &model, &iter))
1085         return;
1086 
1087     GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
1088     path_func(path);
1089 
1090     GtkTreeIter position;
1091     if (gtk_tree_model_get_iter(model, &position, path)) {
1092         move_func(_w.treestore, &iter, &position);
1093     }
1094 
1095     gtk_tree_path_free(path);
1096 }
1097 
1098 void
add_system(GtkTreeStore * store,GtkTreeIter * iter,const char * name,const char * config_name,const char * icon_name)1099 OptionsWindow::add_system(GtkTreeStore *store, GtkTreeIter *iter, const char *name, const char *config_name, const char *icon_name) {
1100     GtkTreeIter iter_system;
1101     GdkPixbuf *pixbuf = get_icon(icon_name);
1102     gtk_tree_store_append(store, &iter_system, iter);
1103     gtk_tree_store_set(store, &iter_system,
1104             TREE_INT_COLUMN, 2,
1105             TREE_TEXT_COLUMN, name,
1106             TREE_CONFIG_NAME_COLUMN, config_name,
1107             TREE_ICON_COLUMN, pixbuf,
1108             -1);
1109 
1110     list<Profile *> children = Preferences::instance()->find_child_profiles(config_name);
1111     for (list<Profile *>::iterator it = children.begin();it != children.end();it++) {
1112         GtkTreeIter iter_child;
1113         gtk_tree_store_append(store, &iter_child, &iter_system);
1114         gtk_tree_store_set(store, &iter_child,
1115                 TREE_INT_COLUMN, 2,
1116                 TREE_TEXT_COLUMN, (*it)->get_name(),
1117                 TREE_CONFIG_NAME_COLUMN, (*it)->get_config_name(),
1118                 TREE_ICON_COLUMN, _w.pixbuf_default,
1119                 -1);
1120     }
1121 }
1122 
1123 GtkTreeStore *
get_tree_model(void)1124 OptionsWindow::get_tree_model(void) {
1125     GtkTreeStore *store = gtk_tree_store_new(TREE_N_COLUMNS, G_TYPE_INT, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_STRING);
1126 
1127     GtkTreeIter iter_root;
1128     gtk_tree_store_append(store, &iter_root, NULL);
1129     gtk_tree_store_set(store, &iter_root, TREE_INT_COLUMN, 1, TREE_TEXT_COLUMN, "Default", TREE_ICON_COLUMN, _w.pixbuf_root, TREE_CONFIG_NAME_COLUMN, "default", -1);
1130 
1131     emulation_type_list_t list = EmulationType::get_emulation_types();
1132     for (emulation_type_list_t::iterator it = list.begin();it != list.end();it++) {
1133         add_system(store, &iter_root, (*it)->get_name(), (*it)->get_config_name(), (*it)->get_icon_name());
1134     }
1135 
1136     return store;
1137 }
1138 
1139 GtkListStore *
get_system_list_model(void)1140 OptionsWindow::get_system_list_model(void) {
1141     GtkListStore *store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
1142 
1143     emulation_type_list_t list = EmulationType::get_emulation_types();
1144     for (emulation_type_list_t::iterator it = list.begin();it != list.end();it++) {
1145         GtkTreeIter iter;
1146         gtk_list_store_append(store, &iter);
1147         gtk_list_store_set(store, &iter, 0, (*it)->get_name(), 1, (*it)->get_kc_type(), -1);
1148     }
1149 
1150     return store;
1151 }
1152 
1153 GtkListStore *
get_variant_list_model(kc_variant_t kc_variant,const char * name,...)1154 OptionsWindow::get_variant_list_model(kc_variant_t kc_variant, const char *name, ...) {
1155     GtkListStore *store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
1156 
1157     va_list ap;
1158     va_start(ap, name);
1159 
1160     while (242) {
1161         GtkTreeIter iter;
1162         gtk_list_store_append(store, &iter);
1163         gtk_list_store_set(store, &iter, 0, name, 1, kc_variant, -1);
1164 
1165         kc_variant = (kc_variant_t)va_arg(ap, int);
1166         if (kc_variant < 0)
1167             break;
1168 
1169         name = va_arg(ap, const char *);
1170     }
1171 
1172     va_end(ap);
1173 
1174     return store;
1175 }
1176 
1177 GtkListStore *
get_modules_list_model(kc_type_t kc_type)1178 OptionsWindow::get_modules_list_model(kc_type_t kc_type) {
1179     GtkListStore *store = gtk_list_store_new(MODULES_N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
1180 
1181     for (ModuleList::iterator it = module_list->begin();it != module_list->end();it++) {
1182         kc_type_t mod_kc_type = (*it)->get_kc_type();
1183         if ((mod_kc_type & kc_type) == 0)
1184             continue;
1185 
1186         const char *name = (*it)->get_name();
1187         const char *modif_name = (*it)->get_mod() == NULL ? NULL : (*it)->get_mod()->get_name();
1188 
1189         GtkTreeIter iter;
1190         gtk_list_store_append(store, &iter);
1191         gtk_list_store_set(store, &iter, MODULES_NAME_COLUMN, name, MODULES_MODIF_COLUMN, modif_name, MODULES_POINTER_COLUMN, (*it), -1);
1192     }
1193 
1194     return store;
1195 }
1196 
1197 void
wire_check_button(const char * preferences_key,const char * default_dir,const char * check_button_name,const char * filechooser_button_name,const char * button_clear_name)1198 OptionsWindow::wire_check_button(const char *preferences_key, const char *default_dir, const char *check_button_name, const char *filechooser_button_name, const char *button_clear_name) {
1199     GtkWidget *check_button = get_widget(check_button_name);
1200     GtkWidget *filechooser_button = get_widget(filechooser_button_name);
1201     GtkWidget *button_clear = get_widget(button_clear_name);
1202     g_object_set_data(G_OBJECT(check_button), FILE_CHOOSER_BUTTON_KEY, filechooser_button);
1203     g_object_set_data(G_OBJECT(check_button), FILE_CHOOSER_CLEAR_BUTTON_KEY, button_clear);
1204     g_object_set_data(G_OBJECT(button_clear), FILE_CHOOSER_BUTTON_KEY, filechooser_button);
1205     g_object_set_data(G_OBJECT(filechooser_button), DATA_KEY_CHECK_BUTTON, check_button);
1206     g_object_set_data(G_OBJECT(filechooser_button), PREFERENCES_KEY, strdup(preferences_key));
1207     if (default_dir != NULL)
1208         g_object_set_data(G_OBJECT(filechooser_button), DEFAULT_DIR_KEY, strdup(default_dir));
1209     g_signal_connect(check_button, "toggled", G_CALLBACK(on_media_check_button_toggled), this);
1210     g_signal_connect(button_clear, "clicked", G_CALLBACK(on_media_clear_button_clicked), this);
1211     g_signal_connect(filechooser_button, "file-set", G_CALLBACK(on_media_filechooser_file_set), this);
1212 }
1213 
1214 void
wire_check_button(const char * preferences_key,GtkCheckButton * check_button,GCallback callback,GtkWidget * target1,GtkWidget * target2,GtkWidget * target3)1215 OptionsWindow::wire_check_button(const char *preferences_key, GtkCheckButton *check_button, GCallback callback, GtkWidget *target1, GtkWidget *target2, GtkWidget *target3) {
1216     g_object_set_data(G_OBJECT(check_button), PREFERENCES_KEY, strdup(preferences_key));
1217     g_object_set_data(G_OBJECT(check_button), TARGET_WIDGET1_KEY, target1);
1218     g_object_set_data(G_OBJECT(target1), DATA_KEY_CHECK_BUTTON, check_button);
1219 
1220     if (target2 != NULL) {
1221         g_object_set_data(G_OBJECT(check_button), TARGET_WIDGET2_KEY, target2);
1222         g_object_set_data(G_OBJECT(target2), DATA_KEY_CHECK_BUTTON, check_button);
1223     }
1224     if (target3 != NULL) {
1225         g_object_set_data(G_OBJECT(check_button), TARGET_WIDGET3_KEY, target3);
1226         g_object_set_data(G_OBJECT(target3), DATA_KEY_CHECK_BUTTON, check_button);
1227     }
1228 
1229     g_signal_connect(check_button, "toggled", callback, this);
1230 }
1231 
1232 void
init(void)1233 OptionsWindow::init(void) {
1234     _window = get_widget("options_window");
1235     gtk_signal_connect(GTK_OBJECT(_window), "delete_event",
1236             GTK_SIGNAL_FUNC(cmd_exec_sft),
1237             (char *)"ui-options-window-toggle"); // FIXME:
1238 
1239     _w.pixbuf_root = get_icon("icon-root.png");
1240     _w.pixbuf_default = get_icon("icon-default.png");
1241     _w.pixbuf_deleted = get_icon("icon-deleted.png");
1242 
1243     _w.treestore = get_tree_model();
1244     _w.treeview = get_widget("tree_treeview");
1245     gtk_tree_view_set_model(GTK_TREE_VIEW(_w.treeview), GTK_TREE_MODEL(_w.treestore));
1246     gtk_tree_view_columns_autosize(GTK_TREE_VIEW(_w.treeview));
1247 
1248     GtkTreeViewColumn *column1 = gtk_tree_view_column_new();
1249     add_icon_renderer(GTK_TREE_VIEW(_w.treeview), column1, "", "pixbuf", TREE_ICON_COLUMN, NULL);
1250     add_text_renderer(GTK_TREE_VIEW(_w.treeview), column1, "Profile", "text", TREE_TEXT_COLUMN, NULL);
1251     gtk_tree_view_append_column(GTK_TREE_VIEW(_w.treeview), column1);
1252     //add_text_column(GTK_TREE_VIEW(_w.treeview), "Comment", "text", TOOLTIP_COLUMN, NULL);
1253 
1254     _w.notebook = GTK_NOTEBOOK(get_widget("notebook"));
1255 
1256     _w.b_new = get_widget("tree_button_new");
1257     g_signal_connect(_w.b_new, "clicked", G_CALLBACK(on_button_new_clicked), this);
1258 
1259     _w.b_copy = get_widget("tree_button_copy");
1260     g_signal_connect(_w.b_copy, "clicked", G_CALLBACK(on_button_copy_clicked), this);
1261 
1262     _w.b_delete = get_widget("tree_button_delete");
1263     g_signal_connect(_w.b_delete, "clicked", G_CALLBACK(on_button_delete_clicked), this);
1264 
1265     _w.b_up = get_widget("tree_button_up");
1266     g_signal_connect(_w.b_up, "clicked", G_CALLBACK(on_button_up_clicked), this);
1267 
1268     _w.b_down = get_widget("tree_button_down");
1269     g_signal_connect(_w.b_down, "clicked", G_CALLBACK(on_button_down_clicked), this);
1270 
1271     _w.b_expand = get_widget("tree_button_expand");
1272     g_signal_connect(_w.b_expand, "clicked", G_CALLBACK(on_button_expand_clicked), this);
1273 
1274     _w.b_collapse = get_widget("tree_button_collapse");
1275     g_signal_connect(_w.b_collapse, "clicked", G_CALLBACK(on_button_collapse_clicked), this);
1276 
1277     _w.b_ok = get_widget("dialog_button_ok");
1278     g_signal_connect(_w.b_ok, "clicked", G_CALLBACK(on_button_ok_clicked), this);
1279 
1280     _w.b_close = get_widget("dialog_button_close");
1281     g_signal_connect(_w.b_close, "clicked", G_CALLBACK(on_button_close_clicked), this);
1282 
1283     /* setup the selection handler */
1284     GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(_w.treeview));
1285     gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE);
1286     g_signal_connect(G_OBJECT(select), "changed", G_CALLBACK(on_tree_selection_changed), this);
1287 
1288     _w.entry_profile_name = GTK_ENTRY(get_widget("system_entry_profile_name"));
1289     _w.on_profile_name_changed_id = g_signal_connect(_w.entry_profile_name, "changed", G_CALLBACK(on_profile_name_changed), this);
1290 
1291     _w.textview_comment = GTK_TEXT_VIEW(get_widget("system_textview_comment"));
1292     _w.textbuffer_comment = gtk_text_view_get_buffer(_w.textview_comment);
1293     _w.on_comment_changed_id = g_signal_connect(_w.textbuffer_comment, "changed", G_CALLBACK(on_comment_changed), this);
1294 
1295     wire_check_button("tape_file",   "/tapes/", "media_check_button_tape",  "media_filechooserbutton_tape",  "media_button_tape_clear");
1296     wire_check_button("audio_file",       NULL, "media_check_button_audio", "media_filechooserbutton_audio", "media_button_audio_clear");
1297     wire_check_button("disk_1",      "/disks/", "media_check_button_disk1", "media_filechooserbutton_disk1", "media_button_disk1_clear");
1298     wire_check_button("disk_2",      "/disks/", "media_check_button_disk2", "media_filechooserbutton_disk2", "media_button_disk2_clear");
1299     wire_check_button("disk_3",      "/disks/", "media_check_button_disk3", "media_filechooserbutton_disk3", "media_button_disk3_clear");
1300     wire_check_button("disk_4",      "/disks/", "media_check_button_disk4", "media_filechooserbutton_disk4", "media_button_disk4_clear");
1301     wire_check_button("hard_disk_1",      NULL, "media_check_button_hd1",   "media_filechooserbutton_hd1",   "media_button_hd1_clear");
1302     wire_check_button("hard_disk_2",      NULL, "media_check_button_hd2",   "media_filechooserbutton_hd2",   "media_button_hd2_clear");
1303 
1304     _w.check_button_display_scale = GTK_CHECK_BUTTON(get_widget("display_check_button_scale"));
1305     _w.check_button_display_effects = GTK_CHECK_BUTTON(get_widget("display_check_button_effects"));
1306     _w.check_button_display_mem_access = GTK_CHECK_BUTTON(get_widget("display_check_button_mem_access"));
1307     _w.check_button_display_debug = GTK_CHECK_BUTTON(get_widget("display_check_button_debug"));
1308     _w.spin_button_display_scale = GTK_SPIN_BUTTON(get_widget("display_spin_button_scale"));
1309     _w.combobox_display_effects = GTK_COMBO_BOX(get_widget("display_combobox_effects"));
1310     _w.combobox_display_mem_access = GTK_COMBO_BOX(get_widget("display_combobox_mem_access"));
1311     _w.combobox_display_debug = GTK_COMBO_BOX(get_widget("display_combobox_debug"));
1312     wire_check_button("display_scale",      _w.check_button_display_scale, G_CALLBACK(on_display_check_button_toggled),      GTK_WIDGET(_w.spin_button_display_scale));
1313     wire_check_button("display_effects",    _w.check_button_display_effects, G_CALLBACK(on_display_check_button_toggled),    GTK_WIDGET(_w.combobox_display_effects));
1314     wire_check_button("display_mem_access", _w.check_button_display_mem_access, G_CALLBACK(on_display_check_button_toggled), GTK_WIDGET(_w.combobox_display_mem_access));
1315     wire_check_button("display_debug",      _w.check_button_display_debug, G_CALLBACK(on_display_check_button_toggled),      GTK_WIDGET(_w.combobox_display_debug));
1316     _w.on_display_scale_value_changed_id = g_signal_connect(_w.spin_button_display_scale, "value-changed", G_CALLBACK(on_display_scale_value_changed), this);
1317     _w.on_display_effects_changed_id = g_signal_connect(_w.combobox_display_effects, "changed", G_CALLBACK(on_display_effects_changed), this);
1318     _w.on_display_mem_access_changed_id = g_signal_connect(_w.combobox_display_mem_access, "changed", G_CALLBACK(on_display_mem_access_changed), this);
1319     _w.on_display_debug_changed_id = g_signal_connect(_w.combobox_display_debug, "changed", G_CALLBACK(on_display_debug_changed), this);
1320 
1321     _w.check_button_d004 = GTK_CHECK_BUTTON(get_widget("kc85_checkbutton_d004"));
1322     _w.check_button_f8_rom = GTK_CHECK_BUTTON(get_widget("kc85_checkbutton_f8_rom"));
1323     _w.check_button_busdrivers = GTK_CHECK_BUTTON(get_widget("kc85_checkbutton_busdrivers"));
1324     _w.combobox_d004 = GTK_COMBO_BOX(get_widget("kc85_combobox_d004"));
1325     _w.combobox_f8_rom = GTK_COMBO_BOX(get_widget("kc85_combobox_f8_rom"));
1326     _w.spin_button_busdrivers = GTK_SPIN_BUTTON(get_widget("kc85_spinbutton_busdrivers"));
1327     wire_check_button("d004", _w.check_button_d004, G_CALLBACK(on_kc85_settings_check_button_toggled), GTK_WIDGET(_w.combobox_d004));
1328     wire_check_button("d004_f8", _w.check_button_f8_rom, G_CALLBACK(on_kc85_settings_check_button_toggled), GTK_WIDGET(_w.combobox_f8_rom));
1329     wire_check_button("busdrivers", _w.check_button_busdrivers, G_CALLBACK(on_kc85_settings_check_button_toggled), GTK_WIDGET(_w.spin_button_busdrivers));
1330 
1331     _w.on_kc85_d004_changed_id = g_signal_connect(_w.combobox_d004, "changed", G_CALLBACK(on_kc85_d004_changed), this);
1332     _w.on_kc85_f8_rom_changed_id = g_signal_connect(_w.combobox_f8_rom, "changed", G_CALLBACK(on_kc85_f8_rom_changed), this);
1333     _w.on_kc85_busdrivers_changed_id = g_signal_connect(_w.spin_button_busdrivers, "value-changed", G_CALLBACK(on_kc85_busdrivers_changed), this);
1334 
1335     for (int a = 0;a < NR_OF_MODULES;a++) {
1336         _w.combobox_module[a] = GTK_COMBO_BOX(get_widget("modules_combobox_module", a + 1));
1337         _w.on_module_changed_id[a] = g_signal_connect(_w.combobox_module[a], "changed", G_CALLBACK(on_module_changed), this);
1338         bind_list_model_column(_w.combobox_module[a], MODULES_NAME_COLUMN, NULL);
1339     }
1340     _w.check_button_modules = GTK_CHECK_BUTTON(get_widget("modules_check_button"));
1341     g_signal_connect(_w.check_button_modules, "toggled", G_CALLBACK(on_modules_check_button_toggled), this);
1342 
1343     _w.liststore_system = get_system_list_model();
1344     _w.combobox_system_type = GTK_COMBO_BOX(get_widget("system_combobox_system_type"));
1345     gtk_combo_box_set_model(_w.combobox_system_type, GTK_TREE_MODEL(_w.liststore_system));
1346     bind_list_model_column(_w.combobox_system_type, 0, NULL);
1347     _w.on_system_type_changed_id = g_signal_connect(_w.combobox_system_type, "changed", G_CALLBACK(on_system_type_changed), this);
1348 
1349     _w.combobox_system_variant = GTK_COMBO_BOX(get_widget("system_combobox_system_variant"));
1350     bind_list_model_column(_w.combobox_system_variant, 0, NULL);
1351 
1352     _w.on_system_variant_changed_id = g_signal_connect(_w.combobox_system_variant, "changed", G_CALLBACK(on_system_variant_changed), this);
1353 
1354     _w.check_button_system_variant = GTK_CHECK_BUTTON(get_widget("system_check_button_system_variant"));
1355     g_signal_connect(_w.check_button_system_variant, "toggled", G_CALLBACK(on_system_variant_check_button_toggled), this);
1356 
1357     for (int a = 0;a < NR_OF_ROMS;a++) {
1358         _w.roms_label[a] = GTK_LABEL(get_widget("roms_label_rom", a + 1));
1359         _w.roms_comboboxentry[a] = GTK_COMBO_BOX_ENTRY(get_widget("roms_comboboxentry_rom", a + 1));
1360         _w.roms_open_button[a] = GTK_BUTTON(get_widget("roms_open_button_rom", a + 1));
1361         _w.roms_check_button[a] = GTK_CHECK_BUTTON(get_widget("roms_check_button_rom", a + 1));
1362         wire_check_button("rom_dummy",
1363                       _w.roms_check_button[a],
1364                       G_CALLBACK(on_roms_settings_check_button_toggled),
1365                       GTK_WIDGET(_w.roms_comboboxentry[a]),
1366                       GTK_WIDGET(_w.roms_open_button[a]));
1367 
1368         g_signal_connect(_w.roms_open_button[a], "clicked", G_CALLBACK(on_rom_open_clicked), this);
1369         _w.on_rom_changed_id[a] = g_signal_connect(_w.roms_comboboxentry[a], "changed", G_CALLBACK(on_rom_changed), this);
1370 
1371         GtkListStore *store = gtk_list_store_new(ROMS_N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
1372         gtk_combo_box_set_model(GTK_COMBO_BOX(_w.roms_comboboxentry[a]), GTK_TREE_MODEL(store));
1373         gtk_combo_box_entry_set_text_column(_w.roms_comboboxentry[a], 0);
1374         g_object_unref(store);
1375     }
1376 
1377     _w.entry_network_ip_address = GTK_ENTRY(get_widget("ip_address_entry"));
1378     set_preferences_key(G_OBJECT(_w.entry_network_ip_address), "network_ip_address");
1379     _w.on_network_changed_id[0] = g_signal_connect(_w.entry_network_ip_address, "changed", G_CALLBACK(on_network_changed), this);
1380     wire_check_button("network_ip_address", GTK_CHECK_BUTTON(get_widget("ip_address_checkbutton")), G_CALLBACK(on_network_settings_check_button_toggled), GTK_WIDGET(_w.entry_network_ip_address));
1381 
1382     _w.entry_network_netmask = GTK_ENTRY(get_widget("netmask_entry"));
1383     set_preferences_key(G_OBJECT(_w.entry_network_netmask), "network_netmask");
1384     _w.on_network_changed_id[1] = g_signal_connect(_w.entry_network_netmask, "changed", G_CALLBACK(on_network_changed), this);
1385     wire_check_button("network_netmask", GTK_CHECK_BUTTON(get_widget("netmask_checkbutton")), G_CALLBACK(on_network_settings_check_button_toggled), GTK_WIDGET(_w.entry_network_netmask));
1386 
1387     _w.entry_network_gateway = GTK_ENTRY(get_widget("gateway_entry"));
1388     set_preferences_key(G_OBJECT(_w.entry_network_gateway), "network_gateway");
1389     _w.on_network_changed_id[2] = g_signal_connect(_w.entry_network_gateway, "changed", G_CALLBACK(on_network_changed), this);
1390     wire_check_button("network_gateway", GTK_CHECK_BUTTON(get_widget("gateway_checkbutton")), G_CALLBACK(on_network_settings_check_button_toggled), GTK_WIDGET(_w.entry_network_gateway));
1391 
1392     _w.entry_network_dns_server = GTK_ENTRY(get_widget("dns_server_entry"));
1393     set_preferences_key(G_OBJECT(_w.entry_network_dns_server), "network_dns_server");
1394     _w.on_network_changed_id[3] = g_signal_connect(_w.entry_network_dns_server, "changed", G_CALLBACK(on_network_changed), this);
1395     wire_check_button("network_dns_server", GTK_CHECK_BUTTON(get_widget("dns_server_checkbutton")), G_CALLBACK(on_network_settings_check_button_toggled), GTK_WIDGET(_w.entry_network_dns_server));
1396 
1397     collapse_tree();
1398 
1399     init_dialog(NULL, NULL);
1400 }
1401 
1402 void
save(void)1403 OptionsWindow::save(void) {
1404     string config_name = _current_profile->get_config_name();
1405 
1406     Preferences::instance()->save();
1407 
1408     GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(_w.treeview));
1409     gtk_tree_model_foreach(model, tree_model_foreach_func_delete, this);
1410 
1411     /* select parent if we have deleted the currently selected profile */
1412     if (Preferences::instance()->find_profile(config_name.c_str()) == NULL) {
1413         GtkTreeIter iter;
1414         GtkTreeModel *model = get_selected_tree_iter(&iter);
1415         if (model != NULL) {
1416             GtkTreeIter parent;
1417             if (gtk_tree_model_iter_parent(model, &parent, &iter)) {
1418                 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(_w.treeview));
1419                 gtk_tree_selection_select_iter(selection, &parent);
1420             }
1421         }
1422     }
1423 
1424     // delete in reverse order. otherwise we invalidate the collected path strings
1425     for (list<string>::reverse_iterator it = _delete_path.rbegin();it != _delete_path.rend();it++) {
1426         GtkTreeIter iter;
1427         if (gtk_tree_model_get_iter_from_string(model, &iter, (*it).c_str())) {
1428             gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
1429         }
1430     }
1431     _delete_path.clear();
1432 
1433     hide();
1434 }
1435 
1436 void
reject(void)1437 OptionsWindow::reject(void) {
1438     Preferences::instance()->reject();
1439     apply_profile();
1440     hide();
1441 }
1442