ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/prefs_editor_gtk.cpp
Revision: 1.29
Committed: 2005-11-21T21:39:08Z (18 years, 7 months ago) by gbeauche
Branch: MAIN
Changes since 1.28: +164 -54 lines
Log Message:
GUI cosmetics from the Windows port: add "browse" button to ROM & keycodes
file selectors, improve "Memory/Misc" pane to be more attractive and simplify
RAM size selection, rename to "Keyboard/Mouse" pane to match the actual order
of elements in the pane, make "<control>-S" save/start the config.

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