ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/prefs_editor_gtk.cpp
Revision: 1.6
Committed: 2005-11-20T23:59:18Z (18 years, 7 months ago) by gbeauche
Branch: MAIN
Changes since 1.5: +2 -4 lines
Log Message:
Windows GUI: don't mess the button pad, map '<ctrl>-S' to Start/Save config

File Contents

# Content
1 /*
2 * prefs_editor_gtk.cpp - Preferences editor, Unix implementation using GTK+
3 *
4 * Basilisk II (C) 1997-2005 Christian Bauer
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "sysdeps.h"
22
23 #include <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 }
837
838 // "5 Hz".."60Hz" selected
839 static void mn_5hz(...) {PrefsReplaceInt32("frameskip", 12);}
840 static void mn_7hz(...) {PrefsReplaceInt32("frameskip", 8);}
841 static void mn_10hz(...) {PrefsReplaceInt32("frameskip", 6);}
842 static void mn_15hz(...) {PrefsReplaceInt32("frameskip", 4);}
843 static void mn_30hz(...) {PrefsReplaceInt32("frameskip", 2);}
844 static void mn_60hz(...) {PrefsReplaceInt32("frameskip", 1);}
845 static void mn_dynamic(...) {PrefsReplaceInt32("frameskip", 0);}
846
847 // Set sensitivity of widgets
848 static void set_graphics_sensitive(void)
849 {
850 const bool sound_enabled = !PrefsFindBool("nosound");
851 }
852
853 // "Disable Sound Output" button toggled
854 static void tb_nosound(GtkWidget *widget)
855 {
856 PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active);
857 set_graphics_sensitive();
858 }
859
860 // Read graphics preferences
861 static void parse_graphics_prefs(void)
862 {
863 display_type = DISPLAY_WINDOW;
864 dis_width = 512;
865 dis_height = 384;
866
867 const char *str = PrefsFindString("screen");
868 if (str) {
869 if (sscanf(str, "win/%d/%d", &dis_width, &dis_height) == 2)
870 display_type = DISPLAY_WINDOW;
871 else if (sscanf(str, "dga/%d/%d", &dis_width, &dis_height) == 2)
872 display_type = DISPLAY_SCREEN;
873 }
874 }
875
876 // Read settings from widgets and set preferences
877 static void read_graphics_settings(void)
878 {
879 const char *str;
880
881 str = gtk_entry_get_text(GTK_ENTRY(w_display_x));
882 dis_width = atoi(str);
883
884 str = gtk_entry_get_text(GTK_ENTRY(w_display_y));
885 dis_height = atoi(str);
886
887 char pref[256];
888 switch (display_type) {
889 case DISPLAY_WINDOW:
890 sprintf(pref, "win/%d/%d", dis_width, dis_height);
891 break;
892 case DISPLAY_SCREEN:
893 sprintf(pref, "dga/%d/%d", dis_width, dis_height);
894 break;
895 default:
896 PrefsRemoveItem("screen");
897 return;
898 }
899 PrefsReplaceString("screen", pref);
900 }
901
902 // Create "Graphics/Sound" pane
903 static void create_graphics_pane(GtkWidget *top)
904 {
905 GtkWidget *box, *table, *label, *opt, *menu, *combo;
906 char str[32];
907
908 parse_graphics_prefs();
909
910 box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE);
911 table = make_table(box, 2, 5);
912
913 label = gtk_label_new(GetString(STR_VIDEO_TYPE_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 opt = gtk_option_menu_new();
918 gtk_widget_show(opt);
919 menu = gtk_menu_new();
920 add_menu_item(menu, STR_WINDOW_LAB, GTK_SIGNAL_FUNC(mn_window));
921 add_menu_item(menu, STR_FULLSCREEN_LAB, GTK_SIGNAL_FUNC(mn_fullscreen));
922 switch (display_type) {
923 case DISPLAY_WINDOW:
924 gtk_menu_set_active(GTK_MENU(menu), 0);
925 break;
926 case DISPLAY_SCREEN:
927 gtk_menu_set_active(GTK_MENU(menu), 1);
928 break;
929 }
930 gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
931 gtk_table_attach(GTK_TABLE(table), opt, 1, 2, 0, 1, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
932
933 l_frameskip = gtk_label_new(GetString(STR_FRAMESKIP_CTRL));
934 gtk_widget_show(l_frameskip);
935 gtk_table_attach(GTK_TABLE(table), l_frameskip, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
936
937 w_frameskip = gtk_option_menu_new();
938 gtk_widget_show(w_frameskip);
939 menu = gtk_menu_new();
940 add_menu_item(menu, STR_REF_5HZ_LAB, GTK_SIGNAL_FUNC(mn_5hz));
941 add_menu_item(menu, STR_REF_7_5HZ_LAB, GTK_SIGNAL_FUNC(mn_7hz));
942 add_menu_item(menu, STR_REF_10HZ_LAB, GTK_SIGNAL_FUNC(mn_10hz));
943 add_menu_item(menu, STR_REF_15HZ_LAB, GTK_SIGNAL_FUNC(mn_15hz));
944 add_menu_item(menu, STR_REF_30HZ_LAB, GTK_SIGNAL_FUNC(mn_30hz));
945 add_menu_item(menu, STR_REF_60HZ_LAB, GTK_SIGNAL_FUNC(mn_60hz));
946 add_menu_item(menu, STR_REF_DYNAMIC_LAB, GTK_SIGNAL_FUNC(mn_dynamic));
947 int frameskip = PrefsFindInt32("frameskip");
948 int item = -1;
949 switch (frameskip) {
950 case 12: item = 0; break;
951 case 8: item = 1; break;
952 case 6: item = 2; break;
953 case 4: item = 3; break;
954 case 2: item = 4; break;
955 case 1: item = 5; break;
956 case 0: item = 6; break;
957 }
958 if (item >= 0)
959 gtk_menu_set_active(GTK_MENU(menu), item);
960 gtk_option_menu_set_menu(GTK_OPTION_MENU(w_frameskip), menu);
961 gtk_table_attach(GTK_TABLE(table), w_frameskip, 1, 2, 1, 2, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
962
963 l_display_x = gtk_label_new(GetString(STR_DISPLAY_X_CTRL));
964 gtk_widget_show(l_display_x);
965 gtk_table_attach(GTK_TABLE(table), l_display_x, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
966
967 combo = gtk_combo_new();
968 gtk_widget_show(combo);
969 GList *glist1 = NULL;
970 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_512_LAB));
971 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_640_LAB));
972 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_800_LAB));
973 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_1024_LAB));
974 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_MAX_LAB));
975 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist1);
976 if (dis_width)
977 sprintf(str, "%d", dis_width);
978 else
979 strcpy(str, GetString(STR_SIZE_MAX_LAB));
980 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
981 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
982 w_display_x = GTK_COMBO(combo)->entry;
983
984 l_display_y = gtk_label_new(GetString(STR_DISPLAY_Y_CTRL));
985 gtk_widget_show(l_display_y);
986 gtk_table_attach(GTK_TABLE(table), l_display_y, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
987
988 combo = gtk_combo_new();
989 gtk_widget_show(combo);
990 GList *glist2 = NULL;
991 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_384_LAB));
992 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_480_LAB));
993 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_600_LAB));
994 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_768_LAB));
995 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_MAX_LAB));
996 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist2);
997 if (dis_height)
998 sprintf(str, "%d", dis_height);
999 else
1000 strcpy(str, GetString(STR_SIZE_MAX_LAB));
1001 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1002 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
1003 w_display_y = GTK_COMBO(combo)->entry;
1004
1005 make_separator(box);
1006 make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound));
1007
1008 set_graphics_sensitive();
1009
1010 hide_show_graphics_widgets();
1011 }
1012
1013
1014 /*
1015 * "Input" pane
1016 */
1017
1018 static GtkWidget *w_keycode_file;
1019 static GtkWidget *w_mouse_wheel_lines;
1020
1021 // Set sensitivity of widgets
1022 static void set_input_sensitive(void)
1023 {
1024 const bool use_keycodes = PrefsFindBool("keycodes");
1025 gtk_widget_set_sensitive(w_keycode_file, use_keycodes);
1026 gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_keycode_file), "chooser_button")), use_keycodes);
1027 gtk_widget_set_sensitive(w_mouse_wheel_lines, PrefsFindInt32("mousewheelmode") == 1);
1028 }
1029
1030 // "Use Raw Keycodes" button toggled
1031 static void tb_keycodes(GtkWidget *widget)
1032 {
1033 PrefsReplaceBool("keycodes", GTK_TOGGLE_BUTTON(widget)->active);
1034 set_input_sensitive();
1035 }
1036
1037 // "Mouse Wheel Mode" selected
1038 static void mn_wheel_page(...) {PrefsReplaceInt32("mousewheelmode", 0); set_input_sensitive();}
1039 static void mn_wheel_cursor(...) {PrefsReplaceInt32("mousewheelmode", 1); set_input_sensitive();}
1040
1041 // Read settings from widgets and set preferences
1042 static void read_input_settings(void)
1043 {
1044 const char *str = get_file_entry_path(w_keycode_file);
1045 if (str && strlen(str))
1046 PrefsReplaceString("keycodefile", str);
1047 else
1048 PrefsRemoveItem("keycodefile");
1049
1050 PrefsReplaceInt32("mousewheellines", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_mouse_wheel_lines)));
1051 }
1052
1053 // Create "Input" pane
1054 static void create_input_pane(GtkWidget *top)
1055 {
1056 GtkWidget *box, *hbox, *menu, *label, *button;
1057 GtkObject *adj;
1058
1059 box = make_pane(top, STR_INPUT_PANE_TITLE);
1060
1061 make_checkbox(box, STR_KEYCODES_CTRL, "keycodes", GTK_SIGNAL_FUNC(tb_keycodes));
1062
1063 hbox = gtk_hbox_new(FALSE, 4);
1064 gtk_widget_show(hbox);
1065 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1066
1067 label = gtk_label_new(GetString(STR_KEYCODES_CTRL));
1068 gtk_widget_show(label);
1069 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1070
1071 const char *str = PrefsFindString("keycodefile");
1072 if (str == NULL)
1073 str = "";
1074
1075 w_keycode_file = gtk_entry_new();
1076 gtk_entry_set_text(GTK_ENTRY(w_keycode_file), str);
1077 gtk_widget_show(w_keycode_file);
1078 gtk_box_pack_start(GTK_BOX(hbox), w_keycode_file, TRUE, TRUE, 0);
1079
1080 button = make_browse_button(w_keycode_file);
1081 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1082 g_object_set_data(G_OBJECT(w_keycode_file), "chooser_button", button);
1083
1084 make_separator(box);
1085
1086 static const opt_desc options[] = {
1087 {STR_MOUSEWHEELMODE_PAGE_LAB, GTK_SIGNAL_FUNC(mn_wheel_page)},
1088 {STR_MOUSEWHEELMODE_CURSOR_LAB, GTK_SIGNAL_FUNC(mn_wheel_cursor)},
1089 {0, NULL}
1090 };
1091 int wheelmode = PrefsFindInt32("mousewheelmode"), active = 0;
1092 switch (wheelmode) {
1093 case 0: active = 0; break;
1094 case 1: active = 1; break;
1095 }
1096 menu = make_option_menu(box, STR_MOUSEWHEELMODE_CTRL, options, active);
1097
1098 hbox = gtk_hbox_new(FALSE, 4);
1099 gtk_widget_show(hbox);
1100 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1101
1102 label = gtk_label_new(GetString(STR_MOUSEWHEELLINES_CTRL));
1103 gtk_widget_show(label);
1104 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1105
1106 adj = gtk_adjustment_new(PrefsFindInt32("mousewheellines"), 1, 1000, 1, 5, 0);
1107 w_mouse_wheel_lines = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0);
1108 gtk_widget_show(w_mouse_wheel_lines);
1109 gtk_box_pack_start(GTK_BOX(hbox), w_mouse_wheel_lines, FALSE, FALSE, 0);
1110
1111 set_input_sensitive();
1112 }
1113
1114
1115 /*
1116 * "Serial" pane
1117 */
1118
1119 static GtkWidget *w_seriala, *w_portfile0;
1120 static GtkWidget *w_serialb, *w_portfile1;
1121
1122 // Set sensitivity of widgets
1123 static void set_serial_sensitive(void)
1124 {
1125 const char *str;
1126 bool is_file;
1127
1128 str = gtk_entry_get_text(GTK_ENTRY(w_seriala));
1129 is_file = strcmp(str, "FILE") == 0;
1130 gtk_widget_set_sensitive(w_portfile0, is_file);
1131 gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_portfile0), "chooser_button")), is_file);
1132
1133 str = gtk_entry_get_text(GTK_ENTRY(w_serialb));
1134 is_file = strcmp(str, "FILE") == 0;
1135 gtk_widget_set_sensitive(w_portfile1, is_file);
1136 gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_portfile1), "chooser_button")), is_file);
1137 }
1138
1139 // Read settings from widgets and set preferences
1140 static void read_serial_settings(void)
1141 {
1142 const char *str;
1143
1144 str = gtk_entry_get_text(GTK_ENTRY(w_seriala));
1145 PrefsReplaceString("seriala", str);
1146
1147 str = gtk_entry_get_text(GTK_ENTRY(w_serialb));
1148 PrefsReplaceString("serialb", str);
1149
1150 str = gtk_entry_get_text(GTK_ENTRY(w_portfile0));
1151 PrefsReplaceString("portfile0", str);
1152
1153 str = gtk_entry_get_text(GTK_ENTRY(w_portfile1));
1154 PrefsReplaceString("portfile1", str);
1155 }
1156
1157 // Port changed in combo
1158 static void cb_serial_port_changed(...)
1159 {
1160 set_serial_sensitive();
1161 }
1162
1163 // Add names of serial devices
1164 static GList *add_serial_names(void)
1165 {
1166 GList *glist = NULL;
1167
1168 static const char *port_names[] = {
1169 "COM1", "COM2", "COM3", "COM4", "COM5", "COM6",
1170 "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6",
1171 "FILE",
1172 NULL
1173 };
1174
1175 for (int i = 0; port_names[i] != NULL; i++)
1176 glist = g_list_append(glist, (void *)port_names[i]);
1177
1178 return glist;
1179 }
1180
1181 // Create "Serial" pane
1182 static void create_serial_pane(GtkWidget *top)
1183 {
1184 GtkWidget *box, *hbox, *table, *label, *combo, *sep, *entry;
1185 GtkObject *adj;
1186
1187 box = make_pane(top, STR_SERIAL_PANE_TITLE);
1188 table = make_table(box, 2, 5);
1189
1190 GList *glist = add_serial_names();
1191 const char *str = PrefsFindString("seriala");
1192 combo = table_make_combobox(table, 0, STR_SERIALA_CTRL, str, glist);
1193 w_seriala = GTK_COMBO(combo)->entry;
1194 gtk_signal_connect(GTK_OBJECT(w_seriala), "changed", GTK_SIGNAL_FUNC(cb_serial_port_changed), NULL);
1195
1196 w_portfile0 = table_make_file_entry(table, 1, STR_FILE_CTRL, "portfile0");
1197
1198 sep = gtk_hseparator_new();
1199 gtk_widget_show(sep);
1200 gtk_table_attach(GTK_TABLE(table), sep, 0, 2, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1201
1202 str = PrefsFindString("serialb");
1203 combo = table_make_combobox(table, 3, STR_SERIALB_CTRL, str, glist);
1204 w_serialb = GTK_COMBO(combo)->entry;
1205 gtk_signal_connect(GTK_OBJECT(w_serialb), "changed", GTK_SIGNAL_FUNC(cb_serial_port_changed), NULL);
1206
1207 w_portfile1 = table_make_file_entry(table, 4, STR_FILE_CTRL, "portfile1");
1208
1209 set_serial_sensitive();
1210 }
1211
1212
1213 /*
1214 * "Ethernet" pane
1215 */
1216
1217 static GtkWidget *w_ether;
1218 static GtkWidget *w_ftp_port_list, *w_tcp_port_list;
1219 static const char s_nat_router[] = "NAT/Router module";
1220
1221 // Set sensitivity of widgets
1222 static void set_ethernet_sensitive(void)
1223 {
1224 const char *str = gtk_entry_get_text(GTK_ENTRY(w_ether));
1225
1226 bool is_nat_router = strcmp(str, s_nat_router) == 0;
1227 gtk_widget_set_sensitive(w_ftp_port_list, is_nat_router);
1228 gtk_widget_set_sensitive(w_tcp_port_list, is_nat_router);
1229 }
1230
1231 // Read settings from widgets and set preferences
1232 static void read_ethernet_settings(void)
1233 {
1234 const char *str = gtk_entry_get_text(GTK_ENTRY(w_ether));
1235 if (str && strlen(str) > 6 && strncmp(str, "NDIS: ", 6) == 0)
1236 PrefsReplaceString("ether", &str[6]);
1237 else
1238 PrefsRemoveItem("ether");
1239
1240 const bool router_enabled = str && strcmp(str, s_nat_router) == 0;
1241 PrefsReplaceBool("routerenabled", router_enabled);
1242 if (router_enabled) {
1243 str = gtk_entry_get_text(GTK_ENTRY(w_ftp_port_list));
1244 PrefsReplaceString("ftp_port_list", str);
1245 str = gtk_entry_get_text(GTK_ENTRY(w_tcp_port_list));
1246 PrefsReplaceString("tcp_port", str);
1247 }
1248 }
1249
1250 // Ethernet emulation type changed in menulist
1251 static void cb_ether_changed(...)
1252 {
1253 set_ethernet_sensitive();
1254 }
1255
1256 // Add names of ethernet interfaces
1257 static GList *add_ether_names(void)
1258 {
1259 GList *glist = NULL;
1260
1261 // TODO: Get list of all Ethernet interfaces
1262 #ifdef HAVE_SLIRP
1263 static const char s_slirp[] = "slirp";
1264 glist = g_list_append(glist, (void *)s_slirp);
1265 #endif
1266 glist = g_list_append(glist, (void *)s_nat_router);
1267 glist = g_list_append(glist, (void *)GetString(STR_NONE_LAB));
1268 return glist;
1269 }
1270
1271
1272 // Create "Ethernet" pane
1273 static void create_ethernet_pane(GtkWidget *top)
1274 {
1275 GtkWidget *box, *hbox, *table, *label, *combo, *sep, *entry;
1276
1277 box = make_pane(top, STR_NETWORK_PANE_TITLE);
1278 table = make_table(box, 2, 5);
1279
1280 label = gtk_label_new(GetString(STR_ETHERNET_IF_CTRL));
1281 gtk_widget_show(label);
1282 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1283
1284 GList *glist = add_ether_names();
1285 combo = gtk_combo_new();
1286 gtk_widget_show(combo);
1287 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1288 const char *str = PrefsFindString("ether");
1289 if (str == NULL || str[0] == '\0') {
1290 if (PrefsFindBool("routerenabled"))
1291 str = s_nat_router;
1292 else
1293 str = GetString(STR_NONE_LAB);
1294 }
1295 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1296 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1297 w_ether = GTK_COMBO(combo)->entry;
1298 gtk_signal_connect(GTK_OBJECT(w_ether), "changed", GTK_SIGNAL_FUNC(cb_ether_changed), NULL);
1299
1300 sep = gtk_hseparator_new();
1301 gtk_widget_show(sep);
1302 gtk_table_attach(GTK_TABLE(table), sep, 0, 2, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1303
1304 label = gtk_label_new(GetString(STR_ETHER_FTP_PORT_LIST_CTRL));
1305 gtk_widget_show(label);
1306 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1307
1308 entry = gtk_entry_new();
1309 str = PrefsFindString("ftp_port_list");
1310 if (str == NULL)
1311 str = "";
1312 gtk_entry_set_text(GTK_ENTRY(entry), str);
1313 gtk_widget_show(entry);
1314 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 2, 3, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1315 w_ftp_port_list = entry;
1316
1317 label = gtk_label_new(GetString(STR_ETHER_TCP_PORT_LIST_CTRL));
1318 gtk_widget_show(label);
1319 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1320
1321 entry = gtk_entry_new();
1322 str = PrefsFindString("tcp_port");
1323 if (str == NULL)
1324 str = "";
1325 gtk_entry_set_text(GTK_ENTRY(entry), str);
1326 gtk_widget_show(entry);
1327 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 3, 4, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1328 w_tcp_port_list = entry;
1329
1330 set_ethernet_sensitive();
1331 }
1332
1333
1334 /*
1335 * "Memory/Misc" pane
1336 */
1337
1338 static GtkWidget *w_ramsize;
1339 static GtkWidget *w_rom_file;
1340
1341 // "Ignore SEGV" button toggled
1342 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1343 static void tb_ignoresegv(GtkWidget *widget)
1344 {
1345 PrefsReplaceBool("ignoresegv", GTK_TOGGLE_BUTTON(widget)->active);
1346 }
1347 #endif
1348
1349 // Model ID selected
1350 static void mn_modelid_5(...) {PrefsReplaceInt32("modelid", 5);}
1351 static void mn_modelid_14(...) {PrefsReplaceInt32("modelid", 14);}
1352
1353 // CPU/FPU type
1354 static void mn_cpu_68020(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", false);}
1355 static void mn_cpu_68020_fpu(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", true);}
1356 static void mn_cpu_68030(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", false);}
1357 static void mn_cpu_68030_fpu(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", true);}
1358 static void mn_cpu_68040(...) {PrefsReplaceInt32("cpu", 4); PrefsReplaceBool("fpu", true);}
1359
1360 // Read settings from widgets and set preferences
1361 static void read_memory_settings(void)
1362 {
1363 const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_ramsize)->entry));
1364 PrefsReplaceInt32("ramsize", atoi(str) << 20);
1365
1366 str = get_file_entry_path(w_rom_file);
1367 if (str && strlen(str))
1368 PrefsReplaceString("rom", str);
1369 else
1370 PrefsRemoveItem("rom");
1371
1372 }
1373
1374 // Create "Memory/Misc" pane
1375 static void create_memory_pane(GtkWidget *top)
1376 {
1377 GtkWidget *box, *hbox, *table, *label, *scale, *menu;
1378
1379 box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE);
1380 table = make_table(box, 2, 5);
1381
1382 static const combo_desc options[] = {
1383 STR_RAMSIZE_2MB_LAB,
1384 STR_RAMSIZE_4MB_LAB,
1385 STR_RAMSIZE_8MB_LAB,
1386 STR_RAMSIZE_16MB_LAB,
1387 STR_RAMSIZE_32MB_LAB,
1388 STR_RAMSIZE_64MB_LAB,
1389 STR_RAMSIZE_128MB_LAB,
1390 STR_RAMSIZE_256MB_LAB,
1391 STR_RAMSIZE_512MB_LAB,
1392 STR_RAMSIZE_1024MB_LAB,
1393 0
1394 };
1395 char default_ramsize[10];
1396 sprintf(default_ramsize, "%d", PrefsFindInt32("ramsize") >> 20);
1397 w_ramsize = table_make_combobox(table, 0, STR_RAMSIZE_CTRL, default_ramsize, options);
1398
1399 static const opt_desc model_options[] = {
1400 {STR_MODELID_5_LAB, GTK_SIGNAL_FUNC(mn_modelid_5)},
1401 {STR_MODELID_14_LAB, GTK_SIGNAL_FUNC(mn_modelid_14)},
1402 {0, NULL}
1403 };
1404 int modelid = PrefsFindInt32("modelid"), active = 0;
1405 switch (modelid) {
1406 case 5: active = 0; break;
1407 case 14: active = 1; break;
1408 }
1409 table_make_option_menu(table, 2, STR_MODELID_CTRL, model_options, active);
1410
1411 #if EMULATED_68K
1412 static const opt_desc cpu_options[] = {
1413 {STR_CPU_68020_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020)},
1414 {STR_CPU_68020_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020_fpu)},
1415 {STR_CPU_68030_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030)},
1416 {STR_CPU_68030_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030_fpu)},
1417 {STR_CPU_68040_LAB, GTK_SIGNAL_FUNC(mn_cpu_68040)},
1418 {0, NULL}
1419 };
1420 int cpu = PrefsFindInt32("cpu");
1421 bool fpu = PrefsFindBool("fpu");
1422 active = 0;
1423 switch (cpu) {
1424 case 2: active = fpu ? 1 : 0; break;
1425 case 3: active = fpu ? 3 : 2; break;
1426 case 4: active = 4;
1427 }
1428 table_make_option_menu(table, 3, STR_CPU_CTRL, cpu_options, active);
1429 #endif
1430
1431 w_rom_file = table_make_file_entry(table, 4, STR_ROM_FILE_CTRL, "rom");
1432
1433 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1434 make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv));
1435 #endif
1436 }
1437
1438
1439 /*
1440 * Read settings from widgets and set preferences
1441 */
1442
1443 static void read_settings(void)
1444 {
1445 read_volumes_settings();
1446 read_scsi_settings();
1447 read_graphics_settings();
1448 read_input_settings();
1449 read_serial_settings();
1450 read_ethernet_settings();
1451 read_memory_settings();
1452 read_jit_settings();
1453 }
1454
1455
1456 /*
1457 * Fake unused data and functions
1458 */
1459
1460 uint8 XPRAM[XPRAM_SIZE];
1461 void MountVolume(void *fh) { }
1462 void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) { }
1463 void WarningAlert(const char *text) { }
1464
1465
1466 /*
1467 * Add default serial prefs (must be added, even if no ports present)
1468 */
1469
1470 void SysAddSerialPrefs(void)
1471 {
1472 PrefsAddString("seriala", "COM1");
1473 PrefsAddString("serialb", "COM2");
1474 }
1475
1476
1477 /*
1478 * Display alerts
1479 */
1480
1481 static void display_alert(int title_id, const char *text, int flags)
1482 {
1483 MessageBox(NULL, text, GetString(title_id), MB_OK | flags);
1484 }
1485
1486 static void ErrorAlert(const char *text)
1487 {
1488 display_alert(STR_ERROR_ALERT_TITLE, text, MB_ICONSTOP);
1489 }
1490
1491
1492 /*
1493 * Start standalone GUI
1494 */
1495
1496 int main(int argc, char *argv[])
1497 {
1498 // Init GTK
1499 gtk_set_locale();
1500 gtk_init(&argc, &argv);
1501
1502 // Read preferences
1503 PrefsInit(argc, argv);
1504
1505 // Show preferences editor
1506 bool start = PrefsEditor();
1507
1508 // Exit preferences
1509 PrefsExit();
1510
1511 // Transfer control to the Basilisk II executable
1512 if (start) {
1513 char path[_MAX_PATH];
1514 bool ok = GetModuleFileName(NULL, path, sizeof(path)) != 0;
1515 if (ok) {
1516 char b2_path[_MAX_PATH];
1517 char *p = strrchr(path, '\\');
1518 *++p = '\0';
1519 SetCurrentDirectory(path);
1520 strcpy(b2_path, path);
1521 strcat(b2_path, "BasiliskII.exe");
1522 HINSTANCE h = ShellExecute(GetDesktopWindow(), "open",
1523 b2_path, "", path, SW_SHOWNORMAL);
1524 if ((int)h <= 32)
1525 ok = false;
1526 }
1527 if (!ok) {
1528 ErrorAlert("Coult not start BasiliskII executable");
1529 return 1;
1530 }
1531 }
1532
1533 return 0;
1534 }