ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/prefs_editor_gtk.cpp
Revision: 1.41
Committed: 2010-01-15T01:53:31Z (14 years, 3 months ago) by asvitkine
Branch: MAIN
CVS Tags: HEAD
Changes since 1.40: +1 -1 lines
Log Message:
Fix PrefsInit() calls to take correct number of parameter

File Contents

# Content
1 /*
2 * prefs_editor_gtk.cpp - Preferences editor, Unix implementation using GTK+
3 *
4 * Basilisk II (C) 1997-2008 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 <gtk/gtk.h>
24 #include <stdlib.h>
25 #include <dirent.h>
26 #include <sys/socket.h>
27 #include <sys/ioctl.h>
28 #include <net/if.h>
29 #include <net/if_arp.h>
30
31 #ifdef HAVE_GNOMEUI
32 #include <gnome.h>
33 #endif
34
35 #include "user_strings.h"
36 #include "version.h"
37 #include "cdrom.h"
38 #include "xpram.h"
39 #include "prefs.h"
40 #include "prefs_editor.h"
41
42 #define DEBUG 0
43 #include "debug.h"
44
45
46 // Global variables
47 static GtkWidget *win; // Preferences window
48 static bool start_clicked = false; // Return value of PrefsEditor() function
49
50
51 // Prototypes
52 static void create_volumes_pane(GtkWidget *top);
53 static void create_scsi_pane(GtkWidget *top);
54 static void create_graphics_pane(GtkWidget *top);
55 static void create_input_pane(GtkWidget *top);
56 static void create_serial_pane(GtkWidget *top);
57 static void create_memory_pane(GtkWidget *top);
58 static void create_jit_pane(GtkWidget *top);
59 static void read_settings(void);
60
61
62 /*
63 * Utility functions
64 */
65
66 #if ! GLIB_CHECK_VERSION(2,0,0)
67 #define G_OBJECT(obj) GTK_OBJECT(obj)
68 #define g_object_get_data(obj, key) gtk_object_get_data((obj), (key))
69 #define g_object_set_data(obj, key, data) gtk_object_set_data((obj), (key), (data))
70 #endif
71
72 struct opt_desc {
73 int label_id;
74 GtkSignalFunc func;
75 };
76
77 struct combo_desc {
78 int label_id;
79 };
80
81 struct file_req_assoc {
82 file_req_assoc(GtkWidget *r, GtkWidget *e) : req(r), entry(e) {}
83 GtkWidget *req;
84 GtkWidget *entry;
85 };
86
87 static void cb_browse_ok(GtkWidget *button, file_req_assoc *assoc)
88 {
89 gchar *file = (char *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
90 gtk_entry_set_text(GTK_ENTRY(assoc->entry), file);
91 gtk_widget_destroy(assoc->req);
92 delete assoc;
93 }
94
95 static void cb_browse(GtkWidget *widget, void *user_data)
96 {
97 GtkWidget *req = gtk_file_selection_new(GetString(STR_BROWSE_TITLE));
98 gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
99 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));
100 gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
101 gtk_widget_show(req);
102 }
103
104 static GtkWidget *make_browse_button(GtkWidget *entry)
105 {
106 GtkWidget *button;
107
108 button = gtk_button_new_with_label(GetString(STR_BROWSE_CTRL));
109 gtk_widget_show(button);
110 gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc)cb_browse, (void *)entry);
111 return button;
112 }
113
114 static void add_menu_item(GtkWidget *menu, int label_id, GtkSignalFunc func)
115 {
116 GtkWidget *item = gtk_menu_item_new_with_label(GetString(label_id));
117 gtk_widget_show(item);
118 gtk_signal_connect(GTK_OBJECT(item), "activate", func, NULL);
119 gtk_menu_append(GTK_MENU(menu), item);
120 }
121
122 static GtkWidget *make_pane(GtkWidget *notebook, int title_id)
123 {
124 GtkWidget *frame, *label, *box;
125
126 frame = gtk_frame_new(NULL);
127 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
128
129 box = gtk_vbox_new(FALSE, 4);
130 gtk_container_set_border_width(GTK_CONTAINER(box), 4);
131 gtk_container_add(GTK_CONTAINER(frame), box);
132
133 gtk_widget_show_all(frame);
134
135 label = gtk_label_new(GetString(title_id));
136 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label);
137 return box;
138 }
139
140 static GtkWidget *make_button_box(GtkWidget *top, int border, const opt_desc *buttons)
141 {
142 GtkWidget *bb, *button;
143
144 bb = gtk_hbutton_box_new();
145 gtk_widget_show(bb);
146 gtk_container_set_border_width(GTK_CONTAINER(bb), border);
147 gtk_button_box_set_layout(GTK_BUTTON_BOX(bb), GTK_BUTTONBOX_DEFAULT_STYLE);
148 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bb), 4);
149 gtk_box_pack_start(GTK_BOX(top), bb, FALSE, FALSE, 0);
150
151 while (buttons->label_id) {
152 button = gtk_button_new_with_label(GetString(buttons->label_id));
153 gtk_widget_show(button);
154 gtk_signal_connect_object(GTK_OBJECT(button), "clicked", buttons->func, NULL);
155 gtk_box_pack_start(GTK_BOX(bb), button, TRUE, TRUE, 0);
156 buttons++;
157 }
158 return bb;
159 }
160
161 static GtkWidget *make_separator(GtkWidget *top)
162 {
163 GtkWidget *sep = gtk_hseparator_new();
164 gtk_box_pack_start(GTK_BOX(top), sep, FALSE, FALSE, 0);
165 gtk_widget_show(sep);
166 return sep;
167 }
168
169 static GtkWidget *make_table(GtkWidget *top, int x, int y)
170 {
171 GtkWidget *table = gtk_table_new(x, y, FALSE);
172 gtk_widget_show(table);
173 gtk_box_pack_start(GTK_BOX(top), table, FALSE, FALSE, 0);
174 return table;
175 }
176
177 static GtkWidget *table_make_option_menu(GtkWidget *table, int row, int label_id, const opt_desc *options, int active)
178 {
179 GtkWidget *label, *opt, *menu;
180
181 label = gtk_label_new(GetString(label_id));
182 gtk_widget_show(label);
183 gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
184
185 opt = gtk_option_menu_new();
186 gtk_widget_show(opt);
187 menu = gtk_menu_new();
188
189 while (options->label_id) {
190 add_menu_item(menu, options->label_id, options->func);
191 options++;
192 }
193 gtk_menu_set_active(GTK_MENU(menu), active);
194
195 gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
196 gtk_table_attach(GTK_TABLE(table), opt, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
197 return menu;
198 }
199
200 static GtkWidget *table_make_combobox(GtkWidget *table, int row, int label_id, const char *default_value, GList *glist)
201 {
202 GtkWidget *label, *combo;
203 char str[32];
204
205 label = gtk_label_new(GetString(label_id));
206 gtk_widget_show(label);
207 gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
208
209 combo = gtk_combo_new();
210 gtk_widget_show(combo);
211 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
212
213 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), default_value);
214 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
215
216 return combo;
217 }
218
219 static GtkWidget *table_make_combobox(GtkWidget *table, int row, int label_id, const char *default_value, const combo_desc *options)
220 {
221 GList *glist = NULL;
222 while (options->label_id) {
223 glist = g_list_append(glist, (void *)GetString(options->label_id));
224 options++;
225 }
226
227 return table_make_combobox(table, row, label_id, default_value, glist);
228 }
229
230 static GtkWidget *table_make_file_entry(GtkWidget *table, int row, int label_id, const char *prefs_item, bool only_dirs = false)
231 {
232 GtkWidget *box, *label, *entry, *button;
233
234 label = gtk_label_new(GetString(label_id));
235 gtk_widget_show(label);
236 gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
237
238 const char *str = PrefsFindString(prefs_item);
239 if (str == NULL)
240 str = "";
241
242 box = gtk_hbox_new(FALSE, 4);
243 gtk_widget_show(box);
244 gtk_table_attach(GTK_TABLE(table), box, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
245
246 entry = gtk_entry_new();
247 gtk_entry_set_text(GTK_ENTRY(entry), str);
248 gtk_widget_show(entry);
249 gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0);
250
251 button = make_browse_button(entry);
252 gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
253 g_object_set_data(G_OBJECT(entry), "chooser_button", button);
254 return entry;
255 }
256
257 static GtkWidget *make_option_menu(GtkWidget *top, int label_id, const opt_desc *options, int active)
258 {
259 GtkWidget *box, *label, *opt, *menu;
260
261 box = gtk_hbox_new(FALSE, 4);
262 gtk_widget_show(box);
263 gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0);
264
265 label = gtk_label_new(GetString(label_id));
266 gtk_widget_show(label);
267 gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
268
269 opt = gtk_option_menu_new();
270 gtk_widget_show(opt);
271 menu = gtk_menu_new();
272
273 while (options->label_id) {
274 add_menu_item(menu, options->label_id, options->func);
275 options++;
276 }
277 gtk_menu_set_active(GTK_MENU(menu), active);
278
279 gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
280 gtk_box_pack_start(GTK_BOX(box), opt, FALSE, FALSE, 0);
281 return menu;
282 }
283
284 static GtkWidget *make_file_entry(GtkWidget *top, int label_id, const char *prefs_item, bool only_dirs = false)
285 {
286 GtkWidget *box, *label, *entry;
287
288 box = gtk_hbox_new(FALSE, 4);
289 gtk_widget_show(box);
290 gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0);
291
292 label = gtk_label_new(GetString(label_id));
293 gtk_widget_show(label);
294 gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
295
296 const char *str = PrefsFindString(prefs_item);
297 if (str == NULL)
298 str = "";
299
300 #ifdef HAVE_GNOMEUI
301 entry = gnome_file_entry_new(NULL, GetString(label_id));
302 if (only_dirs)
303 gnome_file_entry_set_directory(GNOME_FILE_ENTRY(entry), true);
304 gtk_entry_set_text(GTK_ENTRY(gnome_file_entry_gtk_entry(GNOME_FILE_ENTRY(entry))), str);
305 #else
306 entry = gtk_entry_new();
307 gtk_entry_set_text(GTK_ENTRY(entry), str);
308 #endif
309 gtk_widget_show(entry);
310 gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0);
311 return entry;
312 }
313
314 static const gchar *get_file_entry_path(GtkWidget *entry)
315 {
316 #ifdef HAVE_GNOMEUI
317 return gnome_file_entry_get_full_path(GNOME_FILE_ENTRY(entry), false);
318 #else
319 return gtk_entry_get_text(GTK_ENTRY(entry));
320 #endif
321 }
322
323 static GtkWidget *make_checkbox(GtkWidget *top, int label_id, const char *prefs_item, GtkSignalFunc func)
324 {
325 GtkWidget *button = gtk_check_button_new_with_label(GetString(label_id));
326 gtk_widget_show(button);
327 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), PrefsFindBool(prefs_item));
328 gtk_signal_connect(GTK_OBJECT(button), "toggled", func, button);
329 gtk_box_pack_start(GTK_BOX(top), button, FALSE, FALSE, 0);
330 return button;
331 }
332
333 static GtkWidget *make_combobox(GtkWidget *top, int label_id, const char *prefs_item, const combo_desc *options)
334 {
335 GtkWidget *box, *label, *combo;
336 char str[32];
337
338 box = gtk_hbox_new(FALSE, 4);
339 gtk_widget_show(box);
340 gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0);
341
342 label = gtk_label_new(GetString(label_id));
343 gtk_widget_show(label);
344 gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
345
346 GList *glist = NULL;
347 while (options->label_id) {
348 glist = g_list_append(glist, (void *)GetString(options->label_id));
349 options++;
350 }
351
352 combo = gtk_combo_new();
353 gtk_widget_show(combo);
354 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
355
356 sprintf(str, "%d", PrefsFindInt32(prefs_item));
357 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
358 gtk_box_pack_start(GTK_BOX(box), combo, TRUE, TRUE, 0);
359
360 return combo;
361 }
362
363
364 /*
365 * Show preferences editor
366 * Returns true when user clicked on "Start", false otherwise
367 */
368
369 // Window closed
370 static gint window_closed(void)
371 {
372 return FALSE;
373 }
374
375 // Window destroyed
376 static void window_destroyed(void)
377 {
378 gtk_main_quit();
379 }
380
381 // "Start" button clicked
382 static void cb_start(...)
383 {
384 start_clicked = true;
385 read_settings();
386 SavePrefs();
387 gtk_widget_destroy(win);
388 }
389
390 // "Quit" button clicked
391 static void cb_quit(...)
392 {
393 start_clicked = false;
394 gtk_widget_destroy(win);
395 }
396
397 // "OK" button of "About" dialog clicked
398 static void dl_quit(GtkWidget *dialog)
399 {
400 gtk_widget_destroy(dialog);
401 }
402
403 // "About" selected
404 static void mn_about(...)
405 {
406 GtkWidget *dialog;
407
408 #ifdef HAVE_GNOMEUI
409
410 char version[32];
411 sprintf(version, "Version %d.%d", VERSION_MAJOR, VERSION_MINOR);
412 const char *authors[] = {
413 "Christian Bauer",
414 "Orlando Bassotto",
415 "Gwenolé Beauchesne",
416 "Marc Chabanas",
417 "Marc Hellwig",
418 "Biill Huey",
419 "Brian J. Johnson",
420 "Jürgen Lachmann",
421 "Samuel Lander",
422 "David Lawrence",
423 "Lauri Pesonen",
424 "Bernd Schmidt",
425 "and others",
426 NULL
427 };
428 dialog = gnome_about_new(
429 "Basilisk II",
430 version,
431 "Copyright (C) 1997-2008 Christian Bauer",
432 authors,
433 "Basilisk II comes with ABSOLUTELY NO WARRANTY."
434 "This is free software, and you are welcome to redistribute it"
435 "under the terms of the GNU General Public License.",
436 NULL
437 );
438 gnome_dialog_set_parent(GNOME_DIALOG(dialog), GTK_WINDOW(win));
439
440 #else
441
442 GtkWidget *label, *button;
443
444 char str[512];
445 sprintf(str,
446 "Basilisk II\nVersion %d.%d\n\n"
447 "Copyright (C) 1997-2008 Christian Bauer et al.\n"
448 "E-mail: Christian.Bauer@uni-mainz.de\n"
449 "http://www.uni-mainz.de/~bauec002/B2Main.html\n\n"
450 "Basilisk II comes with ABSOLUTELY NO\n"
451 "WARRANTY. This is free software, and\n"
452 "you are welcome to redistribute it\n"
453 "under the terms of the GNU General\n"
454 "Public License.\n",
455 VERSION_MAJOR, VERSION_MINOR
456 );
457
458 dialog = gtk_dialog_new();
459 gtk_window_set_title(GTK_WINDOW(dialog), GetString(STR_ABOUT_TITLE));
460 gtk_container_border_width(GTK_CONTAINER(dialog), 5);
461 gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
462
463 label = gtk_label_new(str);
464 gtk_widget_show(label);
465 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
466
467 button = gtk_button_new_with_label(GetString(STR_OK_BUTTON));
468 gtk_widget_show(button);
469 gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
470 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
471 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
472 gtk_widget_grab_default(button);
473
474 #endif
475
476 gtk_widget_show(dialog);
477 }
478
479 // "Zap PRAM" selected
480 static void mn_zap_pram(...)
481 {
482 ZapPRAM();
483 }
484
485 // Menu item descriptions
486 static GtkItemFactoryEntry menu_items[] = {
487 {(gchar *)GetString(STR_PREFS_MENU_FILE_GTK), NULL, NULL, 0, "<Branch>"},
488 {(gchar *)GetString(STR_PREFS_ITEM_START_GTK), "<control>S", GTK_SIGNAL_FUNC(cb_start), 0, NULL},
489 {(gchar *)GetString(STR_PREFS_ITEM_ZAP_PRAM_GTK), NULL, GTK_SIGNAL_FUNC(mn_zap_pram), 0, NULL},
490 {(gchar *)GetString(STR_PREFS_ITEM_SEPL_GTK), NULL, NULL, 0, "<Separator>"},
491 {(gchar *)GetString(STR_PREFS_ITEM_QUIT_GTK), "<control>Q", GTK_SIGNAL_FUNC(cb_quit), 0, NULL},
492 {(gchar *)GetString(STR_HELP_MENU_GTK), NULL, NULL, 0, "<LastBranch>"},
493 {(gchar *)GetString(STR_HELP_ITEM_ABOUT_GTK), NULL, GTK_SIGNAL_FUNC(mn_about), 0, NULL}
494 };
495
496 bool PrefsEditor(void)
497 {
498 // Create window
499 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
500 gtk_window_set_title(GTK_WINDOW(win), GetString(STR_PREFS_TITLE));
501 gtk_signal_connect(GTK_OBJECT(win), "delete_event", GTK_SIGNAL_FUNC(window_closed), NULL);
502 gtk_signal_connect(GTK_OBJECT(win), "destroy", GTK_SIGNAL_FUNC(window_destroyed), NULL);
503
504 // Create window contents
505 GtkWidget *box = gtk_vbox_new(FALSE, 4);
506 gtk_widget_show(box);
507 gtk_container_add(GTK_CONTAINER(win), box);
508
509 GtkAccelGroup *accel_group = gtk_accel_group_new();
510 GtkItemFactory *item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
511 gtk_item_factory_create_items(item_factory, sizeof(menu_items) / sizeof(menu_items[0]), menu_items, NULL);
512 #if GTK_CHECK_VERSION(1,3,15)
513 gtk_window_add_accel_group(GTK_WINDOW(win), accel_group);
514 #else
515 gtk_accel_group_attach(accel_group, GTK_OBJECT(win));
516 #endif
517 GtkWidget *menu_bar = gtk_item_factory_get_widget(item_factory, "<main>");
518 gtk_widget_show(menu_bar);
519 gtk_box_pack_start(GTK_BOX(box), menu_bar, FALSE, TRUE, 0);
520
521 GtkWidget *notebook = gtk_notebook_new();
522 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
523 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), FALSE);
524 gtk_box_pack_start(GTK_BOX(box), notebook, TRUE, TRUE, 0);
525 gtk_widget_realize(notebook);
526
527 create_volumes_pane(notebook);
528 create_scsi_pane(notebook);
529 create_graphics_pane(notebook);
530 create_input_pane(notebook);
531 create_serial_pane(notebook);
532 create_memory_pane(notebook);
533 create_jit_pane(notebook);
534 gtk_widget_show(notebook);
535
536 static const opt_desc buttons[] = {
537 {STR_START_BUTTON, GTK_SIGNAL_FUNC(cb_start)},
538 {STR_QUIT_BUTTON, GTK_SIGNAL_FUNC(cb_quit)},
539 {0, NULL}
540 };
541 make_button_box(box, 4, buttons);
542
543 // Show window and enter main loop
544 gtk_widget_show(win);
545 gtk_main();
546 return start_clicked;
547 }
548
549
550 /*
551 * "Volumes" pane
552 */
553
554 static GtkWidget *volume_list, *w_extfs;
555 static int selected_volume;
556
557 // Volume in list selected
558 static void cl_selected(GtkWidget *list, int row, int column)
559 {
560 selected_volume = row;
561 }
562
563 // Volume selected for addition
564 static void add_volume_ok(GtkWidget *button, file_req_assoc *assoc)
565 {
566 gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
567 gtk_clist_append(GTK_CLIST(volume_list), &file);
568 gtk_widget_destroy(assoc->req);
569 delete assoc;
570 }
571
572 // Volume selected for creation
573 static void create_volume_ok(GtkWidget *button, file_req_assoc *assoc)
574 {
575 gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
576
577 const gchar *str = gtk_entry_get_text(GTK_ENTRY(assoc->entry));
578 int size = atoi(str);
579
580 char cmd[1024];
581 sprintf(cmd, "dd if=/dev/zero \"of=%s\" bs=1024k count=%d", file, size);
582 int ret = system(cmd);
583 if (ret == 0)
584 gtk_clist_append(GTK_CLIST(volume_list), &file);
585 gtk_widget_destroy(GTK_WIDGET(assoc->req));
586 delete assoc;
587 }
588
589 // "Add Volume" button clicked
590 static void cb_add_volume(...)
591 {
592 GtkWidget *req = gtk_file_selection_new(GetString(STR_ADD_VOLUME_TITLE));
593 gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
594 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(add_volume_ok), new file_req_assoc(req, NULL));
595 gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
596 gtk_widget_show(req);
597 }
598
599 // "Create Hardfile" button clicked
600 static void cb_create_volume(...)
601 {
602 GtkWidget *req = gtk_file_selection_new(GetString(STR_CREATE_VOLUME_TITLE));
603
604 GtkWidget *box = gtk_hbox_new(FALSE, 4);
605 gtk_widget_show(box);
606 GtkWidget *label = gtk_label_new(GetString(STR_HARDFILE_SIZE_CTRL));
607 gtk_widget_show(label);
608 GtkWidget *entry = gtk_entry_new();
609 gtk_widget_show(entry);
610 char str[32];
611 sprintf(str, "%d", 40);
612 gtk_entry_set_text(GTK_ENTRY(entry), str);
613 gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
614 gtk_box_pack_start(GTK_BOX(box), entry, FALSE, FALSE, 0);
615 gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(req)->main_vbox), box, FALSE, FALSE, 0);
616
617 gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
618 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(create_volume_ok), new file_req_assoc(req, entry));
619 gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
620 gtk_widget_show(req);
621 }
622
623 // "Remove Volume" button clicked
624 static void cb_remove_volume(...)
625 {
626 gtk_clist_remove(GTK_CLIST(volume_list), selected_volume);
627 }
628
629 // "Boot From" selected
630 static void mn_boot_any(...) {PrefsReplaceInt32("bootdriver", 0);}
631 static void mn_boot_cdrom(...) {PrefsReplaceInt32("bootdriver", CDROMRefNum);}
632
633 // "No CD-ROM Driver" button toggled
634 static void tb_nocdrom(GtkWidget *widget)
635 {
636 PrefsReplaceBool("nocdrom", GTK_TOGGLE_BUTTON(widget)->active);
637 }
638
639 // Read settings from widgets and set preferences
640 static void read_volumes_settings(void)
641 {
642 while (PrefsFindString("disk"))
643 PrefsRemoveItem("disk");
644
645 for (int i=0; i<GTK_CLIST(volume_list)->rows; i++) {
646 char *str;
647 gtk_clist_get_text(GTK_CLIST(volume_list), i, 0, &str);
648 PrefsAddString("disk", str);
649 }
650
651 PrefsReplaceString("extfs", get_file_entry_path(w_extfs));
652 }
653
654 // Create "Volumes" pane
655 static void create_volumes_pane(GtkWidget *top)
656 {
657 GtkWidget *box, *scroll, *menu;
658
659 box = make_pane(top, STR_VOLUMES_PANE_TITLE);
660
661 scroll = gtk_scrolled_window_new(NULL, NULL);
662 gtk_widget_show(scroll);
663 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
664 volume_list = gtk_clist_new(1);
665 gtk_widget_show(volume_list);
666 gtk_clist_set_selection_mode(GTK_CLIST(volume_list), GTK_SELECTION_SINGLE);
667 gtk_clist_set_shadow_type(GTK_CLIST(volume_list), GTK_SHADOW_NONE);
668 gtk_clist_set_reorderable(GTK_CLIST(volume_list), true);
669 gtk_signal_connect(GTK_OBJECT(volume_list), "select_row", GTK_SIGNAL_FUNC(cl_selected), NULL);
670 char *str;
671 int32 index = 0;
672 while ((str = const_cast<char *>(PrefsFindString("disk", index++))) != NULL)
673 gtk_clist_append(GTK_CLIST(volume_list), &str);
674 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), volume_list);
675 gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 0);
676 selected_volume = 0;
677
678 static const opt_desc buttons[] = {
679 {STR_ADD_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_add_volume)},
680 {STR_CREATE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_create_volume)},
681 {STR_REMOVE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_remove_volume)},
682 {0, NULL},
683 };
684 make_button_box(box, 0, buttons);
685 make_separator(box);
686
687 w_extfs = make_file_entry(box, STR_EXTFS_CTRL, "extfs", true);
688
689 static const opt_desc options[] = {
690 {STR_BOOT_ANY_LAB, GTK_SIGNAL_FUNC(mn_boot_any)},
691 {STR_BOOT_CDROM_LAB, GTK_SIGNAL_FUNC(mn_boot_cdrom)},
692 {0, NULL}
693 };
694 int bootdriver = PrefsFindInt32("bootdriver"), active = 0;
695 switch (bootdriver) {
696 case 0: active = 0; break;
697 case CDROMRefNum: active = 1; break;
698 }
699 menu = make_option_menu(box, STR_BOOTDRIVER_CTRL, options, active);
700
701 make_checkbox(box, STR_NOCDROM_CTRL, "nocdrom", GTK_SIGNAL_FUNC(tb_nocdrom));
702 }
703
704
705 /*
706 * "JIT Compiler" pane
707 */
708
709 static GtkWidget *w_jit_fpu;
710 static GtkWidget *w_jit_atraps;
711 static GtkWidget *w_jit_cache_size;
712 static GtkWidget *w_jit_lazy_flush;
713 static GtkWidget *w_jit_follow_const_jumps;
714
715 // Are we running a JIT capable CPU?
716 static bool is_jit_capable(void)
717 {
718 #if USE_JIT && (defined __i386__ || defined __x86_64__)
719 return true;
720 #elif defined __APPLE__ && defined __MACH__
721 // XXX run-time detect so that we can use a PPC GUI prefs editor
722 static char cpu[10];
723 if (cpu[0] == 0) {
724 FILE *fp = popen("uname -p", "r");
725 if (fp == NULL)
726 return false;
727 fgets(cpu, sizeof(cpu) - 1, fp);
728 fclose(fp);
729 }
730 if (cpu[0] == 'i' && cpu[2] == '8' && cpu[3] == '6') // XXX assuming i?86
731 return true;
732 #endif
733 return false;
734 }
735
736 // Set sensitivity of widgets
737 static void set_jit_sensitive(void)
738 {
739 const bool jit_enabled = PrefsFindBool("jit");
740 gtk_widget_set_sensitive(w_jit_fpu, jit_enabled);
741 gtk_widget_set_sensitive(w_jit_cache_size, jit_enabled);
742 gtk_widget_set_sensitive(w_jit_lazy_flush, jit_enabled);
743 gtk_widget_set_sensitive(w_jit_follow_const_jumps, jit_enabled);
744 }
745
746 // "Use JIT Compiler" button toggled
747 static void tb_jit(GtkWidget *widget)
748 {
749 PrefsReplaceBool("jit", GTK_TOGGLE_BUTTON(widget)->active);
750 set_jit_sensitive();
751 }
752
753 // "Compile FPU Instructions" button toggled
754 static void tb_jit_fpu(GtkWidget *widget)
755 {
756 PrefsReplaceBool("jitfpu", GTK_TOGGLE_BUTTON(widget)->active);
757 }
758
759 // "Lazy translation cache invalidation" button toggled
760 static void tb_jit_lazy_flush(GtkWidget *widget)
761 {
762 PrefsReplaceBool("jitlazyflush", GTK_TOGGLE_BUTTON(widget)->active);
763 }
764
765 // "Translate through constant jumps (inline blocks)" button toggled
766 static void tb_jit_follow_const_jumps(GtkWidget *widget)
767 {
768 PrefsReplaceBool("jitinline", GTK_TOGGLE_BUTTON(widget)->active);
769 }
770
771 // Read settings from widgets and set preferences
772 static void read_jit_settings(void)
773 {
774 bool jit_enabled = is_jit_capable() && PrefsFindBool("jit");
775 if (jit_enabled) {
776 const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_jit_cache_size)->entry));
777 PrefsReplaceInt32("jitcachesize", atoi(str));
778 }
779 }
780
781 // Create "JIT Compiler" pane
782 static void create_jit_pane(GtkWidget *top)
783 {
784 if (!is_jit_capable())
785 return;
786
787 GtkWidget *box, *table, *label, *menu;
788 char str[32];
789
790 box = make_pane(top, STR_JIT_PANE_TITLE);
791 make_checkbox(box, STR_JIT_CTRL, "jit", GTK_SIGNAL_FUNC(tb_jit));
792
793 w_jit_fpu = make_checkbox(box, STR_JIT_FPU_CTRL, "jitfpu", GTK_SIGNAL_FUNC(tb_jit_fpu));
794
795 // Translation cache size
796 static const combo_desc options[] = {
797 STR_JIT_CACHE_SIZE_2MB_LAB,
798 STR_JIT_CACHE_SIZE_4MB_LAB,
799 STR_JIT_CACHE_SIZE_8MB_LAB,
800 STR_JIT_CACHE_SIZE_16MB_LAB,
801 0
802 };
803 w_jit_cache_size = make_combobox(box, STR_JIT_CACHE_SIZE_CTRL, "jitcachesize", options);
804
805 // Lazy translation cache invalidation
806 w_jit_lazy_flush = make_checkbox(box, STR_JIT_LAZY_CINV_CTRL, "jitlazyflush", GTK_SIGNAL_FUNC(tb_jit_lazy_flush));
807
808 // Follow constant jumps (inline basic blocks)
809 w_jit_follow_const_jumps = make_checkbox(box, STR_JIT_FOLLOW_CONST_JUMPS, "jitinline", GTK_SIGNAL_FUNC(tb_jit_follow_const_jumps));
810
811 set_jit_sensitive();
812 }
813
814 /*
815 * "SCSI" pane
816 */
817
818 static GtkWidget *w_scsi[7];
819
820 // Read settings from widgets and set preferences
821 static void read_scsi_settings(void)
822 {
823 for (int id=0; id<7; id++) {
824 char prefs_name[32];
825 sprintf(prefs_name, "scsi%d", id);
826 const char *str = get_file_entry_path(w_scsi[id]);
827 if (str && strlen(str))
828 PrefsReplaceString(prefs_name, str);
829 else
830 PrefsRemoveItem(prefs_name);
831 }
832 }
833
834 // Create "SCSI" pane
835 static void create_scsi_pane(GtkWidget *top)
836 {
837 GtkWidget *box;
838
839 box = make_pane(top, STR_SCSI_PANE_TITLE);
840
841 for (int id=0; id<7; id++) {
842 char prefs_name[32];
843 sprintf(prefs_name, "scsi%d", id);
844 w_scsi[id] = make_file_entry(box, STR_SCSI_ID_0 + id, prefs_name);
845 }
846 }
847
848
849 /*
850 * "Graphics/Sound" pane
851 */
852
853 // Display types
854 enum {
855 DISPLAY_WINDOW,
856 DISPLAY_SCREEN
857 };
858
859 static GtkWidget *w_frameskip, *w_display_x, *w_display_y;
860 static GtkWidget *l_frameskip, *l_display_x, *l_display_y;
861 static int display_type;
862 static int dis_width, dis_height;
863
864 #ifdef ENABLE_FBDEV_DGA
865 static GtkWidget *w_fbdev_name, *w_fbdevice_file;
866 static GtkWidget *l_fbdev_name, *l_fbdevice_file;
867 static char fbdev_name[256];
868 #endif
869
870 static GtkWidget *w_dspdevice_file, *w_mixerdevice_file;
871
872 // Hide/show graphics widgets
873 static void hide_show_graphics_widgets(void)
874 {
875 switch (display_type) {
876 case DISPLAY_WINDOW:
877 gtk_widget_show(w_frameskip); gtk_widget_show(l_frameskip);
878 #ifdef ENABLE_FBDEV_DGA
879 gtk_widget_show(w_display_x); gtk_widget_show(l_display_x);
880 gtk_widget_show(w_display_y); gtk_widget_show(l_display_y);
881 gtk_widget_hide(w_fbdev_name); gtk_widget_hide(l_fbdev_name);
882 #endif
883 break;
884 case DISPLAY_SCREEN:
885 gtk_widget_hide(w_frameskip); gtk_widget_hide(l_frameskip);
886 #ifdef ENABLE_FBDEV_DGA
887 gtk_widget_hide(w_display_x); gtk_widget_hide(l_display_x);
888 gtk_widget_hide(w_display_y); gtk_widget_hide(l_display_y);
889 gtk_widget_show(w_fbdev_name); gtk_widget_show(l_fbdev_name);
890 #endif
891 break;
892 }
893 }
894
895 // "Window" video type selected
896 static void mn_window(...)
897 {
898 display_type = DISPLAY_WINDOW;
899 hide_show_graphics_widgets();
900 }
901
902 // "Fullscreen" video type selected
903 static void mn_fullscreen(...)
904 {
905 display_type = DISPLAY_SCREEN;
906 hide_show_graphics_widgets();
907 }
908
909 // "5 Hz".."60Hz" selected
910 static void mn_5hz(...) {PrefsReplaceInt32("frameskip", 12);}
911 static void mn_7hz(...) {PrefsReplaceInt32("frameskip", 8);}
912 static void mn_10hz(...) {PrefsReplaceInt32("frameskip", 6);}
913 static void mn_15hz(...) {PrefsReplaceInt32("frameskip", 4);}
914 static void mn_30hz(...) {PrefsReplaceInt32("frameskip", 2);}
915 static void mn_60hz(...) {PrefsReplaceInt32("frameskip", 1);}
916 static void mn_dynamic(...) {PrefsReplaceInt32("frameskip", 0);}
917
918 // Set sensitivity of widgets
919 static void set_graphics_sensitive(void)
920 {
921 const bool sound_enabled = !PrefsFindBool("nosound");
922 gtk_widget_set_sensitive(w_dspdevice_file, sound_enabled);
923 gtk_widget_set_sensitive(w_mixerdevice_file, sound_enabled);
924 }
925
926 // "Disable Sound Output" button toggled
927 static void tb_nosound(GtkWidget *widget)
928 {
929 PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active);
930 set_graphics_sensitive();
931 }
932
933 // Read graphics preferences
934 static void parse_graphics_prefs(void)
935 {
936 display_type = DISPLAY_WINDOW;
937 dis_width = 512;
938 dis_height = 384;
939 #ifdef ENABLE_FBDEV_DGA
940 fbdev_name[0] = 0;
941 #endif
942
943 const char *str = PrefsFindString("screen");
944 if (str) {
945 if (sscanf(str, "win/%d/%d", &dis_width, &dis_height) == 2)
946 display_type = DISPLAY_WINDOW;
947 #ifdef ENABLE_FBDEV_DGA
948 else if (sscanf(str, "dga/%255s", fbdev_name) == 1)
949 #else
950 else if (sscanf(str, "dga/%d/%d", &dis_width, &dis_height) == 2)
951 #endif
952 display_type = DISPLAY_SCREEN;
953 }
954 }
955
956 // Read settings from widgets and set preferences
957 static void read_graphics_settings(void)
958 {
959 const char *str;
960
961 str = gtk_entry_get_text(GTK_ENTRY(w_display_x));
962 dis_width = atoi(str);
963
964 str = gtk_entry_get_text(GTK_ENTRY(w_display_y));
965 dis_height = atoi(str);
966
967 char pref[256];
968 switch (display_type) {
969 case DISPLAY_WINDOW:
970 sprintf(pref, "win/%d/%d", dis_width, dis_height);
971 break;
972 case DISPLAY_SCREEN:
973 #ifdef ENABLE_FBDEV_DGA
974 str = gtk_entry_get_text(GTK_ENTRY(w_fbdev_name));
975 sprintf(pref, "dga/%s", str);
976 #else
977 sprintf(pref, "dga/%d/%d", dis_width, dis_height);
978 #endif
979 break;
980 default:
981 PrefsRemoveItem("screen");
982 return;
983 }
984 PrefsReplaceString("screen", pref);
985
986 #ifdef ENABLE_FBDEV_DGA
987 str = get_file_entry_path(w_fbdevice_file);
988 if (str && strlen(str))
989 PrefsReplaceString("fbdevicefile", str);
990 else
991 PrefsRemoveItem("fbdevicefile");
992 #endif
993 PrefsReplaceString("dsp", get_file_entry_path(w_dspdevice_file));
994 PrefsReplaceString("mixer", get_file_entry_path(w_mixerdevice_file));
995 }
996
997 // Create "Graphics/Sound" pane
998 static void create_graphics_pane(GtkWidget *top)
999 {
1000 GtkWidget *box, *table, *label, *opt, *menu, *combo;
1001 char str[32];
1002
1003 parse_graphics_prefs();
1004
1005 box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE);
1006 table = make_table(box, 2, 5);
1007
1008 label = gtk_label_new(GetString(STR_VIDEO_TYPE_CTRL));
1009 gtk_widget_show(label);
1010 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1011
1012 opt = gtk_option_menu_new();
1013 gtk_widget_show(opt);
1014 menu = gtk_menu_new();
1015 add_menu_item(menu, STR_WINDOW_LAB, GTK_SIGNAL_FUNC(mn_window));
1016 add_menu_item(menu, STR_FULLSCREEN_LAB, GTK_SIGNAL_FUNC(mn_fullscreen));
1017 switch (display_type) {
1018 case DISPLAY_WINDOW:
1019 gtk_menu_set_active(GTK_MENU(menu), 0);
1020 break;
1021 case DISPLAY_SCREEN:
1022 gtk_menu_set_active(GTK_MENU(menu), 1);
1023 break;
1024 }
1025 gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
1026 gtk_table_attach(GTK_TABLE(table), opt, 1, 2, 0, 1, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
1027
1028 l_frameskip = gtk_label_new(GetString(STR_FRAMESKIP_CTRL));
1029 gtk_widget_show(l_frameskip);
1030 gtk_table_attach(GTK_TABLE(table), l_frameskip, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1031
1032 w_frameskip = gtk_option_menu_new();
1033 gtk_widget_show(w_frameskip);
1034 menu = gtk_menu_new();
1035 add_menu_item(menu, STR_REF_5HZ_LAB, GTK_SIGNAL_FUNC(mn_5hz));
1036 add_menu_item(menu, STR_REF_7_5HZ_LAB, GTK_SIGNAL_FUNC(mn_7hz));
1037 add_menu_item(menu, STR_REF_10HZ_LAB, GTK_SIGNAL_FUNC(mn_10hz));
1038 add_menu_item(menu, STR_REF_15HZ_LAB, GTK_SIGNAL_FUNC(mn_15hz));
1039 add_menu_item(menu, STR_REF_30HZ_LAB, GTK_SIGNAL_FUNC(mn_30hz));
1040 add_menu_item(menu, STR_REF_60HZ_LAB, GTK_SIGNAL_FUNC(mn_60hz));
1041 add_menu_item(menu, STR_REF_DYNAMIC_LAB, GTK_SIGNAL_FUNC(mn_dynamic));
1042 int frameskip = PrefsFindInt32("frameskip");
1043 int item = -1;
1044 switch (frameskip) {
1045 case 12: item = 0; break;
1046 case 8: item = 1; break;
1047 case 6: item = 2; break;
1048 case 4: item = 3; break;
1049 case 2: item = 4; break;
1050 case 1: item = 5; break;
1051 case 0: item = 6; break;
1052 }
1053 if (item >= 0)
1054 gtk_menu_set_active(GTK_MENU(menu), item);
1055 gtk_option_menu_set_menu(GTK_OPTION_MENU(w_frameskip), menu);
1056 gtk_table_attach(GTK_TABLE(table), w_frameskip, 1, 2, 1, 2, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
1057
1058 l_display_x = gtk_label_new(GetString(STR_DISPLAY_X_CTRL));
1059 gtk_widget_show(l_display_x);
1060 gtk_table_attach(GTK_TABLE(table), l_display_x, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1061
1062 combo = gtk_combo_new();
1063 gtk_widget_show(combo);
1064 GList *glist1 = NULL;
1065 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_512_LAB));
1066 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_640_LAB));
1067 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_800_LAB));
1068 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_1024_LAB));
1069 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_MAX_LAB));
1070 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist1);
1071 if (dis_width)
1072 sprintf(str, "%d", dis_width);
1073 else
1074 strcpy(str, GetString(STR_SIZE_MAX_LAB));
1075 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1076 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
1077 w_display_x = GTK_COMBO(combo)->entry;
1078
1079 l_display_y = gtk_label_new(GetString(STR_DISPLAY_Y_CTRL));
1080 gtk_widget_show(l_display_y);
1081 gtk_table_attach(GTK_TABLE(table), l_display_y, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1082
1083 combo = gtk_combo_new();
1084 gtk_widget_show(combo);
1085 GList *glist2 = NULL;
1086 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_384_LAB));
1087 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_480_LAB));
1088 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_600_LAB));
1089 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_768_LAB));
1090 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_MAX_LAB));
1091 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist2);
1092 if (dis_height)
1093 sprintf(str, "%d", dis_height);
1094 else
1095 strcpy(str, GetString(STR_SIZE_MAX_LAB));
1096 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1097 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
1098 w_display_y = GTK_COMBO(combo)->entry;
1099
1100 #ifdef ENABLE_FBDEV_DGA
1101 l_fbdev_name = gtk_label_new(GetString(STR_FBDEV_NAME_CTRL));
1102 gtk_widget_show(l_fbdev_name);
1103 gtk_table_attach(GTK_TABLE(table), l_fbdev_name, 0, 1, 4, 5, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1104
1105 w_fbdev_name = gtk_entry_new();
1106 gtk_widget_show(w_fbdev_name);
1107 gtk_entry_set_text(GTK_ENTRY(w_fbdev_name), fbdev_name);
1108 gtk_table_attach(GTK_TABLE(table), w_fbdev_name, 1, 2, 4, 5, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1109
1110 w_fbdevice_file = make_file_entry(box, STR_FBDEVICE_FILE_CTRL, "fbdevicefile");
1111 #endif
1112
1113 make_separator(box);
1114 make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound));
1115 w_dspdevice_file = make_file_entry(box, STR_DSPDEVICE_FILE_CTRL, "dsp");
1116 w_mixerdevice_file = make_file_entry(box, STR_MIXERDEVICE_FILE_CTRL, "mixer");
1117
1118 set_graphics_sensitive();
1119
1120 hide_show_graphics_widgets();
1121 }
1122
1123
1124 /*
1125 * "Input" pane
1126 */
1127
1128 static GtkWidget *w_keycode_file;
1129 static GtkWidget *w_mouse_wheel_lines;
1130
1131 // Set sensitivity of widgets
1132 static void set_input_sensitive(void)
1133 {
1134 const bool use_keycodes = PrefsFindBool("keycodes");
1135 gtk_widget_set_sensitive(w_keycode_file, use_keycodes);
1136 gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_keycode_file), "chooser_button")), use_keycodes);
1137 gtk_widget_set_sensitive(w_mouse_wheel_lines, PrefsFindInt32("mousewheelmode") == 1);
1138 }
1139
1140 // "Use Raw Keycodes" button toggled
1141 static void tb_keycodes(GtkWidget *widget)
1142 {
1143 PrefsReplaceBool("keycodes", GTK_TOGGLE_BUTTON(widget)->active);
1144 set_input_sensitive();
1145 }
1146
1147 // "Mouse Wheel Mode" selected
1148 static void mn_wheel_page(...) {PrefsReplaceInt32("mousewheelmode", 0); set_input_sensitive();}
1149 static void mn_wheel_cursor(...) {PrefsReplaceInt32("mousewheelmode", 1); set_input_sensitive();}
1150
1151 // Read settings from widgets and set preferences
1152 static void read_input_settings(void)
1153 {
1154 const char *str = get_file_entry_path(w_keycode_file);
1155 if (str && strlen(str))
1156 PrefsReplaceString("keycodefile", str);
1157 else
1158 PrefsRemoveItem("keycodefile");
1159
1160 PrefsReplaceInt32("mousewheellines", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_mouse_wheel_lines)));
1161 }
1162
1163 // Create "Input" pane
1164 static void create_input_pane(GtkWidget *top)
1165 {
1166 GtkWidget *box, *hbox, *menu, *label, *button;
1167 GtkObject *adj;
1168
1169 box = make_pane(top, STR_INPUT_PANE_TITLE);
1170
1171 make_checkbox(box, STR_KEYCODES_CTRL, "keycodes", GTK_SIGNAL_FUNC(tb_keycodes));
1172
1173 hbox = gtk_hbox_new(FALSE, 4);
1174 gtk_widget_show(hbox);
1175 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1176
1177 label = gtk_label_new(GetString(STR_KEYCODES_CTRL));
1178 gtk_widget_show(label);
1179 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1180
1181 const char *str = PrefsFindString("keycodefile");
1182 if (str == NULL)
1183 str = "";
1184
1185 w_keycode_file = gtk_entry_new();
1186 gtk_entry_set_text(GTK_ENTRY(w_keycode_file), str);
1187 gtk_widget_show(w_keycode_file);
1188 gtk_box_pack_start(GTK_BOX(hbox), w_keycode_file, TRUE, TRUE, 0);
1189
1190 button = make_browse_button(w_keycode_file);
1191 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1192 g_object_set_data(G_OBJECT(w_keycode_file), "chooser_button", button);
1193
1194 make_separator(box);
1195
1196 static const opt_desc options[] = {
1197 {STR_MOUSEWHEELMODE_PAGE_LAB, GTK_SIGNAL_FUNC(mn_wheel_page)},
1198 {STR_MOUSEWHEELMODE_CURSOR_LAB, GTK_SIGNAL_FUNC(mn_wheel_cursor)},
1199 {0, NULL}
1200 };
1201 int wheelmode = PrefsFindInt32("mousewheelmode"), active = 0;
1202 switch (wheelmode) {
1203 case 0: active = 0; break;
1204 case 1: active = 1; break;
1205 }
1206 menu = make_option_menu(box, STR_MOUSEWHEELMODE_CTRL, options, active);
1207
1208 hbox = gtk_hbox_new(FALSE, 4);
1209 gtk_widget_show(hbox);
1210 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1211
1212 label = gtk_label_new(GetString(STR_MOUSEWHEELLINES_CTRL));
1213 gtk_widget_show(label);
1214 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1215
1216 adj = gtk_adjustment_new(PrefsFindInt32("mousewheellines"), 1, 1000, 1, 5, 0);
1217 w_mouse_wheel_lines = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0);
1218 gtk_widget_show(w_mouse_wheel_lines);
1219 gtk_box_pack_start(GTK_BOX(hbox), w_mouse_wheel_lines, FALSE, FALSE, 0);
1220
1221 set_input_sensitive();
1222 }
1223
1224
1225 /*
1226 * "Serial/Network" pane
1227 */
1228
1229 static GtkWidget *w_seriala, *w_serialb, *w_ether, *w_udp_port;
1230
1231 // Set sensitivity of widgets
1232 static void set_serial_sensitive(void)
1233 {
1234 #if SUPPORTS_UDP_TUNNEL
1235 gtk_widget_set_sensitive(w_ether, !PrefsFindBool("udptunnel"));
1236 gtk_widget_set_sensitive(w_udp_port, PrefsFindBool("udptunnel"));
1237 #endif
1238 }
1239
1240 // "Tunnel AppleTalk over IP" button toggled
1241 static void tb_udptunnel(GtkWidget *widget)
1242 {
1243 PrefsReplaceBool("udptunnel", GTK_TOGGLE_BUTTON(widget)->active);
1244 set_serial_sensitive();
1245 }
1246
1247 // Read settings from widgets and set preferences
1248 static void read_serial_settings(void)
1249 {
1250 const char *str;
1251
1252 str = gtk_entry_get_text(GTK_ENTRY(w_seriala));
1253 PrefsReplaceString("seriala", str);
1254
1255 str = gtk_entry_get_text(GTK_ENTRY(w_serialb));
1256 PrefsReplaceString("serialb", str);
1257
1258 str = gtk_entry_get_text(GTK_ENTRY(w_ether));
1259 if (str && strlen(str))
1260 PrefsReplaceString("ether", str);
1261 else
1262 PrefsRemoveItem("ether");
1263
1264 #if SUPPORTS_UDP_TUNNEL
1265 PrefsReplaceInt32("udpport", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_udp_port)));
1266 #endif
1267 }
1268
1269 // Add names of serial devices
1270 static gint gl_str_cmp(gconstpointer a, gconstpointer b)
1271 {
1272 return strcmp((char *)a, (char *)b);
1273 }
1274
1275 static GList *add_serial_names(void)
1276 {
1277 GList *glist = NULL;
1278
1279 // Search /dev for ttyS* and lp*
1280 DIR *d = opendir("/dev");
1281 if (d) {
1282 struct dirent *de;
1283 while ((de = readdir(d)) != NULL) {
1284 #if defined(__linux__)
1285 if (strncmp(de->d_name, "ttyS", 4) == 0 || strncmp(de->d_name, "lp", 2) == 0) {
1286 #elif defined(__FreeBSD__)
1287 if (strncmp(de->d_name, "cuaa", 4) == 0 || strncmp(de->d_name, "lpt", 3) == 0) {
1288 #elif defined(__NetBSD__)
1289 if (strncmp(de->d_name, "tty0", 4) == 0 || strncmp(de->d_name, "lpt", 3) == 0) {
1290 #elif defined(sgi)
1291 if (strncmp(de->d_name, "ttyf", 4) == 0 || strncmp(de->d_name, "plp", 3) == 0) {
1292 #else
1293 if (false) {
1294 #endif
1295 char *str = new char[64];
1296 sprintf(str, "/dev/%s", de->d_name);
1297 glist = g_list_append(glist, str);
1298 }
1299 }
1300 closedir(d);
1301 }
1302 if (glist)
1303 g_list_sort(glist, gl_str_cmp);
1304 else
1305 glist = g_list_append(glist, (void *)GetString(STR_NONE_LAB));
1306 return glist;
1307 }
1308
1309 // Add names of ethernet interfaces
1310 static GList *add_ether_names(void)
1311 {
1312 GList *glist = NULL;
1313
1314 // Get list of all Ethernet interfaces
1315 int s = socket(PF_INET, SOCK_DGRAM, 0);
1316 if (s >= 0) {
1317 char inbuf[8192];
1318 struct ifconf ifc;
1319 ifc.ifc_len = sizeof(inbuf);
1320 ifc.ifc_buf = inbuf;
1321 if (ioctl(s, SIOCGIFCONF, &ifc) == 0) {
1322 struct ifreq req, *ifr = ifc.ifc_req;
1323 for (int i=0; i<ifc.ifc_len; i+=sizeof(ifreq), ifr++) {
1324 req = *ifr;
1325 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(sgi)
1326 if (ioctl(s, SIOCGIFADDR, &req) == 0 && (req.ifr_addr.sa_family == ARPHRD_ETHER || req.ifr_addr.sa_family == ARPHRD_ETHER+1)) {
1327 #elif defined(__linux__)
1328 if (ioctl(s, SIOCGIFHWADDR, &req) == 0 && req.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
1329 #else
1330 if (false) {
1331 #endif
1332 char *str = new char[64];
1333 strncpy(str, ifr->ifr_name, 63);
1334 glist = g_list_append(glist, str);
1335 }
1336 }
1337 }
1338 close(s);
1339 }
1340 #ifdef HAVE_SLIRP
1341 static char s_slirp[] = "slirp";
1342 glist = g_list_append(glist, s_slirp);
1343 #endif
1344 if (glist)
1345 g_list_sort(glist, gl_str_cmp);
1346 else
1347 glist = g_list_append(glist, (void *)GetString(STR_NONE_LAB));
1348 return glist;
1349 }
1350
1351 // Create "Serial/Network" pane
1352 static void create_serial_pane(GtkWidget *top)
1353 {
1354 GtkWidget *box, *hbox, *table, *label, *combo, *sep;
1355 GtkObject *adj;
1356
1357 box = make_pane(top, STR_SERIAL_NETWORK_PANE_TITLE);
1358 table = make_table(box, 2, 4);
1359
1360 label = gtk_label_new(GetString(STR_SERIALA_CTRL));
1361 gtk_widget_show(label);
1362 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1363
1364 GList *glist = add_serial_names();
1365 combo = gtk_combo_new();
1366 gtk_widget_show(combo);
1367 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1368 const char *str = PrefsFindString("seriala");
1369 if (str == NULL)
1370 str = "";
1371 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1372 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1373 w_seriala = GTK_COMBO(combo)->entry;
1374
1375 label = gtk_label_new(GetString(STR_SERIALB_CTRL));
1376 gtk_widget_show(label);
1377 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1378
1379 combo = gtk_combo_new();
1380 gtk_widget_show(combo);
1381 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1382 str = PrefsFindString("serialb");
1383 if (str == NULL)
1384 str = "";
1385 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1386 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 1, 2, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1387 w_serialb = GTK_COMBO(combo)->entry;
1388
1389 sep = gtk_hseparator_new();
1390 gtk_widget_show(sep);
1391 gtk_table_attach(GTK_TABLE(table), sep, 0, 2, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1392
1393 label = gtk_label_new(GetString(STR_ETHERNET_IF_CTRL));
1394 gtk_widget_show(label);
1395 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1396
1397 glist = add_ether_names();
1398 combo = gtk_combo_new();
1399 gtk_widget_show(combo);
1400 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1401 str = PrefsFindString("ether");
1402 if (str == NULL)
1403 str = "";
1404 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1405 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1406 w_ether = GTK_COMBO(combo)->entry;
1407
1408 #if SUPPORTS_UDP_TUNNEL
1409 make_checkbox(box, STR_UDPTUNNEL_CTRL, "udptunnel", GTK_SIGNAL_FUNC(tb_udptunnel));
1410
1411 hbox = gtk_hbox_new(FALSE, 4);
1412 gtk_widget_show(hbox);
1413 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1414
1415 label = gtk_label_new(GetString(STR_UDPPORT_CTRL));
1416 gtk_widget_show(label);
1417 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1418
1419 adj = gtk_adjustment_new(PrefsFindInt32("udpport"), 1, 65535, 1, 5, 0);
1420 w_udp_port = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0);
1421 gtk_widget_show(w_udp_port);
1422 gtk_box_pack_start(GTK_BOX(hbox), w_udp_port, FALSE, FALSE, 0);
1423 #endif
1424
1425 set_serial_sensitive();
1426 }
1427
1428
1429 /*
1430 * "Memory/Misc" pane
1431 */
1432
1433 static GtkWidget *w_ramsize;
1434 static GtkWidget *w_rom_file;
1435
1436 // Don't use CPU when idle?
1437 static void tb_idlewait(GtkWidget *widget)
1438 {
1439 PrefsReplaceBool("idlewait", GTK_TOGGLE_BUTTON(widget)->active);
1440 }
1441
1442 // "Ignore SEGV" button toggled
1443 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1444 static void tb_ignoresegv(GtkWidget *widget)
1445 {
1446 PrefsReplaceBool("ignoresegv", GTK_TOGGLE_BUTTON(widget)->active);
1447 }
1448 #endif
1449
1450 // Model ID selected
1451 static void mn_modelid_5(...) {PrefsReplaceInt32("modelid", 5);}
1452 static void mn_modelid_14(...) {PrefsReplaceInt32("modelid", 14);}
1453
1454 // CPU/FPU type
1455 static void mn_cpu_68020(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", false);}
1456 static void mn_cpu_68020_fpu(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", true);}
1457 static void mn_cpu_68030(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", false);}
1458 static void mn_cpu_68030_fpu(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", true);}
1459 static void mn_cpu_68040(...) {PrefsReplaceInt32("cpu", 4); PrefsReplaceBool("fpu", true);}
1460
1461 // Read settings from widgets and set preferences
1462 static void read_memory_settings(void)
1463 {
1464 const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_ramsize)->entry));
1465 PrefsReplaceInt32("ramsize", atoi(str) << 20);
1466
1467 str = get_file_entry_path(w_rom_file);
1468 if (str && strlen(str))
1469 PrefsReplaceString("rom", str);
1470 else
1471 PrefsRemoveItem("rom");
1472
1473 }
1474
1475 // Create "Memory/Misc" pane
1476 static void create_memory_pane(GtkWidget *top)
1477 {
1478 GtkWidget *box, *hbox, *table, *label, *menu;
1479
1480 box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE);
1481 table = make_table(box, 2, 5);
1482
1483 static const combo_desc options[] = {
1484 STR_RAMSIZE_2MB_LAB,
1485 STR_RAMSIZE_4MB_LAB,
1486 STR_RAMSIZE_8MB_LAB,
1487 STR_RAMSIZE_16MB_LAB,
1488 STR_RAMSIZE_32MB_LAB,
1489 STR_RAMSIZE_64MB_LAB,
1490 STR_RAMSIZE_128MB_LAB,
1491 STR_RAMSIZE_256MB_LAB,
1492 STR_RAMSIZE_512MB_LAB,
1493 STR_RAMSIZE_1024MB_LAB,
1494 0
1495 };
1496 char default_ramsize[10];
1497 sprintf(default_ramsize, "%d", PrefsFindInt32("ramsize") >> 20);
1498 w_ramsize = table_make_combobox(table, 0, STR_RAMSIZE_CTRL, default_ramsize, options);
1499
1500 static const opt_desc model_options[] = {
1501 {STR_MODELID_5_LAB, GTK_SIGNAL_FUNC(mn_modelid_5)},
1502 {STR_MODELID_14_LAB, GTK_SIGNAL_FUNC(mn_modelid_14)},
1503 {0, NULL}
1504 };
1505 int modelid = PrefsFindInt32("modelid"), active = 0;
1506 switch (modelid) {
1507 case 5: active = 0; break;
1508 case 14: active = 1; break;
1509 }
1510 table_make_option_menu(table, 2, STR_MODELID_CTRL, model_options, active);
1511
1512 #if EMULATED_68K
1513 static const opt_desc cpu_options[] = {
1514 {STR_CPU_68020_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020)},
1515 {STR_CPU_68020_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020_fpu)},
1516 {STR_CPU_68030_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030)},
1517 {STR_CPU_68030_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030_fpu)},
1518 {STR_CPU_68040_LAB, GTK_SIGNAL_FUNC(mn_cpu_68040)},
1519 {0, NULL}
1520 };
1521 int cpu = PrefsFindInt32("cpu");
1522 bool fpu = PrefsFindBool("fpu");
1523 active = 0;
1524 switch (cpu) {
1525 case 2: active = fpu ? 1 : 0; break;
1526 case 3: active = fpu ? 3 : 2; break;
1527 case 4: active = 4;
1528 }
1529 table_make_option_menu(table, 3, STR_CPU_CTRL, cpu_options, active);
1530 #endif
1531
1532 w_rom_file = table_make_file_entry(table, 4, STR_ROM_FILE_CTRL, "rom");
1533
1534 make_checkbox(box, STR_IDLEWAIT_CTRL, "idlewait", GTK_SIGNAL_FUNC(tb_idlewait));
1535 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1536 make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv));
1537 #endif
1538 }
1539
1540
1541 /*
1542 * Read settings from widgets and set preferences
1543 */
1544
1545 static void read_settings(void)
1546 {
1547 read_volumes_settings();
1548 read_scsi_settings();
1549 read_graphics_settings();
1550 read_input_settings();
1551 read_serial_settings();
1552 read_memory_settings();
1553 read_jit_settings();
1554 }
1555
1556
1557 #ifdef STANDALONE_GUI
1558 #include <errno.h>
1559 #include <sys/wait.h>
1560 #include "rpc.h"
1561
1562 /*
1563 * Fake unused data and functions
1564 */
1565
1566 uint8 XPRAM[XPRAM_SIZE];
1567 void MountVolume(void *fh) { }
1568 void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) { }
1569
1570 #if defined __APPLE__ && defined __MACH__
1571 void DarwinSysInit(void) { }
1572 void DarwinSysExit(void) { }
1573 void DarwinAddFloppyPrefs(void) { }
1574 void DarwinAddSerialPrefs(void) { }
1575 bool DarwinCDReadTOC(char *, uint8 *) { }
1576 #endif
1577
1578
1579 /*
1580 * Display alert
1581 */
1582
1583 static void dl_destroyed(void)
1584 {
1585 gtk_main_quit();
1586 }
1587
1588 static void display_alert(int title_id, int prefix_id, int button_id, const char *text)
1589 {
1590 char str[256];
1591 sprintf(str, GetString(prefix_id), text);
1592
1593 GtkWidget *dialog = gtk_dialog_new();
1594 gtk_window_set_title(GTK_WINDOW(dialog), GetString(title_id));
1595 gtk_container_border_width(GTK_CONTAINER(dialog), 5);
1596 gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
1597 gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(dl_destroyed), NULL);
1598
1599 GtkWidget *label = gtk_label_new(str);
1600 gtk_widget_show(label);
1601 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
1602
1603 GtkWidget *button = gtk_button_new_with_label(GetString(button_id));
1604 gtk_widget_show(button);
1605 gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
1606 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
1607 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1608 gtk_widget_grab_default(button);
1609 gtk_widget_show(dialog);
1610
1611 gtk_main();
1612 }
1613
1614
1615 /*
1616 * Display error alert
1617 */
1618
1619 void ErrorAlert(const char *text)
1620 {
1621 display_alert(STR_ERROR_ALERT_TITLE, STR_GUI_ERROR_PREFIX, STR_QUIT_BUTTON, text);
1622 }
1623
1624
1625 /*
1626 * Display warning alert
1627 */
1628
1629 void WarningAlert(const char *text)
1630 {
1631 display_alert(STR_WARNING_ALERT_TITLE, STR_GUI_WARNING_PREFIX, STR_OK_BUTTON, text);
1632 }
1633
1634
1635 /*
1636 * RPC handlers
1637 */
1638
1639 static GMainLoop *g_gui_loop;
1640
1641 static int handle_ErrorAlert(rpc_connection_t *connection)
1642 {
1643 D(bug("handle_ErrorAlert\n"));
1644
1645 int error;
1646 char *str;
1647 if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0)
1648 return error;
1649
1650 ErrorAlert(str);
1651 free(str);
1652 return RPC_ERROR_NO_ERROR;
1653 }
1654
1655 static int handle_WarningAlert(rpc_connection_t *connection)
1656 {
1657 D(bug("handle_WarningAlert\n"));
1658
1659 int error;
1660 char *str;
1661 if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0)
1662 return error;
1663
1664 WarningAlert(str);
1665 free(str);
1666 return RPC_ERROR_NO_ERROR;
1667 }
1668
1669 static int handle_Exit(rpc_connection_t *connection)
1670 {
1671 D(bug("handle_Exit\n"));
1672
1673 g_main_quit(g_gui_loop);
1674 return RPC_ERROR_NO_ERROR;
1675 }
1676
1677
1678 /*
1679 * SIGCHLD handler
1680 */
1681
1682 static char g_app_path[PATH_MAX];
1683 static rpc_connection_t *g_gui_connection = NULL;
1684
1685 static void sigchld_handler(int sig, siginfo_t *sip, void *)
1686 {
1687 D(bug("Child %d exitted with status = %x\n", sip->si_pid, sip->si_status));
1688
1689 // XXX perform a new wait because sip->si_status is sometimes not
1690 // the exit _value_ on MacOS X but rather the usual status field
1691 // from waitpid() -- we could arrange this code in some other way...
1692 int status;
1693 if (waitpid(sip->si_pid, &status, 0) < 0)
1694 status = sip->si_status;
1695 if (WIFEXITED(status))
1696 status = WEXITSTATUS(status);
1697 if (status & 0x80)
1698 status |= -1 ^0xff;
1699
1700 if (status < 0) { // negative -> execlp/-errno
1701 char str[256];
1702 sprintf(str, GetString(STR_NO_B2_EXE_FOUND), g_app_path, strerror(-status));
1703 ErrorAlert(str);
1704 status = 1;
1705 }
1706
1707 if (status != 0) {
1708 if (g_gui_connection)
1709 rpc_exit(g_gui_connection);
1710 exit(status);
1711 }
1712 }
1713
1714
1715 /*
1716 * Start standalone GUI
1717 */
1718
1719 int main(int argc, char *argv[])
1720 {
1721 #ifdef HAVE_GNOMEUI
1722 // Init GNOME/GTK
1723 char version[16];
1724 sprintf(version, "%d.%d", VERSION_MAJOR, VERSION_MINOR);
1725 gnome_init("Basilisk II", version, argc, argv);
1726 #else
1727 // Init GTK
1728 gtk_set_locale();
1729 gtk_init(&argc, &argv);
1730 #endif
1731
1732 // Read preferences
1733 PrefsInit(NULL, argc, argv);
1734
1735 // Show preferences editor
1736 bool start = PrefsEditor();
1737
1738 // Exit preferences
1739 PrefsExit();
1740
1741 // Transfer control to the executable
1742 if (start) {
1743 char gui_connection_path[64];
1744 sprintf(gui_connection_path, "/org/BasiliskII/GUI/%d", getpid());
1745
1746 // Catch exits from the child process
1747 struct sigaction sigchld_sa, old_sigchld_sa;
1748 sigemptyset(&sigchld_sa.sa_mask);
1749 sigchld_sa.sa_sigaction = sigchld_handler;
1750 sigchld_sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
1751 if (sigaction(SIGCHLD, &sigchld_sa, &old_sigchld_sa) < 0) {
1752 char str[256];
1753 sprintf(str, GetString(STR_SIG_INSTALL_ERR), SIGCHLD, strerror(errno));
1754 ErrorAlert(str);
1755 return 1;
1756 }
1757
1758 // Search and run the BasiliskII executable
1759 char *p;
1760 strcpy(g_app_path, argv[0]);
1761 if ((p = strstr(g_app_path, "BasiliskIIGUI.app/Contents/MacOS")) != NULL) {
1762 strcpy(p, "BasiliskII.app/Contents/MacOS/BasiliskII");
1763 if (access(g_app_path, X_OK) < 0) {
1764 char str[256];
1765 sprintf(str, GetString(STR_NO_B2_EXE_FOUND), g_app_path, strerror(errno));
1766 WarningAlert(str);
1767 strcpy(g_app_path, "/Applications/BasiliskII.app/Contents/MacOS/BasiliskII");
1768 }
1769 } else {
1770 p = strrchr(g_app_path, '/');
1771 p = p ? p + 1 : g_app_path;
1772 strcpy(p, "BasiliskII");
1773 }
1774
1775 int pid = fork();
1776 if (pid == 0) {
1777 D(bug("Trying to execute %s\n", g_app_path));
1778 execlp(g_app_path, g_app_path, "--gui-connection", gui_connection_path, (char *)NULL);
1779 #ifdef _POSIX_PRIORITY_SCHEDULING
1780 // XXX get a chance to run the parent process so that to not confuse/upset GTK...
1781 sched_yield();
1782 #endif
1783 _exit(-errno);
1784 }
1785
1786 // Establish a connection to Basilisk II
1787 if ((g_gui_connection = rpc_init_server(gui_connection_path)) == NULL) {
1788 printf("ERROR: failed to initialize GUI-side RPC server connection\n");
1789 return 1;
1790 }
1791 static const rpc_method_descriptor_t vtable[] = {
1792 { RPC_METHOD_ERROR_ALERT, handle_ErrorAlert },
1793 { RPC_METHOD_WARNING_ALERT, handle_WarningAlert },
1794 { RPC_METHOD_EXIT, handle_Exit }
1795 };
1796 if (rpc_method_add_callbacks(g_gui_connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) {
1797 printf("ERROR: failed to setup GUI method callbacks\n");
1798 return 1;
1799 }
1800 int socket;
1801 if ((socket = rpc_listen_socket(g_gui_connection)) < 0) {
1802 printf("ERROR: failed to initialize RPC server thread\n");
1803 return 1;
1804 }
1805
1806 g_gui_loop = g_main_new(TRUE);
1807 while (g_main_is_running(g_gui_loop)) {
1808
1809 // Process a few events pending
1810 const int N_EVENTS_DISPATCH = 10;
1811 for (int i = 0; i < N_EVENTS_DISPATCH; i++) {
1812 if (!g_main_iteration(FALSE))
1813 break;
1814 }
1815
1816 // Check for RPC events (100 ms timeout)
1817 int ret = rpc_wait_dispatch(g_gui_connection, 100000);
1818 if (ret == 0)
1819 continue;
1820 if (ret < 0)
1821 break;
1822 rpc_dispatch(g_gui_connection);
1823 }
1824
1825 rpc_exit(g_gui_connection);
1826 return 0;
1827 }
1828
1829 return 0;
1830 }
1831 #endif