ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/prefs_editor_gtk.cpp
Revision: 1.1
Committed: 2002-02-04T16:58:13Z (22 years, 4 months ago) by cebix
Branch: MAIN
Branch point for: cebix
Log Message:
Initial revision

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * prefs_editor_linux.cpp - Preferences editor, Linux implementation using GTK+
3     *
4     * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig
5     *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include "sysdeps.h"
22    
23     #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    
43    
44     // Prototypes
45     static void create_volumes_pane(GtkWidget *top);
46     static void create_graphics_pane(GtkWidget *top);
47     static void create_serial_pane(GtkWidget *top);
48     static void create_memory_pane(GtkWidget *top);
49     static void read_settings(void);
50    
51    
52     /*
53     * Utility functions
54     */
55    
56     struct opt_desc {
57     int label_id;
58     GtkSignalFunc func;
59     };
60    
61     static void add_menu_item(GtkWidget *menu, int label_id, GtkSignalFunc func)
62     {
63     GtkWidget *item = gtk_menu_item_new_with_label(GetString(label_id));
64     gtk_widget_show(item);
65     gtk_signal_connect(GTK_OBJECT(item), "activate", func, NULL);
66     gtk_menu_append(GTK_MENU(menu), item);
67     }
68    
69     static GtkWidget *make_pane(GtkWidget *notebook, int title_id)
70     {
71     GtkWidget *frame, *label, *box;
72    
73     frame = gtk_frame_new(NULL);
74     gtk_widget_show(frame);
75     gtk_container_border_width(GTK_CONTAINER(frame), 4);
76    
77     label = gtk_label_new(GetString(title_id));
78     gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label);
79    
80     box = gtk_vbox_new(FALSE, 4);
81     gtk_widget_show(box);
82     gtk_container_set_border_width(GTK_CONTAINER(box), 4);
83     gtk_container_add(GTK_CONTAINER(frame), box);
84     return box;
85     }
86    
87     static GtkWidget *make_button_box(GtkWidget *top, int border, const opt_desc *buttons)
88     {
89     GtkWidget *bb, *button;
90    
91     bb = gtk_hbutton_box_new();
92     gtk_widget_show(bb);
93     gtk_container_set_border_width(GTK_CONTAINER(bb), border);
94     gtk_button_box_set_layout(GTK_BUTTON_BOX(bb), GTK_BUTTONBOX_DEFAULT_STYLE);
95     gtk_button_box_set_spacing(GTK_BUTTON_BOX(bb), 4);
96     gtk_box_pack_start(GTK_BOX(top), bb, FALSE, FALSE, 0);
97    
98     while (buttons->label_id) {
99     button = gtk_button_new_with_label(GetString(buttons->label_id));
100     gtk_widget_show(button);
101     gtk_signal_connect_object(GTK_OBJECT(button), "clicked", buttons->func, NULL);
102     gtk_box_pack_start(GTK_BOX(bb), button, TRUE, TRUE, 0);
103     buttons++;
104     }
105     return bb;
106     }
107    
108     static GtkWidget *make_separator(GtkWidget *top)
109     {
110     GtkWidget *sep = gtk_hseparator_new();
111     gtk_box_pack_start(GTK_BOX(top), sep, FALSE, FALSE, 0);
112     gtk_widget_show(sep);
113     return sep;
114     }
115    
116     static GtkWidget *make_table(GtkWidget *top, int x, int y)
117     {
118     GtkWidget *table = gtk_table_new(x, y, FALSE);
119     gtk_widget_show(table);
120     gtk_box_pack_start(GTK_BOX(top), table, FALSE, FALSE, 0);
121     return table;
122     }
123    
124     static GtkWidget *make_option_menu(GtkWidget *top, int label_id, const opt_desc *options, int active)
125     {
126     GtkWidget *box, *label, *opt, *menu;
127    
128     box = gtk_hbox_new(FALSE, 4);
129     gtk_widget_show(box);
130     gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0);
131    
132     label = gtk_label_new(GetString(label_id));
133     gtk_widget_show(label);
134     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
135    
136     opt = gtk_option_menu_new();
137     gtk_widget_show(opt);
138     menu = gtk_menu_new();
139    
140     while (options->label_id) {
141     add_menu_item(menu, options->label_id, options->func);
142     options++;
143     }
144     gtk_menu_set_active(GTK_MENU(menu), active);
145    
146     gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
147     gtk_box_pack_start(GTK_BOX(box), opt, FALSE, FALSE, 0);
148     return menu;
149     }
150    
151     static GtkWidget *make_entry(GtkWidget *top, int label_id, const char *prefs_item)
152     {
153     GtkWidget *box, *label, *entry;
154    
155     box = gtk_hbox_new(FALSE, 4);
156     gtk_widget_show(box);
157     gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0);
158    
159     label = gtk_label_new(GetString(label_id));
160     gtk_widget_show(label);
161     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
162    
163     entry = gtk_entry_new();
164     gtk_widget_show(entry);
165     const char *str = PrefsFindString(prefs_item);
166     if (str == NULL)
167     str = "";
168     gtk_entry_set_text(GTK_ENTRY(entry), str);
169     gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0);
170     return entry;
171     }
172    
173     static GtkWidget *make_checkbox(GtkWidget *top, int label_id, const char *prefs_item, GtkSignalFunc func)
174     {
175     GtkWidget *button = gtk_check_button_new_with_label(GetString(label_id));
176     gtk_widget_show(button);
177     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), PrefsFindBool(prefs_item));
178     gtk_signal_connect(GTK_OBJECT(button), "toggled", func, button);
179     gtk_box_pack_start(GTK_BOX(top), button, FALSE, FALSE, 0);
180     return button;
181     }
182    
183     static GtkWidget *make_checkbox(GtkWidget *top, int label_id, bool active, GtkSignalFunc func)
184     {
185     GtkWidget *button = gtk_check_button_new_with_label(GetString(label_id));
186     gtk_widget_show(button);
187     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), active);
188     gtk_signal_connect(GTK_OBJECT(button), "toggled", func, button);
189     gtk_box_pack_start(GTK_BOX(top), button, FALSE, FALSE, 0);
190     return button;
191     }
192    
193    
194     /*
195     * Show preferences editor
196     * Returns true when user clicked on "Start", false otherwise
197     */
198    
199     // Window closed
200     static gint window_closed(void)
201     {
202     return FALSE;
203     }
204    
205     // Window destroyed
206     static void window_destroyed(void)
207     {
208     gtk_main_quit();
209     }
210    
211     // "Start" button clicked
212     static void cb_start(...)
213     {
214     start_clicked = true;
215     read_settings();
216     SavePrefs();
217     gtk_widget_destroy(win);
218     }
219    
220     // "Quit" button clicked
221     static void cb_quit(...)
222     {
223     start_clicked = false;
224     gtk_widget_destroy(win);
225     }
226    
227     // "OK" button of "About" dialog clicked
228     static void dl_quit(GtkWidget *dialog)
229     {
230     gtk_widget_destroy(dialog);
231     }
232    
233     // "About" selected
234     static void mn_about(...)
235     {
236     GtkWidget *dialog, *label, *button;
237    
238     char str[512];
239     sprintf(str,
240     "SheepShaver\nVersion %d.%d\n\n"
241     "Copyright (C) 1997-2002 Christian Bauer and Marc Hellwig\n"
242     "E-mail: Christian.Bauer@uni-mainz.de\n"
243     "http://www.uni-mainz.de/~bauec002/\n\n"
244     "SheepShaver comes with ABSOLUTELY NO\n"
245     "WARRANTY. This is free software, and\n"
246     "you are welcome to redistribute it\n"
247     "under the terms of the GNU General\n"
248     "Public License.\n",
249     VERSION_MAJOR, VERSION_MINOR
250     );
251    
252     dialog = gtk_dialog_new();
253     gtk_window_set_title(GTK_WINDOW(dialog), GetString(STR_ABOUT_TITLE));
254     gtk_container_border_width(GTK_CONTAINER(dialog), 5);
255     gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
256    
257     label = gtk_label_new(str);
258     gtk_widget_show(label);
259     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
260    
261     button = gtk_button_new_with_label(GetString(STR_OK_BUTTON));
262     gtk_widget_show(button);
263     gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
264     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
265     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
266     gtk_widget_grab_default(button);
267     gtk_widget_show(dialog);
268     }
269    
270     // "Zap NVRAM" selected
271     static void mn_zap_pram(...)
272     {
273     ZapPRAM();
274     }
275    
276     // Menu item descriptions
277     static GtkItemFactoryEntry menu_items[] = {
278     {(gchar *)GetString(STR_PREFS_MENU_FILE_GTK), NULL, NULL, 0, "<Branch>"},
279     {(gchar *)GetString(STR_PREFS_ITEM_START_GTK), NULL, GTK_SIGNAL_FUNC(cb_start), 0, NULL},
280     {(gchar *)GetString(STR_PREFS_ITEM_ZAP_PRAM_GTK), NULL, GTK_SIGNAL_FUNC(mn_zap_pram), 0, NULL},
281     {(gchar *)GetString(STR_PREFS_ITEM_SEPL_GTK), NULL, NULL, 0, "<Separator>"},
282     {(gchar *)GetString(STR_PREFS_ITEM_QUIT_GTK), "<control>Q", GTK_SIGNAL_FUNC(cb_quit), 0, NULL},
283     {(gchar *)GetString(STR_HELP_MENU_GTK), NULL, NULL, 0, "<LastBranch>"},
284     {(gchar *)GetString(STR_HELP_ITEM_ABOUT_GTK), NULL, GTK_SIGNAL_FUNC(mn_about), 0, NULL}
285     };
286    
287     bool PrefsEditor(void)
288     {
289     // Create window
290     win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
291     gtk_window_set_title(GTK_WINDOW(win), GetString(STR_PREFS_TITLE));
292     gtk_signal_connect(GTK_OBJECT(win), "delete_event", GTK_SIGNAL_FUNC(window_closed), NULL);
293     gtk_signal_connect(GTK_OBJECT(win), "destroy", GTK_SIGNAL_FUNC(window_destroyed), NULL);
294    
295     // Create window contents
296     GtkWidget *box = gtk_vbox_new(FALSE, 4);
297     gtk_widget_show(box);
298     gtk_container_add(GTK_CONTAINER(win), box);
299    
300     GtkAccelGroup *accel_group = gtk_accel_group_new();
301     GtkItemFactory *item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
302     gtk_item_factory_create_items(item_factory, sizeof(menu_items) / sizeof(menu_items[0]), menu_items, NULL);
303     gtk_accel_group_attach(accel_group, GTK_OBJECT(win));
304     GtkWidget *menu_bar = gtk_item_factory_get_widget(item_factory, "<main>");
305     gtk_widget_show(menu_bar);
306     gtk_box_pack_start(GTK_BOX(box), menu_bar, FALSE, TRUE, 0);
307    
308     GtkWidget *notebook = gtk_notebook_new();
309     gtk_widget_show(notebook);
310     gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
311     gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), FALSE);
312     gtk_box_pack_start(GTK_BOX(box), notebook, TRUE, TRUE, 0);
313    
314     create_volumes_pane(notebook);
315     create_graphics_pane(notebook);
316     create_serial_pane(notebook);
317     create_memory_pane(notebook);
318    
319     static const opt_desc buttons[] = {
320     {STR_START_BUTTON, GTK_SIGNAL_FUNC(cb_start)},
321     {STR_QUIT_BUTTON, GTK_SIGNAL_FUNC(cb_quit)},
322     {0, NULL}
323     };
324     make_button_box(box, 4, buttons);
325    
326     // Show window and enter main loop
327     gtk_widget_show(win);
328     gtk_main();
329     return start_clicked;
330     }
331    
332    
333     /*
334     * "Volumes" pane
335     */
336    
337     static GtkWidget *volume_list, *w_extfs;
338     static int selected_volume;
339    
340     // Volume in list selected
341     static void cl_selected(GtkWidget *list, int row, int column)
342     {
343     selected_volume = row;
344     }
345    
346     struct file_req_assoc {
347     file_req_assoc(GtkWidget *r, GtkWidget *e) : req(r), entry(e) {}
348     GtkWidget *req;
349     GtkWidget *entry;
350     };
351    
352     // Volume selected for addition
353     static void add_volume_ok(GtkWidget *button, file_req_assoc *assoc)
354     {
355     char *file = gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
356     gtk_clist_append(GTK_CLIST(volume_list), &file);
357     gtk_widget_destroy(assoc->req);
358     delete assoc;
359     }
360    
361     // Volume selected for creation
362     static void create_volume_ok(GtkWidget *button, file_req_assoc *assoc)
363     {
364     char *file = gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
365    
366     char *str = gtk_entry_get_text(GTK_ENTRY(assoc->entry));
367     int size = atoi(str);
368    
369     char cmd[1024];
370     sprintf(cmd, "dd if=/dev/zero \"of=%s\" bs=1024k count=%d", file, size);
371     int ret = system(cmd);
372     if (ret == 0)
373     gtk_clist_append(GTK_CLIST(volume_list), &file);
374     gtk_widget_destroy(GTK_WIDGET(assoc->req));
375     delete assoc;
376     }
377    
378     // "Add Volume" button clicked
379     static void cb_add_volume(...)
380     {
381     GtkWidget *req = gtk_file_selection_new(GetString(STR_ADD_VOLUME_TITLE));
382     gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
383     gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(add_volume_ok), new file_req_assoc(req, NULL));
384     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
385     gtk_widget_show(req);
386     }
387    
388     // "Create Hardfile" button clicked
389     static void cb_create_volume(...)
390     {
391     GtkWidget *req = gtk_file_selection_new(GetString(STR_CREATE_VOLUME_TITLE));
392    
393     GtkWidget *box = gtk_hbox_new(FALSE, 4);
394     gtk_widget_show(box);
395     GtkWidget *label = gtk_label_new(GetString(STR_HARDFILE_SIZE_CTRL));
396     gtk_widget_show(label);
397     GtkWidget *entry = gtk_entry_new();
398     gtk_widget_show(entry);
399     char str[32];
400     sprintf(str, "%d", 40);
401     gtk_entry_set_text(GTK_ENTRY(entry), str);
402     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
403     gtk_box_pack_start(GTK_BOX(box), entry, FALSE, FALSE, 0);
404     gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(req)->main_vbox), box, FALSE, FALSE, 0);
405    
406     gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
407     gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(create_volume_ok), new file_req_assoc(req, entry));
408     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
409     gtk_widget_show(req);
410     }
411    
412     // "Remove Volume" button clicked
413     static void cb_remove_volume(...)
414     {
415     gtk_clist_remove(GTK_CLIST(volume_list), selected_volume);
416     }
417    
418     // "Boot From" selected
419     static void mn_boot_any(...) {PrefsReplaceInt32("bootdriver", 0);}
420     static void mn_boot_cdrom(...) {PrefsReplaceInt32("bootdriver", CDROMRefNum);}
421    
422     // "No CD-ROM Driver" button toggled
423     static void tb_nocdrom(GtkWidget *widget)
424     {
425     PrefsReplaceBool("nocdrom", GTK_TOGGLE_BUTTON(widget)->active);
426     }
427    
428     // Read settings from widgets and set preferences
429     static void read_volumes_settings(void)
430     {
431     while (PrefsFindString("disk"))
432     PrefsRemoveItem("disk");
433    
434     for (int i=0; i<GTK_CLIST(volume_list)->rows; i++) {
435     char *str;
436     gtk_clist_get_text(GTK_CLIST(volume_list), i, 0, &str);
437     PrefsAddString("disk", str);
438     }
439    
440     PrefsReplaceString("extfs", gtk_entry_get_text(GTK_ENTRY(w_extfs)));
441     }
442    
443     // Create "Volumes" pane
444     static void create_volumes_pane(GtkWidget *top)
445     {
446     GtkWidget *box, *scroll, *menu;
447    
448     box = make_pane(top, STR_VOLUMES_PANE_TITLE);
449    
450     scroll = gtk_scrolled_window_new(NULL, NULL);
451     gtk_widget_show(scroll);
452     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
453     volume_list = gtk_clist_new(1);
454     gtk_widget_show(volume_list);
455     gtk_clist_set_selection_mode(GTK_CLIST(volume_list), GTK_SELECTION_SINGLE);
456     gtk_clist_set_shadow_type(GTK_CLIST(volume_list), GTK_SHADOW_NONE);
457     gtk_clist_set_reorderable(GTK_CLIST(volume_list), true);
458     gtk_signal_connect(GTK_OBJECT(volume_list), "select_row", GTK_SIGNAL_FUNC(cl_selected), NULL);
459     char *str;
460     int32 index = 0;
461     while ((str = (char *)PrefsFindString("disk", index++)) != NULL)
462     gtk_clist_append(GTK_CLIST(volume_list), &str);
463     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), volume_list);
464     gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 0);
465     selected_volume = 0;
466    
467     static const opt_desc buttons[] = {
468     {STR_ADD_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_add_volume)},
469     {STR_CREATE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_create_volume)},
470     {STR_REMOVE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_remove_volume)},
471     {0, NULL},
472     };
473     make_button_box(box, 0, buttons);
474     make_separator(box);
475    
476     w_extfs = make_entry(box, STR_EXTFS_CTRL, "extfs");
477    
478     static const opt_desc options[] = {
479     {STR_BOOT_ANY_LAB, GTK_SIGNAL_FUNC(mn_boot_any)},
480     {STR_BOOT_CDROM_LAB, GTK_SIGNAL_FUNC(mn_boot_cdrom)},
481     {0, NULL}
482     };
483     int bootdriver = PrefsFindInt32("bootdriver"), active = 0;
484     switch (bootdriver) {
485     case 0: active = 0; break;
486     case CDROMRefNum: active = 1; break;
487     }
488     menu = make_option_menu(box, STR_BOOTDRIVER_CTRL, options, active);
489    
490     make_checkbox(box, STR_NOCDROM_CTRL, "nocdrom", GTK_SIGNAL_FUNC(tb_nocdrom));
491     }
492    
493    
494     /*
495     * "Graphics/Sound" pane
496     */
497    
498     static GtkWidget *w_frameskip;
499    
500     // "5 Hz".."60Hz" selected
501     static void mn_5hz(...) {PrefsReplaceInt32("frameskip", 12);}
502     static void mn_7hz(...) {PrefsReplaceInt32("frameskip", 8);}
503     static void mn_10hz(...) {PrefsReplaceInt32("frameskip", 6);}
504     static void mn_15hz(...) {PrefsReplaceInt32("frameskip", 4);}
505     static void mn_30hz(...) {PrefsReplaceInt32("frameskip", 2);}
506     static void mn_60hz(...) {PrefsReplaceInt32("frameskip", 1);}
507    
508     // Video modes
509     static void tb_w640x480(GtkWidget *widget)
510     {
511     if (GTK_TOGGLE_BUTTON(widget)->active)
512     PrefsReplaceInt32("windowmodes", PrefsFindInt32("windowmodes") | 1);
513     else
514     PrefsReplaceInt32("windowmodes", PrefsFindInt32("windowmodes") & ~1);
515     }
516    
517     static void tb_w800x600(GtkWidget *widget)
518     {
519     if (GTK_TOGGLE_BUTTON(widget)->active)
520     PrefsReplaceInt32("windowmodes", PrefsFindInt32("windowmodes") | 2);
521     else
522     PrefsReplaceInt32("windowmodes", PrefsFindInt32("windowmodes") & ~2);
523     }
524    
525     static void tb_fs640x480(GtkWidget *widget)
526     {
527     if (GTK_TOGGLE_BUTTON(widget)->active)
528     PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 1);
529     else
530     PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~1);
531     }
532    
533     static void tb_fs800x600(GtkWidget *widget)
534     {
535     if (GTK_TOGGLE_BUTTON(widget)->active)
536     PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 2);
537     else
538     PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~2);
539     }
540    
541     static void tb_fs1024x768(GtkWidget *widget)
542     {
543     if (GTK_TOGGLE_BUTTON(widget)->active)
544     PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 4);
545     else
546     PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~4);
547     }
548    
549     static void tb_fs1152x900(GtkWidget *widget)
550     {
551     if (GTK_TOGGLE_BUTTON(widget)->active)
552     PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 8);
553     else
554     PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~8);
555     }
556    
557     static void tb_fs1280x1024(GtkWidget *widget)
558     {
559     if (GTK_TOGGLE_BUTTON(widget)->active)
560     PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 16);
561     else
562     PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~16);
563     }
564    
565     static void tb_fs1600x1200(GtkWidget *widget)
566     {
567     if (GTK_TOGGLE_BUTTON(widget)->active)
568     PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 32);
569     else
570     PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~32);
571     }
572    
573     // "Disable Sound Output" button toggled
574     static void tb_nosound(GtkWidget *widget)
575     {
576     PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active);
577     }
578    
579     // Read settings from widgets and set preferences
580     static void read_graphics_settings(void)
581     {
582     }
583    
584     // Create "Graphics/Sound" pane
585     static void create_graphics_pane(GtkWidget *top)
586     {
587     GtkWidget *box, *vbox, *frame;
588    
589     box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE);
590    
591     static const opt_desc options[] = {
592     {STR_REF_5HZ_LAB, GTK_SIGNAL_FUNC(mn_5hz)},
593     {STR_REF_7_5HZ_LAB, GTK_SIGNAL_FUNC(mn_7hz)},
594     {STR_REF_10HZ_LAB, GTK_SIGNAL_FUNC(mn_10hz)},
595     {STR_REF_15HZ_LAB, GTK_SIGNAL_FUNC(mn_15hz)},
596     {STR_REF_30HZ_LAB, GTK_SIGNAL_FUNC(mn_30hz)},
597     {STR_REF_60HZ_LAB, GTK_SIGNAL_FUNC(mn_60hz)},
598     {0, NULL}
599     };
600     int frameskip = PrefsFindInt32("frameskip"), active = 0;
601     switch (frameskip) {
602     case 12: active = 0; break;
603     case 8: active = 1; break;
604     case 6: active = 2; break;
605     case 4: active = 3; break;
606     case 2: active = 4; break;
607     case 1: active = 5; break;
608     }
609     w_frameskip = make_option_menu(box, STR_FRAMESKIP_CTRL, options, active);
610    
611     frame = gtk_frame_new (GetString(STR_VIDEO_MODE_CTRL));
612     gtk_widget_show(frame);
613     gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 0);
614    
615     vbox = gtk_vbox_new(FALSE, 4);
616     gtk_widget_show(vbox);
617     gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
618     gtk_container_add(GTK_CONTAINER(frame), vbox);
619    
620     make_checkbox(vbox, STR_W_640x480_CTRL, PrefsFindInt32("windowmodes") & 1, GTK_SIGNAL_FUNC(tb_w640x480));
621     make_checkbox(vbox, STR_W_800x600_CTRL, PrefsFindInt32("windowmodes") & 2, GTK_SIGNAL_FUNC(tb_w800x600));
622     make_checkbox(vbox, STR_640x480_CTRL, PrefsFindInt32("screenmodes") & 1, GTK_SIGNAL_FUNC(tb_fs640x480));
623     make_checkbox(vbox, STR_800x600_CTRL, PrefsFindInt32("screenmodes") & 2, GTK_SIGNAL_FUNC(tb_fs800x600));
624     make_checkbox(vbox, STR_1024x768_CTRL, PrefsFindInt32("screenmodes") & 4, GTK_SIGNAL_FUNC(tb_fs1024x768));
625     make_checkbox(vbox, STR_1152x900_CTRL, PrefsFindInt32("screenmodes") & 8, GTK_SIGNAL_FUNC(tb_fs1152x900));
626     make_checkbox(vbox, STR_1280x1024_CTRL, PrefsFindInt32("screenmodes") & 16, GTK_SIGNAL_FUNC(tb_fs1280x1024));
627     make_checkbox(vbox, STR_1600x1200_CTRL, PrefsFindInt32("screenmodes") & 32, GTK_SIGNAL_FUNC(tb_fs1600x1200));
628    
629     make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound));
630     }
631    
632    
633     /*
634     * "Serial/Network" pane
635     */
636    
637     static GtkWidget *w_seriala, *w_serialb, *w_ether;
638    
639     // Read settings from widgets and set preferences
640     static void read_serial_settings(void)
641     {
642     const char *str;
643    
644     str = gtk_entry_get_text(GTK_ENTRY(w_seriala));
645     PrefsReplaceString("seriala", str);
646    
647     str = gtk_entry_get_text(GTK_ENTRY(w_serialb));
648     PrefsReplaceString("serialb", str);
649    
650     str = gtk_entry_get_text(GTK_ENTRY(w_ether));
651     if (str && strlen(str))
652     PrefsReplaceString("ether", str);
653     else
654     PrefsRemoveItem("ether");
655     }
656    
657     // Add names of serial devices
658     static gint gl_str_cmp(gconstpointer a, gconstpointer b)
659     {
660     return strcmp((char *)a, (char *)b);
661     }
662    
663     static GList *add_serial_names(void)
664     {
665     GList *glist = NULL;
666    
667     // Search /dev for ttyS* and lp*
668     DIR *d = opendir("/dev");
669     if (d) {
670     struct dirent *de;
671     while ((de = readdir(d)) != NULL) {
672     if (strncmp(de->d_name, "ttyS", 4) == 0 || strncmp(de->d_name, "lp", 2) == 0) {
673     char *str = new char[64];
674     sprintf(str, "/dev/%s", de->d_name);
675     glist = g_list_append(glist, str);
676     }
677     }
678     closedir(d);
679     }
680     if (glist)
681     g_list_sort(glist, gl_str_cmp);
682     else
683     glist = g_list_append(glist, (void *)"<none>");
684     return glist;
685     }
686    
687     // Add names of ethernet interfaces
688     static GList *add_ether_names(void)
689     {
690     GList *glist = NULL;
691    
692     // Get list of all Ethernet interfaces
693     int s = socket(PF_INET, SOCK_DGRAM, 0);
694     if (s >= 0) {
695     char inbuf[8192];
696     struct ifconf ifc;
697     ifc.ifc_len = sizeof(inbuf);
698     ifc.ifc_buf = inbuf;
699     if (ioctl(s, SIOCGIFCONF, &ifc) == 0) {
700     struct ifreq req, *ifr = ifc.ifc_req;
701     for (int i=0; i<ifc.ifc_len; i+=sizeof(ifreq), ifr++) {
702     req = *ifr;
703     if (ioctl(s, SIOCGIFHWADDR, &req) == 0 && req.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
704     char *str = new char[64];
705     strncpy(str, ifr->ifr_name, 63);
706     glist = g_list_append(glist, str);
707     }
708     }
709     }
710     close(s);
711     }
712     if (glist)
713     g_list_sort(glist, gl_str_cmp);
714     else
715     glist = g_list_append(glist, (void *)"<none>");
716     return glist;
717     }
718    
719     // Create "Serial/Network" pane
720     static void create_serial_pane(GtkWidget *top)
721     {
722     GtkWidget *box, *table, *label, *combo;
723     GList *glist = add_serial_names();
724    
725     box = make_pane(top, STR_SERIAL_NETWORK_PANE_TITLE);
726     table = make_table(box, 2, 3);
727    
728     label = gtk_label_new(GetString(STR_SERPORTA_CTRL));
729     gtk_widget_show(label);
730     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
731    
732     combo = gtk_combo_new();
733     gtk_widget_show(combo);
734     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
735     const char *str = PrefsFindString("seriala");
736     if (str == NULL)
737     str = "";
738     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
739     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
740     w_seriala = GTK_COMBO(combo)->entry;
741    
742     label = gtk_label_new(GetString(STR_SERPORTB_CTRL));
743     gtk_widget_show(label);
744     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
745    
746     combo = gtk_combo_new();
747     gtk_widget_show(combo);
748     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
749     str = PrefsFindString("serialb");
750     if (str == NULL)
751     str = "";
752     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
753     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 1, 2, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
754     w_serialb = GTK_COMBO(combo)->entry;
755    
756     label = gtk_label_new(GetString(STR_ETHERNET_IF_CTRL));
757     gtk_widget_show(label);
758     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
759    
760     glist = add_ether_names();
761     combo = gtk_combo_new();
762     gtk_widget_show(combo);
763     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
764     str = PrefsFindString("ether");
765     if (str == NULL)
766     str = "";
767     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
768     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
769     w_ether = GTK_COMBO(combo)->entry;
770     }
771    
772    
773     /*
774     * "Memory/Misc" pane
775     */
776    
777     static GtkObject *w_ramsize_adj;
778     static GtkWidget *w_rom_file;
779    
780     // "Ignore SEGV" button toggled
781     static void tb_ignoresegv(GtkWidget *widget)
782     {
783     PrefsReplaceBool("ignoresegv", GTK_TOGGLE_BUTTON(widget)->active);
784     }
785    
786     // Read settings from widgets and set preferences
787     static void read_memory_settings(void)
788     {
789     PrefsReplaceInt32("ramsize", int(GTK_ADJUSTMENT(w_ramsize_adj)->value) << 20);
790    
791     const char *str = gtk_entry_get_text(GTK_ENTRY(w_rom_file));
792     if (str && strlen(str))
793     PrefsReplaceString("rom", str);
794     else
795     PrefsRemoveItem("rom");
796     }
797    
798     // Create "Memory/Misc" pane
799     static void create_memory_pane(GtkWidget *top)
800     {
801     GtkWidget *box, *vbox, *hbox, *hbox2, *label, *scale;
802    
803     box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE);
804    
805     hbox = gtk_hbox_new(FALSE, 4);
806     gtk_widget_show(hbox);
807    
808     label = gtk_label_new(GetString(STR_RAMSIZE_SLIDER));
809     gtk_widget_show(label);
810     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
811    
812     vbox = gtk_vbox_new(FALSE, 4);
813     gtk_widget_show(vbox);
814    
815     gfloat min, max;
816     min = 1;
817     max = 256;
818     w_ramsize_adj = gtk_adjustment_new(min, min, max, 1, 16, 0);
819     gtk_adjustment_set_value(GTK_ADJUSTMENT(w_ramsize_adj), PrefsFindInt32("ramsize") >> 20);
820    
821     scale = gtk_hscale_new(GTK_ADJUSTMENT(w_ramsize_adj));
822     gtk_widget_show(scale);
823     gtk_scale_set_digits(GTK_SCALE(scale), 0);
824     gtk_box_pack_start(GTK_BOX(vbox), scale, TRUE, TRUE, 0);
825    
826     hbox2 = gtk_hbox_new(FALSE, 4);
827     gtk_widget_show(hbox2);
828    
829     char val[32];
830     sprintf(val, GetString(STR_RAMSIZE_FMT), int(min));
831     label = gtk_label_new(val);
832     gtk_widget_show(label);
833     gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
834    
835     sprintf(val, GetString(STR_RAMSIZE_FMT), int(max));
836     label = gtk_label_new(val);
837     gtk_widget_show(label);
838     gtk_box_pack_end(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
839     gtk_box_pack_start(GTK_BOX(vbox), hbox2, TRUE, TRUE, 0);
840     gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
841     gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
842    
843     w_rom_file = make_entry(box, STR_ROM_FILE_CTRL, "rom");
844    
845     make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv));
846     }
847    
848    
849     /*
850     * Read settings from widgets and set preferences
851     */
852    
853     static void read_settings(void)
854     {
855     read_volumes_settings();
856     read_graphics_settings();
857     read_serial_settings();
858     read_memory_settings();
859     }