ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/prefs_editor_gtk.cpp
Revision: 1.7
Committed: 2005-11-22T22:57:30Z (18 years, 7 months ago) by gbeauche
Branch: MAIN
Changes since 1.6: +1 -0 lines
Log Message:
Windows GUI: set "frameskip" to 1 when switching to fullscreen mode

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 gbeauche 1.6 {(gchar *)GetString(STR_PREFS_ITEM_START_GTK), "<control>S", GTK_SIGNAL_FUNC(cb_start), 0, NULL},
428 gbeauche 1.1 {(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 gbeauche 1.6 {(gchar *)GetString(STR_HELP_ITEM_ABOUT_GTK), "<control>H", GTK_SIGNAL_FUNC(cb_about), 0, NULL}
433 gbeauche 1.1 };
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_QUIT_BUTTON, GTK_SIGNAL_FUNC(cb_quit)},
478     {0, NULL}
479     };
480     make_button_box(box, 4, buttons);
481    
482     // Show window and enter main loop
483     gtk_widget_show(win);
484     gtk_main();
485     return start_clicked;
486     }
487    
488    
489     /*
490     * "Volumes" pane
491     */
492    
493 gbeauche 1.4 static GtkWidget *w_enableextfs, *w_extdrives;
494 gbeauche 1.1 static GtkWidget *volume_list;
495     static int selected_volume;
496    
497 gbeauche 1.4 // Set sensitivity of widgets
498     static void set_volumes_sensitive(void)
499     {
500     const bool enable_extfs = PrefsFindBool("enableextfs");
501     gtk_widget_set_sensitive(w_extdrives, enable_extfs);
502     }
503    
504 gbeauche 1.1 // Volume in list selected
505     static void cl_selected(GtkWidget *list, int row, int column)
506     {
507     selected_volume = row;
508     }
509    
510     // Volume selected for addition
511     static void add_volume_ok(GtkWidget *button, file_req_assoc *assoc)
512     {
513     gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
514     gtk_clist_append(GTK_CLIST(volume_list), &file);
515     gtk_widget_destroy(assoc->req);
516     delete assoc;
517     }
518    
519     // Volume selected for creation
520     static void create_volume_ok(GtkWidget *button, file_req_assoc *assoc)
521     {
522     gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
523    
524     const gchar *str = gtk_entry_get_text(GTK_ENTRY(assoc->entry));
525 gbeauche 1.4 size_t size = atoi(str) << 20;
526 gbeauche 1.1
527 gbeauche 1.4 int fd = _open(file, _O_WRONLY | _O_CREAT | _O_BINARY | _O_TRUNC, _S_IREAD | _S_IWRITE);
528     if (fd >= 0) {
529     if (_chsize(fd, size) == 0)
530 gbeauche 1.1 gtk_clist_append(GTK_CLIST(volume_list), &file);
531 gbeauche 1.4 _close(fd);
532     }
533 gbeauche 1.1 gtk_widget_destroy(GTK_WIDGET(assoc->req));
534     delete assoc;
535     }
536    
537     // "Add Volume" button clicked
538     static void cb_add_volume(...)
539     {
540     GtkWidget *req = gtk_file_selection_new(GetString(STR_ADD_VOLUME_TITLE));
541     gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
542     gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(add_volume_ok), new file_req_assoc(req, NULL));
543     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
544     gtk_widget_show(req);
545     }
546    
547     // "Create Hardfile" button clicked
548     static void cb_create_volume(...)
549     {
550     GtkWidget *req = gtk_file_selection_new(GetString(STR_CREATE_VOLUME_TITLE));
551    
552     GtkWidget *box = gtk_hbox_new(FALSE, 4);
553     gtk_widget_show(box);
554     GtkWidget *label = gtk_label_new(GetString(STR_HARDFILE_SIZE_CTRL));
555     gtk_widget_show(label);
556     GtkWidget *entry = gtk_entry_new();
557     gtk_widget_show(entry);
558     char str[32];
559     sprintf(str, "%d", 40);
560     gtk_entry_set_text(GTK_ENTRY(entry), str);
561     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
562     gtk_box_pack_start(GTK_BOX(box), entry, FALSE, FALSE, 0);
563     gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(req)->main_vbox), box, FALSE, FALSE, 0);
564    
565     gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
566     gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(create_volume_ok), new file_req_assoc(req, entry));
567     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
568     gtk_widget_show(req);
569     }
570    
571     // "Remove Volume" button clicked
572     static void cb_remove_volume(...)
573     {
574     gtk_clist_remove(GTK_CLIST(volume_list), selected_volume);
575     }
576    
577     // "Boot From" selected
578     static void mn_boot_any(...) {PrefsReplaceInt32("bootdriver", 0);}
579     static void mn_boot_cdrom(...) {PrefsReplaceInt32("bootdriver", CDROMRefNum);}
580    
581 gbeauche 1.4 // "Enable external file system" button toggled
582     static void tb_enableextfs(GtkWidget *widget)
583     {
584     PrefsReplaceBool("enableextfs", GTK_TOGGLE_BUTTON(widget)->active);
585     set_volumes_sensitive();
586     }
587    
588 gbeauche 1.1 // "No CD-ROM Driver" button toggled
589     static void tb_nocdrom(GtkWidget *widget)
590     {
591     PrefsReplaceBool("nocdrom", GTK_TOGGLE_BUTTON(widget)->active);
592     }
593    
594 gbeauche 1.4 // "Enable polling" button toggled
595     static void tb_pollmedia(GtkWidget *widget)
596     {
597     PrefsReplaceBool("pollmedia", GTK_TOGGLE_BUTTON(widget)->active);
598     }
599    
600 gbeauche 1.1 // Read settings from widgets and set preferences
601     static void read_volumes_settings(void)
602     {
603     while (PrefsFindString("disk"))
604     PrefsRemoveItem("disk");
605    
606     for (int i=0; i<GTK_CLIST(volume_list)->rows; i++) {
607     char *str;
608     gtk_clist_get_text(GTK_CLIST(volume_list), i, 0, &str);
609     PrefsAddString("disk", str);
610     }
611 gbeauche 1.4
612     PrefsReplaceString("extdrives", get_file_entry_path(w_extdrives));
613 gbeauche 1.1 }
614    
615     // Create "Volumes" pane
616     static void create_volumes_pane(GtkWidget *top)
617     {
618     GtkWidget *box, *scroll, *menu;
619    
620     box = make_pane(top, STR_VOLUMES_PANE_TITLE);
621    
622     scroll = gtk_scrolled_window_new(NULL, NULL);
623     gtk_widget_show(scroll);
624     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
625     volume_list = gtk_clist_new(1);
626     gtk_widget_show(volume_list);
627     gtk_clist_set_selection_mode(GTK_CLIST(volume_list), GTK_SELECTION_SINGLE);
628     gtk_clist_set_shadow_type(GTK_CLIST(volume_list), GTK_SHADOW_NONE);
629     gtk_clist_set_reorderable(GTK_CLIST(volume_list), true);
630     gtk_signal_connect(GTK_OBJECT(volume_list), "select_row", GTK_SIGNAL_FUNC(cl_selected), NULL);
631     char *str;
632     int32 index = 0;
633     while ((str = const_cast<char *>(PrefsFindString("disk", index++))) != NULL)
634     gtk_clist_append(GTK_CLIST(volume_list), &str);
635     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), volume_list);
636     gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 0);
637     selected_volume = 0;
638    
639     static const opt_desc buttons[] = {
640     {STR_ADD_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_add_volume)},
641     {STR_CREATE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_create_volume)},
642     {STR_REMOVE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_remove_volume)},
643     {0, NULL},
644     };
645     make_button_box(box, 0, buttons);
646     make_separator(box);
647    
648     static const opt_desc options[] = {
649     {STR_BOOT_ANY_LAB, GTK_SIGNAL_FUNC(mn_boot_any)},
650     {STR_BOOT_CDROM_LAB, GTK_SIGNAL_FUNC(mn_boot_cdrom)},
651     {0, NULL}
652     };
653     int bootdriver = PrefsFindInt32("bootdriver"), active = 0;
654     switch (bootdriver) {
655     case 0: active = 0; break;
656     case CDROMRefNum: active = 1; break;
657     }
658     menu = make_option_menu(box, STR_BOOTDRIVER_CTRL, options, active);
659    
660     make_checkbox(box, STR_NOCDROM_CTRL, "nocdrom", GTK_SIGNAL_FUNC(tb_nocdrom));
661 gbeauche 1.4
662     make_checkbox(box, STR_POLLMEDIA_CTRL, "pollmedia", GTK_SIGNAL_FUNC(tb_pollmedia));
663    
664     make_separator(box);
665     w_enableextfs = make_checkbox(box, STR_EXTFS_ENABLE_CTRL, "enableextfs", GTK_SIGNAL_FUNC(tb_enableextfs));
666     w_extdrives = make_file_entry(box, STR_EXTFS_DRIVES_CTRL, "extdrives", true);
667    
668     set_volumes_sensitive();
669 gbeauche 1.1 }
670    
671    
672     /*
673     * "JIT Compiler" pane
674     */
675    
676     static GtkWidget *w_jit_fpu;
677     static GtkWidget *w_jit_atraps;
678     static GtkWidget *w_jit_cache_size;
679     static GtkWidget *w_jit_lazy_flush;
680     static GtkWidget *w_jit_follow_const_jumps;
681    
682     // Set sensitivity of widgets
683     static void set_jit_sensitive(void)
684     {
685     const bool jit_enabled = PrefsFindBool("jit");
686     gtk_widget_set_sensitive(w_jit_fpu, jit_enabled);
687     gtk_widget_set_sensitive(w_jit_cache_size, jit_enabled);
688     gtk_widget_set_sensitive(w_jit_lazy_flush, jit_enabled);
689     gtk_widget_set_sensitive(w_jit_follow_const_jumps, jit_enabled);
690     }
691    
692     // "Use JIT Compiler" button toggled
693     static void tb_jit(GtkWidget *widget)
694     {
695     PrefsReplaceBool("jit", GTK_TOGGLE_BUTTON(widget)->active);
696     set_jit_sensitive();
697     }
698    
699     // "Compile FPU Instructions" button toggled
700     static void tb_jit_fpu(GtkWidget *widget)
701     {
702     PrefsReplaceBool("jitfpu", GTK_TOGGLE_BUTTON(widget)->active);
703     }
704    
705     // "Lazy translation cache invalidation" button toggled
706     static void tb_jit_lazy_flush(GtkWidget *widget)
707     {
708     PrefsReplaceBool("jitlazyflush", GTK_TOGGLE_BUTTON(widget)->active);
709     }
710    
711     // "Translate through constant jumps (inline blocks)" button toggled
712     static void tb_jit_follow_const_jumps(GtkWidget *widget)
713     {
714     PrefsReplaceBool("jitinline", GTK_TOGGLE_BUTTON(widget)->active);
715     }
716    
717     // Read settings from widgets and set preferences
718     static void read_jit_settings(void)
719     {
720     #if USE_JIT
721     bool jit_enabled = PrefsFindBool("jit");
722     if (jit_enabled) {
723     const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_jit_cache_size)->entry));
724     PrefsReplaceInt32("jitcachesize", atoi(str));
725     }
726     #endif
727     }
728    
729     // Create "JIT Compiler" pane
730     static void create_jit_pane(GtkWidget *top)
731     {
732     #if USE_JIT
733     GtkWidget *box, *table, *label, *menu;
734     char str[32];
735    
736     box = make_pane(top, STR_JIT_PANE_TITLE);
737     make_checkbox(box, STR_JIT_CTRL, "jit", GTK_SIGNAL_FUNC(tb_jit));
738    
739     w_jit_fpu = make_checkbox(box, STR_JIT_FPU_CTRL, "jitfpu", GTK_SIGNAL_FUNC(tb_jit_fpu));
740    
741     // Translation cache size
742     static const combo_desc options[] = {
743     STR_JIT_CACHE_SIZE_2MB_LAB,
744     STR_JIT_CACHE_SIZE_4MB_LAB,
745     STR_JIT_CACHE_SIZE_8MB_LAB,
746     STR_JIT_CACHE_SIZE_16MB_LAB,
747     0
748     };
749     w_jit_cache_size = make_combobox(box, STR_JIT_CACHE_SIZE_CTRL, "jitcachesize", options);
750    
751     // Lazy translation cache invalidation
752     w_jit_lazy_flush = make_checkbox(box, STR_JIT_LAZY_CINV_CTRL, "jitlazyflush", GTK_SIGNAL_FUNC(tb_jit_lazy_flush));
753    
754     // Follow constant jumps (inline basic blocks)
755     w_jit_follow_const_jumps = make_checkbox(box, STR_JIT_FOLLOW_CONST_JUMPS, "jitinline", GTK_SIGNAL_FUNC(tb_jit_follow_const_jumps));
756    
757     set_jit_sensitive();
758     #endif
759     }
760    
761     /*
762     * "SCSI" pane
763     */
764    
765     static GtkWidget *w_scsi[7];
766    
767     // Read settings from widgets and set preferences
768     static void read_scsi_settings(void)
769     {
770     for (int id=0; id<7; id++) {
771     char prefs_name[32];
772     sprintf(prefs_name, "scsi%d", id);
773     const char *str = get_file_entry_path(w_scsi[id]);
774     if (str && strlen(str))
775     PrefsReplaceString(prefs_name, str);
776     else
777     PrefsRemoveItem(prefs_name);
778     }
779     }
780    
781     // Create "SCSI" pane
782     static void create_scsi_pane(GtkWidget *top)
783     {
784     GtkWidget *box;
785    
786     box = make_pane(top, STR_SCSI_PANE_TITLE);
787    
788     for (int id=0; id<7; id++) {
789     char prefs_name[32];
790     sprintf(prefs_name, "scsi%d", id);
791     w_scsi[id] = make_file_entry(box, STR_SCSI_ID_0 + id, prefs_name);
792     }
793     }
794    
795    
796     /*
797     * "Graphics/Sound" pane
798     */
799    
800     // Display types
801     enum {
802     DISPLAY_WINDOW,
803     DISPLAY_SCREEN
804     };
805    
806     static GtkWidget *w_frameskip, *w_display_x, *w_display_y;
807     static GtkWidget *l_frameskip, *l_display_x, *l_display_y;
808     static int display_type;
809     static int dis_width, dis_height;
810    
811     // Hide/show graphics widgets
812     static void hide_show_graphics_widgets(void)
813     {
814     switch (display_type) {
815     case DISPLAY_WINDOW:
816     gtk_widget_show(w_frameskip); gtk_widget_show(l_frameskip);
817     break;
818     case DISPLAY_SCREEN:
819     gtk_widget_hide(w_frameskip); gtk_widget_hide(l_frameskip);
820     break;
821     }
822     }
823    
824     // "Window" video type selected
825     static void mn_window(...)
826     {
827     display_type = DISPLAY_WINDOW;
828     hide_show_graphics_widgets();
829     }
830    
831     // "Fullscreen" video type selected
832     static void mn_fullscreen(...)
833     {
834     display_type = DISPLAY_SCREEN;
835     hide_show_graphics_widgets();
836 gbeauche 1.7 PrefsReplaceInt32("frameskip", 1);
837 gbeauche 1.1 }
838    
839     // "5 Hz".."60Hz" selected
840     static void mn_5hz(...) {PrefsReplaceInt32("frameskip", 12);}
841     static void mn_7hz(...) {PrefsReplaceInt32("frameskip", 8);}
842     static void mn_10hz(...) {PrefsReplaceInt32("frameskip", 6);}
843     static void mn_15hz(...) {PrefsReplaceInt32("frameskip", 4);}
844     static void mn_30hz(...) {PrefsReplaceInt32("frameskip", 2);}
845     static void mn_60hz(...) {PrefsReplaceInt32("frameskip", 1);}
846     static void mn_dynamic(...) {PrefsReplaceInt32("frameskip", 0);}
847    
848     // Set sensitivity of widgets
849     static void set_graphics_sensitive(void)
850     {
851     const bool sound_enabled = !PrefsFindBool("nosound");
852     }
853    
854     // "Disable Sound Output" button toggled
855     static void tb_nosound(GtkWidget *widget)
856     {
857     PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active);
858     set_graphics_sensitive();
859     }
860    
861     // Read graphics preferences
862     static void parse_graphics_prefs(void)
863     {
864     display_type = DISPLAY_WINDOW;
865     dis_width = 512;
866     dis_height = 384;
867    
868     const char *str = PrefsFindString("screen");
869     if (str) {
870     if (sscanf(str, "win/%d/%d", &dis_width, &dis_height) == 2)
871     display_type = DISPLAY_WINDOW;
872     else if (sscanf(str, "dga/%d/%d", &dis_width, &dis_height) == 2)
873     display_type = DISPLAY_SCREEN;
874     }
875     }
876    
877     // Read settings from widgets and set preferences
878     static void read_graphics_settings(void)
879     {
880     const char *str;
881    
882     str = gtk_entry_get_text(GTK_ENTRY(w_display_x));
883     dis_width = atoi(str);
884    
885     str = gtk_entry_get_text(GTK_ENTRY(w_display_y));
886     dis_height = atoi(str);
887    
888     char pref[256];
889     switch (display_type) {
890     case DISPLAY_WINDOW:
891     sprintf(pref, "win/%d/%d", dis_width, dis_height);
892     break;
893     case DISPLAY_SCREEN:
894     sprintf(pref, "dga/%d/%d", dis_width, dis_height);
895     break;
896     default:
897     PrefsRemoveItem("screen");
898     return;
899     }
900     PrefsReplaceString("screen", pref);
901     }
902    
903     // Create "Graphics/Sound" pane
904     static void create_graphics_pane(GtkWidget *top)
905     {
906     GtkWidget *box, *table, *label, *opt, *menu, *combo;
907     char str[32];
908    
909     parse_graphics_prefs();
910    
911     box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE);
912     table = make_table(box, 2, 5);
913    
914     label = gtk_label_new(GetString(STR_VIDEO_TYPE_CTRL));
915     gtk_widget_show(label);
916     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
917    
918     opt = gtk_option_menu_new();
919     gtk_widget_show(opt);
920     menu = gtk_menu_new();
921     add_menu_item(menu, STR_WINDOW_LAB, GTK_SIGNAL_FUNC(mn_window));
922     add_menu_item(menu, STR_FULLSCREEN_LAB, GTK_SIGNAL_FUNC(mn_fullscreen));
923     switch (display_type) {
924     case DISPLAY_WINDOW:
925     gtk_menu_set_active(GTK_MENU(menu), 0);
926     break;
927     case DISPLAY_SCREEN:
928     gtk_menu_set_active(GTK_MENU(menu), 1);
929     break;
930     }
931     gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
932     gtk_table_attach(GTK_TABLE(table), opt, 1, 2, 0, 1, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
933    
934     l_frameskip = gtk_label_new(GetString(STR_FRAMESKIP_CTRL));
935     gtk_widget_show(l_frameskip);
936     gtk_table_attach(GTK_TABLE(table), l_frameskip, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
937    
938     w_frameskip = gtk_option_menu_new();
939     gtk_widget_show(w_frameskip);
940     menu = gtk_menu_new();
941     add_menu_item(menu, STR_REF_5HZ_LAB, GTK_SIGNAL_FUNC(mn_5hz));
942     add_menu_item(menu, STR_REF_7_5HZ_LAB, GTK_SIGNAL_FUNC(mn_7hz));
943     add_menu_item(menu, STR_REF_10HZ_LAB, GTK_SIGNAL_FUNC(mn_10hz));
944     add_menu_item(menu, STR_REF_15HZ_LAB, GTK_SIGNAL_FUNC(mn_15hz));
945     add_menu_item(menu, STR_REF_30HZ_LAB, GTK_SIGNAL_FUNC(mn_30hz));
946     add_menu_item(menu, STR_REF_60HZ_LAB, GTK_SIGNAL_FUNC(mn_60hz));
947     add_menu_item(menu, STR_REF_DYNAMIC_LAB, GTK_SIGNAL_FUNC(mn_dynamic));
948     int frameskip = PrefsFindInt32("frameskip");
949     int item = -1;
950     switch (frameskip) {
951     case 12: item = 0; break;
952     case 8: item = 1; break;
953     case 6: item = 2; break;
954     case 4: item = 3; break;
955     case 2: item = 4; break;
956     case 1: item = 5; break;
957     case 0: item = 6; break;
958     }
959     if (item >= 0)
960     gtk_menu_set_active(GTK_MENU(menu), item);
961     gtk_option_menu_set_menu(GTK_OPTION_MENU(w_frameskip), menu);
962     gtk_table_attach(GTK_TABLE(table), w_frameskip, 1, 2, 1, 2, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
963    
964     l_display_x = gtk_label_new(GetString(STR_DISPLAY_X_CTRL));
965     gtk_widget_show(l_display_x);
966     gtk_table_attach(GTK_TABLE(table), l_display_x, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
967    
968     combo = gtk_combo_new();
969     gtk_widget_show(combo);
970     GList *glist1 = NULL;
971     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_512_LAB));
972     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_640_LAB));
973     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_800_LAB));
974     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_1024_LAB));
975     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_MAX_LAB));
976     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist1);
977     if (dis_width)
978     sprintf(str, "%d", dis_width);
979     else
980     strcpy(str, GetString(STR_SIZE_MAX_LAB));
981     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
982     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
983     w_display_x = GTK_COMBO(combo)->entry;
984    
985     l_display_y = gtk_label_new(GetString(STR_DISPLAY_Y_CTRL));
986     gtk_widget_show(l_display_y);
987     gtk_table_attach(GTK_TABLE(table), l_display_y, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
988    
989     combo = gtk_combo_new();
990     gtk_widget_show(combo);
991     GList *glist2 = NULL;
992     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_384_LAB));
993     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_480_LAB));
994     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_600_LAB));
995     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_768_LAB));
996     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_MAX_LAB));
997     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist2);
998     if (dis_height)
999     sprintf(str, "%d", dis_height);
1000     else
1001     strcpy(str, GetString(STR_SIZE_MAX_LAB));
1002     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1003     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
1004     w_display_y = GTK_COMBO(combo)->entry;
1005    
1006     make_separator(box);
1007     make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound));
1008    
1009     set_graphics_sensitive();
1010    
1011     hide_show_graphics_widgets();
1012     }
1013    
1014    
1015     /*
1016     * "Input" pane
1017     */
1018    
1019     static GtkWidget *w_keycode_file;
1020     static GtkWidget *w_mouse_wheel_lines;
1021    
1022     // Set sensitivity of widgets
1023     static void set_input_sensitive(void)
1024     {
1025 gbeauche 1.4 const bool use_keycodes = PrefsFindBool("keycodes");
1026     gtk_widget_set_sensitive(w_keycode_file, use_keycodes);
1027     gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_keycode_file), "chooser_button")), use_keycodes);
1028 gbeauche 1.1 gtk_widget_set_sensitive(w_mouse_wheel_lines, PrefsFindInt32("mousewheelmode") == 1);
1029     }
1030    
1031     // "Use Raw Keycodes" button toggled
1032     static void tb_keycodes(GtkWidget *widget)
1033     {
1034     PrefsReplaceBool("keycodes", GTK_TOGGLE_BUTTON(widget)->active);
1035     set_input_sensitive();
1036     }
1037    
1038     // "Mouse Wheel Mode" selected
1039     static void mn_wheel_page(...) {PrefsReplaceInt32("mousewheelmode", 0); set_input_sensitive();}
1040     static void mn_wheel_cursor(...) {PrefsReplaceInt32("mousewheelmode", 1); set_input_sensitive();}
1041    
1042     // Read settings from widgets and set preferences
1043     static void read_input_settings(void)
1044     {
1045     const char *str = get_file_entry_path(w_keycode_file);
1046     if (str && strlen(str))
1047     PrefsReplaceString("keycodefile", str);
1048     else
1049     PrefsRemoveItem("keycodefile");
1050    
1051     PrefsReplaceInt32("mousewheellines", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_mouse_wheel_lines)));
1052     }
1053    
1054     // Create "Input" pane
1055     static void create_input_pane(GtkWidget *top)
1056     {
1057 gbeauche 1.4 GtkWidget *box, *hbox, *menu, *label, *button;
1058 gbeauche 1.1 GtkObject *adj;
1059    
1060     box = make_pane(top, STR_INPUT_PANE_TITLE);
1061    
1062     make_checkbox(box, STR_KEYCODES_CTRL, "keycodes", GTK_SIGNAL_FUNC(tb_keycodes));
1063 gbeauche 1.4
1064     hbox = gtk_hbox_new(FALSE, 4);
1065     gtk_widget_show(hbox);
1066     gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1067    
1068     label = gtk_label_new(GetString(STR_KEYCODES_CTRL));
1069     gtk_widget_show(label);
1070     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1071    
1072     const char *str = PrefsFindString("keycodefile");
1073     if (str == NULL)
1074     str = "";
1075    
1076     w_keycode_file = gtk_entry_new();
1077     gtk_entry_set_text(GTK_ENTRY(w_keycode_file), str);
1078     gtk_widget_show(w_keycode_file);
1079     gtk_box_pack_start(GTK_BOX(hbox), w_keycode_file, TRUE, TRUE, 0);
1080    
1081     button = make_browse_button(w_keycode_file);
1082     gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1083     g_object_set_data(G_OBJECT(w_keycode_file), "chooser_button", button);
1084 gbeauche 1.1
1085     make_separator(box);
1086    
1087     static const opt_desc options[] = {
1088     {STR_MOUSEWHEELMODE_PAGE_LAB, GTK_SIGNAL_FUNC(mn_wheel_page)},
1089     {STR_MOUSEWHEELMODE_CURSOR_LAB, GTK_SIGNAL_FUNC(mn_wheel_cursor)},
1090     {0, NULL}
1091     };
1092     int wheelmode = PrefsFindInt32("mousewheelmode"), active = 0;
1093     switch (wheelmode) {
1094     case 0: active = 0; break;
1095     case 1: active = 1; break;
1096     }
1097     menu = make_option_menu(box, STR_MOUSEWHEELMODE_CTRL, options, active);
1098    
1099     hbox = gtk_hbox_new(FALSE, 4);
1100     gtk_widget_show(hbox);
1101     gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1102    
1103     label = gtk_label_new(GetString(STR_MOUSEWHEELLINES_CTRL));
1104     gtk_widget_show(label);
1105     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1106    
1107     adj = gtk_adjustment_new(PrefsFindInt32("mousewheellines"), 1, 1000, 1, 5, 0);
1108     w_mouse_wheel_lines = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0);
1109     gtk_widget_show(w_mouse_wheel_lines);
1110     gtk_box_pack_start(GTK_BOX(hbox), w_mouse_wheel_lines, FALSE, FALSE, 0);
1111    
1112     set_input_sensitive();
1113     }
1114    
1115    
1116     /*
1117 gbeauche 1.2 * "Serial" pane
1118 gbeauche 1.1 */
1119    
1120 gbeauche 1.3 static GtkWidget *w_seriala, *w_portfile0;
1121     static GtkWidget *w_serialb, *w_portfile1;
1122 gbeauche 1.1
1123     // Set sensitivity of widgets
1124     static void set_serial_sensitive(void)
1125     {
1126     const char *str;
1127     bool is_file;
1128    
1129     str = gtk_entry_get_text(GTK_ENTRY(w_seriala));
1130     is_file = strcmp(str, "FILE") == 0;
1131     gtk_widget_set_sensitive(w_portfile0, is_file);
1132 gbeauche 1.3 gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_portfile0), "chooser_button")), is_file);
1133 gbeauche 1.1
1134     str = gtk_entry_get_text(GTK_ENTRY(w_serialb));
1135     is_file = strcmp(str, "FILE") == 0;
1136     gtk_widget_set_sensitive(w_portfile1, is_file);
1137 gbeauche 1.3 gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_portfile1), "chooser_button")), is_file);
1138 gbeauche 1.1 }
1139    
1140     // Read settings from widgets and set preferences
1141     static void read_serial_settings(void)
1142     {
1143     const char *str;
1144    
1145     str = gtk_entry_get_text(GTK_ENTRY(w_seriala));
1146     PrefsReplaceString("seriala", str);
1147    
1148     str = gtk_entry_get_text(GTK_ENTRY(w_serialb));
1149     PrefsReplaceString("serialb", str);
1150    
1151     str = gtk_entry_get_text(GTK_ENTRY(w_portfile0));
1152     PrefsReplaceString("portfile0", str);
1153    
1154     str = gtk_entry_get_text(GTK_ENTRY(w_portfile1));
1155     PrefsReplaceString("portfile1", str);
1156     }
1157    
1158     // Port changed in combo
1159     static void cb_serial_port_changed(...)
1160     {
1161     set_serial_sensitive();
1162     }
1163    
1164     // Add names of serial devices
1165     static GList *add_serial_names(void)
1166     {
1167     GList *glist = NULL;
1168    
1169     static const char *port_names[] = {
1170     "COM1", "COM2", "COM3", "COM4", "COM5", "COM6",
1171     "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6",
1172     "FILE",
1173     NULL
1174     };
1175    
1176     for (int i = 0; port_names[i] != NULL; i++)
1177     glist = g_list_append(glist, (void *)port_names[i]);
1178    
1179     return glist;
1180     }
1181    
1182 gbeauche 1.2 // Create "Serial" pane
1183 gbeauche 1.1 static void create_serial_pane(GtkWidget *top)
1184     {
1185     GtkWidget *box, *hbox, *table, *label, *combo, *sep, *entry;
1186     GtkObject *adj;
1187    
1188     box = make_pane(top, STR_SERIAL_PANE_TITLE);
1189     table = make_table(box, 2, 5);
1190    
1191     GList *glist = add_serial_names();
1192     const char *str = PrefsFindString("seriala");
1193 gbeauche 1.3 combo = table_make_combobox(table, 0, STR_SERIALA_CTRL, str, glist);
1194 gbeauche 1.1 w_seriala = GTK_COMBO(combo)->entry;
1195     gtk_signal_connect(GTK_OBJECT(w_seriala), "changed", GTK_SIGNAL_FUNC(cb_serial_port_changed), NULL);
1196    
1197 gbeauche 1.3 w_portfile0 = table_make_file_entry(table, 1, STR_FILE_CTRL, "portfile0");
1198 gbeauche 1.1
1199     sep = gtk_hseparator_new();
1200     gtk_widget_show(sep);
1201     gtk_table_attach(GTK_TABLE(table), sep, 0, 2, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1202    
1203     str = PrefsFindString("serialb");
1204 gbeauche 1.3 combo = table_make_combobox(table, 3, STR_SERIALB_CTRL, str, glist);
1205 gbeauche 1.1 w_serialb = GTK_COMBO(combo)->entry;
1206     gtk_signal_connect(GTK_OBJECT(w_serialb), "changed", GTK_SIGNAL_FUNC(cb_serial_port_changed), NULL);
1207    
1208 gbeauche 1.3 w_portfile1 = table_make_file_entry(table, 4, STR_FILE_CTRL, "portfile1");
1209 gbeauche 1.1
1210     set_serial_sensitive();
1211     }
1212    
1213    
1214     /*
1215     * "Ethernet" pane
1216     */
1217    
1218 gbeauche 1.5 static GtkWidget *w_ether;
1219     static GtkWidget *w_ftp_port_list, *w_tcp_port_list;
1220     static const char s_nat_router[] = "NAT/Router module";
1221 gbeauche 1.1
1222     // Set sensitivity of widgets
1223     static void set_ethernet_sensitive(void)
1224     {
1225 gbeauche 1.5 const char *str = gtk_entry_get_text(GTK_ENTRY(w_ether));
1226    
1227     bool is_nat_router = strcmp(str, s_nat_router) == 0;
1228     gtk_widget_set_sensitive(w_ftp_port_list, is_nat_router);
1229     gtk_widget_set_sensitive(w_tcp_port_list, is_nat_router);
1230 gbeauche 1.1 }
1231    
1232     // Read settings from widgets and set preferences
1233     static void read_ethernet_settings(void)
1234     {
1235     const char *str = gtk_entry_get_text(GTK_ENTRY(w_ether));
1236 gbeauche 1.5 if (str && strlen(str) > 6 && strncmp(str, "NDIS: ", 6) == 0)
1237     PrefsReplaceString("ether", &str[6]);
1238 gbeauche 1.1 else
1239     PrefsRemoveItem("ether");
1240 gbeauche 1.5
1241     const bool router_enabled = str && strcmp(str, s_nat_router) == 0;
1242     PrefsReplaceBool("routerenabled", router_enabled);
1243     if (router_enabled) {
1244     str = gtk_entry_get_text(GTK_ENTRY(w_ftp_port_list));
1245     PrefsReplaceString("ftp_port_list", str);
1246     str = gtk_entry_get_text(GTK_ENTRY(w_tcp_port_list));
1247     PrefsReplaceString("tcp_port", str);
1248     }
1249     }
1250    
1251     // Ethernet emulation type changed in menulist
1252     static void cb_ether_changed(...)
1253     {
1254     set_ethernet_sensitive();
1255 gbeauche 1.1 }
1256    
1257     // Add names of ethernet interfaces
1258     static GList *add_ether_names(void)
1259     {
1260     GList *glist = NULL;
1261    
1262     // TODO: Get list of all Ethernet interfaces
1263     #ifdef HAVE_SLIRP
1264 gbeauche 1.5 static const char s_slirp[] = "slirp";
1265     glist = g_list_append(glist, (void *)s_slirp);
1266 gbeauche 1.1 #endif
1267 gbeauche 1.5 glist = g_list_append(glist, (void *)s_nat_router);
1268     glist = g_list_append(glist, (void *)GetString(STR_NONE_LAB));
1269 gbeauche 1.1 return glist;
1270     }
1271    
1272    
1273     // Create "Ethernet" pane
1274     static void create_ethernet_pane(GtkWidget *top)
1275     {
1276     GtkWidget *box, *hbox, *table, *label, *combo, *sep, *entry;
1277    
1278     box = make_pane(top, STR_NETWORK_PANE_TITLE);
1279     table = make_table(box, 2, 5);
1280    
1281     label = gtk_label_new(GetString(STR_ETHERNET_IF_CTRL));
1282     gtk_widget_show(label);
1283     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1284    
1285     GList *glist = add_ether_names();
1286     combo = gtk_combo_new();
1287     gtk_widget_show(combo);
1288     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1289     const char *str = PrefsFindString("ether");
1290 gbeauche 1.5 if (str == NULL || str[0] == '\0') {
1291     if (PrefsFindBool("routerenabled"))
1292     str = s_nat_router;
1293     else
1294     str = GetString(STR_NONE_LAB);
1295     }
1296 gbeauche 1.1 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1297     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1298     w_ether = GTK_COMBO(combo)->entry;
1299 gbeauche 1.5 gtk_signal_connect(GTK_OBJECT(w_ether), "changed", GTK_SIGNAL_FUNC(cb_ether_changed), NULL);
1300    
1301     sep = gtk_hseparator_new();
1302     gtk_widget_show(sep);
1303     gtk_table_attach(GTK_TABLE(table), sep, 0, 2, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1304    
1305     label = gtk_label_new(GetString(STR_ETHER_FTP_PORT_LIST_CTRL));
1306     gtk_widget_show(label);
1307     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1308    
1309     entry = gtk_entry_new();
1310     str = PrefsFindString("ftp_port_list");
1311     if (str == NULL)
1312     str = "";
1313     gtk_entry_set_text(GTK_ENTRY(entry), str);
1314     gtk_widget_show(entry);
1315     gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 2, 3, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1316     w_ftp_port_list = entry;
1317    
1318     label = gtk_label_new(GetString(STR_ETHER_TCP_PORT_LIST_CTRL));
1319     gtk_widget_show(label);
1320     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1321    
1322     entry = gtk_entry_new();
1323     str = PrefsFindString("tcp_port");
1324     if (str == NULL)
1325     str = "";
1326     gtk_entry_set_text(GTK_ENTRY(entry), str);
1327     gtk_widget_show(entry);
1328     gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 3, 4, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1329     w_tcp_port_list = entry;
1330 gbeauche 1.1
1331     set_ethernet_sensitive();
1332     }
1333    
1334    
1335     /*
1336     * "Memory/Misc" pane
1337     */
1338    
1339 gbeauche 1.3 static GtkWidget *w_ramsize;
1340 gbeauche 1.1 static GtkWidget *w_rom_file;
1341    
1342     // "Ignore SEGV" button toggled
1343     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1344     static void tb_ignoresegv(GtkWidget *widget)
1345     {
1346     PrefsReplaceBool("ignoresegv", GTK_TOGGLE_BUTTON(widget)->active);
1347     }
1348     #endif
1349    
1350     // Model ID selected
1351     static void mn_modelid_5(...) {PrefsReplaceInt32("modelid", 5);}
1352     static void mn_modelid_14(...) {PrefsReplaceInt32("modelid", 14);}
1353    
1354     // CPU/FPU type
1355     static void mn_cpu_68020(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", false);}
1356     static void mn_cpu_68020_fpu(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", true);}
1357     static void mn_cpu_68030(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", false);}
1358     static void mn_cpu_68030_fpu(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", true);}
1359     static void mn_cpu_68040(...) {PrefsReplaceInt32("cpu", 4); PrefsReplaceBool("fpu", true);}
1360    
1361     // Read settings from widgets and set preferences
1362     static void read_memory_settings(void)
1363     {
1364 gbeauche 1.3 const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_ramsize)->entry));
1365     PrefsReplaceInt32("ramsize", atoi(str) << 20);
1366 gbeauche 1.1
1367 gbeauche 1.3 str = get_file_entry_path(w_rom_file);
1368 gbeauche 1.1 if (str && strlen(str))
1369     PrefsReplaceString("rom", str);
1370     else
1371     PrefsRemoveItem("rom");
1372    
1373     }
1374    
1375     // Create "Memory/Misc" pane
1376     static void create_memory_pane(GtkWidget *top)
1377     {
1378 gbeauche 1.3 GtkWidget *box, *hbox, *table, *label, *scale, *menu;
1379 gbeauche 1.1
1380     box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE);
1381 gbeauche 1.3 table = make_table(box, 2, 5);
1382 gbeauche 1.1
1383 gbeauche 1.3 static const combo_desc options[] = {
1384     STR_RAMSIZE_2MB_LAB,
1385     STR_RAMSIZE_4MB_LAB,
1386     STR_RAMSIZE_8MB_LAB,
1387     STR_RAMSIZE_16MB_LAB,
1388     STR_RAMSIZE_32MB_LAB,
1389     STR_RAMSIZE_64MB_LAB,
1390     STR_RAMSIZE_128MB_LAB,
1391     STR_RAMSIZE_256MB_LAB,
1392     STR_RAMSIZE_512MB_LAB,
1393     STR_RAMSIZE_1024MB_LAB,
1394     0
1395     };
1396     char default_ramsize[10];
1397     sprintf(default_ramsize, "%d", PrefsFindInt32("ramsize") >> 20);
1398     w_ramsize = table_make_combobox(table, 0, STR_RAMSIZE_CTRL, default_ramsize, options);
1399 gbeauche 1.1
1400     static const opt_desc model_options[] = {
1401     {STR_MODELID_5_LAB, GTK_SIGNAL_FUNC(mn_modelid_5)},
1402     {STR_MODELID_14_LAB, GTK_SIGNAL_FUNC(mn_modelid_14)},
1403     {0, NULL}
1404     };
1405     int modelid = PrefsFindInt32("modelid"), active = 0;
1406     switch (modelid) {
1407     case 5: active = 0; break;
1408     case 14: active = 1; break;
1409     }
1410 gbeauche 1.3 table_make_option_menu(table, 2, STR_MODELID_CTRL, model_options, active);
1411 gbeauche 1.1
1412     #if EMULATED_68K
1413     static const opt_desc cpu_options[] = {
1414     {STR_CPU_68020_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020)},
1415     {STR_CPU_68020_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020_fpu)},
1416     {STR_CPU_68030_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030)},
1417     {STR_CPU_68030_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030_fpu)},
1418     {STR_CPU_68040_LAB, GTK_SIGNAL_FUNC(mn_cpu_68040)},
1419     {0, NULL}
1420     };
1421     int cpu = PrefsFindInt32("cpu");
1422     bool fpu = PrefsFindBool("fpu");
1423     active = 0;
1424     switch (cpu) {
1425     case 2: active = fpu ? 1 : 0; break;
1426     case 3: active = fpu ? 3 : 2; break;
1427     case 4: active = 4;
1428     }
1429 gbeauche 1.3 table_make_option_menu(table, 3, STR_CPU_CTRL, cpu_options, active);
1430 gbeauche 1.1 #endif
1431    
1432 gbeauche 1.3 w_rom_file = table_make_file_entry(table, 4, STR_ROM_FILE_CTRL, "rom");
1433 gbeauche 1.1
1434     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1435     make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv));
1436     #endif
1437     }
1438    
1439    
1440     /*
1441     * Read settings from widgets and set preferences
1442     */
1443    
1444     static void read_settings(void)
1445     {
1446     read_volumes_settings();
1447     read_scsi_settings();
1448     read_graphics_settings();
1449     read_input_settings();
1450     read_serial_settings();
1451     read_ethernet_settings();
1452     read_memory_settings();
1453     read_jit_settings();
1454     }
1455    
1456    
1457     /*
1458     * Fake unused data and functions
1459     */
1460    
1461     uint8 XPRAM[XPRAM_SIZE];
1462     void MountVolume(void *fh) { }
1463     void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) { }
1464     void WarningAlert(const char *text) { }
1465    
1466    
1467     /*
1468     * Add default serial prefs (must be added, even if no ports present)
1469     */
1470    
1471     void SysAddSerialPrefs(void)
1472     {
1473     PrefsAddString("seriala", "COM1");
1474     PrefsAddString("serialb", "COM2");
1475     }
1476    
1477    
1478     /*
1479 gbeauche 1.5 * Display alerts
1480     */
1481    
1482     static void display_alert(int title_id, const char *text, int flags)
1483     {
1484     MessageBox(NULL, text, GetString(title_id), MB_OK | flags);
1485     }
1486    
1487     static void ErrorAlert(const char *text)
1488     {
1489     display_alert(STR_ERROR_ALERT_TITLE, text, MB_ICONSTOP);
1490     }
1491    
1492    
1493     /*
1494 gbeauche 1.1 * Start standalone GUI
1495     */
1496    
1497     int main(int argc, char *argv[])
1498     {
1499     // Init GTK
1500     gtk_set_locale();
1501     gtk_init(&argc, &argv);
1502    
1503     // Read preferences
1504     PrefsInit(argc, argv);
1505    
1506     // Show preferences editor
1507     bool start = PrefsEditor();
1508    
1509     // Exit preferences
1510     PrefsExit();
1511    
1512     // Transfer control to the Basilisk II executable
1513     if (start) {
1514 gbeauche 1.5 char path[_MAX_PATH];
1515     bool ok = GetModuleFileName(NULL, path, sizeof(path)) != 0;
1516     if (ok) {
1517     char b2_path[_MAX_PATH];
1518     char *p = strrchr(path, '\\');
1519     *++p = '\0';
1520     SetCurrentDirectory(path);
1521     strcpy(b2_path, path);
1522     strcat(b2_path, "BasiliskII.exe");
1523     HINSTANCE h = ShellExecute(GetDesktopWindow(), "open",
1524     b2_path, "", path, SW_SHOWNORMAL);
1525     if ((int)h <= 32)
1526     ok = false;
1527     }
1528     if (!ok) {
1529     ErrorAlert("Coult not start BasiliskII executable");
1530     return 1;
1531     }
1532 gbeauche 1.1 }
1533    
1534     return 0;
1535     }