81
struct file_req_assoc {
82
file_req_assoc(GtkWidget *r, GtkWidget *e) : req(r), entry(e) {}
87
static void cb_browse_ok(GtkWidget *button, file_req_assoc *assoc)
89
gchar *file = (char *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
90
gtk_entry_set_text(GTK_ENTRY(assoc->entry), file);
91
gtk_widget_destroy(assoc->req);
95
static void cb_browse(GtkWidget *widget, void *user_data)
97
GtkWidget *req = gtk_file_selection_new(GetString(STR_BROWSE_TITLE));
98
gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
99
gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(cb_browse_ok), new file_req_assoc(req, (GtkWidget *)user_data));
100
gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req));
101
gtk_widget_show(req);
104
static GtkWidget *make_browse_button(GtkWidget *entry)
108
button = gtk_button_new_with_label(GetString(STR_BROWSE_CTRL));
109
gtk_widget_show(button);
110
gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc)cb_browse, (void *)entry);
72
114
static void add_menu_item(GtkWidget *menu, int label_id, GtkSignalFunc func)
74
116
GtkWidget *item = gtk_menu_item_new_with_label(GetString(label_id));
177
static GtkWidget *table_make_option_menu(GtkWidget *table, int row, int label_id, const opt_desc *options, int active)
179
GtkWidget *label, *opt, *menu;
181
label = gtk_label_new(GetString(label_id));
182
gtk_widget_show(label);
183
gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
185
opt = gtk_option_menu_new();
186
gtk_widget_show(opt);
187
menu = gtk_menu_new();
189
while (options->label_id) {
190
add_menu_item(menu, options->label_id, options->func);
193
gtk_menu_set_active(GTK_MENU(menu), active);
195
gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
196
gtk_table_attach(GTK_TABLE(table), opt, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
200
static GtkWidget *table_make_combobox(GtkWidget *table, int row, int label_id, const char *default_value, GList *glist)
202
GtkWidget *label, *combo;
205
label = gtk_label_new(GetString(label_id));
206
gtk_widget_show(label);
207
gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
209
combo = gtk_combo_new();
210
gtk_widget_show(combo);
211
gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist);
213
gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), default_value);
214
gtk_table_attach(GTK_TABLE(table), combo, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
219
static GtkWidget *table_make_combobox(GtkWidget *table, int row, int label_id, const char *default_value, const combo_desc *options)
222
while (options->label_id) {
223
glist = g_list_append(glist, (void *)GetString(options->label_id));
227
return table_make_combobox(table, row, label_id, default_value, glist);
230
static GtkWidget *table_make_file_entry(GtkWidget *table, int row, int label_id, const char *prefs_item, bool only_dirs = false)
232
GtkWidget *box, *label, *entry, *button;
234
label = gtk_label_new(GetString(label_id));
235
gtk_widget_show(label);
236
gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4);
238
const char *str = PrefsFindString(prefs_item);
242
box = gtk_hbox_new(FALSE, 4);
243
gtk_widget_show(box);
244
gtk_table_attach(GTK_TABLE(table), box, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4);
246
entry = gtk_entry_new();
247
gtk_entry_set_text(GTK_ENTRY(entry), str);
248
gtk_widget_show(entry);
249
gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0);
251
button = make_browse_button(entry);
252
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
253
g_object_set_data(G_OBJECT(entry), "chooser_button", button);
135
257
static GtkWidget *make_option_menu(GtkWidget *top, int label_id, const opt_desc *options, int active)
137
259
GtkWidget *box, *label, *opt, *menu;
1024
1163
// Create "Input" pane
1025
1164
static void create_input_pane(GtkWidget *top)
1027
GtkWidget *box, *hbox, *menu, *label;
1166
GtkWidget *box, *hbox, *menu, *label, *button;
1028
1167
GtkObject *adj;
1030
1169
box = make_pane(top, STR_INPUT_PANE_TITLE);
1032
1171
make_checkbox(box, STR_KEYCODES_CTRL, "keycodes", GTK_SIGNAL_FUNC(tb_keycodes));
1033
w_keycode_file = make_file_entry(box, STR_KEYCODE_FILE_CTRL, "keycodefile");
1173
hbox = gtk_hbox_new(FALSE, 4);
1174
gtk_widget_show(hbox);
1175
gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1177
label = gtk_label_new(GetString(STR_KEYCODES_CTRL));
1178
gtk_widget_show(label);
1179
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1181
const char *str = PrefsFindString("keycodefile");
1185
w_keycode_file = gtk_entry_new();
1186
gtk_entry_set_text(GTK_ENTRY(w_keycode_file), str);
1187
gtk_widget_show(w_keycode_file);
1188
gtk_box_pack_start(GTK_BOX(hbox), w_keycode_file, TRUE, TRUE, 0);
1190
button = make_browse_button(w_keycode_file);
1191
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1192
g_object_set_data(G_OBJECT(w_keycode_file), "chooser_button", button);
1035
1194
make_separator(box);
1309
1475
// Create "Memory/Misc" pane
1310
1476
static void create_memory_pane(GtkWidget *top)
1312
GtkWidget *box, *hbox, *vbox, *hbox2, *label, *scale;
1478
GtkWidget *box, *hbox, *table, *label, *menu;
1314
1480
box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE);
1316
hbox = gtk_hbox_new(FALSE, 4);
1317
gtk_widget_show(hbox);
1319
label = gtk_label_new(GetString(STR_RAMSIZE_SLIDER));
1320
gtk_widget_show(label);
1321
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1323
vbox = gtk_vbox_new(FALSE, 4);
1324
gtk_widget_show(vbox);
1329
w_ramsize_adj = gtk_adjustment_new(min, min, max, 1, 16, 0);
1330
gtk_adjustment_set_value(GTK_ADJUSTMENT(w_ramsize_adj), PrefsFindInt32("ramsize") >> 20);
1332
scale = gtk_hscale_new(GTK_ADJUSTMENT(w_ramsize_adj));
1333
gtk_widget_show(scale);
1334
gtk_scale_set_digits(GTK_SCALE(scale), 0);
1335
gtk_box_pack_start(GTK_BOX(vbox), scale, TRUE, TRUE, 0);
1337
hbox2 = gtk_hbox_new(FALSE, 4);
1338
gtk_widget_show(hbox2);
1341
sprintf(val, GetString(STR_RAMSIZE_FMT), int(min));
1342
label = gtk_label_new(val);
1343
gtk_widget_show(label);
1344
gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
1346
sprintf(val, GetString(STR_RAMSIZE_FMT), int(max));
1347
label = gtk_label_new(val);
1348
gtk_widget_show(label);
1349
gtk_box_pack_end(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
1350
gtk_box_pack_start(GTK_BOX(vbox), hbox2, TRUE, TRUE, 0);
1351
gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
1352
gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
1481
table = make_table(box, 2, 5);
1483
static const combo_desc options[] = {
1484
STR_RAMSIZE_2MB_LAB,
1485
STR_RAMSIZE_4MB_LAB,
1486
STR_RAMSIZE_8MB_LAB,
1487
STR_RAMSIZE_16MB_LAB,
1488
STR_RAMSIZE_32MB_LAB,
1489
STR_RAMSIZE_64MB_LAB,
1490
STR_RAMSIZE_128MB_LAB,
1491
STR_RAMSIZE_256MB_LAB,
1492
STR_RAMSIZE_512MB_LAB,
1493
STR_RAMSIZE_1024MB_LAB,
1496
char default_ramsize[10];
1497
sprintf(default_ramsize, "%d", PrefsFindInt32("ramsize") >> 20);
1498
w_ramsize = table_make_combobox(table, 0, STR_RAMSIZE_CTRL, default_ramsize, options);
1354
1500
static const opt_desc model_options[] = {
1355
1501
{STR_MODELID_5_LAB, GTK_SIGNAL_FUNC(mn_modelid_5)},
1405
1552
read_memory_settings();
1406
1553
read_jit_settings();
1557
#ifdef STANDALONE_GUI
1559
#include <sys/wait.h>
1563
* Fake unused data and functions
1566
uint8 XPRAM[XPRAM_SIZE];
1567
void MountVolume(void *fh) { }
1568
void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) { }
1570
#if defined __APPLE__ && defined __MACH__
1571
void DarwinSysInit(void) { }
1572
void DarwinSysExit(void) { }
1573
void DarwinAddFloppyPrefs(void) { }
1574
void DarwinAddSerialPrefs(void) { }
1575
bool DarwinCDReadTOC(char *, uint8 *) { }
1583
static void dl_destroyed(void)
1588
static void display_alert(int title_id, int prefix_id, int button_id, const char *text)
1591
sprintf(str, GetString(prefix_id), text);
1593
GtkWidget *dialog = gtk_dialog_new();
1594
gtk_window_set_title(GTK_WINDOW(dialog), GetString(title_id));
1595
gtk_container_border_width(GTK_CONTAINER(dialog), 5);
1596
gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
1597
gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(dl_destroyed), NULL);
1599
GtkWidget *label = gtk_label_new(str);
1600
gtk_widget_show(label);
1601
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
1603
GtkWidget *button = gtk_button_new_with_label(GetString(button_id));
1604
gtk_widget_show(button);
1605
gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
1606
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
1607
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1608
gtk_widget_grab_default(button);
1609
gtk_widget_show(dialog);
1616
* Display error alert
1619
void ErrorAlert(const char *text)
1621
display_alert(STR_ERROR_ALERT_TITLE, STR_GUI_ERROR_PREFIX, STR_QUIT_BUTTON, text);
1626
* Display warning alert
1629
void WarningAlert(const char *text)
1631
display_alert(STR_WARNING_ALERT_TITLE, STR_GUI_WARNING_PREFIX, STR_OK_BUTTON, text);
1639
static GMainLoop *g_gui_loop;
1641
static int handle_ErrorAlert(rpc_connection_t *connection)
1643
D(bug("handle_ErrorAlert\n"));
1647
if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0)
1652
return RPC_ERROR_NO_ERROR;
1655
static int handle_WarningAlert(rpc_connection_t *connection)
1657
D(bug("handle_WarningAlert\n"));
1661
if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0)
1666
return RPC_ERROR_NO_ERROR;
1669
static int handle_Exit(rpc_connection_t *connection)
1671
D(bug("handle_Exit\n"));
1673
g_main_quit(g_gui_loop);
1674
return RPC_ERROR_NO_ERROR;
1682
static char g_app_path[PATH_MAX];
1683
static rpc_connection_t *g_gui_connection = NULL;
1685
static void sigchld_handler(int sig, siginfo_t *sip, void *)
1687
D(bug("Child %d exitted with status = %x\n", sip->si_pid, sip->si_status));
1689
// XXX perform a new wait because sip->si_status is sometimes not
1690
// the exit _value_ on MacOS X but rather the usual status field
1691
// from waitpid() -- we could arrange this code in some other way...
1693
if (waitpid(sip->si_pid, &status, 0) < 0)
1694
status = sip->si_status;
1695
if (WIFEXITED(status))
1696
status = WEXITSTATUS(status);
1700
if (status < 0) { // negative -> execlp/-errno
1702
sprintf(str, GetString(STR_NO_B2_EXE_FOUND), g_app_path, strerror(-status));
1708
if (g_gui_connection)
1709
rpc_exit(g_gui_connection);
1716
* Start standalone GUI
1719
int main(int argc, char *argv[])
1724
sprintf(version, "%d.%d", VERSION_MAJOR, VERSION_MINOR);
1725
gnome_init("Basilisk II", version, argc, argv);
1729
gtk_init(&argc, &argv);
1733
PrefsInit(argc, argv);
1735
// Show preferences editor
1736
bool start = PrefsEditor();
1741
// Transfer control to the executable
1743
char gui_connection_path[64];
1744
sprintf(gui_connection_path, "/org/BasiliskII/GUI/%d", getpid());
1746
// Catch exits from the child process
1747
struct sigaction sigchld_sa, old_sigchld_sa;
1748
sigemptyset(&sigchld_sa.sa_mask);
1749
sigchld_sa.sa_sigaction = sigchld_handler;
1750
sigchld_sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
1751
if (sigaction(SIGCHLD, &sigchld_sa, &old_sigchld_sa) < 0) {
1753
sprintf(str, GetString(STR_SIG_INSTALL_ERR), SIGCHLD, strerror(errno));
1758
// Search and run the BasiliskII executable
1760
strcpy(g_app_path, argv[0]);
1761
if ((p = strstr(g_app_path, "BasiliskIIGUI.app/Contents/MacOS")) != NULL) {
1762
strcpy(p, "BasiliskII.app/Contents/MacOS/BasiliskII");
1763
if (access(g_app_path, X_OK) < 0) {
1765
sprintf(str, GetString(STR_NO_B2_EXE_FOUND), g_app_path, strerror(errno));
1767
strcpy(g_app_path, "/Applications/BasiliskII.app/Contents/MacOS/BasiliskII");
1770
p = strrchr(g_app_path, '/');
1771
p = p ? p + 1 : g_app_path;
1772
strcpy(p, "BasiliskII");
1777
D(bug("Trying to execute %s\n", g_app_path));
1778
execlp(g_app_path, g_app_path, "--gui-connection", gui_connection_path, (char *)NULL);
1779
#ifdef _POSIX_PRIORITY_SCHEDULING
1780
// XXX get a chance to run the parent process so that to not confuse/upset GTK...
1786
// Establish a connection to Basilisk II
1787
if ((g_gui_connection = rpc_init_server(gui_connection_path)) == NULL) {
1788
printf("ERROR: failed to initialize GUI-side RPC server connection\n");
1791
static const rpc_method_descriptor_t vtable[] = {
1792
{ RPC_METHOD_ERROR_ALERT, handle_ErrorAlert },
1793
{ RPC_METHOD_WARNING_ALERT, handle_WarningAlert },
1794
{ RPC_METHOD_EXIT, handle_Exit }
1796
if (rpc_method_add_callbacks(g_gui_connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) {
1797
printf("ERROR: failed to setup GUI method callbacks\n");
1801
if ((socket = rpc_listen_socket(g_gui_connection)) < 0) {
1802
printf("ERROR: failed to initialize RPC server thread\n");
1806
g_gui_loop = g_main_new(TRUE);
1807
while (g_main_is_running(g_gui_loop)) {
1809
// Process a few events pending
1810
const int N_EVENTS_DISPATCH = 10;
1811
for (int i = 0; i < N_EVENTS_DISPATCH; i++) {
1812
if (!g_main_iteration(FALSE))
1816
// Check for RPC events (100 ms timeout)
1817
int ret = rpc_wait_dispatch(g_gui_connection, 100000);
1822
rpc_dispatch(g_gui_connection);
1825
rpc_exit(g_gui_connection);