ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/prefs_editor_gtk.cpp
Revision: 1.7
Committed: 2005-11-22T22:57:30Z (18 years, 6 months ago) by gbeauche
Branch: MAIN
Changes since 1.6: +1 -0 lines
Log Message:
Windows GUI: set "frameskip" to 1 when switching to fullscreen mode

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