ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/prefs_editor_gtk.cpp
Revision: 1.15
Committed: 2005-11-27T16:01:59Z (18 years, 6 months ago) by gbeauche
Branch: MAIN
Changes since 1.14: +174 -52 lines
Log Message:
GUI cosmetics from Basilisk II, add missing "slirp" ethernet option

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * prefs_editor_linux.cpp - Preferences editor, Linux implementation using GTK+
3     *
4 gbeauche 1.11 * SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig
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     #include "user_strings.h"
32     #include "version.h"
33     #include "cdrom.h"
34     #include "xpram.h"
35     #include "prefs.h"
36     #include "prefs_editor.h"
37    
38    
39     // Global variables
40     static GtkWidget *win; // Preferences window
41     static bool start_clicked = true; // Return value of PrefsEditor() function
42 gbeauche 1.13 static int screen_width, screen_height; // Screen dimensions
43 cebix 1.1
44    
45     // Prototypes
46     static void create_volumes_pane(GtkWidget *top);
47     static void create_graphics_pane(GtkWidget *top);
48 gbeauche 1.2 static void create_input_pane(GtkWidget *top);
49 cebix 1.1 static void create_serial_pane(GtkWidget *top);
50     static void create_memory_pane(GtkWidget *top);
51 gbeauche 1.3 static void create_jit_pane(GtkWidget *top);
52 cebix 1.1 static void read_settings(void);
53    
54    
55     /*
56     * Utility functions
57     */
58    
59 gbeauche 1.15 #if ! GLIB_CHECK_VERSION(2,0,0)
60     #define G_OBJECT(obj) GTK_OBJECT(obj)
61     #define g_object_get_data(obj, key) gtk_object_get_data((obj), (key))
62     #define g_object_set_data(obj, key, data) gtk_object_set_data((obj), (key), (data))
63     #endif
64    
65 cebix 1.1 struct opt_desc {
66     int label_id;
67     GtkSignalFunc func;
68     };
69    
70 gbeauche 1.15 struct combo_desc {
71     int label_id;
72     };
73    
74     struct file_req_assoc {
75     file_req_assoc(GtkWidget *r, GtkWidget *e) : req(r), entry(e) {}
76     GtkWidget *req;
77     GtkWidget *entry;
78     };
79    
80     static void cb_browse_ok(GtkWidget *button, file_req_assoc *assoc)
81     {
82     gchar *file = (char *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
83     gtk_entry_set_text(GTK_ENTRY(assoc->entry), file);
84     gtk_widget_destroy(assoc->req);
85     delete assoc;
86     }
87    
88     static void cb_browse(GtkWidget *widget, void *user_data)
89     {
90     GtkWidget *req = gtk_file_selection_new(GetString(STR_BROWSE_TITLE));
91     gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
92     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));
93     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
94     gtk_widget_show(req);
95     }
96    
97     static GtkWidget *make_browse_button(GtkWidget *entry)
98     {
99     GtkWidget *button;
100    
101     button = gtk_button_new_with_label(GetString(STR_BROWSE_CTRL));
102     gtk_widget_show(button);
103     gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc)cb_browse, (void *)entry);
104     return button;
105     }
106    
107 cebix 1.1 static void add_menu_item(GtkWidget *menu, int label_id, GtkSignalFunc func)
108     {
109     GtkWidget *item = gtk_menu_item_new_with_label(GetString(label_id));
110     gtk_widget_show(item);
111     gtk_signal_connect(GTK_OBJECT(item), "activate", func, NULL);
112     gtk_menu_append(GTK_MENU(menu), item);
113     }
114    
115     static GtkWidget *make_pane(GtkWidget *notebook, int title_id)
116     {
117     GtkWidget *frame, *label, *box;
118    
119     frame = gtk_frame_new(NULL);
120     gtk_widget_show(frame);
121     gtk_container_border_width(GTK_CONTAINER(frame), 4);
122    
123     label = gtk_label_new(GetString(title_id));
124     gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label);
125    
126     box = gtk_vbox_new(FALSE, 4);
127     gtk_widget_show(box);
128     gtk_container_set_border_width(GTK_CONTAINER(box), 4);
129     gtk_container_add(GTK_CONTAINER(frame), box);
130     return box;
131     }
132    
133     static GtkWidget *make_button_box(GtkWidget *top, int border, const opt_desc *buttons)
134     {
135     GtkWidget *bb, *button;
136    
137     bb = gtk_hbutton_box_new();
138     gtk_widget_show(bb);
139     gtk_container_set_border_width(GTK_CONTAINER(bb), border);
140     gtk_button_box_set_layout(GTK_BUTTON_BOX(bb), GTK_BUTTONBOX_DEFAULT_STYLE);
141     gtk_button_box_set_spacing(GTK_BUTTON_BOX(bb), 4);
142     gtk_box_pack_start(GTK_BOX(top), bb, FALSE, FALSE, 0);
143    
144     while (buttons->label_id) {
145     button = gtk_button_new_with_label(GetString(buttons->label_id));
146     gtk_widget_show(button);
147     gtk_signal_connect_object(GTK_OBJECT(button), "clicked", buttons->func, NULL);
148     gtk_box_pack_start(GTK_BOX(bb), button, TRUE, TRUE, 0);
149     buttons++;
150     }
151     return bb;
152     }
153    
154     static GtkWidget *make_separator(GtkWidget *top)
155     {
156     GtkWidget *sep = gtk_hseparator_new();
157     gtk_box_pack_start(GTK_BOX(top), sep, FALSE, FALSE, 0);
158     gtk_widget_show(sep);
159     return sep;
160     }
161    
162     static GtkWidget *make_table(GtkWidget *top, int x, int y)
163     {
164     GtkWidget *table = gtk_table_new(x, y, FALSE);
165     gtk_widget_show(table);
166     gtk_box_pack_start(GTK_BOX(top), table, FALSE, FALSE, 0);
167     return table;
168     }
169    
170 gbeauche 1.15 static GtkWidget *table_make_option_menu(GtkWidget *table, int row, int label_id, const opt_desc *options, int active)
171     {
172     GtkWidget *label, *opt, *menu;
173    
174     label = gtk_label_new(GetString(label_id));
175     gtk_widget_show(label);
176     gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
177    
178     opt = gtk_option_menu_new();
179     gtk_widget_show(opt);
180     menu = gtk_menu_new();
181    
182     while (options->label_id) {
183     add_menu_item(menu, options->label_id, options->func);
184     options++;
185     }
186     gtk_menu_set_active(GTK_MENU(menu), active);
187    
188     gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
189     gtk_table_attach(GTK_TABLE(table), opt, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
190     return menu;
191     }
192    
193     static GtkWidget *table_make_combobox(GtkWidget *table, int row, int label_id, const char *default_value, GList *glist)
194     {
195     GtkWidget *label, *combo;
196     char str[32];
197    
198     label = gtk_label_new(GetString(label_id));
199     gtk_widget_show(label);
200     gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
201    
202     combo = gtk_combo_new();
203     gtk_widget_show(combo);
204     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
205    
206     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), default_value);
207     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
208    
209     return combo;
210     }
211    
212     static GtkWidget *table_make_combobox(GtkWidget *table, int row, int label_id, const char *default_value, const combo_desc *options)
213     {
214     GList *glist = NULL;
215     while (options->label_id) {
216     glist = g_list_append(glist, (void *)GetString(options->label_id));
217     options++;
218     }
219    
220     return table_make_combobox(table, row, label_id, default_value, glist);
221     }
222    
223     static GtkWidget *table_make_file_entry(GtkWidget *table, int row, int label_id, const char *prefs_item, bool only_dirs = false)
224     {
225     GtkWidget *box, *label, *entry, *button;
226    
227     label = gtk_label_new(GetString(label_id));
228     gtk_widget_show(label);
229     gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
230    
231     const char *str = PrefsFindString(prefs_item);
232     if (str == NULL)
233     str = "";
234    
235     box = gtk_hbox_new(FALSE, 4);
236     gtk_widget_show(box);
237     gtk_table_attach(GTK_TABLE(table), box, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
238    
239     entry = gtk_entry_new();
240     gtk_entry_set_text(GTK_ENTRY(entry), str);
241     gtk_widget_show(entry);
242     gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0);
243    
244     button = make_browse_button(entry);
245     gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
246     g_object_set_data(G_OBJECT(entry), "chooser_button", button);
247     return entry;
248     }
249    
250 cebix 1.1 static GtkWidget *make_option_menu(GtkWidget *top, int label_id, const opt_desc *options, int active)
251     {
252     GtkWidget *box, *label, *opt, *menu;
253    
254     box = gtk_hbox_new(FALSE, 4);
255     gtk_widget_show(box);
256     gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0);
257    
258     label = gtk_label_new(GetString(label_id));
259     gtk_widget_show(label);
260     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
261    
262     opt = gtk_option_menu_new();
263     gtk_widget_show(opt);
264     menu = gtk_menu_new();
265    
266     while (options->label_id) {
267     add_menu_item(menu, options->label_id, options->func);
268     options++;
269     }
270     gtk_menu_set_active(GTK_MENU(menu), active);
271    
272     gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
273     gtk_box_pack_start(GTK_BOX(box), opt, FALSE, FALSE, 0);
274     return menu;
275     }
276    
277     static GtkWidget *make_entry(GtkWidget *top, int label_id, const char *prefs_item)
278     {
279     GtkWidget *box, *label, *entry;
280    
281     box = gtk_hbox_new(FALSE, 4);
282     gtk_widget_show(box);
283     gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0);
284    
285     label = gtk_label_new(GetString(label_id));
286     gtk_widget_show(label);
287     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
288    
289     entry = gtk_entry_new();
290     gtk_widget_show(entry);
291     const char *str = PrefsFindString(prefs_item);
292     if (str == NULL)
293     str = "";
294     gtk_entry_set_text(GTK_ENTRY(entry), str);
295     gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0);
296     return entry;
297     }
298    
299 gbeauche 1.12 static const gchar *get_file_entry_path(GtkWidget *entry)
300 gbeauche 1.2 {
301     return gtk_entry_get_text(GTK_ENTRY(entry));
302     }
303    
304 cebix 1.1 static GtkWidget *make_checkbox(GtkWidget *top, int label_id, const char *prefs_item, GtkSignalFunc func)
305     {
306     GtkWidget *button = gtk_check_button_new_with_label(GetString(label_id));
307     gtk_widget_show(button);
308     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), PrefsFindBool(prefs_item));
309     gtk_signal_connect(GTK_OBJECT(button), "toggled", func, button);
310     gtk_box_pack_start(GTK_BOX(top), button, FALSE, FALSE, 0);
311     return button;
312     }
313    
314     static GtkWidget *make_checkbox(GtkWidget *top, int label_id, bool active, GtkSignalFunc func)
315     {
316     GtkWidget *button = gtk_check_button_new_with_label(GetString(label_id));
317     gtk_widget_show(button);
318     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), active);
319     gtk_signal_connect(GTK_OBJECT(button), "toggled", func, button);
320     gtk_box_pack_start(GTK_BOX(top), button, FALSE, FALSE, 0);
321     return button;
322     }
323    
324    
325     /*
326     * Show preferences editor
327     * Returns true when user clicked on "Start", false otherwise
328     */
329    
330     // Window closed
331     static gint window_closed(void)
332     {
333     return FALSE;
334     }
335    
336     // Window destroyed
337     static void window_destroyed(void)
338     {
339     gtk_main_quit();
340     }
341    
342     // "Start" button clicked
343     static void cb_start(...)
344     {
345     start_clicked = true;
346     read_settings();
347     SavePrefs();
348     gtk_widget_destroy(win);
349     }
350    
351     // "Quit" button clicked
352     static void cb_quit(...)
353     {
354     start_clicked = false;
355     gtk_widget_destroy(win);
356     }
357    
358     // "OK" button of "About" dialog clicked
359     static void dl_quit(GtkWidget *dialog)
360     {
361     gtk_widget_destroy(dialog);
362     }
363    
364     // "About" selected
365     static void mn_about(...)
366     {
367     GtkWidget *dialog, *label, *button;
368    
369     char str[512];
370     sprintf(str,
371     "SheepShaver\nVersion %d.%d\n\n"
372 cebix 1.6 "Copyright (C) 1997-2004 Christian Bauer and Marc Hellwig\n"
373 cebix 1.1 "E-mail: Christian.Bauer@uni-mainz.de\n"
374     "http://www.uni-mainz.de/~bauec002/\n\n"
375     "SheepShaver comes with ABSOLUTELY NO\n"
376     "WARRANTY. This is free software, and\n"
377     "you are welcome to redistribute it\n"
378     "under the terms of the GNU General\n"
379     "Public License.\n",
380     VERSION_MAJOR, VERSION_MINOR
381     );
382    
383     dialog = gtk_dialog_new();
384     gtk_window_set_title(GTK_WINDOW(dialog), GetString(STR_ABOUT_TITLE));
385     gtk_container_border_width(GTK_CONTAINER(dialog), 5);
386     gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
387    
388     label = gtk_label_new(str);
389     gtk_widget_show(label);
390     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
391    
392     button = gtk_button_new_with_label(GetString(STR_OK_BUTTON));
393     gtk_widget_show(button);
394     gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
395     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
396     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
397     gtk_widget_grab_default(button);
398     gtk_widget_show(dialog);
399     }
400    
401     // "Zap NVRAM" selected
402     static void mn_zap_pram(...)
403     {
404     ZapPRAM();
405     }
406    
407     // Menu item descriptions
408     static GtkItemFactoryEntry menu_items[] = {
409     {(gchar *)GetString(STR_PREFS_MENU_FILE_GTK), NULL, NULL, 0, "<Branch>"},
410 gbeauche 1.15 {(gchar *)GetString(STR_PREFS_ITEM_START_GTK), "<control>S", GTK_SIGNAL_FUNC(cb_start), 0, NULL},
411 cebix 1.1 {(gchar *)GetString(STR_PREFS_ITEM_ZAP_PRAM_GTK), NULL, GTK_SIGNAL_FUNC(mn_zap_pram), 0, NULL},
412     {(gchar *)GetString(STR_PREFS_ITEM_SEPL_GTK), NULL, NULL, 0, "<Separator>"},
413     {(gchar *)GetString(STR_PREFS_ITEM_QUIT_GTK), "<control>Q", GTK_SIGNAL_FUNC(cb_quit), 0, NULL},
414     {(gchar *)GetString(STR_HELP_MENU_GTK), NULL, NULL, 0, "<LastBranch>"},
415     {(gchar *)GetString(STR_HELP_ITEM_ABOUT_GTK), NULL, GTK_SIGNAL_FUNC(mn_about), 0, NULL}
416     };
417    
418     bool PrefsEditor(void)
419     {
420 gbeauche 1.13 // Get screen dimensions
421     screen_width = gdk_screen_width();
422     screen_height = gdk_screen_height();
423    
424 cebix 1.1 // Create window
425     win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
426     gtk_window_set_title(GTK_WINDOW(win), GetString(STR_PREFS_TITLE));
427     gtk_signal_connect(GTK_OBJECT(win), "delete_event", GTK_SIGNAL_FUNC(window_closed), NULL);
428     gtk_signal_connect(GTK_OBJECT(win), "destroy", GTK_SIGNAL_FUNC(window_destroyed), NULL);
429    
430     // Create window contents
431     GtkWidget *box = gtk_vbox_new(FALSE, 4);
432     gtk_widget_show(box);
433     gtk_container_add(GTK_CONTAINER(win), box);
434    
435     GtkAccelGroup *accel_group = gtk_accel_group_new();
436     GtkItemFactory *item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
437     gtk_item_factory_create_items(item_factory, sizeof(menu_items) / sizeof(menu_items[0]), menu_items, NULL);
438 gbeauche 1.12 #if GTK_CHECK_VERSION(1,3,15)
439     gtk_window_add_accel_group(GTK_WINDOW(win), accel_group);
440     #else
441 cebix 1.1 gtk_accel_group_attach(accel_group, GTK_OBJECT(win));
442 gbeauche 1.12 #endif
443 cebix 1.1 GtkWidget *menu_bar = gtk_item_factory_get_widget(item_factory, "<main>");
444     gtk_widget_show(menu_bar);
445     gtk_box_pack_start(GTK_BOX(box), menu_bar, FALSE, TRUE, 0);
446    
447     GtkWidget *notebook = gtk_notebook_new();
448     gtk_widget_show(notebook);
449     gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
450     gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), FALSE);
451     gtk_box_pack_start(GTK_BOX(box), notebook, TRUE, TRUE, 0);
452    
453     create_volumes_pane(notebook);
454     create_graphics_pane(notebook);
455 gbeauche 1.2 create_input_pane(notebook);
456 cebix 1.1 create_serial_pane(notebook);
457     create_memory_pane(notebook);
458 gbeauche 1.3 create_jit_pane(notebook);
459 cebix 1.1
460     static const opt_desc buttons[] = {
461     {STR_START_BUTTON, GTK_SIGNAL_FUNC(cb_start)},
462     {STR_QUIT_BUTTON, GTK_SIGNAL_FUNC(cb_quit)},
463     {0, NULL}
464     };
465     make_button_box(box, 4, buttons);
466    
467     // Show window and enter main loop
468     gtk_widget_show(win);
469     gtk_main();
470     return start_clicked;
471     }
472    
473    
474     /*
475     * "Volumes" pane
476     */
477    
478     static GtkWidget *volume_list, *w_extfs;
479     static int selected_volume;
480    
481     // Volume in list selected
482     static void cl_selected(GtkWidget *list, int row, int column)
483     {
484     selected_volume = row;
485     }
486    
487     // Volume selected for addition
488     static void add_volume_ok(GtkWidget *button, file_req_assoc *assoc)
489     {
490 gbeauche 1.12 gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
491 cebix 1.1 gtk_clist_append(GTK_CLIST(volume_list), &file);
492     gtk_widget_destroy(assoc->req);
493     delete assoc;
494     }
495    
496     // Volume selected for creation
497     static void create_volume_ok(GtkWidget *button, file_req_assoc *assoc)
498     {
499 gbeauche 1.12 gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
500 cebix 1.1
501 gbeauche 1.12 const gchar *str = gtk_entry_get_text(GTK_ENTRY(assoc->entry));
502 cebix 1.1 int size = atoi(str);
503    
504     char cmd[1024];
505     sprintf(cmd, "dd if=/dev/zero \"of=%s\" bs=1024k count=%d", file, size);
506     int ret = system(cmd);
507     if (ret == 0)
508     gtk_clist_append(GTK_CLIST(volume_list), &file);
509     gtk_widget_destroy(GTK_WIDGET(assoc->req));
510     delete assoc;
511     }
512    
513     // "Add Volume" button clicked
514     static void cb_add_volume(...)
515     {
516     GtkWidget *req = gtk_file_selection_new(GetString(STR_ADD_VOLUME_TITLE));
517     gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
518     gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(add_volume_ok), new file_req_assoc(req, NULL));
519     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
520     gtk_widget_show(req);
521     }
522    
523     // "Create Hardfile" button clicked
524     static void cb_create_volume(...)
525     {
526     GtkWidget *req = gtk_file_selection_new(GetString(STR_CREATE_VOLUME_TITLE));
527    
528     GtkWidget *box = gtk_hbox_new(FALSE, 4);
529     gtk_widget_show(box);
530     GtkWidget *label = gtk_label_new(GetString(STR_HARDFILE_SIZE_CTRL));
531     gtk_widget_show(label);
532     GtkWidget *entry = gtk_entry_new();
533     gtk_widget_show(entry);
534     char str[32];
535     sprintf(str, "%d", 40);
536     gtk_entry_set_text(GTK_ENTRY(entry), str);
537     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
538     gtk_box_pack_start(GTK_BOX(box), entry, FALSE, FALSE, 0);
539     gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(req)->main_vbox), box, FALSE, FALSE, 0);
540    
541     gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
542     gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(create_volume_ok), new file_req_assoc(req, entry));
543     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
544     gtk_widget_show(req);
545     }
546    
547     // "Remove Volume" button clicked
548     static void cb_remove_volume(...)
549     {
550     gtk_clist_remove(GTK_CLIST(volume_list), selected_volume);
551     }
552    
553     // "Boot From" selected
554     static void mn_boot_any(...) {PrefsReplaceInt32("bootdriver", 0);}
555     static void mn_boot_cdrom(...) {PrefsReplaceInt32("bootdriver", CDROMRefNum);}
556    
557     // "No CD-ROM Driver" button toggled
558     static void tb_nocdrom(GtkWidget *widget)
559     {
560     PrefsReplaceBool("nocdrom", GTK_TOGGLE_BUTTON(widget)->active);
561     }
562    
563     // Read settings from widgets and set preferences
564     static void read_volumes_settings(void)
565     {
566     while (PrefsFindString("disk"))
567     PrefsRemoveItem("disk");
568    
569     for (int i=0; i<GTK_CLIST(volume_list)->rows; i++) {
570     char *str;
571     gtk_clist_get_text(GTK_CLIST(volume_list), i, 0, &str);
572     PrefsAddString("disk", str);
573     }
574    
575     PrefsReplaceString("extfs", gtk_entry_get_text(GTK_ENTRY(w_extfs)));
576     }
577    
578     // Create "Volumes" pane
579     static void create_volumes_pane(GtkWidget *top)
580     {
581     GtkWidget *box, *scroll, *menu;
582    
583     box = make_pane(top, STR_VOLUMES_PANE_TITLE);
584    
585     scroll = gtk_scrolled_window_new(NULL, NULL);
586     gtk_widget_show(scroll);
587     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
588     volume_list = gtk_clist_new(1);
589     gtk_widget_show(volume_list);
590     gtk_clist_set_selection_mode(GTK_CLIST(volume_list), GTK_SELECTION_SINGLE);
591     gtk_clist_set_shadow_type(GTK_CLIST(volume_list), GTK_SHADOW_NONE);
592     gtk_clist_set_reorderable(GTK_CLIST(volume_list), true);
593     gtk_signal_connect(GTK_OBJECT(volume_list), "select_row", GTK_SIGNAL_FUNC(cl_selected), NULL);
594     char *str;
595     int32 index = 0;
596     while ((str = (char *)PrefsFindString("disk", index++)) != NULL)
597     gtk_clist_append(GTK_CLIST(volume_list), &str);
598     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), volume_list);
599     gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 0);
600     selected_volume = 0;
601    
602     static const opt_desc buttons[] = {
603     {STR_ADD_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_add_volume)},
604     {STR_CREATE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_create_volume)},
605     {STR_REMOVE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_remove_volume)},
606     {0, NULL},
607     };
608     make_button_box(box, 0, buttons);
609     make_separator(box);
610    
611     w_extfs = make_entry(box, STR_EXTFS_CTRL, "extfs");
612    
613     static const opt_desc options[] = {
614     {STR_BOOT_ANY_LAB, GTK_SIGNAL_FUNC(mn_boot_any)},
615     {STR_BOOT_CDROM_LAB, GTK_SIGNAL_FUNC(mn_boot_cdrom)},
616     {0, NULL}
617     };
618     int bootdriver = PrefsFindInt32("bootdriver"), active = 0;
619     switch (bootdriver) {
620     case 0: active = 0; break;
621     case CDROMRefNum: active = 1; break;
622     }
623     menu = make_option_menu(box, STR_BOOTDRIVER_CTRL, options, active);
624    
625     make_checkbox(box, STR_NOCDROM_CTRL, "nocdrom", GTK_SIGNAL_FUNC(tb_nocdrom));
626     }
627    
628    
629     /*
630 gbeauche 1.3 * "JIT Compiler" pane
631     */
632    
633     // Set sensitivity of widgets
634     static void set_jit_sensitive(void)
635     {
636     const bool jit_enabled = PrefsFindBool("jit");
637     }
638    
639     // "Use JIT Compiler" button toggled
640     static void tb_jit(GtkWidget *widget)
641     {
642     PrefsReplaceBool("jit", GTK_TOGGLE_BUTTON(widget)->active);
643     set_jit_sensitive();
644     }
645    
646     // Read settings from widgets and set preferences
647     static void read_jit_settings(void)
648     {
649     #if USE_JIT
650     bool jit_enabled = PrefsFindBool("jit");
651     #endif
652     }
653    
654 gbeauche 1.10 // "Use built-in 68k DR emulator" button toggled
655     static void tb_jit_68k(GtkWidget *widget)
656     {
657     PrefsReplaceBool("jit68k", GTK_TOGGLE_BUTTON(widget)->active);
658     }
659    
660 gbeauche 1.3 // Create "JIT Compiler" pane
661     static void create_jit_pane(GtkWidget *top)
662     {
663     GtkWidget *box, *table, *label, *menu;
664     char str[32];
665    
666     box = make_pane(top, STR_JIT_PANE_TITLE);
667 gbeauche 1.10 #if USE_JIT
668 gbeauche 1.3 make_checkbox(box, STR_JIT_CTRL, "jit", GTK_SIGNAL_FUNC(tb_jit));
669     set_jit_sensitive();
670     #endif
671 gbeauche 1.10 make_checkbox(box, STR_JIT_68K_CTRL, "jit68k", GTK_SIGNAL_FUNC(tb_jit_68k));
672 gbeauche 1.3 }
673    
674    
675     /*
676 cebix 1.1 * "Graphics/Sound" pane
677     */
678    
679 gbeauche 1.13 // Display types
680     enum {
681     DISPLAY_WINDOW,
682     DISPLAY_SCREEN
683     };
684    
685     static GtkWidget *w_frameskip, *w_display_x, *w_display_y;
686     static GtkWidget *l_frameskip, *l_display_x, *l_display_y;
687     static int display_type;
688     static int dis_width, dis_height;
689 gbeauche 1.14 static bool is_fbdev_dga_mode = false;
690 cebix 1.1
691 gbeauche 1.4 static GtkWidget *w_dspdevice_file, *w_mixerdevice_file;
692    
693 gbeauche 1.13 // Hide/show graphics widgets
694     static void hide_show_graphics_widgets(void)
695     {
696     switch (display_type) {
697     case DISPLAY_WINDOW:
698     gtk_widget_show(w_frameskip); gtk_widget_show(l_frameskip);
699     break;
700     case DISPLAY_SCREEN:
701     gtk_widget_hide(w_frameskip); gtk_widget_hide(l_frameskip);
702     break;
703     }
704     }
705    
706     // "Window" video type selected
707     static void mn_window(...)
708     {
709     display_type = DISPLAY_WINDOW;
710     hide_show_graphics_widgets();
711     }
712    
713     // "Fullscreen" video type selected
714     static void mn_fullscreen(...)
715     {
716     display_type = DISPLAY_SCREEN;
717     hide_show_graphics_widgets();
718     }
719    
720 cebix 1.1 // "5 Hz".."60Hz" selected
721     static void mn_5hz(...) {PrefsReplaceInt32("frameskip", 12);}
722     static void mn_7hz(...) {PrefsReplaceInt32("frameskip", 8);}
723     static void mn_10hz(...) {PrefsReplaceInt32("frameskip", 6);}
724     static void mn_15hz(...) {PrefsReplaceInt32("frameskip", 4);}
725     static void mn_30hz(...) {PrefsReplaceInt32("frameskip", 2);}
726     static void mn_60hz(...) {PrefsReplaceInt32("frameskip", 1);}
727    
728 gbeauche 1.9 // QuickDraw acceleration
729     static void tb_gfxaccel(GtkWidget *widget)
730     {
731     PrefsReplaceBool("gfxaccel", GTK_TOGGLE_BUTTON(widget)->active);
732     }
733    
734 gbeauche 1.4 // Set sensitivity of widgets
735     static void set_graphics_sensitive(void)
736     {
737     const bool sound_enabled = !PrefsFindBool("nosound");
738     gtk_widget_set_sensitive(w_dspdevice_file, sound_enabled);
739     gtk_widget_set_sensitive(w_mixerdevice_file, sound_enabled);
740     }
741    
742 cebix 1.1 // "Disable Sound Output" button toggled
743     static void tb_nosound(GtkWidget *widget)
744     {
745     PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active);
746 gbeauche 1.4 set_graphics_sensitive();
747 cebix 1.1 }
748    
749 gbeauche 1.13 // Read and convert graphics preferences
750     static void parse_graphics_prefs(void)
751     {
752     display_type = DISPLAY_WINDOW;
753     dis_width = 640;
754     dis_height = 480;
755    
756     const char *str = PrefsFindString("screen");
757     if (str) {
758     if (sscanf(str, "win/%d/%d", &dis_width, &dis_height) == 2)
759     display_type = DISPLAY_WINDOW;
760     else if (sscanf(str, "dga/%d/%d", &dis_width, &dis_height) == 2)
761     display_type = DISPLAY_SCREEN;
762 gbeauche 1.14 #ifdef ENABLE_FBDEV_DGA
763     else if (sscanf(str, "fbdev/%d/%d", &dis_width, &dis_height) == 2) {
764     is_fbdev_dga_mode = true;
765     display_type = DISPLAY_SCREEN;
766     }
767     #endif
768 gbeauche 1.13 }
769     else {
770     uint32 window_modes = PrefsFindInt32("windowmodes");
771     uint32 screen_modes = PrefsFindInt32("screenmodes");
772     if (screen_modes) {
773     display_type = DISPLAY_SCREEN;
774     static const struct {
775     int id;
776     int width;
777     int height;
778     }
779     modes[] = {
780     { 1, 640, 480 },
781     { 2, 800, 600 },
782     { 4, 1024, 768 },
783     { 64, 1152, 768 },
784     { 8, 1152, 900 },
785     { 16, 1280, 1024 },
786     { 32, 1600, 1200 },
787     { 0, }
788     };
789     for (int i = 0; modes[i].id != 0; i++) {
790     if (screen_modes & modes[i].id) {
791     if (modes[i].width <= screen_width && modes[i].height <= screen_height) {
792     dis_width = modes[i].width;
793     dis_height = modes[i].height;
794     }
795     }
796     }
797     }
798     else if (window_modes) {
799     display_type = DISPLAY_WINDOW;
800     if (window_modes & 1)
801     dis_width = 640, dis_height = 480;
802     if (window_modes & 2)
803     dis_width = 800, dis_height = 600;
804     }
805     }
806     if (dis_width == screen_width)
807     dis_width = 0;
808     if (dis_height == screen_height)
809     dis_height = 0;
810     }
811    
812 cebix 1.1 // Read settings from widgets and set preferences
813     static void read_graphics_settings(void)
814     {
815 gbeauche 1.13 const char *str;
816    
817     str = gtk_entry_get_text(GTK_ENTRY(w_display_x));
818     dis_width = atoi(str);
819    
820     str = gtk_entry_get_text(GTK_ENTRY(w_display_y));
821     dis_height = atoi(str);
822    
823     char pref[256];
824 gbeauche 1.14 bool use_screen_mode = true;
825 gbeauche 1.13 switch (display_type) {
826     case DISPLAY_WINDOW:
827     sprintf(pref, "win/%d/%d", dis_width, dis_height);
828     break;
829     case DISPLAY_SCREEN:
830     sprintf(pref, "dga/%d/%d", dis_width, dis_height);
831     break;
832     default:
833 gbeauche 1.14 use_screen_mode = false;
834 gbeauche 1.13 PrefsRemoveItem("screen");
835     return;
836     }
837 gbeauche 1.14 if (use_screen_mode) {
838     PrefsReplaceString("screen", pref);
839     // Old prefs are now migrated
840     PrefsRemoveItem("windowmodes");
841     PrefsRemoveItem("screenmodes");
842     }
843 gbeauche 1.13
844 gbeauche 1.4 PrefsReplaceString("dsp", get_file_entry_path(w_dspdevice_file));
845     PrefsReplaceString("mixer", get_file_entry_path(w_mixerdevice_file));
846 cebix 1.1 }
847    
848     // Create "Graphics/Sound" pane
849     static void create_graphics_pane(GtkWidget *top)
850     {
851 gbeauche 1.13 GtkWidget *box, *table, *label, *opt, *menu, *combo;
852     char str[32];
853    
854     parse_graphics_prefs();
855 cebix 1.1
856     box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE);
857 gbeauche 1.13 table = make_table(box, 2, 4);
858    
859     label = gtk_label_new(GetString(STR_VIDEO_TYPE_CTRL));
860     gtk_widget_show(label);
861     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
862 cebix 1.1
863 gbeauche 1.13 opt = gtk_option_menu_new();
864     gtk_widget_show(opt);
865     menu = gtk_menu_new();
866     add_menu_item(menu, STR_WINDOW_CTRL, GTK_SIGNAL_FUNC(mn_window));
867     add_menu_item(menu, STR_FULLSCREEN_CTRL, GTK_SIGNAL_FUNC(mn_fullscreen));
868     switch (display_type) {
869     case DISPLAY_WINDOW:
870     gtk_menu_set_active(GTK_MENU(menu), 0);
871     break;
872     case DISPLAY_SCREEN:
873     gtk_menu_set_active(GTK_MENU(menu), 1);
874     break;
875     }
876     gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
877     gtk_table_attach(GTK_TABLE(table), opt, 1, 2, 0, 1, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
878    
879     l_frameskip = gtk_label_new(GetString(STR_FRAMESKIP_CTRL));
880     gtk_widget_show(l_frameskip);
881     gtk_table_attach(GTK_TABLE(table), l_frameskip, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
882    
883     w_frameskip = gtk_option_menu_new();
884     gtk_widget_show(w_frameskip);
885     menu = gtk_menu_new();
886     add_menu_item(menu, STR_REF_5HZ_LAB, GTK_SIGNAL_FUNC(mn_5hz));
887     add_menu_item(menu, STR_REF_7_5HZ_LAB, GTK_SIGNAL_FUNC(mn_7hz));
888     add_menu_item(menu, STR_REF_10HZ_LAB, GTK_SIGNAL_FUNC(mn_10hz));
889     add_menu_item(menu, STR_REF_15HZ_LAB, GTK_SIGNAL_FUNC(mn_15hz));
890     add_menu_item(menu, STR_REF_30HZ_LAB, GTK_SIGNAL_FUNC(mn_30hz));
891     add_menu_item(menu, STR_REF_60HZ_LAB, GTK_SIGNAL_FUNC(mn_60hz));
892     int frameskip = PrefsFindInt32("frameskip");
893     int item = -1;
894 cebix 1.1 switch (frameskip) {
895 gbeauche 1.13 case 12: item = 0; break;
896     case 8: item = 1; break;
897     case 6: item = 2; break;
898     case 4: item = 3; break;
899     case 2: item = 4; break;
900     case 1: item = 5; break;
901     case 0: item = 5; break;
902 cebix 1.1 }
903 gbeauche 1.13 if (item >= 0)
904     gtk_menu_set_active(GTK_MENU(menu), item);
905     gtk_option_menu_set_menu(GTK_OPTION_MENU(w_frameskip), menu);
906     gtk_table_attach(GTK_TABLE(table), w_frameskip, 1, 2, 1, 2, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
907    
908     l_display_x = gtk_label_new(GetString(STR_DISPLAY_X_CTRL));
909     gtk_widget_show(l_display_x);
910     gtk_table_attach(GTK_TABLE(table), l_display_x, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
911 cebix 1.1
912 gbeauche 1.13 combo = gtk_combo_new();
913     gtk_widget_show(combo);
914     GList *glist1 = NULL;
915     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_512_LAB));
916     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_640_LAB));
917     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_800_LAB));
918     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_1024_LAB));
919     glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_MAX_LAB));
920     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist1);
921     if (dis_width)
922     sprintf(str, "%d", dis_width);
923     else
924     strcpy(str, GetString(STR_SIZE_MAX_LAB));
925     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
926     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
927     w_display_x = GTK_COMBO(combo)->entry;
928 gbeauche 1.9
929 gbeauche 1.13 l_display_y = gtk_label_new(GetString(STR_DISPLAY_Y_CTRL));
930     gtk_widget_show(l_display_y);
931     gtk_table_attach(GTK_TABLE(table), l_display_y, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
932 cebix 1.1
933 gbeauche 1.13 combo = gtk_combo_new();
934     gtk_widget_show(combo);
935     GList *glist2 = NULL;
936     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_384_LAB));
937     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_480_LAB));
938     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_600_LAB));
939     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_768_LAB));
940     glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_MAX_LAB));
941     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist2);
942     if (dis_height)
943     sprintf(str, "%d", dis_height);
944     else
945     strcpy(str, GetString(STR_SIZE_MAX_LAB));
946     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
947     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
948     w_display_y = GTK_COMBO(combo)->entry;
949 cebix 1.1
950 gbeauche 1.13 make_checkbox(box, STR_GFXACCEL_CTRL, PrefsFindBool("gfxaccel"), GTK_SIGNAL_FUNC(tb_gfxaccel));
951 cebix 1.1
952 gbeauche 1.4 make_separator(box);
953 cebix 1.1 make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound));
954 gbeauche 1.4 w_dspdevice_file = make_entry(box, STR_DSPDEVICE_FILE_CTRL, "dsp");
955     w_mixerdevice_file = make_entry(box, STR_MIXERDEVICE_FILE_CTRL, "mixer");
956    
957     set_graphics_sensitive();
958 gbeauche 1.13
959     hide_show_graphics_widgets();
960 gbeauche 1.2 }
961    
962    
963     /*
964     * "Input" pane
965     */
966    
967     static GtkWidget *w_keycode_file;
968 gbeauche 1.5 static GtkWidget *w_mouse_wheel_lines;
969 gbeauche 1.2
970     // Set sensitivity of widgets
971     static void set_input_sensitive(void)
972     {
973 gbeauche 1.15 const bool use_keycodes = PrefsFindBool("keycodes");
974     gtk_widget_set_sensitive(w_keycode_file, use_keycodes);
975     gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_keycode_file), "chooser_button")), use_keycodes);
976 gbeauche 1.5 gtk_widget_set_sensitive(w_mouse_wheel_lines, PrefsFindInt32("mousewheelmode") == 1);
977 gbeauche 1.2 }
978    
979     // "Use Raw Keycodes" button toggled
980     static void tb_keycodes(GtkWidget *widget)
981     {
982     PrefsReplaceBool("keycodes", GTK_TOGGLE_BUTTON(widget)->active);
983     set_input_sensitive();
984     }
985    
986 gbeauche 1.5 // "Mouse Wheel Mode" selected
987     static void mn_wheel_page(...) {PrefsReplaceInt32("mousewheelmode", 0); set_input_sensitive();}
988     static void mn_wheel_cursor(...) {PrefsReplaceInt32("mousewheelmode", 1); set_input_sensitive();}
989    
990 gbeauche 1.2 // Read settings from widgets and set preferences
991     static void read_input_settings(void)
992     {
993     const char *str = get_file_entry_path(w_keycode_file);
994     if (str && strlen(str))
995     PrefsReplaceString("keycodefile", str);
996     else
997     PrefsRemoveItem("keycodefile");
998 gbeauche 1.5
999     PrefsReplaceInt32("mousewheellines", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_mouse_wheel_lines)));
1000 gbeauche 1.2 }
1001    
1002     // Create "Input" pane
1003     static void create_input_pane(GtkWidget *top)
1004     {
1005 gbeauche 1.15 GtkWidget *box, *hbox, *menu, *label, *button;
1006 gbeauche 1.2 GtkObject *adj;
1007    
1008     box = make_pane(top, STR_INPUT_PANE_TITLE);
1009    
1010     make_checkbox(box, STR_KEYCODES_CTRL, "keycodes", GTK_SIGNAL_FUNC(tb_keycodes));
1011 gbeauche 1.15
1012     hbox = gtk_hbox_new(FALSE, 4);
1013     gtk_widget_show(hbox);
1014     gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1015    
1016     label = gtk_label_new(GetString(STR_KEYCODES_CTRL));
1017     gtk_widget_show(label);
1018     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1019    
1020     const char *str = PrefsFindString("keycodefile");
1021     if (str == NULL)
1022     str = "";
1023    
1024     w_keycode_file = gtk_entry_new();
1025     gtk_entry_set_text(GTK_ENTRY(w_keycode_file), str);
1026     gtk_widget_show(w_keycode_file);
1027     gtk_box_pack_start(GTK_BOX(hbox), w_keycode_file, TRUE, TRUE, 0);
1028    
1029     button = make_browse_button(w_keycode_file);
1030     gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1031     g_object_set_data(G_OBJECT(w_keycode_file), "chooser_button", button);
1032 gbeauche 1.5
1033     make_separator(box);
1034    
1035     static const opt_desc options[] = {
1036     {STR_MOUSEWHEELMODE_PAGE_LAB, GTK_SIGNAL_FUNC(mn_wheel_page)},
1037     {STR_MOUSEWHEELMODE_CURSOR_LAB, GTK_SIGNAL_FUNC(mn_wheel_cursor)},
1038     {0, NULL}
1039     };
1040     int wheelmode = PrefsFindInt32("mousewheelmode"), active = 0;
1041     switch (wheelmode) {
1042     case 0: active = 0; break;
1043     case 1: active = 1; break;
1044     }
1045     menu = make_option_menu(box, STR_MOUSEWHEELMODE_CTRL, options, active);
1046    
1047     hbox = gtk_hbox_new(FALSE, 4);
1048     gtk_widget_show(hbox);
1049     gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1050    
1051     label = gtk_label_new(GetString(STR_MOUSEWHEELLINES_CTRL));
1052     gtk_widget_show(label);
1053     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1054    
1055     adj = gtk_adjustment_new(PrefsFindInt32("mousewheellines"), 1, 1000, 1, 5, 0);
1056     w_mouse_wheel_lines = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0);
1057     gtk_widget_show(w_mouse_wheel_lines);
1058     gtk_box_pack_start(GTK_BOX(hbox), w_mouse_wheel_lines, FALSE, FALSE, 0);
1059 gbeauche 1.2
1060     set_input_sensitive();
1061 cebix 1.1 }
1062    
1063    
1064     /*
1065     * "Serial/Network" pane
1066     */
1067    
1068     static GtkWidget *w_seriala, *w_serialb, *w_ether;
1069    
1070     // Read settings from widgets and set preferences
1071     static void read_serial_settings(void)
1072     {
1073     const char *str;
1074    
1075     str = gtk_entry_get_text(GTK_ENTRY(w_seriala));
1076     PrefsReplaceString("seriala", str);
1077    
1078     str = gtk_entry_get_text(GTK_ENTRY(w_serialb));
1079     PrefsReplaceString("serialb", str);
1080    
1081     str = gtk_entry_get_text(GTK_ENTRY(w_ether));
1082     if (str && strlen(str))
1083     PrefsReplaceString("ether", str);
1084     else
1085     PrefsRemoveItem("ether");
1086     }
1087    
1088     // Add names of serial devices
1089     static gint gl_str_cmp(gconstpointer a, gconstpointer b)
1090     {
1091     return strcmp((char *)a, (char *)b);
1092     }
1093    
1094     static GList *add_serial_names(void)
1095     {
1096     GList *glist = NULL;
1097    
1098     // Search /dev for ttyS* and lp*
1099     DIR *d = opendir("/dev");
1100     if (d) {
1101     struct dirent *de;
1102     while ((de = readdir(d)) != NULL) {
1103 gbeauche 1.7 #if defined(__linux__)
1104 cebix 1.1 if (strncmp(de->d_name, "ttyS", 4) == 0 || strncmp(de->d_name, "lp", 2) == 0) {
1105 gbeauche 1.7 #elif defined(__FreeBSD__)
1106     if (strncmp(de->d_name, "cuaa", 4) == 0 || strncmp(de->d_name, "lpt", 3) == 0) {
1107     #elif defined(__NetBSD__)
1108     if (strncmp(de->d_name, "tty0", 4) == 0 || strncmp(de->d_name, "lpt", 3) == 0) {
1109     #elif defined(sgi)
1110     if (strncmp(de->d_name, "ttyf", 4) == 0 || strncmp(de->d_name, "plp", 3) == 0) {
1111     #else
1112     if (false) {
1113     #endif
1114 cebix 1.1 char *str = new char[64];
1115     sprintf(str, "/dev/%s", de->d_name);
1116     glist = g_list_append(glist, str);
1117     }
1118     }
1119     closedir(d);
1120     }
1121     if (glist)
1122     g_list_sort(glist, gl_str_cmp);
1123     else
1124     glist = g_list_append(glist, (void *)"<none>");
1125     return glist;
1126     }
1127    
1128     // Add names of ethernet interfaces
1129     static GList *add_ether_names(void)
1130     {
1131     GList *glist = NULL;
1132    
1133     // Get list of all Ethernet interfaces
1134     int s = socket(PF_INET, SOCK_DGRAM, 0);
1135     if (s >= 0) {
1136     char inbuf[8192];
1137     struct ifconf ifc;
1138     ifc.ifc_len = sizeof(inbuf);
1139     ifc.ifc_buf = inbuf;
1140     if (ioctl(s, SIOCGIFCONF, &ifc) == 0) {
1141     struct ifreq req, *ifr = ifc.ifc_req;
1142     for (int i=0; i<ifc.ifc_len; i+=sizeof(ifreq), ifr++) {
1143     req = *ifr;
1144 gbeauche 1.7 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(sgi)
1145     if (ioctl(s, SIOCGIFADDR, &req) == 0 && (req.ifr_addr.sa_family == ARPHRD_ETHER || req.ifr_addr.sa_family == ARPHRD_ETHER+1)) {
1146     #elif defined(__linux__)
1147 cebix 1.1 if (ioctl(s, SIOCGIFHWADDR, &req) == 0 && req.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
1148 gbeauche 1.7 #else
1149     if (false) {
1150     #endif
1151 cebix 1.1 char *str = new char[64];
1152     strncpy(str, ifr->ifr_name, 63);
1153     glist = g_list_append(glist, str);
1154     }
1155     }
1156     }
1157     close(s);
1158     }
1159 gbeauche 1.15 #ifdef HAVE_SLIRP
1160     static char s_slirp[] = "slirp";
1161     glist = g_list_append(glist, s_slirp);
1162     #endif
1163 cebix 1.1 if (glist)
1164     g_list_sort(glist, gl_str_cmp);
1165     else
1166     glist = g_list_append(glist, (void *)"<none>");
1167     return glist;
1168     }
1169    
1170     // Create "Serial/Network" pane
1171     static void create_serial_pane(GtkWidget *top)
1172     {
1173     GtkWidget *box, *table, *label, *combo;
1174     GList *glist = add_serial_names();
1175    
1176     box = make_pane(top, STR_SERIAL_NETWORK_PANE_TITLE);
1177     table = make_table(box, 2, 3);
1178    
1179     label = gtk_label_new(GetString(STR_SERPORTA_CTRL));
1180     gtk_widget_show(label);
1181     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1182    
1183     combo = gtk_combo_new();
1184     gtk_widget_show(combo);
1185     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1186     const char *str = PrefsFindString("seriala");
1187     if (str == NULL)
1188     str = "";
1189     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1190     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1191     w_seriala = GTK_COMBO(combo)->entry;
1192    
1193     label = gtk_label_new(GetString(STR_SERPORTB_CTRL));
1194     gtk_widget_show(label);
1195     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1196    
1197     combo = gtk_combo_new();
1198     gtk_widget_show(combo);
1199     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1200     str = PrefsFindString("serialb");
1201     if (str == NULL)
1202     str = "";
1203     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1204     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 1, 2, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1205     w_serialb = GTK_COMBO(combo)->entry;
1206    
1207     label = gtk_label_new(GetString(STR_ETHERNET_IF_CTRL));
1208     gtk_widget_show(label);
1209     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1210    
1211     glist = add_ether_names();
1212     combo = gtk_combo_new();
1213     gtk_widget_show(combo);
1214     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1215     str = PrefsFindString("ether");
1216     if (str == NULL)
1217     str = "";
1218     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1219     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1220     w_ether = GTK_COMBO(combo)->entry;
1221     }
1222    
1223    
1224     /*
1225     * "Memory/Misc" pane
1226     */
1227    
1228 gbeauche 1.15 static GtkWidget *w_ramsize;
1229 cebix 1.1 static GtkWidget *w_rom_file;
1230    
1231 gbeauche 1.9 // Don't use CPU when idle?
1232     static void tb_idlewait(GtkWidget *widget)
1233     {
1234     PrefsReplaceBool("idlewait", GTK_TOGGLE_BUTTON(widget)->active);
1235     }
1236    
1237 cebix 1.1 // "Ignore SEGV" button toggled
1238     static void tb_ignoresegv(GtkWidget *widget)
1239     {
1240     PrefsReplaceBool("ignoresegv", GTK_TOGGLE_BUTTON(widget)->active);
1241     }
1242    
1243     // Read settings from widgets and set preferences
1244     static void read_memory_settings(void)
1245     {
1246 gbeauche 1.15 const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_ramsize)->entry));
1247     PrefsReplaceInt32("ramsize", atoi(str) << 20);
1248 cebix 1.1
1249 gbeauche 1.15 str = gtk_entry_get_text(GTK_ENTRY(w_rom_file));
1250 cebix 1.1 if (str && strlen(str))
1251     PrefsReplaceString("rom", str);
1252     else
1253     PrefsRemoveItem("rom");
1254     }
1255    
1256     // Create "Memory/Misc" pane
1257     static void create_memory_pane(GtkWidget *top)
1258     {
1259 gbeauche 1.15 GtkWidget *box, *hbox, *table, *label, *menu;
1260 cebix 1.1
1261     box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE);
1262 gbeauche 1.15 table = make_table(box, 2, 5);
1263 cebix 1.1
1264 gbeauche 1.15 static const combo_desc options[] = {
1265     STR_RAMSIZE_4MB_LAB,
1266     STR_RAMSIZE_8MB_LAB,
1267     STR_RAMSIZE_16MB_LAB,
1268     STR_RAMSIZE_32MB_LAB,
1269     STR_RAMSIZE_64MB_LAB,
1270     STR_RAMSIZE_128MB_LAB,
1271     STR_RAMSIZE_256MB_LAB,
1272     STR_RAMSIZE_512MB_LAB,
1273     0
1274     };
1275     char default_ramsize[10];
1276     sprintf(default_ramsize, "%d", PrefsFindInt32("ramsize") >> 20);
1277     w_ramsize = table_make_combobox(table, 0, STR_RAMSIZE_CTRL, default_ramsize, options);
1278 cebix 1.1
1279 gbeauche 1.15 w_rom_file = table_make_file_entry(table, 1, STR_ROM_FILE_CTRL, "rom");
1280 cebix 1.1
1281     make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv));
1282 gbeauche 1.9 make_checkbox(box, STR_IDLEWAIT_CTRL, "idlewait", GTK_SIGNAL_FUNC(tb_idlewait));
1283 cebix 1.1 }
1284    
1285    
1286     /*
1287     * Read settings from widgets and set preferences
1288     */
1289    
1290     static void read_settings(void)
1291     {
1292     read_volumes_settings();
1293     read_graphics_settings();
1294     read_serial_settings();
1295     read_memory_settings();
1296 gbeauche 1.3 read_jit_settings();
1297 cebix 1.1 }