+\f
+/* GL crap */
+
+Visual *
+get_best_gl_visual (saver_info *si, Screen *screen)
+{
+ pid_t forked;
+ int fds [2];
+ int in, out;
+ int errfds[2];
+ int errin = -1, errout = -1;
+ char buf[1024];
+
+ char *av[10];
+ int ac = 0;
+
+ av[ac++] = "xscreensaver-gl-helper";
+ av[ac] = 0;
+
+ if (pipe (fds))
+ {
+ perror ("error creating pipe:");
+ return 0;
+ }
+
+ in = fds [0];
+ out = fds [1];
+
+ if (!si->prefs.verbose_p)
+ {
+ if (pipe (errfds))
+ {
+ perror ("error creating pipe:");
+ return 0;
+ }
+
+ errin = errfds [0];
+ errout = errfds [1];
+ }
+
+ block_sigchld(); /* This blocks it in the parent and child, to avoid
+ racing. It is never unblocked in the child before
+ the child exits, but that doesn't matter.
+ */
+
+ switch ((int) (forked = fork ()))
+ {
+ case -1:
+ {
+ sprintf (buf, "%s: couldn't fork", blurb());
+ perror (buf);
+ saver_exit (si, 1, 0);
+ }
+ case 0:
+ {
+ close (in); /* don't need this one */
+ close (ConnectionNumber (si->dpy)); /* close display fd */
+
+ if (dup2 (out, STDOUT_FILENO) < 0) /* pipe stdout */
+ {
+ perror ("could not dup() a new stdout:");
+ return 0;
+ }
+
+ if (! si->prefs.verbose_p)
+ {
+ close(errin);
+ if (dup2 (errout, STDERR_FILENO) < 0)
+ {
+ perror ("could not dup() a new stderr:");
+ return 0;
+ }
+ }
+
+ hack_subproc_environment (screen, 0); /* set $DISPLAY */
+
+ execvp (av[0], av); /* shouldn't return. */
+
+ if (errno != ENOENT /* || si->prefs.verbose_p */ )
+ {
+ /* Ignore "no such file or directory" errors.
+ Issue all other exec errors, though. */
+ sprintf (buf, "%s: running %s", blurb(), av[0]);
+ perror (buf);
+ }
+ exit (1); /* exits fork */
+ break;
+ }
+ default:
+ {
+ int result = 0;
+ int wait_status = 0;
+ pid_t pid = -1;
+
+ FILE *f = fdopen (in, "r");
+ unsigned long v = 0;
+ char c;
+
+ close (out); /* don't need this one */
+
+ *buf = 0;
+ if (! fgets (buf, sizeof(buf)-1, f))
+ *buf = 0;
+ fclose (f);
+
+ if (! si->prefs.verbose_p)
+ {
+ close (errout);
+ close (errin);
+ }
+
+ /* Wait for the child to die - wait for this pid only, not others. */
+ pid = waitpid (forked, &wait_status, 0);
+ if (si->prefs.debug_p)
+ {
+ write_string (STDERR_FILENO, blurb());
+ write_string (STDERR_FILENO, ": waitpid(");
+ write_long (STDERR_FILENO, (long) forked);
+ write_string (STDERR_FILENO, ") ==> ");
+ write_long (STDERR_FILENO, (long) pid);
+ write_string (STDERR_FILENO, "\n");
+ }
+
+ unblock_sigchld(); /* child is dead and waited, unblock now. */
+
+ if (1 == sscanf (buf, "0x%lx %c", &v, &c))
+ result = (int) v;
+
+ if (result == 0)
+ {
+ if (si->prefs.verbose_p)
+ {
+ int L = strlen(buf);
+ fprintf (stderr, "%s: %s did not report a GL visual!\n",
+ blurb(), av[0]);
+
+ if (L && buf[L-1] == '\n')
+ buf[--L] = 0;
+ if (*buf)
+ fprintf (stderr, "%s: %s said: \"%s\"\n",
+ blurb(), av[0], buf);
+ }
+ return 0;
+ }
+ else
+ {
+ Visual *v = id_to_visual (screen, result);
+ if (si->prefs.verbose_p)
+ fprintf (stderr, "%s: %d: %s: GL visual is 0x%X%s.\n",
+ blurb(), screen_number (screen),
+ av[0], result,
+ (v == DefaultVisualOfScreen (screen)
+ ? " (default)" : ""));
+ return v;
+ }
+ }
+ }
+
+ abort();
+}
+
+