/* subprocs.c --- choosing, spawning, and killing screenhacks.
- * xscreensaver, Copyright (c) 1991-2005 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1991-2008 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
#endif
#include <sys/time.h> /* sys/resource.h needs this for timeval */
+#include <sys/param.h> /* for PATH_MAX */
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h> /* for waitpid() and associated macros */
#define Widget void*
#include "xscreensaver.h"
+#include "exec.h"
#include "yarandom.h"
#include "visual.h" /* for id_to_visual() */
num = -num;
}
- while ((num > 0) && (num_digits < sizeof(string - 1)))
+ while ((num > 0) && (num_digits < sizeof(string) - 1))
{
int digit;
digit = (int) num % 10;
static struct screenhack_job *jobs = 0;
-/* for debugging -- nothing calls this, but it's useful to invoke from gdb. */
+/* for debugging -- nothing calls this, but it's useful to invoke from gdb.
+ */
+void show_job_list (void);
+
void
show_job_list (void)
{
block_sigchld (void)
{
#ifdef HAVE_SIGACTION
+ struct sigaction sa;
sigset_t child_set;
+
+ memset (&sa, 0, sizeof (sa));
+ sa.sa_handler = SIG_IGN;
+ sigaction (SIGPIPE, &sa, NULL);
+
sigemptyset (&child_set);
sigaddset (&child_set, SIGCHLD);
- sigaddset (&child_set, SIGPIPE);
sigprocmask (SIG_BLOCK, &child_set, 0);
-#endif /* HAVE_SIGACTION */
+
+#else /* !HAVE_SIGACTION */
+ signal (SIGPIPE, SIG_IGN);
+#endif /* !HAVE_SIGACTION */
block_sigchld_handler++;
unblock_sigchld (void)
{
#ifdef HAVE_SIGACTION
+ struct sigaction sa;
sigset_t child_set;
+
+ memset(&sa, 0, sizeof (sa));
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGPIPE, &sa, NULL);
+
sigemptyset(&child_set);
sigaddset(&child_set, SIGCHLD);
- sigaddset(&child_set, SIGPIPE);
sigprocmask(SIG_UNBLOCK, &child_set, 0);
-#endif /* HAVE_SIGACTION */
+
+#else /* !HAVE_SIGACTION */
+ signal(SIGPIPE, SIG_DFL);
+#endif /* !HAVE_SIGACTION */
block_sigchld_handler--;
}
case 0:
close (ConnectionNumber (si->dpy)); /* close display fd */
limit_subproc_memory (p->inferior_memory_limit, p->verbose_p);
- hack_subproc_environment (ssi); /* set $DISPLAY */
+ hack_subproc_environment (ssi->screen, ssi->screensaver_window);
if (p->verbose_p)
fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu.\n",
}
-static void
-spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
+void
+spawn_screenhack (saver_screen_info *ssi)
{
saver_info *si = ssi->global;
saver_preferences *p = &si->prefs;
- raise_window (si, first_time_p, True, False);
XFlush (si->dpy);
+ if (!monitor_powered_on_p (si))
+ {
+ if (si->prefs.verbose_p)
+ fprintf (stderr,
+ "%s: %d: X says monitor has powered down; "
+ "not launching a hack.\n", blurb(), ssi->number);
+ return;
+ }
+
if (p->screenhacks_count)
{
screenhack *hack;
break;
}
}
-}
-
-
-void
-spawn_screenhack (saver_info *si, Bool first_time_p)
-{
- if (monitor_powered_on_p (si))
- {
- int i;
- for (i = 0; i < si->nscreens; i++)
- {
- saver_screen_info *ssi = &si->screens[i];
- spawn_screenhack_1 (ssi, first_time_p);
- }
- }
- else if (si->prefs.verbose_p)
- fprintf (stderr,
- "%s: X says monitor has powered down; "
- "not launching a hack.\n", blurb());
- store_saver_status (si); /* store current hack numbers */
+ store_saver_status (si); /* store current hack number */
}
void
-kill_screenhack (saver_info *si)
+kill_screenhack (saver_screen_info *ssi)
{
- int i;
- for (i = 0; i < si->nscreens; i++)
- {
- saver_screen_info *ssi = &si->screens[i];
- if (ssi->pid)
- kill_job (si, ssi->pid, SIGTERM);
- ssi->pid = 0;
- }
+ saver_info *si = ssi->global;
+ if (ssi->pid)
+ kill_job (si, ssi->pid, SIGTERM);
+ ssi->pid = 0;
}
void
-suspend_screenhack (saver_info *si, Bool suspend_p)
+suspend_screenhack (saver_screen_info *ssi, Bool suspend_p)
{
#ifdef SIGSTOP /* older VMS doesn't have it... */
- int i;
- for (i = 0; i < si->nscreens; i++)
- {
- saver_screen_info *ssi = &si->screens[i];
- if (ssi->pid)
- kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
- }
+ saver_info *si = ssi->global;
+ if (ssi->pid)
+ kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
#endif /* SIGSTOP */
}
void
-hack_subproc_environment (saver_screen_info *ssi)
+hack_subproc_environment (Screen *screen, Window saver_window)
{
/* Store $DISPLAY into the environment, so that the $DISPLAY variable that
the spawned processes inherit is correct. First, it must be on the same
us to (eventually) run multiple hacks in Xinerama mode, where each hack
has the same $DISPLAY but a different piece of glass.
*/
- saver_info *si = ssi->global;
- const char *odpy = DisplayString (si->dpy);
+ Display *dpy = DisplayOfScreen (screen);
+ const char *odpy = DisplayString (dpy);
char *ndpy = (char *) malloc (strlen(odpy) + 20);
char *nssw = (char *) malloc (40);
- char *s;
+ char *s, *c;
strcpy (ndpy, "DISPLAY=");
s = ndpy + strlen(ndpy);
strcpy (s, odpy);
- while (*s && *s != ':') s++; /* skip to colon */
- while (*s == ':') s++; /* skip over colons */
+ /* We have to find the last colon since it is the boundary between
+ hostname & screen - IPv6 numeric format addresses may have many
+ colons before that point, and DECnet addresses always have two colons */
+ c = strrchr(s,':'); /* skip to last colon */
+ if (c != NULL) s = c+1;
while (isdigit(*s)) s++; /* skip over dpy number */
while (*s == '.') s++; /* skip over dot */
if (s[-1] != '.') *s++ = '.'; /* put on a dot */
- sprintf(s, "%d", ssi->real_screen_number); /* put on screen number */
+ sprintf(s, "%d", screen_number (screen)); /* put on screen number */
- sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX",
- (unsigned long) ssi->screensaver_window);
+ sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX", (unsigned long) saver_window);
/* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
any more, right? It's not Posix, but everyone seems to have it. */
/* GL crap */
Visual *
-get_best_gl_visual (saver_screen_info *ssi)
+get_best_gl_visual (saver_info *si, Screen *screen)
{
- saver_info *si = ssi->global;
pid_t forked;
int fds [2];
int in, out;
in = fds [0];
out = fds [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:
perror ("could not dup() a new stdout:");
return 0;
}
- hack_subproc_environment (ssi); /* set $DISPLAY */
+ hack_subproc_environment (screen, 0); /* set $DISPLAY */
execvp (av[0], av); /* shouldn't return. */
- if (errno != ENOENT || si->prefs.verbose_p)
+ if (errno != ENOENT /* || si->prefs.verbose_p */ )
{
- /* Ignore "no such file or directory" errors, unless verbose.
+ /* Ignore "no such file or directory" errors.
Issue all other exec errors, though. */
sprintf (buf, "%s: running %s", blurb(), av[0]);
perror (buf);
/* Wait for the child to die. */
waitpid (-1, &wait_status, 0);
+ unblock_sigchld(); /* child is dead and waited, unblock now. */
+
if (1 == sscanf (buf, "0x%lx %c", &v, &c))
result = (int) v;
}
else
{
- Visual *v = id_to_visual (ssi->screen, result);
+ 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(), ssi->number,
+ blurb(), screen_number (screen),
av[0], result,
- (v == ssi->default_visual ? " (default)" : ""));
+ (v == DefaultVisualOfScreen (screen)
+ ? " (default)" : ""));
return v;
}
}