ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/prefs_editor_gtk.cpp
Revision: 1.10
Committed: 2004-06-03T21:52:55Z (20 years ago) by gbeauche
Branch: MAIN
Changes since 1.9: +8 -2 lines
Log Message:
Add "jit68k" prefs item to enable built-in 68k DR emulator.

File Contents

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