Fork a child process for X11 message boxes, so setlocale() doesn't break stuff.
authorRyan C. Gordon <icculus@icculus.org>
Sat, 08 Dec 2012 15:33:14 -0500
changeset 6726 f2898757eaae
parent 6725 a7a99a9d419a
child 6727 1b5280cd5885
Fork a child process for X11 message boxes, so setlocale() doesn't break stuff.
src/video/x11/SDL_x11messagebox.c
--- a/src/video/x11/SDL_x11messagebox.c	Fri Dec 07 20:28:52 2012 -0800
+++ b/src/video/x11/SDL_x11messagebox.c	Sat Dec 08 15:33:14 2012 -0500
@@ -26,9 +26,20 @@
 #include "SDL.h"
 #include "SDL_x11video.h"
 #include "SDL_x11dyn.h"
+#include "SDL_assert.h"
 
 #include <locale.h>
 
+
+#define SDL_FORK_MESSAGEBOX 1
+
+#if SDL_FORK_MESSAGEBOX
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
+#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 @@
     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 @@
     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: */