ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/prefs_editor_gtk.cpp
Revision: 1.34
Committed: 2006-04-17T14:25:57Z (18 years, 3 months ago) by gbeauche
Branch: MAIN
Changes since 1.33: +10 -9 lines
Log Message:
Fixes for GTK+1.2 GUI on MacOS X

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 <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 = true; // 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-2005 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-2005 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 // Set sensitivity of widgets
716 static void set_jit_sensitive(void)
717 {
718 const bool jit_enabled = PrefsFindBool("jit");
719 gtk_widget_set_sensitive(w_jit_fpu, jit_enabled);
720 gtk_widget_set_sensitive(w_jit_cache_size, jit_enabled);
721 gtk_widget_set_sensitive(w_jit_lazy_flush, jit_enabled);
722 gtk_widget_set_sensitive(w_jit_follow_const_jumps, jit_enabled);
723 }
724
725 // "Use JIT Compiler" button toggled
726 static void tb_jit(GtkWidget *widget)
727 {
728 PrefsReplaceBool("jit", GTK_TOGGLE_BUTTON(widget)->active);
729 set_jit_sensitive();
730 }
731
732 // "Compile FPU Instructions" button toggled
733 static void tb_jit_fpu(GtkWidget *widget)
734 {
735 PrefsReplaceBool("jitfpu", GTK_TOGGLE_BUTTON(widget)->active);
736 }
737
738 // "Lazy translation cache invalidation" button toggled
739 static void tb_jit_lazy_flush(GtkWidget *widget)
740 {
741 PrefsReplaceBool("jitlazyflush", GTK_TOGGLE_BUTTON(widget)->active);
742 }
743
744 // "Translate through constant jumps (inline blocks)" button toggled
745 static void tb_jit_follow_const_jumps(GtkWidget *widget)
746 {
747 PrefsReplaceBool("jitinline", GTK_TOGGLE_BUTTON(widget)->active);
748 }
749
750 // Read settings from widgets and set preferences
751 static void read_jit_settings(void)
752 {
753 #if USE_JIT
754 bool jit_enabled = PrefsFindBool("jit");
755 if (jit_enabled) {
756 const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_jit_cache_size)->entry));
757 PrefsReplaceInt32("jitcachesize", atoi(str));
758 }
759 #endif
760 }
761
762 // Create "JIT Compiler" pane
763 static void create_jit_pane(GtkWidget *top)
764 {
765 #if USE_JIT
766 GtkWidget *box, *table, *label, *menu;
767 char str[32];
768
769 box = make_pane(top, STR_JIT_PANE_TITLE);
770 make_checkbox(box, STR_JIT_CTRL, "jit", GTK_SIGNAL_FUNC(tb_jit));
771
772 w_jit_fpu = make_checkbox(box, STR_JIT_FPU_CTRL, "jitfpu", GTK_SIGNAL_FUNC(tb_jit_fpu));
773
774 // Translation cache size
775 static const combo_desc options[] = {
776 STR_JIT_CACHE_SIZE_2MB_LAB,
777 STR_JIT_CACHE_SIZE_4MB_LAB,
778 STR_JIT_CACHE_SIZE_8MB_LAB,
779 STR_JIT_CACHE_SIZE_16MB_LAB,
780 0
781 };
782 w_jit_cache_size = make_combobox(box, STR_JIT_CACHE_SIZE_CTRL, "jitcachesize", options);
783
784 // Lazy translation cache invalidation
785 w_jit_lazy_flush = make_checkbox(box, STR_JIT_LAZY_CINV_CTRL, "jitlazyflush", GTK_SIGNAL_FUNC(tb_jit_lazy_flush));
786
787 // Follow constant jumps (inline basic blocks)
788 w_jit_follow_const_jumps = make_checkbox(box, STR_JIT_FOLLOW_CONST_JUMPS, "jitinline", GTK_SIGNAL_FUNC(tb_jit_follow_const_jumps));
789
790 set_jit_sensitive();
791 #endif
792 }
793
794 /*
795 * "SCSI" pane
796 */
797
798 static GtkWidget *w_scsi[7];
799
800 // Read settings from widgets and set preferences
801 static void read_scsi_settings(void)
802 {
803 for (int id=0; id<7; id++) {
804 char prefs_name[32];
805 sprintf(prefs_name, "scsi%d", id);
806 const char *str = get_file_entry_path(w_scsi[id]);
807 if (str && strlen(str))
808 PrefsReplaceString(prefs_name, str);
809 else
810 PrefsRemoveItem(prefs_name);
811 }
812 }
813
814 // Create "SCSI" pane
815 static void create_scsi_pane(GtkWidget *top)
816 {
817 GtkWidget *box;
818
819 box = make_pane(top, STR_SCSI_PANE_TITLE);
820
821 for (int id=0; id<7; id++) {
822 char prefs_name[32];
823 sprintf(prefs_name, "scsi%d", id);
824 w_scsi[id] = make_file_entry(box, STR_SCSI_ID_0 + id, prefs_name);
825 }
826 }
827
828
829 /*
830 * "Graphics/Sound" pane
831 */
832
833 // Display types
834 enum {
835 DISPLAY_WINDOW,
836 DISPLAY_SCREEN
837 };
838
839 static GtkWidget *w_frameskip, *w_display_x, *w_display_y;
840 static GtkWidget *l_frameskip, *l_display_x, *l_display_y;
841 static int display_type;
842 static int dis_width, dis_height;
843
844 #ifdef ENABLE_FBDEV_DGA
845 static GtkWidget *w_fbdev_name, *w_fbdevice_file;
846 static GtkWidget *l_fbdev_name, *l_fbdevice_file;
847 static char fbdev_name[256];
848 #endif
849
850 static GtkWidget *w_dspdevice_file, *w_mixerdevice_file;
851
852 // Hide/show graphics widgets
853 static void hide_show_graphics_widgets(void)
854 {
855 switch (display_type) {
856 case DISPLAY_WINDOW:
857 gtk_widget_show(w_frameskip); gtk_widget_show(l_frameskip);
858 #ifdef ENABLE_FBDEV_DGA
859 gtk_widget_show(w_display_x); gtk_widget_show(l_display_x);
860 gtk_widget_show(w_display_y); gtk_widget_show(l_display_y);
861 gtk_widget_hide(w_fbdev_name); gtk_widget_hide(l_fbdev_name);
862 #endif
863 break;
864 case DISPLAY_SCREEN:
865 gtk_widget_hide(w_frameskip); gtk_widget_hide(l_frameskip);
866 #ifdef ENABLE_FBDEV_DGA
867 gtk_widget_hide(w_display_x); gtk_widget_hide(l_display_x);
868 gtk_widget_hide(w_display_y); gtk_widget_hide(l_display_y);
869 gtk_widget_show(w_fbdev_name); gtk_widget_show(l_fbdev_name);
870 #endif
871 break;
872 }
873 }
874
875 // "Window" video type selected
876 static void mn_window(...)
877 {
878 display_type = DISPLAY_WINDOW;
879 hide_show_graphics_widgets();
880 }
881
882 // "Fullscreen" video type selected
883 static void mn_fullscreen(...)
884 {
885 display_type = DISPLAY_SCREEN;
886 hide_show_graphics_widgets();
887 }
888
889 // "5 Hz".."60Hz" selected
890 static void mn_5hz(...) {PrefsReplaceInt32("frameskip", 12);}
891 static void mn_7hz(...) {PrefsReplaceInt32("frameskip", 8);}
892 static void mn_10hz(...) {PrefsReplaceInt32("frameskip", 6);}
893 static void mn_15hz(...) {PrefsReplaceInt32("frameskip", 4);}
894 static void mn_30hz(...) {PrefsReplaceInt32("frameskip", 2);}
895 static void mn_60hz(...) {PrefsReplaceInt32("frameskip", 1);}
896 static void mn_dynamic(...) {PrefsReplaceInt32("frameskip", 0);}
897
898 // Set sensitivity of widgets
899 static void set_graphics_sensitive(void)
900 {
901 const bool sound_enabled = !PrefsFindBool("nosound");
902 gtk_widget_set_sensitive(w_dspdevice_file, sound_enabled);
903 gtk_widget_set_sensitive(w_mixerdevice_file, sound_enabled);
904 }
905
906 // "Disable Sound Output" button toggled
907 static void tb_nosound(GtkWidget *widget)
908 {
909 PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active);
910 set_graphics_sensitive();
911 }
912
913 // Read graphics preferences
914 static void parse_graphics_prefs(void)
915 {
916 display_type = DISPLAY_WINDOW;
917 dis_width = 512;
918 dis_height = 384;
919 #ifdef ENABLE_FBDEV_DGA
920 fbdev_name[0] = 0;
921 #endif
922
923 const char *str = PrefsFindString("screen");
924 if (str) {
925 if (sscanf(str, "win/%d/%d", &dis_width, &dis_height) == 2)
926 display_type = DISPLAY_WINDOW;
927 #ifdef ENABLE_FBDEV_DGA
928 else if (sscanf(str, "dga/%255s", fbdev_name) == 1)
929 #else
930 else if (sscanf(str, "dga/%d/%d", &dis_width, &dis_height) == 2)
931 #endif
932 display_type = DISPLAY_SCREEN;
933 }
934 }
935
936 // Read settings from widgets and set preferences
937 static void read_graphics_settings(void)
938 {
939 const char *str;
940
941 str = gtk_entry_get_text(GTK_ENTRY(w_display_x));
942 dis_width = atoi(str);
943
944 str = gtk_entry_get_text(GTK_ENTRY(w_display_y));
945 dis_height = atoi(str);
946
947 char pref[256];
948 switch (display_type) {
949 case DISPLAY_WINDOW:
950 sprintf(pref, "win/%d/%d", dis_width, dis_height);
951 break;
952 case DISPLAY_SCREEN:
953 #ifdef ENABLE_FBDEV_DGA
954 str = gtk_entry_get_text(GTK_ENTRY(w_fbdev_name));
955 sprintf(pref, "dga/%s", str);
956 #else
957 sprintf(pref, "dga/%d/%d", dis_width, dis_height);
958 #endif
959 break;
960 default:
961 PrefsRemoveItem("screen");
962 return;
963 }
964 PrefsReplaceString("screen", pref);
965
966 #ifdef ENABLE_FBDEV_DGA
967 str = get_file_entry_path(w_fbdevice_file);
968 if (str && strlen(str))
969 PrefsReplaceString("fbdevicefile", str);
970 else
971 PrefsRemoveItem("fbdevicefile");
972 #endif
973 PrefsReplaceString("dsp", get_file_entry_path(w_dspdevice_file));
974 PrefsReplaceString("mixer", get_file_entry_path(w_mixerdevice_file));
975 }
976
977 // Create "Graphics/Sound" pane
978 static void create_graphics_pane(GtkWidget *top)
979 {
980 GtkWidget *box, *table, *label, *opt, *menu, *combo;
981 char str[32];
982
983 parse_graphics_prefs();
984
985 box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE);
986 table = make_table(box, 2, 5);
987
988 label = gtk_label_new(GetString(STR_VIDEO_TYPE_CTRL));
989 gtk_widget_show(label);
990 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
991
992 opt = gtk_option_menu_new();
993 gtk_widget_show(opt);
994 menu = gtk_menu_new();
995 add_menu_item(menu, STR_WINDOW_LAB, GTK_SIGNAL_FUNC(mn_window));
996 add_menu_item(menu, STR_FULLSCREEN_LAB, GTK_SIGNAL_FUNC(mn_fullscreen));
997 switch (display_type) {
998 case DISPLAY_WINDOW:
999 gtk_menu_set_active(GTK_MENU(menu), 0);
1000 break;
1001 case DISPLAY_SCREEN:
1002 gtk_menu_set_active(GTK_MENU(menu), 1);
1003 break;
1004 }
1005 gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
1006 gtk_table_attach(GTK_TABLE(table), opt, 1, 2, 0, 1, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
1007
1008 l_frameskip = gtk_label_new(GetString(STR_FRAMESKIP_CTRL));
1009 gtk_widget_show(l_frameskip);
1010 gtk_table_attach(GTK_TABLE(table), l_frameskip, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1011
1012 w_frameskip = gtk_option_menu_new();
1013 gtk_widget_show(w_frameskip);
1014 menu = gtk_menu_new();
1015 add_menu_item(menu, STR_REF_5HZ_LAB, GTK_SIGNAL_FUNC(mn_5hz));
1016 add_menu_item(menu, STR_REF_7_5HZ_LAB, GTK_SIGNAL_FUNC(mn_7hz));
1017 add_menu_item(menu, STR_REF_10HZ_LAB, GTK_SIGNAL_FUNC(mn_10hz));
1018 add_menu_item(menu, STR_REF_15HZ_LAB, GTK_SIGNAL_FUNC(mn_15hz));
1019 add_menu_item(menu, STR_REF_30HZ_LAB, GTK_SIGNAL_FUNC(mn_30hz));
1020 add_menu_item(menu, STR_REF_60HZ_LAB, GTK_SIGNAL_FUNC(mn_60hz));
1021 add_menu_item(menu, STR_REF_DYNAMIC_LAB, GTK_SIGNAL_FUNC(mn_dynamic));
1022 int frameskip = PrefsFindInt32("frameskip");
1023 int item = -1;
1024 switch (frameskip) {
1025 case 12: item = 0; break;
1026 case 8: item = 1; break;
1027 case 6: item = 2; break;
1028 case 4: item = 3; break;
1029 case 2: item = 4; break;
1030 case 1: item = 5; break;
1031 case 0: item = 6; break;
1032 }
1033 if (item >= 0)
1034 gtk_menu_set_active(GTK_MENU(menu), item);
1035 gtk_option_menu_set_menu(GTK_OPTION_MENU(w_frameskip), menu);
1036 gtk_table_attach(GTK_TABLE(table), w_frameskip, 1, 2, 1, 2, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
1037
1038 l_display_x = gtk_label_new(GetString(STR_DISPLAY_X_CTRL));
1039 gtk_widget_show(l_display_x);
1040 gtk_table_attach(GTK_TABLE(table), l_display_x, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1041
1042 combo = gtk_combo_new();
1043 gtk_widget_show(combo);
1044 GList *glist1 = NULL;
1045 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_512_LAB));
1046 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_640_LAB));
1047 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_800_LAB));
1048 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_1024_LAB));
1049 glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_MAX_LAB));
1050 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist1);
1051 if (dis_width)
1052 sprintf(str, "%d", dis_width);
1053 else
1054 strcpy(str, GetString(STR_SIZE_MAX_LAB));
1055 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1056 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
1057 w_display_x = GTK_COMBO(combo)->entry;
1058
1059 l_display_y = gtk_label_new(GetString(STR_DISPLAY_Y_CTRL));
1060 gtk_widget_show(l_display_y);
1061 gtk_table_attach(GTK_TABLE(table), l_display_y, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1062
1063 combo = gtk_combo_new();
1064 gtk_widget_show(combo);
1065 GList *glist2 = NULL;
1066 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_384_LAB));
1067 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_480_LAB));
1068 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_600_LAB));
1069 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_768_LAB));
1070 glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_MAX_LAB));
1071 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist2);
1072 if (dis_height)
1073 sprintf(str, "%d", dis_height);
1074 else
1075 strcpy(str, GetString(STR_SIZE_MAX_LAB));
1076 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1077 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
1078 w_display_y = GTK_COMBO(combo)->entry;
1079
1080 #ifdef ENABLE_FBDEV_DGA
1081 l_fbdev_name = gtk_label_new(GetString(STR_FBDEV_NAME_CTRL));
1082 gtk_widget_show(l_fbdev_name);
1083 gtk_table_attach(GTK_TABLE(table), l_fbdev_name, 0, 1, 4, 5, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1084
1085 w_fbdev_name = gtk_entry_new();
1086 gtk_widget_show(w_fbdev_name);
1087 gtk_entry_set_text(GTK_ENTRY(w_fbdev_name), fbdev_name);
1088 gtk_table_attach(GTK_TABLE(table), w_fbdev_name, 1, 2, 4, 5, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1089
1090 w_fbdevice_file = make_file_entry(box, STR_FBDEVICE_FILE_CTRL, "fbdevicefile");
1091 #endif
1092
1093 make_separator(box);
1094 make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound));
1095 w_dspdevice_file = make_file_entry(box, STR_DSPDEVICE_FILE_CTRL, "dsp");
1096 w_mixerdevice_file = make_file_entry(box, STR_MIXERDEVICE_FILE_CTRL, "mixer");
1097
1098 set_graphics_sensitive();
1099
1100 hide_show_graphics_widgets();
1101 }
1102
1103
1104 /*
1105 * "Input" pane
1106 */
1107
1108 static GtkWidget *w_keycode_file;
1109 static GtkWidget *w_mouse_wheel_lines;
1110
1111 // Set sensitivity of widgets
1112 static void set_input_sensitive(void)
1113 {
1114 const bool use_keycodes = PrefsFindBool("keycodes");
1115 gtk_widget_set_sensitive(w_keycode_file, use_keycodes);
1116 gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_keycode_file), "chooser_button")), use_keycodes);
1117 gtk_widget_set_sensitive(w_mouse_wheel_lines, PrefsFindInt32("mousewheelmode") == 1);
1118 }
1119
1120 // "Use Raw Keycodes" button toggled
1121 static void tb_keycodes(GtkWidget *widget)
1122 {
1123 PrefsReplaceBool("keycodes", GTK_TOGGLE_BUTTON(widget)->active);
1124 set_input_sensitive();
1125 }
1126
1127 // "Mouse Wheel Mode" selected
1128 static void mn_wheel_page(...) {PrefsReplaceInt32("mousewheelmode", 0); set_input_sensitive();}
1129 static void mn_wheel_cursor(...) {PrefsReplaceInt32("mousewheelmode", 1); set_input_sensitive();}
1130
1131 // Read settings from widgets and set preferences
1132 static void read_input_settings(void)
1133 {
1134 const char *str = get_file_entry_path(w_keycode_file);
1135 if (str && strlen(str))
1136 PrefsReplaceString("keycodefile", str);
1137 else
1138 PrefsRemoveItem("keycodefile");
1139
1140 PrefsReplaceInt32("mousewheellines", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_mouse_wheel_lines)));
1141 }
1142
1143 // Create "Input" pane
1144 static void create_input_pane(GtkWidget *top)
1145 {
1146 GtkWidget *box, *hbox, *menu, *label, *button;
1147 GtkObject *adj;
1148
1149 box = make_pane(top, STR_INPUT_PANE_TITLE);
1150
1151 make_checkbox(box, STR_KEYCODES_CTRL, "keycodes", GTK_SIGNAL_FUNC(tb_keycodes));
1152
1153 hbox = gtk_hbox_new(FALSE, 4);
1154 gtk_widget_show(hbox);
1155 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1156
1157 label = gtk_label_new(GetString(STR_KEYCODES_CTRL));
1158 gtk_widget_show(label);
1159 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1160
1161 const char *str = PrefsFindString("keycodefile");
1162 if (str == NULL)
1163 str = "";
1164
1165 w_keycode_file = gtk_entry_new();
1166 gtk_entry_set_text(GTK_ENTRY(w_keycode_file), str);
1167 gtk_widget_show(w_keycode_file);
1168 gtk_box_pack_start(GTK_BOX(hbox), w_keycode_file, TRUE, TRUE, 0);
1169
1170 button = make_browse_button(w_keycode_file);
1171 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1172 g_object_set_data(G_OBJECT(w_keycode_file), "chooser_button", button);
1173
1174 make_separator(box);
1175
1176 static const opt_desc options[] = {
1177 {STR_MOUSEWHEELMODE_PAGE_LAB, GTK_SIGNAL_FUNC(mn_wheel_page)},
1178 {STR_MOUSEWHEELMODE_CURSOR_LAB, GTK_SIGNAL_FUNC(mn_wheel_cursor)},
1179 {0, NULL}
1180 };
1181 int wheelmode = PrefsFindInt32("mousewheelmode"), active = 0;
1182 switch (wheelmode) {
1183 case 0: active = 0; break;
1184 case 1: active = 1; break;
1185 }
1186 menu = make_option_menu(box, STR_MOUSEWHEELMODE_CTRL, options, active);
1187
1188 hbox = gtk_hbox_new(FALSE, 4);
1189 gtk_widget_show(hbox);
1190 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1191
1192 label = gtk_label_new(GetString(STR_MOUSEWHEELLINES_CTRL));
1193 gtk_widget_show(label);
1194 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1195
1196 adj = gtk_adjustment_new(PrefsFindInt32("mousewheellines"), 1, 1000, 1, 5, 0);
1197 w_mouse_wheel_lines = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0);
1198 gtk_widget_show(w_mouse_wheel_lines);
1199 gtk_box_pack_start(GTK_BOX(hbox), w_mouse_wheel_lines, FALSE, FALSE, 0);
1200
1201 set_input_sensitive();
1202 }
1203
1204
1205 /*
1206 * "Serial/Network" pane
1207 */
1208
1209 static GtkWidget *w_seriala, *w_serialb, *w_ether, *w_udp_port;
1210
1211 // Set sensitivity of widgets
1212 static void set_serial_sensitive(void)
1213 {
1214 #if SUPPORTS_UDP_TUNNEL
1215 gtk_widget_set_sensitive(w_ether, !PrefsFindBool("udptunnel"));
1216 gtk_widget_set_sensitive(w_udp_port, PrefsFindBool("udptunnel"));
1217 #endif
1218 }
1219
1220 // "Tunnel AppleTalk over IP" button toggled
1221 static void tb_udptunnel(GtkWidget *widget)
1222 {
1223 PrefsReplaceBool("udptunnel", GTK_TOGGLE_BUTTON(widget)->active);
1224 set_serial_sensitive();
1225 }
1226
1227 // Read settings from widgets and set preferences
1228 static void read_serial_settings(void)
1229 {
1230 const char *str;
1231
1232 str = gtk_entry_get_text(GTK_ENTRY(w_seriala));
1233 PrefsReplaceString("seriala", str);
1234
1235 str = gtk_entry_get_text(GTK_ENTRY(w_serialb));
1236 PrefsReplaceString("serialb", str);
1237
1238 str = gtk_entry_get_text(GTK_ENTRY(w_ether));
1239 if (str && strlen(str))
1240 PrefsReplaceString("ether", str);
1241 else
1242 PrefsRemoveItem("ether");
1243
1244 #if SUPPORTS_UDP_TUNNEL
1245 PrefsReplaceInt32("udpport", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_udp_port)));
1246 #endif
1247 }
1248
1249 // Add names of serial devices
1250 static gint gl_str_cmp(gconstpointer a, gconstpointer b)
1251 {
1252 return strcmp((char *)a, (char *)b);
1253 }
1254
1255 static GList *add_serial_names(void)
1256 {
1257 GList *glist = NULL;
1258
1259 // Search /dev for ttyS* and lp*
1260 DIR *d = opendir("/dev");
1261 if (d) {
1262 struct dirent *de;
1263 while ((de = readdir(d)) != NULL) {
1264 #if defined(__linux__)
1265 if (strncmp(de->d_name, "ttyS", 4) == 0 || strncmp(de->d_name, "lp", 2) == 0) {
1266 #elif defined(__FreeBSD__)
1267 if (strncmp(de->d_name, "cuaa", 4) == 0 || strncmp(de->d_name, "lpt", 3) == 0) {
1268 #elif defined(__NetBSD__)
1269 if (strncmp(de->d_name, "tty0", 4) == 0 || strncmp(de->d_name, "lpt", 3) == 0) {
1270 #elif defined(sgi)
1271 if (strncmp(de->d_name, "ttyf", 4) == 0 || strncmp(de->d_name, "plp", 3) == 0) {
1272 #else
1273 if (false) {
1274 #endif
1275 char *str = new char[64];
1276 sprintf(str, "/dev/%s", de->d_name);
1277 glist = g_list_append(glist, str);
1278 }
1279 }
1280 closedir(d);
1281 }
1282 if (glist)
1283 g_list_sort(glist, gl_str_cmp);
1284 else
1285 glist = g_list_append(glist, (void *)GetString(STR_NONE_LAB));
1286 return glist;
1287 }
1288
1289 // Add names of ethernet interfaces
1290 static GList *add_ether_names(void)
1291 {
1292 GList *glist = NULL;
1293
1294 // Get list of all Ethernet interfaces
1295 int s = socket(PF_INET, SOCK_DGRAM, 0);
1296 if (s >= 0) {
1297 char inbuf[8192];
1298 struct ifconf ifc;
1299 ifc.ifc_len = sizeof(inbuf);
1300 ifc.ifc_buf = inbuf;
1301 if (ioctl(s, SIOCGIFCONF, &ifc) == 0) {
1302 struct ifreq req, *ifr = ifc.ifc_req;
1303 for (int i=0; i<ifc.ifc_len; i+=sizeof(ifreq), ifr++) {
1304 req = *ifr;
1305 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(sgi)
1306 if (ioctl(s, SIOCGIFADDR, &req) == 0 && (req.ifr_addr.sa_family == ARPHRD_ETHER || req.ifr_addr.sa_family == ARPHRD_ETHER+1)) {
1307 #elif defined(__linux__)
1308 if (ioctl(s, SIOCGIFHWADDR, &req) == 0 && req.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
1309 #else
1310 if (false) {
1311 #endif
1312 char *str = new char[64];
1313 strncpy(str, ifr->ifr_name, 63);
1314 glist = g_list_append(glist, str);
1315 }
1316 }
1317 }
1318 close(s);
1319 }
1320 #ifdef HAVE_SLIRP
1321 static char s_slirp[] = "slirp";
1322 glist = g_list_append(glist, s_slirp);
1323 #endif
1324 if (glist)
1325 g_list_sort(glist, gl_str_cmp);
1326 else
1327 glist = g_list_append(glist, (void *)GetString(STR_NONE_LAB));
1328 return glist;
1329 }
1330
1331 // Create "Serial/Network" pane
1332 static void create_serial_pane(GtkWidget *top)
1333 {
1334 GtkWidget *box, *hbox, *table, *label, *combo, *sep;
1335 GtkObject *adj;
1336
1337 box = make_pane(top, STR_SERIAL_NETWORK_PANE_TITLE);
1338 table = make_table(box, 2, 4);
1339
1340 label = gtk_label_new(GetString(STR_SERIALA_CTRL));
1341 gtk_widget_show(label);
1342 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1343
1344 GList *glist = add_serial_names();
1345 combo = gtk_combo_new();
1346 gtk_widget_show(combo);
1347 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1348 const char *str = PrefsFindString("seriala");
1349 if (str == NULL)
1350 str = "";
1351 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1352 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1353 w_seriala = GTK_COMBO(combo)->entry;
1354
1355 label = gtk_label_new(GetString(STR_SERIALB_CTRL));
1356 gtk_widget_show(label);
1357 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1358
1359 combo = gtk_combo_new();
1360 gtk_widget_show(combo);
1361 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1362 str = PrefsFindString("serialb");
1363 if (str == NULL)
1364 str = "";
1365 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1366 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 1, 2, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1367 w_serialb = GTK_COMBO(combo)->entry;
1368
1369 sep = gtk_hseparator_new();
1370 gtk_widget_show(sep);
1371 gtk_table_attach(GTK_TABLE(table), sep, 0, 2, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1372
1373 label = gtk_label_new(GetString(STR_ETHERNET_IF_CTRL));
1374 gtk_widget_show(label);
1375 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1376
1377 glist = add_ether_names();
1378 combo = gtk_combo_new();
1379 gtk_widget_show(combo);
1380 gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1381 str = PrefsFindString("ether");
1382 if (str == NULL)
1383 str = "";
1384 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1385 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1386 w_ether = GTK_COMBO(combo)->entry;
1387
1388 #if SUPPORTS_UDP_TUNNEL
1389 make_checkbox(box, STR_UDPTUNNEL_CTRL, "udptunnel", GTK_SIGNAL_FUNC(tb_udptunnel));
1390
1391 hbox = gtk_hbox_new(FALSE, 4);
1392 gtk_widget_show(hbox);
1393 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1394
1395 label = gtk_label_new(GetString(STR_UDPPORT_CTRL));
1396 gtk_widget_show(label);
1397 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1398
1399 adj = gtk_adjustment_new(PrefsFindInt32("udpport"), 1, 65535, 1, 5, 0);
1400 w_udp_port = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0);
1401 gtk_widget_show(w_udp_port);
1402 gtk_box_pack_start(GTK_BOX(hbox), w_udp_port, FALSE, FALSE, 0);
1403 #endif
1404
1405 set_serial_sensitive();
1406 }
1407
1408
1409 /*
1410 * "Memory/Misc" pane
1411 */
1412
1413 static GtkWidget *w_ramsize;
1414 static GtkWidget *w_rom_file;
1415
1416 // "Ignore SEGV" button toggled
1417 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1418 static void tb_ignoresegv(GtkWidget *widget)
1419 {
1420 PrefsReplaceBool("ignoresegv", GTK_TOGGLE_BUTTON(widget)->active);
1421 }
1422 #endif
1423
1424 // Model ID selected
1425 static void mn_modelid_5(...) {PrefsReplaceInt32("modelid", 5);}
1426 static void mn_modelid_14(...) {PrefsReplaceInt32("modelid", 14);}
1427
1428 // CPU/FPU type
1429 static void mn_cpu_68020(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", false);}
1430 static void mn_cpu_68020_fpu(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", true);}
1431 static void mn_cpu_68030(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", false);}
1432 static void mn_cpu_68030_fpu(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", true);}
1433 static void mn_cpu_68040(...) {PrefsReplaceInt32("cpu", 4); PrefsReplaceBool("fpu", true);}
1434
1435 // Read settings from widgets and set preferences
1436 static void read_memory_settings(void)
1437 {
1438 const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_ramsize)->entry));
1439 PrefsReplaceInt32("ramsize", atoi(str) << 20);
1440
1441 str = get_file_entry_path(w_rom_file);
1442 if (str && strlen(str))
1443 PrefsReplaceString("rom", str);
1444 else
1445 PrefsRemoveItem("rom");
1446
1447 }
1448
1449 // Create "Memory/Misc" pane
1450 static void create_memory_pane(GtkWidget *top)
1451 {
1452 GtkWidget *box, *hbox, *table, *label, *menu;
1453
1454 box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE);
1455 table = make_table(box, 2, 5);
1456
1457 static const combo_desc options[] = {
1458 STR_RAMSIZE_2MB_LAB,
1459 STR_RAMSIZE_4MB_LAB,
1460 STR_RAMSIZE_8MB_LAB,
1461 STR_RAMSIZE_16MB_LAB,
1462 STR_RAMSIZE_32MB_LAB,
1463 STR_RAMSIZE_64MB_LAB,
1464 STR_RAMSIZE_128MB_LAB,
1465 STR_RAMSIZE_256MB_LAB,
1466 STR_RAMSIZE_512MB_LAB,
1467 STR_RAMSIZE_1024MB_LAB,
1468 0
1469 };
1470 char default_ramsize[10];
1471 sprintf(default_ramsize, "%d", PrefsFindInt32("ramsize") >> 20);
1472 w_ramsize = table_make_combobox(table, 0, STR_RAMSIZE_CTRL, default_ramsize, options);
1473
1474 static const opt_desc model_options[] = {
1475 {STR_MODELID_5_LAB, GTK_SIGNAL_FUNC(mn_modelid_5)},
1476 {STR_MODELID_14_LAB, GTK_SIGNAL_FUNC(mn_modelid_14)},
1477 {0, NULL}
1478 };
1479 int modelid = PrefsFindInt32("modelid"), active = 0;
1480 switch (modelid) {
1481 case 5: active = 0; break;
1482 case 14: active = 1; break;
1483 }
1484 table_make_option_menu(table, 2, STR_MODELID_CTRL, model_options, active);
1485
1486 #if EMULATED_68K
1487 static const opt_desc cpu_options[] = {
1488 {STR_CPU_68020_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020)},
1489 {STR_CPU_68020_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020_fpu)},
1490 {STR_CPU_68030_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030)},
1491 {STR_CPU_68030_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030_fpu)},
1492 {STR_CPU_68040_LAB, GTK_SIGNAL_FUNC(mn_cpu_68040)},
1493 {0, NULL}
1494 };
1495 int cpu = PrefsFindInt32("cpu");
1496 bool fpu = PrefsFindBool("fpu");
1497 active = 0;
1498 switch (cpu) {
1499 case 2: active = fpu ? 1 : 0; break;
1500 case 3: active = fpu ? 3 : 2; break;
1501 case 4: active = 4;
1502 }
1503 table_make_option_menu(table, 3, STR_CPU_CTRL, cpu_options, active);
1504 #endif
1505
1506 w_rom_file = table_make_file_entry(table, 4, STR_ROM_FILE_CTRL, "rom");
1507
1508 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1509 make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv));
1510 #endif
1511 }
1512
1513
1514 /*
1515 * Read settings from widgets and set preferences
1516 */
1517
1518 static void read_settings(void)
1519 {
1520 read_volumes_settings();
1521 read_scsi_settings();
1522 read_graphics_settings();
1523 read_input_settings();
1524 read_serial_settings();
1525 read_memory_settings();
1526 read_jit_settings();
1527 }
1528
1529
1530 #ifdef STANDALONE_GUI
1531 #include <errno.h>
1532 #include <sys/wait.h>
1533 #include "rpc.h"
1534
1535 /*
1536 * Fake unused data and functions
1537 */
1538
1539 uint8 XPRAM[XPRAM_SIZE];
1540 void MountVolume(void *fh) { }
1541 void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) { }
1542
1543
1544 /*
1545 * Display alert
1546 */
1547
1548 static void dl_destroyed(void)
1549 {
1550 gtk_main_quit();
1551 }
1552
1553 static void display_alert(int title_id, int prefix_id, int button_id, const char *text)
1554 {
1555 char str[256];
1556 sprintf(str, GetString(prefix_id), text);
1557
1558 GtkWidget *dialog = gtk_dialog_new();
1559 gtk_window_set_title(GTK_WINDOW(dialog), GetString(title_id));
1560 gtk_container_border_width(GTK_CONTAINER(dialog), 5);
1561 gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
1562 gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(dl_destroyed), NULL);
1563
1564 GtkWidget *label = gtk_label_new(str);
1565 gtk_widget_show(label);
1566 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
1567
1568 GtkWidget *button = gtk_button_new_with_label(GetString(button_id));
1569 gtk_widget_show(button);
1570 gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
1571 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
1572 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1573 gtk_widget_grab_default(button);
1574 gtk_widget_show(dialog);
1575
1576 gtk_main();
1577 }
1578
1579
1580 /*
1581 * Display error alert
1582 */
1583
1584 void ErrorAlert(const char *text)
1585 {
1586 display_alert(STR_ERROR_ALERT_TITLE, STR_GUI_ERROR_PREFIX, STR_QUIT_BUTTON, text);
1587 }
1588
1589
1590 /*
1591 * Display warning alert
1592 */
1593
1594 void WarningAlert(const char *text)
1595 {
1596 display_alert(STR_WARNING_ALERT_TITLE, STR_GUI_WARNING_PREFIX, STR_OK_BUTTON, text);
1597 }
1598
1599
1600 /*
1601 * RPC handlers
1602 */
1603
1604 static int handle_ErrorAlert(rpc_connection_t *connection)
1605 {
1606 D(bug("handle_ErrorAlert\n"));
1607
1608 int error;
1609 char *str;
1610 if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0)
1611 return error;
1612
1613 ErrorAlert(str);
1614 free(str);
1615 return RPC_ERROR_NO_ERROR;
1616 }
1617
1618 static int handle_WarningAlert(rpc_connection_t *connection)
1619 {
1620 D(bug("handle_WarningAlert\n"));
1621
1622 int error;
1623 char *str;
1624 if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0)
1625 return error;
1626
1627 WarningAlert(str);
1628 free(str);
1629 return RPC_ERROR_NO_ERROR;
1630 }
1631
1632 static int handle_Exit(rpc_connection_t *connection)
1633 {
1634 D(bug("handle_Exit\n"));
1635
1636 return RPC_ERROR_NO_ERROR;
1637 }
1638
1639
1640 /*
1641 * Start standalone GUI
1642 */
1643
1644 int main(int argc, char *argv[])
1645 {
1646 #ifdef HAVE_GNOMEUI
1647 // Init GNOME/GTK
1648 char version[16];
1649 sprintf(version, "%d.%d", VERSION_MAJOR, VERSION_MINOR);
1650 gnome_init("Basilisk II", version, argc, argv);
1651 #else
1652 // Init GTK
1653 gtk_set_locale();
1654 gtk_init(&argc, &argv);
1655 #endif
1656
1657 // Read preferences
1658 PrefsInit(argc, argv);
1659
1660 // Show preferences editor
1661 bool start = PrefsEditor();
1662
1663 // Exit preferences
1664 PrefsExit();
1665
1666 // Transfer control to the executable
1667 if (start) {
1668 char gui_connection_path[64];
1669 sprintf(gui_connection_path, "/org/BasiliskII/GUI/%d", getpid());
1670
1671 int pid = fork();
1672 if (pid == 0) { // Child
1673 char b2_path[PATH_MAX];
1674 strcpy(b2_path, argv[0]);
1675 char *p = strrchr(b2_path, '/');
1676 p = p ? p + 1 : b2_path;
1677 *p = '\0';
1678 strcat(b2_path, "BasiliskII");
1679 execl(b2_path, b2_path, "--gui-connection", gui_connection_path, (char *)NULL);
1680
1681 char str[256];
1682 sprintf(str, GetString(STR_NO_B2_EXE_FOUND), b2_path, strerror(errno));
1683 ErrorAlert(str);
1684 return 1;
1685 }
1686 else { // Parent
1687 rpc_connection_t *connection;
1688 if ((connection = rpc_init_server(gui_connection_path)) == NULL) {
1689 printf("ERROR: failed to initialize GUI-side RPC server connection\n");
1690 return 1;
1691 }
1692
1693 static const rpc_method_descriptor_t vtable[] = {
1694 { RPC_METHOD_ERROR_ALERT, handle_ErrorAlert },
1695 { RPC_METHOD_WARNING_ALERT, handle_WarningAlert },
1696 { RPC_METHOD_EXIT, handle_Exit }
1697 };
1698 if (rpc_method_add_callbacks(connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) {
1699 printf("ERROR: failed to setup GUI method callbacks\n");
1700 return 1;
1701 }
1702
1703 if (rpc_listen(connection) < 0) {
1704 printf("ERROR: failed to initialize RPC server thread\n");
1705 return 1;
1706 }
1707
1708 int status, ret = -1;
1709 while (waitpid(pid, &status, 0) != pid)
1710 ;
1711 if (WIFEXITED(status))
1712 ret = WEXITSTATUS(status);
1713
1714 rpc_exit(connection);
1715 return ret;
1716 }
1717 }
1718
1719 return 0;
1720 }
1721 #endif