X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=driver%2Fstderr.c;h=84fa697290d6268c34846fb36fb548ea56b8503a;hb=aa75c7476aeaa84cf3abc192b376a8b03c325213;hp=0c999e2fcfd55cdef991c2712069e15b3243b902;hpb=c6b273ef7292ba10943694df1656b05203d7b62f;p=xscreensaver diff --git a/driver/stderr.c b/driver/stderr.c index 0c999e2f..84fa6972 100644 --- a/driver/stderr.c +++ b/driver/stderr.c @@ -1,5 +1,5 @@ /* stderr.c --- capturing stdout/stderr output onto the screensaver window. - * xscreensaver, Copyright (c) 1991-1998 Jamie Zawinski + * xscreensaver, Copyright (c) 1991-2016 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -47,9 +47,14 @@ static char stderr_buffer [4096]; 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) { @@ -57,7 +62,7 @@ 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; @@ -75,6 +80,10 @@ reset_stderr (saver_screen_info *ssi) 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) { @@ -86,6 +95,8 @@ 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) { @@ -102,12 +113,13 @@ print_stderr_1 (saver_screen_info *ssi, char *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) @@ -117,7 +129,7 @@ print_stderr_1 (saver_screen_info *ssi, char *string) 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) @@ -126,8 +138,8 @@ print_stderr_1 (saver_screen_info *ssi, char *string) cmap = ssi->stderr_cmap; } - fg = get_pixel_resource ("overlayTextForeground","Foreground",dpy,cmap); - bg = get_pixel_resource ("overlayTextBackground","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; @@ -163,15 +175,17 @@ print_stderr_1 (saver_screen_info *ssi, char *string) 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 } @@ -202,12 +216,14 @@ make_stderr_overlay_window (saver_screen_info *ssi) { 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), @@ -224,13 +240,15 @@ make_stderr_overlay_window (saver_screen_info *ssi) 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) { @@ -246,6 +264,9 @@ 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) { @@ -268,6 +289,9 @@ 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) { @@ -277,6 +301,9 @@ 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; @@ -329,6 +356,10 @@ stderr_callback (XtPointer closure, int *fd, XtIntervalId *id) } } +/* 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) { @@ -339,7 +370,7 @@ 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; @@ -347,10 +378,9 @@ initialize_stderr (saver_info *si) 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)) @@ -392,6 +422,8 @@ initialize_stderr (saver_info *si) if (stderr_dialog_p) { FILE *new_stderr_file; + FILE *new_stdout_file; + new_stderr = dup (stderr_fd); if (new_stderr < 0) { @@ -411,11 +443,8 @@ initialize_stderr (saver_info *si) 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) { @@ -435,8 +464,97 @@ initialize_stderr (saver_info *si) 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(0)); +} + + +/* 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; + } +}