ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/prefs_editor_gtk.cpp
Revision: 1.5
Committed: 2005-11-20T23:47:42Z (18 years, 7 months ago) by gbeauche
Branch: MAIN
Changes since 1.4: +102 -17 lines
Log Message:
Windows GUI: disable SCSI settings for now since they are not merged yet,
handle Ethernet (NAT/Router module, None) and actually execute BasiliskII.exe

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