ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/prefs_editor_gtk.cpp
Revision: 1.8
Committed: 2005-11-27T23:51:47Z (18 years, 6 months ago) by gbeauche
Branch: MAIN
Changes since 1.7: +95 -11 lines
Log Message:
SheepShaver GUI, remove extraneous "slirp" currently inexistent for Windows

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