ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/prefs_editor_gtk.cpp
Revision: 1.5
Committed: 2003-12-27T10:37:30Z (20 years, 5 months ago) by gbeauche
Branch: MAIN
Changes since 1.4: +35 -0 lines
Log Message:
Merge in Mouse Wheel support from Basilisk II.

File Contents

# Content
1 /*
2 * prefs_editor_linux.cpp - Preferences editor, Linux implementation using GTK+
3 *
4 * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "sysdeps.h"
22
23 #include <gtk/gtk.h>
24 #include <stdlib.h>
25 #include <dirent.h>
26 #include <sys/socket.h>
27 #include <sys/ioctl.h>
28 #include <net/if.h>
29 #include <net/if_arp.h>
30
31 #include "user_strings.h"
32 #include "version.h"
33 #include "cdrom.h"
34 #include "xpram.h"
35 #include "prefs.h"
36 #include "prefs_editor.h"
37
38
39 // Global variables
40 static GtkWidget *win; // Preferences window
41 static bool start_clicked = true; // Return value of PrefsEditor() function
42
43
44 // Prototypes
45 static void create_volumes_pane(GtkWidget *top);
46 static void create_graphics_pane(GtkWidget *top);
47 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-2002 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 // Create "JIT Compiler" pane
529 static void create_jit_pane(GtkWidget *top)
530 {
531 #if USE_JIT
532 GtkWidget *box, *table, *label, *menu;
533 char str[32];
534
535 box = make_pane(top, STR_JIT_PANE_TITLE);
536 make_checkbox(box, STR_JIT_CTRL, "jit", GTK_SIGNAL_FUNC(tb_jit));
537
538 set_jit_sensitive();
539 #endif
540 }
541
542
543 /*
544 * "Graphics/Sound" pane
545 */
546
547 static GtkWidget *w_frameskip;
548
549 static GtkWidget *w_dspdevice_file, *w_mixerdevice_file;
550
551 // "5 Hz".."60Hz" selected
552 static void mn_5hz(...) {PrefsReplaceInt32("frameskip", 12);}
553 static void mn_7hz(...) {PrefsReplaceInt32("frameskip", 8);}
554 static void mn_10hz(...) {PrefsReplaceInt32("frameskip", 6);}
555 static void mn_15hz(...) {PrefsReplaceInt32("frameskip", 4);}
556 static void mn_30hz(...) {PrefsReplaceInt32("frameskip", 2);}
557 static void mn_60hz(...) {PrefsReplaceInt32("frameskip", 1);}
558
559 // Video modes
560 static void tb_w640x480(GtkWidget *widget)
561 {
562 if (GTK_TOGGLE_BUTTON(widget)->active)
563 PrefsReplaceInt32("windowmodes", PrefsFindInt32("windowmodes") | 1);
564 else
565 PrefsReplaceInt32("windowmodes", PrefsFindInt32("windowmodes") & ~1);
566 }
567
568 static void tb_w800x600(GtkWidget *widget)
569 {
570 if (GTK_TOGGLE_BUTTON(widget)->active)
571 PrefsReplaceInt32("windowmodes", PrefsFindInt32("windowmodes") | 2);
572 else
573 PrefsReplaceInt32("windowmodes", PrefsFindInt32("windowmodes") & ~2);
574 }
575
576 static void tb_fs640x480(GtkWidget *widget)
577 {
578 if (GTK_TOGGLE_BUTTON(widget)->active)
579 PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 1);
580 else
581 PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~1);
582 }
583
584 static void tb_fs800x600(GtkWidget *widget)
585 {
586 if (GTK_TOGGLE_BUTTON(widget)->active)
587 PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 2);
588 else
589 PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~2);
590 }
591
592 static void tb_fs1024x768(GtkWidget *widget)
593 {
594 if (GTK_TOGGLE_BUTTON(widget)->active)
595 PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 4);
596 else
597 PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~4);
598 }
599
600 static void tb_fs1152x900(GtkWidget *widget)
601 {
602 if (GTK_TOGGLE_BUTTON(widget)->active)
603 PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 8);
604 else
605 PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~8);
606 }
607
608 static void tb_fs1280x1024(GtkWidget *widget)
609 {
610 if (GTK_TOGGLE_BUTTON(widget)->active)
611 PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 16);
612 else
613 PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~16);
614 }
615
616 static void tb_fs1600x1200(GtkWidget *widget)
617 {
618 if (GTK_TOGGLE_BUTTON(widget)->active)
619 PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 32);
620 else
621 PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~32);
622 }
623
624 // Set sensitivity of widgets
625 static void set_graphics_sensitive(void)
626 {
627 const bool sound_enabled = !PrefsFindBool("nosound");
628 gtk_widget_set_sensitive(w_dspdevice_file, sound_enabled);
629 gtk_widget_set_sensitive(w_mixerdevice_file, sound_enabled);
630 }
631
632 // "Disable Sound Output" button toggled
633 static void tb_nosound(GtkWidget *widget)
634 {
635 PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active);
636 set_graphics_sensitive();
637 }
638
639 // Read settings from widgets and set preferences
640 static void read_graphics_settings(void)
641 {
642 PrefsReplaceString("dsp", get_file_entry_path(w_dspdevice_file));
643 PrefsReplaceString("mixer", get_file_entry_path(w_mixerdevice_file));
644 }
645
646 // Create "Graphics/Sound" pane
647 static void create_graphics_pane(GtkWidget *top)
648 {
649 GtkWidget *box, *vbox, *frame;
650
651 box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE);
652
653 static const opt_desc options[] = {
654 {STR_REF_5HZ_LAB, GTK_SIGNAL_FUNC(mn_5hz)},
655 {STR_REF_7_5HZ_LAB, GTK_SIGNAL_FUNC(mn_7hz)},
656 {STR_REF_10HZ_LAB, GTK_SIGNAL_FUNC(mn_10hz)},
657 {STR_REF_15HZ_LAB, GTK_SIGNAL_FUNC(mn_15hz)},
658 {STR_REF_30HZ_LAB, GTK_SIGNAL_FUNC(mn_30hz)},
659 {STR_REF_60HZ_LAB, GTK_SIGNAL_FUNC(mn_60hz)},
660 {0, NULL}
661 };
662 int frameskip = PrefsFindInt32("frameskip"), active = 0;
663 switch (frameskip) {
664 case 12: active = 0; break;
665 case 8: active = 1; break;
666 case 6: active = 2; break;
667 case 4: active = 3; break;
668 case 2: active = 4; break;
669 case 1: active = 5; break;
670 }
671 w_frameskip = make_option_menu(box, STR_FRAMESKIP_CTRL, options, active);
672
673 frame = gtk_frame_new (GetString(STR_VIDEO_MODE_CTRL));
674 gtk_widget_show(frame);
675 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 0);
676
677 vbox = gtk_vbox_new(FALSE, 4);
678 gtk_widget_show(vbox);
679 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
680 gtk_container_add(GTK_CONTAINER(frame), vbox);
681
682 make_checkbox(vbox, STR_W_640x480_CTRL, PrefsFindInt32("windowmodes") & 1, GTK_SIGNAL_FUNC(tb_w640x480));
683 make_checkbox(vbox, STR_W_800x600_CTRL, PrefsFindInt32("windowmodes") & 2, GTK_SIGNAL_FUNC(tb_w800x600));
684 make_checkbox(vbox, STR_640x480_CTRL, PrefsFindInt32("screenmodes") & 1, GTK_SIGNAL_FUNC(tb_fs640x480));
685 make_checkbox(vbox, STR_800x600_CTRL, PrefsFindInt32("screenmodes") & 2, GTK_SIGNAL_FUNC(tb_fs800x600));
686 make_checkbox(vbox, STR_1024x768_CTRL, PrefsFindInt32("screenmodes") & 4, GTK_SIGNAL_FUNC(tb_fs1024x768));
687 make_checkbox(vbox, STR_1152x900_CTRL, PrefsFindInt32("screenmodes") & 8, GTK_SIGNAL_FUNC(tb_fs1152x900));
688 make_checkbox(vbox, STR_1280x1024_CTRL, PrefsFindInt32("screenmodes") & 16, GTK_SIGNAL_FUNC(tb_fs1280x1024));
689 make_checkbox(vbox, STR_1600x1200_CTRL, PrefsFindInt32("screenmodes") & 32, GTK_SIGNAL_FUNC(tb_fs1600x1200));
690
691 make_separator(box);
692 make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound));
693 w_dspdevice_file = make_entry(box, STR_DSPDEVICE_FILE_CTRL, "dsp");
694 w_mixerdevice_file = make_entry(box, STR_MIXERDEVICE_FILE_CTRL, "mixer");
695
696 set_graphics_sensitive();
697 }
698
699
700 /*
701 * "Input" pane
702 */
703
704 static GtkWidget *w_keycode_file;
705 static GtkWidget *w_mouse_wheel_lines;
706
707 // Set sensitivity of widgets
708 static void set_input_sensitive(void)
709 {
710 gtk_widget_set_sensitive(w_keycode_file, PrefsFindBool("keycodes"));
711 gtk_widget_set_sensitive(w_mouse_wheel_lines, PrefsFindInt32("mousewheelmode") == 1);
712 }
713
714 // "Use Raw Keycodes" button toggled
715 static void tb_keycodes(GtkWidget *widget)
716 {
717 PrefsReplaceBool("keycodes", GTK_TOGGLE_BUTTON(widget)->active);
718 set_input_sensitive();
719 }
720
721 // "Mouse Wheel Mode" selected
722 static void mn_wheel_page(...) {PrefsReplaceInt32("mousewheelmode", 0); set_input_sensitive();}
723 static void mn_wheel_cursor(...) {PrefsReplaceInt32("mousewheelmode", 1); set_input_sensitive();}
724
725 // Read settings from widgets and set preferences
726 static void read_input_settings(void)
727 {
728 const char *str = get_file_entry_path(w_keycode_file);
729 if (str && strlen(str))
730 PrefsReplaceString("keycodefile", str);
731 else
732 PrefsRemoveItem("keycodefile");
733
734 PrefsReplaceInt32("mousewheellines", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_mouse_wheel_lines)));
735 }
736
737 // Create "Input" pane
738 static void create_input_pane(GtkWidget *top)
739 {
740 GtkWidget *box, *hbox, *menu, *label;
741 GtkObject *adj;
742
743 box = make_pane(top, STR_INPUT_PANE_TITLE);
744
745 make_checkbox(box, STR_KEYCODES_CTRL, "keycodes", GTK_SIGNAL_FUNC(tb_keycodes));
746 w_keycode_file = make_entry(box, STR_KEYCODE_FILE_CTRL, "keycodefile");
747
748 make_separator(box);
749
750 static const opt_desc options[] = {
751 {STR_MOUSEWHEELMODE_PAGE_LAB, GTK_SIGNAL_FUNC(mn_wheel_page)},
752 {STR_MOUSEWHEELMODE_CURSOR_LAB, GTK_SIGNAL_FUNC(mn_wheel_cursor)},
753 {0, NULL}
754 };
755 int wheelmode = PrefsFindInt32("mousewheelmode"), active = 0;
756 switch (wheelmode) {
757 case 0: active = 0; break;
758 case 1: active = 1; break;
759 }
760 menu = make_option_menu(box, STR_MOUSEWHEELMODE_CTRL, options, active);
761
762 hbox = gtk_hbox_new(FALSE, 4);
763 gtk_widget_show(hbox);
764 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
765
766 label = gtk_label_new(GetString(STR_MOUSEWHEELLINES_CTRL));
767 gtk_widget_show(label);
768 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
769
770 adj = gtk_adjustment_new(PrefsFindInt32("mousewheellines"), 1, 1000, 1, 5, 0);
771 w_mouse_wheel_lines = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0);
772 gtk_widget_show(w_mouse_wheel_lines);
773 gtk_box_pack_start(GTK_BOX(hbox), w_mouse_wheel_lines, FALSE, FALSE, 0);
774
775 set_input_sensitive();
776 }
777
778
779 /*
780 * "Serial/Network" pane
781 */
782
783 static GtkWidget *w_seriala, *w_serialb, *w_ether;
784
785 // Read settings from widgets and set preferences
786 static void read_serial_settings(void)
787 {
788 const char *str;
789
790 str = gtk_entry_get_text(GTK_ENTRY(w_seriala));
791 PrefsReplaceString("seriala", str);
792
793 str = gtk_entry_get_text(GTK_ENTRY(w_serialb));
794 PrefsReplaceString("serialb", str);
795
796 str = gtk_entry_get_text(GTK_ENTRY(w_ether));
797 if (str && strlen(str))
798 PrefsReplaceString("ether", str);
799 else
800 PrefsRemoveItem("ether");
801 }
802
803 // Add names of serial devices
804 static gint gl_str_cmp(gconstpointer a, gconstpointer b)
805 {
806 return strcmp((char *)a, (char *)b);
807 }
808
809 static GList *add_serial_names(void)
810 {
811 GList *glist = NULL;
812
813 // Search /dev for ttyS* and lp*
814 DIR *d = opendir("/dev");
815 if (d) {
816 struct dirent *de;
817 while ((de = readdir(d)) != NULL) {
818 if (strncmp(de->d_name, "ttyS", 4) == 0 || strncmp(de->d_name, "lp", 2) == 0) {
819 char *str = new char[64];
820 sprintf(str, "/dev/%s", de->d_name);
821 glist = g_list_append(glist, str);
822 }
823 }
824 closedir(d);
825 }
826 if (glist)
827 g_list_sort(glist, gl_str_cmp);
828 else
829 glist = g_list_append(glist, (void *)"<none>");
830 return glist;
831 }
832
833 // Add names of ethernet interfaces
834 static GList *add_ether_names(void)
835 {
836 GList *glist = NULL;
837
838 // Get list of all Ethernet interfaces
839 int s = socket(PF_INET, SOCK_DGRAM, 0);
840 if (s >= 0) {
841 char inbuf[8192];
842 struct ifconf ifc;
843 ifc.ifc_len = sizeof(inbuf);
844 ifc.ifc_buf = inbuf;
845 if (ioctl(s, SIOCGIFCONF, &ifc) == 0) {
846 struct ifreq req, *ifr = ifc.ifc_req;
847 for (int i=0; i<ifc.ifc_len; i+=sizeof(ifreq), ifr++) {
848 req = *ifr;
849 if (ioctl(s, SIOCGIFHWADDR, &req) == 0 && req.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
850 char *str = new char[64];
851 strncpy(str, ifr->ifr_name, 63);
852 glist = g_list_append(glist, str);
853 }
854 }
855 }
856 close(s);
857 }
858 if (glist)
859 g_list_sort(glist, gl_str_cmp);
860 else
861 glist = g_list_append(glist, (void *)"<none>");
862 return glist;
863 }
864
865 // Create "Serial/Network" pane
866 static void create_serial_pane(GtkWidget *top)
867 {
868 GtkWidget *box, *table, *label, *combo;
869 GList *glist = add_serial_names();
870
871 box = make_pane(top, STR_SERIAL_NETWORK_PANE_TITLE);
872 table = make_table(box, 2, 3);
873
874 label = gtk_label_new(GetString(STR_SERPORTA_CTRL));
875 gtk_widget_show(label);
876 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
877
878 combo = gtk_combo_new();
879 gtk_widget_show(combo);
880 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
881 const char *str = PrefsFindString("seriala");
882 if (str == NULL)
883 str = "";
884 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
885 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
886 w_seriala = GTK_COMBO(combo)->entry;
887
888 label = gtk_label_new(GetString(STR_SERPORTB_CTRL));
889 gtk_widget_show(label);
890 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
891
892 combo = gtk_combo_new();
893 gtk_widget_show(combo);
894 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
895 str = PrefsFindString("serialb");
896 if (str == NULL)
897 str = "";
898 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
899 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 1, 2, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
900 w_serialb = GTK_COMBO(combo)->entry;
901
902 label = gtk_label_new(GetString(STR_ETHERNET_IF_CTRL));
903 gtk_widget_show(label);
904 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
905
906 glist = add_ether_names();
907 combo = gtk_combo_new();
908 gtk_widget_show(combo);
909 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
910 str = PrefsFindString("ether");
911 if (str == NULL)
912 str = "";
913 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
914 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
915 w_ether = GTK_COMBO(combo)->entry;
916 }
917
918
919 /*
920 * "Memory/Misc" pane
921 */
922
923 static GtkObject *w_ramsize_adj;
924 static GtkWidget *w_rom_file;
925
926 // "Ignore SEGV" button toggled
927 static void tb_ignoresegv(GtkWidget *widget)
928 {
929 PrefsReplaceBool("ignoresegv", GTK_TOGGLE_BUTTON(widget)->active);
930 }
931
932 // Read settings from widgets and set preferences
933 static void read_memory_settings(void)
934 {
935 PrefsReplaceInt32("ramsize", int(GTK_ADJUSTMENT(w_ramsize_adj)->value) << 20);
936
937 const char *str = gtk_entry_get_text(GTK_ENTRY(w_rom_file));
938 if (str && strlen(str))
939 PrefsReplaceString("rom", str);
940 else
941 PrefsRemoveItem("rom");
942 }
943
944 // Create "Memory/Misc" pane
945 static void create_memory_pane(GtkWidget *top)
946 {
947 GtkWidget *box, *vbox, *hbox, *hbox2, *label, *scale;
948
949 box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE);
950
951 hbox = gtk_hbox_new(FALSE, 4);
952 gtk_widget_show(hbox);
953
954 label = gtk_label_new(GetString(STR_RAMSIZE_SLIDER));
955 gtk_widget_show(label);
956 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
957
958 vbox = gtk_vbox_new(FALSE, 4);
959 gtk_widget_show(vbox);
960
961 gfloat min, max;
962 min = 1;
963 max = 256;
964 w_ramsize_adj = gtk_adjustment_new(min, min, max, 1, 16, 0);
965 gtk_adjustment_set_value(GTK_ADJUSTMENT(w_ramsize_adj), PrefsFindInt32("ramsize") >> 20);
966
967 scale = gtk_hscale_new(GTK_ADJUSTMENT(w_ramsize_adj));
968 gtk_widget_show(scale);
969 gtk_scale_set_digits(GTK_SCALE(scale), 0);
970 gtk_box_pack_start(GTK_BOX(vbox), scale, TRUE, TRUE, 0);
971
972 hbox2 = gtk_hbox_new(FALSE, 4);
973 gtk_widget_show(hbox2);
974
975 char val[32];
976 sprintf(val, GetString(STR_RAMSIZE_FMT), int(min));
977 label = gtk_label_new(val);
978 gtk_widget_show(label);
979 gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
980
981 sprintf(val, GetString(STR_RAMSIZE_FMT), int(max));
982 label = gtk_label_new(val);
983 gtk_widget_show(label);
984 gtk_box_pack_end(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
985 gtk_box_pack_start(GTK_BOX(vbox), hbox2, TRUE, TRUE, 0);
986 gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
987 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
988
989 w_rom_file = make_entry(box, STR_ROM_FILE_CTRL, "rom");
990
991 make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv));
992 }
993
994
995 /*
996 * Read settings from widgets and set preferences
997 */
998
999 static void read_settings(void)
1000 {
1001 read_volumes_settings();
1002 read_graphics_settings();
1003 read_serial_settings();
1004 read_memory_settings();
1005 read_jit_settings();
1006 }