ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/prefs_editor_gtk.cpp
Revision: 1.41
Committed: 2010-01-15T01:53:31Z (14 years, 4 months ago) by asvitkine
Branch: MAIN
CVS Tags: HEAD
Changes since 1.40: +1 -1 lines
Log Message:
Fix PrefsInit() calls to take correct number of parameter

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * prefs_editor_gtk.cpp - Preferences editor, Unix implementation using GTK+
3     *
4 gbeauche 1.40 * Basilisk II (C) 1997-2008 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.40 "Copyright (C) 1997-2008 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.40 "Copyright (C) 1997-2008 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.38 // Don't use CPU when idle?
1437     static void tb_idlewait(GtkWidget *widget)
1438     {
1439     PrefsReplaceBool("idlewait", GTK_TOGGLE_BUTTON(widget)->active);
1440     }
1441    
1442 gbeauche 1.22 // "Ignore SEGV" button toggled
1443     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1444     static void tb_ignoresegv(GtkWidget *widget)
1445     {
1446     PrefsReplaceBool("ignoresegv", GTK_TOGGLE_BUTTON(widget)->active);
1447     }
1448     #endif
1449    
1450 cebix 1.1 // Model ID selected
1451     static void mn_modelid_5(...) {PrefsReplaceInt32("modelid", 5);}
1452     static void mn_modelid_14(...) {PrefsReplaceInt32("modelid", 14);}
1453    
1454 cebix 1.9 // CPU/FPU type
1455     static void mn_cpu_68020(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", false);}
1456     static void mn_cpu_68020_fpu(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", true);}
1457     static void mn_cpu_68030(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", false);}
1458     static void mn_cpu_68030_fpu(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", true);}
1459     static void mn_cpu_68040(...) {PrefsReplaceInt32("cpu", 4); PrefsReplaceBool("fpu", true);}
1460 cebix 1.8
1461 cebix 1.1 // Read settings from widgets and set preferences
1462     static void read_memory_settings(void)
1463     {
1464 gbeauche 1.29 const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_ramsize)->entry));
1465     PrefsReplaceInt32("ramsize", atoi(str) << 20);
1466 cebix 1.1
1467 gbeauche 1.29 str = get_file_entry_path(w_rom_file);
1468 cebix 1.1 if (str && strlen(str))
1469     PrefsReplaceString("rom", str);
1470     else
1471     PrefsRemoveItem("rom");
1472    
1473     }
1474    
1475     // Create "Memory/Misc" pane
1476     static void create_memory_pane(GtkWidget *top)
1477     {
1478 gbeauche 1.29 GtkWidget *box, *hbox, *table, *label, *menu;
1479 cebix 1.1
1480     box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE);
1481 gbeauche 1.29 table = make_table(box, 2, 5);
1482 cebix 1.1
1483 gbeauche 1.29 static const combo_desc options[] = {
1484     STR_RAMSIZE_2MB_LAB,
1485     STR_RAMSIZE_4MB_LAB,
1486     STR_RAMSIZE_8MB_LAB,
1487     STR_RAMSIZE_16MB_LAB,
1488     STR_RAMSIZE_32MB_LAB,
1489     STR_RAMSIZE_64MB_LAB,
1490     STR_RAMSIZE_128MB_LAB,
1491     STR_RAMSIZE_256MB_LAB,
1492     STR_RAMSIZE_512MB_LAB,
1493     STR_RAMSIZE_1024MB_LAB,
1494     0
1495     };
1496     char default_ramsize[10];
1497     sprintf(default_ramsize, "%d", PrefsFindInt32("ramsize") >> 20);
1498     w_ramsize = table_make_combobox(table, 0, STR_RAMSIZE_CTRL, default_ramsize, options);
1499 cebix 1.1
1500 cebix 1.9 static const opt_desc model_options[] = {
1501 cebix 1.1 {STR_MODELID_5_LAB, GTK_SIGNAL_FUNC(mn_modelid_5)},
1502     {STR_MODELID_14_LAB, GTK_SIGNAL_FUNC(mn_modelid_14)},
1503     {0, NULL}
1504     };
1505     int modelid = PrefsFindInt32("modelid"), active = 0;
1506     switch (modelid) {
1507     case 5: active = 0; break;
1508     case 14: active = 1; break;
1509     }
1510 gbeauche 1.29 table_make_option_menu(table, 2, STR_MODELID_CTRL, model_options, active);
1511 cebix 1.9
1512 cebix 1.11 #if EMULATED_68K
1513 cebix 1.9 static const opt_desc cpu_options[] = {
1514     {STR_CPU_68020_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020)},
1515     {STR_CPU_68020_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020_fpu)},
1516     {STR_CPU_68030_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030)},
1517     {STR_CPU_68030_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030_fpu)},
1518     {STR_CPU_68040_LAB, GTK_SIGNAL_FUNC(mn_cpu_68040)},
1519     {0, NULL}
1520     };
1521     int cpu = PrefsFindInt32("cpu");
1522     bool fpu = PrefsFindBool("fpu");
1523     active = 0;
1524     switch (cpu) {
1525     case 2: active = fpu ? 1 : 0; break;
1526     case 3: active = fpu ? 3 : 2; break;
1527     case 4: active = 4;
1528     }
1529 gbeauche 1.29 table_make_option_menu(table, 3, STR_CPU_CTRL, cpu_options, active);
1530 cebix 1.11 #endif
1531 cebix 1.1
1532 gbeauche 1.29 w_rom_file = table_make_file_entry(table, 4, STR_ROM_FILE_CTRL, "rom");
1533 gbeauche 1.22
1534 gbeauche 1.38 make_checkbox(box, STR_IDLEWAIT_CTRL, "idlewait", GTK_SIGNAL_FUNC(tb_idlewait));
1535 gbeauche 1.22 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1536     make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv));
1537     #endif
1538 cebix 1.1 }
1539    
1540    
1541     /*
1542     * Read settings from widgets and set preferences
1543     */
1544    
1545     static void read_settings(void)
1546     {
1547     read_volumes_settings();
1548     read_scsi_settings();
1549     read_graphics_settings();
1550 cebix 1.13 read_input_settings();
1551 cebix 1.1 read_serial_settings();
1552     read_memory_settings();
1553 gbeauche 1.23 read_jit_settings();
1554 cebix 1.1 }
1555 gbeauche 1.32
1556    
1557     #ifdef STANDALONE_GUI
1558     #include <errno.h>
1559 gbeauche 1.33 #include <sys/wait.h>
1560     #include "rpc.h"
1561 gbeauche 1.32
1562     /*
1563     * Fake unused data and functions
1564     */
1565    
1566     uint8 XPRAM[XPRAM_SIZE];
1567     void MountVolume(void *fh) { }
1568     void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) { }
1569    
1570 gbeauche 1.35 #if defined __APPLE__ && defined __MACH__
1571 gbeauche 1.39 void DarwinSysInit(void) { }
1572     void DarwinSysExit(void) { }
1573 gbeauche 1.35 void DarwinAddFloppyPrefs(void) { }
1574     void DarwinAddSerialPrefs(void) { }
1575     bool DarwinCDReadTOC(char *, uint8 *) { }
1576     #endif
1577    
1578 gbeauche 1.32
1579     /*
1580     * Display alert
1581     */
1582    
1583     static void dl_destroyed(void)
1584     {
1585     gtk_main_quit();
1586     }
1587    
1588     static void display_alert(int title_id, int prefix_id, int button_id, const char *text)
1589     {
1590     char str[256];
1591     sprintf(str, GetString(prefix_id), text);
1592    
1593     GtkWidget *dialog = gtk_dialog_new();
1594     gtk_window_set_title(GTK_WINDOW(dialog), GetString(title_id));
1595     gtk_container_border_width(GTK_CONTAINER(dialog), 5);
1596     gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
1597     gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(dl_destroyed), NULL);
1598    
1599     GtkWidget *label = gtk_label_new(str);
1600     gtk_widget_show(label);
1601     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
1602    
1603     GtkWidget *button = gtk_button_new_with_label(GetString(button_id));
1604     gtk_widget_show(button);
1605     gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
1606     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
1607     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1608     gtk_widget_grab_default(button);
1609     gtk_widget_show(dialog);
1610    
1611     gtk_main();
1612     }
1613    
1614    
1615     /*
1616     * Display error alert
1617     */
1618    
1619 gbeauche 1.33 void ErrorAlert(const char *text)
1620 gbeauche 1.32 {
1621     display_alert(STR_ERROR_ALERT_TITLE, STR_GUI_ERROR_PREFIX, STR_QUIT_BUTTON, text);
1622     }
1623    
1624    
1625     /*
1626 gbeauche 1.33 * Display warning alert
1627     */
1628    
1629     void WarningAlert(const char *text)
1630     {
1631     display_alert(STR_WARNING_ALERT_TITLE, STR_GUI_WARNING_PREFIX, STR_OK_BUTTON, text);
1632     }
1633    
1634    
1635     /*
1636     * RPC handlers
1637     */
1638    
1639 gbeauche 1.36 static GMainLoop *g_gui_loop;
1640    
1641 gbeauche 1.33 static int handle_ErrorAlert(rpc_connection_t *connection)
1642     {
1643     D(bug("handle_ErrorAlert\n"));
1644    
1645     int error;
1646     char *str;
1647     if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0)
1648     return error;
1649    
1650     ErrorAlert(str);
1651     free(str);
1652     return RPC_ERROR_NO_ERROR;
1653     }
1654    
1655     static int handle_WarningAlert(rpc_connection_t *connection)
1656     {
1657     D(bug("handle_WarningAlert\n"));
1658    
1659     int error;
1660     char *str;
1661     if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0)
1662     return error;
1663    
1664     WarningAlert(str);
1665     free(str);
1666     return RPC_ERROR_NO_ERROR;
1667     }
1668    
1669     static int handle_Exit(rpc_connection_t *connection)
1670     {
1671     D(bug("handle_Exit\n"));
1672    
1673 gbeauche 1.36 g_main_quit(g_gui_loop);
1674 gbeauche 1.33 return RPC_ERROR_NO_ERROR;
1675     }
1676    
1677    
1678     /*
1679 gbeauche 1.36 * SIGCHLD handler
1680     */
1681    
1682     static char g_app_path[PATH_MAX];
1683     static rpc_connection_t *g_gui_connection = NULL;
1684    
1685     static void sigchld_handler(int sig, siginfo_t *sip, void *)
1686     {
1687     D(bug("Child %d exitted with status = %x\n", sip->si_pid, sip->si_status));
1688    
1689 gbeauche 1.37 // XXX perform a new wait because sip->si_status is sometimes not
1690     // the exit _value_ on MacOS X but rather the usual status field
1691     // from waitpid() -- we could arrange this code in some other way...
1692     int status;
1693     if (waitpid(sip->si_pid, &status, 0) < 0)
1694     status = sip->si_status;
1695     if (WIFEXITED(status))
1696     status = WEXITSTATUS(status);
1697 gbeauche 1.36 if (status & 0x80)
1698     status |= -1 ^0xff;
1699    
1700     if (status < 0) { // negative -> execlp/-errno
1701     char str[256];
1702     sprintf(str, GetString(STR_NO_B2_EXE_FOUND), g_app_path, strerror(-status));
1703     ErrorAlert(str);
1704     status = 1;
1705     }
1706    
1707     if (status != 0) {
1708     if (g_gui_connection)
1709     rpc_exit(g_gui_connection);
1710     exit(status);
1711     }
1712     }
1713    
1714    
1715     /*
1716 gbeauche 1.32 * Start standalone GUI
1717     */
1718    
1719     int main(int argc, char *argv[])
1720     {
1721     #ifdef HAVE_GNOMEUI
1722     // Init GNOME/GTK
1723     char version[16];
1724     sprintf(version, "%d.%d", VERSION_MAJOR, VERSION_MINOR);
1725     gnome_init("Basilisk II", version, argc, argv);
1726     #else
1727     // Init GTK
1728     gtk_set_locale();
1729     gtk_init(&argc, &argv);
1730     #endif
1731    
1732     // Read preferences
1733 asvitkine 1.41 PrefsInit(NULL, argc, argv);
1734 gbeauche 1.32
1735     // Show preferences editor
1736     bool start = PrefsEditor();
1737    
1738     // Exit preferences
1739     PrefsExit();
1740    
1741     // Transfer control to the executable
1742     if (start) {
1743 gbeauche 1.33 char gui_connection_path[64];
1744     sprintf(gui_connection_path, "/org/BasiliskII/GUI/%d", getpid());
1745 gbeauche 1.35
1746 gbeauche 1.36 // Catch exits from the child process
1747     struct sigaction sigchld_sa, old_sigchld_sa;
1748     sigemptyset(&sigchld_sa.sa_mask);
1749     sigchld_sa.sa_sigaction = sigchld_handler;
1750     sigchld_sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
1751     if (sigaction(SIGCHLD, &sigchld_sa, &old_sigchld_sa) < 0) {
1752     char str[256];
1753     sprintf(str, GetString(STR_SIG_INSTALL_ERR), SIGCHLD, strerror(errno));
1754     ErrorAlert(str);
1755     return 1;
1756     }
1757    
1758 gbeauche 1.35 // Search and run the BasiliskII executable
1759 gbeauche 1.37 char *p;
1760 gbeauche 1.36 strcpy(g_app_path, argv[0]);
1761 gbeauche 1.37 if ((p = strstr(g_app_path, "BasiliskIIGUI.app/Contents/MacOS")) != NULL) {
1762     strcpy(p, "BasiliskII.app/Contents/MacOS/BasiliskII");
1763     if (access(g_app_path, X_OK) < 0) {
1764     char str[256];
1765     sprintf(str, GetString(STR_NO_B2_EXE_FOUND), g_app_path, strerror(errno));
1766     WarningAlert(str);
1767     strcpy(g_app_path, "/Applications/BasiliskII.app/Contents/MacOS/BasiliskII");
1768     }
1769     } else {
1770     p = strrchr(g_app_path, '/');
1771     p = p ? p + 1 : g_app_path;
1772     strcpy(p, "BasiliskII");
1773     }
1774 gbeauche 1.35
1775 gbeauche 1.33 int pid = fork();
1776 gbeauche 1.35 if (pid == 0) {
1777 gbeauche 1.37 D(bug("Trying to execute %s\n", g_app_path));
1778 gbeauche 1.36 execlp(g_app_path, g_app_path, "--gui-connection", gui_connection_path, (char *)NULL);
1779     #ifdef _POSIX_PRIORITY_SCHEDULING
1780     // XXX get a chance to run the parent process so that to not confuse/upset GTK...
1781     sched_yield();
1782     #endif
1783     _exit(-errno);
1784 gbeauche 1.35 }
1785 gbeauche 1.33
1786 gbeauche 1.35 // Establish a connection to Basilisk II
1787 gbeauche 1.36 if ((g_gui_connection = rpc_init_server(gui_connection_path)) == NULL) {
1788 gbeauche 1.35 printf("ERROR: failed to initialize GUI-side RPC server connection\n");
1789     return 1;
1790     }
1791     static const rpc_method_descriptor_t vtable[] = {
1792     { RPC_METHOD_ERROR_ALERT, handle_ErrorAlert },
1793     { RPC_METHOD_WARNING_ALERT, handle_WarningAlert },
1794     { RPC_METHOD_EXIT, handle_Exit }
1795     };
1796 gbeauche 1.36 if (rpc_method_add_callbacks(g_gui_connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) {
1797 gbeauche 1.35 printf("ERROR: failed to setup GUI method callbacks\n");
1798     return 1;
1799     }
1800     int socket;
1801 gbeauche 1.36 if ((socket = rpc_listen_socket(g_gui_connection)) < 0) {
1802 gbeauche 1.35 printf("ERROR: failed to initialize RPC server thread\n");
1803 gbeauche 1.33 return 1;
1804     }
1805 gbeauche 1.35
1806 gbeauche 1.36 g_gui_loop = g_main_new(TRUE);
1807     while (g_main_is_running(g_gui_loop)) {
1808 gbeauche 1.35
1809     // Process a few events pending
1810     const int N_EVENTS_DISPATCH = 10;
1811     for (int i = 0; i < N_EVENTS_DISPATCH; i++) {
1812     if (!g_main_iteration(FALSE))
1813     break;
1814 gbeauche 1.33 }
1815    
1816 gbeauche 1.36 // Check for RPC events (100 ms timeout)
1817     int ret = rpc_wait_dispatch(g_gui_connection, 100000);
1818     if (ret == 0)
1819     continue;
1820 gbeauche 1.35 if (ret < 0)
1821     break;
1822 gbeauche 1.36 rpc_dispatch(g_gui_connection);
1823 gbeauche 1.33 }
1824 gbeauche 1.35
1825 gbeauche 1.36 rpc_exit(g_gui_connection);
1826     return 0;
1827 gbeauche 1.32 }
1828    
1829     return 0;
1830     }
1831     #endif