ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/prefs_editor_gtk.cpp
Revision: 1.35
Committed: 2006-04-17T21:22:01Z (18 years, 7 months ago) by gbeauche
Branch: MAIN
Changes since 1.34: +108 -41 lines
Log Message:
- Only start the emulator if requested (click on the "Start" button)
- Rewrote dispatch loop to accomodate GTK+1.2 for MacOS X (which doesn't
  like threads nor forks(!)). The latter also requires an additional patch
  to the version 0.7 available on SourceForge
- Run-time detect JIT capability so that we could hopefully use the ppc GUI
  on intel based Macs (check!)

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * prefs_editor_gtk.cpp - Preferences editor, Unix implementation using GTK+
3     *
4 gbeauche 1.26 * Basilisk II (C) 1997-2005 Christian Bauer
5 cebix 1.1 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include "sysdeps.h"
22    
23     #include <gtk/gtk.h>
24     #include <stdlib.h>
25     #include <dirent.h>
26     #include <sys/socket.h>
27     #include <sys/ioctl.h>
28     #include <net/if.h>
29     #include <net/if_arp.h>
30    
31 cebix 1.21 #ifdef HAVE_GNOMEUI
32     #include <gnome.h>
33     #endif
34    
35 cebix 1.1 #include "user_strings.h"
36     #include "version.h"
37     #include "cdrom.h"
38     #include "xpram.h"
39     #include "prefs.h"
40     #include "prefs_editor.h"
41    
42 gbeauche 1.33 #define DEBUG 0
43     #include "debug.h"
44    
45 cebix 1.1
46     // Global variables
47     static GtkWidget *win; // Preferences window
48 gbeauche 1.35 static bool start_clicked = false; // Return value of PrefsEditor() function
49 cebix 1.1
50    
51     // Prototypes
52     static void create_volumes_pane(GtkWidget *top);
53     static void create_scsi_pane(GtkWidget *top);
54     static void create_graphics_pane(GtkWidget *top);
55 cebix 1.13 static void create_input_pane(GtkWidget *top);
56 cebix 1.1 static void create_serial_pane(GtkWidget *top);
57     static void create_memory_pane(GtkWidget *top);
58 gbeauche 1.23 static void create_jit_pane(GtkWidget *top);
59 cebix 1.1 static void read_settings(void);
60    
61    
62     /*
63     * Utility functions
64     */
65    
66 gbeauche 1.31 #if ! GLIB_CHECK_VERSION(2,0,0)
67     #define G_OBJECT(obj) GTK_OBJECT(obj)
68     #define g_object_get_data(obj, key) gtk_object_get_data((obj), (key))
69     #define g_object_set_data(obj, key, data) gtk_object_set_data((obj), (key), (data))
70     #endif
71    
72 cebix 1.1 struct opt_desc {
73     int label_id;
74     GtkSignalFunc func;
75     };
76    
77 gbeauche 1.23 struct combo_desc {
78     int label_id;
79     };
80    
81 gbeauche 1.29 struct file_req_assoc {
82     file_req_assoc(GtkWidget *r, GtkWidget *e) : req(r), entry(e) {}
83     GtkWidget *req;
84     GtkWidget *entry;
85     };
86    
87     static void cb_browse_ok(GtkWidget *button, file_req_assoc *assoc)
88     {
89     gchar *file = (char *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
90     gtk_entry_set_text(GTK_ENTRY(assoc->entry), file);
91     gtk_widget_destroy(assoc->req);
92     delete assoc;
93     }
94    
95     static void cb_browse(GtkWidget *widget, void *user_data)
96     {
97     GtkWidget *req = gtk_file_selection_new(GetString(STR_BROWSE_TITLE));
98     gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
99     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));
100     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
101     gtk_widget_show(req);
102     }
103    
104     static GtkWidget *make_browse_button(GtkWidget *entry)
105     {
106     GtkWidget *button;
107    
108     button = gtk_button_new_with_label(GetString(STR_BROWSE_CTRL));
109     gtk_widget_show(button);
110     gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc)cb_browse, (void *)entry);
111     return button;
112     }
113    
114 cebix 1.1 static void add_menu_item(GtkWidget *menu, int label_id, GtkSignalFunc func)
115     {
116     GtkWidget *item = gtk_menu_item_new_with_label(GetString(label_id));
117     gtk_widget_show(item);
118     gtk_signal_connect(GTK_OBJECT(item), "activate", func, NULL);
119     gtk_menu_append(GTK_MENU(menu), item);
120     }
121    
122     static GtkWidget *make_pane(GtkWidget *notebook, int title_id)
123     {
124     GtkWidget *frame, *label, *box;
125    
126     frame = gtk_frame_new(NULL);
127 gbeauche 1.34 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
128 cebix 1.1
129     box = gtk_vbox_new(FALSE, 4);
130     gtk_container_set_border_width(GTK_CONTAINER(box), 4);
131     gtk_container_add(GTK_CONTAINER(frame), box);
132 gbeauche 1.34
133     gtk_widget_show_all(frame);
134    
135     label = gtk_label_new(GetString(title_id));
136     gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label);
137 cebix 1.1 return box;
138     }
139    
140     static GtkWidget *make_button_box(GtkWidget *top, int border, const opt_desc *buttons)
141     {
142     GtkWidget *bb, *button;
143    
144     bb = gtk_hbutton_box_new();
145     gtk_widget_show(bb);
146     gtk_container_set_border_width(GTK_CONTAINER(bb), border);
147     gtk_button_box_set_layout(GTK_BUTTON_BOX(bb), GTK_BUTTONBOX_DEFAULT_STYLE);
148     gtk_button_box_set_spacing(GTK_BUTTON_BOX(bb), 4);
149     gtk_box_pack_start(GTK_BOX(top), bb, FALSE, FALSE, 0);
150    
151     while (buttons->label_id) {
152     button = gtk_button_new_with_label(GetString(buttons->label_id));
153     gtk_widget_show(button);
154     gtk_signal_connect_object(GTK_OBJECT(button), "clicked", buttons->func, NULL);
155     gtk_box_pack_start(GTK_BOX(bb), button, TRUE, TRUE, 0);
156     buttons++;
157     }
158     return bb;
159     }
160    
161     static GtkWidget *make_separator(GtkWidget *top)
162     {
163     GtkWidget *sep = gtk_hseparator_new();
164     gtk_box_pack_start(GTK_BOX(top), sep, FALSE, FALSE, 0);
165     gtk_widget_show(sep);
166     return sep;
167     }
168    
169     static GtkWidget *make_table(GtkWidget *top, int x, int y)
170     {
171     GtkWidget *table = gtk_table_new(x, y, FALSE);
172     gtk_widget_show(table);
173     gtk_box_pack_start(GTK_BOX(top), table, FALSE, FALSE, 0);
174     return table;
175     }
176    
177 gbeauche 1.29 static GtkWidget *table_make_option_menu(GtkWidget *table, int row, int label_id, const opt_desc *options, int active)
178     {
179     GtkWidget *label, *opt, *menu;
180    
181     label = gtk_label_new(GetString(label_id));
182     gtk_widget_show(label);
183     gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
184    
185     opt = gtk_option_menu_new();
186     gtk_widget_show(opt);
187     menu = gtk_menu_new();
188    
189     while (options->label_id) {
190     add_menu_item(menu, options->label_id, options->func);
191     options++;
192     }
193     gtk_menu_set_active(GTK_MENU(menu), active);
194    
195     gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
196     gtk_table_attach(GTK_TABLE(table), opt, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
197     return menu;
198     }
199    
200     static GtkWidget *table_make_combobox(GtkWidget *table, int row, int label_id, const char *default_value, GList *glist)
201     {
202     GtkWidget *label, *combo;
203     char str[32];
204    
205     label = gtk_label_new(GetString(label_id));
206     gtk_widget_show(label);
207     gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
208    
209     combo = gtk_combo_new();
210     gtk_widget_show(combo);
211     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
212    
213     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), default_value);
214     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
215    
216     return combo;
217     }
218    
219     static GtkWidget *table_make_combobox(GtkWidget *table, int row, int label_id, const char *default_value, const combo_desc *options)
220     {
221     GList *glist = NULL;
222     while (options->label_id) {
223     glist = g_list_append(glist, (void *)GetString(options->label_id));
224     options++;
225     }
226    
227     return table_make_combobox(table, row, label_id, default_value, glist);
228     }
229    
230     static GtkWidget *table_make_file_entry(GtkWidget *table, int row, int label_id, const char *prefs_item, bool only_dirs = false)
231     {
232     GtkWidget *box, *label, *entry, *button;
233    
234     label = gtk_label_new(GetString(label_id));
235     gtk_widget_show(label);
236     gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
237    
238     const char *str = PrefsFindString(prefs_item);
239     if (str == NULL)
240     str = "";
241    
242     box = gtk_hbox_new(FALSE, 4);
243     gtk_widget_show(box);
244     gtk_table_attach(GTK_TABLE(table), box, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
245    
246     entry = gtk_entry_new();
247     gtk_entry_set_text(GTK_ENTRY(entry), str);
248     gtk_widget_show(entry);
249     gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0);
250    
251     button = make_browse_button(entry);
252     gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
253     g_object_set_data(G_OBJECT(entry), "chooser_button", button);
254     return entry;
255     }
256    
257 cebix 1.1 static GtkWidget *make_option_menu(GtkWidget *top, int label_id, const opt_desc *options, int active)
258     {
259     GtkWidget *box, *label, *opt, *menu;
260    
261     box = gtk_hbox_new(FALSE, 4);
262     gtk_widget_show(box);
263     gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0);
264    
265     label = gtk_label_new(GetString(label_id));
266     gtk_widget_show(label);
267     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
268    
269     opt = gtk_option_menu_new();
270     gtk_widget_show(opt);
271     menu = gtk_menu_new();
272    
273     while (options->label_id) {
274     add_menu_item(menu, options->label_id, options->func);
275     options++;
276     }
277     gtk_menu_set_active(GTK_MENU(menu), active);
278    
279     gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
280     gtk_box_pack_start(GTK_BOX(box), opt, FALSE, FALSE, 0);
281     return menu;
282     }
283    
284 cebix 1.21 static GtkWidget *make_file_entry(GtkWidget *top, int label_id, const char *prefs_item, bool only_dirs = false)
285 cebix 1.1 {
286     GtkWidget *box, *label, *entry;
287    
288     box = gtk_hbox_new(FALSE, 4);
289     gtk_widget_show(box);
290     gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0);
291    
292     label = gtk_label_new(GetString(label_id));
293     gtk_widget_show(label);
294     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
295    
296     const char *str = PrefsFindString(prefs_item);
297     if (str == NULL)
298     str = "";
299 cebix 1.21
300     #ifdef HAVE_GNOMEUI
301     entry = gnome_file_entry_new(NULL, GetString(label_id));
302     if (only_dirs)
303     gnome_file_entry_set_directory(GNOME_FILE_ENTRY(entry), true);
304     gtk_entry_set_text(GTK_ENTRY(gnome_file_entry_gtk_entry(GNOME_FILE_ENTRY(entry))), str);
305     #else
306     entry = gtk_entry_new();
307 cebix 1.1 gtk_entry_set_text(GTK_ENTRY(entry), str);
308 cebix 1.21 #endif
309     gtk_widget_show(entry);
310 cebix 1.1 gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0);
311     return entry;
312     }
313    
314 gbeauche 1.28 static const gchar *get_file_entry_path(GtkWidget *entry)
315 cebix 1.21 {
316     #ifdef HAVE_GNOMEUI
317     return gnome_file_entry_get_full_path(GNOME_FILE_ENTRY(entry), false);
318     #else
319     return gtk_entry_get_text(GTK_ENTRY(entry));
320     #endif
321     }
322    
323 cebix 1.1 static GtkWidget *make_checkbox(GtkWidget *top, int label_id, const char *prefs_item, GtkSignalFunc func)
324     {
325     GtkWidget *button = gtk_check_button_new_with_label(GetString(label_id));
326     gtk_widget_show(button);
327     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), PrefsFindBool(prefs_item));
328     gtk_signal_connect(GTK_OBJECT(button), "toggled", func, button);
329     gtk_box_pack_start(GTK_BOX(top), button, FALSE, FALSE, 0);
330     return button;
331     }
332    
333 gbeauche 1.23 static GtkWidget *make_combobox(GtkWidget *top, int label_id, const char *prefs_item, const combo_desc *options)
334     {
335     GtkWidget *box, *label, *combo;
336     char str[32];
337    
338     box = gtk_hbox_new(FALSE, 4);
339     gtk_widget_show(box);
340     gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0);
341    
342     label = gtk_label_new(GetString(label_id));
343     gtk_widget_show(label);
344     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
345    
346     GList *glist = NULL;
347     while (options->label_id) {
348     glist = g_list_append(glist, (void *)GetString(options->label_id));
349     options++;
350     }
351    
352     combo = gtk_combo_new();
353     gtk_widget_show(combo);
354     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
355    
356     sprintf(str, "%d", PrefsFindInt32(prefs_item));
357     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
358     gtk_box_pack_start(GTK_BOX(box), combo, TRUE, TRUE, 0);
359    
360     return combo;
361     }
362 cebix 1.1
363 gbeauche 1.23
364 cebix 1.1 /*
365     * Show preferences editor
366     * Returns true when user clicked on "Start", false otherwise
367     */
368    
369     // Window closed
370     static gint window_closed(void)
371     {
372     return FALSE;
373     }
374    
375     // Window destroyed
376     static void window_destroyed(void)
377     {
378     gtk_main_quit();
379     }
380    
381     // "Start" button clicked
382     static void cb_start(...)
383     {
384     start_clicked = true;
385     read_settings();
386     SavePrefs();
387     gtk_widget_destroy(win);
388     }
389    
390     // "Quit" button clicked
391     static void cb_quit(...)
392     {
393     start_clicked = false;
394     gtk_widget_destroy(win);
395     }
396    
397     // "OK" button of "About" dialog clicked
398     static void dl_quit(GtkWidget *dialog)
399     {
400     gtk_widget_destroy(dialog);
401     }
402    
403     // "About" selected
404     static void mn_about(...)
405     {
406 cebix 1.21 GtkWidget *dialog;
407    
408     #ifdef HAVE_GNOMEUI
409    
410     char version[32];
411     sprintf(version, "Version %d.%d", VERSION_MAJOR, VERSION_MINOR);
412     const char *authors[] = {
413     "Christian Bauer",
414     "Orlando Bassotto",
415     "Gwenolé Beauchesne",
416     "Marc Chabanas",
417     "Marc Hellwig",
418     "Biill Huey",
419     "Brian J. Johnson",
420     "Jürgen Lachmann",
421     "Samuel Lander",
422     "David Lawrence",
423     "Lauri Pesonen",
424     "Bernd Schmidt",
425     "and others",
426     NULL
427     };
428     dialog = gnome_about_new(
429     "Basilisk II",
430     version,
431 gbeauche 1.30 "Copyright (C) 1997-2005 Christian Bauer",
432 cebix 1.21 authors,
433     "Basilisk II comes with ABSOLUTELY NO WARRANTY."
434     "This is free software, and you are welcome to redistribute it"
435     "under the terms of the GNU General Public License.",
436     NULL
437     );
438     gnome_dialog_set_parent(GNOME_DIALOG(dialog), GTK_WINDOW(win));
439    
440     #else
441    
442     GtkWidget *label, *button;
443 cebix 1.1
444 cebix 1.16 char str[512];
445     sprintf(str,
446     "Basilisk II\nVersion %d.%d\n\n"
447 gbeauche 1.30 "Copyright (C) 1997-2005 Christian Bauer et al.\n"
448 cebix 1.16 "E-mail: Christian.Bauer@uni-mainz.de\n"
449     "http://www.uni-mainz.de/~bauec002/B2Main.html\n\n"
450     "Basilisk II comes with ABSOLUTELY NO\n"
451     "WARRANTY. This is free software, and\n"
452     "you are welcome to redistribute it\n"
453     "under the terms of the GNU General\n"
454     "Public License.\n",
455     VERSION_MAJOR, VERSION_MINOR
456     );
457 cebix 1.1
458     dialog = gtk_dialog_new();
459     gtk_window_set_title(GTK_WINDOW(dialog), GetString(STR_ABOUT_TITLE));
460     gtk_container_border_width(GTK_CONTAINER(dialog), 5);
461     gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
462    
463     label = gtk_label_new(str);
464     gtk_widget_show(label);
465     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
466    
467     button = gtk_button_new_with_label(GetString(STR_OK_BUTTON));
468     gtk_widget_show(button);
469     gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
470     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
471     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
472     gtk_widget_grab_default(button);
473 cebix 1.21
474     #endif
475    
476 cebix 1.1 gtk_widget_show(dialog);
477     }
478    
479     // "Zap PRAM" selected
480     static void mn_zap_pram(...)
481     {
482     ZapPRAM();
483     }
484    
485     // Menu item descriptions
486     static GtkItemFactoryEntry menu_items[] = {
487 cebix 1.4 {(gchar *)GetString(STR_PREFS_MENU_FILE_GTK), NULL, NULL, 0, "<Branch>"},
488 gbeauche 1.29 {(gchar *)GetString(STR_PREFS_ITEM_START_GTK), "<control>S", GTK_SIGNAL_FUNC(cb_start), 0, NULL},
489 cebix 1.4 {(gchar *)GetString(STR_PREFS_ITEM_ZAP_PRAM_GTK), NULL, GTK_SIGNAL_FUNC(mn_zap_pram), 0, NULL},
490     {(gchar *)GetString(STR_PREFS_ITEM_SEPL_GTK), NULL, NULL, 0, "<Separator>"},
491     {(gchar *)GetString(STR_PREFS_ITEM_QUIT_GTK), "<control>Q", GTK_SIGNAL_FUNC(cb_quit), 0, NULL},
492     {(gchar *)GetString(STR_HELP_MENU_GTK), NULL, NULL, 0, "<LastBranch>"},
493     {(gchar *)GetString(STR_HELP_ITEM_ABOUT_GTK), NULL, GTK_SIGNAL_FUNC(mn_about), 0, NULL}
494 cebix 1.1 };
495    
496     bool PrefsEditor(void)
497     {
498     // Create window
499     win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
500     gtk_window_set_title(GTK_WINDOW(win), GetString(STR_PREFS_TITLE));
501     gtk_signal_connect(GTK_OBJECT(win), "delete_event", GTK_SIGNAL_FUNC(window_closed), NULL);
502     gtk_signal_connect(GTK_OBJECT(win), "destroy", GTK_SIGNAL_FUNC(window_destroyed), NULL);
503    
504     // Create window contents
505     GtkWidget *box = gtk_vbox_new(FALSE, 4);
506     gtk_widget_show(box);
507     gtk_container_add(GTK_CONTAINER(win), box);
508    
509     GtkAccelGroup *accel_group = gtk_accel_group_new();
510     GtkItemFactory *item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
511     gtk_item_factory_create_items(item_factory, sizeof(menu_items) / sizeof(menu_items[0]), menu_items, NULL);
512 gbeauche 1.28 #if GTK_CHECK_VERSION(1,3,15)
513     gtk_window_add_accel_group(GTK_WINDOW(win), accel_group);
514     #else
515 cebix 1.1 gtk_accel_group_attach(accel_group, GTK_OBJECT(win));
516 gbeauche 1.28 #endif
517 cebix 1.1 GtkWidget *menu_bar = gtk_item_factory_get_widget(item_factory, "<main>");
518     gtk_widget_show(menu_bar);
519     gtk_box_pack_start(GTK_BOX(box), menu_bar, FALSE, TRUE, 0);
520    
521     GtkWidget *notebook = gtk_notebook_new();
522     gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
523 cebix 1.8 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), FALSE);
524 cebix 1.1 gtk_box_pack_start(GTK_BOX(box), notebook, TRUE, TRUE, 0);
525 gbeauche 1.34 gtk_widget_realize(notebook);
526 cebix 1.1
527     create_volumes_pane(notebook);
528     create_scsi_pane(notebook);
529     create_graphics_pane(notebook);
530 cebix 1.13 create_input_pane(notebook);
531 cebix 1.1 create_serial_pane(notebook);
532     create_memory_pane(notebook);
533 gbeauche 1.23 create_jit_pane(notebook);
534 gbeauche 1.34 gtk_widget_show(notebook);
535 cebix 1.1
536     static const opt_desc buttons[] = {
537     {STR_START_BUTTON, GTK_SIGNAL_FUNC(cb_start)},
538     {STR_QUIT_BUTTON, GTK_SIGNAL_FUNC(cb_quit)},
539     {0, NULL}
540     };
541     make_button_box(box, 4, buttons);
542    
543     // Show window and enter main loop
544     gtk_widget_show(win);
545     gtk_main();
546     return start_clicked;
547     }
548    
549    
550     /*
551     * "Volumes" pane
552     */
553    
554 cebix 1.6 static GtkWidget *volume_list, *w_extfs;
555 cebix 1.1 static int selected_volume;
556    
557     // Volume in list selected
558     static void cl_selected(GtkWidget *list, int row, int column)
559     {
560     selected_volume = row;
561     }
562    
563     // Volume selected for addition
564     static void add_volume_ok(GtkWidget *button, file_req_assoc *assoc)
565     {
566 gbeauche 1.28 gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
567 cebix 1.1 gtk_clist_append(GTK_CLIST(volume_list), &file);
568     gtk_widget_destroy(assoc->req);
569     delete assoc;
570     }
571    
572     // Volume selected for creation
573     static void create_volume_ok(GtkWidget *button, file_req_assoc *assoc)
574     {
575 gbeauche 1.28 gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
576 cebix 1.1
577 gbeauche 1.28 const gchar *str = gtk_entry_get_text(GTK_ENTRY(assoc->entry));
578 cebix 1.1 int size = atoi(str);
579    
580     char cmd[1024];
581     sprintf(cmd, "dd if=/dev/zero \"of=%s\" bs=1024k count=%d", file, size);
582     int ret = system(cmd);
583     if (ret == 0)
584     gtk_clist_append(GTK_CLIST(volume_list), &file);
585     gtk_widget_destroy(GTK_WIDGET(assoc->req));
586     delete assoc;
587     }
588    
589     // "Add Volume" button clicked
590     static void cb_add_volume(...)
591     {
592     GtkWidget *req = gtk_file_selection_new(GetString(STR_ADD_VOLUME_TITLE));
593     gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
594     gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(add_volume_ok), new file_req_assoc(req, NULL));
595     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
596     gtk_widget_show(req);
597     }
598    
599     // "Create Hardfile" button clicked
600     static void cb_create_volume(...)
601     {
602     GtkWidget *req = gtk_file_selection_new(GetString(STR_CREATE_VOLUME_TITLE));
603    
604     GtkWidget *box = gtk_hbox_new(FALSE, 4);
605     gtk_widget_show(box);
606     GtkWidget *label = gtk_label_new(GetString(STR_HARDFILE_SIZE_CTRL));
607     gtk_widget_show(label);
608     GtkWidget *entry = gtk_entry_new();
609     gtk_widget_show(entry);
610     char str[32];
611     sprintf(str, "%d", 40);
612     gtk_entry_set_text(GTK_ENTRY(entry), str);
613     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
614     gtk_box_pack_start(GTK_BOX(box), entry, FALSE, FALSE, 0);
615     gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(req)->main_vbox), box, FALSE, FALSE, 0);
616    
617     gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
618     gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(create_volume_ok), new file_req_assoc(req, entry));
619     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
620     gtk_widget_show(req);
621     }
622    
623     // "Remove Volume" button clicked
624     static void cb_remove_volume(...)
625     {
626     gtk_clist_remove(GTK_CLIST(volume_list), selected_volume);
627     }
628    
629     // "Boot From" selected
630 cebix 1.14 static void mn_boot_any(...) {PrefsReplaceInt32("bootdriver", 0);}
631     static void mn_boot_cdrom(...) {PrefsReplaceInt32("bootdriver", CDROMRefNum);}
632 cebix 1.1
633     // "No CD-ROM Driver" button toggled
634     static void tb_nocdrom(GtkWidget *widget)
635     {
636     PrefsReplaceBool("nocdrom", GTK_TOGGLE_BUTTON(widget)->active);
637     }
638    
639     // Read settings from widgets and set preferences
640     static void read_volumes_settings(void)
641     {
642     while (PrefsFindString("disk"))
643     PrefsRemoveItem("disk");
644    
645     for (int i=0; i<GTK_CLIST(volume_list)->rows; i++) {
646     char *str;
647     gtk_clist_get_text(GTK_CLIST(volume_list), i, 0, &str);
648     PrefsAddString("disk", str);
649     }
650 cebix 1.6
651 cebix 1.21 PrefsReplaceString("extfs", get_file_entry_path(w_extfs));
652 cebix 1.1 }
653    
654     // Create "Volumes" pane
655     static void create_volumes_pane(GtkWidget *top)
656     {
657     GtkWidget *box, *scroll, *menu;
658    
659     box = make_pane(top, STR_VOLUMES_PANE_TITLE);
660    
661     scroll = gtk_scrolled_window_new(NULL, NULL);
662     gtk_widget_show(scroll);
663     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
664     volume_list = gtk_clist_new(1);
665     gtk_widget_show(volume_list);
666     gtk_clist_set_selection_mode(GTK_CLIST(volume_list), GTK_SELECTION_SINGLE);
667     gtk_clist_set_shadow_type(GTK_CLIST(volume_list), GTK_SHADOW_NONE);
668 cebix 1.5 gtk_clist_set_reorderable(GTK_CLIST(volume_list), true);
669 cebix 1.1 gtk_signal_connect(GTK_OBJECT(volume_list), "select_row", GTK_SIGNAL_FUNC(cl_selected), NULL);
670     char *str;
671     int32 index = 0;
672 cebix 1.21 while ((str = const_cast<char *>(PrefsFindString("disk", index++))) != NULL)
673 cebix 1.1 gtk_clist_append(GTK_CLIST(volume_list), &str);
674     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), volume_list);
675     gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 0);
676     selected_volume = 0;
677    
678     static const opt_desc buttons[] = {
679     {STR_ADD_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_add_volume)},
680     {STR_CREATE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_create_volume)},
681     {STR_REMOVE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_remove_volume)},
682     {0, NULL},
683     };
684     make_button_box(box, 0, buttons);
685     make_separator(box);
686 cebix 1.6
687 cebix 1.21 w_extfs = make_file_entry(box, STR_EXTFS_CTRL, "extfs", true);
688 cebix 1.1
689     static const opt_desc options[] = {
690     {STR_BOOT_ANY_LAB, GTK_SIGNAL_FUNC(mn_boot_any)},
691     {STR_BOOT_CDROM_LAB, GTK_SIGNAL_FUNC(mn_boot_cdrom)},
692     {0, NULL}
693     };
694 cebix 1.14 int bootdriver = PrefsFindInt32("bootdriver"), active = 0;
695 cebix 1.1 switch (bootdriver) {
696     case 0: active = 0; break;
697     case CDROMRefNum: active = 1; break;
698     }
699     menu = make_option_menu(box, STR_BOOTDRIVER_CTRL, options, active);
700    
701     make_checkbox(box, STR_NOCDROM_CTRL, "nocdrom", GTK_SIGNAL_FUNC(tb_nocdrom));
702     }
703    
704    
705     /*
706 gbeauche 1.23 * "JIT Compiler" pane
707     */
708    
709     static GtkWidget *w_jit_fpu;
710     static GtkWidget *w_jit_atraps;
711     static GtkWidget *w_jit_cache_size;
712     static GtkWidget *w_jit_lazy_flush;
713 gbeauche 1.27 static GtkWidget *w_jit_follow_const_jumps;
714 gbeauche 1.23
715 gbeauche 1.35 // Are we running a JIT capable CPU?
716     static bool is_jit_capable(void)
717     {
718     #if USE_JIT && (defined __i386__ || defined __x86_64__)
719     return true;
720     #elif defined __APPLE__ && defined __MACH__
721     // XXX run-time detect so that we can use a PPC GUI prefs editor
722     static char cpu[10];
723     if (cpu[0] == 0) {
724     FILE *fp = popen("uname -p", "r");
725     if (fp == NULL)
726     return false;
727     fgets(cpu, sizeof(cpu) - 1, fp);
728     fclose(fp);
729     }
730     if (cpu[0] == 'i' && cpu[2] == '8' && cpu[3] == '6') // XXX assuming i?86
731     return true;
732     #endif
733     return false;
734     }
735    
736 gbeauche 1.23 // Set sensitivity of widgets
737     static void set_jit_sensitive(void)
738     {
739     const bool jit_enabled = PrefsFindBool("jit");
740     gtk_widget_set_sensitive(w_jit_fpu, jit_enabled);
741     gtk_widget_set_sensitive(w_jit_cache_size, jit_enabled);
742     gtk_widget_set_sensitive(w_jit_lazy_flush, jit_enabled);
743 gbeauche 1.27 gtk_widget_set_sensitive(w_jit_follow_const_jumps, jit_enabled);
744 gbeauche 1.23 }
745    
746     // "Use JIT Compiler" button toggled
747     static void tb_jit(GtkWidget *widget)
748     {
749     PrefsReplaceBool("jit", GTK_TOGGLE_BUTTON(widget)->active);
750     set_jit_sensitive();
751     }
752    
753     // "Compile FPU Instructions" button toggled
754     static void tb_jit_fpu(GtkWidget *widget)
755     {
756     PrefsReplaceBool("jitfpu", GTK_TOGGLE_BUTTON(widget)->active);
757     }
758    
759     // "Lazy translation cache invalidation" button toggled
760     static void tb_jit_lazy_flush(GtkWidget *widget)
761     {
762     PrefsReplaceBool("jitlazyflush", GTK_TOGGLE_BUTTON(widget)->active);
763     }
764    
765 gbeauche 1.27 // "Translate through constant jumps (inline blocks)" button toggled
766     static void tb_jit_follow_const_jumps(GtkWidget *widget)
767     {
768     PrefsReplaceBool("jitinline", GTK_TOGGLE_BUTTON(widget)->active);
769     }
770    
771 gbeauche 1.23 // Read settings from widgets and set preferences
772     static void read_jit_settings(void)
773     {
774 gbeauche 1.35 bool jit_enabled = is_jit_capable() && PrefsFindBool("jit");
775 gbeauche 1.23 if (jit_enabled) {
776     const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_jit_cache_size)->entry));
777     PrefsReplaceInt32("jitcachesize", atoi(str));
778     }
779     }
780    
781     // Create "JIT Compiler" pane
782     static void create_jit_pane(GtkWidget *top)
783     {
784 gbeauche 1.35 if (!is_jit_capable())
785     return;
786    
787 gbeauche 1.23 GtkWidget *box, *table, *label, *menu;
788     char str[32];
789    
790     box = make_pane(top, STR_JIT_PANE_TITLE);
791     make_checkbox(box, STR_JIT_CTRL, "jit", GTK_SIGNAL_FUNC(tb_jit));
792    
793     w_jit_fpu = make_checkbox(box, STR_JIT_FPU_CTRL, "jitfpu", GTK_SIGNAL_FUNC(tb_jit_fpu));
794    
795     // Translation cache size
796     static const combo_desc options[] = {
797     STR_JIT_CACHE_SIZE_2MB_LAB,
798     STR_JIT_CACHE_SIZE_4MB_LAB,
799     STR_JIT_CACHE_SIZE_8MB_LAB,
800     STR_JIT_CACHE_SIZE_16MB_LAB,
801     0
802     };
803     w_jit_cache_size = make_combobox(box, STR_JIT_CACHE_SIZE_CTRL, "jitcachesize", options);
804    
805     // Lazy translation cache invalidation
806     w_jit_lazy_flush = make_checkbox(box, STR_JIT_LAZY_CINV_CTRL, "jitlazyflush", GTK_SIGNAL_FUNC(tb_jit_lazy_flush));
807 gbeauche 1.27
808     // Follow constant jumps (inline basic blocks)
809     w_jit_follow_const_jumps = make_checkbox(box, STR_JIT_FOLLOW_CONST_JUMPS, "jitinline", GTK_SIGNAL_FUNC(tb_jit_follow_const_jumps));
810    
811 gbeauche 1.23 set_jit_sensitive();
812     }
813    
814     /*
815 cebix 1.1 * "SCSI" pane
816     */
817    
818     static GtkWidget *w_scsi[7];
819    
820     // Read settings from widgets and set preferences
821     static void read_scsi_settings(void)
822     {
823     for (int id=0; id<7; id++) {
824     char prefs_name[32];
825     sprintf(prefs_name, "scsi%d", id);
826 cebix 1.21 const char *str = get_file_entry_path(w_scsi[id]);
827 cebix 1.1 if (str && strlen(str))
828     PrefsReplaceString(prefs_name, str);
829     else
830     PrefsRemoveItem(prefs_name);
831     }
832     }
833    
834     // Create "SCSI" pane
835     static void create_scsi_pane(GtkWidget *top)
836     {
837     GtkWidget *box;
838    
839     box = make_pane(top, STR_SCSI_PANE_TITLE);
840    
841     for (int id=0; id<7; id++) {
842     char prefs_name[32];
843     sprintf(prefs_name, "scsi%d", id);
844 cebix 1.21 w_scsi[id] = make_file_entry(box, STR_SCSI_ID_0 + id, prefs_name);
845 cebix 1.1 }
846     }
847    
848    
849     /*
850     * "Graphics/Sound" pane
851     */
852    
853     // Display types
854     enum {
855     DISPLAY_WINDOW,
856     DISPLAY_SCREEN
857     };
858    
859     static GtkWidget *w_frameskip, *w_display_x, *w_display_y;
860     static GtkWidget *l_frameskip, *l_display_x, *l_display_y;
861     static int display_type;
862     static int dis_width, dis_height;
863    
864 cebix 1.11 #ifdef ENABLE_FBDEV_DGA
865 cebix 1.7 static GtkWidget *w_fbdev_name, *w_fbdevice_file;
866     static GtkWidget *l_fbdev_name, *l_fbdevice_file;
867     static char fbdev_name[256];
868     #endif
869    
870 cebix 1.24 static GtkWidget *w_dspdevice_file, *w_mixerdevice_file;
871    
872 cebix 1.1 // Hide/show graphics widgets
873     static void hide_show_graphics_widgets(void)
874     {
875     switch (display_type) {
876     case DISPLAY_WINDOW:
877     gtk_widget_show(w_frameskip); gtk_widget_show(l_frameskip);
878 cebix 1.11 #ifdef ENABLE_FBDEV_DGA
879 cebix 1.7 gtk_widget_show(w_display_x); gtk_widget_show(l_display_x);
880     gtk_widget_show(w_display_y); gtk_widget_show(l_display_y);
881     gtk_widget_hide(w_fbdev_name); gtk_widget_hide(l_fbdev_name);
882     #endif
883 cebix 1.1 break;
884     case DISPLAY_SCREEN:
885     gtk_widget_hide(w_frameskip); gtk_widget_hide(l_frameskip);
886 cebix 1.11 #ifdef ENABLE_FBDEV_DGA
887 cebix 1.7 gtk_widget_hide(w_display_x); gtk_widget_hide(l_display_x);
888     gtk_widget_hide(w_display_y); gtk_widget_hide(l_display_y);
889     gtk_widget_show(w_fbdev_name); gtk_widget_show(l_fbdev_name);
890     #endif
891 cebix 1.1 break;
892     }
893     }
894    
895     // "Window" video type selected
896     static void mn_window(...)
897     {
898     display_type = DISPLAY_WINDOW;
899     hide_show_graphics_widgets();
900     }
901    
902     // "Fullscreen" video type selected
903     static void mn_fullscreen(...)
904     {
905     display_type = DISPLAY_SCREEN;
906     hide_show_graphics_widgets();
907     }
908    
909     // "5 Hz".."60Hz" selected
910     static void mn_5hz(...) {PrefsReplaceInt32("frameskip", 12);}
911     static void mn_7hz(...) {PrefsReplaceInt32("frameskip", 8);}
912     static void mn_10hz(...) {PrefsReplaceInt32("frameskip", 6);}
913     static void mn_15hz(...) {PrefsReplaceInt32("frameskip", 4);}
914     static void mn_30hz(...) {PrefsReplaceInt32("frameskip", 2);}
915     static void mn_60hz(...) {PrefsReplaceInt32("frameskip", 1);}
916 cebix 1.12 static void mn_dynamic(...) {PrefsReplaceInt32("frameskip", 0);}
917 cebix 1.1
918 cebix 1.24 // Set sensitivity of widgets
919     static void set_graphics_sensitive(void)
920     {
921     const bool sound_enabled = !PrefsFindBool("nosound");
922     gtk_widget_set_sensitive(w_dspdevice_file, sound_enabled);
923     gtk_widget_set_sensitive(w_mixerdevice_file, sound_enabled);
924     }
925    
926 cebix 1.1 // "Disable Sound Output" button toggled
927     static void tb_nosound(GtkWidget *widget)
928     {
929     PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active);
930 cebix 1.24 set_graphics_sensitive();
931 cebix 1.1 }
932    
933     // Read graphics preferences
934     static void parse_graphics_prefs(void)
935     {
936     display_type = DISPLAY_WINDOW;
937     dis_width = 512;
938     dis_height = 384;
939 cebix 1.11 #ifdef ENABLE_FBDEV_DGA
940 cebix 1.7 fbdev_name[0] = 0;
941     #endif
942 cebix 1.1
943     const char *str = PrefsFindString("screen");
944     if (str) {
945     if (sscanf(str, "win/%d/%d", &dis_width, &dis_height) == 2)
946     display_type = DISPLAY_WINDOW;
947 cebix 1.11 #ifdef ENABLE_FBDEV_DGA
948 cebix 1.7 else if (sscanf(str, "dga/%255s", fbdev_name) == 1)
949     #else
950 cebix 1.2 else if (sscanf(str, "dga/%d/%d", &dis_width, &dis_height) == 2)
951 cebix 1.7 #endif
952 cebix 1.1 display_type = DISPLAY_SCREEN;
953     }
954     }
955    
956     // Read settings from widgets and set preferences
957     static void read_graphics_settings(void)
958     {
959     const char *str;
960    
961     str = gtk_entry_get_text(GTK_ENTRY(w_display_x));
962     dis_width = atoi(str);
963    
964     str = gtk_entry_get_text(GTK_ENTRY(w_display_y));
965     dis_height = atoi(str);
966    
967     char pref[256];
968     switch (display_type) {
969     case DISPLAY_WINDOW:
970     sprintf(pref, "win/%d/%d", dis_width, dis_height);
971     break;
972     case DISPLAY_SCREEN:
973 cebix 1.11 #ifdef ENABLE_FBDEV_DGA
974 cebix 1.7 str = gtk_entry_get_text(GTK_ENTRY(w_fbdev_name));
975     sprintf(pref, "dga/%s", str);
976     #else
977 cebix 1.2 sprintf(pref, "dga/%d/%d", dis_width, dis_height);
978 cebix 1.7 #endif
979 cebix 1.1 break;
980     default:
981     PrefsRemoveItem("screen");
982     return;
983     }
984     PrefsReplaceString("screen", pref);
985 cebix 1.21
986     #ifdef ENABLE_FBDEV_DGA
987     str = get_file_entry_path(w_fbdevice_file);
988     if (str && strlen(str))
989     PrefsReplaceString("fbdevicefile", str);
990     else
991     PrefsRemoveItem("fbdevicefile");
992     #endif
993 cebix 1.24 PrefsReplaceString("dsp", get_file_entry_path(w_dspdevice_file));
994     PrefsReplaceString("mixer", get_file_entry_path(w_mixerdevice_file));
995 cebix 1.1 }
996    
997     // Create "Graphics/Sound" pane
998     static void create_graphics_pane(GtkWidget *top)
999     {
1000 cebix 1.2 GtkWidget *box, *table, *label, *opt, *menu, *combo;
1001 cebix 1.1 char str[32];
1002    
1003     parse_graphics_prefs();
1004    
1005     box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE);
1006 cebix 1.7 table = make_table(box, 2, 5);
1007 cebix 1.1
1008     label = gtk_label_new(GetString(STR_VIDEO_TYPE_CTRL));
1009     gtk_widget_show(label);
1010     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1011    
1012     opt = gtk_option_menu_new();
1013     gtk_widget_show(opt);
1014     menu = gtk_menu_new();
1015     add_menu_item(menu, STR_WINDOW_LAB, GTK_SIGNAL_FUNC(mn_window));
1016     add_menu_item(menu, STR_FULLSCREEN_LAB, GTK_SIGNAL_FUNC(mn_fullscreen));
1017     switch (display_type) {
1018     case DISPLAY_WINDOW:
1019     gtk_menu_set_active(GTK_MENU(menu), 0);
1020     break;
1021     case DISPLAY_SCREEN:
1022     gtk_menu_set_active(GTK_MENU(menu), 1);
1023     break;
1024     }
1025     gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
1026     gtk_table_attach(GTK_TABLE(table), opt, 1, 2, 0, 1, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
1027    
1028     l_frameskip = gtk_label_new(GetString(STR_FRAMESKIP_CTRL));
1029     gtk_widget_show(l_frameskip);
1030     gtk_table_attach(GTK_TABLE(table), l_frameskip, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1031    
1032     w_frameskip = gtk_option_menu_new();
1033     gtk_widget_show(w_frameskip);
1034     menu = gtk_menu_new();
1035     add_menu_item(menu, STR_REF_5HZ_LAB, GTK_SIGNAL_FUNC(mn_5hz));
1036     add_menu_item(menu, STR_REF_7_5HZ_LAB, GTK_SIGNAL_FUNC(mn_7hz));
1037     add_menu_item(menu, STR_REF_10HZ_LAB, GTK_SIGNAL_FUNC(mn_10hz));
1038     add_menu_item(menu, STR_REF_15HZ_LAB, GTK_SIGNAL_FUNC(mn_15hz));
1039     add_menu_item(menu, STR_REF_30HZ_LAB, GTK_SIGNAL_FUNC(mn_30hz));
1040     add_menu_item(menu, STR_REF_60HZ_LAB, GTK_SIGNAL_FUNC(mn_60hz));
1041 cebix 1.12 add_menu_item(menu, STR_REF_DYNAMIC_LAB, GTK_SIGNAL_FUNC(mn_dynamic));
1042 cebix 1.1 int frameskip = PrefsFindInt32("frameskip");
1043 cebix 1.12 int item = -1;
1044 cebix 1.1 switch (frameskip) {
1045 cebix 1.12 case 12: item = 0; break;
1046     case 8: item = 1; break;
1047     case 6: item = 2; break;
1048     case 4: item = 3; break;
1049     case 2: item = 4; break;
1050     case 1: item = 5; break;
1051     case 0: item = 6; break;
1052 cebix 1.1 }
1053 cebix 1.12 if (item >= 0)
1054     gtk_menu_set_active(GTK_MENU(menu), item);
1055 cebix 1.1 gtk_option_menu_set_menu(GTK_OPTION_MENU(w_frameskip), menu);
1056     gtk_table_attach(GTK_TABLE(table), w_frameskip, 1, 2, 1, 2, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
1057    
1058     l_display_x = gtk_label_new(GetString(STR_DISPLAY_X_CTRL));
1059     gtk_widget_show(l_display_x);
1060     gtk_table_attach(GTK_TABLE(table), l_display_x, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1061    
1062 cebix 1.2 combo = gtk_combo_new();
1063     gtk_widget_show(combo);
1064     GList *glist1 = NULL;
1065 cebix 1.4 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_512_LAB));
1066     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_640_LAB));
1067     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_800_LAB));
1068     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_1024_LAB));
1069     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_MAX_LAB));
1070 cebix 1.2 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist1);
1071     if (dis_width)
1072     sprintf(str, "%d", dis_width);
1073     else
1074 cebix 1.3 strcpy(str, GetString(STR_SIZE_MAX_LAB));
1075 cebix 1.2 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1076     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
1077     w_display_x = GTK_COMBO(combo)->entry;
1078 cebix 1.1
1079     l_display_y = gtk_label_new(GetString(STR_DISPLAY_Y_CTRL));
1080     gtk_widget_show(l_display_y);
1081     gtk_table_attach(GTK_TABLE(table), l_display_y, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1082    
1083 cebix 1.2 combo = gtk_combo_new();
1084     gtk_widget_show(combo);
1085     GList *glist2 = NULL;
1086 cebix 1.4 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_384_LAB));
1087     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_480_LAB));
1088     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_600_LAB));
1089     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_768_LAB));
1090     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_MAX_LAB));
1091 cebix 1.2 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist2);
1092     if (dis_height)
1093     sprintf(str, "%d", dis_height);
1094     else
1095 cebix 1.3 strcpy(str, GetString(STR_SIZE_MAX_LAB));
1096 cebix 1.2 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1097     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
1098     w_display_y = GTK_COMBO(combo)->entry;
1099 cebix 1.7
1100 cebix 1.11 #ifdef ENABLE_FBDEV_DGA
1101 cebix 1.7 l_fbdev_name = gtk_label_new(GetString(STR_FBDEV_NAME_CTRL));
1102     gtk_widget_show(l_fbdev_name);
1103     gtk_table_attach(GTK_TABLE(table), l_fbdev_name, 0, 1, 4, 5, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1104    
1105     w_fbdev_name = gtk_entry_new();
1106     gtk_widget_show(w_fbdev_name);
1107     gtk_entry_set_text(GTK_ENTRY(w_fbdev_name), fbdev_name);
1108     gtk_table_attach(GTK_TABLE(table), w_fbdev_name, 1, 2, 4, 5, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1109    
1110 cebix 1.21 w_fbdevice_file = make_file_entry(box, STR_FBDEVICE_FILE_CTRL, "fbdevicefile");
1111 cebix 1.7 #endif
1112 cebix 1.1
1113 cebix 1.13 make_separator(box);
1114 cebix 1.1 make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound));
1115 cebix 1.24 w_dspdevice_file = make_file_entry(box, STR_DSPDEVICE_FILE_CTRL, "dsp");
1116     w_mixerdevice_file = make_file_entry(box, STR_MIXERDEVICE_FILE_CTRL, "mixer");
1117    
1118     set_graphics_sensitive();
1119 cebix 1.1
1120     hide_show_graphics_widgets();
1121     }
1122    
1123    
1124     /*
1125 cebix 1.13 * "Input" pane
1126     */
1127    
1128     static GtkWidget *w_keycode_file;
1129     static GtkWidget *w_mouse_wheel_lines;
1130    
1131     // Set sensitivity of widgets
1132     static void set_input_sensitive(void)
1133     {
1134 gbeauche 1.29 const bool use_keycodes = PrefsFindBool("keycodes");
1135     gtk_widget_set_sensitive(w_keycode_file, use_keycodes);
1136     gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_keycode_file), "chooser_button")), use_keycodes);
1137 cebix 1.14 gtk_widget_set_sensitive(w_mouse_wheel_lines, PrefsFindInt32("mousewheelmode") == 1);
1138 cebix 1.13 }
1139    
1140     // "Use Raw Keycodes" button toggled
1141     static void tb_keycodes(GtkWidget *widget)
1142     {
1143     PrefsReplaceBool("keycodes", GTK_TOGGLE_BUTTON(widget)->active);
1144     set_input_sensitive();
1145     }
1146    
1147     // "Mouse Wheel Mode" selected
1148 cebix 1.14 static void mn_wheel_page(...) {PrefsReplaceInt32("mousewheelmode", 0); set_input_sensitive();}
1149     static void mn_wheel_cursor(...) {PrefsReplaceInt32("mousewheelmode", 1); set_input_sensitive();}
1150 cebix 1.13
1151     // Read settings from widgets and set preferences
1152     static void read_input_settings(void)
1153     {
1154 cebix 1.21 const char *str = get_file_entry_path(w_keycode_file);
1155 cebix 1.13 if (str && strlen(str))
1156     PrefsReplaceString("keycodefile", str);
1157     else
1158     PrefsRemoveItem("keycodefile");
1159    
1160 cebix 1.14 PrefsReplaceInt32("mousewheellines", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_mouse_wheel_lines)));
1161 cebix 1.13 }
1162    
1163     // Create "Input" pane
1164     static void create_input_pane(GtkWidget *top)
1165     {
1166 gbeauche 1.29 GtkWidget *box, *hbox, *menu, *label, *button;
1167 cebix 1.13 GtkObject *adj;
1168    
1169     box = make_pane(top, STR_INPUT_PANE_TITLE);
1170    
1171     make_checkbox(box, STR_KEYCODES_CTRL, "keycodes", GTK_SIGNAL_FUNC(tb_keycodes));
1172 gbeauche 1.29
1173     hbox = gtk_hbox_new(FALSE, 4);
1174     gtk_widget_show(hbox);
1175     gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1176    
1177     label = gtk_label_new(GetString(STR_KEYCODES_CTRL));
1178     gtk_widget_show(label);
1179     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1180    
1181     const char *str = PrefsFindString("keycodefile");
1182     if (str == NULL)
1183     str = "";
1184    
1185     w_keycode_file = gtk_entry_new();
1186     gtk_entry_set_text(GTK_ENTRY(w_keycode_file), str);
1187     gtk_widget_show(w_keycode_file);
1188     gtk_box_pack_start(GTK_BOX(hbox), w_keycode_file, TRUE, TRUE, 0);
1189    
1190     button = make_browse_button(w_keycode_file);
1191     gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1192     g_object_set_data(G_OBJECT(w_keycode_file), "chooser_button", button);
1193 cebix 1.13
1194     make_separator(box);
1195    
1196     static const opt_desc options[] = {
1197     {STR_MOUSEWHEELMODE_PAGE_LAB, GTK_SIGNAL_FUNC(mn_wheel_page)},
1198     {STR_MOUSEWHEELMODE_CURSOR_LAB, GTK_SIGNAL_FUNC(mn_wheel_cursor)},
1199     {0, NULL}
1200     };
1201 cebix 1.14 int wheelmode = PrefsFindInt32("mousewheelmode"), active = 0;
1202 cebix 1.13 switch (wheelmode) {
1203     case 0: active = 0; break;
1204     case 1: active = 1; break;
1205     }
1206     menu = make_option_menu(box, STR_MOUSEWHEELMODE_CTRL, options, active);
1207    
1208     hbox = gtk_hbox_new(FALSE, 4);
1209     gtk_widget_show(hbox);
1210     gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1211    
1212     label = gtk_label_new(GetString(STR_MOUSEWHEELLINES_CTRL));
1213     gtk_widget_show(label);
1214     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1215    
1216 cebix 1.14 adj = gtk_adjustment_new(PrefsFindInt32("mousewheellines"), 1, 1000, 1, 5, 0);
1217 cebix 1.13 w_mouse_wheel_lines = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0);
1218     gtk_widget_show(w_mouse_wheel_lines);
1219     gtk_box_pack_start(GTK_BOX(hbox), w_mouse_wheel_lines, FALSE, FALSE, 0);
1220    
1221     set_input_sensitive();
1222     }
1223    
1224    
1225     /*
1226 cebix 1.1 * "Serial/Network" pane
1227     */
1228    
1229 cebix 1.18 static GtkWidget *w_seriala, *w_serialb, *w_ether, *w_udp_port;
1230    
1231     // Set sensitivity of widgets
1232     static void set_serial_sensitive(void)
1233     {
1234     #if SUPPORTS_UDP_TUNNEL
1235     gtk_widget_set_sensitive(w_ether, !PrefsFindBool("udptunnel"));
1236     gtk_widget_set_sensitive(w_udp_port, PrefsFindBool("udptunnel"));
1237     #endif
1238     }
1239    
1240     // "Tunnel AppleTalk over IP" button toggled
1241     static void tb_udptunnel(GtkWidget *widget)
1242     {
1243     PrefsReplaceBool("udptunnel", GTK_TOGGLE_BUTTON(widget)->active);
1244     set_serial_sensitive();
1245     }
1246 cebix 1.1
1247     // Read settings from widgets and set preferences
1248     static void read_serial_settings(void)
1249     {
1250     const char *str;
1251    
1252     str = gtk_entry_get_text(GTK_ENTRY(w_seriala));
1253     PrefsReplaceString("seriala", str);
1254    
1255     str = gtk_entry_get_text(GTK_ENTRY(w_serialb));
1256     PrefsReplaceString("serialb", str);
1257    
1258     str = gtk_entry_get_text(GTK_ENTRY(w_ether));
1259     if (str && strlen(str))
1260     PrefsReplaceString("ether", str);
1261     else
1262     PrefsRemoveItem("ether");
1263 cebix 1.18
1264     #if SUPPORTS_UDP_TUNNEL
1265     PrefsReplaceInt32("udpport", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_udp_port)));
1266     #endif
1267 cebix 1.1 }
1268    
1269     // Add names of serial devices
1270     static gint gl_str_cmp(gconstpointer a, gconstpointer b)
1271     {
1272     return strcmp((char *)a, (char *)b);
1273     }
1274    
1275     static GList *add_serial_names(void)
1276     {
1277     GList *glist = NULL;
1278    
1279     // Search /dev for ttyS* and lp*
1280     DIR *d = opendir("/dev");
1281     if (d) {
1282     struct dirent *de;
1283     while ((de = readdir(d)) != NULL) {
1284     #if defined(__linux__)
1285     if (strncmp(de->d_name, "ttyS", 4) == 0 || strncmp(de->d_name, "lp", 2) == 0) {
1286     #elif defined(__FreeBSD__)
1287     if (strncmp(de->d_name, "cuaa", 4) == 0 || strncmp(de->d_name, "lpt", 3) == 0) {
1288 cebix 1.4 #elif defined(__NetBSD__)
1289     if (strncmp(de->d_name, "tty0", 4) == 0 || strncmp(de->d_name, "lpt", 3) == 0) {
1290 cebix 1.1 #elif defined(sgi)
1291     if (strncmp(de->d_name, "ttyf", 4) == 0 || strncmp(de->d_name, "plp", 3) == 0) {
1292     #else
1293     if (false) {
1294     #endif
1295     char *str = new char[64];
1296     sprintf(str, "/dev/%s", de->d_name);
1297     glist = g_list_append(glist, str);
1298     }
1299     }
1300     closedir(d);
1301     }
1302     if (glist)
1303     g_list_sort(glist, gl_str_cmp);
1304     else
1305 cebix 1.4 glist = g_list_append(glist, (void *)GetString(STR_NONE_LAB));
1306 cebix 1.1 return glist;
1307     }
1308    
1309     // Add names of ethernet interfaces
1310     static GList *add_ether_names(void)
1311     {
1312     GList *glist = NULL;
1313    
1314     // Get list of all Ethernet interfaces
1315     int s = socket(PF_INET, SOCK_DGRAM, 0);
1316     if (s >= 0) {
1317     char inbuf[8192];
1318     struct ifconf ifc;
1319     ifc.ifc_len = sizeof(inbuf);
1320     ifc.ifc_buf = inbuf;
1321     if (ioctl(s, SIOCGIFCONF, &ifc) == 0) {
1322     struct ifreq req, *ifr = ifc.ifc_req;
1323     for (int i=0; i<ifc.ifc_len; i+=sizeof(ifreq), ifr++) {
1324     req = *ifr;
1325 cebix 1.4 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(sgi)
1326 cebix 1.1 if (ioctl(s, SIOCGIFADDR, &req) == 0 && (req.ifr_addr.sa_family == ARPHRD_ETHER || req.ifr_addr.sa_family == ARPHRD_ETHER+1)) {
1327 cebix 1.4 #elif defined(__linux__)
1328     if (ioctl(s, SIOCGIFHWADDR, &req) == 0 && req.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
1329 cebix 1.1 #else
1330 cebix 1.4 if (false) {
1331 cebix 1.1 #endif
1332     char *str = new char[64];
1333     strncpy(str, ifr->ifr_name, 63);
1334     glist = g_list_append(glist, str);
1335     }
1336     }
1337     }
1338     close(s);
1339     }
1340 gbeauche 1.27 #ifdef HAVE_SLIRP
1341     static char s_slirp[] = "slirp";
1342     glist = g_list_append(glist, s_slirp);
1343     #endif
1344 cebix 1.1 if (glist)
1345     g_list_sort(glist, gl_str_cmp);
1346     else
1347 cebix 1.4 glist = g_list_append(glist, (void *)GetString(STR_NONE_LAB));
1348 cebix 1.1 return glist;
1349     }
1350    
1351     // Create "Serial/Network" pane
1352     static void create_serial_pane(GtkWidget *top)
1353     {
1354 cebix 1.18 GtkWidget *box, *hbox, *table, *label, *combo, *sep;
1355     GtkObject *adj;
1356 cebix 1.1
1357     box = make_pane(top, STR_SERIAL_NETWORK_PANE_TITLE);
1358 cebix 1.13 table = make_table(box, 2, 4);
1359 cebix 1.1
1360     label = gtk_label_new(GetString(STR_SERIALA_CTRL));
1361     gtk_widget_show(label);
1362     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1363    
1364 cebix 1.18 GList *glist = add_serial_names();
1365 cebix 1.1 combo = gtk_combo_new();
1366     gtk_widget_show(combo);
1367     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1368     const char *str = PrefsFindString("seriala");
1369     if (str == NULL)
1370     str = "";
1371     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1372     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1373     w_seriala = GTK_COMBO(combo)->entry;
1374    
1375     label = gtk_label_new(GetString(STR_SERIALB_CTRL));
1376     gtk_widget_show(label);
1377     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1378    
1379     combo = gtk_combo_new();
1380     gtk_widget_show(combo);
1381     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1382     str = PrefsFindString("serialb");
1383     if (str == NULL)
1384     str = "";
1385     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1386     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 1, 2, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1387     w_serialb = GTK_COMBO(combo)->entry;
1388    
1389 cebix 1.13 sep = gtk_hseparator_new();
1390     gtk_widget_show(sep);
1391     gtk_table_attach(GTK_TABLE(table), sep, 0, 2, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1392    
1393 cebix 1.1 label = gtk_label_new(GetString(STR_ETHERNET_IF_CTRL));
1394     gtk_widget_show(label);
1395 cebix 1.13 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1396 cebix 1.1
1397     glist = add_ether_names();
1398     combo = gtk_combo_new();
1399     gtk_widget_show(combo);
1400     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1401     str = PrefsFindString("ether");
1402     if (str == NULL)
1403     str = "";
1404     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1405 cebix 1.13 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1406 cebix 1.1 w_ether = GTK_COMBO(combo)->entry;
1407 cebix 1.18
1408     #if SUPPORTS_UDP_TUNNEL
1409     make_checkbox(box, STR_UDPTUNNEL_CTRL, "udptunnel", GTK_SIGNAL_FUNC(tb_udptunnel));
1410    
1411     hbox = gtk_hbox_new(FALSE, 4);
1412     gtk_widget_show(hbox);
1413     gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1414    
1415     label = gtk_label_new(GetString(STR_UDPPORT_CTRL));
1416     gtk_widget_show(label);
1417     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1418    
1419     adj = gtk_adjustment_new(PrefsFindInt32("udpport"), 1, 65535, 1, 5, 0);
1420     w_udp_port = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0);
1421     gtk_widget_show(w_udp_port);
1422     gtk_box_pack_start(GTK_BOX(hbox), w_udp_port, FALSE, FALSE, 0);
1423     #endif
1424    
1425     set_serial_sensitive();
1426 cebix 1.1 }
1427    
1428    
1429     /*
1430     * "Memory/Misc" pane
1431     */
1432    
1433 gbeauche 1.29 static GtkWidget *w_ramsize;
1434 cebix 1.1 static GtkWidget *w_rom_file;
1435    
1436 gbeauche 1.22 // "Ignore SEGV" button toggled
1437     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1438     static void tb_ignoresegv(GtkWidget *widget)
1439     {
1440     PrefsReplaceBool("ignoresegv", GTK_TOGGLE_BUTTON(widget)->active);
1441     }
1442     #endif
1443    
1444 cebix 1.1 // Model ID selected
1445     static void mn_modelid_5(...) {PrefsReplaceInt32("modelid", 5);}
1446     static void mn_modelid_14(...) {PrefsReplaceInt32("modelid", 14);}
1447    
1448 cebix 1.9 // CPU/FPU type
1449     static void mn_cpu_68020(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", false);}
1450     static void mn_cpu_68020_fpu(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", true);}
1451     static void mn_cpu_68030(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", false);}
1452     static void mn_cpu_68030_fpu(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", true);}
1453     static void mn_cpu_68040(...) {PrefsReplaceInt32("cpu", 4); PrefsReplaceBool("fpu", true);}
1454 cebix 1.8
1455 cebix 1.1 // Read settings from widgets and set preferences
1456     static void read_memory_settings(void)
1457     {
1458 gbeauche 1.29 const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_ramsize)->entry));
1459     PrefsReplaceInt32("ramsize", atoi(str) << 20);
1460 cebix 1.1
1461 gbeauche 1.29 str = get_file_entry_path(w_rom_file);
1462 cebix 1.1 if (str && strlen(str))
1463     PrefsReplaceString("rom", str);
1464     else
1465     PrefsRemoveItem("rom");
1466    
1467     }
1468    
1469     // Create "Memory/Misc" pane
1470     static void create_memory_pane(GtkWidget *top)
1471     {
1472 gbeauche 1.29 GtkWidget *box, *hbox, *table, *label, *menu;
1473 cebix 1.1
1474     box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE);
1475 gbeauche 1.29 table = make_table(box, 2, 5);
1476 cebix 1.1
1477 gbeauche 1.29 static const combo_desc options[] = {
1478     STR_RAMSIZE_2MB_LAB,
1479     STR_RAMSIZE_4MB_LAB,
1480     STR_RAMSIZE_8MB_LAB,
1481     STR_RAMSIZE_16MB_LAB,
1482     STR_RAMSIZE_32MB_LAB,
1483     STR_RAMSIZE_64MB_LAB,
1484     STR_RAMSIZE_128MB_LAB,
1485     STR_RAMSIZE_256MB_LAB,
1486     STR_RAMSIZE_512MB_LAB,
1487     STR_RAMSIZE_1024MB_LAB,
1488     0
1489     };
1490     char default_ramsize[10];
1491     sprintf(default_ramsize, "%d", PrefsFindInt32("ramsize") >> 20);
1492     w_ramsize = table_make_combobox(table, 0, STR_RAMSIZE_CTRL, default_ramsize, options);
1493 cebix 1.1
1494 cebix 1.9 static const opt_desc model_options[] = {
1495 cebix 1.1 {STR_MODELID_5_LAB, GTK_SIGNAL_FUNC(mn_modelid_5)},
1496     {STR_MODELID_14_LAB, GTK_SIGNAL_FUNC(mn_modelid_14)},
1497     {0, NULL}
1498     };
1499     int modelid = PrefsFindInt32("modelid"), active = 0;
1500     switch (modelid) {
1501     case 5: active = 0; break;
1502     case 14: active = 1; break;
1503     }
1504 gbeauche 1.29 table_make_option_menu(table, 2, STR_MODELID_CTRL, model_options, active);
1505 cebix 1.9
1506 cebix 1.11 #if EMULATED_68K
1507 cebix 1.9 static const opt_desc cpu_options[] = {
1508     {STR_CPU_68020_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020)},
1509     {STR_CPU_68020_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020_fpu)},
1510     {STR_CPU_68030_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030)},
1511     {STR_CPU_68030_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030_fpu)},
1512     {STR_CPU_68040_LAB, GTK_SIGNAL_FUNC(mn_cpu_68040)},
1513     {0, NULL}
1514     };
1515     int cpu = PrefsFindInt32("cpu");
1516     bool fpu = PrefsFindBool("fpu");
1517     active = 0;
1518     switch (cpu) {
1519     case 2: active = fpu ? 1 : 0; break;
1520     case 3: active = fpu ? 3 : 2; break;
1521     case 4: active = 4;
1522     }
1523 gbeauche 1.29 table_make_option_menu(table, 3, STR_CPU_CTRL, cpu_options, active);
1524 cebix 1.11 #endif
1525 cebix 1.1
1526 gbeauche 1.29 w_rom_file = table_make_file_entry(table, 4, STR_ROM_FILE_CTRL, "rom");
1527 gbeauche 1.22
1528     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1529     make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv));
1530     #endif
1531 cebix 1.1 }
1532    
1533    
1534     /*
1535     * Read settings from widgets and set preferences
1536     */
1537    
1538     static void read_settings(void)
1539     {
1540     read_volumes_settings();
1541     read_scsi_settings();
1542     read_graphics_settings();
1543 cebix 1.13 read_input_settings();
1544 cebix 1.1 read_serial_settings();
1545     read_memory_settings();
1546 gbeauche 1.23 read_jit_settings();
1547 cebix 1.1 }
1548 gbeauche 1.32
1549    
1550     #ifdef STANDALONE_GUI
1551     #include <errno.h>
1552 gbeauche 1.33 #include <sys/wait.h>
1553     #include "rpc.h"
1554 gbeauche 1.32
1555     /*
1556     * Fake unused data and functions
1557     */
1558    
1559     uint8 XPRAM[XPRAM_SIZE];
1560     void MountVolume(void *fh) { }
1561     void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) { }
1562    
1563 gbeauche 1.35 #if defined __APPLE__ && defined __MACH__
1564     void DarwinAddCDROMPrefs(void) { }
1565     void DarwinAddFloppyPrefs(void) { }
1566     void DarwinAddSerialPrefs(void) { }
1567     bool DarwinCDReadTOC(char *, uint8 *) { }
1568     #endif
1569    
1570 gbeauche 1.32
1571     /*
1572     * Display alert
1573     */
1574    
1575     static void dl_destroyed(void)
1576     {
1577     gtk_main_quit();
1578     }
1579    
1580     static void display_alert(int title_id, int prefix_id, int button_id, const char *text)
1581     {
1582     char str[256];
1583     sprintf(str, GetString(prefix_id), text);
1584    
1585     GtkWidget *dialog = gtk_dialog_new();
1586     gtk_window_set_title(GTK_WINDOW(dialog), GetString(title_id));
1587     gtk_container_border_width(GTK_CONTAINER(dialog), 5);
1588     gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
1589     gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(dl_destroyed), NULL);
1590    
1591     GtkWidget *label = gtk_label_new(str);
1592     gtk_widget_show(label);
1593     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
1594    
1595     GtkWidget *button = gtk_button_new_with_label(GetString(button_id));
1596     gtk_widget_show(button);
1597     gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
1598     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
1599     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1600     gtk_widget_grab_default(button);
1601     gtk_widget_show(dialog);
1602    
1603     gtk_main();
1604     }
1605    
1606    
1607     /*
1608     * Display error alert
1609     */
1610    
1611 gbeauche 1.33 void ErrorAlert(const char *text)
1612 gbeauche 1.32 {
1613     display_alert(STR_ERROR_ALERT_TITLE, STR_GUI_ERROR_PREFIX, STR_QUIT_BUTTON, text);
1614     }
1615    
1616    
1617     /*
1618 gbeauche 1.33 * Display warning alert
1619     */
1620    
1621     void WarningAlert(const char *text)
1622     {
1623     display_alert(STR_WARNING_ALERT_TITLE, STR_GUI_WARNING_PREFIX, STR_OK_BUTTON, text);
1624     }
1625    
1626    
1627     /*
1628     * RPC handlers
1629     */
1630    
1631     static int handle_ErrorAlert(rpc_connection_t *connection)
1632     {
1633     D(bug("handle_ErrorAlert\n"));
1634    
1635     int error;
1636     char *str;
1637     if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0)
1638     return error;
1639    
1640     ErrorAlert(str);
1641     free(str);
1642     return RPC_ERROR_NO_ERROR;
1643     }
1644    
1645     static int handle_WarningAlert(rpc_connection_t *connection)
1646     {
1647     D(bug("handle_WarningAlert\n"));
1648    
1649     int error;
1650     char *str;
1651     if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0)
1652     return error;
1653    
1654     WarningAlert(str);
1655     free(str);
1656     return RPC_ERROR_NO_ERROR;
1657     }
1658    
1659     static int handle_Exit(rpc_connection_t *connection)
1660     {
1661     D(bug("handle_Exit\n"));
1662    
1663     return RPC_ERROR_NO_ERROR;
1664     }
1665    
1666    
1667     /*
1668 gbeauche 1.32 * Start standalone GUI
1669     */
1670    
1671     int main(int argc, char *argv[])
1672     {
1673     #ifdef HAVE_GNOMEUI
1674     // Init GNOME/GTK
1675     char version[16];
1676     sprintf(version, "%d.%d", VERSION_MAJOR, VERSION_MINOR);
1677     gnome_init("Basilisk II", version, argc, argv);
1678     #else
1679     // Init GTK
1680     gtk_set_locale();
1681     gtk_init(&argc, &argv);
1682     #endif
1683    
1684     // Read preferences
1685     PrefsInit(argc, argv);
1686    
1687     // Show preferences editor
1688     bool start = PrefsEditor();
1689    
1690     // Exit preferences
1691     PrefsExit();
1692    
1693     // Transfer control to the executable
1694     if (start) {
1695 gbeauche 1.33 char gui_connection_path[64];
1696     sprintf(gui_connection_path, "/org/BasiliskII/GUI/%d", getpid());
1697 gbeauche 1.35
1698     // Search and run the BasiliskII executable
1699     // XXX it can be in a bundle on MacOS X
1700     char b2_path[PATH_MAX];
1701     strcpy(b2_path, argv[0]);
1702     char *p = strrchr(b2_path, '/');
1703     p = p ? p + 1 : b2_path;
1704     *p = '\0';
1705     strcat(b2_path, "BasiliskII");
1706    
1707 gbeauche 1.33 int pid = fork();
1708 gbeauche 1.35 if (pid == 0) {
1709 gbeauche 1.33 execl(b2_path, b2_path, "--gui-connection", gui_connection_path, (char *)NULL);
1710 gbeauche 1.35 return -errno;
1711     }
1712 gbeauche 1.33
1713 gbeauche 1.35 // Establish a connection to Basilisk II
1714     rpc_connection_t *connection;
1715     if ((connection = rpc_init_server(gui_connection_path)) == NULL) {
1716     printf("ERROR: failed to initialize GUI-side RPC server connection\n");
1717     return 1;
1718     }
1719     static const rpc_method_descriptor_t vtable[] = {
1720     { RPC_METHOD_ERROR_ALERT, handle_ErrorAlert },
1721     { RPC_METHOD_WARNING_ALERT, handle_WarningAlert },
1722     { RPC_METHOD_EXIT, handle_Exit }
1723     };
1724     if (rpc_method_add_callbacks(connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) {
1725     printf("ERROR: failed to setup GUI method callbacks\n");
1726     return 1;
1727     }
1728     int socket;
1729     if ((socket = rpc_listen_socket(connection)) < 0) {
1730     printf("ERROR: failed to initialize RPC server thread\n");
1731 gbeauche 1.33 return 1;
1732     }
1733 gbeauche 1.35
1734     int child_status = 1;
1735     GMainLoop *loop = g_main_new(TRUE);
1736     while (g_main_is_running(loop)) {
1737    
1738     // Process a few events pending
1739     const int N_EVENTS_DISPATCH = 10;
1740     for (int i = 0; i < N_EVENTS_DISPATCH; i++) {
1741     if (!g_main_iteration(FALSE))
1742     break;
1743 gbeauche 1.33 }
1744    
1745 gbeauche 1.35 // Check if the child has terminated
1746     int status = 1;
1747     int ret = waitpid(pid, &status, WNOHANG);
1748     if (ret == pid || (ret < 0 && errno == ECHILD)) {
1749     if (WIFEXITED(status)) {
1750     child_status = WEXITSTATUS(status);
1751     if (child_status & 0x80)
1752     child_status |= -1 ^0xff;
1753     }
1754     break;
1755 gbeauche 1.33 }
1756    
1757 gbeauche 1.35 // Check for RPC events
1758     // XXX implement an rpc_try_dispatch(connection, timeout)
1759     fd_set rfds;
1760     FD_ZERO(&rfds);
1761     FD_SET(socket, &rfds);
1762     struct timeval tv;
1763     tv.tv_sec = 1;
1764     tv.tv_usec = 0;
1765     ret = select(socket + 1, &rfds, NULL, NULL, &tv);
1766     if (ret < 0)
1767     break;
1768     if (ret == 0)
1769     continue;
1770     rpc_dispatch(connection);
1771     }
1772 gbeauche 1.33
1773 gbeauche 1.35 rpc_exit(connection);
1774 gbeauche 1.33
1775 gbeauche 1.35 // Report failure to execute the BasiliskII binary
1776     if (child_status < 0) {
1777     char str[256];
1778     sprintf(str, GetString(STR_NO_B2_EXE_FOUND), b2_path, strerror(-child_status));
1779     ErrorAlert(str);
1780     return 1;
1781 gbeauche 1.33 }
1782 gbeauche 1.35
1783     return child_status;
1784 gbeauche 1.32 }
1785    
1786     return 0;
1787     }
1788     #endif