Make Basilisk II main application not use GTK libraries when compiling with

STANDALONE_GUI. This is the second step towards a more interesting GUI alike
to VMware. Communication from/to the GUI is held by some lightweight RPC.

Note: The step should be enough to provide a tiny GTK GUI for MacOS X.
This commit is contained in:
gbeauche 2006-04-16 21:25:41 +00:00
parent 6994ab671e
commit 252f396ff3
6 changed files with 1408 additions and 25 deletions

View File

@ -36,8 +36,10 @@ SLIRP_SRCS = @SLIRP_SRCS@
SLIRP_OBJS = $(SLIRP_SRCS:../slirp/%.c=obj/%.o)
STANDALONE_GUI = @STANDALONE_GUI@
GUI_CFLAGS = @GUI_CFLAGS@
GUI_LIBS = @GUI_LIBS@
GUI_SRCS = ../prefs.cpp prefs_unix.cpp prefs_editor_gtk.cpp ../prefs_items.cpp \
../user_strings.cpp user_strings_unix.cpp xpram_unix.cpp sys_unix.cpp
../user_strings.cpp user_strings_unix.cpp xpram_unix.cpp sys_unix.cpp rpc_unix.cpp
## Files
SRCS = ../main.cpp main_unix.cpp ../prefs.cpp ../prefs_items.cpp prefs_unix.cpp \
@ -46,7 +48,7 @@ SRCS = ../main.cpp main_unix.cpp ../prefs.cpp ../prefs_items.cpp prefs_unix.cpp
timer_unix.cpp ../adb.cpp ../serial.cpp ../ether.cpp \
../sony.cpp ../disk.cpp ../cdrom.cpp ../scsi.cpp ../video.cpp video_blit.cpp \
vm_alloc.cpp sigsegv.cpp ../audio.cpp ../extfs.cpp \
../user_strings.cpp user_strings_unix.cpp sshpty.c strlcpy.c \
../user_strings.cpp user_strings_unix.cpp sshpty.c strlcpy.c rpc_unix.cpp \
$(SYSSRCS) $(CPUSRCS) $(SLIRP_SRCS)
APP = BasiliskII
APP_APP = $(APP).app
@ -55,6 +57,9 @@ PROGS = $(APP)$(EXEEXT)
ifeq ($(STANDALONE_GUI),yes)
GUI_APP = BasiliskIIGUI
PROGS += $(GUI_APP)$(EXEEXT)
else
CXXFLAGS += $(GUI_CFLAGS)
LIBS += $(GUI_LIBS)
endif
## Rules
@ -75,7 +80,7 @@ endef
OBJS = $(SRCS_LIST_TO_OBJS)
define GUI_SRCS_LIST_TO_OBJS
$(addprefix $(OBJ_DIR)/, $(addsuffix .o, $(foreach file, $(GUI_SRCS), \
$(addprefix $(OBJ_DIR)/, $(addsuffix .go, $(foreach file, $(GUI_SRCS), \
$(basename $(notdir $(file))))))
endef
GUI_OBJS = $(GUI_SRCS_LIST_TO_OBJS)
@ -89,7 +94,7 @@ $(APP)$(EXEEXT): $(OBJ_DIR) $(OBJS)
$(BLESS) $(APP)$(EXEEXT)
$(GUI_APP)$(EXEEXT): $(OBJ_DIR) $(GUI_OBJS)
$(CXX) -o $@ $(LDFLAGS) $(GUI_OBJS) $(LIBS)
$(CXX) -o $@ $(LDFLAGS) $(GUI_OBJS) $(LIBS) $(GUI_LIBS)
$(APP)_app: $(APP) ../MacOSX/Info.plist ../MacOSX/$(APP).icns
mkdir -p $(APP_APP)/Contents
@ -152,6 +157,8 @@ $(OBJ_DIR)/%.o : %.mm
$(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) -c $< -o $@
$(OBJ_DIR)/%.o : %.s
$(CC) $(CPPFLAGS) $(DEFS) $(CFLAGS) -c $< -o $@
$(OBJ_DIR)/%.go : %.cpp
$(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) $(GUI_CFLAGS) -c $< -o $@
# Windows resources
$(OBJ_DIR)/%.o: %.rc

View File

@ -254,9 +254,8 @@ case "x$WANT_GTK" in
xgtk2*)
AM_PATH_GTK_2_0(1.3.15, [
AC_DEFINE(ENABLE_GTK, 1, [Define if using GTK.])
CFLAGS="$CFLAGS $GTK_CFLAGS"
CXXFLAGS="$CXXFLAGS $GTK_CFLAGS"
LIBS="$LIBS $GTK_LIBS"
GUI_CFLAGS="$GTK_CFLAGS"
GUI_LIBS="$GTK_LIBS"
UISRCS=prefs_editor_gtk.cpp
WANT_GTK=gtk2
], [
@ -276,8 +275,8 @@ esac
if [[ "x$WANT_GTK" = "xgtk" ]]; then
AM_PATH_GTK(1.2.0, [
AC_DEFINE(ENABLE_GTK, 1, [Define if using GTK.])
CXXFLAGS="$CXXFLAGS $GTK_CFLAGS"
LIBS="$LIBS $GTK_LIBS"
GUI_CFLAGS="$GTK_CFLAGS"
GUI_LIBS="$GTK_LIBS"
UISRCS=prefs_editor_gtk.cpp
dnl somehow, <gnome-i18n.h> would redefine gettext() to nothing if
dnl ENABLE_NLS is not set, thusly conflicting with C++ <string> which
@ -285,14 +284,16 @@ if [[ "x$WANT_GTK" = "xgtk" ]]; then
AM_GNU_GETTEXT
B2_PATH_GNOMEUI([
AC_DEFINE(HAVE_GNOMEUI, 1, [Define if libgnomeui is available.])
CXXFLAGS="$CXXFLAGS $GNOMEUI_CFLAGS"
LIBS="$LIBS $GNOMEUI_LIBS"
GUI_CFLAGS="$GUI_CFLAGS $GNOMEUI_CFLAGS"
GUI_LIBS="$GUI_LIBS $GNOMEUI_LIBS"
], [])
], [
AC_MSG_WARN([Could not find GTK+, disabling user interface.])
WANT_GTK=no
])
fi
AC_SUBST(GUI_CFLAGS)
AC_SUBST(GUI_LIBS)
dnl Enable standalone GUI?
if [[ "$WANT_STANDALONE_GUI" != "yes" ]]; then

View File

@ -55,6 +55,11 @@ struct sigstate {
# define SS_USERREGS 0x04
#endif
#ifdef STANDALONE_GUI
# undef ENABLE_GTK
# include "rpc.h"
#endif
#ifdef ENABLE_GTK
# include <gtk/gtk.h>
# include <gdk/gdk.h>
@ -192,6 +197,11 @@ static void sigint_handler(...);
static bool lm_area_mapped = false; // Flag: Low Memory area mmap()ped
#endif
#ifdef STANDALONE_GUI
static rpc_connection_t *gui_connection; // RPC connection to the GUI
static const char *gui_connection_path; // GUI connection identifier
#endif
// Prototypes
static void *xpram_func(void *arg);
@ -412,6 +422,14 @@ int main(int argc, char **argv)
i++; // don't remove the argument, gtk_init() needs it too
if (i < argc)
x_display_name = strdup(argv[i]);
#endif
#ifdef STANDALONE_GUI
} else if (strcmp(argv[i], "--gui-connection") == 0) {
argv[i++] = NULL;
if (i < argc) {
gui_connection_path = argv[i];
argv[i] = NULL;
}
#endif
} else if (strcmp(argv[i], "--break") == 0) {
argv[i++] = NULL;
@ -446,6 +464,15 @@ int main(int argc, char **argv)
}
}
#ifdef STANDALONE_GUI
if (gui_connection_path) {
if ((gui_connection = rpc_init_client(gui_connection_path)) == NULL) {
fprintf(stderr, "Failed to initialize RPC client connection to the GUI\n");
return 1;
}
}
#endif
#ifdef ENABLE_GTK
#ifdef HAVE_GNOMEUI
// Init GNOME/GTK
@ -908,6 +935,14 @@ void QuitEmulator(void)
XCloseDisplay(x_display);
#endif
#ifdef STANDALONE_GUI
// Notify GUI we are about to leave
if (gui_connection) {
if (rpc_method_invoke(gui_connection, RPC_METHOD_EXIT, RPC_TYPE_INVALID) == RPC_ERROR_NO_ERROR)
rpc_method_wait_for_reply(gui_connection, RPC_TYPE_INVALID);
}
#endif
exit(0);
}
@ -1548,6 +1583,13 @@ void display_alert(int title_id, int prefix_id, int button_id, const char *text)
void ErrorAlert(const char *text)
{
#ifdef STANDALONE_GUI
if (gui_connection) {
if (rpc_method_invoke(gui_connection, RPC_METHOD_ERROR_ALERT, RPC_TYPE_STRING, text, RPC_TYPE_INVALID) == RPC_ERROR_NO_ERROR &&
rpc_method_wait_for_reply(gui_connection, RPC_TYPE_INVALID) == RPC_ERROR_NO_ERROR)
return;
}
#endif
#if defined(ENABLE_GTK) && !defined(USE_SDL_VIDEO)
if (PrefsFindBool("nogui") || x_display == NULL) {
printf(GetString(STR_SHELL_ERROR_PREFIX), text);
@ -1567,6 +1609,13 @@ void ErrorAlert(const char *text)
void WarningAlert(const char *text)
{
#ifdef STANDALONE_GUI
if (gui_connection) {
if (rpc_method_invoke(gui_connection, RPC_METHOD_WARNING_ALERT, RPC_TYPE_STRING, text, RPC_TYPE_INVALID) == RPC_ERROR_NO_ERROR &&
rpc_method_wait_for_reply(gui_connection, RPC_TYPE_INVALID) == RPC_ERROR_NO_ERROR)
return;
}
#endif
#if defined(ENABLE_GTK) && !defined(USE_SDL_VIDEO)
if (PrefsFindBool("nogui") || x_display == NULL) {
printf(GetString(STR_SHELL_WARNING_PREFIX), text);

View File

@ -39,6 +39,9 @@
#include "prefs.h"
#include "prefs_editor.h"
#define DEBUG 0
#include "debug.h"
// Global variables
static GtkWidget *win; // Preferences window
@ -1525,6 +1528,8 @@ static void read_settings(void)
#ifdef STANDALONE_GUI
#include <errno.h>
#include <sys/wait.h>
#include "rpc.h"
/*
* Fake unused data and functions
@ -1533,7 +1538,6 @@ static void read_settings(void)
uint8 XPRAM[XPRAM_SIZE];
void MountVolume(void *fh) { }
void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) { }
void WarningAlert(const char *text) { }
/*
@ -1576,12 +1580,62 @@ static void display_alert(int title_id, int prefix_id, int button_id, const char
* Display error alert
*/
static void ErrorAlert(const char *text)
void ErrorAlert(const char *text)
{
display_alert(STR_ERROR_ALERT_TITLE, STR_GUI_ERROR_PREFIX, STR_QUIT_BUTTON, text);
}
/*
* Display warning alert
*/
void WarningAlert(const char *text)
{
display_alert(STR_WARNING_ALERT_TITLE, STR_GUI_WARNING_PREFIX, STR_OK_BUTTON, text);
}
/*
* RPC handlers
*/
static int handle_ErrorAlert(rpc_connection_t *connection)
{
D(bug("handle_ErrorAlert\n"));
int error;
char *str;
if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0)
return error;
ErrorAlert(str);
free(str);
return RPC_ERROR_NO_ERROR;
}
static int handle_WarningAlert(rpc_connection_t *connection)
{
D(bug("handle_WarningAlert\n"));
int error;
char *str;
if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0)
return error;
WarningAlert(str);
free(str);
return RPC_ERROR_NO_ERROR;
}
static int handle_Exit(rpc_connection_t *connection)
{
D(bug("handle_Exit\n"));
return RPC_ERROR_NO_ERROR;
}
/*
* Start standalone GUI
*/
@ -1610,20 +1664,56 @@ int main(int argc, char *argv[])
// Transfer control to the executable
if (start) {
char gui_connection_path[64];
sprintf(gui_connection_path, "/org/BasiliskII/GUI/%d", getpid());
int pid = fork();
if (pid == 0) { // Child
char b2_path[PATH_MAX];
strcpy(b2_path, argv[0]);
char *p = strrchr(b2_path, '/');
p = p ? p + 1 : b2_path;
*p = '\0';
strcat(b2_path, "BasiliskII");
argv[0] = b2_path;
execv(b2_path, argv);
execl(b2_path, b2_path, "--gui-connection", gui_connection_path, (char *)NULL);
char str[256];
sprintf(str, GetString(STR_NO_B2_EXE_FOUND), b2_path, strerror(errno));
ErrorAlert(str);
return 1;
}
else { // Parent
rpc_connection_t *connection;
if ((connection = rpc_init_server(gui_connection_path)) == NULL) {
printf("ERROR: failed to initialize GUI-side RPC server connection\n");
return 1;
}
static const rpc_method_descriptor_t vtable[] = {
{ RPC_METHOD_ERROR_ALERT, handle_ErrorAlert },
{ RPC_METHOD_WARNING_ALERT, handle_WarningAlert },
{ RPC_METHOD_EXIT, handle_Exit }
};
if (rpc_method_add_callbacks(connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) {
printf("ERROR: failed to setup GUI method callbacks\n");
return 1;
}
if (rpc_listen(connection) < 0) {
printf("ERROR: failed to initialize RPC server thread\n");
return 1;
}
int status, ret = -1;
while (waitpid(pid, &status, 0) != pid)
;
if (WIFEXITED(status))
ret = WEXITSTATUS(status);
rpc_exit(connection);
return ret;
}
}
return 0;
}

101
BasiliskII/src/Unix/rpc.h Normal file
View File

@ -0,0 +1,101 @@
/*
* rpc.h - Remote Procedure Calls
*
* Basilisk II (C) 1997-2006 Christian Bauer
* Contributed by Gwenole Beauchesne
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef RPC_H
#define RPC_H
// Error Types
enum {
RPC_ERROR_NO_ERROR = 0,
RPC_ERROR_GENERIC = -1000,
RPC_ERROR_ERRNO_SET = -1001,
RPC_ERROR_NO_MEMORY = -1002,
RPC_ERROR_CONNECTION_NULL = -1003,
RPC_ERROR_CONNECTION_TYPE_MISMATCH = -1004,
RPC_ERROR_MESSAGE_TRUNCATED = -1005,
RPC_ERROR_MESSAGE_ARGUMENT_MISMATCH = -1006,
RPC_ERROR_MESSAGE_ARGUMENT_UNKNOWN = -1007,
};
// Connection Handling
typedef struct rpc_connection_t rpc_connection_t;
extern rpc_connection_t *rpc_init_server(const char *ident);
extern rpc_connection_t *rpc_init_client(const char *ident);
extern int rpc_exit(rpc_connection_t *connection);
extern int rpc_listen_socket(rpc_connection_t *connection);
extern int rpc_listen(rpc_connection_t *connection);
extern int rpc_dispatch(rpc_connection_t *connection);
extern int rpc_connection_busy(rpc_connection_t *connection);
// Message Passing
enum {
RPC_TYPE_INVALID = 0,
RPC_TYPE_CHAR = -2000,
RPC_TYPE_BOOLEAN = -2001,
RPC_TYPE_INT32 = -2002,
RPC_TYPE_UINT32 = -2003,
RPC_TYPE_STRING = -2004,
RPC_TYPE_ARRAY = -2005,
};
typedef struct rpc_message_t rpc_message_t;
extern int rpc_message_send_char(rpc_message_t *message, char c);
extern int rpc_message_send_int32(rpc_message_t *message, int32_t value);
extern int rpc_message_send_uint32(rpc_message_t *message, uint32_t value);
extern int rpc_message_send_string(rpc_message_t *message, const char *str);
extern int rpc_message_send_bytes(rpc_message_t *message, unsigned char *bytes, int count);
extern int rpc_message_recv_char(rpc_message_t *message, char *ret);
extern int rpc_message_recv_int32(rpc_message_t *message, int32_t *ret);
extern int rpc_message_recv_uint32(rpc_message_t *message, uint32_t *ret);
extern int rpc_message_recv_string(rpc_message_t *message, char **ret);
extern int rpc_message_recv_bytes(rpc_message_t *message, unsigned char *bytes, int count);
typedef int (*rpc_message_callback_t)(rpc_message_t *message, void *p_value);
typedef struct {
int id;
int size;
rpc_message_callback_t send_callback;
rpc_message_callback_t recv_callback;
} rpc_message_descriptor_t;
extern int rpc_message_add_callbacks(const rpc_message_descriptor_t *descs, int n_descs);
// Method Callbacks Handling
typedef int (*rpc_method_callback_t)(rpc_connection_t *connection);
typedef struct {
int id;
rpc_method_callback_t callback;
} rpc_method_descriptor_t;
extern int rpc_method_add_callbacks(rpc_connection_t *connection, const rpc_method_descriptor_t *descs, int n_descs);
extern int rpc_method_remove_callback_id(rpc_connection_t *connection, int id);
extern int rpc_method_remove_callbacks(rpc_connection_t *connection, const rpc_method_descriptor_t *descs, int n_descs);
// Remote Procedure Call (method invocation)
extern int rpc_method_invoke(rpc_connection_t *connection, int method, ...);
extern int rpc_method_wait_for_reply(rpc_connection_t *connection, ...);
extern int rpc_method_get_args(rpc_connection_t *connection, ...);
extern int rpc_method_send_reply(rpc_connection_t *connection, ...);
// Message Protocol
enum {
RPC_METHOD_ERROR_ALERT = 1,
RPC_METHOD_WARNING_ALERT,
RPC_METHOD_EXIT
};
#endif /* RPC_H */

File diff suppressed because it is too large Load Diff