ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/prefs_editor_gtk.cpp
Revision: 1.16
Committed: 2005-11-29T23:59:36Z (18 years, 6 months ago) by gbeauche
Branch: MAIN
Changes since 1.15: +3 -3 lines
Log Message:
Copyright and URL changes

File Contents

# Content
1 /*
2 * prefs_editor_linux.cpp - Preferences editor, Linux implementation using GTK+
3 *
4 * SheepShaver (C) 1997-2005 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 static int screen_width, screen_height; // Screen dimensions
43
44
45 // Prototypes
46 static void create_volumes_pane(GtkWidget *top);
47 static void create_graphics_pane(GtkWidget *top);
48 static void create_input_pane(GtkWidget *top);
49 static void create_serial_pane(GtkWidget *top);
50 static void create_memory_pane(GtkWidget *top);
51 static void create_jit_pane(GtkWidget *top);
52 static void read_settings(void);
53
54
55 /*
56 * Utility functions
57 */
58
59 #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 struct opt_desc {
66 int label_id;
67 GtkSignalFunc func;
68 };
69
70 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 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 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 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 static const gchar *get_file_entry_path(GtkWidget *entry)
300 {
301 return gtk_entry_get_text(GTK_ENTRY(entry));
302 }
303
304 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 "Copyright (C) 1997-2005 Christian Bauer and Marc Hellwig\n"
373 "E-mail: cb@cebix.net\n"
374 "http://sheepshaver.cebix.net/\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 {(gchar *)GetString(STR_PREFS_ITEM_START_GTK), "<control>S", GTK_SIGNAL_FUNC(cb_start), 0, NULL},
411 {(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 // Get screen dimensions
421 screen_width = gdk_screen_width();
422 screen_height = gdk_screen_height();
423
424 // 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 #if GTK_CHECK_VERSION(1,3,15)
439 gtk_window_add_accel_group(GTK_WINDOW(win), accel_group);
440 #else
441 gtk_accel_group_attach(accel_group, GTK_OBJECT(win));
442 #endif
443 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 create_input_pane(notebook);
456 create_serial_pane(notebook);
457 create_memory_pane(notebook);
458 create_jit_pane(notebook);
459
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 gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
491 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 gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
500
501 const gchar *str = gtk_entry_get_text(GTK_ENTRY(assoc->entry));
502 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 * "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 // "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 // 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 #if USE_JIT
668 make_checkbox(box, STR_JIT_CTRL, "jit", GTK_SIGNAL_FUNC(tb_jit));
669 set_jit_sensitive();
670 #endif
671 make_checkbox(box, STR_JIT_68K_CTRL, "jit68k", GTK_SIGNAL_FUNC(tb_jit_68k));
672 }
673
674
675 /*
676 * "Graphics/Sound" pane
677 */
678
679 // 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 static bool is_fbdev_dga_mode = false;
690
691 static GtkWidget *w_dspdevice_file, *w_mixerdevice_file;
692
693 // 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 // "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 // QuickDraw acceleration
729 static void tb_gfxaccel(GtkWidget *widget)
730 {
731 PrefsReplaceBool("gfxaccel", GTK_TOGGLE_BUTTON(widget)->active);
732 }
733
734 // 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 // "Disable Sound Output" button toggled
743 static void tb_nosound(GtkWidget *widget)
744 {
745 PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active);
746 set_graphics_sensitive();
747 }
748
749 // 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 #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 }
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 // Read settings from widgets and set preferences
813 static void read_graphics_settings(void)
814 {
815 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 bool use_screen_mode = true;
825 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 use_screen_mode = false;
834 PrefsRemoveItem("screen");
835 return;
836 }
837 if (use_screen_mode) {
838 PrefsReplaceString("screen", pref);
839 // Old prefs are now migrated
840 PrefsRemoveItem("windowmodes");
841 PrefsRemoveItem("screenmodes");
842 }
843
844 PrefsReplaceString("dsp", get_file_entry_path(w_dspdevice_file));
845 PrefsReplaceString("mixer", get_file_entry_path(w_mixerdevice_file));
846 }
847
848 // Create "Graphics/Sound" pane
849 static void create_graphics_pane(GtkWidget *top)
850 {
851 GtkWidget *box, *table, *label, *opt, *menu, *combo;
852 char str[32];
853
854 parse_graphics_prefs();
855
856 box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE);
857 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
863 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 switch (frameskip) {
895 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 }
903 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
912 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
929 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
933 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
950 make_checkbox(box, STR_GFXACCEL_CTRL, PrefsFindBool("gfxaccel"), GTK_SIGNAL_FUNC(tb_gfxaccel));
951
952 make_separator(box);
953 make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound));
954 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
959 hide_show_graphics_widgets();
960 }
961
962
963 /*
964 * "Input" pane
965 */
966
967 static GtkWidget *w_keycode_file;
968 static GtkWidget *w_mouse_wheel_lines;
969
970 // Set sensitivity of widgets
971 static void set_input_sensitive(void)
972 {
973 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 gtk_widget_set_sensitive(w_mouse_wheel_lines, PrefsFindInt32("mousewheelmode") == 1);
977 }
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 // "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 // 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
999 PrefsReplaceInt32("mousewheellines", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_mouse_wheel_lines)));
1000 }
1001
1002 // Create "Input" pane
1003 static void create_input_pane(GtkWidget *top)
1004 {
1005 GtkWidget *box, *hbox, *menu, *label, *button;
1006 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
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
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
1060 set_input_sensitive();
1061 }
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 #if defined(__linux__)
1104 if (strncmp(de->d_name, "ttyS", 4) == 0 || strncmp(de->d_name, "lp", 2) == 0) {
1105 #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 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 #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 if (ioctl(s, SIOCGIFHWADDR, &req) == 0 && req.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
1148 #else
1149 if (false) {
1150 #endif
1151 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 #ifdef HAVE_SLIRP
1160 static char s_slirp[] = "slirp";
1161 glist = g_list_append(glist, s_slirp);
1162 #endif
1163 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 static GtkWidget *w_ramsize;
1229 static GtkWidget *w_rom_file;
1230
1231 // 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 // "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 const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_ramsize)->entry));
1247 PrefsReplaceInt32("ramsize", atoi(str) << 20);
1248
1249 str = gtk_entry_get_text(GTK_ENTRY(w_rom_file));
1250 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 GtkWidget *box, *hbox, *table, *label, *menu;
1260
1261 box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE);
1262 table = make_table(box, 2, 5);
1263
1264 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
1279 w_rom_file = table_make_file_entry(table, 1, STR_ROM_FILE_CTRL, "rom");
1280
1281 make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv));
1282 make_checkbox(box, STR_IDLEWAIT_CTRL, "idlewait", GTK_SIGNAL_FUNC(tb_idlewait));
1283 }
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 read_jit_settings();
1297 }