ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/prefs_editor_gtk.cpp
(Generate patch)

Comparing BasiliskII/src/Unix/prefs_editor_gtk.cpp (file contents):
Revision 1.14 by cebix, 2001-01-04T19:50:22Z vs.
Revision 1.36 by gbeauche, 2006-04-18T21:29:01Z

# Line 1 | Line 1
1   /*
2   *  prefs_editor_gtk.cpp - Preferences editor, Unix implementation using GTK+
3   *
4 < *  Basilisk II (C) 1997-2000 Christian Bauer
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
# Line 28 | Line 28
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"
# Line 35 | Line 39
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
48 > static bool start_clicked = false;      // Return value of PrefsEditor() function
49  
50  
51   // Prototypes
# Line 48 | Line 55 | static void create_graphics_pane(GtkWidg
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  
# Line 55 | Line 63 | static void read_settings(void);
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));
# Line 73 | Line 124 | static GtkWidget *make_pane(GtkWidget *n
124          GtkWidget *frame, *label, *box;
125  
126          frame = gtk_frame_new(NULL);
127 <        gtk_widget_show(frame);
77 <        gtk_container_border_width(GTK_CONTAINER(frame), 4);
78 <
79 <        label = gtk_label_new(GetString(title_id));
80 <        gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label);
127 >        gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
128  
129          box = gtk_vbox_new(FALSE, 4);
83        gtk_widget_show(box);
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  
# Line 123 | Line 174 | static GtkWidget *make_table(GtkWidget *
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;
# Line 150 | Line 281 | static GtkWidget *make_option_menu(GtkWi
281          return menu;
282   }
283  
284 < static GtkWidget *make_entry(GtkWidget *top, int label_id, const char *prefs_item)
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  
# Line 162 | Line 293 | static GtkWidget *make_entry(GtkWidget *
293          gtk_widget_show(label);
294          gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
295  
165        entry = gtk_entry_new();
166        gtk_widget_show(entry);
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));
# Line 182 | Line 330 | static GtkWidget *make_checkbox(GtkWidge
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
# Line 225 | Line 403 | static void dl_quit(GtkWidget *dialog)
403   // "About" selected
404   static void mn_about(...)
405   {
406 <        GtkWidget *dialog, *label, *button;
406 >        GtkWidget *dialog;
407  
408 <        char str[256];
409 <        sprintf(str, GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
410 <        strncat(str, "\n", 255);
411 <        strncat(str, GetString(STR_ABOUT_TEXT2), 255);
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();
236        gtk_widget_set_usize(GTK_WIDGET(dialog), strlen(GetString(STR_ABOUT_TEXT2)) + 200, 120);
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);
# Line 248 | Line 470 | static void mn_about(...)
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  
# Line 260 | Line 485 | static void mn_zap_pram(...)
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),          NULL,                   GTK_SIGNAL_FUNC(cb_start),              0, NULL},
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},
# Line 284 | Line 509 | bool PrefsEditor(void)
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();
293        gtk_widget_show(notebook);
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);
# Line 301 | Line 530 | bool PrefsEditor(void)
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)},
# Line 329 | Line 560 | static void cl_selected(GtkWidget *list,
560          selected_volume = row;
561   }
562  
332 struct file_req_assoc {
333        file_req_assoc(GtkWidget *r, GtkWidget *e) : req(r), entry(e) {}
334        GtkWidget *req;
335        GtkWidget *entry;
336 };
337
563   // Volume selected for addition
564   static void add_volume_ok(GtkWidget *button, file_req_assoc *assoc)
565   {
566 <        char *file = gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
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;
# Line 347 | Line 572 | static void add_volume_ok(GtkWidget *but
572   // Volume selected for creation
573   static void create_volume_ok(GtkWidget *button, file_req_assoc *assoc)
574   {
575 <        char *file = gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
575 >        gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
576  
577 <        char *str = gtk_entry_get_text(GTK_ENTRY(assoc->entry));
577 >        const gchar *str = gtk_entry_get_text(GTK_ENTRY(assoc->entry));
578          int size = atoi(str);
579  
580          char cmd[1024];
# Line 423 | Line 648 | static void read_volumes_settings(void)
648                  PrefsAddString("disk", str);
649          }
650  
651 <        PrefsReplaceString("extfs", gtk_entry_get_text(GTK_ENTRY(w_extfs)));
651 >        PrefsReplaceString("extfs", get_file_entry_path(w_extfs));
652   }
653  
654   // Create "Volumes" pane
# Line 444 | Line 669 | static void create_volumes_pane(GtkWidge
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 = (char *)PrefsFindString("disk", index++)) != NULL)
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);
# Line 459 | Line 684 | static void create_volumes_pane(GtkWidge
684          make_button_box(box, 0, buttons);
685          make_separator(box);
686  
687 <        w_extfs = make_entry(box, STR_EXTFS_CTRL, "extfs");
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)},
# Line 478 | Line 703 | static void create_volumes_pane(GtkWidge
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  
# Line 489 | Line 823 | static void read_scsi_settings(void)
823          for (int id=0; id<7; id++) {
824                  char prefs_name[32];
825                  sprintf(prefs_name, "scsi%d", id);
826 <                const char *str = gtk_entry_get_text(GTK_ENTRY(w_scsi[id]));
826 >                const char *str = get_file_entry_path(w_scsi[id]);
827                  if (str && strlen(str))
828                          PrefsReplaceString(prefs_name, str);
829                  else
# Line 507 | Line 841 | static void create_scsi_pane(GtkWidget *
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_entry(box, STR_SCSI_ID_0 + id, prefs_name);
844 >                w_scsi[id] = make_file_entry(box, STR_SCSI_ID_0 + id, prefs_name);
845          }
846   }
847  
# Line 533 | Line 867 | static GtkWidget *l_fbdev_name, *l_fbdev
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   {
# Line 579 | Line 915 | static void mn_30hz(...) {PrefsReplaceIn
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
# Line 637 | Line 982 | static void read_graphics_settings(void)
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
# Line 752 | Line 1107 | static void create_graphics_pane(GtkWidg
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_entry(box, STR_FBDEVICE_FILE_CTRL, "fbdevicefile");
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   }
# Line 772 | Line 1131 | static GtkWidget *w_mouse_wheel_lines;
1131   // Set sensitivity of widgets
1132   static void set_input_sensitive(void)
1133   {
1134 <        gtk_widget_set_sensitive(w_keycode_file, PrefsFindBool("keycodes"));
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  
# Line 790 | Line 1151 | static void mn_wheel_cursor(...) {PrefsR
1151   // Read settings from widgets and set preferences
1152   static void read_input_settings(void)
1153   {
1154 <        const char *str = gtk_entry_get_text(GTK_ENTRY(w_keycode_file));
1154 >        const char *str = get_file_entry_path(w_keycode_file);
1155          if (str && strlen(str))
1156                  PrefsReplaceString("keycodefile", str);
1157          else
# Line 802 | Line 1163 | static void read_input_settings(void)
1163   // Create "Input" pane
1164   static void create_input_pane(GtkWidget *top)
1165   {
1166 <        GtkWidget *box, *hbox, *menu, *label;
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 <        w_keycode_file = make_entry(box, STR_KEYCODE_FILE_CTRL, "keycodefile");
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  
# Line 845 | Line 1226 | static void create_input_pane(GtkWidget
1226   *  "Serial/Network" pane
1227   */
1228  
1229 < static GtkWidget *w_seriala, *w_serialb, *w_ether;
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)
# Line 863 | Line 1260 | static void read_serial_settings(void)
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
# Line 936 | Line 1337 | static GList *add_ether_names(void)
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
# Line 946 | Line 1351 | static GList *add_ether_names(void)
1351   // Create "Serial/Network" pane
1352   static void create_serial_pane(GtkWidget *top)
1353   {
1354 <        GtkWidget *box, *table, *label, *combo, *sep;
1355 <        GList *glist = add_serial_names();
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);
# Line 956 | Line 1361 | static void create_serial_pane(GtkWidget
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);
# Line 998 | Line 1404 | static void create_serial_pane(GtkWidget
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  
# Line 1005 | Line 1430 | static void create_serial_pane(GtkWidget
1430   *  "Memory/Misc" pane
1431   */
1432  
1433 < static GtkObject *w_ramsize_adj;
1433 > static GtkWidget *w_ramsize;
1434   static GtkWidget *w_rom_file;
1435  
1436 + // "Ignore SEGV" button toggled
1437 + #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1438 + static void tb_ignoresegv(GtkWidget *widget)
1439 + {
1440 +        PrefsReplaceBool("ignoresegv", GTK_TOGGLE_BUTTON(widget)->active);
1441 + }
1442 + #endif
1443 +
1444   // Model ID selected
1445   static void mn_modelid_5(...) {PrefsReplaceInt32("modelid", 5);}
1446   static void mn_modelid_14(...) {PrefsReplaceInt32("modelid", 14);}
# Line 1022 | Line 1455 | static void mn_cpu_68040(...) {PrefsRepl
1455   // Read settings from widgets and set preferences
1456   static void read_memory_settings(void)
1457   {
1458 <        PrefsReplaceInt32("ramsize", int(GTK_ADJUSTMENT(w_ramsize_adj)->value) << 20);
1458 >        const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_ramsize)->entry));
1459 >        PrefsReplaceInt32("ramsize", atoi(str) << 20);
1460  
1461 <        const char *str = gtk_entry_get_text(GTK_ENTRY(w_rom_file));
1461 >        str = get_file_entry_path(w_rom_file);
1462          if (str && strlen(str))
1463                  PrefsReplaceString("rom", str);
1464          else
# Line 1035 | Line 1469 | static void read_memory_settings(void)
1469   // Create "Memory/Misc" pane
1470   static void create_memory_pane(GtkWidget *top)
1471   {
1472 <        GtkWidget *box, *hbox, *vbox, *hbox2, *label, *scale, *menu;
1472 >        GtkWidget *box, *hbox, *table, *label, *menu;
1473  
1474          box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE);
1475 +        table = make_table(box, 2, 5);
1476  
1477 <        hbox = gtk_hbox_new(FALSE, 4);
1478 <        gtk_widget_show(hbox);
1479 <
1480 <        label = gtk_label_new(GetString(STR_RAMSIZE_SLIDER));
1481 <        gtk_widget_show(label);
1482 <        gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1483 <
1484 <        vbox = gtk_vbox_new(FALSE, 4);
1485 <        gtk_widget_show(vbox);
1486 <
1487 <        gfloat min, max;
1488 <        min = 1;
1489 <        max = 1024;
1490 <        w_ramsize_adj = gtk_adjustment_new(min, min, max, 1, 16, 0);
1491 <        gtk_adjustment_set_value(GTK_ADJUSTMENT(w_ramsize_adj), PrefsFindInt32("ramsize") >> 20);
1492 <
1058 <        scale = gtk_hscale_new(GTK_ADJUSTMENT(w_ramsize_adj));
1059 <        gtk_widget_show(scale);
1060 <        gtk_scale_set_digits(GTK_SCALE(scale), 0);
1061 <        gtk_box_pack_start(GTK_BOX(vbox), scale, TRUE, TRUE, 0);
1062 <
1063 <        hbox2 = gtk_hbox_new(FALSE, 4);
1064 <        gtk_widget_show(hbox2);
1065 <
1066 <        char val[32];
1067 <        sprintf(val, GetString(STR_RAMSIZE_FMT), int(min));
1068 <        label = gtk_label_new(val);
1069 <        gtk_widget_show(label);
1070 <        gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
1071 <
1072 <        sprintf(val, GetString(STR_RAMSIZE_FMT), int(max));
1073 <        label = gtk_label_new(val);
1074 <        gtk_widget_show(label);
1075 <        gtk_box_pack_end(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
1076 <        gtk_box_pack_start(GTK_BOX(vbox), hbox2, TRUE, TRUE, 0);
1077 <        gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
1078 <        gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1477 >        static const combo_desc options[] = {
1478 >                STR_RAMSIZE_2MB_LAB,
1479 >                STR_RAMSIZE_4MB_LAB,
1480 >                STR_RAMSIZE_8MB_LAB,
1481 >                STR_RAMSIZE_16MB_LAB,
1482 >                STR_RAMSIZE_32MB_LAB,
1483 >                STR_RAMSIZE_64MB_LAB,
1484 >                STR_RAMSIZE_128MB_LAB,
1485 >                STR_RAMSIZE_256MB_LAB,
1486 >                STR_RAMSIZE_512MB_LAB,
1487 >                STR_RAMSIZE_1024MB_LAB,
1488 >                0
1489 >        };
1490 >        char default_ramsize[10];
1491 >        sprintf(default_ramsize, "%d", PrefsFindInt32("ramsize") >> 20);
1492 >        w_ramsize = table_make_combobox(table, 0, STR_RAMSIZE_CTRL, default_ramsize, options);
1493  
1494          static const opt_desc model_options[] = {
1495                  {STR_MODELID_5_LAB, GTK_SIGNAL_FUNC(mn_modelid_5)},
# Line 1087 | Line 1501 | static void create_memory_pane(GtkWidget
1501                  case 5: active = 0; break;
1502                  case 14: active = 1; break;
1503          }
1504 <        make_option_menu(box, STR_MODELID_CTRL, model_options, active);
1504 >        table_make_option_menu(table, 2, STR_MODELID_CTRL, model_options, active);
1505  
1506   #if EMULATED_68K
1507          static const opt_desc cpu_options[] = {
# Line 1106 | Line 1520 | static void create_memory_pane(GtkWidget
1520                  case 3: active = fpu ? 3 : 2; break;
1521                  case 4: active = 4;
1522          }
1523 <        make_option_menu(box, STR_CPU_CTRL, cpu_options, active);
1523 >        table_make_option_menu(table, 3, STR_CPU_CTRL, cpu_options, active);
1524   #endif
1525  
1526 <        w_rom_file = make_entry(box, STR_ROM_FILE_CTRL, "rom");
1526 >        w_rom_file = table_make_file_entry(table, 4, STR_ROM_FILE_CTRL, "rom");
1527 >
1528 > #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1529 >        make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv));
1530 > #endif
1531   }
1532  
1533  
# Line 1125 | Line 1543 | static void read_settings(void)
1543          read_input_settings();
1544          read_serial_settings();
1545          read_memory_settings();
1546 +        read_jit_settings();
1547 + }
1548 +
1549 +
1550 + #ifdef STANDALONE_GUI
1551 + #include <errno.h>
1552 + #include <sys/wait.h>
1553 + #include "rpc.h"
1554 +
1555 + /*
1556 + *  Fake unused data and functions
1557 + */
1558 +
1559 + uint8 XPRAM[XPRAM_SIZE];
1560 + void MountVolume(void *fh) { }
1561 + void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) { }
1562 +
1563 + #if defined __APPLE__ && defined __MACH__
1564 + void DarwinAddCDROMPrefs(void) { }
1565 + void DarwinAddFloppyPrefs(void) { }
1566 + void DarwinAddSerialPrefs(void) { }
1567 + bool DarwinCDReadTOC(char *, uint8 *) { }
1568 + #endif
1569 +
1570 +
1571 + /*
1572 + *  Display alert
1573 + */
1574 +
1575 + static void dl_destroyed(void)
1576 + {
1577 +        gtk_main_quit();
1578 + }
1579 +
1580 + static void display_alert(int title_id, int prefix_id, int button_id, const char *text)
1581 + {
1582 +        char str[256];
1583 +        sprintf(str, GetString(prefix_id), text);
1584 +
1585 +        GtkWidget *dialog = gtk_dialog_new();
1586 +        gtk_window_set_title(GTK_WINDOW(dialog), GetString(title_id));
1587 +        gtk_container_border_width(GTK_CONTAINER(dialog), 5);
1588 +        gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
1589 +        gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(dl_destroyed), NULL);
1590 +
1591 +        GtkWidget *label = gtk_label_new(str);
1592 +        gtk_widget_show(label);
1593 +        gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
1594 +
1595 +        GtkWidget *button = gtk_button_new_with_label(GetString(button_id));
1596 +        gtk_widget_show(button);
1597 +        gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
1598 +        gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
1599 +        GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1600 +        gtk_widget_grab_default(button);
1601 +        gtk_widget_show(dialog);
1602 +
1603 +        gtk_main();
1604 + }
1605 +
1606 +
1607 + /*
1608 + *  Display error alert
1609 + */
1610 +
1611 + void ErrorAlert(const char *text)
1612 + {
1613 +        display_alert(STR_ERROR_ALERT_TITLE, STR_GUI_ERROR_PREFIX, STR_QUIT_BUTTON, text);
1614 + }
1615 +
1616 +
1617 + /*
1618 + *  Display warning alert
1619 + */
1620 +
1621 + void WarningAlert(const char *text)
1622 + {
1623 +        display_alert(STR_WARNING_ALERT_TITLE, STR_GUI_WARNING_PREFIX, STR_OK_BUTTON, text);
1624 + }
1625 +
1626 +
1627 + /*
1628 + *  RPC handlers
1629 + */
1630 +
1631 + static GMainLoop *g_gui_loop;
1632 +
1633 + static int handle_ErrorAlert(rpc_connection_t *connection)
1634 + {
1635 +        D(bug("handle_ErrorAlert\n"));
1636 +
1637 +        int error;
1638 +        char *str;
1639 +        if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0)
1640 +                return error;
1641 +
1642 +        ErrorAlert(str);
1643 +        free(str);
1644 +        return RPC_ERROR_NO_ERROR;
1645 + }
1646 +
1647 + static int handle_WarningAlert(rpc_connection_t *connection)
1648 + {
1649 +        D(bug("handle_WarningAlert\n"));
1650 +
1651 +        int error;
1652 +        char *str;
1653 +        if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0)
1654 +                return error;
1655 +
1656 +        WarningAlert(str);
1657 +        free(str);
1658 +        return RPC_ERROR_NO_ERROR;
1659 + }
1660 +
1661 + static int handle_Exit(rpc_connection_t *connection)
1662 + {
1663 +        D(bug("handle_Exit\n"));
1664 +
1665 +        g_main_quit(g_gui_loop);
1666 +        return RPC_ERROR_NO_ERROR;
1667   }
1668 +
1669 +
1670 + /*
1671 + *  SIGCHLD handler
1672 + */
1673 +
1674 + static char g_app_path[PATH_MAX];
1675 + static rpc_connection_t *g_gui_connection = NULL;
1676 +
1677 + static void sigchld_handler(int sig, siginfo_t *sip, void *)
1678 + {
1679 +        D(bug("Child %d exitted with status = %x\n", sip->si_pid, sip->si_status));
1680 +
1681 +        int status = sip->si_status;
1682 +        if (status & 0x80)
1683 +                status |= -1 ^0xff;
1684 +
1685 +        if (status < 0) {       // negative -> execlp/-errno
1686 +                char str[256];
1687 +                sprintf(str, GetString(STR_NO_B2_EXE_FOUND), g_app_path, strerror(-status));
1688 +                ErrorAlert(str);
1689 +                status = 1;
1690 +        }
1691 +
1692 +        if (status != 0) {
1693 +                if (g_gui_connection)
1694 +                        rpc_exit(g_gui_connection);
1695 +                exit(status);
1696 +        }
1697 + }
1698 +
1699 +
1700 + /*
1701 + *  Start standalone GUI
1702 + */
1703 +
1704 + int main(int argc, char *argv[])
1705 + {
1706 + #ifdef HAVE_GNOMEUI
1707 +        // Init GNOME/GTK
1708 +        char version[16];
1709 +        sprintf(version, "%d.%d", VERSION_MAJOR, VERSION_MINOR);
1710 +        gnome_init("Basilisk II", version, argc, argv);
1711 + #else
1712 +        // Init GTK
1713 +        gtk_set_locale();
1714 +        gtk_init(&argc, &argv);
1715 + #endif
1716 +
1717 +        // Read preferences
1718 +        PrefsInit(argc, argv);
1719 +
1720 +        // Show preferences editor
1721 +        bool start = PrefsEditor();
1722 +
1723 +        // Exit preferences
1724 +        PrefsExit();
1725 +
1726 +        // Transfer control to the executable
1727 +        if (start) {
1728 +                char gui_connection_path[64];
1729 +                sprintf(gui_connection_path, "/org/BasiliskII/GUI/%d", getpid());
1730 +
1731 +                // Catch exits from the child process
1732 +                struct sigaction sigchld_sa, old_sigchld_sa;
1733 +                sigemptyset(&sigchld_sa.sa_mask);
1734 +                sigchld_sa.sa_sigaction = sigchld_handler;
1735 +                sigchld_sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
1736 +                if (sigaction(SIGCHLD, &sigchld_sa, &old_sigchld_sa) < 0) {
1737 +                        char str[256];
1738 +                        sprintf(str, GetString(STR_SIG_INSTALL_ERR), SIGCHLD, strerror(errno));
1739 +                        ErrorAlert(str);
1740 +                        return 1;
1741 +                }
1742 +
1743 +                // Search and run the BasiliskII executable
1744 +                // XXX it can be in a bundle on MacOS X
1745 +                strcpy(g_app_path, argv[0]);
1746 +                char *p = strrchr(g_app_path, '/');
1747 +                p = p ? p + 1 : g_app_path;
1748 +                *p = '\0';
1749 +                strcat(g_app_path, "BasiliskII");
1750 +
1751 +                int pid = fork();
1752 +                if (pid == 0) {
1753 +                        execlp(g_app_path, g_app_path, "--gui-connection", gui_connection_path, (char *)NULL);
1754 + #ifdef _POSIX_PRIORITY_SCHEDULING
1755 +                        // XXX get a chance to run the parent process so that to not confuse/upset GTK...
1756 +                        sched_yield();
1757 + #endif
1758 +                        _exit(-errno);
1759 +                }
1760 +
1761 +                // Establish a connection to Basilisk II
1762 +                if ((g_gui_connection = rpc_init_server(gui_connection_path)) == NULL) {
1763 +                        printf("ERROR: failed to initialize GUI-side RPC server connection\n");
1764 +                        return 1;
1765 +                }
1766 +                static const rpc_method_descriptor_t vtable[] = {
1767 +                        { RPC_METHOD_ERROR_ALERT,                       handle_ErrorAlert },
1768 +                        { RPC_METHOD_WARNING_ALERT,                     handle_WarningAlert },
1769 +                        { RPC_METHOD_EXIT,                                      handle_Exit }
1770 +                };
1771 +                if (rpc_method_add_callbacks(g_gui_connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) {
1772 +                        printf("ERROR: failed to setup GUI method callbacks\n");
1773 +                        return 1;
1774 +                }
1775 +                int socket;
1776 +                if ((socket = rpc_listen_socket(g_gui_connection)) < 0) {
1777 +                        printf("ERROR: failed to initialize RPC server thread\n");
1778 +                        return 1;
1779 +                }
1780 +
1781 +                g_gui_loop = g_main_new(TRUE);
1782 +                while (g_main_is_running(g_gui_loop)) {
1783 +
1784 +                        // Process a few events pending
1785 +                        const int N_EVENTS_DISPATCH = 10;
1786 +                        for (int i = 0; i < N_EVENTS_DISPATCH; i++) {
1787 +                                if (!g_main_iteration(FALSE))
1788 +                                        break;
1789 +                        }
1790 +
1791 +                        // Check for RPC events (100 ms timeout)
1792 +                        int ret = rpc_wait_dispatch(g_gui_connection, 100000);
1793 +                        if (ret == 0)
1794 +                                continue;
1795 +                        if (ret < 0)
1796 +                                break;
1797 +                        rpc_dispatch(g_gui_connection);
1798 +                }
1799 +
1800 +                rpc_exit(g_gui_connection);
1801 +                return 0;
1802 +        }
1803 +
1804 +        return 0;
1805 + }
1806 + #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines