ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/prefs_editor_gtk.cpp
Revision: 1.5
Committed: 2005-11-20T23:47:42Z (18 years, 6 months ago) by gbeauche
Branch: MAIN
Changes since 1.4: +102 -17 lines
Log Message:
Windows GUI: disable SCSI settings for now since they are not merged yet,
handle Ethernet (NAT/Router module, None) and actually execute BasiliskII.exe

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), NULL, 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), NULL, 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_PREFS_ITEM_ZAP_PRAM, GTK_SIGNAL_FUNC(cb_zap_pram)},
478 {STR_ABOUT_BUTTON, GTK_SIGNAL_FUNC(cb_about)},
479 {STR_QUIT_BUTTON, GTK_SIGNAL_FUNC(cb_quit)},
480 {0, NULL}
481 };
482 make_button_box(box, 4, buttons);
483
484 // Show window and enter main loop
485 gtk_widget_show(win);
486 gtk_main();
487 return start_clicked;
488 }
489
490
491 /*
492 * "Volumes" pane
493 */
494
495 static GtkWidget *w_enableextfs, *w_extdrives;
496 static GtkWidget *volume_list;
497 static int selected_volume;
498
499 // Set sensitivity of widgets
500 static void set_volumes_sensitive(void)
501 {
502 const bool enable_extfs = PrefsFindBool("enableextfs");
503 gtk_widget_set_sensitive(w_extdrives, enable_extfs);
504 }
505
506 // Volume in list selected
507 static void cl_selected(GtkWidget *list, int row, int column)
508 {
509 selected_volume = row;
510 }
511
512 // Volume selected for addition
513 static void add_volume_ok(GtkWidget *button, file_req_assoc *assoc)
514 {
515 gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
516 gtk_clist_append(GTK_CLIST(volume_list), &file);
517 gtk_widget_destroy(assoc->req);
518 delete assoc;
519 }
520
521 // Volume selected for creation
522 static void create_volume_ok(GtkWidget *button, file_req_assoc *assoc)
523 {
524 gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
525
526 const gchar *str = gtk_entry_get_text(GTK_ENTRY(assoc->entry));
527 size_t size = atoi(str) << 20;
528
529 int fd = _open(file, _O_WRONLY | _O_CREAT | _O_BINARY | _O_TRUNC, _S_IREAD | _S_IWRITE);
530 if (fd >= 0) {
531 if (_chsize(fd, size) == 0)
532 gtk_clist_append(GTK_CLIST(volume_list), &file);
533 _close(fd);
534 }
535 gtk_widget_destroy(GTK_WIDGET(assoc->req));
536 delete assoc;
537 }
538
539 // "Add Volume" button clicked
540 static void cb_add_volume(...)
541 {
542 GtkWidget *req = gtk_file_selection_new(GetString(STR_ADD_VOLUME_TITLE));
543 gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
544 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(add_volume_ok), new file_req_assoc(req, NULL));
545 gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
546 gtk_widget_show(req);
547 }
548
549 // "Create Hardfile" button clicked
550 static void cb_create_volume(...)
551 {
552 GtkWidget *req = gtk_file_selection_new(GetString(STR_CREATE_VOLUME_TITLE));
553
554 GtkWidget *box = gtk_hbox_new(FALSE, 4);
555 gtk_widget_show(box);
556 GtkWidget *label = gtk_label_new(GetString(STR_HARDFILE_SIZE_CTRL));
557 gtk_widget_show(label);
558 GtkWidget *entry = gtk_entry_new();
559 gtk_widget_show(entry);
560 char str[32];
561 sprintf(str, "%d", 40);
562 gtk_entry_set_text(GTK_ENTRY(entry), str);
563 gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
564 gtk_box_pack_start(GTK_BOX(box), entry, FALSE, FALSE, 0);
565 gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(req)->main_vbox), box, FALSE, FALSE, 0);
566
567 gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
568 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(create_volume_ok), new file_req_assoc(req, entry));
569 gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
570 gtk_widget_show(req);
571 }
572
573 // "Remove Volume" button clicked
574 static void cb_remove_volume(...)
575 {
576 gtk_clist_remove(GTK_CLIST(volume_list), selected_volume);
577 }
578
579 // "Boot From" selected
580 static void mn_boot_any(...) {PrefsReplaceInt32("bootdriver", 0);}
581 static void mn_boot_cdrom(...) {PrefsReplaceInt32("bootdriver", CDROMRefNum);}
582
583 // "Enable external file system" button toggled
584 static void tb_enableextfs(GtkWidget *widget)
585 {
586 PrefsReplaceBool("enableextfs", GTK_TOGGLE_BUTTON(widget)->active);
587 set_volumes_sensitive();
588 }
589
590 // "No CD-ROM Driver" button toggled
591 static void tb_nocdrom(GtkWidget *widget)
592 {
593 PrefsReplaceBool("nocdrom", GTK_TOGGLE_BUTTON(widget)->active);
594 }
595
596 // "Enable polling" button toggled
597 static void tb_pollmedia(GtkWidget *widget)
598 {
599 PrefsReplaceBool("pollmedia", GTK_TOGGLE_BUTTON(widget)->active);
600 }
601
602 // Read settings from widgets and set preferences
603 static void read_volumes_settings(void)
604 {
605 while (PrefsFindString("disk"))
606 PrefsRemoveItem("disk");
607
608 for (int i=0; i<GTK_CLIST(volume_list)->rows; i++) {
609 char *str;
610 gtk_clist_get_text(GTK_CLIST(volume_list), i, 0, &str);
611 PrefsAddString("disk", str);
612 }
613
614 PrefsReplaceString("extdrives", get_file_entry_path(w_extdrives));
615 }
616
617 // Create "Volumes" pane
618 static void create_volumes_pane(GtkWidget *top)
619 {
620 GtkWidget *box, *scroll, *menu;
621
622 box = make_pane(top, STR_VOLUMES_PANE_TITLE);
623
624 scroll = gtk_scrolled_window_new(NULL, NULL);
625 gtk_widget_show(scroll);
626 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
627 volume_list = gtk_clist_new(1);
628 gtk_widget_show(volume_list);
629 gtk_clist_set_selection_mode(GTK_CLIST(volume_list), GTK_SELECTION_SINGLE);
630 gtk_clist_set_shadow_type(GTK_CLIST(volume_list), GTK_SHADOW_NONE);
631 gtk_clist_set_reorderable(GTK_CLIST(volume_list), true);
632 gtk_signal_connect(GTK_OBJECT(volume_list), "select_row", GTK_SIGNAL_FUNC(cl_selected), NULL);
633 char *str;
634 int32 index = 0;
635 while ((str = const_cast<char *>(PrefsFindString("disk", index++))) != NULL)
636 gtk_clist_append(GTK_CLIST(volume_list), &str);
637 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), volume_list);
638 gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 0);
639 selected_volume = 0;
640
641 static const opt_desc buttons[] = {
642 {STR_ADD_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_add_volume)},
643 {STR_CREATE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_create_volume)},
644 {STR_REMOVE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_remove_volume)},
645 {0, NULL},
646 };
647 make_button_box(box, 0, buttons);
648 make_separator(box);
649
650 static const opt_desc options[] = {
651 {STR_BOOT_ANY_LAB, GTK_SIGNAL_FUNC(mn_boot_any)},
652 {STR_BOOT_CDROM_LAB, GTK_SIGNAL_FUNC(mn_boot_cdrom)},
653 {0, NULL}
654 };
655 int bootdriver = PrefsFindInt32("bootdriver"), active = 0;
656 switch (bootdriver) {
657 case 0: active = 0; break;
658 case CDROMRefNum: active = 1; break;
659 }
660 menu = make_option_menu(box, STR_BOOTDRIVER_CTRL, options, active);
661
662 make_checkbox(box, STR_NOCDROM_CTRL, "nocdrom", GTK_SIGNAL_FUNC(tb_nocdrom));
663
664 make_checkbox(box, STR_POLLMEDIA_CTRL, "pollmedia", GTK_SIGNAL_FUNC(tb_pollmedia));
665
666 make_separator(box);
667 w_enableextfs = make_checkbox(box, STR_EXTFS_ENABLE_CTRL, "enableextfs", GTK_SIGNAL_FUNC(tb_enableextfs));
668 w_extdrives = make_file_entry(box, STR_EXTFS_DRIVES_CTRL, "extdrives", true);
669
670 set_volumes_sensitive();
671 }
672
673
674 /*
675 * "JIT Compiler" pane
676 */
677
678 static GtkWidget *w_jit_fpu;
679 static GtkWidget *w_jit_atraps;
680 static GtkWidget *w_jit_cache_size;
681 static GtkWidget *w_jit_lazy_flush;
682 static GtkWidget *w_jit_follow_const_jumps;
683
684 // Set sensitivity of widgets
685 static void set_jit_sensitive(void)
686 {
687 const bool jit_enabled = PrefsFindBool("jit");
688 gtk_widget_set_sensitive(w_jit_fpu, jit_enabled);
689 gtk_widget_set_sensitive(w_jit_cache_size, jit_enabled);
690 gtk_widget_set_sensitive(w_jit_lazy_flush, jit_enabled);
691 gtk_widget_set_sensitive(w_jit_follow_const_jumps, jit_enabled);
692 }
693
694 // "Use JIT Compiler" button toggled
695 static void tb_jit(GtkWidget *widget)
696 {
697 PrefsReplaceBool("jit", GTK_TOGGLE_BUTTON(widget)->active);
698 set_jit_sensitive();
699 }
700
701 // "Compile FPU Instructions" button toggled
702 static void tb_jit_fpu(GtkWidget *widget)
703 {
704 PrefsReplaceBool("jitfpu", GTK_TOGGLE_BUTTON(widget)->active);
705 }
706
707 // "Lazy translation cache invalidation" button toggled
708 static void tb_jit_lazy_flush(GtkWidget *widget)
709 {
710 PrefsReplaceBool("jitlazyflush", GTK_TOGGLE_BUTTON(widget)->active);
711 }
712
713 // "Translate through constant jumps (inline blocks)" button toggled
714 static void tb_jit_follow_const_jumps(GtkWidget *widget)
715 {
716 PrefsReplaceBool("jitinline", GTK_TOGGLE_BUTTON(widget)->active);
717 }
718
719 // Read settings from widgets and set preferences
720 static void read_jit_settings(void)
721 {
722 #if USE_JIT
723 bool jit_enabled = PrefsFindBool("jit");
724 if (jit_enabled) {
725 const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_jit_cache_size)->entry));
726 PrefsReplaceInt32("jitcachesize", atoi(str));
727 }
728 #endif
729 }
730
731 // Create "JIT Compiler" pane
732 static void create_jit_pane(GtkWidget *top)
733 {
734 #if USE_JIT
735 GtkWidget *box, *table, *label, *menu;
736 char str[32];
737
738 box = make_pane(top, STR_JIT_PANE_TITLE);
739 make_checkbox(box, STR_JIT_CTRL, "jit", GTK_SIGNAL_FUNC(tb_jit));
740
741 w_jit_fpu = make_checkbox(box, STR_JIT_FPU_CTRL, "jitfpu", GTK_SIGNAL_FUNC(tb_jit_fpu));
742
743 // Translation cache size
744 static const combo_desc options[] = {
745 STR_JIT_CACHE_SIZE_2MB_LAB,
746 STR_JIT_CACHE_SIZE_4MB_LAB,
747 STR_JIT_CACHE_SIZE_8MB_LAB,
748 STR_JIT_CACHE_SIZE_16MB_LAB,
749 0
750 };
751 w_jit_cache_size = make_combobox(box, STR_JIT_CACHE_SIZE_CTRL, "jitcachesize", options);
752
753 // Lazy translation cache invalidation
754 w_jit_lazy_flush = make_checkbox(box, STR_JIT_LAZY_CINV_CTRL, "jitlazyflush", GTK_SIGNAL_FUNC(tb_jit_lazy_flush));
755
756 // Follow constant jumps (inline basic blocks)
757 w_jit_follow_const_jumps = make_checkbox(box, STR_JIT_FOLLOW_CONST_JUMPS, "jitinline", GTK_SIGNAL_FUNC(tb_jit_follow_const_jumps));
758
759 set_jit_sensitive();
760 #endif
761 }
762
763 /*
764 * "SCSI" pane
765 */
766
767 static GtkWidget *w_scsi[7];
768
769 // Read settings from widgets and set preferences
770 static void read_scsi_settings(void)
771 {
772 for (int id=0; id<7; id++) {
773 char prefs_name[32];
774 sprintf(prefs_name, "scsi%d", id);
775 const char *str = get_file_entry_path(w_scsi[id]);
776 if (str && strlen(str))
777 PrefsReplaceString(prefs_name, str);
778 else
779 PrefsRemoveItem(prefs_name);
780 }
781 }
782
783 // Create "SCSI" pane
784 static void create_scsi_pane(GtkWidget *top)
785 {
786 GtkWidget *box;
787
788 box = make_pane(top, STR_SCSI_PANE_TITLE);
789
790 for (int id=0; id<7; id++) {
791 char prefs_name[32];
792 sprintf(prefs_name, "scsi%d", id);
793 w_scsi[id] = make_file_entry(box, STR_SCSI_ID_0 + id, prefs_name);
794 }
795 }
796
797
798 /*
799 * "Graphics/Sound" pane
800 */
801
802 // Display types
803 enum {
804 DISPLAY_WINDOW,
805 DISPLAY_SCREEN
806 };
807
808 static GtkWidget *w_frameskip, *w_display_x, *w_display_y;
809 static GtkWidget *l_frameskip, *l_display_x, *l_display_y;
810 static int display_type;
811 static int dis_width, dis_height;
812
813 // Hide/show graphics widgets
814 static void hide_show_graphics_widgets(void)
815 {
816 switch (display_type) {
817 case DISPLAY_WINDOW:
818 gtk_widget_show(w_frameskip); gtk_widget_show(l_frameskip);
819 break;
820 case DISPLAY_SCREEN:
821 gtk_widget_hide(w_frameskip); gtk_widget_hide(l_frameskip);
822 break;
823 }
824 }
825
826 // "Window" video type selected
827 static void mn_window(...)
828 {
829 display_type = DISPLAY_WINDOW;
830 hide_show_graphics_widgets();
831 }
832
833 // "Fullscreen" video type selected
834 static void mn_fullscreen(...)
835 {
836 display_type = DISPLAY_SCREEN;
837 hide_show_graphics_widgets();
838 }
839
840 // "5 Hz".."60Hz" selected
841 static void mn_5hz(...) {PrefsReplaceInt32("frameskip", 12);}
842 static void mn_7hz(...) {PrefsReplaceInt32("frameskip", 8);}
843 static void mn_10hz(...) {PrefsReplaceInt32("frameskip", 6);}
844 static void mn_15hz(...) {PrefsReplaceInt32("frameskip", 4);}
845 static void mn_30hz(...) {PrefsReplaceInt32("frameskip", 2);}
846 static void mn_60hz(...) {PrefsReplaceInt32("frameskip", 1);}
847 static void mn_dynamic(...) {PrefsReplaceInt32("frameskip", 0);}
848
849 // Set sensitivity of widgets
850 static void set_graphics_sensitive(void)
851 {
852 const bool sound_enabled = !PrefsFindBool("nosound");
853 }
854
855 // "Disable Sound Output" button toggled
856 static void tb_nosound(GtkWidget *widget)
857 {
858 PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active);
859 set_graphics_sensitive();
860 }
861
862 // Read graphics preferences
863 static void parse_graphics_prefs(void)
864 {
865 display_type = DISPLAY_WINDOW;
866 dis_width = 512;
867 dis_height = 384;
868
869 const char *str = PrefsFindString("screen");
870 if (str) {
871 if (sscanf(str, "win/%d/%d", &dis_width, &dis_height) == 2)
872 display_type = DISPLAY_WINDOW;
873 else if (sscanf(str, "dga/%d/%d", &dis_width, &dis_height) == 2)
874 display_type = DISPLAY_SCREEN;
875 }
876 }
877
878 // Read settings from widgets and set preferences
879 static void read_graphics_settings(void)
880 {
881 const char *str;
882
883 str = gtk_entry_get_text(GTK_ENTRY(w_display_x));
884 dis_width = atoi(str);
885
886 str = gtk_entry_get_text(GTK_ENTRY(w_display_y));
887 dis_height = atoi(str);
888
889 char pref[256];
890 switch (display_type) {
891 case DISPLAY_WINDOW:
892 sprintf(pref, "win/%d/%d", dis_width, dis_height);
893 break;
894 case DISPLAY_SCREEN:
895 sprintf(pref, "dga/%d/%d", dis_width, dis_height);
896 break;
897 default:
898 PrefsRemoveItem("screen");
899 return;
900 }
901 PrefsReplaceString("screen", pref);
902 }
903
904 // Create "Graphics/Sound" pane
905 static void create_graphics_pane(GtkWidget *top)
906 {
907 GtkWidget *box, *table, *label, *opt, *menu, *combo;
908 char str[32];
909
910 parse_graphics_prefs();
911
912 box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE);
913 table = make_table(box, 2, 5);
914
915 label = gtk_label_new(GetString(STR_VIDEO_TYPE_CTRL));
916 gtk_widget_show(label);
917 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
918
919 opt = gtk_option_menu_new();
920 gtk_widget_show(opt);
921 menu = gtk_menu_new();
922 add_menu_item(menu, STR_WINDOW_LAB, GTK_SIGNAL_FUNC(mn_window));
923 add_menu_item(menu, STR_FULLSCREEN_LAB, GTK_SIGNAL_FUNC(mn_fullscreen));
924 switch (display_type) {
925 case DISPLAY_WINDOW:
926 gtk_menu_set_active(GTK_MENU(menu), 0);
927 break;
928 case DISPLAY_SCREEN:
929 gtk_menu_set_active(GTK_MENU(menu), 1);
930 break;
931 }
932 gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
933 gtk_table_attach(GTK_TABLE(table), opt, 1, 2, 0, 1, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
934
935 l_frameskip = gtk_label_new(GetString(STR_FRAMESKIP_CTRL));
936 gtk_widget_show(l_frameskip);
937 gtk_table_attach(GTK_TABLE(table), l_frameskip, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
938
939 w_frameskip = gtk_option_menu_new();
940 gtk_widget_show(w_frameskip);
941 menu = gtk_menu_new();
942 add_menu_item(menu, STR_REF_5HZ_LAB, GTK_SIGNAL_FUNC(mn_5hz));
943 add_menu_item(menu, STR_REF_7_5HZ_LAB, GTK_SIGNAL_FUNC(mn_7hz));
944 add_menu_item(menu, STR_REF_10HZ_LAB, GTK_SIGNAL_FUNC(mn_10hz));
945 add_menu_item(menu, STR_REF_15HZ_LAB, GTK_SIGNAL_FUNC(mn_15hz));
946 add_menu_item(menu, STR_REF_30HZ_LAB, GTK_SIGNAL_FUNC(mn_30hz));
947 add_menu_item(menu, STR_REF_60HZ_LAB, GTK_SIGNAL_FUNC(mn_60hz));
948 add_menu_item(menu, STR_REF_DYNAMIC_LAB, GTK_SIGNAL_FUNC(mn_dynamic));
949 int frameskip = PrefsFindInt32("frameskip");
950 int item = -1;
951 switch (frameskip) {
952 case 12: item = 0; break;
953 case 8: item = 1; break;
954 case 6: item = 2; break;
955 case 4: item = 3; break;
956 case 2: item = 4; break;
957 case 1: item = 5; break;
958 case 0: item = 6; break;
959 }
960 if (item >= 0)
961 gtk_menu_set_active(GTK_MENU(menu), item);
962 gtk_option_menu_set_menu(GTK_OPTION_MENU(w_frameskip), menu);
963 gtk_table_attach(GTK_TABLE(table), w_frameskip, 1, 2, 1, 2, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
964
965 l_display_x = gtk_label_new(GetString(STR_DISPLAY_X_CTRL));
966 gtk_widget_show(l_display_x);
967 gtk_table_attach(GTK_TABLE(table), l_display_x, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
968
969 combo = gtk_combo_new();
970 gtk_widget_show(combo);
971 GList *glist1 = NULL;
972 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_512_LAB));
973 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_640_LAB));
974 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_800_LAB));
975 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_1024_LAB));
976 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_MAX_LAB));
977 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist1);
978 if (dis_width)
979 sprintf(str, "%d", dis_width);
980 else
981 strcpy(str, GetString(STR_SIZE_MAX_LAB));
982 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
983 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
984 w_display_x = GTK_COMBO(combo)->entry;
985
986 l_display_y = gtk_label_new(GetString(STR_DISPLAY_Y_CTRL));
987 gtk_widget_show(l_display_y);
988 gtk_table_attach(GTK_TABLE(table), l_display_y, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
989
990 combo = gtk_combo_new();
991 gtk_widget_show(combo);
992 GList *glist2 = NULL;
993 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_384_LAB));
994 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_480_LAB));
995 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_600_LAB));
996 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_768_LAB));
997 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_MAX_LAB));
998 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist2);
999 if (dis_height)
1000 sprintf(str, "%d", dis_height);
1001 else
1002 strcpy(str, GetString(STR_SIZE_MAX_LAB));
1003 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1004 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
1005 w_display_y = GTK_COMBO(combo)->entry;
1006
1007 make_separator(box);
1008 make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound));
1009
1010 set_graphics_sensitive();
1011
1012 hide_show_graphics_widgets();
1013 }
1014
1015
1016 /*
1017 * "Input" pane
1018 */
1019
1020 static GtkWidget *w_keycode_file;
1021 static GtkWidget *w_mouse_wheel_lines;
1022
1023 // Set sensitivity of widgets
1024 static void set_input_sensitive(void)
1025 {
1026 const bool use_keycodes = PrefsFindBool("keycodes");
1027 gtk_widget_set_sensitive(w_keycode_file, use_keycodes);
1028 gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_keycode_file), "chooser_button")), use_keycodes);
1029 gtk_widget_set_sensitive(w_mouse_wheel_lines, PrefsFindInt32("mousewheelmode") == 1);
1030 }
1031
1032 // "Use Raw Keycodes" button toggled
1033 static void tb_keycodes(GtkWidget *widget)
1034 {
1035 PrefsReplaceBool("keycodes", GTK_TOGGLE_BUTTON(widget)->active);
1036 set_input_sensitive();
1037 }
1038
1039 // "Mouse Wheel Mode" selected
1040 static void mn_wheel_page(...) {PrefsReplaceInt32("mousewheelmode", 0); set_input_sensitive();}
1041 static void mn_wheel_cursor(...) {PrefsReplaceInt32("mousewheelmode", 1); set_input_sensitive();}
1042
1043 // Read settings from widgets and set preferences
1044 static void read_input_settings(void)
1045 {
1046 const char *str = get_file_entry_path(w_keycode_file);
1047 if (str && strlen(str))
1048 PrefsReplaceString("keycodefile", str);
1049 else
1050 PrefsRemoveItem("keycodefile");
1051
1052 PrefsReplaceInt32("mousewheellines", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_mouse_wheel_lines)));
1053 }
1054
1055 // Create "Input" pane
1056 static void create_input_pane(GtkWidget *top)
1057 {
1058 GtkWidget *box, *hbox, *menu, *label, *button;
1059 GtkObject *adj;
1060
1061 box = make_pane(top, STR_INPUT_PANE_TITLE);
1062
1063 make_checkbox(box, STR_KEYCODES_CTRL, "keycodes", GTK_SIGNAL_FUNC(tb_keycodes));
1064
1065 hbox = gtk_hbox_new(FALSE, 4);
1066 gtk_widget_show(hbox);
1067 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1068
1069 label = gtk_label_new(GetString(STR_KEYCODES_CTRL));
1070 gtk_widget_show(label);
1071 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1072
1073 const char *str = PrefsFindString("keycodefile");
1074 if (str == NULL)
1075 str = "";
1076
1077 w_keycode_file = gtk_entry_new();
1078 gtk_entry_set_text(GTK_ENTRY(w_keycode_file), str);
1079 gtk_widget_show(w_keycode_file);
1080 gtk_box_pack_start(GTK_BOX(hbox), w_keycode_file, TRUE, TRUE, 0);
1081
1082 button = make_browse_button(w_keycode_file);
1083 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1084 g_object_set_data(G_OBJECT(w_keycode_file), "chooser_button", button);
1085
1086 make_separator(box);
1087
1088 static const opt_desc options[] = {
1089 {STR_MOUSEWHEELMODE_PAGE_LAB, GTK_SIGNAL_FUNC(mn_wheel_page)},
1090 {STR_MOUSEWHEELMODE_CURSOR_LAB, GTK_SIGNAL_FUNC(mn_wheel_cursor)},
1091 {0, NULL}
1092 };
1093 int wheelmode = PrefsFindInt32("mousewheelmode"), active = 0;
1094 switch (wheelmode) {
1095 case 0: active = 0; break;
1096 case 1: active = 1; break;
1097 }
1098 menu = make_option_menu(box, STR_MOUSEWHEELMODE_CTRL, options, active);
1099
1100 hbox = gtk_hbox_new(FALSE, 4);
1101 gtk_widget_show(hbox);
1102 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1103
1104 label = gtk_label_new(GetString(STR_MOUSEWHEELLINES_CTRL));
1105 gtk_widget_show(label);
1106 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1107
1108 adj = gtk_adjustment_new(PrefsFindInt32("mousewheellines"), 1, 1000, 1, 5, 0);
1109 w_mouse_wheel_lines = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0);
1110 gtk_widget_show(w_mouse_wheel_lines);
1111 gtk_box_pack_start(GTK_BOX(hbox), w_mouse_wheel_lines, FALSE, FALSE, 0);
1112
1113 set_input_sensitive();
1114 }
1115
1116
1117 /*
1118 * "Serial" pane
1119 */
1120
1121 static GtkWidget *w_seriala, *w_portfile0;
1122 static GtkWidget *w_serialb, *w_portfile1;
1123
1124 // Set sensitivity of widgets
1125 static void set_serial_sensitive(void)
1126 {
1127 const char *str;
1128 bool is_file;
1129
1130 str = gtk_entry_get_text(GTK_ENTRY(w_seriala));
1131 is_file = strcmp(str, "FILE") == 0;
1132 gtk_widget_set_sensitive(w_portfile0, is_file);
1133 gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_portfile0), "chooser_button")), is_file);
1134
1135 str = gtk_entry_get_text(GTK_ENTRY(w_serialb));
1136 is_file = strcmp(str, "FILE") == 0;
1137 gtk_widget_set_sensitive(w_portfile1, is_file);
1138 gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_portfile1), "chooser_button")), is_file);
1139 }
1140
1141 // Read settings from widgets and set preferences
1142 static void read_serial_settings(void)
1143 {
1144 const char *str;
1145
1146 str = gtk_entry_get_text(GTK_ENTRY(w_seriala));
1147 PrefsReplaceString("seriala", str);
1148
1149 str = gtk_entry_get_text(GTK_ENTRY(w_serialb));
1150 PrefsReplaceString("serialb", str);
1151
1152 str = gtk_entry_get_text(GTK_ENTRY(w_portfile0));
1153 PrefsReplaceString("portfile0", str);
1154
1155 str = gtk_entry_get_text(GTK_ENTRY(w_portfile1));
1156 PrefsReplaceString("portfile1", str);
1157 }
1158
1159 // Port changed in combo
1160 static void cb_serial_port_changed(...)
1161 {
1162 set_serial_sensitive();
1163 }
1164
1165 // Add names of serial devices
1166 static GList *add_serial_names(void)
1167 {
1168 GList *glist = NULL;
1169
1170 static const char *port_names[] = {
1171 "COM1", "COM2", "COM3", "COM4", "COM5", "COM6",
1172 "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6",
1173 "FILE",
1174 NULL
1175 };
1176
1177 for (int i = 0; port_names[i] != NULL; i++)
1178 glist = g_list_append(glist, (void *)port_names[i]);
1179
1180 return glist;
1181 }
1182
1183 // Create "Serial" pane
1184 static void create_serial_pane(GtkWidget *top)
1185 {
1186 GtkWidget *box, *hbox, *table, *label, *combo, *sep, *entry;
1187 GtkObject *adj;
1188
1189 box = make_pane(top, STR_SERIAL_PANE_TITLE);
1190 table = make_table(box, 2, 5);
1191
1192 GList *glist = add_serial_names();
1193 const char *str = PrefsFindString("seriala");
1194 combo = table_make_combobox(table, 0, STR_SERIALA_CTRL, str, glist);
1195 w_seriala = GTK_COMBO(combo)->entry;
1196 gtk_signal_connect(GTK_OBJECT(w_seriala), "changed", GTK_SIGNAL_FUNC(cb_serial_port_changed), NULL);
1197
1198 w_portfile0 = table_make_file_entry(table, 1, STR_FILE_CTRL, "portfile0");
1199
1200 sep = gtk_hseparator_new();
1201 gtk_widget_show(sep);
1202 gtk_table_attach(GTK_TABLE(table), sep, 0, 2, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1203
1204 str = PrefsFindString("serialb");
1205 combo = table_make_combobox(table, 3, STR_SERIALB_CTRL, str, glist);
1206 w_serialb = GTK_COMBO(combo)->entry;
1207 gtk_signal_connect(GTK_OBJECT(w_serialb), "changed", GTK_SIGNAL_FUNC(cb_serial_port_changed), NULL);
1208
1209 w_portfile1 = table_make_file_entry(table, 4, STR_FILE_CTRL, "portfile1");
1210
1211 set_serial_sensitive();
1212 }
1213
1214
1215 /*
1216 * "Ethernet" pane
1217 */
1218
1219 static GtkWidget *w_ether;
1220 static GtkWidget *w_ftp_port_list, *w_tcp_port_list;
1221 static const char s_nat_router[] = "NAT/Router module";
1222
1223 // Set sensitivity of widgets
1224 static void set_ethernet_sensitive(void)
1225 {
1226 const char *str = gtk_entry_get_text(GTK_ENTRY(w_ether));
1227
1228 bool is_nat_router = strcmp(str, s_nat_router) == 0;
1229 gtk_widget_set_sensitive(w_ftp_port_list, is_nat_router);
1230 gtk_widget_set_sensitive(w_tcp_port_list, is_nat_router);
1231 }
1232
1233 // Read settings from widgets and set preferences
1234 static void read_ethernet_settings(void)
1235 {
1236 const char *str = gtk_entry_get_text(GTK_ENTRY(w_ether));
1237 if (str && strlen(str) > 6 && strncmp(str, "NDIS: ", 6) == 0)
1238 PrefsReplaceString("ether", &str[6]);
1239 else
1240 PrefsRemoveItem("ether");
1241
1242 const bool router_enabled = str && strcmp(str, s_nat_router) == 0;
1243 PrefsReplaceBool("routerenabled", router_enabled);
1244 if (router_enabled) {
1245 str = gtk_entry_get_text(GTK_ENTRY(w_ftp_port_list));
1246 PrefsReplaceString("ftp_port_list", str);
1247 str = gtk_entry_get_text(GTK_ENTRY(w_tcp_port_list));
1248 PrefsReplaceString("tcp_port", str);
1249 }
1250 }
1251
1252 // Ethernet emulation type changed in menulist
1253 static void cb_ether_changed(...)
1254 {
1255 set_ethernet_sensitive();
1256 }
1257
1258 // Add names of ethernet interfaces
1259 static GList *add_ether_names(void)
1260 {
1261 GList *glist = NULL;
1262
1263 // TODO: Get list of all Ethernet interfaces
1264 #ifdef HAVE_SLIRP
1265 static const char s_slirp[] = "slirp";
1266 glist = g_list_append(glist, (void *)s_slirp);
1267 #endif
1268 glist = g_list_append(glist, (void *)s_nat_router);
1269 glist = g_list_append(glist, (void *)GetString(STR_NONE_LAB));
1270 return glist;
1271 }
1272
1273
1274 // Create "Ethernet" pane
1275 static void create_ethernet_pane(GtkWidget *top)
1276 {
1277 GtkWidget *box, *hbox, *table, *label, *combo, *sep, *entry;
1278
1279 box = make_pane(top, STR_NETWORK_PANE_TITLE);
1280 table = make_table(box, 2, 5);
1281
1282 label = gtk_label_new(GetString(STR_ETHERNET_IF_CTRL));
1283 gtk_widget_show(label);
1284 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1285
1286 GList *glist = add_ether_names();
1287 combo = gtk_combo_new();
1288 gtk_widget_show(combo);
1289 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1290 const char *str = PrefsFindString("ether");
1291 if (str == NULL || str[0] == '\0') {
1292 if (PrefsFindBool("routerenabled"))
1293 str = s_nat_router;
1294 else
1295 str = GetString(STR_NONE_LAB);
1296 }
1297 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1298 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1299 w_ether = GTK_COMBO(combo)->entry;
1300 gtk_signal_connect(GTK_OBJECT(w_ether), "changed", GTK_SIGNAL_FUNC(cb_ether_changed), NULL);
1301
1302 sep = gtk_hseparator_new();
1303 gtk_widget_show(sep);
1304 gtk_table_attach(GTK_TABLE(table), sep, 0, 2, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1305
1306 label = gtk_label_new(GetString(STR_ETHER_FTP_PORT_LIST_CTRL));
1307 gtk_widget_show(label);
1308 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1309
1310 entry = gtk_entry_new();
1311 str = PrefsFindString("ftp_port_list");
1312 if (str == NULL)
1313 str = "";
1314 gtk_entry_set_text(GTK_ENTRY(entry), str);
1315 gtk_widget_show(entry);
1316 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 2, 3, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1317 w_ftp_port_list = entry;
1318
1319 label = gtk_label_new(GetString(STR_ETHER_TCP_PORT_LIST_CTRL));
1320 gtk_widget_show(label);
1321 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1322
1323 entry = gtk_entry_new();
1324 str = PrefsFindString("tcp_port");
1325 if (str == NULL)
1326 str = "";
1327 gtk_entry_set_text(GTK_ENTRY(entry), str);
1328 gtk_widget_show(entry);
1329 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 3, 4, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1330 w_tcp_port_list = entry;
1331
1332 set_ethernet_sensitive();
1333 }
1334
1335
1336 /*
1337 * "Memory/Misc" pane
1338 */
1339
1340 static GtkWidget *w_ramsize;
1341 static GtkWidget *w_rom_file;
1342
1343 // "Ignore SEGV" button toggled
1344 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1345 static void tb_ignoresegv(GtkWidget *widget)
1346 {
1347 PrefsReplaceBool("ignoresegv", GTK_TOGGLE_BUTTON(widget)->active);
1348 }
1349 #endif
1350
1351 // Model ID selected
1352 static void mn_modelid_5(...) {PrefsReplaceInt32("modelid", 5);}
1353 static void mn_modelid_14(...) {PrefsReplaceInt32("modelid", 14);}
1354
1355 // CPU/FPU type
1356 static void mn_cpu_68020(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", false);}
1357 static void mn_cpu_68020_fpu(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", true);}
1358 static void mn_cpu_68030(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", false);}
1359 static void mn_cpu_68030_fpu(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", true);}
1360 static void mn_cpu_68040(...) {PrefsReplaceInt32("cpu", 4); PrefsReplaceBool("fpu", true);}
1361
1362 // Read settings from widgets and set preferences
1363 static void read_memory_settings(void)
1364 {
1365 const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_ramsize)->entry));
1366 PrefsReplaceInt32("ramsize", atoi(str) << 20);
1367
1368 str = get_file_entry_path(w_rom_file);
1369 if (str && strlen(str))
1370 PrefsReplaceString("rom", str);
1371 else
1372 PrefsRemoveItem("rom");
1373
1374 }
1375
1376 // Create "Memory/Misc" pane
1377 static void create_memory_pane(GtkWidget *top)
1378 {
1379 GtkWidget *box, *hbox, *table, *label, *scale, *menu;
1380
1381 box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE);
1382 table = make_table(box, 2, 5);
1383
1384 static const combo_desc options[] = {
1385 STR_RAMSIZE_2MB_LAB,
1386 STR_RAMSIZE_4MB_LAB,
1387 STR_RAMSIZE_8MB_LAB,
1388 STR_RAMSIZE_16MB_LAB,
1389 STR_RAMSIZE_32MB_LAB,
1390 STR_RAMSIZE_64MB_LAB,
1391 STR_RAMSIZE_128MB_LAB,
1392 STR_RAMSIZE_256MB_LAB,
1393 STR_RAMSIZE_512MB_LAB,
1394 STR_RAMSIZE_1024MB_LAB,
1395 0
1396 };
1397 char default_ramsize[10];
1398 sprintf(default_ramsize, "%d", PrefsFindInt32("ramsize") >> 20);
1399 w_ramsize = table_make_combobox(table, 0, STR_RAMSIZE_CTRL, default_ramsize, options);
1400
1401 static const opt_desc model_options[] = {
1402 {STR_MODELID_5_LAB, GTK_SIGNAL_FUNC(mn_modelid_5)},
1403 {STR_MODELID_14_LAB, GTK_SIGNAL_FUNC(mn_modelid_14)},
1404 {0, NULL}
1405 };
1406 int modelid = PrefsFindInt32("modelid"), active = 0;
1407 switch (modelid) {
1408 case 5: active = 0; break;
1409 case 14: active = 1; break;
1410 }
1411 table_make_option_menu(table, 2, STR_MODELID_CTRL, model_options, active);
1412
1413 #if EMULATED_68K
1414 static const opt_desc cpu_options[] = {
1415 {STR_CPU_68020_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020)},
1416 {STR_CPU_68020_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020_fpu)},
1417 {STR_CPU_68030_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030)},
1418 {STR_CPU_68030_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030_fpu)},
1419 {STR_CPU_68040_LAB, GTK_SIGNAL_FUNC(mn_cpu_68040)},
1420 {0, NULL}
1421 };
1422 int cpu = PrefsFindInt32("cpu");
1423 bool fpu = PrefsFindBool("fpu");
1424 active = 0;
1425 switch (cpu) {
1426 case 2: active = fpu ? 1 : 0; break;
1427 case 3: active = fpu ? 3 : 2; break;
1428 case 4: active = 4;
1429 }
1430 table_make_option_menu(table, 3, STR_CPU_CTRL, cpu_options, active);
1431 #endif
1432
1433 w_rom_file = table_make_file_entry(table, 4, STR_ROM_FILE_CTRL, "rom");
1434
1435 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1436 make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv));
1437 #endif
1438 }
1439
1440
1441 /*
1442 * Read settings from widgets and set preferences
1443 */
1444
1445 static void read_settings(void)
1446 {
1447 read_volumes_settings();
1448 read_scsi_settings();
1449 read_graphics_settings();
1450 read_input_settings();
1451 read_serial_settings();
1452 read_ethernet_settings();
1453 read_memory_settings();
1454 read_jit_settings();
1455 }
1456
1457
1458 /*
1459 * Fake unused data and functions
1460 */
1461
1462 uint8 XPRAM[XPRAM_SIZE];
1463 void MountVolume(void *fh) { }
1464 void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) { }
1465 void WarningAlert(const char *text) { }
1466
1467
1468 /*
1469 * Add default serial prefs (must be added, even if no ports present)
1470 */
1471
1472 void SysAddSerialPrefs(void)
1473 {
1474 PrefsAddString("seriala", "COM1");
1475 PrefsAddString("serialb", "COM2");
1476 }
1477
1478
1479 /*
1480 * Display alerts
1481 */
1482
1483 static void display_alert(int title_id, const char *text, int flags)
1484 {
1485 MessageBox(NULL, text, GetString(title_id), MB_OK | flags);
1486 }
1487
1488 static void ErrorAlert(const char *text)
1489 {
1490 display_alert(STR_ERROR_ALERT_TITLE, text, MB_ICONSTOP);
1491 }
1492
1493
1494 /*
1495 * Start standalone GUI
1496 */
1497
1498 int main(int argc, char *argv[])
1499 {
1500 // Init GTK
1501 gtk_set_locale();
1502 gtk_init(&argc, &argv);
1503
1504 // Read preferences
1505 PrefsInit(argc, argv);
1506
1507 // Show preferences editor
1508 bool start = PrefsEditor();
1509
1510 // Exit preferences
1511 PrefsExit();
1512
1513 // Transfer control to the Basilisk II executable
1514 if (start) {
1515 char path[_MAX_PATH];
1516 bool ok = GetModuleFileName(NULL, path, sizeof(path)) != 0;
1517 if (ok) {
1518 char b2_path[_MAX_PATH];
1519 char *p = strrchr(path, '\\');
1520 *++p = '\0';
1521 SetCurrentDirectory(path);
1522 strcpy(b2_path, path);
1523 strcat(b2_path, "BasiliskII.exe");
1524 HINSTANCE h = ShellExecute(GetDesktopWindow(), "open",
1525 b2_path, "", path, SW_SHOWNORMAL);
1526 if ((int)h <= 32)
1527 ok = false;
1528 }
1529 if (!ok) {
1530 ErrorAlert("Coult not start BasiliskII executable");
1531 return 1;
1532 }
1533 }
1534
1535 return 0;
1536 }