ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/prefs_editor_gtk.cpp
Revision: 1.1
Committed: 2005-06-20T08:40:34Z (19 years ago) by gbeauche
Branch: MAIN
Log Message:
WIP prefs editor for Windows in GTK

File Contents

# User Rev Content
1 gbeauche 1.1 /*
2     * prefs_editor_gtk.cpp - Preferences editor, Unix implementation using GTK+
3     *
4     * Basilisk II (C) 1997-2005 Christian Bauer
5     *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include "sysdeps.h"
22    
23     #include <gtk/gtk.h>
24     #include <stdlib.h>
25    
26     #include "user_strings.h"
27     #include "version.h"
28     #include "cdrom.h"
29     #include "xpram.h"
30     #include "prefs.h"
31     #include "prefs_editor.h"
32    
33    
34     // Global variables
35     static GtkWidget *win; // Preferences window
36     static bool start_clicked = true; // Return value of PrefsEditor() function
37    
38    
39     // Prototypes
40     static void create_volumes_pane(GtkWidget *top);
41     static void create_scsi_pane(GtkWidget *top);
42     static void create_graphics_pane(GtkWidget *top);
43     static void create_input_pane(GtkWidget *top);
44     static void create_serial_pane(GtkWidget *top);
45     static void create_ethernet_pane(GtkWidget *top);
46     static void create_memory_pane(GtkWidget *top);
47     static void create_jit_pane(GtkWidget *top);
48     static void read_settings(void);
49    
50    
51     /*
52     * Utility functions
53     */
54    
55     struct opt_desc {
56     int label_id;
57     GtkSignalFunc func;
58     };
59    
60     struct combo_desc {
61     int label_id;
62     };
63    
64     struct file_req_assoc {
65     file_req_assoc(GtkWidget *r, GtkWidget *e) : req(r), entry(e) {}
66     GtkWidget *req;
67     GtkWidget *entry;
68     };
69    
70     static void cb_browse_ok(GtkWidget *button, file_req_assoc *assoc)
71     {
72     gchar *file = (char *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
73     gtk_entry_set_text(GTK_ENTRY(assoc->entry), file);
74     gtk_widget_destroy(assoc->req);
75     delete assoc;
76     }
77    
78     static void cb_browse(GtkWidget *widget, void *user_data)
79     {
80     GtkWidget *req = gtk_file_selection_new(GetString(STR_BROWSE_TITLE));
81     gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
82     gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(cb_browse_ok), new file_req_assoc(req, (GtkWidget *)user_data));
83     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
84     gtk_widget_show(req);
85     }
86    
87     static GtkWidget *make_browse_button(GtkWidget *entry)
88     {
89     GtkWidget *button;
90    
91     button = gtk_button_new_with_label(GetString(STR_BROWSE_CTRL));
92     gtk_widget_show(button);
93     gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc)cb_browse, (void *)entry);
94     return button;
95     }
96    
97     static void add_menu_item(GtkWidget *menu, int label_id, GtkSignalFunc func)
98     {
99     GtkWidget *item = gtk_menu_item_new_with_label(GetString(label_id));
100     gtk_widget_show(item);
101     gtk_signal_connect(GTK_OBJECT(item), "activate", func, NULL);
102     gtk_menu_append(GTK_MENU(menu), item);
103     }
104    
105     static GtkWidget *make_pane(GtkWidget *notebook, int title_id)
106     {
107     GtkWidget *frame, *label, *box;
108    
109     frame = gtk_frame_new(NULL);
110     gtk_widget_show(frame);
111     gtk_container_border_width(GTK_CONTAINER(frame), 4);
112    
113     label = gtk_label_new(GetString(title_id));
114     gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label);
115    
116     box = gtk_vbox_new(FALSE, 4);
117     gtk_widget_show(box);
118     gtk_container_set_border_width(GTK_CONTAINER(box), 4);
119     gtk_container_add(GTK_CONTAINER(frame), box);
120     return box;
121     }
122    
123     static GtkWidget *make_button_box(GtkWidget *top, int border, const opt_desc *buttons)
124     {
125     GtkWidget *bb, *button;
126    
127     bb = gtk_hbutton_box_new();
128     gtk_widget_show(bb);
129     gtk_container_set_border_width(GTK_CONTAINER(bb), border);
130     gtk_button_box_set_layout(GTK_BUTTON_BOX(bb), GTK_BUTTONBOX_DEFAULT_STYLE);
131     gtk_button_box_set_spacing(GTK_BUTTON_BOX(bb), 4);
132     gtk_box_pack_start(GTK_BOX(top), bb, FALSE, FALSE, 0);
133    
134     while (buttons->label_id) {
135     button = gtk_button_new_with_label(GetString(buttons->label_id));
136     gtk_widget_show(button);
137     gtk_signal_connect_object(GTK_OBJECT(button), "clicked", buttons->func, NULL);
138     gtk_box_pack_start(GTK_BOX(bb), button, TRUE, TRUE, 0);
139     buttons++;
140     }
141     return bb;
142     }
143    
144     static GtkWidget *make_separator(GtkWidget *top)
145     {
146     GtkWidget *sep = gtk_hseparator_new();
147     gtk_box_pack_start(GTK_BOX(top), sep, FALSE, FALSE, 0);
148     gtk_widget_show(sep);
149     return sep;
150     }
151    
152     static GtkWidget *make_table(GtkWidget *top, int x, int y)
153     {
154     GtkWidget *table = gtk_table_new(x, y, FALSE);
155     gtk_widget_show(table);
156     gtk_box_pack_start(GTK_BOX(top), table, FALSE, FALSE, 0);
157     return table;
158     }
159    
160     static GtkWidget *make_option_menu(GtkWidget *top, int label_id, const opt_desc *options, int active)
161     {
162     GtkWidget *box, *label, *opt, *menu;
163    
164     box = gtk_hbox_new(FALSE, 4);
165     gtk_widget_show(box);
166     gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0);
167    
168     label = gtk_label_new(GetString(label_id));
169     gtk_widget_show(label);
170     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
171    
172     opt = gtk_option_menu_new();
173     gtk_widget_show(opt);
174     menu = gtk_menu_new();
175    
176     while (options->label_id) {
177     add_menu_item(menu, options->label_id, options->func);
178     options++;
179     }
180     gtk_menu_set_active(GTK_MENU(menu), active);
181    
182     gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
183     gtk_box_pack_start(GTK_BOX(box), opt, FALSE, FALSE, 0);
184     return menu;
185     }
186    
187     static GtkWidget *make_file_entry(GtkWidget *top, int label_id, const char *prefs_item, bool only_dirs = false)
188     {
189     GtkWidget *box, *label, *entry;
190    
191     box = gtk_hbox_new(FALSE, 4);
192     gtk_widget_show(box);
193     gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0);
194    
195     label = gtk_label_new(GetString(label_id));
196     gtk_widget_show(label);
197     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
198    
199     const char *str = PrefsFindString(prefs_item);
200     if (str == NULL)
201     str = "";
202    
203     entry = gtk_entry_new();
204     gtk_entry_set_text(GTK_ENTRY(entry), str);
205     gtk_widget_show(entry);
206     gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0);
207     return entry;
208     }
209    
210     static const gchar *get_file_entry_path(GtkWidget *entry)
211     {
212     return gtk_entry_get_text(GTK_ENTRY(entry));
213     }
214    
215     static GtkWidget *make_checkbox(GtkWidget *top, int label_id, const char *prefs_item, GtkSignalFunc func)
216     {
217     GtkWidget *button = gtk_check_button_new_with_label(GetString(label_id));
218     gtk_widget_show(button);
219     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), PrefsFindBool(prefs_item));
220     gtk_signal_connect(GTK_OBJECT(button), "toggled", func, button);
221     gtk_box_pack_start(GTK_BOX(top), button, FALSE, FALSE, 0);
222     return button;
223     }
224    
225     static GtkWidget *make_combobox(GtkWidget *top, int label_id, const char *prefs_item, const combo_desc *options)
226     {
227     GtkWidget *box, *label, *combo;
228     char str[32];
229    
230     box = gtk_hbox_new(FALSE, 4);
231     gtk_widget_show(box);
232     gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0);
233    
234     label = gtk_label_new(GetString(label_id));
235     gtk_widget_show(label);
236     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
237    
238     GList *glist = NULL;
239     while (options->label_id) {
240     glist = g_list_append(glist, (void *)GetString(options->label_id));
241     options++;
242     }
243    
244     combo = gtk_combo_new();
245     gtk_widget_show(combo);
246     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
247    
248     sprintf(str, "%d", PrefsFindInt32(prefs_item));
249     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
250     gtk_box_pack_start(GTK_BOX(box), combo, TRUE, TRUE, 0);
251    
252     return combo;
253     }
254    
255    
256     /*
257     * Show preferences editor
258     * Returns true when user clicked on "Start", false otherwise
259     */
260    
261     // Window closed
262     static gint window_closed(void)
263     {
264     return FALSE;
265     }
266    
267     // Window destroyed
268     static void window_destroyed(void)
269     {
270     gtk_main_quit();
271     }
272    
273     // "Start" button clicked
274     static void cb_start(...)
275     {
276     start_clicked = true;
277     read_settings();
278     SavePrefs();
279     gtk_widget_destroy(win);
280     }
281    
282     // "Zap PRAM" button clicked
283     static void cb_zap_pram(...)
284     {
285     ZapPRAM();
286     }
287    
288     // "Quit" button clicked
289     static void cb_quit(...)
290     {
291     start_clicked = false;
292     gtk_widget_destroy(win);
293     }
294    
295     // "OK" button of "About" dialog clicked
296     static void dl_quit(GtkWidget *dialog)
297     {
298     gtk_widget_destroy(dialog);
299     }
300    
301     // "About" button clicked
302     static void cb_about(...)
303     {
304     GtkWidget *dialog;
305    
306     GtkWidget *label, *button;
307    
308     char str[512];
309     sprintf(str,
310     "Basilisk II\nVersion %d.%d\n\n"
311     "Copyright (C) 1997-2005 Christian Bauer et al.\n"
312     "E-mail: Christian.Bauer@uni-mainz.de\n"
313     "http://www.uni-mainz.de/~bauec002/B2Main.html\n\n"
314     "Basilisk II comes with ABSOLUTELY NO\n"
315     "WARRANTY. This is free software, and\n"
316     "you are welcome to redistribute it\n"
317     "under the terms of the GNU General\n"
318     "Public License.\n",
319     VERSION_MAJOR, VERSION_MINOR
320     );
321    
322     dialog = gtk_dialog_new();
323     gtk_window_set_title(GTK_WINDOW(dialog), GetString(STR_ABOUT_TITLE));
324     gtk_container_border_width(GTK_CONTAINER(dialog), 5);
325     gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
326    
327     label = gtk_label_new(str);
328     gtk_widget_show(label);
329     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
330    
331     button = gtk_button_new_with_label(GetString(STR_OK_BUTTON));
332     gtk_widget_show(button);
333     gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
334     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
335     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
336     gtk_widget_grab_default(button);
337    
338     gtk_widget_show(dialog);
339     }
340    
341     // Menu item descriptions
342     static GtkItemFactoryEntry menu_items[] = {
343     {(gchar *)GetString(STR_PREFS_MENU_FILE_GTK), NULL, NULL, 0, "<Branch>"},
344     {(gchar *)GetString(STR_PREFS_ITEM_START_GTK), NULL, GTK_SIGNAL_FUNC(cb_start), 0, NULL},
345     {(gchar *)GetString(STR_PREFS_ITEM_ZAP_PRAM_GTK), NULL, GTK_SIGNAL_FUNC(cb_zap_pram), 0, NULL},
346     {(gchar *)GetString(STR_PREFS_ITEM_SEPL_GTK), NULL, NULL, 0, "<Separator>"},
347     {(gchar *)GetString(STR_PREFS_ITEM_QUIT_GTK), "<control>Q", GTK_SIGNAL_FUNC(cb_quit), 0, NULL},
348     {(gchar *)GetString(STR_HELP_MENU_GTK), NULL, NULL, 0, "<LastBranch>"},
349     {(gchar *)GetString(STR_HELP_ITEM_ABOUT_GTK), NULL, GTK_SIGNAL_FUNC(cb_about), 0, NULL}
350     };
351    
352     bool PrefsEditor(void)
353     {
354     // Create window
355     win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
356     gtk_window_set_title(GTK_WINDOW(win), GetString(STR_PREFS_TITLE));
357     gtk_signal_connect(GTK_OBJECT(win), "delete_event", GTK_SIGNAL_FUNC(window_closed), NULL);
358     gtk_signal_connect(GTK_OBJECT(win), "destroy", GTK_SIGNAL_FUNC(window_destroyed), NULL);
359    
360     // Create window contents
361     GtkWidget *box = gtk_vbox_new(FALSE, 4);
362     gtk_widget_show(box);
363     gtk_container_add(GTK_CONTAINER(win), box);
364    
365     GtkAccelGroup *accel_group = gtk_accel_group_new();
366     GtkItemFactory *item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
367     gtk_item_factory_create_items(item_factory, sizeof(menu_items) / sizeof(menu_items[0]), menu_items, NULL);
368     #if GTK_CHECK_VERSION(1,3,15)
369     gtk_window_add_accel_group(GTK_WINDOW(win), accel_group);
370     #else
371     gtk_accel_group_attach(accel_group, GTK_OBJECT(win));
372     #endif
373     GtkWidget *menu_bar = gtk_item_factory_get_widget(item_factory, "<main>");
374     gtk_widget_show(menu_bar);
375     gtk_box_pack_start(GTK_BOX(box), menu_bar, FALSE, TRUE, 0);
376    
377     GtkWidget *notebook = gtk_notebook_new();
378     gtk_widget_show(notebook);
379     gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
380     gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), FALSE);
381     gtk_box_pack_start(GTK_BOX(box), notebook, TRUE, TRUE, 0);
382    
383     create_volumes_pane(notebook);
384     create_scsi_pane(notebook);
385     create_graphics_pane(notebook);
386     create_input_pane(notebook);
387     create_serial_pane(notebook);
388     create_ethernet_pane(notebook);
389     create_memory_pane(notebook);
390     create_jit_pane(notebook);
391    
392     static const opt_desc buttons[] = {
393     {STR_START_BUTTON, GTK_SIGNAL_FUNC(cb_start)},
394     {STR_PREFS_ITEM_ZAP_PRAM, GTK_SIGNAL_FUNC(cb_zap_pram)},
395     {STR_ABOUT_BUTTON, GTK_SIGNAL_FUNC(cb_about)},
396     {STR_QUIT_BUTTON, GTK_SIGNAL_FUNC(cb_quit)},
397     {0, NULL}
398     };
399     make_button_box(box, 4, buttons);
400    
401     // Show window and enter main loop
402     gtk_widget_show(win);
403     gtk_main();
404     return start_clicked;
405     }
406    
407    
408     /*
409     * "Volumes" pane
410     */
411    
412     static GtkWidget *volume_list;
413     static int selected_volume;
414    
415     // Volume in list selected
416     static void cl_selected(GtkWidget *list, int row, int column)
417     {
418     selected_volume = row;
419     }
420    
421     // Volume selected for addition
422     static void add_volume_ok(GtkWidget *button, file_req_assoc *assoc)
423     {
424     gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
425     gtk_clist_append(GTK_CLIST(volume_list), &file);
426     gtk_widget_destroy(assoc->req);
427     delete assoc;
428     }
429    
430     // Volume selected for creation
431     static void create_volume_ok(GtkWidget *button, file_req_assoc *assoc)
432     {
433     gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
434    
435     const gchar *str = gtk_entry_get_text(GTK_ENTRY(assoc->entry));
436     int size = atoi(str);
437    
438     char cmd[1024];
439     sprintf(cmd, "dd if=/dev/zero \"of=%s\" bs=1024k count=%d", file, size);
440     int ret = system(cmd);
441     if (ret == 0)
442     gtk_clist_append(GTK_CLIST(volume_list), &file);
443     gtk_widget_destroy(GTK_WIDGET(assoc->req));
444     delete assoc;
445     }
446    
447     // "Add Volume" button clicked
448     static void cb_add_volume(...)
449     {
450     GtkWidget *req = gtk_file_selection_new(GetString(STR_ADD_VOLUME_TITLE));
451     gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
452     gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(add_volume_ok), new file_req_assoc(req, NULL));
453     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
454     gtk_widget_show(req);
455     }
456    
457     // "Create Hardfile" button clicked
458     static void cb_create_volume(...)
459     {
460     GtkWidget *req = gtk_file_selection_new(GetString(STR_CREATE_VOLUME_TITLE));
461    
462     GtkWidget *box = gtk_hbox_new(FALSE, 4);
463     gtk_widget_show(box);
464     GtkWidget *label = gtk_label_new(GetString(STR_HARDFILE_SIZE_CTRL));
465     gtk_widget_show(label);
466     GtkWidget *entry = gtk_entry_new();
467     gtk_widget_show(entry);
468     char str[32];
469     sprintf(str, "%d", 40);
470     gtk_entry_set_text(GTK_ENTRY(entry), str);
471     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
472     gtk_box_pack_start(GTK_BOX(box), entry, FALSE, FALSE, 0);
473     gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(req)->main_vbox), box, FALSE, FALSE, 0);
474    
475     gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
476     gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(create_volume_ok), new file_req_assoc(req, entry));
477     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
478     gtk_widget_show(req);
479     }
480    
481     // "Remove Volume" button clicked
482     static void cb_remove_volume(...)
483     {
484     gtk_clist_remove(GTK_CLIST(volume_list), selected_volume);
485     }
486    
487     // "Boot From" selected
488     static void mn_boot_any(...) {PrefsReplaceInt32("bootdriver", 0);}
489     static void mn_boot_cdrom(...) {PrefsReplaceInt32("bootdriver", CDROMRefNum);}
490    
491     // "No CD-ROM Driver" button toggled
492     static void tb_nocdrom(GtkWidget *widget)
493     {
494     PrefsReplaceBool("nocdrom", GTK_TOGGLE_BUTTON(widget)->active);
495     }
496    
497     // Read settings from widgets and set preferences
498     static void read_volumes_settings(void)
499     {
500     while (PrefsFindString("disk"))
501     PrefsRemoveItem("disk");
502    
503     for (int i=0; i<GTK_CLIST(volume_list)->rows; i++) {
504     char *str;
505     gtk_clist_get_text(GTK_CLIST(volume_list), i, 0, &str);
506     PrefsAddString("disk", str);
507     }
508     }
509    
510     // Create "Volumes" pane
511     static void create_volumes_pane(GtkWidget *top)
512     {
513     GtkWidget *box, *scroll, *menu;
514    
515     box = make_pane(top, STR_VOLUMES_PANE_TITLE);
516    
517     scroll = gtk_scrolled_window_new(NULL, NULL);
518     gtk_widget_show(scroll);
519     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
520     volume_list = gtk_clist_new(1);
521     gtk_widget_show(volume_list);
522     gtk_clist_set_selection_mode(GTK_CLIST(volume_list), GTK_SELECTION_SINGLE);
523     gtk_clist_set_shadow_type(GTK_CLIST(volume_list), GTK_SHADOW_NONE);
524     gtk_clist_set_reorderable(GTK_CLIST(volume_list), true);
525     gtk_signal_connect(GTK_OBJECT(volume_list), "select_row", GTK_SIGNAL_FUNC(cl_selected), NULL);
526     char *str;
527     int32 index = 0;
528     while ((str = const_cast<char *>(PrefsFindString("disk", index++))) != NULL)
529     gtk_clist_append(GTK_CLIST(volume_list), &str);
530     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), volume_list);
531     gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 0);
532     selected_volume = 0;
533    
534     static const opt_desc buttons[] = {
535     {STR_ADD_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_add_volume)},
536     {STR_CREATE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_create_volume)},
537     {STR_REMOVE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_remove_volume)},
538     {0, NULL},
539     };
540     make_button_box(box, 0, buttons);
541     make_separator(box);
542    
543     static const opt_desc options[] = {
544     {STR_BOOT_ANY_LAB, GTK_SIGNAL_FUNC(mn_boot_any)},
545     {STR_BOOT_CDROM_LAB, GTK_SIGNAL_FUNC(mn_boot_cdrom)},
546     {0, NULL}
547     };
548     int bootdriver = PrefsFindInt32("bootdriver"), active = 0;
549     switch (bootdriver) {
550     case 0: active = 0; break;
551     case CDROMRefNum: active = 1; break;
552     }
553     menu = make_option_menu(box, STR_BOOTDRIVER_CTRL, options, active);
554    
555     make_checkbox(box, STR_NOCDROM_CTRL, "nocdrom", GTK_SIGNAL_FUNC(tb_nocdrom));
556     }
557    
558    
559     /*
560     * "JIT Compiler" pane
561     */
562    
563     static GtkWidget *w_jit_fpu;
564     static GtkWidget *w_jit_atraps;
565     static GtkWidget *w_jit_cache_size;
566     static GtkWidget *w_jit_lazy_flush;
567     static GtkWidget *w_jit_follow_const_jumps;
568    
569     // Set sensitivity of widgets
570     static void set_jit_sensitive(void)
571     {
572     const bool jit_enabled = PrefsFindBool("jit");
573     gtk_widget_set_sensitive(w_jit_fpu, jit_enabled);
574     gtk_widget_set_sensitive(w_jit_cache_size, jit_enabled);
575     gtk_widget_set_sensitive(w_jit_lazy_flush, jit_enabled);
576     gtk_widget_set_sensitive(w_jit_follow_const_jumps, jit_enabled);
577     }
578    
579     // "Use JIT Compiler" button toggled
580     static void tb_jit(GtkWidget *widget)
581     {
582     PrefsReplaceBool("jit", GTK_TOGGLE_BUTTON(widget)->active);
583     set_jit_sensitive();
584     }
585    
586     // "Compile FPU Instructions" button toggled
587     static void tb_jit_fpu(GtkWidget *widget)
588     {
589     PrefsReplaceBool("jitfpu", GTK_TOGGLE_BUTTON(widget)->active);
590     }
591    
592     // "Lazy translation cache invalidation" button toggled
593     static void tb_jit_lazy_flush(GtkWidget *widget)
594     {
595     PrefsReplaceBool("jitlazyflush", GTK_TOGGLE_BUTTON(widget)->active);
596     }
597    
598     // "Translate through constant jumps (inline blocks)" button toggled
599     static void tb_jit_follow_const_jumps(GtkWidget *widget)
600     {
601     PrefsReplaceBool("jitinline", GTK_TOGGLE_BUTTON(widget)->active);
602     }
603    
604     // Read settings from widgets and set preferences
605     static void read_jit_settings(void)
606     {
607     #if USE_JIT
608     bool jit_enabled = PrefsFindBool("jit");
609     if (jit_enabled) {
610     const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_jit_cache_size)->entry));
611     PrefsReplaceInt32("jitcachesize", atoi(str));
612     }
613     #endif
614     }
615    
616     // Create "JIT Compiler" pane
617     static void create_jit_pane(GtkWidget *top)
618     {
619     #if USE_JIT
620     GtkWidget *box, *table, *label, *menu;
621     char str[32];
622    
623     box = make_pane(top, STR_JIT_PANE_TITLE);
624     make_checkbox(box, STR_JIT_CTRL, "jit", GTK_SIGNAL_FUNC(tb_jit));
625    
626     w_jit_fpu = make_checkbox(box, STR_JIT_FPU_CTRL, "jitfpu", GTK_SIGNAL_FUNC(tb_jit_fpu));
627    
628     // Translation cache size
629     static const combo_desc options[] = {
630     STR_JIT_CACHE_SIZE_2MB_LAB,
631     STR_JIT_CACHE_SIZE_4MB_LAB,
632     STR_JIT_CACHE_SIZE_8MB_LAB,
633     STR_JIT_CACHE_SIZE_16MB_LAB,
634     0
635     };
636     w_jit_cache_size = make_combobox(box, STR_JIT_CACHE_SIZE_CTRL, "jitcachesize", options);
637    
638     // Lazy translation cache invalidation
639     w_jit_lazy_flush = make_checkbox(box, STR_JIT_LAZY_CINV_CTRL, "jitlazyflush", GTK_SIGNAL_FUNC(tb_jit_lazy_flush));
640    
641     // Follow constant jumps (inline basic blocks)
642     w_jit_follow_const_jumps = make_checkbox(box, STR_JIT_FOLLOW_CONST_JUMPS, "jitinline", GTK_SIGNAL_FUNC(tb_jit_follow_const_jumps));
643    
644     set_jit_sensitive();
645     #endif
646     }
647    
648     /*
649     * "SCSI" pane
650     */
651    
652     static GtkWidget *w_scsi[7];
653    
654     // Read settings from widgets and set preferences
655     static void read_scsi_settings(void)
656     {
657     for (int id=0; id<7; id++) {
658     char prefs_name[32];
659     sprintf(prefs_name, "scsi%d", id);
660     const char *str = get_file_entry_path(w_scsi[id]);
661     if (str && strlen(str))
662     PrefsReplaceString(prefs_name, str);
663     else
664     PrefsRemoveItem(prefs_name);
665     }
666     }
667    
668     // Create "SCSI" pane
669     static void create_scsi_pane(GtkWidget *top)
670     {
671     GtkWidget *box;
672    
673     box = make_pane(top, STR_SCSI_PANE_TITLE);
674    
675     for (int id=0; id<7; id++) {
676     char prefs_name[32];
677     sprintf(prefs_name, "scsi%d", id);
678     w_scsi[id] = make_file_entry(box, STR_SCSI_ID_0 + id, prefs_name);
679     }
680     }
681    
682    
683     /*
684     * "Graphics/Sound" pane
685     */
686    
687     // Display types
688     enum {
689     DISPLAY_WINDOW,
690     DISPLAY_SCREEN
691     };
692    
693     static GtkWidget *w_frameskip, *w_display_x, *w_display_y;
694     static GtkWidget *l_frameskip, *l_display_x, *l_display_y;
695     static int display_type;
696     static int dis_width, dis_height;
697    
698     // Hide/show graphics widgets
699     static void hide_show_graphics_widgets(void)
700     {
701     switch (display_type) {
702     case DISPLAY_WINDOW:
703     gtk_widget_show(w_frameskip); gtk_widget_show(l_frameskip);
704     break;
705     case DISPLAY_SCREEN:
706     gtk_widget_hide(w_frameskip); gtk_widget_hide(l_frameskip);
707     break;
708     }
709     }
710    
711     // "Window" video type selected
712     static void mn_window(...)
713     {
714     display_type = DISPLAY_WINDOW;
715     hide_show_graphics_widgets();
716     }
717    
718     // "Fullscreen" video type selected
719     static void mn_fullscreen(...)
720     {
721     display_type = DISPLAY_SCREEN;
722     hide_show_graphics_widgets();
723     }
724    
725     // "5 Hz".."60Hz" selected
726     static void mn_5hz(...) {PrefsReplaceInt32("frameskip", 12);}
727     static void mn_7hz(...) {PrefsReplaceInt32("frameskip", 8);}
728     static void mn_10hz(...) {PrefsReplaceInt32("frameskip", 6);}
729     static void mn_15hz(...) {PrefsReplaceInt32("frameskip", 4);}
730     static void mn_30hz(...) {PrefsReplaceInt32("frameskip", 2);}
731     static void mn_60hz(...) {PrefsReplaceInt32("frameskip", 1);}
732     static void mn_dynamic(...) {PrefsReplaceInt32("frameskip", 0);}
733    
734     // Set sensitivity of widgets
735     static void set_graphics_sensitive(void)
736     {
737     const bool sound_enabled = !PrefsFindBool("nosound");
738     }
739    
740     // "Disable Sound Output" button toggled
741     static void tb_nosound(GtkWidget *widget)
742     {
743     PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active);
744     set_graphics_sensitive();
745     }
746    
747     // Read graphics preferences
748     static void parse_graphics_prefs(void)
749     {
750     display_type = DISPLAY_WINDOW;
751     dis_width = 512;
752     dis_height = 384;
753    
754     const char *str = PrefsFindString("screen");
755     if (str) {
756     if (sscanf(str, "win/%d/%d", &dis_width, &dis_height) == 2)
757     display_type = DISPLAY_WINDOW;
758     else if (sscanf(str, "dga/%d/%d", &dis_width, &dis_height) == 2)
759     display_type = DISPLAY_SCREEN;
760     }
761     }
762    
763     // Read settings from widgets and set preferences
764     static void read_graphics_settings(void)
765     {
766     const char *str;
767    
768     str = gtk_entry_get_text(GTK_ENTRY(w_display_x));
769     dis_width = atoi(str);
770    
771     str = gtk_entry_get_text(GTK_ENTRY(w_display_y));
772     dis_height = atoi(str);
773    
774     char pref[256];
775     switch (display_type) {
776     case DISPLAY_WINDOW:
777     sprintf(pref, "win/%d/%d", dis_width, dis_height);
778     break;
779     case DISPLAY_SCREEN:
780     sprintf(pref, "dga/%d/%d", dis_width, dis_height);
781     break;
782     default:
783     PrefsRemoveItem("screen");
784     return;
785     }
786     PrefsReplaceString("screen", pref);
787     }
788    
789     // Create "Graphics/Sound" pane
790     static void create_graphics_pane(GtkWidget *top)
791     {
792     GtkWidget *box, *table, *label, *opt, *menu, *combo;
793     char str[32];
794    
795     parse_graphics_prefs();
796    
797     box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE);
798     table = make_table(box, 2, 5);
799    
800     label = gtk_label_new(GetString(STR_VIDEO_TYPE_CTRL));
801     gtk_widget_show(label);
802     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
803    
804     opt = gtk_option_menu_new();
805     gtk_widget_show(opt);
806     menu = gtk_menu_new();
807     add_menu_item(menu, STR_WINDOW_LAB, GTK_SIGNAL_FUNC(mn_window));
808     add_menu_item(menu, STR_FULLSCREEN_LAB, GTK_SIGNAL_FUNC(mn_fullscreen));
809     switch (display_type) {
810     case DISPLAY_WINDOW:
811     gtk_menu_set_active(GTK_MENU(menu), 0);
812     break;
813     case DISPLAY_SCREEN:
814     gtk_menu_set_active(GTK_MENU(menu), 1);
815     break;
816     }
817     gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
818     gtk_table_attach(GTK_TABLE(table), opt, 1, 2, 0, 1, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
819    
820     l_frameskip = gtk_label_new(GetString(STR_FRAMESKIP_CTRL));
821     gtk_widget_show(l_frameskip);
822     gtk_table_attach(GTK_TABLE(table), l_frameskip, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
823    
824     w_frameskip = gtk_option_menu_new();
825     gtk_widget_show(w_frameskip);
826     menu = gtk_menu_new();
827     add_menu_item(menu, STR_REF_5HZ_LAB, GTK_SIGNAL_FUNC(mn_5hz));
828     add_menu_item(menu, STR_REF_7_5HZ_LAB, GTK_SIGNAL_FUNC(mn_7hz));
829     add_menu_item(menu, STR_REF_10HZ_LAB, GTK_SIGNAL_FUNC(mn_10hz));
830     add_menu_item(menu, STR_REF_15HZ_LAB, GTK_SIGNAL_FUNC(mn_15hz));
831     add_menu_item(menu, STR_REF_30HZ_LAB, GTK_SIGNAL_FUNC(mn_30hz));
832     add_menu_item(menu, STR_REF_60HZ_LAB, GTK_SIGNAL_FUNC(mn_60hz));
833     add_menu_item(menu, STR_REF_DYNAMIC_LAB, GTK_SIGNAL_FUNC(mn_dynamic));
834     int frameskip = PrefsFindInt32("frameskip");
835     int item = -1;
836     switch (frameskip) {
837     case 12: item = 0; break;
838     case 8: item = 1; break;
839     case 6: item = 2; break;
840     case 4: item = 3; break;
841     case 2: item = 4; break;
842     case 1: item = 5; break;
843     case 0: item = 6; break;
844     }
845     if (item >= 0)
846     gtk_menu_set_active(GTK_MENU(menu), item);
847     gtk_option_menu_set_menu(GTK_OPTION_MENU(w_frameskip), menu);
848     gtk_table_attach(GTK_TABLE(table), w_frameskip, 1, 2, 1, 2, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
849    
850     l_display_x = gtk_label_new(GetString(STR_DISPLAY_X_CTRL));
851     gtk_widget_show(l_display_x);
852     gtk_table_attach(GTK_TABLE(table), l_display_x, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
853    
854     combo = gtk_combo_new();
855     gtk_widget_show(combo);
856     GList *glist1 = NULL;
857     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_512_LAB));
858     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_640_LAB));
859     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_800_LAB));
860     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_1024_LAB));
861     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_MAX_LAB));
862     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist1);
863     if (dis_width)
864     sprintf(str, "%d", dis_width);
865     else
866     strcpy(str, GetString(STR_SIZE_MAX_LAB));
867     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
868     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
869     w_display_x = GTK_COMBO(combo)->entry;
870    
871     l_display_y = gtk_label_new(GetString(STR_DISPLAY_Y_CTRL));
872     gtk_widget_show(l_display_y);
873     gtk_table_attach(GTK_TABLE(table), l_display_y, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
874    
875     combo = gtk_combo_new();
876     gtk_widget_show(combo);
877     GList *glist2 = NULL;
878     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_384_LAB));
879     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_480_LAB));
880     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_600_LAB));
881     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_768_LAB));
882     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_MAX_LAB));
883     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist2);
884     if (dis_height)
885     sprintf(str, "%d", dis_height);
886     else
887     strcpy(str, GetString(STR_SIZE_MAX_LAB));
888     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
889     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
890     w_display_y = GTK_COMBO(combo)->entry;
891    
892     make_separator(box);
893     make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound));
894    
895     set_graphics_sensitive();
896    
897     hide_show_graphics_widgets();
898     }
899    
900    
901     /*
902     * "Input" pane
903     */
904    
905     static GtkWidget *w_keycode_file;
906     static GtkWidget *w_mouse_wheel_lines;
907    
908     // Set sensitivity of widgets
909     static void set_input_sensitive(void)
910     {
911     gtk_widget_set_sensitive(w_keycode_file, PrefsFindBool("keycodes"));
912     gtk_widget_set_sensitive(w_mouse_wheel_lines, PrefsFindInt32("mousewheelmode") == 1);
913     }
914    
915     // "Use Raw Keycodes" button toggled
916     static void tb_keycodes(GtkWidget *widget)
917     {
918     PrefsReplaceBool("keycodes", GTK_TOGGLE_BUTTON(widget)->active);
919     set_input_sensitive();
920     }
921    
922     // "Mouse Wheel Mode" selected
923     static void mn_wheel_page(...) {PrefsReplaceInt32("mousewheelmode", 0); set_input_sensitive();}
924     static void mn_wheel_cursor(...) {PrefsReplaceInt32("mousewheelmode", 1); set_input_sensitive();}
925    
926     // Read settings from widgets and set preferences
927     static void read_input_settings(void)
928     {
929     const char *str = get_file_entry_path(w_keycode_file);
930     if (str && strlen(str))
931     PrefsReplaceString("keycodefile", str);
932     else
933     PrefsRemoveItem("keycodefile");
934    
935     PrefsReplaceInt32("mousewheellines", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_mouse_wheel_lines)));
936     }
937    
938     // Create "Input" pane
939     static void create_input_pane(GtkWidget *top)
940     {
941     GtkWidget *box, *hbox, *menu, *label;
942     GtkObject *adj;
943    
944     box = make_pane(top, STR_INPUT_PANE_TITLE);
945    
946     make_checkbox(box, STR_KEYCODES_CTRL, "keycodes", GTK_SIGNAL_FUNC(tb_keycodes));
947     w_keycode_file = make_file_entry(box, STR_KEYCODE_FILE_CTRL, "keycodefile");
948    
949     make_separator(box);
950    
951     static const opt_desc options[] = {
952     {STR_MOUSEWHEELMODE_PAGE_LAB, GTK_SIGNAL_FUNC(mn_wheel_page)},
953     {STR_MOUSEWHEELMODE_CURSOR_LAB, GTK_SIGNAL_FUNC(mn_wheel_cursor)},
954     {0, NULL}
955     };
956     int wheelmode = PrefsFindInt32("mousewheelmode"), active = 0;
957     switch (wheelmode) {
958     case 0: active = 0; break;
959     case 1: active = 1; break;
960     }
961     menu = make_option_menu(box, STR_MOUSEWHEELMODE_CTRL, options, active);
962    
963     hbox = gtk_hbox_new(FALSE, 4);
964     gtk_widget_show(hbox);
965     gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
966    
967     label = gtk_label_new(GetString(STR_MOUSEWHEELLINES_CTRL));
968     gtk_widget_show(label);
969     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
970    
971     adj = gtk_adjustment_new(PrefsFindInt32("mousewheellines"), 1, 1000, 1, 5, 0);
972     w_mouse_wheel_lines = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0);
973     gtk_widget_show(w_mouse_wheel_lines);
974     gtk_box_pack_start(GTK_BOX(hbox), w_mouse_wheel_lines, FALSE, FALSE, 0);
975    
976     set_input_sensitive();
977     }
978    
979    
980     /*
981     * "Ports" pane
982     */
983    
984     static GtkWidget *w_seriala, *w_portfile0, *w_portfile0_browse;
985     static GtkWidget *w_serialb, *w_portfile1, *w_portfile1_browse;
986    
987     // Set sensitivity of widgets
988     static void set_serial_sensitive(void)
989     {
990     const char *str;
991     bool is_file;
992    
993     str = gtk_entry_get_text(GTK_ENTRY(w_seriala));
994     is_file = strcmp(str, "FILE") == 0;
995     gtk_widget_set_sensitive(w_portfile0, is_file);
996     gtk_widget_set_sensitive(w_portfile0_browse, is_file);
997    
998     str = gtk_entry_get_text(GTK_ENTRY(w_serialb));
999     is_file = strcmp(str, "FILE") == 0;
1000     gtk_widget_set_sensitive(w_portfile1, is_file);
1001     gtk_widget_set_sensitive(w_portfile1_browse, is_file);
1002     }
1003    
1004     // Read settings from widgets and set preferences
1005     static void read_serial_settings(void)
1006     {
1007     const char *str;
1008    
1009     str = gtk_entry_get_text(GTK_ENTRY(w_seriala));
1010     PrefsReplaceString("seriala", str);
1011    
1012     str = gtk_entry_get_text(GTK_ENTRY(w_serialb));
1013     PrefsReplaceString("serialb", str);
1014    
1015     str = gtk_entry_get_text(GTK_ENTRY(w_portfile0));
1016     PrefsReplaceString("portfile0", str);
1017    
1018     str = gtk_entry_get_text(GTK_ENTRY(w_portfile1));
1019     PrefsReplaceString("portfile1", str);
1020     }
1021    
1022     // Port changed in combo
1023     static void cb_serial_port_changed(...)
1024     {
1025     printf("serial port changed\n");
1026     set_serial_sensitive();
1027     }
1028    
1029     // Add names of serial devices
1030     static GList *add_serial_names(void)
1031     {
1032     GList *glist = NULL;
1033    
1034     static const char *port_names[] = {
1035     "COM1", "COM2", "COM3", "COM4", "COM5", "COM6",
1036     "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6",
1037     "FILE",
1038     NULL
1039     };
1040    
1041     for (int i = 0; port_names[i] != NULL; i++)
1042     glist = g_list_append(glist, (void *)port_names[i]);
1043    
1044     return glist;
1045     }
1046    
1047     // Create "Ports" pane
1048     static void create_serial_pane(GtkWidget *top)
1049     {
1050     GtkWidget *box, *hbox, *table, *label, *combo, *sep, *entry;
1051     GtkObject *adj;
1052    
1053     box = make_pane(top, STR_SERIAL_PANE_TITLE);
1054     table = make_table(box, 2, 5);
1055    
1056     label = gtk_label_new(GetString(STR_SERIALA_CTRL));
1057     gtk_widget_show(label);
1058     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1059    
1060     GList *glist = add_serial_names();
1061     combo = gtk_combo_new();
1062     gtk_widget_show(combo);
1063     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1064     const char *str = PrefsFindString("seriala");
1065     if (str == NULL)
1066     str = "";
1067     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1068     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1069     w_seriala = GTK_COMBO(combo)->entry;
1070     gtk_signal_connect(GTK_OBJECT(w_seriala), "changed", GTK_SIGNAL_FUNC(cb_serial_port_changed), NULL);
1071    
1072     label = gtk_label_new(GetString(STR_FILE_CTRL));
1073     gtk_widget_show(label);
1074     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1075    
1076     hbox = gtk_hbox_new(FALSE, 4);
1077     gtk_widget_show(hbox);
1078     gtk_table_attach(GTK_TABLE(table), hbox, 1, 2, 1, 2, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1079    
1080     w_portfile0 = gtk_entry_new();
1081     str = PrefsFindString("portfile0");
1082     if (str == NULL)
1083     str = "C:\\B2TEMP0.OUT";
1084     gtk_entry_set_text(GTK_ENTRY(w_portfile0), str);
1085     gtk_widget_show(w_portfile0);
1086     gtk_box_pack_start(GTK_BOX(hbox), w_portfile0, TRUE, TRUE, 0);
1087    
1088     w_portfile0_browse = make_browse_button(w_portfile0);
1089     gtk_box_pack_start(GTK_BOX(hbox), w_portfile0_browse, FALSE, FALSE, 0);
1090    
1091     sep = gtk_hseparator_new();
1092     gtk_widget_show(sep);
1093     gtk_table_attach(GTK_TABLE(table), sep, 0, 2, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1094    
1095     label = gtk_label_new(GetString(STR_SERIALB_CTRL));
1096     gtk_widget_show(label);
1097     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1098    
1099     combo = gtk_combo_new();
1100     gtk_widget_show(combo);
1101     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1102     str = PrefsFindString("serialb");
1103     if (str == NULL)
1104     str = "";
1105     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1106     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1107     w_serialb = GTK_COMBO(combo)->entry;
1108     gtk_signal_connect(GTK_OBJECT(w_serialb), "changed", GTK_SIGNAL_FUNC(cb_serial_port_changed), NULL);
1109    
1110     label = gtk_label_new(GetString(STR_FILE_CTRL));
1111     gtk_widget_show(label);
1112     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1113    
1114     hbox = gtk_hbox_new(FALSE, 4);
1115     gtk_widget_show(hbox);
1116     gtk_table_attach(GTK_TABLE(table), hbox, 1, 2, 4, 5, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1117    
1118     w_portfile1 = gtk_entry_new();
1119     str = PrefsFindString("portfile1");
1120     if (str == NULL)
1121     str = "C:\\B2TEMP1.OUT";
1122     gtk_entry_set_text(GTK_ENTRY(w_portfile1), str);
1123     gtk_widget_show(w_portfile1);
1124     gtk_box_pack_start(GTK_BOX(hbox), w_portfile1, TRUE, TRUE, 0);
1125    
1126     w_portfile1_browse = make_browse_button(w_portfile1);
1127     gtk_box_pack_start(GTK_BOX(hbox), w_portfile1_browse, FALSE, FALSE, 0);
1128    
1129     set_serial_sensitive();
1130     }
1131    
1132    
1133     /*
1134     * "Ethernet" pane
1135     */
1136    
1137     static GtkWidget *w_ether, *w_udp_port;
1138    
1139     // Set sensitivity of widgets
1140     static void set_ethernet_sensitive(void)
1141     {
1142     }
1143    
1144     // Read settings from widgets and set preferences
1145     static void read_ethernet_settings(void)
1146     {
1147     const char *str = gtk_entry_get_text(GTK_ENTRY(w_ether));
1148     if (str && strlen(str))
1149     PrefsReplaceString("ether", str);
1150     else
1151     PrefsRemoveItem("ether");
1152     }
1153    
1154     // Add names of ethernet interfaces
1155     static GList *add_ether_names(void)
1156     {
1157     GList *glist = NULL;
1158    
1159     // TODO: Get list of all Ethernet interfaces
1160     #ifdef HAVE_SLIRP
1161     static char s_slirp[] = "slirp";
1162     glist = g_list_append(glist, s_slirp);
1163     #endif
1164     #if 0
1165     if (glist)
1166     g_list_sort(glist, gl_str_cmp);
1167     else
1168     #endif
1169     glist = g_list_append(glist, (void *)GetString(STR_NONE_LAB));
1170     return glist;
1171     }
1172    
1173    
1174     // Create "Ethernet" pane
1175     static void create_ethernet_pane(GtkWidget *top)
1176     {
1177     GtkWidget *box, *hbox, *table, *label, *combo, *sep, *entry;
1178    
1179     box = make_pane(top, STR_NETWORK_PANE_TITLE);
1180     table = make_table(box, 2, 5);
1181    
1182     label = gtk_label_new(GetString(STR_ETHERNET_IF_CTRL));
1183     gtk_widget_show(label);
1184     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1185    
1186     GList *glist = add_ether_names();
1187     combo = gtk_combo_new();
1188     gtk_widget_show(combo);
1189     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1190     const char *str = PrefsFindString("ether");
1191     if (str == NULL)
1192     str = "";
1193     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1194     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1195     w_ether = GTK_COMBO(combo)->entry;
1196    
1197     set_ethernet_sensitive();
1198     }
1199    
1200    
1201     /*
1202     * "Memory/Misc" pane
1203     */
1204    
1205     static GtkObject *w_ramsize_adj;
1206     static GtkWidget *w_rom_file;
1207    
1208     // "Ignore SEGV" button toggled
1209     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1210     static void tb_ignoresegv(GtkWidget *widget)
1211     {
1212     PrefsReplaceBool("ignoresegv", GTK_TOGGLE_BUTTON(widget)->active);
1213     }
1214     #endif
1215    
1216     // Model ID selected
1217     static void mn_modelid_5(...) {PrefsReplaceInt32("modelid", 5);}
1218     static void mn_modelid_14(...) {PrefsReplaceInt32("modelid", 14);}
1219    
1220     // CPU/FPU type
1221     static void mn_cpu_68020(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", false);}
1222     static void mn_cpu_68020_fpu(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", true);}
1223     static void mn_cpu_68030(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", false);}
1224     static void mn_cpu_68030_fpu(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", true);}
1225     static void mn_cpu_68040(...) {PrefsReplaceInt32("cpu", 4); PrefsReplaceBool("fpu", true);}
1226    
1227     // Read settings from widgets and set preferences
1228     static void read_memory_settings(void)
1229     {
1230     PrefsReplaceInt32("ramsize", int(GTK_ADJUSTMENT(w_ramsize_adj)->value) << 20);
1231    
1232     const char *str = get_file_entry_path(w_rom_file);
1233     if (str && strlen(str))
1234     PrefsReplaceString("rom", str);
1235     else
1236     PrefsRemoveItem("rom");
1237    
1238     }
1239    
1240     // Create "Memory/Misc" pane
1241     static void create_memory_pane(GtkWidget *top)
1242     {
1243     GtkWidget *box, *hbox, *vbox, *hbox2, *label, *scale;
1244    
1245     box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE);
1246    
1247     hbox = gtk_hbox_new(FALSE, 4);
1248     gtk_widget_show(hbox);
1249    
1250     label = gtk_label_new(GetString(STR_RAMSIZE_SLIDER));
1251     gtk_widget_show(label);
1252     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1253    
1254     vbox = gtk_vbox_new(FALSE, 4);
1255     gtk_widget_show(vbox);
1256    
1257     gfloat min, max;
1258     min = 1;
1259     max = 1024;
1260     w_ramsize_adj = gtk_adjustment_new(min, min, max, 1, 16, 0);
1261     gtk_adjustment_set_value(GTK_ADJUSTMENT(w_ramsize_adj), PrefsFindInt32("ramsize") >> 20);
1262    
1263     scale = gtk_hscale_new(GTK_ADJUSTMENT(w_ramsize_adj));
1264     gtk_widget_show(scale);
1265     gtk_scale_set_digits(GTK_SCALE(scale), 0);
1266     gtk_box_pack_start(GTK_BOX(vbox), scale, TRUE, TRUE, 0);
1267    
1268     hbox2 = gtk_hbox_new(FALSE, 4);
1269     gtk_widget_show(hbox2);
1270    
1271     char val[32];
1272     sprintf(val, GetString(STR_RAMSIZE_FMT), int(min));
1273     label = gtk_label_new(val);
1274     gtk_widget_show(label);
1275     gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
1276    
1277     sprintf(val, GetString(STR_RAMSIZE_FMT), int(max));
1278     label = gtk_label_new(val);
1279     gtk_widget_show(label);
1280     gtk_box_pack_end(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
1281     gtk_box_pack_start(GTK_BOX(vbox), hbox2, TRUE, TRUE, 0);
1282     gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
1283     gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1284    
1285     static const opt_desc model_options[] = {
1286     {STR_MODELID_5_LAB, GTK_SIGNAL_FUNC(mn_modelid_5)},
1287     {STR_MODELID_14_LAB, GTK_SIGNAL_FUNC(mn_modelid_14)},
1288     {0, NULL}
1289     };
1290     int modelid = PrefsFindInt32("modelid"), active = 0;
1291     switch (modelid) {
1292     case 5: active = 0; break;
1293     case 14: active = 1; break;
1294     }
1295     make_option_menu(box, STR_MODELID_CTRL, model_options, active);
1296    
1297     #if EMULATED_68K
1298     static const opt_desc cpu_options[] = {
1299     {STR_CPU_68020_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020)},
1300     {STR_CPU_68020_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020_fpu)},
1301     {STR_CPU_68030_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030)},
1302     {STR_CPU_68030_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030_fpu)},
1303     {STR_CPU_68040_LAB, GTK_SIGNAL_FUNC(mn_cpu_68040)},
1304     {0, NULL}
1305     };
1306     int cpu = PrefsFindInt32("cpu");
1307     bool fpu = PrefsFindBool("fpu");
1308     active = 0;
1309     switch (cpu) {
1310     case 2: active = fpu ? 1 : 0; break;
1311     case 3: active = fpu ? 3 : 2; break;
1312     case 4: active = 4;
1313     }
1314     make_option_menu(box, STR_CPU_CTRL, cpu_options, active);
1315     #endif
1316    
1317     w_rom_file = make_file_entry(box, STR_ROM_FILE_CTRL, "rom");
1318    
1319     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1320     make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv));
1321     #endif
1322     }
1323    
1324    
1325     /*
1326     * Read settings from widgets and set preferences
1327     */
1328    
1329     static void read_settings(void)
1330     {
1331     read_volumes_settings();
1332     read_scsi_settings();
1333     read_graphics_settings();
1334     read_input_settings();
1335     read_serial_settings();
1336     read_ethernet_settings();
1337     read_memory_settings();
1338     read_jit_settings();
1339     }
1340    
1341    
1342     /*
1343     * Fake unused data and functions
1344     */
1345    
1346     uint8 XPRAM[XPRAM_SIZE];
1347     void MountVolume(void *fh) { }
1348     void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) { }
1349     void WarningAlert(const char *text) { }
1350    
1351    
1352     /*
1353     * Add default serial prefs (must be added, even if no ports present)
1354     */
1355    
1356     void SysAddSerialPrefs(void)
1357     {
1358     PrefsAddString("seriala", "COM1");
1359     PrefsAddString("serialb", "COM2");
1360     }
1361    
1362    
1363     /*
1364     * Start standalone GUI
1365     */
1366    
1367     int main(int argc, char *argv[])
1368     {
1369     // Init GTK
1370     gtk_set_locale();
1371     gtk_init(&argc, &argv);
1372    
1373     // Read preferences
1374     PrefsInit(argc, argv);
1375    
1376     // Show preferences editor
1377     bool start = PrefsEditor();
1378    
1379     // Exit preferences
1380     PrefsExit();
1381    
1382     // Transfer control to the Basilisk II executable
1383     if (start) {
1384     printf("Start Basilisk II\n");
1385     }
1386    
1387     return 0;
1388     }