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

Comparing SheepShaver/src/Unix/prefs_editor_gtk.cpp (file contents):
Revision 1.1.1.1 by cebix, 2002-02-04T16:58:13Z vs.
Revision 1.21 by gbeauche, 2008-01-01T09:47:38Z

# Line 1 | Line 1
1   /*
2   *  prefs_editor_linux.cpp - Preferences editor, Linux implementation using GTK+
3   *
4 < *  SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig
4 > *  SheepShaver (C) 1997-2008 Christian Bauer and Marc Hellwig
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 35 | Line 35
35   #include "prefs.h"
36   #include "prefs_editor.h"
37  
38 + #define DEBUG 0
39 + #include "debug.h"
40 +
41  
42   // Global variables
43   static GtkWidget *win;                          // Preferences window
44 < static bool start_clicked = true;       // Return value of PrefsEditor() function
44 > static bool start_clicked = false;      // Return value of PrefsEditor() function
45 > static int screen_width, screen_height; // Screen dimensions
46  
47  
48   // Prototypes
49   static void create_volumes_pane(GtkWidget *top);
50   static void create_graphics_pane(GtkWidget *top);
51 + static void create_input_pane(GtkWidget *top);
52   static void create_serial_pane(GtkWidget *top);
53   static void create_memory_pane(GtkWidget *top);
54 + static void create_jit_pane(GtkWidget *top);
55   static void read_settings(void);
56  
57  
# Line 53 | Line 59 | static void read_settings(void);
59   *  Utility functions
60   */
61  
62 + #if ! GLIB_CHECK_VERSION(2,0,0)
63 + #define G_OBJECT(obj)                                                   GTK_OBJECT(obj)
64 + #define g_object_get_data(obj, key)                             gtk_object_get_data((obj), (key))
65 + #define g_object_set_data(obj, key, data)               gtk_object_set_data((obj), (key), (data))
66 + #endif
67 +
68   struct opt_desc {
69          int label_id;
70          GtkSignalFunc func;
71   };
72  
73 + struct combo_desc {
74 +        int label_id;
75 + };
76 +
77 + struct file_req_assoc {
78 +        file_req_assoc(GtkWidget *r, GtkWidget *e) : req(r), entry(e) {}
79 +        GtkWidget *req;
80 +        GtkWidget *entry;
81 + };
82 +
83 + static void cb_browse_ok(GtkWidget *button, file_req_assoc *assoc)
84 + {
85 +        gchar *file = (char *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
86 +        gtk_entry_set_text(GTK_ENTRY(assoc->entry), file);
87 +        gtk_widget_destroy(assoc->req);
88 +        delete assoc;
89 + }
90 +
91 + static void cb_browse(GtkWidget *widget, void *user_data)
92 + {
93 +        GtkWidget *req = gtk_file_selection_new(GetString(STR_BROWSE_TITLE));
94 +        gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
95 +        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));
96 +        gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
97 +        gtk_widget_show(req);
98 + }
99 +
100 + static GtkWidget *make_browse_button(GtkWidget *entry)
101 + {
102 +        GtkWidget *button;
103 +
104 +        button = gtk_button_new_with_label(GetString(STR_BROWSE_CTRL));
105 +        gtk_widget_show(button);
106 +        gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc)cb_browse, (void *)entry);
107 +        return button;
108 + }
109 +
110   static void add_menu_item(GtkWidget *menu, int label_id, GtkSignalFunc func)
111   {
112          GtkWidget *item = gtk_menu_item_new_with_label(GetString(label_id));
# Line 71 | Line 120 | static GtkWidget *make_pane(GtkWidget *n
120          GtkWidget *frame, *label, *box;
121  
122          frame = gtk_frame_new(NULL);
74        gtk_widget_show(frame);
123          gtk_container_border_width(GTK_CONTAINER(frame), 4);
124  
77        label = gtk_label_new(GetString(title_id));
78        gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label);
79
125          box = gtk_vbox_new(FALSE, 4);
81        gtk_widget_show(box);
126          gtk_container_set_border_width(GTK_CONTAINER(box), 4);
127          gtk_container_add(GTK_CONTAINER(frame), box);
128 +
129 +        gtk_widget_show_all(frame);
130 +
131 +        label = gtk_label_new(GetString(title_id));
132 +        gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label);
133          return box;
134   }
135  
# Line 121 | Line 170 | static GtkWidget *make_table(GtkWidget *
170          return table;
171   }
172  
173 + static GtkWidget *table_make_option_menu(GtkWidget *table, int row, int label_id, const opt_desc *options, int active)
174 + {
175 +        GtkWidget *label, *opt, *menu;
176 +
177 +        label = gtk_label_new(GetString(label_id));
178 +        gtk_widget_show(label);
179 +        gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
180 +
181 +        opt = gtk_option_menu_new();
182 +        gtk_widget_show(opt);
183 +        menu = gtk_menu_new();
184 +
185 +        while (options->label_id) {
186 +                add_menu_item(menu, options->label_id, options->func);
187 +                options++;
188 +        }
189 +        gtk_menu_set_active(GTK_MENU(menu), active);
190 +
191 +        gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
192 +        gtk_table_attach(GTK_TABLE(table), opt, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
193 +        return menu;
194 + }
195 +
196 + static GtkWidget *table_make_combobox(GtkWidget *table, int row, int label_id, const char *default_value, GList *glist)
197 + {
198 +        GtkWidget *label, *combo;
199 +        char str[32];
200 +
201 +        label = gtk_label_new(GetString(label_id));
202 +        gtk_widget_show(label);
203 +        gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
204 +        
205 +        combo = gtk_combo_new();
206 +        gtk_widget_show(combo);
207 +        gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
208 +
209 +        gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), default_value);
210 +        gtk_table_attach(GTK_TABLE(table), combo, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
211 +        
212 +        return combo;
213 + }
214 +
215 + static GtkWidget *table_make_combobox(GtkWidget *table, int row, int label_id, const char *default_value, const combo_desc *options)
216 + {
217 +        GList *glist = NULL;
218 +        while (options->label_id) {
219 +                glist = g_list_append(glist, (void *)GetString(options->label_id));
220 +                options++;
221 +        }
222 +
223 +        return table_make_combobox(table, row, label_id, default_value, glist);
224 + }
225 +
226 + static GtkWidget *table_make_file_entry(GtkWidget *table, int row, int label_id, const char *prefs_item, bool only_dirs = false)
227 + {
228 +        GtkWidget *box, *label, *entry, *button;
229 +
230 +        label = gtk_label_new(GetString(label_id));
231 +        gtk_widget_show(label);
232 +        gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
233 +
234 +        const char *str = PrefsFindString(prefs_item);
235 +        if (str == NULL)
236 +                str = "";
237 +
238 +        box = gtk_hbox_new(FALSE, 4);
239 +        gtk_widget_show(box);
240 +        gtk_table_attach(GTK_TABLE(table), box, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
241 +
242 +        entry = gtk_entry_new();
243 +        gtk_entry_set_text(GTK_ENTRY(entry), str);
244 +        gtk_widget_show(entry);
245 +        gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0);
246 +
247 +        button = make_browse_button(entry);
248 +        gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
249 +        g_object_set_data(G_OBJECT(entry), "chooser_button", button);
250 +        return entry;
251 + }
252 +
253   static GtkWidget *make_option_menu(GtkWidget *top, int label_id, const opt_desc *options, int active)
254   {
255          GtkWidget *box, *label, *opt, *menu;
# Line 170 | Line 299 | static GtkWidget *make_entry(GtkWidget *
299          return entry;
300   }
301  
302 + static const gchar *get_file_entry_path(GtkWidget *entry)
303 + {
304 +        return gtk_entry_get_text(GTK_ENTRY(entry));
305 + }
306 +
307   static GtkWidget *make_checkbox(GtkWidget *top, int label_id, const char *prefs_item, GtkSignalFunc func)
308   {
309          GtkWidget *button = gtk_check_button_new_with_label(GetString(label_id));
# Line 238 | Line 372 | static void mn_about(...)
372          char str[512];
373          sprintf(str,
374                  "SheepShaver\nVersion %d.%d\n\n"
375 <                "Copyright (C) 1997-2002 Christian Bauer and Marc Hellwig\n"
376 <                "E-mail: Christian.Bauer@uni-mainz.de\n"
377 <                "http://www.uni-mainz.de/~bauec002/\n\n"
375 >                "Copyright (C) 1997-2008 Christian Bauer and Marc Hellwig\n"
376 >                "E-mail: cb@cebix.net\n"
377 >                "http://sheepshaver.cebix.net/\n\n"
378                  "SheepShaver comes with ABSOLUTELY NO\n"
379                  "WARRANTY. This is free software, and\n"
380                  "you are welcome to redistribute it\n"
# Line 276 | Line 410 | static void mn_zap_pram(...)
410   // Menu item descriptions
411   static GtkItemFactoryEntry menu_items[] = {
412          {(gchar *)GetString(STR_PREFS_MENU_FILE_GTK),           NULL,                   NULL,                                                   0, "<Branch>"},
413 <        {(gchar *)GetString(STR_PREFS_ITEM_START_GTK),          NULL,                   GTK_SIGNAL_FUNC(cb_start),              0, NULL},
413 >        {(gchar *)GetString(STR_PREFS_ITEM_START_GTK),          "<control>S",   GTK_SIGNAL_FUNC(cb_start),              0, NULL},
414          {(gchar *)GetString(STR_PREFS_ITEM_ZAP_PRAM_GTK),       NULL,                   GTK_SIGNAL_FUNC(mn_zap_pram),   0, NULL},
415          {(gchar *)GetString(STR_PREFS_ITEM_SEPL_GTK),           NULL,                   NULL,                                                   0, "<Separator>"},
416          {(gchar *)GetString(STR_PREFS_ITEM_QUIT_GTK),           "<control>Q",   GTK_SIGNAL_FUNC(cb_quit),               0, NULL},
# Line 286 | Line 420 | static GtkItemFactoryEntry menu_items[]
420  
421   bool PrefsEditor(void)
422   {
423 +        // Get screen dimensions
424 +        screen_width = gdk_screen_width();
425 +        screen_height = gdk_screen_height();
426 +
427          // Create window
428          win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
429          gtk_window_set_title(GTK_WINDOW(win), GetString(STR_PREFS_TITLE));
# Line 300 | Line 438 | bool PrefsEditor(void)
438          GtkAccelGroup *accel_group = gtk_accel_group_new();
439          GtkItemFactory *item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
440          gtk_item_factory_create_items(item_factory, sizeof(menu_items) / sizeof(menu_items[0]), menu_items, NULL);
441 + #if GTK_CHECK_VERSION(1,3,15)
442 +        gtk_window_add_accel_group(GTK_WINDOW(win), accel_group);
443 + #else
444          gtk_accel_group_attach(accel_group, GTK_OBJECT(win));
445 + #endif
446          GtkWidget *menu_bar = gtk_item_factory_get_widget(item_factory, "<main>");
447          gtk_widget_show(menu_bar);
448          gtk_box_pack_start(GTK_BOX(box), menu_bar, FALSE, TRUE, 0);
449  
450          GtkWidget *notebook = gtk_notebook_new();
309        gtk_widget_show(notebook);
451          gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
452          gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), FALSE);
453          gtk_box_pack_start(GTK_BOX(box), notebook, TRUE, TRUE, 0);
454 +        gtk_widget_realize(notebook);
455  
456          create_volumes_pane(notebook);
457          create_graphics_pane(notebook);
458 +        create_input_pane(notebook);
459          create_serial_pane(notebook);
460          create_memory_pane(notebook);
461 +        create_jit_pane(notebook);
462 +        gtk_widget_show(notebook);
463  
464          static const opt_desc buttons[] = {
465                  {STR_START_BUTTON, GTK_SIGNAL_FUNC(cb_start)},
# Line 343 | Line 488 | static void cl_selected(GtkWidget *list,
488          selected_volume = row;
489   }
490  
346 struct file_req_assoc {
347        file_req_assoc(GtkWidget *r, GtkWidget *e) : req(r), entry(e) {}
348        GtkWidget *req;
349        GtkWidget *entry;
350 };
351
491   // Volume selected for addition
492   static void add_volume_ok(GtkWidget *button, file_req_assoc *assoc)
493   {
494 <        char *file = gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
494 >        gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
495          gtk_clist_append(GTK_CLIST(volume_list), &file);
496          gtk_widget_destroy(assoc->req);
497          delete assoc;
# Line 361 | Line 500 | static void add_volume_ok(GtkWidget *but
500   // Volume selected for creation
501   static void create_volume_ok(GtkWidget *button, file_req_assoc *assoc)
502   {
503 <        char *file = gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
503 >        gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
504  
505 <        char *str = gtk_entry_get_text(GTK_ENTRY(assoc->entry));
505 >        const gchar *str = gtk_entry_get_text(GTK_ENTRY(assoc->entry));
506          int size = atoi(str);
507  
508          char cmd[1024];
# Line 492 | Line 631 | static void create_volumes_pane(GtkWidge
631  
632  
633   /*
634 + *  "JIT Compiler" pane
635 + */
636 +
637 + // Are we running a JIT capable CPU?
638 + static bool is_jit_capable(void)
639 + {
640 + #if USE_JIT
641 +        return true;
642 + #elif defined __APPLE__ && defined __MACH__
643 +        // XXX run-time detect so that we can use a PPC GUI prefs editor
644 +        static char cpu[10];
645 +        if (cpu[0] == 0) {
646 +                FILE *fp = popen("uname -p", "r");
647 +                if (fp == NULL)
648 +                        return false;
649 +                fgets(cpu, sizeof(cpu) - 1, fp);
650 +                fclose(fp);
651 +        }
652 +        if (cpu[0] == 'i' && cpu[2] == '8' && cpu[3] == '6') // XXX assuming i?86
653 +                return true;
654 + #endif
655 +        return false;
656 + }
657 +
658 + // Set sensitivity of widgets
659 + static void set_jit_sensitive(void)
660 + {
661 +        const bool jit_enabled = PrefsFindBool("jit");
662 + }
663 +
664 + // "Use JIT Compiler" button toggled
665 + static void tb_jit(GtkWidget *widget)
666 + {
667 +        PrefsReplaceBool("jit", GTK_TOGGLE_BUTTON(widget)->active);
668 +        set_jit_sensitive();
669 + }
670 +
671 + // Read settings from widgets and set preferences
672 + static void read_jit_settings(void)
673 + {
674 +        bool jit_enabled = is_jit_capable() && PrefsFindBool("jit");
675 + }
676 +
677 + // "Use built-in 68k DR emulator" button toggled
678 + static void tb_jit_68k(GtkWidget *widget)
679 + {
680 +        PrefsReplaceBool("jit68k", GTK_TOGGLE_BUTTON(widget)->active);
681 + }
682 +
683 + // Create "JIT Compiler" pane
684 + static void create_jit_pane(GtkWidget *top)
685 + {
686 +        GtkWidget *box, *table, *label, *menu;
687 +        char str[32];
688 +        
689 +        box = make_pane(top, STR_JIT_PANE_TITLE);
690 +
691 +        if (is_jit_capable()) {
692 +                make_checkbox(box, STR_JIT_CTRL, "jit", GTK_SIGNAL_FUNC(tb_jit));
693 +                set_jit_sensitive();
694 +        }
695 +
696 +        make_checkbox(box, STR_JIT_68K_CTRL, "jit68k", GTK_SIGNAL_FUNC(tb_jit_68k));
697 + }
698 +
699 +
700 + /*
701   *  "Graphics/Sound" pane
702   */
703  
704 < static GtkWidget *w_frameskip;
704 > // Display types
705 > enum {
706 >        DISPLAY_WINDOW,
707 >        DISPLAY_SCREEN
708 > };
709 >
710 > static GtkWidget *w_frameskip, *w_display_x, *w_display_y;
711 > static GtkWidget *l_frameskip, *l_display_x, *l_display_y;
712 > static int display_type;
713 > static int dis_width, dis_height;
714 > static bool is_fbdev_dga_mode = false;
715 >
716 > static GtkWidget *w_dspdevice_file, *w_mixerdevice_file;
717 >
718 > // Hide/show graphics widgets
719 > static void hide_show_graphics_widgets(void)
720 > {
721 >        switch (display_type) {
722 >                case DISPLAY_WINDOW:
723 >                        gtk_widget_show(w_frameskip); gtk_widget_show(l_frameskip);
724 >                        break;
725 >                case DISPLAY_SCREEN:
726 >                        gtk_widget_hide(w_frameskip); gtk_widget_hide(l_frameskip);
727 >                        break;
728 >        }
729 > }
730 >
731 > // "Window" video type selected
732 > static void mn_window(...)
733 > {
734 >        display_type = DISPLAY_WINDOW;
735 >        hide_show_graphics_widgets();
736 > }
737 >
738 > // "Fullscreen" video type selected
739 > static void mn_fullscreen(...)
740 > {
741 >        display_type = DISPLAY_SCREEN;
742 >        hide_show_graphics_widgets();
743 > }
744  
745   // "5 Hz".."60Hz" selected
746   static void mn_5hz(...) {PrefsReplaceInt32("frameskip", 12);}
# Line 505 | Line 750 | static void mn_15hz(...) {PrefsReplaceIn
750   static void mn_30hz(...) {PrefsReplaceInt32("frameskip", 2);}
751   static void mn_60hz(...) {PrefsReplaceInt32("frameskip", 1);}
752  
753 < // Video modes
754 < static void tb_w640x480(GtkWidget *widget)
753 > // QuickDraw acceleration
754 > static void tb_gfxaccel(GtkWidget *widget)
755   {
756 <        if (GTK_TOGGLE_BUTTON(widget)->active)
512 <                PrefsReplaceInt32("windowmodes", PrefsFindInt32("windowmodes") | 1);
513 <        else
514 <                PrefsReplaceInt32("windowmodes", PrefsFindInt32("windowmodes") & ~1);
756 >        PrefsReplaceBool("gfxaccel", GTK_TOGGLE_BUTTON(widget)->active);
757   }
758  
759 < static void tb_w800x600(GtkWidget *widget)
759 > // Set sensitivity of widgets
760 > static void set_graphics_sensitive(void)
761   {
762 <        if (GTK_TOGGLE_BUTTON(widget)->active)
763 <                PrefsReplaceInt32("windowmodes", PrefsFindInt32("windowmodes") | 2);
764 <        else
522 <                PrefsReplaceInt32("windowmodes", PrefsFindInt32("windowmodes") & ~2);
762 >        const bool sound_enabled = !PrefsFindBool("nosound");
763 >        gtk_widget_set_sensitive(w_dspdevice_file, sound_enabled);
764 >        gtk_widget_set_sensitive(w_mixerdevice_file, sound_enabled);
765   }
766  
767 < static void tb_fs640x480(GtkWidget *widget)
767 > // "Disable Sound Output" button toggled
768 > static void tb_nosound(GtkWidget *widget)
769   {
770 <        if (GTK_TOGGLE_BUTTON(widget)->active)
771 <                PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 1);
529 <        else
530 <                PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~1);
770 >        PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active);
771 >        set_graphics_sensitive();
772   }
773  
774 < static void tb_fs800x600(GtkWidget *widget)
774 > // Read and convert graphics preferences
775 > static void parse_graphics_prefs(void)
776   {
777 <        if (GTK_TOGGLE_BUTTON(widget)->active)
778 <                PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 2);
779 <        else
780 <                PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~2);
777 >        display_type = DISPLAY_WINDOW;
778 >        dis_width = 640;
779 >        dis_height = 480;
780 >
781 >        const char *str = PrefsFindString("screen");
782 >        if (str) {
783 >                if (sscanf(str, "win/%d/%d", &dis_width, &dis_height) == 2)
784 >                        display_type = DISPLAY_WINDOW;
785 >                else if (sscanf(str, "dga/%d/%d", &dis_width, &dis_height) == 2)
786 >                        display_type = DISPLAY_SCREEN;
787 > #ifdef ENABLE_FBDEV_DGA
788 >                else if (sscanf(str, "fbdev/%d/%d", &dis_width, &dis_height) == 2) {
789 >                        is_fbdev_dga_mode = true;
790 >                        display_type = DISPLAY_SCREEN;
791 >                }
792 > #endif
793 >        }
794 >        else {
795 >                uint32 window_modes = PrefsFindInt32("windowmodes");
796 >                uint32 screen_modes = PrefsFindInt32("screenmodes");
797 >                if (screen_modes) {
798 >                        display_type = DISPLAY_SCREEN;
799 >                        static const struct {
800 >                                int id;
801 >                                int width;
802 >                                int height;
803 >                        }
804 >                        modes[] = {
805 >                                {  1,    640,    480 },
806 >                                {  2,    800,    600 },
807 >                                {  4,   1024,    768 },
808 >                                { 64,   1152,    768 },
809 >                                {  8,   1152,    900 },
810 >                                { 16,   1280,   1024 },
811 >                                { 32,   1600,   1200 },
812 >                                { 0, }
813 >                        };
814 >                        for (int i = 0; modes[i].id != 0; i++) {
815 >                                if (screen_modes & modes[i].id) {
816 >                                        if (modes[i].width <= screen_width && modes[i].height <= screen_height) {
817 >                                                dis_width = modes[i].width;
818 >                                                dis_height = modes[i].height;
819 >                                        }
820 >                                }
821 >                        }
822 >                }
823 >                else if (window_modes) {
824 >                        display_type = DISPLAY_WINDOW;
825 >                        if (window_modes & 1)
826 >                                dis_width = 640, dis_height = 480;
827 >                        if (window_modes & 2)
828 >                                dis_width = 800, dis_height = 600;
829 >                }
830 >        }
831 >        if (dis_width == screen_width)
832 >                dis_width = 0;
833 >        if (dis_height == screen_height)
834 >                dis_height = 0;
835   }
836  
837 < static void tb_fs1024x768(GtkWidget *widget)
837 > // Read settings from widgets and set preferences
838 > static void read_graphics_settings(void)
839   {
840 <        if (GTK_TOGGLE_BUTTON(widget)->active)
841 <                PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 4);
842 <        else
843 <                PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~4);
840 >        const char *str;
841 >
842 >        str = gtk_entry_get_text(GTK_ENTRY(w_display_x));
843 >        dis_width = atoi(str);
844 >
845 >        str = gtk_entry_get_text(GTK_ENTRY(w_display_y));
846 >        dis_height = atoi(str);
847 >
848 >        char pref[256];
849 >        bool use_screen_mode = true;
850 >        switch (display_type) {
851 >                case DISPLAY_WINDOW:
852 >                        sprintf(pref, "win/%d/%d", dis_width, dis_height);
853 >                        break;
854 >                case DISPLAY_SCREEN:
855 >                        sprintf(pref, "dga/%d/%d", dis_width, dis_height);
856 >                        break;
857 >                default:
858 >                        use_screen_mode = false;
859 >                        PrefsRemoveItem("screen");
860 >                        return;
861 >        }
862 >        if (use_screen_mode) {
863 >                PrefsReplaceString("screen", pref);
864 >                // Old prefs are now migrated
865 >                PrefsRemoveItem("windowmodes");
866 >                PrefsRemoveItem("screenmodes");
867 >        }
868 >
869 >        PrefsReplaceString("dsp", get_file_entry_path(w_dspdevice_file));
870 >        PrefsReplaceString("mixer", get_file_entry_path(w_mixerdevice_file));
871   }
872  
873 < static void tb_fs1152x900(GtkWidget *widget)
873 > // Create "Graphics/Sound" pane
874 > static void create_graphics_pane(GtkWidget *top)
875   {
876 <        if (GTK_TOGGLE_BUTTON(widget)->active)
877 <                PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 8);
876 >        GtkWidget *box, *table, *label, *opt, *menu, *combo;
877 >        char str[32];
878 >
879 >        parse_graphics_prefs();
880 >
881 >        box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE);
882 >        table = make_table(box, 2, 4);
883 >
884 >        label = gtk_label_new(GetString(STR_VIDEO_TYPE_CTRL));
885 >        gtk_widget_show(label);
886 >        gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
887 >
888 >        opt = gtk_option_menu_new();
889 >        gtk_widget_show(opt);
890 >        menu = gtk_menu_new();
891 >        add_menu_item(menu, STR_WINDOW_CTRL, GTK_SIGNAL_FUNC(mn_window));
892 >        add_menu_item(menu, STR_FULLSCREEN_CTRL, GTK_SIGNAL_FUNC(mn_fullscreen));
893 >        switch (display_type) {
894 >                case DISPLAY_WINDOW:
895 >                        gtk_menu_set_active(GTK_MENU(menu), 0);
896 >                        break;
897 >                case DISPLAY_SCREEN:
898 >                        gtk_menu_set_active(GTK_MENU(menu), 1);
899 >                        break;
900 >        }
901 >        gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
902 >        gtk_table_attach(GTK_TABLE(table), opt, 1, 2, 0, 1, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
903 >
904 >        l_frameskip = gtk_label_new(GetString(STR_FRAMESKIP_CTRL));
905 >        gtk_widget_show(l_frameskip);
906 >        gtk_table_attach(GTK_TABLE(table), l_frameskip, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
907 >
908 >        w_frameskip = gtk_option_menu_new();
909 >        gtk_widget_show(w_frameskip);
910 >        menu = gtk_menu_new();
911 >        add_menu_item(menu, STR_REF_5HZ_LAB, GTK_SIGNAL_FUNC(mn_5hz));
912 >        add_menu_item(menu, STR_REF_7_5HZ_LAB, GTK_SIGNAL_FUNC(mn_7hz));
913 >        add_menu_item(menu, STR_REF_10HZ_LAB, GTK_SIGNAL_FUNC(mn_10hz));
914 >        add_menu_item(menu, STR_REF_15HZ_LAB, GTK_SIGNAL_FUNC(mn_15hz));
915 >        add_menu_item(menu, STR_REF_30HZ_LAB, GTK_SIGNAL_FUNC(mn_30hz));
916 >        add_menu_item(menu, STR_REF_60HZ_LAB, GTK_SIGNAL_FUNC(mn_60hz));
917 >        int frameskip = PrefsFindInt32("frameskip");
918 >        int item = -1;
919 >        switch (frameskip) {
920 >                case 12: item = 0; break;
921 >                case 8: item = 1; break;
922 >                case 6: item = 2; break;
923 >                case 4: item = 3; break;
924 >                case 2: item = 4; break;
925 >                case 1: item = 5; break;
926 >                case 0: item = 5; break;
927 >        }
928 >        if (item >= 0)
929 >                gtk_menu_set_active(GTK_MENU(menu), item);
930 >        gtk_option_menu_set_menu(GTK_OPTION_MENU(w_frameskip), menu);
931 >        gtk_table_attach(GTK_TABLE(table), w_frameskip, 1, 2, 1, 2, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
932 >
933 >        l_display_x = gtk_label_new(GetString(STR_DISPLAY_X_CTRL));
934 >        gtk_widget_show(l_display_x);
935 >        gtk_table_attach(GTK_TABLE(table), l_display_x, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
936 >
937 >        combo = gtk_combo_new();
938 >        gtk_widget_show(combo);
939 >        GList *glist1 = NULL;
940 >        glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_512_LAB));
941 >        glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_640_LAB));
942 >        glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_800_LAB));
943 >        glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_1024_LAB));
944 >        glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_MAX_LAB));
945 >        gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist1);
946 >        if (dis_width)
947 >                sprintf(str, "%d", dis_width);
948          else
949 <                PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~8);
950 < }
949 >                strcpy(str, GetString(STR_SIZE_MAX_LAB));
950 >        gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
951 >        gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
952 >        w_display_x = GTK_COMBO(combo)->entry;
953  
954 < static void tb_fs1280x1024(GtkWidget *widget)
955 < {
956 <        if (GTK_TOGGLE_BUTTON(widget)->active)
957 <                PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 16);
954 >        l_display_y = gtk_label_new(GetString(STR_DISPLAY_Y_CTRL));
955 >        gtk_widget_show(l_display_y);
956 >        gtk_table_attach(GTK_TABLE(table), l_display_y, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
957 >
958 >        combo = gtk_combo_new();
959 >        gtk_widget_show(combo);
960 >        GList *glist2 = NULL;
961 >        glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_384_LAB));
962 >        glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_480_LAB));
963 >        glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_600_LAB));
964 >        glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_768_LAB));
965 >        glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_MAX_LAB));
966 >        gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist2);
967 >        if (dis_height)
968 >                sprintf(str, "%d", dis_height);
969          else
970 <                PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~16);
970 >                strcpy(str, GetString(STR_SIZE_MAX_LAB));
971 >        gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
972 >        gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4);
973 >        w_display_y = GTK_COMBO(combo)->entry;
974 >
975 >        make_checkbox(box, STR_GFXACCEL_CTRL, PrefsFindBool("gfxaccel"), GTK_SIGNAL_FUNC(tb_gfxaccel));
976 >
977 >        make_separator(box);
978 >        make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound));
979 >        w_dspdevice_file = make_entry(box, STR_DSPDEVICE_FILE_CTRL, "dsp");
980 >        w_mixerdevice_file = make_entry(box, STR_MIXERDEVICE_FILE_CTRL, "mixer");
981 >
982 >        set_graphics_sensitive();
983 >
984 >        hide_show_graphics_widgets();
985   }
986  
987 < static void tb_fs1600x1200(GtkWidget *widget)
987 >
988 > /*
989 > *  "Input" pane
990 > */
991 >
992 > static GtkWidget *w_keycode_file;
993 > static GtkWidget *w_mouse_wheel_lines;
994 >
995 > // Set sensitivity of widgets
996 > static void set_input_sensitive(void)
997   {
998 <        if (GTK_TOGGLE_BUTTON(widget)->active)
999 <                PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 32);
1000 <        else
1001 <                PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~32);
998 >        const bool use_keycodes = PrefsFindBool("keycodes");
999 >        gtk_widget_set_sensitive(w_keycode_file, use_keycodes);
1000 >        gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_keycode_file), "chooser_button")), use_keycodes);
1001 >        gtk_widget_set_sensitive(w_mouse_wheel_lines, PrefsFindInt32("mousewheelmode") == 1);
1002   }
1003  
1004 < // "Disable Sound Output" button toggled
1005 < static void tb_nosound(GtkWidget *widget)
1004 > // "Use Raw Keycodes" button toggled
1005 > static void tb_keycodes(GtkWidget *widget)
1006   {
1007 <        PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active);
1007 >        PrefsReplaceBool("keycodes", GTK_TOGGLE_BUTTON(widget)->active);
1008 >        set_input_sensitive();
1009   }
1010  
1011 + // "Mouse Wheel Mode" selected
1012 + static void mn_wheel_page(...) {PrefsReplaceInt32("mousewheelmode", 0); set_input_sensitive();}
1013 + static void mn_wheel_cursor(...) {PrefsReplaceInt32("mousewheelmode", 1); set_input_sensitive();}
1014 +
1015   // Read settings from widgets and set preferences
1016 < static void read_graphics_settings(void)
1016 > static void read_input_settings(void)
1017   {
1018 +        const char *str = get_file_entry_path(w_keycode_file);
1019 +        if (str && strlen(str))
1020 +                PrefsReplaceString("keycodefile", str);
1021 +        else
1022 +                PrefsRemoveItem("keycodefile");
1023 +
1024 +        PrefsReplaceInt32("mousewheellines", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_mouse_wheel_lines)));
1025   }
1026  
1027 < // Create "Graphics/Sound" pane
1028 < static void create_graphics_pane(GtkWidget *top)
1027 > // Create "Input" pane
1028 > static void create_input_pane(GtkWidget *top)
1029   {
1030 <        GtkWidget *box, *vbox, *frame;
1030 >        GtkWidget *box, *hbox, *menu, *label, *button;
1031 >        GtkObject *adj;
1032  
1033 <        box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE);
1033 >        box = make_pane(top, STR_INPUT_PANE_TITLE);
1034 >
1035 >        make_checkbox(box, STR_KEYCODES_CTRL, "keycodes", GTK_SIGNAL_FUNC(tb_keycodes));
1036 >
1037 >        hbox = gtk_hbox_new(FALSE, 4);
1038 >        gtk_widget_show(hbox);
1039 >        gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1040 >
1041 >        label = gtk_label_new(GetString(STR_KEYCODES_CTRL));
1042 >        gtk_widget_show(label);
1043 >        gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1044 >
1045 >        const char *str = PrefsFindString("keycodefile");
1046 >        if (str == NULL)
1047 >                str = "";
1048 >
1049 >        w_keycode_file = gtk_entry_new();
1050 >        gtk_entry_set_text(GTK_ENTRY(w_keycode_file), str);
1051 >        gtk_widget_show(w_keycode_file);
1052 >        gtk_box_pack_start(GTK_BOX(hbox), w_keycode_file, TRUE, TRUE, 0);
1053 >
1054 >        button = make_browse_button(w_keycode_file);
1055 >        gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1056 >        g_object_set_data(G_OBJECT(w_keycode_file), "chooser_button", button);
1057 >
1058 >        make_separator(box);
1059  
1060          static const opt_desc options[] = {
1061 <                {STR_REF_5HZ_LAB, GTK_SIGNAL_FUNC(mn_5hz)},
1062 <                {STR_REF_7_5HZ_LAB, GTK_SIGNAL_FUNC(mn_7hz)},
594 <                {STR_REF_10HZ_LAB, GTK_SIGNAL_FUNC(mn_10hz)},
595 <                {STR_REF_15HZ_LAB, GTK_SIGNAL_FUNC(mn_15hz)},
596 <                {STR_REF_30HZ_LAB, GTK_SIGNAL_FUNC(mn_30hz)},
597 <                {STR_REF_60HZ_LAB, GTK_SIGNAL_FUNC(mn_60hz)},
1061 >                {STR_MOUSEWHEELMODE_PAGE_LAB, GTK_SIGNAL_FUNC(mn_wheel_page)},
1062 >                {STR_MOUSEWHEELMODE_CURSOR_LAB, GTK_SIGNAL_FUNC(mn_wheel_cursor)},
1063                  {0, NULL}
1064          };
1065 <        int frameskip = PrefsFindInt32("frameskip"), active = 0;
1066 <        switch (frameskip) {
1067 <                case 12: active = 0; break;
1068 <                case 8: active = 1; break;
1069 <                case 6: active = 2; break;
1070 <                case 4: active = 3; break;
606 <                case 2: active = 4; break;
607 <                case 1: active = 5; break;
608 <        }
609 <        w_frameskip = make_option_menu(box, STR_FRAMESKIP_CTRL, options, active);
610 <
611 <        frame = gtk_frame_new (GetString(STR_VIDEO_MODE_CTRL));
612 <        gtk_widget_show(frame);
613 <        gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 0);
614 <
615 <        vbox = gtk_vbox_new(FALSE, 4);
616 <        gtk_widget_show(vbox);
617 <        gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
618 <        gtk_container_add(GTK_CONTAINER(frame), vbox);
619 <
620 <        make_checkbox(vbox, STR_W_640x480_CTRL, PrefsFindInt32("windowmodes") & 1, GTK_SIGNAL_FUNC(tb_w640x480));
621 <        make_checkbox(vbox, STR_W_800x600_CTRL, PrefsFindInt32("windowmodes") & 2, GTK_SIGNAL_FUNC(tb_w800x600));
622 <        make_checkbox(vbox, STR_640x480_CTRL, PrefsFindInt32("screenmodes") & 1, GTK_SIGNAL_FUNC(tb_fs640x480));
623 <        make_checkbox(vbox, STR_800x600_CTRL, PrefsFindInt32("screenmodes") & 2, GTK_SIGNAL_FUNC(tb_fs800x600));
624 <        make_checkbox(vbox, STR_1024x768_CTRL, PrefsFindInt32("screenmodes") & 4, GTK_SIGNAL_FUNC(tb_fs1024x768));
625 <        make_checkbox(vbox, STR_1152x900_CTRL, PrefsFindInt32("screenmodes") & 8, GTK_SIGNAL_FUNC(tb_fs1152x900));
626 <        make_checkbox(vbox, STR_1280x1024_CTRL, PrefsFindInt32("screenmodes") & 16, GTK_SIGNAL_FUNC(tb_fs1280x1024));
627 <        make_checkbox(vbox, STR_1600x1200_CTRL, PrefsFindInt32("screenmodes") & 32, GTK_SIGNAL_FUNC(tb_fs1600x1200));
1065 >        int wheelmode = PrefsFindInt32("mousewheelmode"), active = 0;
1066 >        switch (wheelmode) {
1067 >                case 0: active = 0; break;
1068 >                case 1: active = 1; break;
1069 >        }
1070 >        menu = make_option_menu(box, STR_MOUSEWHEELMODE_CTRL, options, active);
1071  
1072 <        make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound));
1072 >        hbox = gtk_hbox_new(FALSE, 4);
1073 >        gtk_widget_show(hbox);
1074 >        gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1075 >
1076 >        label = gtk_label_new(GetString(STR_MOUSEWHEELLINES_CTRL));
1077 >        gtk_widget_show(label);
1078 >        gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1079 >
1080 >        adj = gtk_adjustment_new(PrefsFindInt32("mousewheellines"), 1, 1000, 1, 5, 0);
1081 >        w_mouse_wheel_lines = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0);
1082 >        gtk_widget_show(w_mouse_wheel_lines);
1083 >        gtk_box_pack_start(GTK_BOX(hbox), w_mouse_wheel_lines, FALSE, FALSE, 0);
1084 >
1085 >        set_input_sensitive();
1086   }
1087  
1088  
# Line 669 | Line 1125 | static GList *add_serial_names(void)
1125          if (d) {
1126                  struct dirent *de;
1127                  while ((de = readdir(d)) != NULL) {
1128 + #if defined(__linux__)
1129                          if (strncmp(de->d_name, "ttyS", 4) == 0 || strncmp(de->d_name, "lp", 2) == 0) {
1130 + #elif defined(__FreeBSD__)
1131 +                        if (strncmp(de->d_name, "cuaa", 4) == 0 || strncmp(de->d_name, "lpt", 3) == 0) {
1132 + #elif defined(__NetBSD__)
1133 +                        if (strncmp(de->d_name, "tty0", 4) == 0 || strncmp(de->d_name, "lpt", 3) == 0) {
1134 + #elif defined(sgi)
1135 +                        if (strncmp(de->d_name, "ttyf", 4) == 0 || strncmp(de->d_name, "plp", 3) == 0) {
1136 + #else
1137 +                        if (false) {
1138 + #endif
1139                                  char *str = new char[64];
1140                                  sprintf(str, "/dev/%s", de->d_name);
1141                                  glist = g_list_append(glist, str);
# Line 700 | Line 1166 | static GList *add_ether_names(void)
1166                          struct ifreq req, *ifr = ifc.ifc_req;
1167                          for (int i=0; i<ifc.ifc_len; i+=sizeof(ifreq), ifr++) {
1168                                  req = *ifr;
1169 + #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(sgi)
1170 +                                if (ioctl(s, SIOCGIFADDR, &req) == 0 && (req.ifr_addr.sa_family == ARPHRD_ETHER || req.ifr_addr.sa_family == ARPHRD_ETHER+1)) {
1171 + #elif defined(__linux__)
1172                                  if (ioctl(s, SIOCGIFHWADDR, &req) == 0 && req.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
1173 + #else
1174 +                                if (false) {
1175 + #endif
1176                                          char *str = new char[64];
1177                                          strncpy(str, ifr->ifr_name, 63);
1178                                          glist = g_list_append(glist, str);
# Line 709 | Line 1181 | static GList *add_ether_names(void)
1181                  }
1182                  close(s);
1183          }
1184 + #ifdef HAVE_SLIRP
1185 +        static char s_slirp[] = "slirp";
1186 +        glist = g_list_append(glist, s_slirp);
1187 + #endif
1188          if (glist)
1189                  g_list_sort(glist, gl_str_cmp);
1190          else
# Line 774 | Line 1250 | static void create_serial_pane(GtkWidget
1250   *  "Memory/Misc" pane
1251   */
1252  
1253 < static GtkObject *w_ramsize_adj;
1253 > static GtkWidget *w_ramsize;
1254   static GtkWidget *w_rom_file;
1255  
1256 + // Don't use CPU when idle?
1257 + static void tb_idlewait(GtkWidget *widget)
1258 + {
1259 +        PrefsReplaceBool("idlewait", GTK_TOGGLE_BUTTON(widget)->active);
1260 + }
1261 +
1262   // "Ignore SEGV" button toggled
1263   static void tb_ignoresegv(GtkWidget *widget)
1264   {
# Line 786 | Line 1268 | static void tb_ignoresegv(GtkWidget *wid
1268   // Read settings from widgets and set preferences
1269   static void read_memory_settings(void)
1270   {
1271 <        PrefsReplaceInt32("ramsize", int(GTK_ADJUSTMENT(w_ramsize_adj)->value) << 20);
1271 >        const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_ramsize)->entry));
1272 >        PrefsReplaceInt32("ramsize", atoi(str) << 20);
1273  
1274 <        const char *str = gtk_entry_get_text(GTK_ENTRY(w_rom_file));
1274 >        str = gtk_entry_get_text(GTK_ENTRY(w_rom_file));
1275          if (str && strlen(str))
1276                  PrefsReplaceString("rom", str);
1277          else
# Line 798 | Line 1281 | static void read_memory_settings(void)
1281   // Create "Memory/Misc" pane
1282   static void create_memory_pane(GtkWidget *top)
1283   {
1284 <        GtkWidget *box, *vbox, *hbox, *hbox2, *label, *scale;
1284 >        GtkWidget *box, *hbox, *table, *label, *menu;
1285  
1286          box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE);
1287 +        table = make_table(box, 2, 5);
1288  
1289 <        hbox = gtk_hbox_new(FALSE, 4);
1290 <        gtk_widget_show(hbox);
1291 <
1292 <        label = gtk_label_new(GetString(STR_RAMSIZE_SLIDER));
1293 <        gtk_widget_show(label);
1294 <        gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1295 <
1296 <        vbox = gtk_vbox_new(FALSE, 4);
1297 <        gtk_widget_show(vbox);
1298 <
1299 <        gfloat min, max;
1300 <        min = 1;
1301 <        max = 256;
1302 <        w_ramsize_adj = gtk_adjustment_new(min, min, max, 1, 16, 0);
1303 <        gtk_adjustment_set_value(GTK_ADJUSTMENT(w_ramsize_adj), PrefsFindInt32("ramsize") >> 20);
820 <
821 <        scale = gtk_hscale_new(GTK_ADJUSTMENT(w_ramsize_adj));
822 <        gtk_widget_show(scale);
823 <        gtk_scale_set_digits(GTK_SCALE(scale), 0);
824 <        gtk_box_pack_start(GTK_BOX(vbox), scale, TRUE, TRUE, 0);
825 <
826 <        hbox2 = gtk_hbox_new(FALSE, 4);
827 <        gtk_widget_show(hbox2);
828 <
829 <        char val[32];
830 <        sprintf(val, GetString(STR_RAMSIZE_FMT), int(min));
831 <        label = gtk_label_new(val);
832 <        gtk_widget_show(label);
833 <        gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
834 <
835 <        sprintf(val, GetString(STR_RAMSIZE_FMT), int(max));
836 <        label = gtk_label_new(val);
837 <        gtk_widget_show(label);
838 <        gtk_box_pack_end(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
839 <        gtk_box_pack_start(GTK_BOX(vbox), hbox2, TRUE, TRUE, 0);
840 <        gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
841 <        gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1289 >        static const combo_desc options[] = {
1290 >                STR_RAMSIZE_4MB_LAB,
1291 >                STR_RAMSIZE_8MB_LAB,
1292 >                STR_RAMSIZE_16MB_LAB,
1293 >                STR_RAMSIZE_32MB_LAB,
1294 >                STR_RAMSIZE_64MB_LAB,
1295 >                STR_RAMSIZE_128MB_LAB,
1296 >                STR_RAMSIZE_256MB_LAB,
1297 >                STR_RAMSIZE_512MB_LAB,
1298 >                STR_RAMSIZE_1024MB_LAB,
1299 >                0
1300 >        };
1301 >        char default_ramsize[16];
1302 >        sprintf(default_ramsize, "%d", PrefsFindInt32("ramsize") >> 20);
1303 >        w_ramsize = table_make_combobox(table, 0, STR_RAMSIZE_CTRL, default_ramsize, options);
1304  
1305 <        w_rom_file = make_entry(box, STR_ROM_FILE_CTRL, "rom");
1305 >        w_rom_file = table_make_file_entry(table, 1, STR_ROM_FILE_CTRL, "rom");
1306  
1307          make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv));
1308 +        make_checkbox(box, STR_IDLEWAIT_CTRL, "idlewait", GTK_SIGNAL_FUNC(tb_idlewait));
1309   }
1310  
1311  
# Line 854 | Line 1317 | static void read_settings(void)
1317   {
1318          read_volumes_settings();
1319          read_graphics_settings();
1320 +        read_input_settings();
1321          read_serial_settings();
1322          read_memory_settings();
1323 +        read_jit_settings();
1324 + }
1325 +
1326 +
1327 + #ifdef STANDALONE_GUI
1328 + #include <errno.h>
1329 + #include <sys/wait.h>
1330 + #include "rpc.h"
1331 +
1332 + /*
1333 + *  Fake unused data and functions
1334 + */
1335 +
1336 + uint8 XPRAM[XPRAM_SIZE];
1337 + void MountVolume(void *fh) { }
1338 + void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) { }
1339 +
1340 + #if defined __APPLE__ && defined __MACH__
1341 + void DarwinSysInit(void) { }
1342 + void DarwinSysExit(void) { }
1343 + void DarwinAddFloppyPrefs(void) { }
1344 + void DarwinAddSerialPrefs(void) { }
1345 + bool DarwinCDReadTOC(char *, uint8 *) { }
1346 + #endif
1347 +
1348 +
1349 + /*
1350 + *  Display alert
1351 + */
1352 +
1353 + static void dl_destroyed(void)
1354 + {
1355 +        gtk_main_quit();
1356 + }
1357 +
1358 + static void display_alert(int title_id, int prefix_id, int button_id, const char *text)
1359 + {
1360 +        char str[256];
1361 +        sprintf(str, GetString(prefix_id), text);
1362 +
1363 +        GtkWidget *dialog = gtk_dialog_new();
1364 +        gtk_window_set_title(GTK_WINDOW(dialog), GetString(title_id));
1365 +        gtk_container_border_width(GTK_CONTAINER(dialog), 5);
1366 +        gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
1367 +        gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(dl_destroyed), NULL);
1368 +
1369 +        GtkWidget *label = gtk_label_new(str);
1370 +        gtk_widget_show(label);
1371 +        gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
1372 +
1373 +        GtkWidget *button = gtk_button_new_with_label(GetString(button_id));
1374 +        gtk_widget_show(button);
1375 +        gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
1376 +        gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
1377 +        GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1378 +        gtk_widget_grab_default(button);
1379 +        gtk_widget_show(dialog);
1380 +
1381 +        gtk_main();
1382 + }
1383 +
1384 +
1385 + /*
1386 + *  Display error alert
1387 + */
1388 +
1389 + void ErrorAlert(const char *text)
1390 + {
1391 +        display_alert(STR_ERROR_ALERT_TITLE, STR_GUI_ERROR_PREFIX, STR_QUIT_BUTTON, text);
1392 + }
1393 +
1394 +
1395 + /*
1396 + *  Display warning alert
1397 + */
1398 +
1399 + void WarningAlert(const char *text)
1400 + {
1401 +        display_alert(STR_WARNING_ALERT_TITLE, STR_GUI_WARNING_PREFIX, STR_OK_BUTTON, text);
1402 + }
1403 +
1404 +
1405 + /*
1406 + *  RPC handlers
1407 + */
1408 +
1409 + static GMainLoop *g_gui_loop;
1410 +
1411 + static int handle_ErrorAlert(rpc_connection_t *connection)
1412 + {
1413 +        D(bug("handle_ErrorAlert\n"));
1414 +
1415 +        int error;
1416 +        char *str;
1417 +        if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0)
1418 +                return error;
1419 +
1420 +        ErrorAlert(str);
1421 +        free(str);
1422 +        return RPC_ERROR_NO_ERROR;
1423 + }
1424 +
1425 + static int handle_WarningAlert(rpc_connection_t *connection)
1426 + {
1427 +        D(bug("handle_WarningAlert\n"));
1428 +
1429 +        int error;
1430 +        char *str;
1431 +        if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0)
1432 +                return error;
1433 +
1434 +        WarningAlert(str);
1435 +        free(str);
1436 +        return RPC_ERROR_NO_ERROR;
1437 + }
1438 +
1439 + static int handle_Exit(rpc_connection_t *connection)
1440 + {
1441 +        D(bug("handle_Exit\n"));
1442 +
1443 +        g_main_quit(g_gui_loop);
1444 +        return RPC_ERROR_NO_ERROR;
1445 + }
1446 +
1447 +
1448 + /*
1449 + *  SIGCHLD handler
1450 + */
1451 +
1452 + static char g_app_path[PATH_MAX];
1453 + static rpc_connection_t *g_gui_connection = NULL;
1454 +
1455 + static void sigchld_handler(int sig, siginfo_t *sip, void *)
1456 + {
1457 +        D(bug("Child %d exitted with status = %x\n", sip->si_pid, sip->si_status));
1458 +
1459 +        // XXX perform a new wait because sip->si_status is sometimes not
1460 +        // the exit _value_ on MacOS X but rather the usual status field
1461 +        // from waitpid() -- we could arrange this code in some other way...
1462 +        int status;
1463 +        if (waitpid(sip->si_pid, &status, 0) < 0)
1464 +                status = sip->si_status;
1465 +        if (WIFEXITED(status))
1466 +                status = WEXITSTATUS(status);
1467 +        if (status & 0x80)
1468 +                status |= -1 ^0xff;
1469 +
1470 +        if (status < 0) {       // negative -> execlp/-errno
1471 +                char str[256];
1472 +                sprintf(str, GetString(STR_NO_B2_EXE_FOUND), g_app_path, strerror(-status));
1473 +                ErrorAlert(str);
1474 +                status = 1;
1475 +        }
1476 +
1477 +        if (status != 0) {
1478 +                if (g_gui_connection)
1479 +                        rpc_exit(g_gui_connection);
1480 +                exit(status);
1481 +        }
1482 + }
1483 +
1484 +
1485 + /*
1486 + *  Start standalone GUI
1487 + */
1488 +
1489 + int main(int argc, char *argv[])
1490 + {
1491 +        // Init GTK
1492 +        gtk_set_locale();
1493 +        gtk_init(&argc, &argv);
1494 +
1495 +        // Read preferences
1496 +        PrefsInit(argc, argv);
1497 +
1498 +        // Show preferences editor
1499 +        bool start = PrefsEditor();
1500 +
1501 +        // Exit preferences
1502 +        PrefsExit();
1503 +
1504 +        // Transfer control to the executable
1505 +        if (start) {
1506 +                char gui_connection_path[64];
1507 +                sprintf(gui_connection_path, "/org/SheepShaver/GUI/%d", getpid());
1508 +
1509 +                // Catch exits from the child process
1510 +                struct sigaction sigchld_sa, old_sigchld_sa;
1511 +                sigemptyset(&sigchld_sa.sa_mask);
1512 +                sigchld_sa.sa_sigaction = sigchld_handler;
1513 +                sigchld_sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
1514 +                if (sigaction(SIGCHLD, &sigchld_sa, &old_sigchld_sa) < 0) {
1515 +                        char str[256];
1516 +                        sprintf(str, GetString(STR_SIG_INSTALL_ERR), SIGCHLD, strerror(errno));
1517 +                        ErrorAlert(str);
1518 +                        return 1;
1519 +                }
1520 +
1521 +                // Search and run the SheepShaver executable
1522 +                char *p;
1523 +                strcpy(g_app_path, argv[0]);
1524 +                if ((p = strstr(g_app_path, "SheepShaverGUI.app/Contents/MacOS")) != NULL) {
1525 +                    strcpy(p, "SheepShaver.app/Contents/MacOS/SheepShaver");
1526 +                        if (access(g_app_path, X_OK) < 0) {
1527 +                                char str[256];
1528 +                                sprintf(str, GetString(STR_NO_B2_EXE_FOUND), g_app_path, strerror(errno));
1529 +                                WarningAlert(str);
1530 +                                strcpy(g_app_path, "/Applications/SheepShaver.app/Contents/MacOS/SheepShaver");
1531 +                        }
1532 +                } else {
1533 +                        p = strrchr(g_app_path, '/');
1534 +                        p = p ? p + 1 : g_app_path;
1535 +                        strcpy(p, "SheepShaver");
1536 +                }
1537 +
1538 +                int pid = fork();
1539 +                if (pid == 0) {
1540 +                        D(bug("Trying to execute %s\n", g_app_path));
1541 +                        execlp(g_app_path, g_app_path, "--gui-connection", gui_connection_path, (char *)NULL);
1542 + #ifdef _POSIX_PRIORITY_SCHEDULING
1543 +                        // XXX get a chance to run the parent process so that to not confuse/upset GTK...
1544 +                        sched_yield();
1545 + #endif
1546 +                        _exit(-errno);
1547 +                }
1548 +
1549 +                // Establish a connection to Basilisk II
1550 +                if ((g_gui_connection = rpc_init_server(gui_connection_path)) == NULL) {
1551 +                        printf("ERROR: failed to initialize GUI-side RPC server connection\n");
1552 +                        return 1;
1553 +                }
1554 +                static const rpc_method_descriptor_t vtable[] = {
1555 +                        { RPC_METHOD_ERROR_ALERT,                       handle_ErrorAlert },
1556 +                        { RPC_METHOD_WARNING_ALERT,                     handle_WarningAlert },
1557 +                        { RPC_METHOD_EXIT,                                      handle_Exit }
1558 +                };
1559 +                if (rpc_method_add_callbacks(g_gui_connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) {
1560 +                        printf("ERROR: failed to setup GUI method callbacks\n");
1561 +                        return 1;
1562 +                }
1563 +                int socket;
1564 +                if ((socket = rpc_listen_socket(g_gui_connection)) < 0) {
1565 +                        printf("ERROR: failed to initialize RPC server thread\n");
1566 +                        return 1;
1567 +                }
1568 +
1569 +                g_gui_loop = g_main_new(TRUE);
1570 +                while (g_main_is_running(g_gui_loop)) {
1571 +
1572 +                        // Process a few events pending
1573 +                        const int N_EVENTS_DISPATCH = 10;
1574 +                        for (int i = 0; i < N_EVENTS_DISPATCH; i++) {
1575 +                                if (!g_main_iteration(FALSE))
1576 +                                        break;
1577 +                        }
1578 +
1579 +                        // Check for RPC events (100 ms timeout)
1580 +                        int ret = rpc_wait_dispatch(g_gui_connection, 100000);
1581 +                        if (ret == 0)
1582 +                                continue;
1583 +                        if (ret < 0)
1584 +                                break;
1585 +                        rpc_dispatch(g_gui_connection);
1586 +                }
1587 +
1588 +                rpc_exit(g_gui_connection);
1589 +                return 0;
1590 +        }
1591 +
1592 +        return 0;
1593   }
1594 + #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines