ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/prefs_editor_gtk.cpp
Revision: 1.6
Committed: 2005-11-20T23:59:18Z (18 years, 7 months ago) by gbeauche
Branch: MAIN
Changes since 1.5: +2 -4 lines
Log Message:
Windows GUI: don't mess the button pad, map '<ctrl>-S' to Start/Save config

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     }
837    
838     // "5 Hz".."60Hz" selected
839     static void mn_5hz(...) {PrefsReplaceInt32("frameskip", 12);}
840     static void mn_7hz(...) {PrefsReplaceInt32("frameskip", 8);}
841     static void mn_10hz(...) {PrefsReplaceInt32("frameskip", 6);}
842     static void mn_15hz(...) {PrefsReplaceInt32("frameskip", 4);}
843     static void mn_30hz(...) {PrefsReplaceInt32("frameskip", 2);}
844     static void mn_60hz(...) {PrefsReplaceInt32("frameskip", 1);}
845     static void mn_dynamic(...) {PrefsReplaceInt32("frameskip", 0);}
846    
847     // Set sensitivity of widgets
848     static void set_graphics_sensitive(void)
849     {
850     const bool sound_enabled = !PrefsFindBool("nosound");
851     }
852    
853     // "Disable Sound Output" button toggled
854     static void tb_nosound(GtkWidget *widget)
855     {
856     PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active);
857     set_graphics_sensitive();
858     }
859    
860     // Read graphics preferences
861     static void parse_graphics_prefs(void)
862     {
863     display_type = DISPLAY_WINDOW;
864     dis_width = 512;
865     dis_height = 384;
866    
867     const char *str = PrefsFindString("screen");
868     if (str) {
869     if (sscanf(str, "win/%d/%d", &dis_width, &dis_height) == 2)
870     display_type = DISPLAY_WINDOW;
871     else if (sscanf(str, "dga/%d/%d", &dis_width, &dis_height) == 2)
872     display_type = DISPLAY_SCREEN;
873     }
874     }
875    
876     // Read settings from widgets and set preferences
877     static void read_graphics_settings(void)
878     {
879     const char *str;
880    
881     str = gtk_entry_get_text(GTK_ENTRY(w_display_x));
882     dis_width = atoi(str);
883    
884     str = gtk_entry_get_text(GTK_ENTRY(w_display_y));
885     dis_height = atoi(str);
886    
887     char pref[256];
888     switch (display_type) {
889     case DISPLAY_WINDOW:
890     sprintf(pref, "win/%d/%d", dis_width, dis_height);
891     break;
892     case DISPLAY_SCREEN:
893     sprintf(pref, "dga/%d/%d", dis_width, dis_height);
894     break;
895     default:
896     PrefsRemoveItem("screen");
897     return;
898     }
899     PrefsReplaceString("screen", pref);
900     }
901    
902     // Create "Graphics/Sound" pane
903     static void create_graphics_pane(GtkWidget *top)
904     {
905     GtkWidget *box, *table, *label, *opt, *menu, *combo;
906     char str[32];
907    
908     parse_graphics_prefs();
909    
910     box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE);
911     table = make_table(box, 2, 5);
912    
913     label = gtk_label_new(GetString(STR_VIDEO_TYPE_CTRL));
914     gtk_widget_show(label);
915     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
916    
917     opt = gtk_option_menu_new();
918     gtk_widget_show(opt);
919     menu = gtk_menu_new();
920     add_menu_item(menu, STR_WINDOW_LAB, GTK_SIGNAL_FUNC(mn_window));
921     add_menu_item(menu, STR_FULLSCREEN_LAB, GTK_SIGNAL_FUNC(mn_fullscreen));
922     switch (display_type) {
923     case DISPLAY_WINDOW:
924     gtk_menu_set_active(GTK_MENU(menu), 0);
925     break;
926     case DISPLAY_SCREEN:
927     gtk_menu_set_active(GTK_MENU(menu), 1);
928     break;
929     }
930     gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
931     gtk_table_attach(GTK_TABLE(table), opt, 1, 2, 0, 1, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
932    
933     l_frameskip = gtk_label_new(GetString(STR_FRAMESKIP_CTRL));
934     gtk_widget_show(l_frameskip);
935     gtk_table_attach(GTK_TABLE(table), l_frameskip, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
936    
937     w_frameskip = gtk_option_menu_new();
938     gtk_widget_show(w_frameskip);
939     menu = gtk_menu_new();
940     add_menu_item(menu, STR_REF_5HZ_LAB, GTK_SIGNAL_FUNC(mn_5hz));
941     add_menu_item(menu, STR_REF_7_5HZ_LAB, GTK_SIGNAL_FUNC(mn_7hz));
942     add_menu_item(menu, STR_REF_10HZ_LAB, GTK_SIGNAL_FUNC(mn_10hz));
943     add_menu_item(menu, STR_REF_15HZ_LAB, GTK_SIGNAL_FUNC(mn_15hz));
944     add_menu_item(menu, STR_REF_30HZ_LAB, GTK_SIGNAL_FUNC(mn_30hz));
945     add_menu_item(menu, STR_REF_60HZ_LAB, GTK_SIGNAL_FUNC(mn_60hz));
946     add_menu_item(menu, STR_REF_DYNAMIC_LAB, GTK_SIGNAL_FUNC(mn_dynamic));
947     int frameskip = PrefsFindInt32("frameskip");
948     int item = -1;
949     switch (frameskip) {
950     case 12: item = 0; break;
951     case 8: item = 1; break;
952     case 6: item = 2; break;
953     case 4: item = 3; break;
954     case 2: item = 4; break;
955     case 1: item = 5; break;
956     case 0: item = 6; break;
957     }
958     if (item >= 0)
959     gtk_menu_set_active(GTK_MENU(menu), item);
960     gtk_option_menu_set_menu(GTK_OPTION_MENU(w_frameskip), menu);
961     gtk_table_attach(GTK_TABLE(table), w_frameskip, 1, 2, 1, 2, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
962    
963     l_display_x = gtk_label_new(GetString(STR_DISPLAY_X_CTRL));
964     gtk_widget_show(l_display_x);
965     gtk_table_attach(GTK_TABLE(table), l_display_x, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
966    
967     combo = gtk_combo_new();
968     gtk_widget_show(combo);
969     GList *glist1 = NULL;
970     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_512_LAB));
971     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_640_LAB));
972     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_800_LAB));
973     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_1024_LAB));
974     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_MAX_LAB));
975     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist1);
976     if (dis_width)
977     sprintf(str, "%d", dis_width);
978     else
979     strcpy(str, GetString(STR_SIZE_MAX_LAB));
980     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
981     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
982     w_display_x = GTK_COMBO(combo)->entry;
983    
984     l_display_y = gtk_label_new(GetString(STR_DISPLAY_Y_CTRL));
985     gtk_widget_show(l_display_y);
986     gtk_table_attach(GTK_TABLE(table), l_display_y, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
987    
988     combo = gtk_combo_new();
989     gtk_widget_show(combo);
990     GList *glist2 = NULL;
991     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_384_LAB));
992     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_480_LAB));
993     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_600_LAB));
994     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_768_LAB));
995     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_MAX_LAB));
996     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist2);
997     if (dis_height)
998     sprintf(str, "%d", dis_height);
999     else
1000     strcpy(str, GetString(STR_SIZE_MAX_LAB));
1001     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1002     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
1003     w_display_y = GTK_COMBO(combo)->entry;
1004    
1005     make_separator(box);
1006     make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound));
1007    
1008     set_graphics_sensitive();
1009    
1010     hide_show_graphics_widgets();
1011     }
1012    
1013    
1014     /*
1015     * "Input" pane
1016     */
1017    
1018     static GtkWidget *w_keycode_file;
1019     static GtkWidget *w_mouse_wheel_lines;
1020    
1021     // Set sensitivity of widgets
1022     static void set_input_sensitive(void)
1023     {
1024 gbeauche 1.4 const bool use_keycodes = PrefsFindBool("keycodes");
1025     gtk_widget_set_sensitive(w_keycode_file, use_keycodes);
1026     gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_keycode_file), "chooser_button")), use_keycodes);
1027 gbeauche 1.1 gtk_widget_set_sensitive(w_mouse_wheel_lines, PrefsFindInt32("mousewheelmode") == 1);
1028     }
1029    
1030     // "Use Raw Keycodes" button toggled
1031     static void tb_keycodes(GtkWidget *widget)
1032     {
1033     PrefsReplaceBool("keycodes", GTK_TOGGLE_BUTTON(widget)->active);
1034     set_input_sensitive();
1035     }
1036    
1037     // "Mouse Wheel Mode" selected
1038     static void mn_wheel_page(...) {PrefsReplaceInt32("mousewheelmode", 0); set_input_sensitive();}
1039     static void mn_wheel_cursor(...) {PrefsReplaceInt32("mousewheelmode", 1); set_input_sensitive();}
1040    
1041     // Read settings from widgets and set preferences
1042     static void read_input_settings(void)
1043     {
1044     const char *str = get_file_entry_path(w_keycode_file);
1045     if (str && strlen(str))
1046     PrefsReplaceString("keycodefile", str);
1047     else
1048     PrefsRemoveItem("keycodefile");
1049    
1050     PrefsReplaceInt32("mousewheellines", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_mouse_wheel_lines)));
1051     }
1052    
1053     // Create "Input" pane
1054     static void create_input_pane(GtkWidget *top)
1055     {
1056 gbeauche 1.4 GtkWidget *box, *hbox, *menu, *label, *button;
1057 gbeauche 1.1 GtkObject *adj;
1058    
1059     box = make_pane(top, STR_INPUT_PANE_TITLE);
1060    
1061     make_checkbox(box, STR_KEYCODES_CTRL, "keycodes", GTK_SIGNAL_FUNC(tb_keycodes));
1062 gbeauche 1.4
1063     hbox = gtk_hbox_new(FALSE, 4);
1064     gtk_widget_show(hbox);
1065     gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1066    
1067     label = gtk_label_new(GetString(STR_KEYCODES_CTRL));
1068     gtk_widget_show(label);
1069     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1070    
1071     const char *str = PrefsFindString("keycodefile");
1072     if (str == NULL)
1073     str = "";
1074    
1075     w_keycode_file = gtk_entry_new();
1076     gtk_entry_set_text(GTK_ENTRY(w_keycode_file), str);
1077     gtk_widget_show(w_keycode_file);
1078     gtk_box_pack_start(GTK_BOX(hbox), w_keycode_file, TRUE, TRUE, 0);
1079    
1080     button = make_browse_button(w_keycode_file);
1081     gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1082     g_object_set_data(G_OBJECT(w_keycode_file), "chooser_button", button);
1083 gbeauche 1.1
1084     make_separator(box);
1085    
1086     static const opt_desc options[] = {
1087     {STR_MOUSEWHEELMODE_PAGE_LAB, GTK_SIGNAL_FUNC(mn_wheel_page)},
1088     {STR_MOUSEWHEELMODE_CURSOR_LAB, GTK_SIGNAL_FUNC(mn_wheel_cursor)},
1089     {0, NULL}
1090     };
1091     int wheelmode = PrefsFindInt32("mousewheelmode"), active = 0;
1092     switch (wheelmode) {
1093     case 0: active = 0; break;
1094     case 1: active = 1; break;
1095     }
1096     menu = make_option_menu(box, STR_MOUSEWHEELMODE_CTRL, options, active);
1097    
1098     hbox = gtk_hbox_new(FALSE, 4);
1099     gtk_widget_show(hbox);
1100     gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1101    
1102     label = gtk_label_new(GetString(STR_MOUSEWHEELLINES_CTRL));
1103     gtk_widget_show(label);
1104     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1105    
1106     adj = gtk_adjustment_new(PrefsFindInt32("mousewheellines"), 1, 1000, 1, 5, 0);
1107     w_mouse_wheel_lines = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0);
1108     gtk_widget_show(w_mouse_wheel_lines);
1109     gtk_box_pack_start(GTK_BOX(hbox), w_mouse_wheel_lines, FALSE, FALSE, 0);
1110    
1111     set_input_sensitive();
1112     }
1113    
1114    
1115     /*
1116 gbeauche 1.2 * "Serial" pane
1117 gbeauche 1.1 */
1118    
1119 gbeauche 1.3 static GtkWidget *w_seriala, *w_portfile0;
1120     static GtkWidget *w_serialb, *w_portfile1;
1121 gbeauche 1.1
1122     // Set sensitivity of widgets
1123     static void set_serial_sensitive(void)
1124     {
1125     const char *str;
1126     bool is_file;
1127    
1128     str = gtk_entry_get_text(GTK_ENTRY(w_seriala));
1129     is_file = strcmp(str, "FILE") == 0;
1130     gtk_widget_set_sensitive(w_portfile0, is_file);
1131 gbeauche 1.3 gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_portfile0), "chooser_button")), is_file);
1132 gbeauche 1.1
1133     str = gtk_entry_get_text(GTK_ENTRY(w_serialb));
1134     is_file = strcmp(str, "FILE") == 0;
1135     gtk_widget_set_sensitive(w_portfile1, is_file);
1136 gbeauche 1.3 gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_portfile1), "chooser_button")), is_file);
1137 gbeauche 1.1 }
1138    
1139     // Read settings from widgets and set preferences
1140     static void read_serial_settings(void)
1141     {
1142     const char *str;
1143    
1144     str = gtk_entry_get_text(GTK_ENTRY(w_seriala));
1145     PrefsReplaceString("seriala", str);
1146    
1147     str = gtk_entry_get_text(GTK_ENTRY(w_serialb));
1148     PrefsReplaceString("serialb", str);
1149    
1150     str = gtk_entry_get_text(GTK_ENTRY(w_portfile0));
1151     PrefsReplaceString("portfile0", str);
1152    
1153     str = gtk_entry_get_text(GTK_ENTRY(w_portfile1));
1154     PrefsReplaceString("portfile1", str);
1155     }
1156    
1157     // Port changed in combo
1158     static void cb_serial_port_changed(...)
1159     {
1160     set_serial_sensitive();
1161     }
1162    
1163     // Add names of serial devices
1164     static GList *add_serial_names(void)
1165     {
1166     GList *glist = NULL;
1167    
1168     static const char *port_names[] = {
1169     "COM1", "COM2", "COM3", "COM4", "COM5", "COM6",
1170     "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6",
1171     "FILE",
1172     NULL
1173     };
1174    
1175     for (int i = 0; port_names[i] != NULL; i++)
1176     glist = g_list_append(glist, (void *)port_names[i]);
1177    
1178     return glist;
1179     }
1180    
1181 gbeauche 1.2 // Create "Serial" pane
1182 gbeauche 1.1 static void create_serial_pane(GtkWidget *top)
1183     {
1184     GtkWidget *box, *hbox, *table, *label, *combo, *sep, *entry;
1185     GtkObject *adj;
1186    
1187     box = make_pane(top, STR_SERIAL_PANE_TITLE);
1188     table = make_table(box, 2, 5);
1189    
1190     GList *glist = add_serial_names();
1191     const char *str = PrefsFindString("seriala");
1192 gbeauche 1.3 combo = table_make_combobox(table, 0, STR_SERIALA_CTRL, str, glist);
1193 gbeauche 1.1 w_seriala = GTK_COMBO(combo)->entry;
1194     gtk_signal_connect(GTK_OBJECT(w_seriala), "changed", GTK_SIGNAL_FUNC(cb_serial_port_changed), NULL);
1195    
1196 gbeauche 1.3 w_portfile0 = table_make_file_entry(table, 1, STR_FILE_CTRL, "portfile0");
1197 gbeauche 1.1
1198     sep = gtk_hseparator_new();
1199     gtk_widget_show(sep);
1200     gtk_table_attach(GTK_TABLE(table), sep, 0, 2, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1201    
1202     str = PrefsFindString("serialb");
1203 gbeauche 1.3 combo = table_make_combobox(table, 3, STR_SERIALB_CTRL, str, glist);
1204 gbeauche 1.1 w_serialb = GTK_COMBO(combo)->entry;
1205     gtk_signal_connect(GTK_OBJECT(w_serialb), "changed", GTK_SIGNAL_FUNC(cb_serial_port_changed), NULL);
1206    
1207 gbeauche 1.3 w_portfile1 = table_make_file_entry(table, 4, STR_FILE_CTRL, "portfile1");
1208 gbeauche 1.1
1209     set_serial_sensitive();
1210     }
1211    
1212    
1213     /*
1214     * "Ethernet" pane
1215     */
1216    
1217 gbeauche 1.5 static GtkWidget *w_ether;
1218     static GtkWidget *w_ftp_port_list, *w_tcp_port_list;
1219     static const char s_nat_router[] = "NAT/Router module";
1220 gbeauche 1.1
1221     // Set sensitivity of widgets
1222     static void set_ethernet_sensitive(void)
1223     {
1224 gbeauche 1.5 const char *str = gtk_entry_get_text(GTK_ENTRY(w_ether));
1225    
1226     bool is_nat_router = strcmp(str, s_nat_router) == 0;
1227     gtk_widget_set_sensitive(w_ftp_port_list, is_nat_router);
1228     gtk_widget_set_sensitive(w_tcp_port_list, is_nat_router);
1229 gbeauche 1.1 }
1230    
1231     // Read settings from widgets and set preferences
1232     static void read_ethernet_settings(void)
1233     {
1234     const char *str = gtk_entry_get_text(GTK_ENTRY(w_ether));
1235 gbeauche 1.5 if (str && strlen(str) > 6 && strncmp(str, "NDIS: ", 6) == 0)
1236     PrefsReplaceString("ether", &str[6]);
1237 gbeauche 1.1 else
1238     PrefsRemoveItem("ether");
1239 gbeauche 1.5
1240     const bool router_enabled = str && strcmp(str, s_nat_router) == 0;
1241     PrefsReplaceBool("routerenabled", router_enabled);
1242     if (router_enabled) {
1243     str = gtk_entry_get_text(GTK_ENTRY(w_ftp_port_list));
1244     PrefsReplaceString("ftp_port_list", str);
1245     str = gtk_entry_get_text(GTK_ENTRY(w_tcp_port_list));
1246     PrefsReplaceString("tcp_port", str);
1247     }
1248     }
1249    
1250     // Ethernet emulation type changed in menulist
1251     static void cb_ether_changed(...)
1252     {
1253     set_ethernet_sensitive();
1254 gbeauche 1.1 }
1255    
1256     // Add names of ethernet interfaces
1257     static GList *add_ether_names(void)
1258     {
1259     GList *glist = NULL;
1260    
1261     // TODO: Get list of all Ethernet interfaces
1262     #ifdef HAVE_SLIRP
1263 gbeauche 1.5 static const char s_slirp[] = "slirp";
1264     glist = g_list_append(glist, (void *)s_slirp);
1265 gbeauche 1.1 #endif
1266 gbeauche 1.5 glist = g_list_append(glist, (void *)s_nat_router);
1267     glist = g_list_append(glist, (void *)GetString(STR_NONE_LAB));
1268 gbeauche 1.1 return glist;
1269     }
1270    
1271    
1272     // Create "Ethernet" pane
1273     static void create_ethernet_pane(GtkWidget *top)
1274     {
1275     GtkWidget *box, *hbox, *table, *label, *combo, *sep, *entry;
1276    
1277     box = make_pane(top, STR_NETWORK_PANE_TITLE);
1278     table = make_table(box, 2, 5);
1279    
1280     label = gtk_label_new(GetString(STR_ETHERNET_IF_CTRL));
1281     gtk_widget_show(label);
1282     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1283    
1284     GList *glist = add_ether_names();
1285     combo = gtk_combo_new();
1286     gtk_widget_show(combo);
1287     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1288     const char *str = PrefsFindString("ether");
1289 gbeauche 1.5 if (str == NULL || str[0] == '\0') {
1290     if (PrefsFindBool("routerenabled"))
1291     str = s_nat_router;
1292     else
1293     str = GetString(STR_NONE_LAB);
1294     }
1295 gbeauche 1.1 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1296     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1297     w_ether = GTK_COMBO(combo)->entry;
1298 gbeauche 1.5 gtk_signal_connect(GTK_OBJECT(w_ether), "changed", GTK_SIGNAL_FUNC(cb_ether_changed), NULL);
1299    
1300     sep = gtk_hseparator_new();
1301     gtk_widget_show(sep);
1302     gtk_table_attach(GTK_TABLE(table), sep, 0, 2, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1303    
1304     label = gtk_label_new(GetString(STR_ETHER_FTP_PORT_LIST_CTRL));
1305     gtk_widget_show(label);
1306     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1307    
1308     entry = gtk_entry_new();
1309     str = PrefsFindString("ftp_port_list");
1310     if (str == NULL)
1311     str = "";
1312     gtk_entry_set_text(GTK_ENTRY(entry), str);
1313     gtk_widget_show(entry);
1314     gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 2, 3, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1315     w_ftp_port_list = entry;
1316    
1317     label = gtk_label_new(GetString(STR_ETHER_TCP_PORT_LIST_CTRL));
1318     gtk_widget_show(label);
1319     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1320    
1321     entry = gtk_entry_new();
1322     str = PrefsFindString("tcp_port");
1323     if (str == NULL)
1324     str = "";
1325     gtk_entry_set_text(GTK_ENTRY(entry), str);
1326     gtk_widget_show(entry);
1327     gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 3, 4, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1328     w_tcp_port_list = entry;
1329 gbeauche 1.1
1330     set_ethernet_sensitive();
1331     }
1332    
1333    
1334     /*
1335     * "Memory/Misc" pane
1336     */
1337    
1338 gbeauche 1.3 static GtkWidget *w_ramsize;
1339 gbeauche 1.1 static GtkWidget *w_rom_file;
1340    
1341     // "Ignore SEGV" button toggled
1342     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1343     static void tb_ignoresegv(GtkWidget *widget)
1344     {
1345     PrefsReplaceBool("ignoresegv", GTK_TOGGLE_BUTTON(widget)->active);
1346     }
1347     #endif
1348    
1349     // Model ID selected
1350     static void mn_modelid_5(...) {PrefsReplaceInt32("modelid", 5);}
1351     static void mn_modelid_14(...) {PrefsReplaceInt32("modelid", 14);}
1352    
1353     // CPU/FPU type
1354     static void mn_cpu_68020(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", false);}
1355     static void mn_cpu_68020_fpu(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", true);}
1356     static void mn_cpu_68030(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", false);}
1357     static void mn_cpu_68030_fpu(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", true);}
1358     static void mn_cpu_68040(...) {PrefsReplaceInt32("cpu", 4); PrefsReplaceBool("fpu", true);}
1359    
1360     // Read settings from widgets and set preferences
1361     static void read_memory_settings(void)
1362     {
1363 gbeauche 1.3 const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_ramsize)->entry));
1364     PrefsReplaceInt32("ramsize", atoi(str) << 20);
1365 gbeauche 1.1
1366 gbeauche 1.3 str = get_file_entry_path(w_rom_file);
1367 gbeauche 1.1 if (str && strlen(str))
1368     PrefsReplaceString("rom", str);
1369     else
1370     PrefsRemoveItem("rom");
1371    
1372     }
1373    
1374     // Create "Memory/Misc" pane
1375     static void create_memory_pane(GtkWidget *top)
1376     {
1377 gbeauche 1.3 GtkWidget *box, *hbox, *table, *label, *scale, *menu;
1378 gbeauche 1.1
1379     box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE);
1380 gbeauche 1.3 table = make_table(box, 2, 5);
1381 gbeauche 1.1
1382 gbeauche 1.3 static const combo_desc options[] = {
1383     STR_RAMSIZE_2MB_LAB,
1384     STR_RAMSIZE_4MB_LAB,
1385     STR_RAMSIZE_8MB_LAB,
1386     STR_RAMSIZE_16MB_LAB,
1387     STR_RAMSIZE_32MB_LAB,
1388     STR_RAMSIZE_64MB_LAB,
1389     STR_RAMSIZE_128MB_LAB,
1390     STR_RAMSIZE_256MB_LAB,
1391     STR_RAMSIZE_512MB_LAB,
1392     STR_RAMSIZE_1024MB_LAB,
1393     0
1394     };
1395     char default_ramsize[10];
1396     sprintf(default_ramsize, "%d", PrefsFindInt32("ramsize") >> 20);
1397     w_ramsize = table_make_combobox(table, 0, STR_RAMSIZE_CTRL, default_ramsize, options);
1398 gbeauche 1.1
1399     static const opt_desc model_options[] = {
1400     {STR_MODELID_5_LAB, GTK_SIGNAL_FUNC(mn_modelid_5)},
1401     {STR_MODELID_14_LAB, GTK_SIGNAL_FUNC(mn_modelid_14)},
1402     {0, NULL}
1403     };
1404     int modelid = PrefsFindInt32("modelid"), active = 0;
1405     switch (modelid) {
1406     case 5: active = 0; break;
1407     case 14: active = 1; break;
1408     }
1409 gbeauche 1.3 table_make_option_menu(table, 2, STR_MODELID_CTRL, model_options, active);
1410 gbeauche 1.1
1411     #if EMULATED_68K
1412     static const opt_desc cpu_options[] = {
1413     {STR_CPU_68020_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020)},
1414     {STR_CPU_68020_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020_fpu)},
1415     {STR_CPU_68030_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030)},
1416     {STR_CPU_68030_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030_fpu)},
1417     {STR_CPU_68040_LAB, GTK_SIGNAL_FUNC(mn_cpu_68040)},
1418     {0, NULL}
1419     };
1420     int cpu = PrefsFindInt32("cpu");
1421     bool fpu = PrefsFindBool("fpu");
1422     active = 0;
1423     switch (cpu) {
1424     case 2: active = fpu ? 1 : 0; break;
1425     case 3: active = fpu ? 3 : 2; break;
1426     case 4: active = 4;
1427     }
1428 gbeauche 1.3 table_make_option_menu(table, 3, STR_CPU_CTRL, cpu_options, active);
1429 gbeauche 1.1 #endif
1430    
1431 gbeauche 1.3 w_rom_file = table_make_file_entry(table, 4, STR_ROM_FILE_CTRL, "rom");
1432 gbeauche 1.1
1433     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1434     make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv));
1435     #endif
1436     }
1437    
1438    
1439     /*
1440     * Read settings from widgets and set preferences
1441     */
1442    
1443     static void read_settings(void)
1444     {
1445     read_volumes_settings();
1446     read_scsi_settings();
1447     read_graphics_settings();
1448     read_input_settings();
1449     read_serial_settings();
1450     read_ethernet_settings();
1451     read_memory_settings();
1452     read_jit_settings();
1453     }
1454    
1455    
1456     /*
1457     * Fake unused data and functions
1458     */
1459    
1460     uint8 XPRAM[XPRAM_SIZE];
1461     void MountVolume(void *fh) { }
1462     void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) { }
1463     void WarningAlert(const char *text) { }
1464    
1465    
1466     /*
1467     * Add default serial prefs (must be added, even if no ports present)
1468     */
1469    
1470     void SysAddSerialPrefs(void)
1471     {
1472     PrefsAddString("seriala", "COM1");
1473     PrefsAddString("serialb", "COM2");
1474     }
1475    
1476    
1477     /*
1478 gbeauche 1.5 * Display alerts
1479     */
1480    
1481     static void display_alert(int title_id, const char *text, int flags)
1482     {
1483     MessageBox(NULL, text, GetString(title_id), MB_OK | flags);
1484     }
1485    
1486     static void ErrorAlert(const char *text)
1487     {
1488     display_alert(STR_ERROR_ALERT_TITLE, text, MB_ICONSTOP);
1489     }
1490    
1491    
1492     /*
1493 gbeauche 1.1 * Start standalone GUI
1494     */
1495    
1496     int main(int argc, char *argv[])
1497     {
1498     // Init GTK
1499     gtk_set_locale();
1500     gtk_init(&argc, &argv);
1501    
1502     // Read preferences
1503     PrefsInit(argc, argv);
1504    
1505     // Show preferences editor
1506     bool start = PrefsEditor();
1507    
1508     // Exit preferences
1509     PrefsExit();
1510    
1511     // Transfer control to the Basilisk II executable
1512     if (start) {
1513 gbeauche 1.5 char path[_MAX_PATH];
1514     bool ok = GetModuleFileName(NULL, path, sizeof(path)) != 0;
1515     if (ok) {
1516     char b2_path[_MAX_PATH];
1517     char *p = strrchr(path, '\\');
1518     *++p = '\0';
1519     SetCurrentDirectory(path);
1520     strcpy(b2_path, path);
1521     strcat(b2_path, "BasiliskII.exe");
1522     HINSTANCE h = ShellExecute(GetDesktopWindow(), "open",
1523     b2_path, "", path, SW_SHOWNORMAL);
1524     if ((int)h <= 32)
1525     ok = false;
1526     }
1527     if (!ok) {
1528     ErrorAlert("Coult not start BasiliskII executable");
1529     return 1;
1530     }
1531 gbeauche 1.1 }
1532    
1533     return 0;
1534     }