/* stderr.c --- capturing stdout/stderr output onto the screensaver window.
- * xscreensaver, Copyright (c) 1991-1997 Jamie Zawinski <jwz@netscape.com>
+ * xscreensaver, Copyright (c) 1991-2012 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
static char *stderr_tail = 0;
static time_t stderr_last_read = 0;
+static int stderr_stdout_read_fd = -1;
+
static void make_stderr_overlay_window (saver_screen_info *);
+/* Recreates the stderr window or GCs: do this when the xscreensaver window
+ on a screen has been re-created.
+ */
void
reset_stderr (saver_screen_info *ssi)
{
if (si->prefs.debug_p)
fprintf ((real_stderr ? real_stderr : stderr),
- "%s: resetting stderr\n", progname);
+ "%s: resetting stderr\n", blurb());
ssi->stderr_text_x = 0;
ssi->stderr_text_y = 0;
ssi->stderr_cmap = 0;
}
+/* Erases any stderr text overlaying the screen (if possible) and resets
+ the stderr output cursor to the upper left. Do this when the xscreensaver
+ window is cleared.
+ */
void
clear_stderr (saver_screen_info *ssi)
{
}
+/* Draws the string on the screen's window.
+ */
static void
print_stderr_1 (saver_screen_info *ssi, char *string)
{
saver_info *si = ssi->global;
- saver_preferences *p = &si->prefs;
Display *dpy = si->dpy;
Screen *screen = ssi->screen;
Window window = (ssi->stderr_overlay_window ?
char *head = string;
char *tail;
- /* In verbose mode, copy it to stderr as well. */
- if (p->verbose_p)
- fprintf (real_stderr, "%s", string);
-
if (! ssi->stderr_font)
{
- char *font_name = get_string_resource ("font", "Font");
- if (!font_name) font_name = "fixed";
+ char *font_name = get_string_resource (dpy, "font", "Font");
+ if (!font_name) font_name = strdup ("fixed");
ssi->stderr_font = XLoadQueryFont (dpy, font_name);
if (! ssi->stderr_font) ssi->stderr_font = XLoadQueryFont (dpy, "fixed");
ssi->stderr_line_height = (ssi->stderr_font->ascent +
ssi->stderr_font->descent);
+ free (font_name);
}
if (! ssi->stderr_gc)
Colormap cmap = ssi->cmap;
if (!ssi->stderr_overlay_window &&
- get_boolean_resource("overlayStderr", "Boolean"))
+ get_boolean_resource(dpy, "overlayStderr", "Boolean"))
{
make_stderr_overlay_window (ssi);
if (ssi->stderr_overlay_window)
cmap = ssi->stderr_cmap;
}
- fg = get_pixel_resource ("textForeground", "Foreground", dpy, cmap);
- bg = get_pixel_resource ("textBackground", "Background", dpy, cmap);
+ fg = get_pixel_resource (dpy,cmap,"overlayTextForeground","Foreground");
+ bg = get_pixel_resource (dpy,cmap,"overlayTextBackground","Background");
gcv.font = ssi->stderr_font->fid;
gcv.foreground = fg;
gcv.background = bg;
ssi->stderr_text_y = 0;
#else
int offset = ssi->stderr_line_height * 5;
+ XWindowAttributes xgwa;
+ XGetWindowAttributes (dpy, window, &xgwa);
+
XCopyArea (dpy, window, window, ssi->stderr_gc,
0, v_border + offset,
- WidthOfScreen (screen),
- (HeightOfScreen (screen) - v_border - v_border
- - offset),
+ xgwa.width,
+ (xgwa.height - v_border - v_border - offset),
0, v_border);
XClearArea (dpy, window,
- 0, HeightOfScreen (screen) - v_border - offset,
- WidthOfScreen (screen), offset, False);
+ 0, xgwa.height - v_border - offset,
+ xgwa.width, offset, False);
ssi->stderr_text_y -= offset;
#endif
}
{
int depth = visual_depth (ssi->screen, visual);
XSetWindowAttributes attrs;
+ XWindowAttributes xgwa;
unsigned long attrmask;
+ XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
if (si->prefs.debug_p)
fprintf(real_stderr,
"%s: using overlay visual 0x%0x for stderr text layer.\n",
- progname, (int) XVisualIDFromVisual (visual));
+ blurb(), (int) XVisualIDFromVisual (visual));
ssi->stderr_cmap = XCreateColormap(si->dpy,
RootWindowOfScreen(ssi->screen),
ssi->stderr_overlay_window =
XCreateWindow(si->dpy, ssi->screensaver_window, 0, 0,
- WidthOfScreen(ssi->screen), HeightOfScreen(ssi->screen),
+ xgwa.width, xgwa.height,
0, depth, InputOutput, visual, attrmask, &attrs);
XMapRaised(si->dpy, ssi->stderr_overlay_window);
}
}
+/* Draws the string on each screen's window as error text.
+ */
static void
print_stderr (saver_info *si, char *string)
{
}
+/* Polls the stderr buffer every few seconds and if it finds any text,
+ writes it on all screens.
+ */
static void
stderr_popup_timer_fn (XtPointer closure, XtIntervalId *id)
{
}
+/* Called when data becomes available on the stderr pipe. Copies it into
+ stderr_buffer where stderr_popup_timer_fn() can find it later.
+ */
static void
stderr_callback (XtPointer closure, int *fd, XtIntervalId *id)
{
int size;
int read_this_time = 0;
+ if (!fd || *fd < 0 || *fd != stderr_stdout_read_fd)
+ abort();
+
if (stderr_tail == 0)
stderr_tail = stderr_buffer;
}
}
+/* If stderr capturing is desired, this replaces `stdout' and `stderr'
+ with a pipe, so that any output written to them will show up on the
+ screen as well as on the original value of those streams.
+ */
void
initialize_stderr (saver_info *si)
{
int stdout_fd = 1;
int stderr_fd = 2;
int flags = 0;
- Boolean stderr_dialog_p, stdout_dialog_p;
+ Boolean stderr_dialog_p;
if (done) return;
done = True;
real_stderr = stderr;
real_stdout = stdout;
- stderr_dialog_p = get_boolean_resource ("captureStderr", "Boolean");
- stdout_dialog_p = get_boolean_resource ("captureStdout", "Boolean");
+ stderr_dialog_p = get_boolean_resource (si->dpy, "captureStderr", "Boolean");
- if (!stderr_dialog_p && !stdout_dialog_p)
+ if (!stderr_dialog_p)
return;
if (pipe (fds))
if (stderr_dialog_p)
{
FILE *new_stderr_file;
+ FILE *new_stdout_file;
+
new_stderr = dup (stderr_fd);
if (new_stderr < 0)
{
perror ("could not dup() a new stderr:");
return;
}
- }
- if (stdout_dialog_p)
- {
- FILE *new_stdout_file;
+
new_stdout = dup (stdout_fd);
if (new_stdout < 0)
{
perror ("could not dup() a new stdout:");
return;
}
+ close (out);
}
+ stderr_stdout_read_fd = in;
XtAppAddInput (si->app, in, (XtPointer) XtInputReadMask, stderr_callback,
(XtPointer) si);
}
+
+
+/* If the "-log file" command-line option has been specified,
+ open the file for append, and redirect stdout/stderr there.
+ This is called very early, before initialize_stderr().
+ */
+void
+stderr_log_file (saver_info *si)
+{
+ int stdout_fd = 1;
+ int stderr_fd = 2;
+ const char *filename = get_string_resource (si->dpy, "logFile", "LogFile");
+ int fd;
+
+ if (!filename || !*filename) return;
+
+ fd = open (filename, O_WRONLY | O_APPEND | O_CREAT, 0666);
+
+ if (fd < 0)
+ {
+ char buf[255];
+ FAIL:
+ sprintf (buf, "%.100s: %.100s", blurb(), filename);
+ perror (buf);
+ fflush (stderr);
+ fflush (stdout);
+ exit (1);
+ }
+
+ fprintf (stderr, "%s: logging to file %s\n", blurb(), filename);
+
+ if (dup2 (fd, stdout_fd) < 0) goto FAIL;
+ if (dup2 (fd, stderr_fd) < 0) goto FAIL;
+
+ fprintf (stderr, "\n\n"
+ "##########################################################################\n"
+ "%s: logging to \"%s\" at %s\n"
+ "##########################################################################\n"
+ "\n",
+ blurb(), filename, timestring());
+}
+
+
+/* If there is anything in the stderr buffer, flush it to the real stderr.
+ This does no X operations. Call this when exiting to make sure any
+ last words actually show up.
+ */
+void
+shutdown_stderr (saver_info *si)
+{
+ fflush (stdout);
+ fflush (stderr);
+
+ if (!real_stderr || stderr_stdout_read_fd < 0)
+ return;
+
+ stderr_callback ((XtPointer) si, &stderr_stdout_read_fd, 0);
+
+ if (stderr_tail &&
+ stderr_buffer < stderr_tail)
+ {
+ *stderr_tail = 0;
+ fprintf (real_stderr, "%s", stderr_buffer);
+ stderr_tail = stderr_buffer;
+ }
+
+ if (real_stdout) fflush (real_stdout);
+ if (real_stderr) fflush (real_stderr);
+
+ if (stdout != real_stdout)
+ {
+ dup2 (fileno(real_stdout), fileno(stdout));
+ fclose (real_stdout);
+ real_stdout = stdout;
+ }
+ if (stderr != real_stderr)
+ {
+ dup2 (fileno(real_stderr), fileno(stderr));
+ fclose (real_stderr);
+ real_stderr = stderr;
+ }
+ if (stderr_stdout_read_fd != -1)
+ {
+ close (stderr_stdout_read_fd);
+ stderr_stdout_read_fd = -1;
+ }
+}