ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/prefs_editor_gtk.cpp
Revision: 1.27
Committed: 2005-06-06T20:11:50Z (19 years, 1 month ago) by gbeauche
Branch: MAIN
Changes since 1.26: +16 -1 lines
Log Message:
Update GTK Prefs Editor with support for "jitinline" and "slirp" ethernet.

File Contents

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