ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/prefs_editor_gtk.cpp
Revision: 1.19
Committed: 2006-05-08T17:20:20Z (18 years ago) by gbeauche
Branch: MAIN
Changes since 1.18: +2 -1 lines
Log Message:
Fix MacOS X GUI (new fake DarwinSys*() functions)

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * prefs_editor_linux.cpp - Preferences editor, Linux implementation using GTK+
3     *
4 gbeauche 1.11 * SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig
5 cebix 1.1 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include "sysdeps.h"
22    
23     #include <gtk/gtk.h>
24     #include <stdlib.h>
25     #include <dirent.h>
26     #include <sys/socket.h>
27     #include <sys/ioctl.h>
28     #include <net/if.h>
29     #include <net/if_arp.h>
30    
31     #include "user_strings.h"
32     #include "version.h"
33     #include "cdrom.h"
34     #include "xpram.h"
35     #include "prefs.h"
36     #include "prefs_editor.h"
37    
38 gbeauche 1.17 #define DEBUG 0
39     #include "debug.h"
40    
41 cebix 1.1
42     // Global variables
43     static GtkWidget *win; // Preferences window
44 gbeauche 1.17 static bool start_clicked = false; // Return value of PrefsEditor() function
45 gbeauche 1.13 static int screen_width, screen_height; // Screen dimensions
46 cebix 1.1
47    
48     // Prototypes
49     static void create_volumes_pane(GtkWidget *top);
50     static void create_graphics_pane(GtkWidget *top);
51 gbeauche 1.2 static void create_input_pane(GtkWidget *top);
52 cebix 1.1 static void create_serial_pane(GtkWidget *top);
53     static void create_memory_pane(GtkWidget *top);
54 gbeauche 1.3 static void create_jit_pane(GtkWidget *top);
55 cebix 1.1 static void read_settings(void);
56    
57    
58     /*
59     * Utility functions
60     */
61    
62 gbeauche 1.15 #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 cebix 1.1 struct opt_desc {
69     int label_id;
70     GtkSignalFunc func;
71     };
72    
73 gbeauche 1.15 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 cebix 1.1 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));
113     gtk_widget_show(item);
114     gtk_signal_connect(GTK_OBJECT(item), "activate", func, NULL);
115     gtk_menu_append(GTK_MENU(menu), item);
116     }
117    
118     static GtkWidget *make_pane(GtkWidget *notebook, int title_id)
119     {
120     GtkWidget *frame, *label, *box;
121    
122     frame = gtk_frame_new(NULL);
123     gtk_container_border_width(GTK_CONTAINER(frame), 4);
124    
125     box = gtk_vbox_new(FALSE, 4);
126     gtk_container_set_border_width(GTK_CONTAINER(box), 4);
127     gtk_container_add(GTK_CONTAINER(frame), box);
128 gbeauche 1.18
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 cebix 1.1 return box;
134     }
135    
136     static GtkWidget *make_button_box(GtkWidget *top, int border, const opt_desc *buttons)
137     {
138     GtkWidget *bb, *button;
139    
140     bb = gtk_hbutton_box_new();
141     gtk_widget_show(bb);
142     gtk_container_set_border_width(GTK_CONTAINER(bb), border);
143     gtk_button_box_set_layout(GTK_BUTTON_BOX(bb), GTK_BUTTONBOX_DEFAULT_STYLE);
144     gtk_button_box_set_spacing(GTK_BUTTON_BOX(bb), 4);
145     gtk_box_pack_start(GTK_BOX(top), bb, FALSE, FALSE, 0);
146    
147     while (buttons->label_id) {
148     button = gtk_button_new_with_label(GetString(buttons->label_id));
149     gtk_widget_show(button);
150     gtk_signal_connect_object(GTK_OBJECT(button), "clicked", buttons->func, NULL);
151     gtk_box_pack_start(GTK_BOX(bb), button, TRUE, TRUE, 0);
152     buttons++;
153     }
154     return bb;
155     }
156    
157     static GtkWidget *make_separator(GtkWidget *top)
158     {
159     GtkWidget *sep = gtk_hseparator_new();
160     gtk_box_pack_start(GTK_BOX(top), sep, FALSE, FALSE, 0);
161     gtk_widget_show(sep);
162     return sep;
163     }
164    
165     static GtkWidget *make_table(GtkWidget *top, int x, int y)
166     {
167     GtkWidget *table = gtk_table_new(x, y, FALSE);
168     gtk_widget_show(table);
169     gtk_box_pack_start(GTK_BOX(top), table, FALSE, FALSE, 0);
170     return table;
171     }
172    
173 gbeauche 1.15 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 cebix 1.1 static GtkWidget *make_option_menu(GtkWidget *top, int label_id, const opt_desc *options, int active)
254     {
255     GtkWidget *box, *label, *opt, *menu;
256    
257     box = gtk_hbox_new(FALSE, 4);
258     gtk_widget_show(box);
259     gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0);
260    
261     label = gtk_label_new(GetString(label_id));
262     gtk_widget_show(label);
263     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
264    
265     opt = gtk_option_menu_new();
266     gtk_widget_show(opt);
267     menu = gtk_menu_new();
268    
269     while (options->label_id) {
270     add_menu_item(menu, options->label_id, options->func);
271     options++;
272     }
273     gtk_menu_set_active(GTK_MENU(menu), active);
274    
275     gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
276     gtk_box_pack_start(GTK_BOX(box), opt, FALSE, FALSE, 0);
277     return menu;
278     }
279    
280     static GtkWidget *make_entry(GtkWidget *top, int label_id, const char *prefs_item)
281     {
282     GtkWidget *box, *label, *entry;
283    
284     box = gtk_hbox_new(FALSE, 4);
285     gtk_widget_show(box);
286     gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0);
287    
288     label = gtk_label_new(GetString(label_id));
289     gtk_widget_show(label);
290     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
291    
292     entry = gtk_entry_new();
293     gtk_widget_show(entry);
294     const char *str = PrefsFindString(prefs_item);
295     if (str == NULL)
296     str = "";
297     gtk_entry_set_text(GTK_ENTRY(entry), str);
298     gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0);
299     return entry;
300     }
301    
302 gbeauche 1.12 static const gchar *get_file_entry_path(GtkWidget *entry)
303 gbeauche 1.2 {
304     return gtk_entry_get_text(GTK_ENTRY(entry));
305     }
306    
307 cebix 1.1 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));
310     gtk_widget_show(button);
311     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), PrefsFindBool(prefs_item));
312     gtk_signal_connect(GTK_OBJECT(button), "toggled", func, button);
313     gtk_box_pack_start(GTK_BOX(top), button, FALSE, FALSE, 0);
314     return button;
315     }
316    
317     static GtkWidget *make_checkbox(GtkWidget *top, int label_id, bool active, GtkSignalFunc func)
318     {
319     GtkWidget *button = gtk_check_button_new_with_label(GetString(label_id));
320     gtk_widget_show(button);
321     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), active);
322     gtk_signal_connect(GTK_OBJECT(button), "toggled", func, button);
323     gtk_box_pack_start(GTK_BOX(top), button, FALSE, FALSE, 0);
324     return button;
325     }
326    
327    
328     /*
329     * Show preferences editor
330     * Returns true when user clicked on "Start", false otherwise
331     */
332    
333     // Window closed
334     static gint window_closed(void)
335     {
336     return FALSE;
337     }
338    
339     // Window destroyed
340     static void window_destroyed(void)
341     {
342     gtk_main_quit();
343     }
344    
345     // "Start" button clicked
346     static void cb_start(...)
347     {
348     start_clicked = true;
349     read_settings();
350     SavePrefs();
351     gtk_widget_destroy(win);
352     }
353    
354     // "Quit" button clicked
355     static void cb_quit(...)
356     {
357     start_clicked = false;
358     gtk_widget_destroy(win);
359     }
360    
361     // "OK" button of "About" dialog clicked
362     static void dl_quit(GtkWidget *dialog)
363     {
364     gtk_widget_destroy(dialog);
365     }
366    
367     // "About" selected
368     static void mn_about(...)
369     {
370     GtkWidget *dialog, *label, *button;
371    
372     char str[512];
373     sprintf(str,
374     "SheepShaver\nVersion %d.%d\n\n"
375 gbeauche 1.16 "Copyright (C) 1997-2005 Christian Bauer and Marc Hellwig\n"
376     "E-mail: cb@cebix.net\n"
377     "http://sheepshaver.cebix.net/\n\n"
378 cebix 1.1 "SheepShaver comes with ABSOLUTELY NO\n"
379     "WARRANTY. This is free software, and\n"
380     "you are welcome to redistribute it\n"
381     "under the terms of the GNU General\n"
382     "Public License.\n",
383     VERSION_MAJOR, VERSION_MINOR
384     );
385    
386     dialog = gtk_dialog_new();
387     gtk_window_set_title(GTK_WINDOW(dialog), GetString(STR_ABOUT_TITLE));
388     gtk_container_border_width(GTK_CONTAINER(dialog), 5);
389     gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
390    
391     label = gtk_label_new(str);
392     gtk_widget_show(label);
393     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
394    
395     button = gtk_button_new_with_label(GetString(STR_OK_BUTTON));
396     gtk_widget_show(button);
397     gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
398     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
399     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
400     gtk_widget_grab_default(button);
401     gtk_widget_show(dialog);
402     }
403    
404     // "Zap NVRAM" selected
405     static void mn_zap_pram(...)
406     {
407     ZapPRAM();
408     }
409    
410     // Menu item descriptions
411     static GtkItemFactoryEntry menu_items[] = {
412     {(gchar *)GetString(STR_PREFS_MENU_FILE_GTK), NULL, NULL, 0, "<Branch>"},
413 gbeauche 1.15 {(gchar *)GetString(STR_PREFS_ITEM_START_GTK), "<control>S", GTK_SIGNAL_FUNC(cb_start), 0, NULL},
414 cebix 1.1 {(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},
417     {(gchar *)GetString(STR_HELP_MENU_GTK), NULL, NULL, 0, "<LastBranch>"},
418     {(gchar *)GetString(STR_HELP_ITEM_ABOUT_GTK), NULL, GTK_SIGNAL_FUNC(mn_about), 0, NULL}
419     };
420    
421     bool PrefsEditor(void)
422     {
423 gbeauche 1.13 // Get screen dimensions
424     screen_width = gdk_screen_width();
425     screen_height = gdk_screen_height();
426    
427 cebix 1.1 // Create window
428     win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
429     gtk_window_set_title(GTK_WINDOW(win), GetString(STR_PREFS_TITLE));
430     gtk_signal_connect(GTK_OBJECT(win), "delete_event", GTK_SIGNAL_FUNC(window_closed), NULL);
431     gtk_signal_connect(GTK_OBJECT(win), "destroy", GTK_SIGNAL_FUNC(window_destroyed), NULL);
432    
433     // Create window contents
434     GtkWidget *box = gtk_vbox_new(FALSE, 4);
435     gtk_widget_show(box);
436     gtk_container_add(GTK_CONTAINER(win), box);
437    
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 gbeauche 1.12 #if GTK_CHECK_VERSION(1,3,15)
442     gtk_window_add_accel_group(GTK_WINDOW(win), accel_group);
443     #else
444 cebix 1.1 gtk_accel_group_attach(accel_group, GTK_OBJECT(win));
445 gbeauche 1.12 #endif
446 cebix 1.1 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();
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 gbeauche 1.18 gtk_widget_realize(notebook);
455 cebix 1.1
456     create_volumes_pane(notebook);
457     create_graphics_pane(notebook);
458 gbeauche 1.2 create_input_pane(notebook);
459 cebix 1.1 create_serial_pane(notebook);
460     create_memory_pane(notebook);
461 gbeauche 1.3 create_jit_pane(notebook);
462 gbeauche 1.18 gtk_widget_show(notebook);
463 cebix 1.1
464     static const opt_desc buttons[] = {
465     {STR_START_BUTTON, GTK_SIGNAL_FUNC(cb_start)},
466     {STR_QUIT_BUTTON, GTK_SIGNAL_FUNC(cb_quit)},
467     {0, NULL}
468     };
469     make_button_box(box, 4, buttons);
470    
471     // Show window and enter main loop
472     gtk_widget_show(win);
473     gtk_main();
474     return start_clicked;
475     }
476    
477    
478     /*
479     * "Volumes" pane
480     */
481    
482     static GtkWidget *volume_list, *w_extfs;
483     static int selected_volume;
484    
485     // Volume in list selected
486     static void cl_selected(GtkWidget *list, int row, int column)
487     {
488     selected_volume = row;
489     }
490    
491     // Volume selected for addition
492     static void add_volume_ok(GtkWidget *button, file_req_assoc *assoc)
493     {
494 gbeauche 1.12 gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
495 cebix 1.1 gtk_clist_append(GTK_CLIST(volume_list), &file);
496     gtk_widget_destroy(assoc->req);
497     delete assoc;
498     }
499    
500     // Volume selected for creation
501     static void create_volume_ok(GtkWidget *button, file_req_assoc *assoc)
502     {
503 gbeauche 1.12 gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
504 cebix 1.1
505 gbeauche 1.12 const gchar *str = gtk_entry_get_text(GTK_ENTRY(assoc->entry));
506 cebix 1.1 int size = atoi(str);
507    
508     char cmd[1024];
509     sprintf(cmd, "dd if=/dev/zero \"of=%s\" bs=1024k count=%d", file, size);
510     int ret = system(cmd);
511     if (ret == 0)
512     gtk_clist_append(GTK_CLIST(volume_list), &file);
513     gtk_widget_destroy(GTK_WIDGET(assoc->req));
514     delete assoc;
515     }
516    
517     // "Add Volume" button clicked
518     static void cb_add_volume(...)
519     {
520     GtkWidget *req = gtk_file_selection_new(GetString(STR_ADD_VOLUME_TITLE));
521     gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
522     gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(add_volume_ok), new file_req_assoc(req, NULL));
523     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
524     gtk_widget_show(req);
525     }
526    
527     // "Create Hardfile" button clicked
528     static void cb_create_volume(...)
529     {
530     GtkWidget *req = gtk_file_selection_new(GetString(STR_CREATE_VOLUME_TITLE));
531    
532     GtkWidget *box = gtk_hbox_new(FALSE, 4);
533     gtk_widget_show(box);
534     GtkWidget *label = gtk_label_new(GetString(STR_HARDFILE_SIZE_CTRL));
535     gtk_widget_show(label);
536     GtkWidget *entry = gtk_entry_new();
537     gtk_widget_show(entry);
538     char str[32];
539     sprintf(str, "%d", 40);
540     gtk_entry_set_text(GTK_ENTRY(entry), str);
541     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
542     gtk_box_pack_start(GTK_BOX(box), entry, FALSE, FALSE, 0);
543     gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(req)->main_vbox), box, FALSE, FALSE, 0);
544    
545     gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
546     gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(create_volume_ok), new file_req_assoc(req, entry));
547     gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
548     gtk_widget_show(req);
549     }
550    
551     // "Remove Volume" button clicked
552     static void cb_remove_volume(...)
553     {
554     gtk_clist_remove(GTK_CLIST(volume_list), selected_volume);
555     }
556    
557     // "Boot From" selected
558     static void mn_boot_any(...) {PrefsReplaceInt32("bootdriver", 0);}
559     static void mn_boot_cdrom(...) {PrefsReplaceInt32("bootdriver", CDROMRefNum);}
560    
561     // "No CD-ROM Driver" button toggled
562     static void tb_nocdrom(GtkWidget *widget)
563     {
564     PrefsReplaceBool("nocdrom", GTK_TOGGLE_BUTTON(widget)->active);
565     }
566    
567     // Read settings from widgets and set preferences
568     static void read_volumes_settings(void)
569     {
570     while (PrefsFindString("disk"))
571     PrefsRemoveItem("disk");
572    
573     for (int i=0; i<GTK_CLIST(volume_list)->rows; i++) {
574     char *str;
575     gtk_clist_get_text(GTK_CLIST(volume_list), i, 0, &str);
576     PrefsAddString("disk", str);
577     }
578    
579     PrefsReplaceString("extfs", gtk_entry_get_text(GTK_ENTRY(w_extfs)));
580     }
581    
582     // Create "Volumes" pane
583     static void create_volumes_pane(GtkWidget *top)
584     {
585     GtkWidget *box, *scroll, *menu;
586    
587     box = make_pane(top, STR_VOLUMES_PANE_TITLE);
588    
589     scroll = gtk_scrolled_window_new(NULL, NULL);
590     gtk_widget_show(scroll);
591     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
592     volume_list = gtk_clist_new(1);
593     gtk_widget_show(volume_list);
594     gtk_clist_set_selection_mode(GTK_CLIST(volume_list), GTK_SELECTION_SINGLE);
595     gtk_clist_set_shadow_type(GTK_CLIST(volume_list), GTK_SHADOW_NONE);
596     gtk_clist_set_reorderable(GTK_CLIST(volume_list), true);
597     gtk_signal_connect(GTK_OBJECT(volume_list), "select_row", GTK_SIGNAL_FUNC(cl_selected), NULL);
598     char *str;
599     int32 index = 0;
600     while ((str = (char *)PrefsFindString("disk", index++)) != NULL)
601     gtk_clist_append(GTK_CLIST(volume_list), &str);
602     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), volume_list);
603     gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 0);
604     selected_volume = 0;
605    
606     static const opt_desc buttons[] = {
607     {STR_ADD_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_add_volume)},
608     {STR_CREATE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_create_volume)},
609     {STR_REMOVE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_remove_volume)},
610     {0, NULL},
611     };
612     make_button_box(box, 0, buttons);
613     make_separator(box);
614    
615     w_extfs = make_entry(box, STR_EXTFS_CTRL, "extfs");
616    
617     static const opt_desc options[] = {
618     {STR_BOOT_ANY_LAB, GTK_SIGNAL_FUNC(mn_boot_any)},
619     {STR_BOOT_CDROM_LAB, GTK_SIGNAL_FUNC(mn_boot_cdrom)},
620     {0, NULL}
621     };
622     int bootdriver = PrefsFindInt32("bootdriver"), active = 0;
623     switch (bootdriver) {
624     case 0: active = 0; break;
625     case CDROMRefNum: active = 1; break;
626     }
627     menu = make_option_menu(box, STR_BOOTDRIVER_CTRL, options, active);
628    
629     make_checkbox(box, STR_NOCDROM_CTRL, "nocdrom", GTK_SIGNAL_FUNC(tb_nocdrom));
630     }
631    
632    
633     /*
634 gbeauche 1.3 * "JIT Compiler" pane
635     */
636    
637 gbeauche 1.18 // 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 gbeauche 1.3 // 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 gbeauche 1.18 bool jit_enabled = is_jit_capable() && PrefsFindBool("jit");
675 gbeauche 1.3 }
676    
677 gbeauche 1.10 // "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 gbeauche 1.3 // 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 gbeauche 1.18
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 gbeauche 1.10 make_checkbox(box, STR_JIT_68K_CTRL, "jit68k", GTK_SIGNAL_FUNC(tb_jit_68k));
697 gbeauche 1.3 }
698    
699    
700     /*
701 cebix 1.1 * "Graphics/Sound" pane
702     */
703    
704 gbeauche 1.13 // 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 gbeauche 1.14 static bool is_fbdev_dga_mode = false;
715 cebix 1.1
716 gbeauche 1.4 static GtkWidget *w_dspdevice_file, *w_mixerdevice_file;
717    
718 gbeauche 1.13 // 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 cebix 1.1 // "5 Hz".."60Hz" selected
746     static void mn_5hz(...) {PrefsReplaceInt32("frameskip", 12);}
747     static void mn_7hz(...) {PrefsReplaceInt32("frameskip", 8);}
748     static void mn_10hz(...) {PrefsReplaceInt32("frameskip", 6);}
749     static void mn_15hz(...) {PrefsReplaceInt32("frameskip", 4);}
750     static void mn_30hz(...) {PrefsReplaceInt32("frameskip", 2);}
751     static void mn_60hz(...) {PrefsReplaceInt32("frameskip", 1);}
752    
753 gbeauche 1.9 // QuickDraw acceleration
754     static void tb_gfxaccel(GtkWidget *widget)
755     {
756     PrefsReplaceBool("gfxaccel", GTK_TOGGLE_BUTTON(widget)->active);
757     }
758    
759 gbeauche 1.4 // Set sensitivity of widgets
760     static void set_graphics_sensitive(void)
761     {
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 cebix 1.1 // "Disable Sound Output" button toggled
768     static void tb_nosound(GtkWidget *widget)
769     {
770     PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active);
771 gbeauche 1.4 set_graphics_sensitive();
772 cebix 1.1 }
773    
774 gbeauche 1.13 // Read and convert graphics preferences
775     static void parse_graphics_prefs(void)
776     {
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 gbeauche 1.14 #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 gbeauche 1.13 }
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 cebix 1.1 // Read settings from widgets and set preferences
838     static void read_graphics_settings(void)
839     {
840 gbeauche 1.13 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 gbeauche 1.14 bool use_screen_mode = true;
850 gbeauche 1.13 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 gbeauche 1.14 use_screen_mode = false;
859 gbeauche 1.13 PrefsRemoveItem("screen");
860     return;
861     }
862 gbeauche 1.14 if (use_screen_mode) {
863     PrefsReplaceString("screen", pref);
864     // Old prefs are now migrated
865     PrefsRemoveItem("windowmodes");
866     PrefsRemoveItem("screenmodes");
867     }
868 gbeauche 1.13
869 gbeauche 1.4 PrefsReplaceString("dsp", get_file_entry_path(w_dspdevice_file));
870     PrefsReplaceString("mixer", get_file_entry_path(w_mixerdevice_file));
871 cebix 1.1 }
872    
873     // Create "Graphics/Sound" pane
874     static void create_graphics_pane(GtkWidget *top)
875     {
876 gbeauche 1.13 GtkWidget *box, *table, *label, *opt, *menu, *combo;
877     char str[32];
878    
879     parse_graphics_prefs();
880 cebix 1.1
881     box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE);
882 gbeauche 1.13 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 cebix 1.1
888 gbeauche 1.13 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 cebix 1.1 switch (frameskip) {
920 gbeauche 1.13 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 cebix 1.1 }
928 gbeauche 1.13 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 cebix 1.1
937 gbeauche 1.13 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     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 gbeauche 1.9
954 gbeauche 1.13 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 cebix 1.1
958 gbeauche 1.13 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     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 cebix 1.1
975 gbeauche 1.13 make_checkbox(box, STR_GFXACCEL_CTRL, PrefsFindBool("gfxaccel"), GTK_SIGNAL_FUNC(tb_gfxaccel));
976 cebix 1.1
977 gbeauche 1.4 make_separator(box);
978 cebix 1.1 make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound));
979 gbeauche 1.4 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 gbeauche 1.13
984     hide_show_graphics_widgets();
985 gbeauche 1.2 }
986    
987    
988     /*
989     * "Input" pane
990     */
991    
992     static GtkWidget *w_keycode_file;
993 gbeauche 1.5 static GtkWidget *w_mouse_wheel_lines;
994 gbeauche 1.2
995     // Set sensitivity of widgets
996     static void set_input_sensitive(void)
997     {
998 gbeauche 1.15 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 gbeauche 1.5 gtk_widget_set_sensitive(w_mouse_wheel_lines, PrefsFindInt32("mousewheelmode") == 1);
1002 gbeauche 1.2 }
1003    
1004     // "Use Raw Keycodes" button toggled
1005     static void tb_keycodes(GtkWidget *widget)
1006     {
1007     PrefsReplaceBool("keycodes", GTK_TOGGLE_BUTTON(widget)->active);
1008     set_input_sensitive();
1009     }
1010    
1011 gbeauche 1.5 // "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 gbeauche 1.2 // Read settings from widgets and set preferences
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 gbeauche 1.5
1024     PrefsReplaceInt32("mousewheellines", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_mouse_wheel_lines)));
1025 gbeauche 1.2 }
1026    
1027     // Create "Input" pane
1028     static void create_input_pane(GtkWidget *top)
1029     {
1030 gbeauche 1.15 GtkWidget *box, *hbox, *menu, *label, *button;
1031 gbeauche 1.2 GtkObject *adj;
1032    
1033     box = make_pane(top, STR_INPUT_PANE_TITLE);
1034    
1035     make_checkbox(box, STR_KEYCODES_CTRL, "keycodes", GTK_SIGNAL_FUNC(tb_keycodes));
1036 gbeauche 1.15
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 gbeauche 1.5
1058     make_separator(box);
1059    
1060     static const opt_desc options[] = {
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 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     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 gbeauche 1.2
1085     set_input_sensitive();
1086 cebix 1.1 }
1087    
1088    
1089     /*
1090     * "Serial/Network" pane
1091     */
1092    
1093     static GtkWidget *w_seriala, *w_serialb, *w_ether;
1094    
1095     // Read settings from widgets and set preferences
1096     static void read_serial_settings(void)
1097     {
1098     const char *str;
1099    
1100     str = gtk_entry_get_text(GTK_ENTRY(w_seriala));
1101     PrefsReplaceString("seriala", str);
1102    
1103     str = gtk_entry_get_text(GTK_ENTRY(w_serialb));
1104     PrefsReplaceString("serialb", str);
1105    
1106     str = gtk_entry_get_text(GTK_ENTRY(w_ether));
1107     if (str && strlen(str))
1108     PrefsReplaceString("ether", str);
1109     else
1110     PrefsRemoveItem("ether");
1111     }
1112    
1113     // Add names of serial devices
1114     static gint gl_str_cmp(gconstpointer a, gconstpointer b)
1115     {
1116     return strcmp((char *)a, (char *)b);
1117     }
1118    
1119     static GList *add_serial_names(void)
1120     {
1121     GList *glist = NULL;
1122    
1123     // Search /dev for ttyS* and lp*
1124     DIR *d = opendir("/dev");
1125     if (d) {
1126     struct dirent *de;
1127     while ((de = readdir(d)) != NULL) {
1128 gbeauche 1.7 #if defined(__linux__)
1129 cebix 1.1 if (strncmp(de->d_name, "ttyS", 4) == 0 || strncmp(de->d_name, "lp", 2) == 0) {
1130 gbeauche 1.7 #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 cebix 1.1 char *str = new char[64];
1140     sprintf(str, "/dev/%s", de->d_name);
1141     glist = g_list_append(glist, str);
1142     }
1143     }
1144     closedir(d);
1145     }
1146     if (glist)
1147     g_list_sort(glist, gl_str_cmp);
1148     else
1149     glist = g_list_append(glist, (void *)"<none>");
1150     return glist;
1151     }
1152    
1153     // Add names of ethernet interfaces
1154     static GList *add_ether_names(void)
1155     {
1156     GList *glist = NULL;
1157    
1158     // Get list of all Ethernet interfaces
1159     int s = socket(PF_INET, SOCK_DGRAM, 0);
1160     if (s >= 0) {
1161     char inbuf[8192];
1162     struct ifconf ifc;
1163     ifc.ifc_len = sizeof(inbuf);
1164     ifc.ifc_buf = inbuf;
1165     if (ioctl(s, SIOCGIFCONF, &ifc) == 0) {
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 gbeauche 1.7 #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 cebix 1.1 if (ioctl(s, SIOCGIFHWADDR, &req) == 0 && req.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
1173 gbeauche 1.7 #else
1174     if (false) {
1175     #endif
1176 cebix 1.1 char *str = new char[64];
1177     strncpy(str, ifr->ifr_name, 63);
1178     glist = g_list_append(glist, str);
1179     }
1180     }
1181     }
1182     close(s);
1183     }
1184 gbeauche 1.15 #ifdef HAVE_SLIRP
1185     static char s_slirp[] = "slirp";
1186     glist = g_list_append(glist, s_slirp);
1187     #endif
1188 cebix 1.1 if (glist)
1189     g_list_sort(glist, gl_str_cmp);
1190     else
1191     glist = g_list_append(glist, (void *)"<none>");
1192     return glist;
1193     }
1194    
1195     // Create "Serial/Network" pane
1196     static void create_serial_pane(GtkWidget *top)
1197     {
1198     GtkWidget *box, *table, *label, *combo;
1199     GList *glist = add_serial_names();
1200    
1201     box = make_pane(top, STR_SERIAL_NETWORK_PANE_TITLE);
1202     table = make_table(box, 2, 3);
1203    
1204     label = gtk_label_new(GetString(STR_SERPORTA_CTRL));
1205     gtk_widget_show(label);
1206     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1207    
1208     combo = gtk_combo_new();
1209     gtk_widget_show(combo);
1210     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1211     const char *str = PrefsFindString("seriala");
1212     if (str == NULL)
1213     str = "";
1214     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1215     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1216     w_seriala = GTK_COMBO(combo)->entry;
1217    
1218     label = gtk_label_new(GetString(STR_SERPORTB_CTRL));
1219     gtk_widget_show(label);
1220     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1221    
1222     combo = gtk_combo_new();
1223     gtk_widget_show(combo);
1224     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1225     str = PrefsFindString("serialb");
1226     if (str == NULL)
1227     str = "";
1228     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1229     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 1, 2, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1230     w_serialb = GTK_COMBO(combo)->entry;
1231    
1232     label = gtk_label_new(GetString(STR_ETHERNET_IF_CTRL));
1233     gtk_widget_show(label);
1234     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
1235    
1236     glist = add_ether_names();
1237     combo = gtk_combo_new();
1238     gtk_widget_show(combo);
1239     gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
1240     str = PrefsFindString("ether");
1241     if (str == NULL)
1242     str = "";
1243     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str);
1244     gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
1245     w_ether = GTK_COMBO(combo)->entry;
1246     }
1247    
1248    
1249     /*
1250     * "Memory/Misc" pane
1251     */
1252    
1253 gbeauche 1.15 static GtkWidget *w_ramsize;
1254 cebix 1.1 static GtkWidget *w_rom_file;
1255    
1256 gbeauche 1.9 // 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 cebix 1.1 // "Ignore SEGV" button toggled
1263     static void tb_ignoresegv(GtkWidget *widget)
1264     {
1265     PrefsReplaceBool("ignoresegv", GTK_TOGGLE_BUTTON(widget)->active);
1266     }
1267    
1268     // Read settings from widgets and set preferences
1269     static void read_memory_settings(void)
1270     {
1271 gbeauche 1.15 const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_ramsize)->entry));
1272     PrefsReplaceInt32("ramsize", atoi(str) << 20);
1273 cebix 1.1
1274 gbeauche 1.15 str = gtk_entry_get_text(GTK_ENTRY(w_rom_file));
1275 cebix 1.1 if (str && strlen(str))
1276     PrefsReplaceString("rom", str);
1277     else
1278     PrefsRemoveItem("rom");
1279     }
1280    
1281     // Create "Memory/Misc" pane
1282     static void create_memory_pane(GtkWidget *top)
1283     {
1284 gbeauche 1.15 GtkWidget *box, *hbox, *table, *label, *menu;
1285 cebix 1.1
1286     box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE);
1287 gbeauche 1.15 table = make_table(box, 2, 5);
1288 cebix 1.1
1289 gbeauche 1.15 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     0
1299     };
1300     char default_ramsize[10];
1301     sprintf(default_ramsize, "%d", PrefsFindInt32("ramsize") >> 20);
1302     w_ramsize = table_make_combobox(table, 0, STR_RAMSIZE_CTRL, default_ramsize, options);
1303 cebix 1.1
1304 gbeauche 1.15 w_rom_file = table_make_file_entry(table, 1, STR_ROM_FILE_CTRL, "rom");
1305 cebix 1.1
1306     make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv));
1307 gbeauche 1.9 make_checkbox(box, STR_IDLEWAIT_CTRL, "idlewait", GTK_SIGNAL_FUNC(tb_idlewait));
1308 cebix 1.1 }
1309    
1310    
1311     /*
1312     * Read settings from widgets and set preferences
1313     */
1314    
1315     static void read_settings(void)
1316     {
1317     read_volumes_settings();
1318     read_graphics_settings();
1319 gbeauche 1.17 read_input_settings();
1320 cebix 1.1 read_serial_settings();
1321     read_memory_settings();
1322 gbeauche 1.3 read_jit_settings();
1323 cebix 1.1 }
1324 gbeauche 1.17
1325    
1326     #ifdef STANDALONE_GUI
1327     #include <errno.h>
1328     #include <sys/wait.h>
1329     #include "rpc.h"
1330    
1331     /*
1332     * Fake unused data and functions
1333     */
1334    
1335     uint8 XPRAM[XPRAM_SIZE];
1336     void MountVolume(void *fh) { }
1337     void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) { }
1338    
1339     #if defined __APPLE__ && defined __MACH__
1340 gbeauche 1.19 void DarwinSysInit(void) { }
1341     void DarwinSysExit(void) { }
1342 gbeauche 1.17 void DarwinAddFloppyPrefs(void) { }
1343     void DarwinAddSerialPrefs(void) { }
1344     bool DarwinCDReadTOC(char *, uint8 *) { }
1345     #endif
1346    
1347    
1348     /*
1349     * Display alert
1350     */
1351    
1352     static void dl_destroyed(void)
1353     {
1354     gtk_main_quit();
1355     }
1356    
1357     static void display_alert(int title_id, int prefix_id, int button_id, const char *text)
1358     {
1359     char str[256];
1360     sprintf(str, GetString(prefix_id), text);
1361    
1362     GtkWidget *dialog = gtk_dialog_new();
1363     gtk_window_set_title(GTK_WINDOW(dialog), GetString(title_id));
1364     gtk_container_border_width(GTK_CONTAINER(dialog), 5);
1365     gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
1366     gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(dl_destroyed), NULL);
1367    
1368     GtkWidget *label = gtk_label_new(str);
1369     gtk_widget_show(label);
1370     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
1371    
1372     GtkWidget *button = gtk_button_new_with_label(GetString(button_id));
1373     gtk_widget_show(button);
1374     gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
1375     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
1376     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1377     gtk_widget_grab_default(button);
1378     gtk_widget_show(dialog);
1379    
1380     gtk_main();
1381     }
1382    
1383    
1384     /*
1385     * Display error alert
1386     */
1387    
1388     void ErrorAlert(const char *text)
1389     {
1390     display_alert(STR_ERROR_ALERT_TITLE, STR_GUI_ERROR_PREFIX, STR_QUIT_BUTTON, text);
1391     }
1392    
1393    
1394     /*
1395     * Display warning alert
1396     */
1397    
1398     void WarningAlert(const char *text)
1399     {
1400     display_alert(STR_WARNING_ALERT_TITLE, STR_GUI_WARNING_PREFIX, STR_OK_BUTTON, text);
1401     }
1402    
1403    
1404     /*
1405     * RPC handlers
1406     */
1407    
1408     static GMainLoop *g_gui_loop;
1409    
1410     static int handle_ErrorAlert(rpc_connection_t *connection)
1411     {
1412     D(bug("handle_ErrorAlert\n"));
1413    
1414     int error;
1415     char *str;
1416     if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0)
1417     return error;
1418    
1419     ErrorAlert(str);
1420     free(str);
1421     return RPC_ERROR_NO_ERROR;
1422     }
1423    
1424     static int handle_WarningAlert(rpc_connection_t *connection)
1425     {
1426     D(bug("handle_WarningAlert\n"));
1427    
1428     int error;
1429     char *str;
1430     if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0)
1431     return error;
1432    
1433     WarningAlert(str);
1434     free(str);
1435     return RPC_ERROR_NO_ERROR;
1436     }
1437    
1438     static int handle_Exit(rpc_connection_t *connection)
1439     {
1440     D(bug("handle_Exit\n"));
1441    
1442     g_main_quit(g_gui_loop);
1443     return RPC_ERROR_NO_ERROR;
1444     }
1445    
1446    
1447     /*
1448     * SIGCHLD handler
1449     */
1450    
1451     static char g_app_path[PATH_MAX];
1452     static rpc_connection_t *g_gui_connection = NULL;
1453    
1454     static void sigchld_handler(int sig, siginfo_t *sip, void *)
1455     {
1456     D(bug("Child %d exitted with status = %x\n", sip->si_pid, sip->si_status));
1457    
1458     // XXX perform a new wait because sip->si_status is sometimes not
1459     // the exit _value_ on MacOS X but rather the usual status field
1460     // from waitpid() -- we could arrange this code in some other way...
1461     int status;
1462     if (waitpid(sip->si_pid, &status, 0) < 0)
1463     status = sip->si_status;
1464     if (WIFEXITED(status))
1465     status = WEXITSTATUS(status);
1466     if (status & 0x80)
1467     status |= -1 ^0xff;
1468    
1469     if (status < 0) { // negative -> execlp/-errno
1470     char str[256];
1471     sprintf(str, GetString(STR_NO_B2_EXE_FOUND), g_app_path, strerror(-status));
1472     ErrorAlert(str);
1473     status = 1;
1474     }
1475    
1476     if (status != 0) {
1477     if (g_gui_connection)
1478     rpc_exit(g_gui_connection);
1479     exit(status);
1480     }
1481     }
1482    
1483    
1484     /*
1485     * Start standalone GUI
1486     */
1487    
1488     int main(int argc, char *argv[])
1489     {
1490     // Init GTK
1491     gtk_set_locale();
1492     gtk_init(&argc, &argv);
1493    
1494     // Read preferences
1495     PrefsInit(argc, argv);
1496    
1497     // Show preferences editor
1498     bool start = PrefsEditor();
1499    
1500     // Exit preferences
1501     PrefsExit();
1502    
1503     // Transfer control to the executable
1504     if (start) {
1505     char gui_connection_path[64];
1506     sprintf(gui_connection_path, "/org/SheepShaver/GUI/%d", getpid());
1507    
1508     // Catch exits from the child process
1509     struct sigaction sigchld_sa, old_sigchld_sa;
1510     sigemptyset(&sigchld_sa.sa_mask);
1511     sigchld_sa.sa_sigaction = sigchld_handler;
1512     sigchld_sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
1513     if (sigaction(SIGCHLD, &sigchld_sa, &old_sigchld_sa) < 0) {
1514     char str[256];
1515     sprintf(str, GetString(STR_SIG_INSTALL_ERR), SIGCHLD, strerror(errno));
1516     ErrorAlert(str);
1517     return 1;
1518     }
1519    
1520     // Search and run the SheepShaver executable
1521     char *p;
1522     strcpy(g_app_path, argv[0]);
1523     if ((p = strstr(g_app_path, "SheepShaverGUI.app/Contents/MacOS")) != NULL) {
1524     strcpy(p, "SheepShaver.app/Contents/MacOS/SheepShaver");
1525     if (access(g_app_path, X_OK) < 0) {
1526     char str[256];
1527     sprintf(str, GetString(STR_NO_B2_EXE_FOUND), g_app_path, strerror(errno));
1528     WarningAlert(str);
1529     strcpy(g_app_path, "/Applications/SheepShaver.app/Contents/MacOS/SheepShaver");
1530     }
1531     } else {
1532     p = strrchr(g_app_path, '/');
1533     p = p ? p + 1 : g_app_path;
1534     strcpy(p, "SheepShaver");
1535     }
1536    
1537     int pid = fork();
1538     if (pid == 0) {
1539     D(bug("Trying to execute %s\n", g_app_path));
1540     execlp(g_app_path, g_app_path, "--gui-connection", gui_connection_path, (char *)NULL);
1541     #ifdef _POSIX_PRIORITY_SCHEDULING
1542     // XXX get a chance to run the parent process so that to not confuse/upset GTK...
1543     sched_yield();
1544     #endif
1545     _exit(-errno);
1546     }
1547    
1548     // Establish a connection to Basilisk II
1549     if ((g_gui_connection = rpc_init_server(gui_connection_path)) == NULL) {
1550     printf("ERROR: failed to initialize GUI-side RPC server connection\n");
1551     return 1;
1552     }
1553     static const rpc_method_descriptor_t vtable[] = {
1554     { RPC_METHOD_ERROR_ALERT, handle_ErrorAlert },
1555     { RPC_METHOD_WARNING_ALERT, handle_WarningAlert },
1556     { RPC_METHOD_EXIT, handle_Exit }
1557     };
1558     if (rpc_method_add_callbacks(g_gui_connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) {
1559     printf("ERROR: failed to setup GUI method callbacks\n");
1560     return 1;
1561     }
1562     int socket;
1563     if ((socket = rpc_listen_socket(g_gui_connection)) < 0) {
1564     printf("ERROR: failed to initialize RPC server thread\n");
1565     return 1;
1566     }
1567    
1568     g_gui_loop = g_main_new(TRUE);
1569     while (g_main_is_running(g_gui_loop)) {
1570    
1571     // Process a few events pending
1572     const int N_EVENTS_DISPATCH = 10;
1573     for (int i = 0; i < N_EVENTS_DISPATCH; i++) {
1574     if (!g_main_iteration(FALSE))
1575     break;
1576     }
1577    
1578     // Check for RPC events (100 ms timeout)
1579     int ret = rpc_wait_dispatch(g_gui_connection, 100000);
1580     if (ret == 0)
1581     continue;
1582     if (ret < 0)
1583     break;
1584     rpc_dispatch(g_gui_connection);
1585     }
1586    
1587     rpc_exit(g_gui_connection);
1588     return 0;
1589     }
1590    
1591     return 0;
1592     }
1593     #endif