From 9b60acb2dafc4db9f1cdeaaa8fda74dbec038ef2 Mon Sep 17 00:00:00 2001 From: gbeauche <> Date: Mon, 1 May 2006 22:33:34 +0000 Subject: [PATCH] Port --enable-standalone-gui support to SheepShaver Others changes include: - Factor out STR_SIG_INSTALL_ERR messages - Process command line arguments early (prior to calling PrefsInit()) - GUI: set start_clicked only if the "Start" button was clicked - GUI: save changes to the "Input" pane when the "Start" button was clicked --- SheepShaver/Makefile | 1 + SheepShaver/src/Unix/Makefile.in | 52 +++- SheepShaver/src/Unix/configure.ac | 22 +- SheepShaver/src/Unix/main_unix.cpp | 85 +++++-- SheepShaver/src/Unix/prefs_editor_gtk.cpp | 275 ++++++++++++++++++++- SheepShaver/src/Unix/user_strings_unix.cpp | 6 +- SheepShaver/src/Unix/user_strings_unix.h | 8 +- 7 files changed, 415 insertions(+), 34 deletions(-) diff --git a/SheepShaver/Makefile b/SheepShaver/Makefile index 18ad6ad0..a6ac0715 100644 --- a/SheepShaver/Makefile +++ b/SheepShaver/Makefile @@ -67,6 +67,7 @@ links: Unix/video_blit.cpp Unix/config.sub Unix/config.guess Unix/m4 \ Unix/keycodes Unix/tunconfig Unix/clip_unix.cpp Unix/Irix/audio_irix.cpp \ Unix/Linux/scsi_linux.cpp Unix/Linux/NetDriver Unix/ether_unix.cpp \ + Unix/rpc.h Unix/rpc_unix.cpp Unix/Darwin/mkstandalone \ Unix/Darwin/lowmem.c Unix/Darwin/pagezero.c Unix/Darwin/testlmem.sh \ dummy/audio_dummy.cpp dummy/clip_dummy.cpp dummy/serial_dummy.cpp \ dummy/prefs_editor_dummy.cpp dummy/scsi_dummy.cpp SDL slirp \ diff --git a/SheepShaver/src/Unix/Makefile.in b/SheepShaver/src/Unix/Makefile.in index e3681265..c4ceb15e 100644 --- a/SheepShaver/src/Unix/Makefile.in +++ b/SheepShaver/src/Unix/Makefile.in @@ -42,6 +42,12 @@ SLIRP_CFLAGS = @SLIRP_CFLAGS@ 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 rpc_unix.cpp + # Append disassembler to dyngen, if available ifneq (:no,$(MONSRCS):$(USE_DYNGEN)) DYNGENSRCS += $(filter %i386-dis.c,$(MONSRCS)) @@ -55,18 +61,29 @@ SRCS = ../main.cpp main_unix.cpp ../prefs.cpp ../prefs_items.cpp prefs_unix.cpp ../gfxaccel.cpp ../video.cpp video_blit.cpp ../audio.cpp ../ether.cpp ../thunks.cpp \ ../serial.cpp ../extfs.cpp \ about_window_unix.cpp ../user_strings.cpp user_strings_unix.cpp \ - vm_alloc.cpp sigsegv.cpp \ + vm_alloc.cpp sigsegv.cpp rpc_unix.cpp \ sshpty.c strlcpy.c $(SYSSRCS) $(CPUSRCS) $(MONSRCS) $(SLIRP_SRCS) APP = SheepShaver APP_EXE = $(APP)$(EXEEXT) APP_APP = $(APP).app +PROGS = $(APP_EXE) +ifeq ($(STANDALONE_GUI),yes) +GUI_APP = SheepShaverGUI +GUI_APP_EXE = $(GUI_APP)$(EXEEXT) +GUI_APP_APP = $(GUI_APP).app +PROGS += $(GUI_APP_EXE) +endif + +CXXFLAGS += $(GUI_CFLAGS) +LIBS += $(GUI_LIBS) + ## Rules .PHONY: modules install uninstall clean distclean depend dep .SUFFIXES: .SUFFIXES: .c .cpp .S .o .h -all: $(APP_EXE) +all: $(PROGS) OBJ_DIR = obj $(OBJ_DIR):: @@ -78,6 +95,12 @@ define SRCS_LIST_TO_OBJS endef OBJS = $(SRCS_LIST_TO_OBJS) +define GUI_SRCS_LIST_TO_OBJS + $(addprefix $(OBJ_DIR)/, $(addsuffix .go, $(foreach file, $(GUI_SRCS), \ + $(basename $(notdir $(file)))))) +endef +GUI_OBJS = $(GUI_SRCS_LIST_TO_OBJS) + define DYNGENSRCS_LIST_TO_OBJS $(addprefix $(OBJ_DIR)/, $(addsuffix .dgo, $(foreach file, $(DYNGENSRCS), \ $(basename $(notdir $(file)))))) @@ -89,10 +112,13 @@ VPATH := VPATH += $(addprefix :, $(subst ,:, $(filter-out $($(subst, :, ,$(VPATH))), $(SRC_PATHS)))) $(APP_EXE): $(OBJ_DIR) $(OBJS) - $(CXX) -o $(APP_EXE) $(LDFLAGS) $(OBJS) $(LIBS) + $(CXX) -o $@ $(LDFLAGS) $(OBJS) $(LIBS) $(BLESS) $(APP_EXE) -$(APP)_app: $(APP) ../MacOSX/Info.plist ../MacOSX/SheepShaver.icns +$(GUI_APP_EXE): $(OBJ_DIR) $(GUI_OBJS) + $(CXX) -o $@ $(LDFLAGS) $(GUI_OBJS) $(GUI_LIBS) + +$(APP)_app: $(APP) ../MacOSX/Info.plist ../MacOSX/$(APP).icns mkdir -p $(APP_APP)/Contents cp -f ../MacOSX/Info.plist $(APP_APP)/Contents/ echo -n 'APPL????' > $(APP_APP)/Contents/PkgInfo @@ -102,11 +128,24 @@ $(APP)_app: $(APP) ../MacOSX/Info.plist ../MacOSX/SheepShaver.icns mkdir -p $(APP_APP)/Contents/Resources cp -f ../MacOSX/SheepShaver.icns $(APP_APP)/Contents/Resources/ +$(GUI_APP)_app: $(GUI_APP) ../MacOSX/Info.plist ../MacOSX/$(APP).icns + mkdir -p $(GUI_APP_APP)/Contents + sed -e "s/$(APP)/$(GUI_APP)/" < ../MacOSX/Info.plist > $(GUI_APP_APP)/Contents/Info.plist + echo -n 'APPL????' > $(GUI_APP_APP)/Contents/PkgInfo + mkdir -p $(GUI_APP_APP)/Contents/MacOS + cp -f $(GUI_APP) $(GUI_APP_APP)/Contents/MacOS/ + strip $(GUI_APP_APP)/Contents/MacOS/$(GUI_APP) + mkdir -p $(GUI_APP_APP)/Contents/Resources + cp -f ../MacOSX/$(APP).icns $(GUI_APP_APP)/Contents/Resources/$(GUI_APP).icns + modules: cd Linux/NetDriver; make -install: $(APP_EXE) installdirs +install: $(PROGS) installdirs $(INSTALL_PROGRAM) $(APP_EXE) $(DESTDIR)$(bindir)/$(APP_EXE) + if test -f "$(GUI_APP_EXE)"; then \ + $(INSTALL_PROGRAM) $(GUI_APP_EXE) $(DESTDIR)$(bindir)/$(GUI_APP_EXE); \ + fi -$(INSTALL_DATA) $(APP).1 $(DESTDIR)$(man1dir)/$(APP).1 $(INSTALL_DATA) $(KEYCODES) $(DESTDIR)$(datadir)/$(APP)/keycodes $(INSTALL_DATA) tunconfig $(DESTDIR)$(datadir)/$(APP)/tunconfig @@ -117,6 +156,7 @@ installdirs: uninstall: rm -f $(DESTDIR)$(bindir)/$(APP_EXE) + rm -f $(DESTDIR)$(bindir)/$(GUI_APP_EXE) rm -f $(DESTDIR)$(man1dir)/$(APP).1 rm -f $(DESTDIR)$(datadir)/$(APP)/keycodes rm -f $(DESTDIR)$(datadir)/$(APP)/tunconfig @@ -148,6 +188,8 @@ $(OBJ_DIR)/%.o : %.S $(CPP) $(CPPFLAGS) -D__ASSEMBLY__ $< -o $*.out.s $(AS) $(ASFLAGS) -o $@ $*.out.s rm $*.out.s +$(OBJ_DIR)/%.go : %.cpp + $(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) $(GUI_CFLAGS) -DSTANDALONE_GUI -c $< -o $@ # Kheperix CPU emulator kpxsrcdir = ../kpx_cpu/src diff --git a/SheepShaver/src/Unix/configure.ac b/SheepShaver/src/Unix/configure.ac index 331d0506..5e836393 100644 --- a/SheepShaver/src/Unix/configure.ac +++ b/SheepShaver/src/Unix/configure.ac @@ -28,6 +28,7 @@ AC_ARG_ENABLE(fbdev-dga, [ --enable-fbdev-dga use direct frame buffer a AC_ARG_ENABLE(xf86-dga, [ --enable-xf86-dga use the XFree86 DGA extension [default=yes]], [WANT_XF86_DGA=$enableval], [WANT_XF86_DGA=yes]) AC_ARG_ENABLE(xf86-vidmode, [ --enable-xf86-vidmode use the XFree86 VidMode extension [default=yes]], [WANT_XF86_VIDMODE=$enableval], [WANT_XF86_VIDMODE=yes]) AC_ARG_ENABLE(vosf, [ --enable-vosf enable video on SEGV signals [default=yes]], [WANT_VOSF=$enableval], [WANT_VOSF=yes]) +AC_ARG_ENABLE(standalone-gui,[ --enable-standalone-gui enable a standalone GUI prefs editor [default=no]], [WANT_STANDALONE_GUI=$enableval], [WANT_STANDALONE_GUI=no]) AC_ARG_WITH(esd, [ --with-esd support ESD for sound under Linux/FreeBSD [default=yes]], [WANT_ESD=$withval], [WANT_ESD=yes]) AC_ARG_WITH(gtk, [ --with-gtk use GTK user interface [default=yes]], [case "$withval" in @@ -246,9 +247,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 ], [ @@ -268,15 +268,25 @@ esac if [[ "x$WANT_GTK" = "xgtk" ]]; then AM_PATH_GTK(1.2.0, [ 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 ], [ AC_MSG_WARN([Could not find GTK+, disabling user interface.]) WANT_GTK=no ]) fi +AC_SUBST(GUI_CFLAGS) +AC_SUBST(GUI_LIBS) + +dnl Build external GUI if requested. +if [[ "$WANT_STANDALONE_GUI" != "yes" ]]; then + WANT_STANDALONE_GUI=no +fi +if [[ "$WANT_GTK" = "no" ]]; then + WANT_STANDALONE_GUI=no +fi +AC_SUBST(STANDALONE_GUI, [$WANT_STANDALONE_GUI]) dnl We use ESD if possible. if [[ "x$WANT_ESD" = "xyes" ]]; then diff --git a/SheepShaver/src/Unix/main_unix.cpp b/SheepShaver/src/Unix/main_unix.cpp index 1120bf1e..8d32c48f 100644 --- a/SheepShaver/src/Unix/main_unix.cpp +++ b/SheepShaver/src/Unix/main_unix.cpp @@ -110,6 +110,7 @@ #include "vm_alloc.h" #include "sigsegv.h" #include "sigregs.h" +#include "rpc.h" #define DEBUG 0 #include "debug.h" @@ -231,6 +232,9 @@ static sigregs sigsegv_regs; // Register dump when crashed static const char *crash_reason = NULL; // Reason of the crash (SIGSEGV, SIGBUS, SIGILL) #endif +static rpc_connection_t *gui_connection = NULL; // RPC connection to the GUI +static const char *gui_connection_path = NULL; // GUI connection identifier + uint32 SheepMem::page_size; // Size of a native page uintptr SheepMem::zero_page = 0; // Address of ro page filled in with zeros uintptr SheepMem::base = 0x60000000; // Address of SheepShaver data @@ -385,15 +389,6 @@ int main(int argc, char **argv) #endif #endif -#ifdef ENABLE_GTK - // Init GTK - gtk_set_locale(); - gtk_init(&argc, &argv); -#endif - - // Read preferences - PrefsInit(argc, argv); - // Parse command line arguments for (int i=1; i i) { + k -= i; + for (int j=i+k; j +#include +#include "rpc.h" + +/* + * Fake unused data and functions + */ + +uint8 XPRAM[XPRAM_SIZE]; +void MountVolume(void *fh) { } +void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) { } + +#if defined __APPLE__ && defined __MACH__ +void DarwinAddCDROMPrefs(void) { } +void DarwinAddFloppyPrefs(void) { } +void DarwinAddSerialPrefs(void) { } +bool DarwinCDReadTOC(char *, uint8 *) { } +#endif + + +/* + * Display alert + */ + +static void dl_destroyed(void) +{ + gtk_main_quit(); +} + +static void display_alert(int title_id, int prefix_id, int button_id, const char *text) +{ + char str[256]; + sprintf(str, GetString(prefix_id), text); + + GtkWidget *dialog = gtk_dialog_new(); + gtk_window_set_title(GTK_WINDOW(dialog), GetString(title_id)); + gtk_container_border_width(GTK_CONTAINER(dialog), 5); + gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150); + gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(dl_destroyed), NULL); + + GtkWidget *label = gtk_label_new(str); + gtk_widget_show(label); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0); + + GtkWidget *button = gtk_button_new_with_label(GetString(button_id)); + gtk_widget_show(button); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog)); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + gtk_widget_show(dialog); + + gtk_main(); +} + + +/* + * Display error alert + */ + +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 GMainLoop *g_gui_loop; + +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")); + + g_main_quit(g_gui_loop); + return RPC_ERROR_NO_ERROR; +} + + +/* + * SIGCHLD handler + */ + +static char g_app_path[PATH_MAX]; +static rpc_connection_t *g_gui_connection = NULL; + +static void sigchld_handler(int sig, siginfo_t *sip, void *) +{ + D(bug("Child %d exitted with status = %x\n", sip->si_pid, sip->si_status)); + + // XXX perform a new wait because sip->si_status is sometimes not + // the exit _value_ on MacOS X but rather the usual status field + // from waitpid() -- we could arrange this code in some other way... + int status; + if (waitpid(sip->si_pid, &status, 0) < 0) + status = sip->si_status; + if (WIFEXITED(status)) + status = WEXITSTATUS(status); + if (status & 0x80) + status |= -1 ^0xff; + + if (status < 0) { // negative -> execlp/-errno + char str[256]; + sprintf(str, GetString(STR_NO_B2_EXE_FOUND), g_app_path, strerror(-status)); + ErrorAlert(str); + status = 1; + } + + if (status != 0) { + if (g_gui_connection) + rpc_exit(g_gui_connection); + exit(status); + } +} + + +/* + * Start standalone GUI + */ + +int main(int argc, char *argv[]) +{ + // Init GTK + gtk_set_locale(); + gtk_init(&argc, &argv); + + // Read preferences + PrefsInit(argc, argv); + + // Show preferences editor + bool start = PrefsEditor(); + + // Exit preferences + PrefsExit(); + + // Transfer control to the executable + if (start) { + char gui_connection_path[64]; + sprintf(gui_connection_path, "/org/SheepShaver/GUI/%d", getpid()); + + // Catch exits from the child process + struct sigaction sigchld_sa, old_sigchld_sa; + sigemptyset(&sigchld_sa.sa_mask); + sigchld_sa.sa_sigaction = sigchld_handler; + sigchld_sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; + if (sigaction(SIGCHLD, &sigchld_sa, &old_sigchld_sa) < 0) { + char str[256]; + sprintf(str, GetString(STR_SIG_INSTALL_ERR), SIGCHLD, strerror(errno)); + ErrorAlert(str); + return 1; + } + + // Search and run the SheepShaver executable + char *p; + strcpy(g_app_path, argv[0]); + if ((p = strstr(g_app_path, "SheepShaverGUI.app/Contents/MacOS")) != NULL) { + strcpy(p, "SheepShaver.app/Contents/MacOS/SheepShaver"); + if (access(g_app_path, X_OK) < 0) { + char str[256]; + sprintf(str, GetString(STR_NO_B2_EXE_FOUND), g_app_path, strerror(errno)); + WarningAlert(str); + strcpy(g_app_path, "/Applications/SheepShaver.app/Contents/MacOS/SheepShaver"); + } + } else { + p = strrchr(g_app_path, '/'); + p = p ? p + 1 : g_app_path; + strcpy(p, "SheepShaver"); + } + + int pid = fork(); + if (pid == 0) { + D(bug("Trying to execute %s\n", g_app_path)); + execlp(g_app_path, g_app_path, "--gui-connection", gui_connection_path, (char *)NULL); +#ifdef _POSIX_PRIORITY_SCHEDULING + // XXX get a chance to run the parent process so that to not confuse/upset GTK... + sched_yield(); +#endif + _exit(-errno); + } + + // Establish a connection to Basilisk II + if ((g_gui_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(g_gui_connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) { + printf("ERROR: failed to setup GUI method callbacks\n"); + return 1; + } + int socket; + if ((socket = rpc_listen_socket(g_gui_connection)) < 0) { + printf("ERROR: failed to initialize RPC server thread\n"); + return 1; + } + + g_gui_loop = g_main_new(TRUE); + while (g_main_is_running(g_gui_loop)) { + + // Process a few events pending + const int N_EVENTS_DISPATCH = 10; + for (int i = 0; i < N_EVENTS_DISPATCH; i++) { + if (!g_main_iteration(FALSE)) + break; + } + + // Check for RPC events (100 ms timeout) + int ret = rpc_wait_dispatch(g_gui_connection, 100000); + if (ret == 0) + continue; + if (ret < 0) + break; + rpc_dispatch(g_gui_connection); + } + + rpc_exit(g_gui_connection); + return 0; + } + + return 0; +} +#endif diff --git a/SheepShaver/src/Unix/user_strings_unix.cpp b/SheepShaver/src/Unix/user_strings_unix.cpp index c2b25e94..a7febbf6 100644 --- a/SheepShaver/src/Unix/user_strings_unix.cpp +++ b/SheepShaver/src/Unix/user_strings_unix.cpp @@ -42,9 +42,7 @@ user_string_def platform_strings[] = { {STR_DR_EMULATOR_MMAP_ERR, "Cannot map DR Emulator: %s."}, {STR_SHEEP_MEM_MMAP_ERR, "Cannot map SheepShaver Data area: %s."}, {STR_SIGALTSTACK_ERR, "Cannot install alternate signal stack (%s). It seems that you need a newer kernel."}, - {STR_SIGSEGV_INSTALL_ERR, "Cannot install SIGSEGV handler: %s."}, - {STR_SIGILL_INSTALL_ERR, "Cannot install SIGILL handler: %s."}, - {STR_SIGUSR2_INSTALL_ERR, "Cannot install SIGUSR2 handler (%s). It seems that you need a newer libc."}, + {STR_SIG_INSTALL_ERR, "Cannot install %s handler (%s)."}, {STR_NO_XSERVER_ERR, "Cannot connect to X server %s."}, {STR_NO_XVISUAL_ERR, "Cannot obtain appropriate X visual."}, {STR_UNSUPP_DEPTH_ERR, "Unsupported color depth of screen."}, @@ -86,6 +84,8 @@ user_string_def platform_strings[] = { {STR_OPEN_WINDOW_ERR, "Cannot open Mac window."}, {STR_WINDOW_TITLE_GRABBED, "SheepShaver (mouse grabbed, press Ctrl-F5 to release)"}, + {STR_NO_B2_EXE_FOUND, "Could not start %s (%s)."}, + {-1, NULL} // End marker }; diff --git a/SheepShaver/src/Unix/user_strings_unix.h b/SheepShaver/src/Unix/user_strings_unix.h index 70ffc600..42526838 100644 --- a/SheepShaver/src/Unix/user_strings_unix.h +++ b/SheepShaver/src/Unix/user_strings_unix.h @@ -33,9 +33,7 @@ enum { STR_DR_EMULATOR_MMAP_ERR, STR_SHEEP_MEM_MMAP_ERR, STR_SIGALTSTACK_ERR, - STR_SIGSEGV_INSTALL_ERR, - STR_SIGILL_INSTALL_ERR, - STR_SIGUSR2_INSTALL_ERR, + STR_SIG_INSTALL_ERR, STR_NO_XSERVER_ERR, STR_NO_XVISUAL_ERR, STR_UNSUPP_DEPTH_ERR, @@ -78,7 +76,9 @@ enum { STR_MOUSEWHEELLINES_CTRL, STR_OPEN_WINDOW_ERR, - STR_WINDOW_TITLE_GRABBED + STR_WINDOW_TITLE_GRABBED, + + STR_NO_B2_EXE_FOUND }; #endif