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