From b0307c66a34a8cd62572212561007cd6b49b8f75 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 8 Dec 2012 15:33:14 -0500 Subject: [PATCH] Fork a child process for X11 message boxes, so setlocale() doesn't break stuff. --- src/video/x11/SDL_x11messagebox.c | 71 +++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/src/video/x11/SDL_x11messagebox.c b/src/video/x11/SDL_x11messagebox.c index 9c99937ae..e7d71e1d8 100644 --- a/src/video/x11/SDL_x11messagebox.c +++ b/src/video/x11/SDL_x11messagebox.c @@ -26,9 +26,20 @@ #include "SDL.h" #include "SDL_x11video.h" #include "SDL_x11dyn.h" +#include "SDL_assert.h" #include + +#define SDL_FORK_MESSAGEBOX 1 + +#if SDL_FORK_MESSAGEBOX +#include +#include +#include +#include +#endif + #define MAX_BUTTONS 8 /* Maximum number of buttons supported */ #define MAX_TEXT_LINES 32 /* Maximum number of text lines supported */ #define MIN_BUTTON_WIDTH 64 /* Minimum button width */ @@ -625,9 +636,8 @@ X11_MessageBoxLoop( SDL_MessageBoxDataX11 *data ) return 0; } -/* Display an x11 message box. */ -int -X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) +static int +X11_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int *buttonid) { int ret; SDL_MessageBoxDataX11 data; @@ -676,6 +686,61 @@ X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) return ret; } +/* Display an x11 message box. */ +int +X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) +{ +#if SDL_FORK_MESSAGEBOX + /* Use a child process to protect against setlocale(). Annoying. */ + pid_t pid; + int fds[2]; + int status = 0; + + if (pipe(fds) == -1) { + return X11_ShowMessageBoxImpl(messageboxdata, buttonid); /* oh well. */ + } + + pid = fork(); + if (pid == -1) { /* failed */ + close(fds[0]); + close(fds[1]); + return X11_ShowMessageBoxImpl(messageboxdata, buttonid); /* oh well. */ + } else if (pid == 0) { /* we're the child */ + int exitcode = 0; + close(fds[0]); + status = X11_ShowMessageBoxImpl(messageboxdata, buttonid); + if (write(fds[1], &status, sizeof (int)) != sizeof (int)) + exitcode = 1; + else if (write(fds[1], buttonid, sizeof (int)) != sizeof (int)) + exitcode = 1; + close(fds[1]); + _exit(exitcode); /* don't run atexit() stuff, static destructors, etc. */ + } else { /* we're the parent */ + pid_t rc; + close(fds[1]); + do { + rc = waitpid(pid, &status, 0); + } while ((rc == -1) && (errno == EINTR)); + + SDL_assert(rc == pid); /* not sure what to do if this fails. */ + + if ((rc == -1) || (!WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) { + SDL_SetError("msgbox child process failed"); + return -1; + } + + if (read(fds[0], &status, sizeof (int)) != sizeof (int)) + status = -1; + else if (read(fds[0], buttonid, sizeof (int)) != sizeof (int)) + status = -1; + close(fds[0]); + + return status; + } +#else + return X11_ShowMessageBoxImpl(messageboxdata, buttonid); +#endif +} #endif /* SDL_VIDEO_DRIVER_X11 */ /* vi: set ts=4 sw=4 expandtab: */