ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/prefs_editor_gtk.cpp
Revision: 1.2
Committed: 2003-11-21T17:01:33Z (20 years, 9 months ago) by gbeauche
Branch: MAIN
Changes since 1.1: +51 -0 lines
Log Message:
Merge in "keycodes" support from Basilisk II. e.g. make French keyboard
layout work correctly for me.

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