1 /* vim: set fdm=marker: */
2 /** \file   uisettings.c
3  * \brief   GTK3 main settings dialog
4  *
5  * \author  Bas Wassink <b.wassink@ziggo.nl>
6  */
7 
8 /*
9  * $VICERES SaveResourcesOnExit     all
10  * $VICERES ConfirmOnExit           all
11  */
12 
13 /*
14  * This file is part of VICE, the Versatile Commodore Emulator.
15  * See README for copyright notice.
16  *
17  *  This program is free software; you can redistribute it and/or modify
18  *  it under the terms of the GNU General Public License as published by
19  *  the Free Software Foundation; either version 2 of the License, or
20  *  (at your option) any later version.
21  *
22  *  This program is distributed in the hope that it will be useful,
23  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
24  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  *  GNU General Public License for more details.
26  *
27  *  You should have received a copy of the GNU General Public License
28  *  along with this program; if not, write to the Free Software
29  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
30  *  02111-1307  USA.
31  */
32 
33 
34 /* The settings_grid is supposed to become this:
35  *
36  * +--------------+---------------------------+
37  * | treeview     |                           |
38  * |  with        |                           |
39  * |   settings   |    central widget,        |
40  * |  more        |    depending on which     |
41  * |   foo        |    item is selected in    |
42  * |   bar        |    the treeview           |
43  * |    whatever  |                           |
44  * | burp         |                           |
45  * +--------------+---------------------------+
46  *
47  * And this is handled by the dialog itself:
48  * +------------------------------------------+
49  * | load | save | load... | save... | close  |
50  * +------------------------------------------+
51  */
52 
53 
54 #include "vice.h"
55 
56 #include <gtk/gtk.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 
61 #include "archdep.h"
62 #include "lib.h"
63 #include "log.h"
64 #include "util.h"
65 #include "machine.h"
66 #include "resources.h"
67 #include "vsync.h"
68 
69 #include "vice_gtk3.h"
70 
71 #include "ui.h"
72 #include "settings_speed.h"
73 #include "settings_keyboard.h"
74 #include "settings_sound.h"
75 #include "settings_autostart.h"
76 #include "settings_drive.h"
77 #include "settings_model.h"
78 #include "settings_misc.h"
79 #include "settings_ramreset.h"
80 #include "settings_video.h"
81 #include "settings_sampler.h"
82 #include "settings_printer.h"
83 #include "settings_controlport.h"
84 #include "settings_joystick.h"
85 #include "settings_mouse.h"
86 #include "settings_soundchip.h"
87 #include "settings_monitor.h"
88 #include "settings_romset.h"
89 #include "settings_snapshot.h"
90 #ifdef HAVE_RAWNET
91 # include "settings_ethernet.h"
92 #endif
93 #include "settings_rs232.h"
94 #include "scpu64settingswidget.h"
95 #include "c64dtvflashsettingswidget.h"
96 
97 /* I/O extension widgets */
98 #include "settings_io.h"
99 #include "settings_io_c64_memhacks.h"
100 #include "settings_io_georam.h"
101 #include "reuwidget.h"
102 #include "ramcartwidget.h"
103 #include "dqbbwidget.h"
104 #include "expertwidget.h"
105 #include "isepicwidget.h"
106 #include "easyflashwidget.h"
107 #include "gmod2widget.h"
108 #include "mmcrwidget.h"
109 #include "mmc64widget.h"
110 #include "ide64widget.h"
111 #include "retroreplaywidget.h"
112 
113 #ifdef HAVE_RAWNET
114 # include "ethernetcartwidget.h"
115 # include "rrnetmk3widget.h"
116 #endif
117 
118 #include "c128functionromwidget.h"
119 #include "ieee488widget.h"
120 #include "digimaxwidget.h"
121 #include "magicvoicewidget.h"
122 #include "midiwidget.h"
123 #include "sfxsoundexpanderwidget.h"
124 #include "ds12c887widget.h"
125 #include "userportdeviceswidget.h"
126 #include "tapeportdeviceswidget.h"
127 #include "sidcartwidget.h"
128 #include "v364speechwidget.h"
129 #include "sfxsoundsamplerwidget.h"
130 #include "megacartwidget.h"
131 #include "petreuwidget.h"
132 #include "petcolourgraphicswidget.h"
133 #include "petdwwwidget.h"
134 #include "supersnapshotwidget.h"
135 #include "cpmwidget.h"
136 #include "burstmodewidget.h"
137 #include "c128fullbankswidget.h"
138 #include "plus4aciawidget.h"
139 #include "plus4digiblasterwidget.h"
140 #include "finalexpansionwidget.h"
141 #include "vicflashwidget.h"
142 #include "ultimemwidget.h"
143 #include "vicieee488widget.h"
144 #include "vicioramwidget.h"
145 #include "vfliwidget.h"
146 #include "petdiagpinwidget.h"
147 #include "pethrewidget.h"
148 #include "settings_crt.h"
149 #include "uimachinewindow.h"
150 
151 /* VSID stuff */
152 #include "hvscsettingswidget.h"
153 
154 
155 #include "uisettings.h"
156 
157 
158 static const char *treeview_css =
159 "@binding-set SettingsTreeViewBinding\n"
160 "{\n"
161 "    bind \"Left\"  { \"select-cursor-parent\" ()\n"
162 "                     \"expand-collapse-cursor-row\" (0,0,0) };\n"
163 "    bind \"Right\" { \"expand-collapse-cursor-row\" (0,1,0) };\n"
164 "}\n"
165 "\n"
166 "GtkTreeView\n"
167 "{\n"
168 "    -gtk-key-bindings: SettingsTreeViewBinding;\n"
169 "}\n";
170 
171 
172 /** \brief  Number of columns in the tree model
173  */
174 #define NUM_COLUMNS 3
175 
176 
177 /** \brief  Column indici for the tree model
178  */
179 enum {
180     COLUMN_NAME = 0,    /**< name */
181     COLUMN_ID,          /**< id */
182     COLUMN_CALLBACK     /**< callback function */
183 };
184 
185 
186 /** \brief  Initial dialog width
187  *
188  * This is not how wide the dialog will actually become, that is determined by
189  * the Gtk theme applied. But it's a rough estimate.
190  */
191 #define DIALOG_WIDTH 800
192 
193 
194 /** \brief  Initial dialog height
195  *
196  * This is not how tall the dialog will actually become, that is determined by
197  * the Gtk theme applied. But it's a rough estimate.
198  */
199 #define DIALOG_HEIGHT 560
200 
201 
202 /** \brief  Maximum width the UI can be
203  *
204  * This again is not a really a fixed value, but more of an indicator when the
205  * UI might get too large after any decorations are applied. The idea is to
206  * have a UI that works on a 1280x768 resolution without requiring scrollbars.
207  */
208 #define DIALOG_WIDTH_MAX 1024
209 
210 
211 /** \brief  Maximum height the UI can be
212  *
213  * This again is not a really a fixed value, but more of an indicator when the
214  * UI might get too large after any decorations are applied. The idea is to
215  * have a UI that works on a 1280x768 resolution without requiring scrollbars.
216  */
217 #define DIALOG_HEIGHT_MAX 640
218 
219 
220 /** \brief  Enum used for the "response" callback of the settings dialog
221  *
222  * All values must be positive since Gtk reserves standard responses in its
223  * GtkResponse enum as negative values.
224  */
225 enum {
226     RESPONSE_RESET = 1, /**< reset current central widget */
227     RESPONSE_FACTORY,   /**< set current central widget's resources to their
228                              factory settings */
229     RESPONSE_DEFAULT    /**< Restore default settings */
230 };
231 
232 
233 /*
234  * I/O extensions per emulator
235  */
236 
237 /* {{{ c64_io_extensions */
238 /** \brief  List of C64 I/O extensions (x64, x64sc)
239  *
240  * Every empty line indicates a separator in the Gtk2 UI's menu
241  */
242 static ui_settings_tree_node_t c64_io_extensions[] = {
243     { "Memory Expansion Hacks",
244        "mem-hacks",
245        settings_io_c64_memhacks_widget_create, NULL },
246 
247     { "GEO-RAM",
248         "geo-ram",
249         settings_io_georam_widget_create, NULL },
250     { "RAM Expansion Module",
251         "reu",
252         reu_widget_create, NULL },
253     { "RamCart",
254         "ramcart",
255         ramcart_widget_create, NULL },
256 
257     { "Double Quick Brown Box",
258         "dqbb",
259         dqbb_widget_create, NULL },
260     { "Expert Cartridge",
261         "expert-cart",
262         expert_widget_create, NULL },
263     { "ISEPIC",
264         "isepic",
265         isepic_widget_create, NULL },
266 
267     { "EasyFlash",
268         "easyflash",
269         easyflash_widget_create, NULL },
270     { "GMod2",
271         "gmod2",
272         gmod2_widget_create, NULL },
273     { "IDE64",
274         "ide64",
275         ide64_widget_create, NULL },
276     { "MMC64",
277         "mmc64",
278         mmc64_widget_create, NULL },
279     { "MMC Replay",
280         "mmcr",
281         mmcr_widget_create, NULL },
282     { "Retro Replay",
283         "retroreplay",
284         retroreplay_widget_create, NULL },
285     { "Super Snapshot V5",
286         "super-snapshot",
287         super_snapshot_widget_create, NULL },
288 
289 #ifdef HAVE_RAWNET
290     { "Ethernet Cartridge",
291         "ethernet-cart",
292         ethernet_cart_widget_create, NULL },
293     { "RR-Net Mk3",
294         "rrnetmk3",
295         rrnetmk3_widget_create, NULL },
296 #endif
297 
298     { "IEEE-448 Interface",
299         "ieee-488",
300         ieee488_widget_create, NULL },
301     { "Burst Mode Modification",
302         "burstmode-mode",
303         burst_mode_widget_create, NULL },
304 
305     { "DigiMAX",
306         "digimax",
307         digimax_widget_create, NULL },
308     { "Magic Voice",
309         "magic-voice",
310         magic_voice_widget_create, NULL },
311     { "MIDI emulation",
312         "midi",
313         midi_widget_create, NULL },
314     { "SFX Sound Expander",
315         "sfx-expander",
316         sfx_sound_expander_widget_create, NULL },
317     { "SFX Sound Sampler",
318         "sfx-sampler",
319         sfx_sound_sampler_widget_create, NULL },
320     { "CP/M Cartridge",
321         "cpm-cart",
322         cpm_widget_create, NULL },
323 
324     { "DS12C887 Real Time Clock",
325         "ds12c887-rtc",
326         ds12c887_widget_create, NULL },
327     { "Userport devices",
328         "userport-devices",
329         userport_devices_widget_create, NULL },
330     { "Tape port devices",
331         "tapeport-devices",
332         tapeport_devices_widget_create, NULL },
333 
334     UI_SETTINGS_TERMINATOR
335 };
336 /* }}} */
337 
338 /* {{{ scpu64_io_extensions */
339 /** \brief  List of SuperCPU64 extensions (xscpu64)
340  *
341  * Every empty line indicates a separator in the Gtk2 UI's menu
342  */
343 static ui_settings_tree_node_t scpu64_io_extensions[] = {
344     { "GEO-RAM",
345         "geo-ram",
346         settings_io_georam_widget_create, NULL },
347     { "RAM Expansion Module",
348         "reu",
349         reu_widget_create, NULL },
350     { "RamCart",
351         "ramcart",
352         ramcart_widget_create, NULL },
353 
354     { "Double Quick Brown Box",
355         "dqbb",
356         dqbb_widget_create, NULL },
357     { "Expert Cartridge",
358         "expert-cart",
359         expert_widget_create, NULL },
360     { "ISEPIC",
361         "isepic",
362         isepic_widget_create, NULL },
363 
364     { "EasyFlash",
365         "easyflash",
366         easyflash_widget_create, NULL },
367     { "GMod2",
368         "gmod2",
369         gmod2_widget_create, NULL },
370     { "IDE64",
371         "ide64",
372         ide64_widget_create, NULL },
373     { "MMC64",
374         "mmc64",
375         mmc64_widget_create, NULL },
376     { "MMC Replay",
377         "mmcr",
378         mmcr_widget_create, NULL },
379     { "Retro Replay",
380         "retroreplay",
381         retroreplay_widget_create, NULL },
382     { "Super Snapshot V5",
383         "super-snapshot",
384         super_snapshot_widget_create, NULL },
385 
386 #ifdef HAVE_RAWNET
387     { "Ethernet Cartridge",
388         "ethernet-cart",
389         ethernet_cart_widget_create, NULL },
390     { "RR-Net Mk3",
391         "rrnetmk3",
392         rrnetmk3_widget_create, NULL },
393 #endif
394 
395     { "IEEE-448 Interface",
396         "ieee-488",
397         ieee488_widget_create, NULL },
398     { "Burst Mode Modification",
399         "burstmode-mode",
400         burst_mode_widget_create, NULL },
401 
402     { "DigiMAX",
403         "digimax",
404         digimax_widget_create, NULL },
405     { "Magic Voice",
406         "magic-voice",
407         magic_voice_widget_create, NULL },
408     { "MIDI emulation",
409         "midi",
410         midi_widget_create, NULL },
411     { "SFX Sound Expander",
412         "sfx-expander",
413         sfx_sound_expander_widget_create, NULL },
414     { "SFX Sound Sampler",
415         "sfx-sampler",
416         sfx_sound_sampler_widget_create, NULL },
417     { "CP/M Cartridge",
418         "cpm-cart",
419         cpm_widget_create, NULL },
420 
421     { "DS12C887 Real Time Clock",
422         "ds12c887-rtc",
423         ds12c887_widget_create, NULL },
424     { "Userport devices",
425         "userport-devices",
426         userport_devices_widget_create, NULL },
427 
428     UI_SETTINGS_TERMINATOR
429 };
430 /* }}} */
431 
432 /* {{{ c128_io_extensions */
433 /** \brief  I/O extensions for C128
434  */
435 static ui_settings_tree_node_t c128_io_extensions[] = {
436     { "Function ROM",
437         "function-rom",
438         c128_function_rom_widget_create, NULL },
439     { "Banks 2 & 3",
440         "banks-23",
441         c128_full_banks_widget_create, NULL },
442 
443     { "GEO-RAM",
444         "geo-ram",
445         settings_io_georam_widget_create, NULL },
446     { "RAM Expansion Module",
447         "reu",
448         reu_widget_create, NULL },
449     { "RamCart",
450         "ramcart",
451         ramcart_widget_create, NULL },
452 
453     { "Double Quick Brown Box",
454         "dqbb",
455         dqbb_widget_create, NULL },
456     { "Expert Cartridge",
457         "expert-cart",
458         expert_widget_create, NULL },
459     { "ISEPIC",
460         "isepic",
461         isepic_widget_create, NULL },
462 
463     { "EasyFlash",
464         "easyflash",
465         easyflash_widget_create, NULL },
466     { "GMod2",
467         "gmod2",
468         gmod2_widget_create, NULL },
469     { "IDE64",
470         "ide64",
471         ide64_widget_create, NULL },
472     { "MMC64",
473         "mmc64",
474         mmc64_widget_create, NULL },
475     { "MMC Replay",
476         "mmcr",
477         mmcr_widget_create, NULL },
478     { "Retro Replay",
479         "retroreplay",
480         retroreplay_widget_create, NULL },
481     { "Super Snapshot V5",
482         "super-snapshot",
483         super_snapshot_widget_create, NULL },
484 
485 #ifdef HAVE_RAWNET
486     { "Ethernet Cartridge",
487         "ethernet-cart",
488         ethernet_cart_widget_create, NULL },
489     { "RR-Net Mk3",
490         "rrnetmk3",
491         rrnetmk3_widget_create, NULL },
492 #endif
493 
494     { "IEEE-448 Interface",
495         "ieee-488",
496         ieee488_widget_create, NULL },
497     { "Burst Mode Modification",
498         "burstmode-mode",
499         burst_mode_widget_create, NULL },
500 
501     { "DigiMAX",
502         "digimax",
503         digimax_widget_create, NULL },
504     { "Magic Voice",
505         "magic-voice",
506         magic_voice_widget_create, NULL },
507     { "MIDI emulation",
508         "midi",
509         midi_widget_create, NULL },
510     { "SFX Sound Expander",
511         "sfx-expander",
512         sfx_sound_expander_widget_create, NULL },
513     { "SFX Sound Sampler",
514         "sfx-sampler",
515         sfx_sound_sampler_widget_create, NULL },
516     { "CP/M Cartridge",
517         "cpm-cart",
518         cpm_widget_create, NULL },
519 
520     { "DS12C887 Real Time Clock",
521         "ds12c887-rtc",
522         ds12c887_widget_create, NULL },
523     { "Userport devices",
524         "userport-devices",
525         userport_devices_widget_create, NULL },
526     { "Tape port devices",
527         "tapeport-devices",
528         tapeport_devices_widget_create, NULL },
529 
530     UI_SETTINGS_TERMINATOR
531 };
532 /* }}} */
533 
534 /* {{{ vic20_io_extensions */
535 /** \brief  List of VIC-20 I/O extensions
536  *
537  * Every empty line indicates a separator in the Gtk2 UI's menu
538  */
539 static ui_settings_tree_node_t vic20_io_extensions[] = {
540     { "Mega Cart",
541         "mega-cart",
542         mega_cart_widget_create, NULL },
543     { "Final Expansion",
544         "final-expansion",
545         final_expansion_widget_create, NULL },
546     { "Vic Flash Plugin",
547         "vic-flash-plugin",
548         vic_flash_widget_create, NULL },
549     { "UltiMem",
550         "ultimem",
551         ultimem_widget_create, NULL },
552     { "SID Cartridge",
553         "sid-cart",
554         sidcart_widget_create, NULL },
555     { "VIC-1112 IEEE-488 interface",
556         "ieee-488",
557         vic_ieee488_widget_create, NULL },
558     { "I/O RAM",
559         "io-ram",
560         vic_ioram_widget_create, NULL },
561     { "VFLI modification",
562         "vfli",
563         vfli_widget_create, NULL },
564 
565     { "DigiMAX (MasC=uerade",
566         "digimax",
567         digimax_widget_create, NULL },
568     { "DS12C887 RTC (MasC=uerade)",
569         "ds12c887-rtc",
570         ds12c887_widget_create, NULL },
571     { "GEO-RAM (MasC=uerade)",
572        "geo-ram",
573        settings_io_georam_widget_create, NULL },
574     { "SFX Sound Expander (MasC=uerade)",
575         "sfx-expander",
576         sfx_sound_expander_widget_create, NULL },
577     { "SFX Sound Sampler (MasC=uerade)",
578         "sfx-sampler",
579         sfx_sound_sampler_widget_create, NULL },
580 
581 #ifdef HAVE_RAWNET
582     { "Ethernet Cartridge (MasC=uerade)",
583         "ethernet-cart",
584         ethernet_cart_widget_create, NULL },
585 #endif
586 
587     { "MIDI emulation",
588         "midi",
589         midi_widget_create, NULL },
590     { "Userport devices",
591         "userport-devices",
592         userport_devices_widget_create, NULL },
593     { "Tapeport devices",
594         "tapeport-devices",
595         tapeport_devices_widget_create, NULL },
596 
597     UI_SETTINGS_TERMINATOR
598 };
599 /* }}} */
600 
601 /* {{{ plus4_io_extensions */
602 /** \brief  List of Plus4 I/O extensions
603  *
604  * Every empty line indicates a separator in the Gtk2 UI's menu
605  */
606 static ui_settings_tree_node_t plus4_io_extensions[] = {
607     { "ACIA",
608         "acia",
609         plus4_acia_widget_create, NULL },
610     { "Digiblaster add-on",
611         "digiblaster",
612         plus4_digiblaster_widget_create, NULL },
613     { "SID Cartridge",
614         "sid-cart",
615         sidcart_widget_create, NULL },
616     { "V364 Speech",
617         "v364",
618         v364_speech_widget_create, NULL },
619 
620     { "Userport devices",
621         "userport-devices",
622         userport_devices_widget_create, NULL },
623     { "Tape port devices",
624         "tapeport-devices",
625         tapeport_devices_widget_create, NULL },
626 
627     UI_SETTINGS_TERMINATOR
628 };
629 /* }}} */
630 
631 /* {{{ pet_io_extensions */
632 /** \brief  List of PET I/O extensions
633  *
634  * Every empty line indicates a separator in the Gtk2 UI's menu
635  */
636 static ui_settings_tree_node_t pet_io_extensions[] = {
637     { "PET RAM Expansion Unit",
638         "pet-reu",
639         pet_reu_widget_create, NULL },
640     { "PET Colour graphics",
641         "pet-colour",
642         pet_colour_graphics_widget_create, NULL },
643     { "PET DWW hi-res graphics",
644         "pet-dww",
645         pet_dww_widget_create, NULL },
646     { "PET HRE hi-res graphics",
647         "pet-hre",
648         pet_hre_widget_create, NULL },
649     { "SID Cartridge",
650         "sid-cart",
651         sidcart_widget_create, NULL },
652     { "Userport devices",
653         "userport-devices",
654         userport_devices_widget_create, NULL },
655     { "Tape port devices",
656         "tapeport-devices",
657         tapeport_devices_widget_create, NULL },
658     { "PET userport diagnostic pin",
659         "pet-diagpin",
660         pet_diagpin_widget_create, NULL },
661     UI_SETTINGS_TERMINATOR
662 };
663 /* }}} */
664 
665 /* {{{ cbm5x0_io_extensions */
666 /** \brief  List of CBM 5x0 I/O extensions
667  *
668  * Every empty line indicates a separator in the Gtk2 UI's menu
669  */
670 static ui_settings_tree_node_t cbm5x0_io_extensions[] = {
671     { "Tape port devices",
672         "tapeport-devices",
673         tapeport_devices_widget_create, NULL },
674     UI_SETTINGS_TERMINATOR
675 };
676 /* }}} */
677 
678 /* {{{ cbm6x0_io_extensions */
679 /** \brief  List of CBM 6x0 I/O extensions
680  *
681  * Every empty line indicates a separator in the Gtk2 UI's menu
682  */
683 static ui_settings_tree_node_t cbm6x0_io_extensions[] = {
684     { "Userport devices",
685         "userport-devices",
686         userport_devices_widget_create, NULL },
687     { "Tape port devices",
688         "tapeport_devices",
689         tapeport_devices_widget_create, NULL },
690     UI_SETTINGS_TERMINATOR
691 };
692 /* }}} */
693 
694 
695 /*
696  * Main tree nodes per emulator
697  */
698 
699 /*****************************************************************************
700  *                  VSID tree nodes for the settings UI                      *
701  ****************************************************************************/
702 
703 /* {{{ main_nodes_vsid */
704 /** \brief  Main tree nodes for VSID
705  */
706 static ui_settings_tree_node_t main_nodes_vsid[] = {
707    { "Sound settings",
708       "sound",
709       settings_sound_create, NULL },
710     { "SID settings",
711       "sid",
712       settings_soundchip_widget_create, NULL },
713     { "Speed settings",
714       "speed",
715        settings_speed_widget_create, NULL },
716     /* XXX: basically a selection between 'PAL'/'NTSC' (50/60Hz) */
717     { "Model settings",
718       "model",
719       settings_model_widget_create, NULL },
720 #if 0
721     /* XXX: do we need this? Sidplay allows ROM selection for Basic, Kernal and
722      *      Chargen, perhaps move into model settings, plenty of space there */
723     { "ROM settings",
724       "rom-settings",
725       settings_romset_widget_create, NULL },
726 #endif
727     /* XXX: perhaps required for VSID-specific things */
728     { "Miscellaneous",
729       "misc",
730       settings_misc_widget_create, NULL },
731     { "Monitor settings",
732       "monitor",
733       settings_monitor_widget_create, NULL },
734 
735     { "HVSC settings",
736       "hvsc",
737       hvsc_settings_widget_create, NULL },
738 
739     UI_SETTINGS_TERMINATOR
740 };
741 /* }}} */
742 
743 
744 /*****************************************************************************
745  *                  C64 tree nodes for the settings UI                       *
746  ****************************************************************************/
747 
748 /* {{{ machine_nodes_c64 */
749 static ui_settings_tree_node_t machine_nodes_c64[] = {
750     { "Model settings",
751       "model",
752       settings_model_widget_create, NULL },
753     { "Speed settings",
754       "speed",
755        settings_speed_widget_create, NULL },
756     { "Autostart settings",
757       "autostart",
758       settings_autostart_widget_create, NULL },
759     { "ROM settings",
760       "rom-settings",
761       settings_romset_widget_create, NULL },
762     { "RAM reset pattern",
763       "ram-reset",
764       settings_ramreset_widget_create, NULL },
765     { "Monitor settings",
766       "monitor",
767       settings_monitor_widget_create, NULL },
768     UI_SETTINGS_TERMINATOR
769 };
770 /* }}} */
771 
772 /* {{{ display_nodes_c64 */
773 static ui_settings_tree_node_t display_nodes_c64[] = {
774     { "VIC-II settings",
775       "vicii",
776       settings_video_create, NULL },
777     { "CRT settings",
778         "crt",
779         settings_crt_widget_create, NULL },
780     UI_SETTINGS_TERMINATOR
781 };
782 /* }}} */
783 
784 /* {{{ audio_nodes_c64 */
785 static ui_settings_tree_node_t audio_nodes_c64[] = {
786     { "Sound settings",
787       "sound",
788       settings_sound_create, NULL },
789     { "SID settings",
790       "sid",
791       settings_soundchip_widget_create, NULL },
792     { "Sampler settings",
793       "sampler",
794       settings_sampler_widget_create, NULL },
795     UI_SETTINGS_TERMINATOR
796 };
797 /* }}} */
798 
799 /* {{{ input_nodes_c64 */
800 static ui_settings_tree_node_t input_nodes_c64[] = {
801     { "Keyboard settings",
802       "keyboard",
803       settings_keyboard_widget_create, NULL },
804     { "Joystick settings",
805       "joystick",
806       settings_joystick_widget_create, NULL },
807     { "Control port settings",
808       "control-port",
809       settings_controlport_widget_create, NULL },
810     { "Mouse settings",
811       "mouse",
812       settings_mouse_widget_create, NULL },
813     UI_SETTINGS_TERMINATOR
814 };
815 /* }}} */
816 
817 /* {{{ peripheral_nodes_c64 */
818 static ui_settings_tree_node_t peripheral_nodes_c64[] = {
819     /* "Output devices? drive is also input */
820     { "Drive settings",
821       "drive",
822       settings_drive_widget_create, NULL },
823     { "Printer settings",
824       "printer",
825       settings_printer_widget_create, NULL },
826 #ifdef HAVE_RS232DEV
827     { "RS232 settings",
828       "rs232",
829       settings_rs232_widget_create, NULL },
830 #endif
831 #ifdef HAVE_RAWNET
832     { "Ethernet settings",
833       "ethernet",
834       settings_ethernet_widget_create, NULL },
835 #endif
836     UI_SETTINGS_TERMINATOR
837 };
838 /* }}} */
839 
840 
841 /* {{{ main_nodes_c64 */
842 /** \brief  Main tree nodes for x64/x64sc
843  */
844 static ui_settings_tree_node_t main_nodes_c64[] = {
845 
846     { "Machine settings",
847         "machine",
848         NULL, machine_nodes_c64 },
849     { "Display settings",
850         "display",
851         NULL, display_nodes_c64 },
852     { "Audio settings",
853         "audio",
854         NULL, audio_nodes_c64 },
855     { "Input devices",
856         "input",
857         NULL, input_nodes_c64 },
858     { "Peripheral devices",
859         "peripheral", /* I'll misspell this many times */
860         NULL, peripheral_nodes_c64 },
861    { "I/O extensions",
862       "io-extensions",
863       settings_io_widget_create, c64_io_extensions },
864     { "Snaphot/event/media recording",
865       "snapshot",
866       settings_snapshot_widget_create, NULL },
867     { "Miscellaneous",
868       "misc",
869       settings_misc_widget_create, NULL },
870     UI_SETTINGS_TERMINATOR
871 };
872 /* }}} */
873 
874 
875 /*****************************************************************************
876  *                  C64DTV tree nodes for the settings UI                    *
877  ****************************************************************************/
878 
879 /* {{{ machine_nodes_c64dtv */
880 static ui_settings_tree_node_t machine_nodes_c64dtv[] = {
881     { "Model settings",
882       "model",
883       settings_model_widget_create, NULL },
884     { "Speed settings",
885       "speed",
886        settings_speed_widget_create, NULL },
887     { "Autostart settings",
888       "autostart",
889       settings_autostart_widget_create, NULL },
890     { "ROM settings",
891       "rom-settings",
892       settings_romset_widget_create, NULL },
893     { "RAM reset pattern",
894       "ram-reset",
895       settings_ramreset_widget_create, NULL },
896     { "Monitor settings",
897       "monitor",
898       settings_monitor_widget_create, NULL },
899     UI_SETTINGS_TERMINATOR
900 };
901 /* }}} */
902 
903 /* {{{ display_nodes_c64dtv */
904 static ui_settings_tree_node_t display_nodes_c64dtv[] = {
905     { "VIC-II settings",
906       "vicii",
907       settings_video_create, NULL },
908     { "CRT settings",
909       "CRT",
910       settings_crt_widget_create, NULL },
911     UI_SETTINGS_TERMINATOR
912 };
913 /* }}} */
914 
915 /* {{{ audio_nodes_c64dtv */
916 static ui_settings_tree_node_t audio_nodes_c64dtv[] = {
917     { "Sound settings",
918       "sound",
919       settings_sound_create, NULL },
920     { "SID settings",
921       "sid",
922       settings_soundchip_widget_create, NULL },
923     { "Sampler settings",
924       "sampler",
925       settings_sampler_widget_create, NULL },
926     UI_SETTINGS_TERMINATOR
927 };
928 /* }}} */
929 
930 /* {{{ input_nodes_c64dtv */
931 static ui_settings_tree_node_t input_nodes_c64dtv[] = {
932     { "Keyboard settings",
933       "keyboard",
934       settings_keyboard_widget_create, NULL },
935     { "Joystick settings",
936       "joystick",
937       settings_joystick_widget_create, NULL },
938     { "Control port settings",
939       "control-port",
940       settings_controlport_widget_create, NULL },
941     { "Mouse settings",
942       "mouse",
943       settings_mouse_widget_create, NULL },
944     UI_SETTINGS_TERMINATOR
945 };
946 /* }}} */
947 
948 /* {{{ peripheral_nodes_c64dtv */
949 static ui_settings_tree_node_t peripheral_nodes_c64dtv[] = {
950     { "Drive settings",
951       "drive",
952       settings_drive_widget_create, NULL },
953     { "Printer settings",
954       "printer",
955       settings_printer_widget_create, NULL },
956 };
957 /* }}} */
958 
959 
960 /* {{{ main_nodes_c64dtv */
961 /** \brief  Main tree nodes for x64dtv
962  */
963 static ui_settings_tree_node_t main_nodes_c64dtv[] = {
964     { "Machine",    "machine",  NULL,   machine_nodes_c64dtv },
965     { "Display",    "display",  NULL,   display_nodes_c64dtv },
966     { "Audio",      "audio",    NULL,   audio_nodes_c64dtv },
967     { "Input devices",      "input",    NULL,   input_nodes_c64dtv },
968     { "Peripheral devices", "peripheral", NULL, peripheral_nodes_c64dtv },
969 
970     { "Flash",
971       "flash",
972       c64dtv_flash_settings_widget_create, NULL },
973     { "I/O extensions",
974       "io-extensions",
975       settings_io_widget_create, NULL },
976     { "Miscellaneous",
977       "misc",
978       settings_misc_widget_create, NULL },
979     { "Snaphot/event/media recording",
980       "snapshot",
981       settings_snapshot_widget_create, NULL },
982 
983     UI_SETTINGS_TERMINATOR
984 };
985 /* }}} */
986 
987 
988 /*****************************************************************************
989  *                      C128 tree nodes for the settings UI                  *
990  ****************************************************************************/
991 
992 /* {{{ machine_nodes_c128 */
993 /** \brief  Machine subnodes for c128
994  */
995 static ui_settings_tree_node_t machine_nodes_c128[] = {
996     { "Model settings",
997       "model",
998       settings_model_widget_create, NULL },
999     { "Speed settings",
1000       "speed",
1001        settings_speed_widget_create, NULL },
1002     { "Autostart settings",
1003       "autostart",
1004       settings_autostart_widget_create, NULL },
1005     { "ROM settings",
1006       "rom-settings",
1007       settings_romset_widget_create, NULL },
1008     { "RAM reset pattern",
1009       "ram-reset",
1010       settings_ramreset_widget_create, NULL },
1011     { "Monitor settings",
1012       "monitor",
1013       settings_monitor_widget_create, NULL },
1014     UI_SETTINGS_TERMINATOR
1015 };
1016 /* }}} */
1017 
1018 /* {{{ display_nodes_c128 */
1019 /** \brief  C128 Display sub nodes
1020  */
1021 static ui_settings_tree_node_t display_nodes_c128[] = {
1022     { "VIC-II settings",
1023       "vicii",
1024       settings_video_create, NULL },
1025     { "VDC settings",
1026       "vdc",
1027       settings_video_create_vdc, NULL },
1028     { "CRT settings",
1029       "crt",
1030       settings_crt_widget_create, NULL },
1031     UI_SETTINGS_TERMINATOR
1032 };
1033 /* }}} */
1034 
1035 /* {{{ audio_nodes_c128 */
1036 /** \brief  C128 Audio sub nodes
1037  */
1038 static ui_settings_tree_node_t audio_nodes_c128[] = {
1039     { "Sound settings",
1040       "sound",
1041       settings_sound_create, NULL },
1042     { "SID settings",
1043       "sid",
1044       settings_soundchip_widget_create, NULL },
1045     { "Sampler settings",
1046       "sampler",
1047       settings_sampler_widget_create, NULL },
1048     UI_SETTINGS_TERMINATOR
1049 };
1050 /* }}} */
1051 
1052 /* {{{ input_nodes_c128 */
1053 /** \brief  C128 Input sub nodes
1054  */
1055 static ui_settings_tree_node_t input_nodes_c128[] = {
1056     { "Keyboard settings",
1057       "keyboard",
1058       settings_keyboard_widget_create, NULL },
1059     { "Joystick settings",
1060       "joystick",
1061       settings_joystick_widget_create, NULL },
1062     { "Control port settings",
1063       "control-port",
1064       settings_controlport_widget_create, NULL },
1065     { "Mouse settings",
1066       "mouse",
1067       settings_mouse_widget_create, NULL },
1068     UI_SETTINGS_TERMINATOR
1069 };
1070 /* }}} */
1071 
1072 /* {{{ peripheral_nodes_c128 */
1073 /** \brief  C128 Peripheral sub nodes
1074  */
1075 static ui_settings_tree_node_t peripheral_nodes_c128[] = {
1076     /* "Output devices? drive is also input */
1077     { "Drive settings",
1078       "drive",
1079       settings_drive_widget_create, NULL },
1080     { "Printer settings",
1081       "printer",
1082       settings_printer_widget_create, NULL },
1083 #ifdef HAVE_RS232DEV
1084     { "RS232 settings",
1085       "rs232",
1086       settings_rs232_widget_create, NULL },
1087 #endif
1088 #ifdef HAVE_RAWNET
1089     { "Ethernet settings",
1090       "ethernet",
1091       settings_ethernet_widget_create, NULL },
1092 #endif
1093     UI_SETTINGS_TERMINATOR
1094 };
1095 /* }}} */
1096 
1097 
1098 /* {{{ main_nodes_c128 */
1099 /** \brief  Main tree nodes for x128
1100  */
1101 static ui_settings_tree_node_t main_nodes_c128[] = {
1102     { "Machine settings",
1103         "machine",
1104         NULL, machine_nodes_c128 },
1105     { "Display settings",
1106         "display",
1107         NULL, display_nodes_c128 },
1108     { "Audio settings",
1109         "audio",
1110         NULL, audio_nodes_c128 },
1111     { "Input devices",
1112         "input",
1113         NULL, input_nodes_c128 },
1114     { "Peripheral devices",
1115         "peripheral", /* I'll misspell this many times */
1116         NULL, peripheral_nodes_c128 },
1117    { "I/O extensions",
1118       "io-extensions",
1119       settings_io_widget_create, c128_io_extensions },
1120     { "Snaphot/event/media recording",
1121       "snapshot",
1122       settings_snapshot_widget_create, NULL },
1123     { "Miscellaneous",
1124       "misc",
1125       settings_misc_widget_create, NULL },
1126     UI_SETTINGS_TERMINATOR
1127 };
1128 /* }}} */
1129 
1130 
1131 /*****************************************************************************
1132  *                  SCPU64 tree nodes for the settings UI                    *
1133  ****************************************************************************/
1134 
1135 /* {{{ machine_nodes_scpu64 */
1136 static ui_settings_tree_node_t machine_nodes_scpu64[] = {
1137     { "Model settings",
1138       "model",
1139       settings_model_widget_create, NULL },
1140     { "SCPU64 settings",
1141       "scpu64",
1142       scpu64_settings_widget_create, NULL },
1143     { "Speed settings",
1144       "speed",
1145        settings_speed_widget_create, NULL },
1146     { "Autostart settings",
1147       "autostart",
1148       settings_autostart_widget_create, NULL },
1149     { "ROM settings",
1150       "rom-settings",
1151       settings_romset_widget_create, NULL },
1152     { "RAM reset pattern",
1153       "ram-reset",
1154       settings_ramreset_widget_create, NULL },
1155     { "Monitor settings",
1156       "monitor",
1157       settings_monitor_widget_create, NULL },
1158     UI_SETTINGS_TERMINATOR
1159 };
1160 /* }}} */
1161 
1162 /* {{{ display_nodes_scpu64 */
1163 static ui_settings_tree_node_t display_nodes_scpu64[] = {
1164     { "VIC-II settings",
1165       "vicii",
1166       settings_video_create, NULL },
1167     { "CRT settings",
1168       "CRT",
1169       settings_crt_widget_create, NULL },
1170     UI_SETTINGS_TERMINATOR
1171 };
1172 /* }}} */
1173 
1174 /* {{{ audio_nodes_scpu64 */
1175 static ui_settings_tree_node_t audio_nodes_scpu64[] = {
1176     { "Sound settings",
1177       "sound",
1178       settings_sound_create, NULL },
1179     { "SID settings",
1180       "sid",
1181       settings_soundchip_widget_create, NULL },
1182     { "Sampler settings",
1183       "sampler",
1184       settings_sampler_widget_create, NULL },
1185     UI_SETTINGS_TERMINATOR
1186 };
1187 /* }}} */
1188 
1189 /* {{{ input_nodes_scpu64 */
1190 static ui_settings_tree_node_t input_nodes_scpu64[] = {
1191     { "Keyboard settings",
1192       "keyboard",
1193       settings_keyboard_widget_create, NULL },
1194     { "Joystick settings",
1195       "joystick",
1196       settings_joystick_widget_create, NULL },
1197     { "Control port settings",
1198       "control-port",
1199       settings_controlport_widget_create, NULL },
1200     { "Mouse settings",
1201       "mouse",
1202       settings_mouse_widget_create, NULL },
1203     UI_SETTINGS_TERMINATOR
1204 };
1205 /* }}} */
1206 
1207 /* {{{ peripheral_nodes_scpu64 */
1208 static ui_settings_tree_node_t peripheral_nodes_scpu64[] = {
1209     { "Drive settings",
1210       "drive",
1211       settings_drive_widget_create, NULL },
1212     { "Printer settings",
1213       "printer",
1214       settings_printer_widget_create, NULL },
1215 #ifdef HAVE_RS232DEV
1216     { "RS232 settings",
1217       "rs232",
1218       settings_rs232_widget_create, NULL },
1219 #endif
1220 #ifdef HAVE_RAWNET
1221     { "Ethernet settings",
1222       "ethernet",
1223       settings_ethernet_widget_create, NULL },
1224 #endif
1225     UI_SETTINGS_TERMINATOR
1226 };
1227 /* }}} */
1228 
1229 
1230 /* {{{ main_nodes_scpu64 */
1231 /** \brief  Main tree nodes for xscpu64
1232  */
1233 static ui_settings_tree_node_t main_nodes_scpu64[] = {
1234     { "Machine",    "machine",  NULL,   machine_nodes_scpu64 },
1235     { "Display",    "display",  NULL,   display_nodes_scpu64 },
1236     { "Audio",      "audio",    NULL,   audio_nodes_scpu64 },
1237     { "Input",      "input",    NULL,   input_nodes_scpu64 },
1238     { "Peripherals",    "peripheral", NULL,    peripheral_nodes_scpu64 },
1239     { "I/O extensions",
1240       "io-extensions",
1241       settings_io_widget_create, scpu64_io_extensions },
1242     { "Snaphot/event/media recording",
1243       "snapshot",
1244       settings_snapshot_widget_create, NULL },
1245     { "Miscellaneous",
1246       "misc",
1247       settings_misc_widget_create, NULL },
1248 
1249     UI_SETTINGS_TERMINATOR
1250 };
1251 /* }}} */
1252 
1253 
1254 /*****************************************************************************
1255  *                  VIC-20 tree nodes for the settings UI                    *
1256  ****************************************************************************/
1257 
1258 /* {{{ machine_nodes_vic20 */
1259 static ui_settings_tree_node_t machine_nodes_vic20[] = {
1260     { "Model settings",
1261       "model",
1262       settings_model_widget_create, NULL },
1263     { "Speed settings",
1264       "speed",
1265        settings_speed_widget_create, NULL },
1266     { "Autostart settings",
1267       "autostart",
1268       settings_autostart_widget_create, NULL },
1269     { "ROM settings",
1270       "rom-settings",
1271       settings_romset_widget_create, NULL },
1272     { "RAM reset pattern",
1273       "ram-reset",
1274       settings_ramreset_widget_create, NULL },
1275     { "Monitor settings",
1276       "monitor",
1277       settings_monitor_widget_create, NULL },
1278     UI_SETTINGS_TERMINATOR
1279 };
1280 /* }}} */
1281 
1282 /* {{{ display_nodes_vic20 */
1283 static ui_settings_tree_node_t display_nodes_vic20[] = {
1284     { "VIC settings",
1285       "vic",
1286       settings_video_create, NULL },
1287     { "CRT settings",
1288       "CRT",
1289       settings_crt_widget_create, NULL },
1290     UI_SETTINGS_TERMINATOR
1291 };
1292 /* }}} */
1293 
1294 /* {{{ audio_nodes_vic20 */
1295 static ui_settings_tree_node_t audio_nodes_vic20[] = {
1296     { "Sound settings",
1297       "sound",
1298       settings_sound_create, NULL },
1299     { "SID settings",
1300       "sid",
1301       settings_soundchip_widget_create, NULL },
1302     { "Sampler settings",
1303       "sampler",
1304       settings_sampler_widget_create, NULL },
1305     UI_SETTINGS_TERMINATOR
1306 };
1307 /* }}} */
1308 
1309 /* {{{ input_nodes_vic20 */
1310 static ui_settings_tree_node_t input_nodes_vic20[] = {
1311     { "Keyboard settings",
1312       "keyboard",
1313       settings_keyboard_widget_create, NULL },
1314     { "Joystick settings",
1315       "joystick",
1316       settings_joystick_widget_create, NULL },
1317     { "Control port settings",
1318       "control-port",
1319       settings_controlport_widget_create, NULL },
1320     { "Mouse settings",
1321       "mouse",
1322       settings_mouse_widget_create, NULL },
1323     UI_SETTINGS_TERMINATOR
1324 };
1325 /* }}} */
1326 
1327 /* {{{ peripheral_nodes_vic20 */
1328 static ui_settings_tree_node_t peripheral_nodes_vic20[] = {
1329    { "Drive settings",
1330       "drive",
1331       settings_drive_widget_create, NULL },
1332     { "Printer settings",
1333       "printer",
1334       settings_printer_widget_create, NULL },
1335 #ifdef HAVE_RS232DEV
1336     { "RS232 settings",
1337       "rs232",
1338       settings_rs232_widget_create, NULL },
1339 #endif
1340 #ifdef HAVE_RAWNET
1341     { "Ethernet settings",
1342       "ethernet",
1343       settings_ethernet_widget_create, NULL },
1344 #endif
1345     UI_SETTINGS_TERMINATOR
1346 };
1347 /* }}} */
1348 
1349 
1350 /* {{{ main_nodes_vic20 */
1351 /** \brief  Main tree nodes for xvic
1352  */
1353 static ui_settings_tree_node_t main_nodes_vic20[] = {
1354 
1355     { "Machine", "machine", NULL, machine_nodes_vic20 },
1356     { "Display", "display", NULL, display_nodes_vic20 },
1357     { "Audio", "audio", NULL, audio_nodes_vic20 },
1358     { "Input", "input", NULL, input_nodes_vic20 },
1359     { "Peripherals", "peripheral", NULL, peripheral_nodes_vic20 },
1360     { "I/O extensions", "io-extensions",
1361       settings_io_widget_create, vic20_io_extensions },
1362     { "Snaphot/event/media recording",
1363       "snapshot",
1364       settings_snapshot_widget_create, NULL },
1365     { "Miscellaneous",
1366       "misc",
1367       settings_misc_widget_create, NULL },
1368     UI_SETTINGS_TERMINATOR
1369 };
1370 /* }}} */
1371 
1372 /*****************************************************************************
1373  *                  Plus4/C16 tree nodes for the settings UI                 *
1374  ****************************************************************************/
1375 
1376 /* {{{ machine_nodes_plus4 */
1377 static ui_settings_tree_node_t machine_nodes_plus4[] = {
1378     { "Model settings",
1379       "model",
1380        settings_model_widget_create, NULL },
1381     { "Speed settings",
1382       "speed",
1383        settings_speed_widget_create, NULL },
1384     { "Autostart settings",
1385       "autostart",
1386        settings_autostart_widget_create, NULL },
1387     { "ROM settings",
1388       "rom-settings",
1389        settings_romset_widget_create, NULL },
1390     { "RAM reset pattern",
1391       "ram-reset",
1392       settings_ramreset_widget_create, NULL },
1393     { "Monitor settings",
1394       "monitor",
1395        settings_monitor_widget_create, NULL },
1396     UI_SETTINGS_TERMINATOR
1397 };
1398 /* }}} */
1399 
1400 /* {{{ display_nodes_plus4 */
1401 static ui_settings_tree_node_t display_nodes_plus4[] = {
1402     { "TED settings",
1403       "ted",
1404       settings_video_create, NULL },
1405     { "CRT settings",
1406       "CRT",
1407       settings_crt_widget_create, NULL },
1408     UI_SETTINGS_TERMINATOR
1409 };
1410 /* }}} */
1411 
1412 /* {{{ audio_nodes_plus4 */
1413 static ui_settings_tree_node_t audio_nodes_plus4[] = {
1414     { "Sound settings",
1415       "sound",
1416       settings_sound_create, NULL },
1417     { "SID settings",
1418       "sid",
1419       settings_soundchip_widget_create, NULL },
1420     { "Sampler settings",
1421       "sampler",
1422       settings_sampler_widget_create, NULL },
1423     UI_SETTINGS_TERMINATOR
1424 };
1425 /* }}} */
1426 
1427 /* {{{ input_nodes_plus4 */
1428 static ui_settings_tree_node_t input_nodes_plus4[] = {
1429     { "Keyboard settings",
1430       "keyboard",
1431       settings_keyboard_widget_create, NULL },
1432     { "Joystick settings",
1433       "joystick",
1434       settings_joystick_widget_create, NULL },
1435     { "Control port settings",
1436       "control-port",
1437       settings_controlport_widget_create, NULL },
1438     { "Mouse settings",
1439       "mouse",
1440       settings_mouse_widget_create, NULL },
1441     UI_SETTINGS_TERMINATOR
1442 };
1443 /* }}} */
1444 
1445 /* {{{ peripheral_nodes_plus4 */
1446 static ui_settings_tree_node_t peripheral_nodes_plus4[] = {
1447     { "Drive settings",
1448       "drive",
1449       settings_drive_widget_create, NULL },
1450     { "Printer settings",
1451       "printer",
1452       settings_printer_widget_create, NULL },
1453 #ifdef HAVE_RS232DEV
1454     { "RS232 settings",
1455       "rs232",
1456       settings_rs232_widget_create, NULL },
1457 #endif
1458 #ifdef HAVE_RAWNET
1459     { "Ethernet settings",
1460       "ethernet",
1461       settings_ethernet_widget_create, NULL },
1462 #endif
1463     UI_SETTINGS_TERMINATOR
1464 };
1465 /* }}} */
1466 
1467 
1468 /* {{{ main_nodes_plus4 */
1469 /** \brief  Main tree nodes for xplus4
1470  */
1471 static ui_settings_tree_node_t main_nodes_plus4[] = {
1472     { "Machine", "machine", NULL, machine_nodes_plus4 },
1473     { "Display", "display", NULL, display_nodes_plus4 },
1474     { "Audio", "audio", NULL, audio_nodes_plus4 },
1475     { "Input", "input", NULL, input_nodes_plus4 },
1476     { "Peripherals", "peripheral", NULL, peripheral_nodes_plus4 },
1477 
1478     { "I/O extensions",
1479       "io-extensions",
1480       settings_io_widget_create, plus4_io_extensions },
1481     { "Snaphot/event/media recording",
1482       "snapshot",
1483       settings_snapshot_widget_create, NULL },
1484     { "Miscellaneous",
1485       "misc",
1486       settings_misc_widget_create, NULL },
1487     UI_SETTINGS_TERMINATOR
1488 };
1489 /* }}} */
1490 
1491 
1492 /*****************************************************************************
1493  *                      PET tree nodes for the settings UI                   *
1494  ****************************************************************************/
1495 
1496 /* {{{ machine_nodes_pet */
1497 static ui_settings_tree_node_t machine_nodes_pet[] = {
1498     { "Model settings",
1499       "model",
1500       settings_model_widget_create, NULL },
1501     { "Speed settings",
1502       "speed",
1503        settings_speed_widget_create, NULL },
1504     { "Autostart settings",
1505       "autostart",
1506       settings_autostart_widget_create, NULL },
1507     { "ROM settings",
1508       "rom-settings",
1509       settings_romset_widget_create, NULL },
1510     { "RAM reset pattern",
1511       "ram-reset",
1512       settings_ramreset_widget_create, NULL },
1513     { "Monitor settings",
1514       "monitor",
1515       settings_monitor_widget_create, NULL },
1516     UI_SETTINGS_TERMINATOR
1517 };
1518 /* }}} */
1519 
1520 /* {{{ display_nodes_pet */
1521 static ui_settings_tree_node_t display_nodes_pet[] = {
1522     { "CRTC settings",
1523       "crtc",
1524       settings_video_create, NULL },
1525     { "CRT settings",
1526       "CRT",
1527       settings_crt_widget_create, NULL },
1528     UI_SETTINGS_TERMINATOR
1529 };
1530 /* }}} */
1531 
1532 /* {{{ audio_nodes_pet */
1533 static ui_settings_tree_node_t audio_nodes_pet[] = {
1534     { "Sound settings",
1535       "sound",
1536       settings_sound_create, NULL },
1537     { "SID settings",
1538       "sid",
1539       settings_soundchip_widget_create, NULL },
1540     { "Sampler settings",
1541       "sampler",
1542       settings_sampler_widget_create, NULL },
1543     UI_SETTINGS_TERMINATOR
1544 };
1545 /* }}} */
1546 
1547 /* {{{ input_nodes_pet */
1548 static ui_settings_tree_node_t input_nodes_pet[] = {
1549     { "Keyboard settings",
1550       "keyboard",
1551       settings_keyboard_widget_create, NULL },
1552     { "Joystick settings",
1553       "joystick",
1554       settings_joystick_widget_create, NULL },
1555     { "Control port settings",
1556       "control-port",
1557       settings_controlport_widget_create, NULL },
1558     { "Mouse settings",
1559       "mouse",
1560       settings_mouse_widget_create, NULL },
1561     UI_SETTINGS_TERMINATOR
1562 };
1563 /* }}} */
1564 
1565 /* {{{ peripheral_nodes_pet */
1566 static ui_settings_tree_node_t peripheral_nodes_pet[] = {
1567     { "Drive settings",
1568       "drive",
1569       settings_drive_widget_create, NULL },
1570     { "Printer settings",
1571       "printer",
1572       settings_printer_widget_create, NULL },
1573 #ifdef HAVE_RS232DEV
1574     { "RS232 settings",
1575       "rs232",
1576       settings_rs232_widget_create, NULL },
1577 #endif
1578 #ifdef HAVE_RAWNET
1579     { "Ethernet settings",
1580       "ethernet",
1581       settings_ethernet_widget_create, NULL },
1582 #endif
1583     UI_SETTINGS_TERMINATOR
1584 };
1585 /* }}} */
1586 
1587 
1588 /* {{{ main_nodes_pet */
1589 /** \brief  Main tree nodes for xpet
1590  */
1591 static ui_settings_tree_node_t main_nodes_pet[] = {
1592     { "Machine", "machine", NULL, machine_nodes_pet },
1593     { "Display", "display", NULL, display_nodes_pet },
1594     { "Audio", "audio", NULL, audio_nodes_pet },
1595     { "Input", "input", NULL, input_nodes_pet },
1596     { "Peripheral", "peripheral", NULL, peripheral_nodes_pet },
1597     { "I/O extensions", "io-extensions",
1598       settings_io_widget_create, pet_io_extensions },
1599     { "Snaphot/event/media recording",
1600       "snapshot",
1601       settings_snapshot_widget_create, NULL },
1602     { "Miscellaneous",
1603       "misc",
1604         settings_misc_widget_create, NULL },
1605     UI_SETTINGS_TERMINATOR
1606 };
1607 /* }}} */
1608 
1609 
1610 /*****************************************************************************
1611  *                  CBM5x0 tree nodes for the settings UI                    *
1612  ****************************************************************************/
1613 
1614 #define ARNIE UI_SETTINGS_TERMINATOR
1615 
1616 /* {{{ machine_nodes_cbm5x0 */
1617 static ui_settings_tree_node_t machine_nodes_cbm5x0[] = {
1618     { "Model settings",
1619       "model",
1620       settings_model_widget_create, NULL },
1621     { "Speed settings",
1622       "speed",
1623        settings_speed_widget_create, NULL },
1624     { "Autostart settings",
1625       "autostart",
1626       settings_autostart_widget_create, NULL },
1627     { "ROM settings",
1628       "rom-settings",
1629       settings_romset_widget_create, NULL },
1630     { "RAM reset pattern",
1631       "ram-reset",
1632       settings_ramreset_widget_create, NULL },
1633     { "Monitor settings",
1634       "monitor",
1635       settings_monitor_widget_create, NULL },
1636     ARNIE
1637 };
1638 /* }}} */
1639 
1640 /* {{{ display_nodes_cbm5x0 */
1641 static ui_settings_tree_node_t display_nodes_cbm5x0[] = {
1642     { "VIC-II settings",
1643       "vicii",
1644       settings_video_create, NULL },
1645     { "CRT settings",
1646       "CRT",
1647       settings_crt_widget_create, NULL },
1648     ARNIE
1649 };
1650 /* }}} */
1651 
1652 /* {{{ audio_nodes_cbm5x0 */
1653 static ui_settings_tree_node_t audio_nodes_cbm5x0[] = {
1654     { "Sound settings",
1655       "sound",
1656       settings_sound_create, NULL },
1657     { "SID settings",
1658       "sid",
1659       settings_soundchip_widget_create, NULL },
1660     { "Sampler settings",
1661       "sampler",
1662       settings_sampler_widget_create, NULL },
1663     ARNIE
1664 };
1665 /* }}} */
1666 
1667 /* {{{ input_nodes_cbm5x0 */
1668 static ui_settings_tree_node_t input_nodes_cbm5x0[] = {
1669      { "Keyboard settings",
1670       "keyboard",
1671       settings_keyboard_widget_create, NULL },
1672     { "Joystick settings",
1673       "joystick",
1674       settings_joystick_widget_create, NULL },
1675     { "Control port settings",
1676       "control-port",
1677       settings_controlport_widget_create, NULL },
1678     { "Mouse settings",
1679       "mouse",
1680       settings_mouse_widget_create, NULL },
1681     ARNIE
1682 };
1683 /* }}} */
1684 
1685 
1686 /* {{{ peripheral_nodes_cbm5x0 */
1687 static ui_settings_tree_node_t peripheral_nodes_cbm5x0[] = {
1688    { "Drive settings",
1689       "drive",
1690       settings_drive_widget_create, NULL },
1691     { "Printer settings",
1692       "printer",
1693       settings_printer_widget_create, NULL },
1694 #ifdef HAVE_RS232DEV
1695     { "RS232 settings",
1696       "rs232",
1697       settings_rs232_widget_create, NULL },
1698 #endif
1699 
1700     ARNIE
1701 };
1702 /* }}} */
1703 
1704 
1705 /* {{{ main_nodes_cbm5x0 */
1706 /** \brief  Main tree nodes for xcbm5x0
1707  */
1708 static ui_settings_tree_node_t main_nodes_cbm5x0[] = {
1709     { "Machine", "machine", NULL, machine_nodes_cbm5x0 },
1710     { "Display", "display", NULL, display_nodes_cbm5x0 },
1711     { "Audio", "audio", NULL, audio_nodes_cbm5x0 },
1712     { "Input", "input", NULL, input_nodes_cbm5x0 },
1713     { "Peripherals", "peripheral", NULL, peripheral_nodes_cbm5x0 },
1714     { "I/O extensions", "io-extensions",
1715       settings_io_widget_create, cbm5x0_io_extensions },
1716     { "Snaphot/event/media recording",
1717       "snapshot",
1718       settings_snapshot_widget_create, NULL },
1719     { "Miscellaneous",
1720       "misc",
1721       settings_misc_widget_create, NULL },
1722 
1723 
1724     UI_SETTINGS_TERMINATOR
1725 };
1726 /* }}} */
1727 
1728 
1729 /* {{{ machine_nodes_cbm6x0 */
1730 static ui_settings_tree_node_t machine_nodes_cbm6x0[] = {
1731     { "Model settings",
1732       "model",
1733       settings_model_widget_create, NULL },
1734     { "Speed settings",
1735       "speed",
1736        settings_speed_widget_create, NULL },
1737     { "Autostart settings",
1738       "autostart",
1739       settings_autostart_widget_create, NULL },
1740     { "ROM settings",
1741       "rom-settings",
1742       settings_romset_widget_create, NULL },
1743     { "RAM reset pattern",
1744       "ram-reset",
1745       settings_ramreset_widget_create, NULL },
1746     { "Monitor settings",
1747       "monitor",
1748       settings_monitor_widget_create, NULL },
1749     ARNIE
1750 };
1751 /* }}} */
1752 
1753 /* {{{ display_nodes_cbm6x0 (*/
1754 static ui_settings_tree_node_t display_nodes_cbm6x0[]= {
1755     { "CRTC settings",
1756       "crtc",
1757       settings_video_create, NULL },
1758     { "CRT settings",
1759       "CRT",
1760       settings_crt_widget_create, NULL },
1761     ARNIE
1762 };
1763 /* }}} */
1764 
1765 /* {{{ audio_nodes_cbm6x0 */
1766 static ui_settings_tree_node_t audio_nodes_cbm6x0[] = {
1767     { "Sound settings",
1768       "sound",
1769       settings_sound_create, NULL },
1770     { "SID settings",
1771        "sid",
1772       settings_soundchip_widget_create, NULL },
1773     { "Sampler settings",
1774       "sampler",
1775       settings_sampler_widget_create, NULL },
1776     ARNIE
1777 };
1778 /* }}} */
1779 
1780 /* {{{ input_nodes_cbm6x0 */
1781 static ui_settings_tree_node_t input_nodes_cbm6x0[] = {
1782     { "Keyboard settings",
1783       "keyboard",
1784       settings_keyboard_widget_create, NULL },
1785     { "Joystick settings",
1786       "joystick",
1787       settings_joystick_widget_create, NULL },
1788     { "Control port settings",
1789       "control-port",
1790       settings_controlport_widget_create, NULL },
1791     { "Mouse settings",
1792       "mouse",
1793       settings_mouse_widget_create, NULL },
1794 
1795     ARNIE
1796 };
1797 /* }}} */
1798 
1799 /* {{{ peripheral nodes_cbm6x0 */
1800 static ui_settings_tree_node_t peripheral_nodes_cbm6x0[] = {
1801     { "Drive settings",
1802       "drive",
1803       settings_drive_widget_create, NULL },
1804     { "Printer settings",
1805       "printer",
1806       settings_printer_widget_create, NULL },
1807 #ifdef HAVE_RS232DEV
1808     { "RS232 settings",
1809       "rs232",
1810       settings_rs232_widget_create, NULL },
1811 #endif
1812 
1813     ARNIE
1814 };
1815 /* }}} */
1816 
1817 
1818 /* {{{ main_nodes_cbm6x0 */
1819 /** \brief  Main tree nodes for xcbm6x0
1820  */
1821 static ui_settings_tree_node_t main_nodes_cbm6x0[] = {
1822     { "Machine", "machine", NULL, machine_nodes_cbm6x0 },
1823     { "Display", "display", NULL, display_nodes_cbm6x0 },
1824     { "Audio", "audio", NULL, audio_nodes_cbm6x0 },
1825     { "Input", "input", NULL, input_nodes_cbm6x0 },
1826     { "Peripherals", "peripheral", NULL, peripheral_nodes_cbm6x0 },
1827     { "I/O extensions",
1828       "io-extensions",
1829       settings_io_widget_create, cbm6x0_io_extensions },
1830     { "Snaphot/event/media recording",
1831       "snapshot",
1832       settings_snapshot_widget_create, NULL },
1833     { "Miscellaneous",
1834       "misc",
1835       settings_misc_widget_create, NULL },
1836     UI_SETTINGS_TERMINATOR
1837 };
1838 /* }}} */
1839 
1840 
1841 /** \brief  Reference to the current 'central' widget in the settings dialog
1842  */
1843 static void ui_settings_set_central_widget(GtkWidget *widget);
1844 
1845 
1846 /** \brief  Reference to the settings dialog
1847  */
1848 static GtkWidget *settings_window = NULL;
1849 
1850 
1851 /** \brief  Reference to the 'content area' widget of the settings dialog
1852  */
1853 static GtkWidget *settings_grid = NULL;
1854 
1855 
1856 /** \brief  Reference to the tree model for the settings tree
1857  */
1858 static GtkTreeStore *settings_model = NULL;
1859 
1860 
1861 /** \brief  Reference to the tree view for the settings tree
1862  */
1863 static GtkWidget *settings_tree = NULL;
1864 
1865 
1866 /** \brief  Path to the last used settings page
1867  */
1868 static GtkTreePath *last_node_path = NULL;
1869 
1870 #if 0
1871 /** \brief  Reference to the resource widget manager of the current page
1872  */
1873 static resource_widget_manager_t *resource_manager = NULL;
1874 #endif
1875 
1876 /** \brief  Set reference to the resource widget manager of the current page
1877  *
1878  * \param[in]   manager resource widget manager reference
1879  */
ui_settings_set_resource_widget_manager(resource_widget_manager_t * manager)1880 void ui_settings_set_resource_widget_manager(resource_widget_manager_t *manager)
1881 {
1882     debug_gtk3("Setting resource-manager-widget reference temporarily"
1883             " disabled.");
1884 #if 0
1885     resource_manager = manager;
1886 #endif
1887 }
1888 
1889 
on_settings_dialog_destroy(GtkWidget * widget,gpointer data)1890 static void on_settings_dialog_destroy(GtkWidget *widget, gpointer data)
1891 {
1892     settings_window = NULL;
1893 }
1894 
1895 
1896 /** \brief  Handler for the double click event of a tree node
1897  *
1898  * Expands or collapses the node and its children (if any)
1899  *
1900  * \param[in,out]   tree_view   tree view instance
1901  * \param[in]       path        tree view path
1902  * \param[in]       column      tree view column (unused)
1903  * \param[in]       user_data   extra event data (unused)
1904  */
on_row_activated(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * column,gpointer user_data)1905 static void on_row_activated(GtkTreeView *tree_view,
1906                             GtkTreePath *path,
1907                             GtkTreeViewColumn *column,
1908                             gpointer user_data)
1909 {
1910     if (gtk_tree_view_row_expanded(tree_view, path)) {
1911         gtk_tree_view_collapse_row(tree_view, path);
1912     } else {
1913         /*
1914          * Only expand the immediate children. A no-op at the moment since
1915          * we only have two levels of nodes in the tree, but perhaps useful
1916          * for later.
1917          */
1918         gtk_tree_view_expand_row(tree_view, path, FALSE);
1919     }
1920 }
1921 
1922 
1923 #if 0
1924 /** \brief  Reset widgets in the central widget to their initial state
1925  *
1926  * Restores all widgets in the central widget to the state they were in when\
1927  * the central widget was instanciated. This requires a call from the central
1928  * widget registering its "resource manager widget".
1929  *
1930  * \param[in]   widget  settings dialog
1931  * \param[in]   data    extra event data (unused at the moment)
1932  */
1933 static void ui_settings_central_widget_reset(GtkWidget *widget, gpointer data)
1934 {
1935     debug_gtk3("Resetting current page's widgets to their initial state");
1936     if (resource_manager != NULL) {
1937         vice_resource_widget_manager_reset(resource_manager);
1938     } else {
1939         debug_gtk3("No resource widget manager registered, skipping");
1940     }
1941 }
1942 #endif
1943 
1944 
1945 #if 0
1946 /** \brief  Reset widgets in the central widget to their factory state
1947  *
1948  * Restores all widgets in the central widget to the factory state of the
1949  * resources they are bound to.
1950  * This requires a call from the central widget registering its
1951  * "resource manager widget".
1952  *
1953  * \param[in]   widget  settings dialog
1954  * \param[in]   data    extra event data (unused at the moment)
1955  */
1956 static void ui_settings_central_widget_factory(GtkWidget *widget, gpointer data)
1957 {
1958     debug_gtk3("Resetting current page's widgets to their factory value");
1959     if (resource_manager != NULL) {
1960         vice_resource_widget_manager_factory(resource_manager);
1961     } else {
1962         debug_gtk3("No resource widget manager registered, skipping");
1963     }
1964 
1965 }
1966 #endif
1967 
1968 /** \brief  Create the widget that is initially shown in the settings UI
1969  *
1970  * \param[in]   parent  parent widget (unused)
1971  *
1972  * \return  GtkGrid
1973  */
ui_settings_inital_widget(GtkWidget * parent)1974 static GtkWidget *ui_settings_inital_widget(GtkWidget *parent)
1975 {
1976     GtkWidget *grid;
1977     GtkWidget *label;
1978 
1979     grid = vice_gtk3_grid_new_spaced(64, 64);
1980     label = gtk_label_new(NULL);
1981     gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1982     gtk_label_set_markup(GTK_LABEL(label),
1983             "This is the first widget/dialog shown when people click on the"
1984             " settings UI.\n"
1985             "So perhaps we could show some instructions or something here.");
1986     gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1);
1987 
1988     gtk_widget_show_all(grid);
1989     return grid;
1990 }
1991 
1992 
1993 #if 0
1994 /** \brief  Paused state when popping up the UI
1995  */
1996 static int old_pause_state;
1997 #endif
1998 
1999 /** \brief  Handler for the "changed" event of the tree view
2000  *
2001  * \param[in]   selection   GtkTreeSelection associated with the tree model
2002  * \param[in]   user_data   data for the event (unused for now)
2003  *
2004  */
on_tree_selection_changed(GtkTreeSelection * selection,gpointer user_data)2005 static void on_tree_selection_changed(
2006         GtkTreeSelection *selection,
2007         gpointer user_data)
2008 {
2009     GtkTreeIter iter;
2010     GtkTreeModel *model;
2011 
2012     if (gtk_tree_selection_get_selected(selection, &model, &iter))
2013     {
2014         gchar *name;
2015         GtkWidget *(*callback)(void *) = NULL;
2016         const char *id;
2017 
2018         gtk_tree_model_get(model, &iter, COLUMN_NAME, &name, -1);
2019         gtk_tree_model_get(model, &iter, COLUMN_CALLBACK, &callback, -1);
2020         gtk_tree_model_get(model, &iter, COLUMN_ID, &id, -1);
2021         debug_gtk3("node name: %s", name);
2022         debug_gtk3("node ID: %s", id);
2023         if (callback != NULL) {
2024             char *title = lib_msprintf("%s settings :: %s", machine_name, name);
2025             gtk_window_set_title(GTK_WINDOW(settings_window), title);
2026             lib_free(title);
2027             /* create new central widget, using settings_window (this dialog)
2028              * as its parent, this will allow for proper blocking in modal
2029              * dialogs, while ui_get_active_window() breaks that. */
2030             if (last_node_path != NULL) {
2031                 gtk_tree_path_free(last_node_path);
2032             }
2033             last_node_path = gtk_tree_model_get_path(
2034                     GTK_TREE_MODEL(settings_model), &iter);
2035             ui_settings_set_central_widget(callback(settings_window));
2036         }
2037         g_free(name);
2038     }
2039 }
2040 
2041 
2042 /** \brief  Create the 'Save on exit' checkbox
2043  *
2044  * The current position/display of the checkbox is a little lame at the moment
2045  *
2046  * \return  GtkCheckButton
2047  */
create_save_on_exit_checkbox(void)2048 static GtkWidget *create_save_on_exit_checkbox(void)
2049 {
2050     return vice_gtk3_resource_check_button_new("SaveResourcesOnExit",
2051             "Save settings on exit");
2052 }
2053 
2054 
2055 /** \brief  Create the 'Confirm on exit' checkbox
2056  *
2057  * The current position/display of the checkbox is a little lame at the moment
2058  *
2059  * \return  GtkCheckButton
2060  */
create_confirm_on_exit_checkbox(void)2061 static GtkWidget *create_confirm_on_exit_checkbox(void)
2062 {
2063     return vice_gtk3_resource_check_button_new("ConfirmOnExit",
2064             "Confirm on exit");
2065 }
2066 
2067 
2068 /** \brief  Create empty tree model for the settings tree
2069  */
create_tree_model(void)2070 static void create_tree_model(void)
2071 {
2072     settings_model = gtk_tree_store_new(NUM_COLUMNS,
2073             G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
2074 }
2075 
2076 
2077 /** \brief  Create tree store containing settings items and children
2078  *
2079  * \return  GtkTreeStore
2080  */
populate_tree_model(void)2081 static GtkTreeStore *populate_tree_model(void)
2082 {
2083     GtkTreeStore *model;
2084     GtkTreeIter iter;
2085     GtkTreeIter child;
2086     ui_settings_tree_node_t *nodes = NULL;
2087     int i;
2088 
2089     model = settings_model;
2090 
2091     switch (machine_class) {
2092         case VICE_MACHINE_C64:  /* fall through */
2093         case VICE_MACHINE_C64SC:
2094             nodes = main_nodes_c64;
2095             break;
2096         case VICE_MACHINE_C64DTV:
2097             nodes = main_nodes_c64dtv;
2098             break;
2099         case VICE_MACHINE_C128:
2100             nodes = main_nodes_c128;
2101             break;
2102         case VICE_MACHINE_SCPU64:
2103             nodes = main_nodes_scpu64;
2104             break;
2105         case VICE_MACHINE_VIC20:
2106             nodes = main_nodes_vic20;
2107             break;
2108         case VICE_MACHINE_PLUS4:
2109             nodes = main_nodes_plus4;
2110             break;
2111         case VICE_MACHINE_PET:
2112             nodes = main_nodes_pet;
2113             break;
2114         case VICE_MACHINE_CBM5x0:
2115             nodes = main_nodes_cbm5x0;
2116             break;
2117         case VICE_MACHINE_CBM6x0:
2118             nodes = main_nodes_cbm6x0;
2119             break;
2120         case VICE_MACHINE_VSID:
2121             nodes = main_nodes_vsid;
2122             break;
2123         default:
2124             fprintf(stderr,
2125                     "Error: %s:%d:%s(): unsupported machine_class %d\n",
2126                     __FILE__, __LINE__, __func__, machine_class);
2127             archdep_vice_exit(1);
2128             break;
2129     }
2130 
2131     for (i = 0; nodes[i].name != NULL; i++) {
2132         gtk_tree_store_append(model, &iter, NULL);
2133         gtk_tree_store_set(model, &iter,
2134                 COLUMN_NAME, nodes[i].name,
2135                 COLUMN_ID, nodes[i].id,
2136                 COLUMN_CALLBACK, nodes[i].callback,
2137                 -1);
2138 
2139         /* this bit will need proper recursion if we need more than two
2140          * levels of subitems */
2141         if (nodes[i].children != NULL) {
2142             int c;
2143             ui_settings_tree_node_t *list = nodes[i].children;
2144 
2145             for (c = 0; list[c].name != NULL; c++) {
2146                 char buffer[256];
2147 
2148                 /* mark items without callback with 'TODO' */
2149                 if (list[c].callback != NULL) {
2150                     g_snprintf(buffer, 256, "%s", list[c].name);
2151                 } else {
2152                     g_snprintf(buffer, 256, "TODO: %s", list[c].name);
2153                 }
2154 
2155                 gtk_tree_store_append(model, &child, &iter);
2156                 gtk_tree_store_set(model, &child,
2157                         COLUMN_NAME, buffer,
2158                         COLUMN_ID, list[c].id,
2159                         COLUMN_CALLBACK, list[c].callback,
2160                         -1);
2161             }
2162         }
2163     }
2164     return model;
2165 }
2166 
2167 
2168 /** \brief  Create treeview for settings side-menu
2169  *
2170  * Reads items from `main_nodes` and adds them to the tree view.
2171  *
2172  * \return  GtkTreeView
2173  *
2174  * TODO:    Handle nested items, and write up somewhere how the hell I finally
2175  *          got the callbacks working.
2176  *          Split into a function creating the tree view and functions adding,
2177  *          altering or removing nodes.
2178  */
create_treeview(void)2179 static GtkWidget *create_treeview(void)
2180 {
2181     GtkWidget *tree;
2182     GtkCellRenderer *text_renderer;
2183     GtkTreeViewColumn *text_column;
2184     GtkCssProvider *css_provider;
2185     GtkStyleContext *style_context;
2186     GError *err = NULL;
2187 
2188     create_tree_model();
2189     tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(populate_tree_model()));
2190     gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree), FALSE);
2191 
2192     text_renderer = gtk_cell_renderer_text_new();
2193     text_column = gtk_tree_view_column_new_with_attributes(
2194             "item-name",
2195             text_renderer,
2196             "text", 0,
2197             NULL);
2198     /*    gtk_tree_view_append_column(GTK_TREE_VIEW(tree), obj_column); */
2199     gtk_tree_view_append_column(GTK_TREE_VIEW(tree), text_column);
2200 
2201     css_provider = gtk_css_provider_new();
2202     if (!gtk_css_provider_load_from_data(css_provider, treeview_css, -1, &err)) {
2203         debug_gtk3("failed to initialize CSS provider");
2204     } else {
2205         style_context = gtk_widget_get_style_context(tree);
2206         gtk_style_context_add_provider(style_context,
2207                                        GTK_STYLE_PROVIDER(css_provider),
2208                                        GTK_STYLE_PROVIDER_PRIORITY_USER);
2209     }
2210 
2211     return tree;
2212 }
2213 
2214 
2215 /** \brief  Set the 'central'/action widget for the settings dialog
2216  *
2217  * Destroys the old 'central' widget and sets the new one.
2218  *
2219  *  \param[in,out]  widget  widget to use as the new 'central' widget
2220  */
ui_settings_set_central_widget(GtkWidget * widget)2221 static void ui_settings_set_central_widget(GtkWidget *widget)
2222 {
2223     GtkWidget *child;
2224 
2225     debug_gtk3("checking for child");
2226     child = gtk_grid_get_child_at(GTK_GRID(settings_grid), 1, 0);
2227     if (child != NULL) {
2228         debug_gtk3("got child widget, calling destroy on child (and setting"
2229                 " the resource_manager reference to NULL)");
2230         gtk_widget_destroy(child);
2231 #if 0
2232         resource_manager = NULL;
2233 #endif
2234     }
2235     gtk_grid_attach(GTK_GRID(settings_grid), widget, 1, 0, 1, 1);
2236     /* add a little space around the widget */
2237     g_object_set(widget, "margin", 16, NULL);
2238 }
2239 
2240 
2241 /** \brief  Create the 'content widget' of the settings dialog
2242  *
2243  * This creates the widget in the dialog used to display the treeview and room
2244  * for the widget connected to that tree's currently selected item.
2245  *
2246  * \param[in]   widget  parent widget
2247  *
2248  * \return  GtkGrid (as a GtkWidget)
2249  */
create_content_widget(GtkWidget * widget)2250 static GtkWidget *create_content_widget(GtkWidget *widget)
2251 {
2252     GtkTreeSelection *selection;
2253     GtkWidget *scroll;
2254     GtkWidget *extra;
2255 
2256     settings_grid = gtk_grid_new();
2257     settings_tree = create_treeview();
2258 
2259     /* pack the tree in a scrolled window to allow scrolling of the tree when
2260      * it gets too large for the dialog
2261      */
2262     scroll = gtk_scrolled_window_new(NULL, NULL);
2263     gtk_container_add(GTK_CONTAINER(scroll), settings_tree);
2264 
2265     gtk_grid_attach(GTK_GRID(settings_grid), scroll, 0, 0, 1, 1);
2266 
2267     /* Remember the previously selected setting/widget and set it here */
2268 
2269     /* do we have a previous settings "page"? */
2270     if (last_node_path == NULL) {
2271         /* nope, display the default one */
2272         ui_settings_set_central_widget(ui_settings_inital_widget(widget));
2273     } else {
2274         /* try to restore the page last shown */
2275         GtkTreeIter iter;
2276 
2277         debug_gtk3("Attempting to get previous settings page");
2278         if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(settings_model), &iter,
2279                     last_node_path)) {
2280             debug_gtk3("Oops");
2281         } else {
2282             GtkWidget *(*callback)(GtkWidget *) = NULL;
2283             gtk_tree_model_get(
2284                     GTK_TREE_MODEL(settings_model), &iter,
2285                     COLUMN_CALLBACK, &callback, -1);
2286             if (callback != NULL) {
2287 
2288                 selection = gtk_tree_view_get_selection(
2289                         GTK_TREE_VIEW(settings_tree));
2290 
2291                 ui_settings_set_central_widget(callback(widget));
2292                 gtk_tree_view_expand_to_path(
2293                         GTK_TREE_VIEW(settings_tree),
2294                         last_node_path);
2295                 gtk_tree_selection_select_path(selection, last_node_path);
2296 
2297             }
2298         }
2299     }
2300 
2301     /* create container for generic settings */
2302     extra = gtk_grid_new();
2303     gtk_grid_set_column_spacing(GTK_GRID(extra), 8);
2304     gtk_grid_set_row_spacing(GTK_GRID(extra), 8);
2305     g_object_set(extra, "margin", 16, NULL);
2306 
2307     gtk_grid_attach(GTK_GRID(extra), create_save_on_exit_checkbox(),
2308             0, 0, 1, 1);
2309     gtk_grid_attach(GTK_GRID(extra), create_confirm_on_exit_checkbox(),
2310             0, 1, 1, 1);
2311 
2312     /* add to main layout */
2313     gtk_grid_attach(GTK_GRID(settings_grid), extra, 0, 2, 2, 1);
2314 
2315     gtk_widget_show(settings_grid);
2316     gtk_widget_show(settings_tree);
2317 
2318     gtk_widget_set_size_request(scroll, 250, 500);
2319     gtk_widget_set_size_request(settings_grid, DIALOG_WIDTH, DIALOG_HEIGHT);
2320 
2321     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(settings_tree));
2322     gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
2323     g_signal_connect(G_OBJECT(selection), "changed",
2324             G_CALLBACK(on_tree_selection_changed), NULL);
2325 
2326     /* handler for the double click event on a node */
2327     g_signal_connect(settings_tree, "row-activated",
2328             G_CALLBACK(on_row_activated), NULL);
2329 
2330     return settings_grid;
2331 }
2332 
2333 
2334 /** \brief  Handler for the "response" event of the settings dialog
2335  *
2336  * This determines what to do based on the 'reponse ID' emitted by the dialog.
2337  *
2338  * \param[in]   widget      widget triggering the event (the dialog)
2339  * \param[in]   response_id response ID
2340  * \param[in]   user_data   extra data (unused)
2341  */
response_callback(GtkWidget * widget,gint response_id,gpointer user_data)2342 static void response_callback(GtkWidget *widget, gint response_id,
2343                               gpointer user_data)
2344 {
2345     switch (response_id) {
2346 
2347         /* close dialog */
2348         case GTK_RESPONSE_DELETE_EVENT:
2349             gtk_widget_destroy(widget);
2350             settings_window = NULL;
2351             break;
2352 
2353         /* reset resources in current central widget to the state they were
2354          * in before entering the (sub)dialog */
2355         case RESPONSE_RESET:
2356             debug_gtk3("Resetting widgets to their dialog-entry state"
2357                     " temporarily disabled.");
2358 #if 0
2359             ui_settings_central_widget_reset(widget, user_data);
2360 #endif
2361             break;
2362 
2363         /* restore resources in (sub)dialog to factory settings */
2364         case RESPONSE_FACTORY:
2365             debug_gtk3("Resetting widgets to their factory value temporarily"
2366                     " disabled.");
2367 #if 0
2368             ui_settings_central_widget_factory(widget, user_data);
2369 #endif
2370             break;
2371 
2372         case RESPONSE_DEFAULT:
2373             if (vice_gtk3_message_confirm("Reset to default setting",
2374                         "Do you wish to reset to default settings?")) {
2375                 resources_set_defaults();
2376                 gtk_widget_destroy(widget);
2377                 /* this one really behaves a little odd: */
2378 #if 0
2379                 machine_reset();
2380 #endif
2381             }
2382             break;
2383 
2384 
2385         default:
2386             break;
2387     }
2388 
2389     ui_set_ignore_mouse_hide(FALSE);
2390 }
2391 
2392 
2393 /** \brief  Respond to window size changes
2394  *
2395  * This allows for quickly seeing if specific dialog is getting too large. The
2396  * DIALOG_WIDTH_MAX and DIALOG_HEIGHT_MAX I sucked out of my thumb, since due
2397  * to window managers using different themes, we can't use 'proper' values, so
2398  * I had to use approximate values.
2399  *
2400  * \param[in]   widget  a GtkWindow
2401  * \param[in]   event   the GDK event
2402  * \param[in]   data    extra event data (unused)
2403  *
2404  * \return  boolean
2405  */
on_dialog_configure_event(GtkWidget * widget,GdkEvent * event,gpointer data)2406 static gboolean on_dialog_configure_event(
2407         GtkWidget *widget,
2408         GdkEvent *event,
2409         gpointer data)
2410 {
2411     if (event->type == GDK_CONFIGURE) {
2412         GdkEventConfigure *cfg = (GdkEventConfigure *)event;
2413         int width = cfg->width;
2414         int height = cfg->height;
2415 
2416         /* debug_gtk3("width %d, height %d.", width, height); */
2417         if (width > DIALOG_WIDTH_MAX || height > DIALOG_HEIGHT_MAX) {
2418             /* uncomment the following to get some 'help' while building
2419              * new dialogs: */
2420 #if 0
2421             gtk_window_set_title(GTK_WINDOW(widget),
2422                     "HELP! --- DIALOG IS TOO BLOODY LARGE -- ERROR!");
2423 #endif
2424             debug_gtk3("Dialog is too large: %dx%d (max: %dx%d).",
2425                     width, height, DIALOG_WIDTH_MAX, DIALOG_HEIGHT_MAX);
2426         }
2427 #if 0
2428         debug_gtk3("XPOS: %d - YPOS: %d", cfg->x, cfg->y);
2429 #endif
2430     }
2431     return FALSE;
2432 }
2433 
2434 
2435 
2436 /** \brief  Dialog create helper
2437  *
2438  * \return  Settings dialog
2439  */
dialog_create_helper(void)2440 static GtkWidget *dialog_create_helper(void)
2441 {
2442     GtkWidget *dialog;
2443     GtkWidget *content;
2444     char title[256];
2445 
2446     vsync_suspend_speed_eval();
2447     ui_set_ignore_mouse_hide(TRUE);
2448 
2449     g_snprintf(title, 256, "%s Settings", machine_name);
2450 
2451     dialog = gtk_dialog_new_with_buttons(
2452             title,
2453             ui_get_active_window(),
2454             GTK_DIALOG_MODAL,
2455             /*
2456              * Temp. disabled due to code freeze, will work on this again
2457              * after the code freeze -- compyx
2458              */
2459 #if 0
2460             "Revert changes", RESPONSE_RESET,
2461             "Factory reset", RESPONSE_FACTORY,
2462 #endif
2463             "Close", GTK_RESPONSE_DELETE_EVENT,
2464             NULL);
2465 
2466     content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
2467     gtk_container_add(GTK_CONTAINER(content), create_content_widget(dialog));
2468 
2469     /* set default response to Close */
2470     gtk_dialog_set_default_response(
2471             GTK_DIALOG(dialog),
2472             GTK_RESPONSE_DELETE_EVENT);
2473 
2474     gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
2475     g_signal_connect(dialog, "response", G_CALLBACK(response_callback), NULL);
2476     g_signal_connect(dialog, "configure-event",
2477             G_CALLBACK(on_dialog_configure_event), NULL);
2478     g_signal_connect(dialog, "destroy", G_CALLBACK(on_settings_dialog_destroy),
2479             NULL);
2480 
2481     return dialog;
2482 }
2483 
2484 
2485 /** \brief  Callback to create the main settings dialog from the menu
2486  *
2487  * \param[in]   widget      (direct) parent widget, the menu item
2488  * \param[in]   user_data   data for the event (unused)
2489  *
2490  * \note    The appearance of minimize/maximize buttons seems to depend on
2491  *          which Window Manager is active:
2492  *
2493  *          On MATE (marco, a Metacity fork) both buttons are hidden.
2494  *          On KDE (KWin) the maximize button is still visible but inactive
2495  *          On OpenBox both min/max are visible with only minimize working
2496  *
2497  * \return  TRUE (avoids the key press getting passed to the emulated machine)
2498  */
ui_settings_dialog_create(GtkWidget * widget,gpointer user_data)2499 gboolean ui_settings_dialog_create(GtkWidget *widget, gpointer user_data)
2500 {
2501     GtkWidget *dialog;
2502 
2503     dialog = dialog_create_helper();
2504     settings_window = dialog;
2505     gtk_widget_show_all(dialog);
2506     return TRUE;
2507 }
2508 
2509 
2510 /** \brief  Clean up resources used on emu exit
2511  *
2512  * Do NOT call this when exiting the settings UI, the event handlers will take
2513  * care of cleaning up resources used by the UI. This function cleans up the
2514  * data used to present the user with the last used settings page.
2515  */
ui_settings_shutdown(void)2516 void ui_settings_shutdown(void)
2517 {
2518     if (last_node_path != NULL) {
2519         gtk_tree_path_free(last_node_path);
2520         last_node_path = NULL;
2521     }
2522 }
2523 
2524 
2525 /** \brief  Find and activate node in the tree view via \a path
2526  *
2527  * The \a path argument is expected to be in the form 'foo/bar/bah', each
2528  * path item indicates a node in the tree view/model. For example:
2529  * "display/vdc" would select the VDC settings dialog on x128, but would fail
2530  * on any other machine.
2531  *
2532  * \param[in]   path    path to the node
2533  *
2534  * \return  bool
2535  */
ui_settings_dialog_activate_node(const char * path)2536 gboolean ui_settings_dialog_activate_node(const char *path)
2537 {
2538     GtkTreeIter iter;
2539     gchar **parts;
2540     const gchar *part;
2541     int column = 0;
2542 
2543     if (settings_window == NULL) {
2544         log_error(LOG_ERR, "settings dialog node activation requested without"
2545                 " the dialog active.");
2546         return FALSE;
2547     }
2548     if (path == NULL || *path == '\0') {
2549         log_error(LOG_ERR, "NULL or empty path pased.");
2550         return FALSE;
2551     }
2552 
2553     /* split path into parts */
2554     parts = g_strsplit(path, "/", 0);
2555     part = parts[0];
2556 
2557     /* get first item in model */
2558     gtk_tree_model_get_iter_first(GTK_TREE_MODEL(settings_model), &iter);
2559 
2560     /* iterate the parts of the path, trying to find to requested node */
2561     while (part != NULL) {
2562 
2563         const gchar *node_id = NULL;
2564 #if 0
2565         debug_gtk3("checking column %d for '%s'.", column, part);
2566 #endif
2567 
2568         /* iterate nodes until either 'part' is found or the nodes in the
2569          * current 'column' run out */
2570         while (TRUE) {
2571             gtk_tree_model_get(GTK_TREE_MODEL(settings_model), &iter,
2572                     COLUMN_ID, &node_id, -1);
2573 #if 0
2574             debug_gtk3("got id '%s'.", node_id);
2575 #endif
2576 
2577             /* check node ID against currently sought part of the path */
2578             if (strcmp(node_id, part) == 0) {
2579                 /* got the requested node */
2580 #if 0
2581                 debug_gtk3("FOUND SOMETHING!");
2582 #endif
2583                 if (parts[column + 1] == NULL) {
2584                     /* got final item */
2585 
2586                     GtkTreeSelection *selection;
2587                     GtkTreePath *tree_path;
2588 
2589                     debug_gtk3("GOT THE ITEM!");
2590                     selection = gtk_tree_view_get_selection(
2591                             GTK_TREE_VIEW(settings_tree));
2592                     tree_path = gtk_tree_model_get_path(
2593                             GTK_TREE_MODEL(settings_model), &iter);
2594                     gtk_tree_view_expand_to_path(
2595                             GTK_TREE_VIEW(settings_tree), tree_path);
2596                     gtk_tree_selection_select_path(selection, tree_path);
2597 
2598                     gtk_tree_path_free(tree_path);
2599                     g_strfreev(parts);
2600                     return TRUE;
2601                 } else {
2602                     /* continue searching, dive into the children of the
2603                      * current node, if there are any */
2604 #if 0
2605                     debug_gtk3("diving into child nodes of %s.", node_id);
2606 #endif
2607                     if (gtk_tree_model_iter_has_child(
2608                                 GTK_TREE_MODEL(settings_model), &iter)) {
2609                         /* node has children, iterate those now */
2610                         GtkTreeIter child;
2611 
2612                         if (!gtk_tree_model_iter_nth_child(
2613                                     GTK_TREE_MODEL(settings_model),
2614                                     &child, &iter, 0)) {
2615                             debug_gtk3("failed to get first child node.");
2616                             g_strfreev(parts);
2617                             return FALSE;
2618                         }
2619                         /* set iterator to first child node, update the index
2620                          * in the path parts */
2621                         iter = child;
2622                         part = parts[++column];
2623                         continue;
2624                     } else {
2625                         /* oops */
2626                         debug_gtk3("error: path '%s' continues into '%s' but"
2627                                 " there are no child nodes.", path, part);
2628                         g_strfreev(parts);
2629                         return FALSE;
2630                     }
2631                 }
2632             } else {
2633                 /* is there another node to inspect? */
2634                 if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(settings_model),
2635                                               &iter)) {
2636                     /* couldn't find the requested node, exit */
2637                     debug_gtk3("failed to find node at path '%s'.", path);
2638                     g_strfreev(parts);
2639                     return FALSE;
2640                 }
2641             }
2642         }
2643     }
2644 
2645     debug_gtk3("warning: should never get here.");
2646     g_strfreev(parts);
2647     return FALSE;
2648 }
2649 
2650 
2651 
2652 /** \brief  Show settings main dialog and activate a node
2653  *
2654  * \param[in]   path    path to name ("foo/bar/blah")
2655  *
2656  * \return  TRUE if node found, false otherwise
2657  */
ui_settings_dialog_create_and_activate_node(const char * path)2658 gboolean ui_settings_dialog_create_and_activate_node(const char *path)
2659 {
2660     GtkWidget *dialog;
2661 
2662     dialog = dialog_create_helper();
2663     settings_window = dialog;
2664 
2665     /* find and activate the node */
2666     if (!ui_settings_dialog_activate_node(path)) {
2667         debug_gtk3("failed to locate node, showing dialog anyway for now.");
2668     }
2669 
2670     gtk_widget_show_all(dialog);
2671     return TRUE;
2672 }
2673