http://ftp.x.org/contrib/applications/xscreensaver-2.24.tar.gz
[xscreensaver] / driver / stderr.c
index 2d18248779dcf7dd87c7e460e9b2606503bbff9f..0743a50e799e58733c2510615001cfb30b5455f5 100644 (file)
@@ -1,4 +1,5 @@
-/* xscreensaver, Copyright (c) 1991-1995 Jamie Zawinski <jwz@mcom.com>
+/* stderr.c --- capturing stdout/stderr output onto the screensaver window.
+ * xscreensaver, Copyright (c) 1991-1998 Jamie Zawinski <jwz@netscape.com>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
 /* stderr hackery - Why Unix Sucks, reason number 32767.
  */
 
-#if __STDC__
-#include <stdlib.h>
-#include <unistd.h>
+#ifdef HAVE_CONFIG_H
+# include "config.h"
 #endif
 
+#include <stdlib.h>
+
 #include <stdio.h>
-#include <fcntl.h>
 #include <time.h>
 
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL
+# include <fcntl.h>
+#endif
+
 #include <X11/Intrinsic.h>
 
 #include "xscreensaver.h"
+#include "resources.h"
+#include "visual.h"
 
-extern XtAppContext app;
-extern Colormap cmap;
-extern Window screensaver_window;
+FILE *real_stderr = 0;
+FILE *real_stdout = 0;
 
-extern char *get_string_resource P((char *, char *));
-extern Bool get_boolean_resource P((char *, char *));
-extern unsigned int get_pixel_resource P((char *, char *,
-                                         Display *, Colormap));
 
-static char stderr_buffer [1024];
+/* It's ok for these to be global, since they refer to the one and only
+   stderr stream, not to a particular screen or window or visual.
+ */
+static char stderr_buffer [4096];
 static char *stderr_tail = 0;
 static time_t stderr_last_read = 0;
-static XtIntervalId stderr_popup_timer = 0;
 
-FILE *real_stderr = 0;
-FILE *real_stdout = 0;
+static void make_stderr_overlay_window (saver_screen_info *);
+
+
+void
+reset_stderr (saver_screen_info *ssi)
+{
+  saver_info *si = ssi->global;
+
+  if (si->prefs.debug_p)
+    fprintf ((real_stderr ? real_stderr : stderr),
+            "%s: resetting stderr\n", blurb());
+
+  ssi->stderr_text_x = 0;
+  ssi->stderr_text_y = 0;
+
+  if (ssi->stderr_gc)
+    XFreeGC (si->dpy, ssi->stderr_gc);
+  ssi->stderr_gc = 0;
 
-static int text_x = 0;
-static int text_y = 0;
+  if (ssi->stderr_overlay_window)
+    XDestroyWindow(si->dpy, ssi->stderr_overlay_window);
+  ssi->stderr_overlay_window = 0;
+
+  if (ssi->stderr_cmap)
+    XFreeColormap(si->dpy, ssi->stderr_cmap);
+  ssi->stderr_cmap = 0;
+}
 
 void
-reset_stderr ()
+clear_stderr (saver_screen_info *ssi)
 {
-  text_x = text_y = 0;
+  saver_info *si = ssi->global;
+  ssi->stderr_text_x = 0;
+  ssi->stderr_text_y = 0;
+  if (ssi->stderr_overlay_window)
+    XClearWindow (si->dpy, ssi->stderr_overlay_window);
 }
 
+
 static void
-print_stderr (string)
-     char *string;
+print_stderr_1 (saver_screen_info *ssi, char *string)
 {
+  saver_info *si = ssi->global;
+  Display *dpy = si->dpy;
+  Screen *screen = ssi->screen;
+  Window window = (ssi->stderr_overlay_window ?
+                  ssi->stderr_overlay_window :
+                  ssi->screensaver_window);
   int h_border = 20;
   int v_border = 20;
-  static int line_height;
-  static XFontStruct *font = 0;
-  static GC gc = 0;
   char *head = string;
   char *tail;
 
-  /* In verbose mode, copy it to stderr as well. */
-  if (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";
+      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);
+    }
 
-  if (! gc)
+  if (! ssi->stderr_gc)
     {
       XGCValues gcv;
       Pixel fg, bg;
-      char *font_name = get_string_resource ("font", "Font");
-      if (!font_name) font_name = "fixed";
-      font = XLoadQueryFont (dpy, font_name);
-      if (! font) font = XLoadQueryFont (dpy, "fixed");
-      line_height = font->ascent + font->descent;
-      fg = get_pixel_resource ("textForeground", "Foreground", dpy, cmap);
-      bg = get_pixel_resource ("textBackground", "Background", dpy, cmap);
-      gcv.font = font->fid;
+      Colormap cmap = ssi->cmap;
+
+      if (!ssi->stderr_overlay_window &&
+         get_boolean_resource("overlayStderr", "Boolean"))
+       {
+         make_stderr_overlay_window (ssi);
+         if (ssi->stderr_overlay_window)
+           window = ssi->stderr_overlay_window;
+         if (ssi->stderr_cmap)
+           cmap = ssi->stderr_cmap;
+       }
+
+      fg = get_pixel_resource ("overlayTextForeground","Foreground",dpy,cmap);
+      bg = get_pixel_resource ("overlayTextBackground","Background",dpy,cmap);
+      gcv.font = ssi->stderr_font->fid;
       gcv.foreground = fg;
       gcv.background = bg;
-      gc = XCreateGC (dpy, screensaver_window,
-                     (GCFont | GCForeground | GCBackground), &gcv);
+      ssi->stderr_gc = XCreateGC (dpy, window,
+                                 (GCFont | GCForeground | GCBackground),
+                                 &gcv);
     }
 
+
+  if (ssi->stderr_cmap)
+    XInstallColormap(si->dpy, ssi->stderr_cmap);
+
   for (tail = string; *tail; tail++)
     {
       if (*tail == '\n' || *tail == '\r')
        {
          int maxy = HeightOfScreen (screen) - v_border - v_border;
          if (tail != head)
-           XDrawImageString (dpy, screensaver_window, gc,
-                             text_x + h_border,
-                             text_y + v_border + font->ascent,
+           XDrawImageString (dpy, window, ssi->stderr_gc,
+                             ssi->stderr_text_x + h_border,
+                             ssi->stderr_text_y + v_border +
+                             ssi->stderr_font->ascent,
                              head, tail - head);
-         text_x = 0;
-         text_y += line_height;
+         ssi->stderr_text_x = 0;
+         ssi->stderr_text_y += ssi->stderr_line_height;
          head = tail + 1;
          if (*tail == '\r' && *head == '\n')
            head++, tail++;
 
-         if (text_y > maxy - line_height)
+         if (ssi->stderr_text_y > maxy - ssi->stderr_line_height)
            {
 #if 0
-             text_y = 0;
+             ssi->stderr_text_y = 0;
 #else
-             int offset = line_height * 5;
-             XCopyArea (dpy, screensaver_window, screensaver_window, gc,
+             int offset = ssi->stderr_line_height * 5;
+             XCopyArea (dpy, window, window, ssi->stderr_gc,
                         0, v_border + offset,
                         WidthOfScreen (screen),
                         (HeightOfScreen (screen) - v_border - v_border
                          - offset),
                         0, v_border);
-             XClearArea (dpy, screensaver_window,
+             XClearArea (dpy, window,
                          0, HeightOfScreen (screen) - v_border - offset,
                          WidthOfScreen (screen), offset, False);
-             text_y -= offset;
+             ssi->stderr_text_y -= offset;
 #endif
            }
        }
@@ -125,21 +181,75 @@ print_stderr (string)
     {
       int direction, ascent, descent;
       XCharStruct overall;
-      XDrawImageString (dpy, screensaver_window, gc,
-                       text_x + h_border, text_y + v_border + font->ascent,
+      XDrawImageString (dpy, window, ssi->stderr_gc,
+                       ssi->stderr_text_x + h_border,
+                       ssi->stderr_text_y + v_border
+                         + ssi->stderr_font->ascent,
                        head, tail - head);
-      XTextExtents (font, tail, tail - head,
+      XTextExtents (ssi->stderr_font, tail, tail - head,
                    &direction, &ascent, &descent, &overall);
-      text_x += overall.width;
+      ssi->stderr_text_x += overall.width;
     }
 }
 
+static void
+make_stderr_overlay_window (saver_screen_info *ssi)
+{
+  saver_info *si = ssi->global;
+  unsigned long transparent_pixel = 0;
+  Visual *visual = get_overlay_visual (ssi->screen, &transparent_pixel);
+  if (visual)
+    {
+      int depth = visual_depth (ssi->screen, visual);
+      XSetWindowAttributes attrs;
+      unsigned long attrmask;
+
+      if (si->prefs.debug_p)
+       fprintf(real_stderr,
+               "%s: using overlay visual 0x%0x for stderr text layer.\n",
+               blurb(), (int) XVisualIDFromVisual (visual));
+
+      ssi->stderr_cmap = XCreateColormap(si->dpy,
+                                        RootWindowOfScreen(ssi->screen),
+                                        visual, AllocNone);
+
+      attrmask = (CWColormap | CWBackPixel | CWBackingPixel | CWBorderPixel |
+                 CWBackingStore | CWSaveUnder);
+      attrs.colormap = ssi->stderr_cmap;
+      attrs.background_pixel = transparent_pixel;
+      attrs.backing_pixel = transparent_pixel;
+      attrs.border_pixel = transparent_pixel;
+      attrs.backing_store = NotUseful;
+      attrs.save_under = False;
+
+      ssi->stderr_overlay_window =
+       XCreateWindow(si->dpy, ssi->screensaver_window, 0, 0,
+                     WidthOfScreen(ssi->screen), HeightOfScreen(ssi->screen),
+                     0, depth, InputOutput, visual, attrmask, &attrs);
+      XMapRaised(si->dpy, ssi->stderr_overlay_window);
+    }
+}
+
+
+static void
+print_stderr (saver_info *si, char *string)
+{
+  saver_preferences *p = &si->prefs;
+  int i;
+
+  /* In verbose mode, copy it to stderr as well. */
+  if (p->verbose_p)
+    fprintf (real_stderr, "%s", string);
+
+  for (i = 0; i < si->nscreens; i++)
+    print_stderr_1 (&si->screens[i], string);
+}
+
 
 static void
-stderr_popup_timer_fn (closure, id)
-     XtPointer closure;
-     XtIntervalId *id;
+stderr_popup_timer_fn (XtPointer closure, XtIntervalId *id)
 {
+  saver_info *si = (saver_info *) closure;
   char *s = stderr_buffer;
   if (*s)
     {
@@ -150,17 +260,18 @@ stderr_popup_timer_fn (closure, id)
       if (strlen (s) > max)
        strcpy (s + max, trailer);
       /* Now show the user. */
-      print_stderr (s);
+      print_stderr (si, s);
     }
 
   stderr_tail = stderr_buffer;
-  stderr_popup_timer = 0;
+  si->stderr_popup_timer = 0;
 }
 
 
 static void
 stderr_callback (XtPointer closure, int *fd, XtIntervalId *id)
 {
+  saver_info *si = (saver_info *) closure;
   char *s;
   int left;
   int size;
@@ -209,16 +320,17 @@ stderr_callback (XtPointer closure, int *fd, XtIntervalId *id)
    */
   if (read_this_time > 0)
     {
-      if (stderr_popup_timer)
-       XtRemoveTimeOut (stderr_popup_timer);
+      if (si->stderr_popup_timer)
+       XtRemoveTimeOut (si->stderr_popup_timer);
 
-      stderr_popup_timer =
-       XtAppAddTimeOut (app, 1 * 1000, stderr_popup_timer_fn, 0);
+      si->stderr_popup_timer =
+       XtAppAddTimeOut (si->app, 1 * 1000, stderr_popup_timer_fn,
+                        (XtPointer) si);
     }
 }
 
 void
-initialize_stderr ()
+initialize_stderr (saver_info *si)
 {
   static Boolean done = False;
   int fds [2];
@@ -226,19 +338,21 @@ initialize_stderr ()
   int new_stdout, new_stderr;
   int stdout_fd = 1;
   int stderr_fd = 2;
-  int flags;
-  Boolean stderr_dialog_p = get_boolean_resource ("captureStderr", "Boolean");
-  Boolean stdout_dialog_p = get_boolean_resource ("captureStdout", "Boolean");
+  int flags = 0;
+  Boolean stderr_dialog_p, stdout_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");
+
   if (!stderr_dialog_p && !stdout_dialog_p)
     return;
 
-  if (done) return;
-  done = True;
-
   if (pipe (fds))
     {
       perror ("error creating pipe:");
@@ -248,15 +362,15 @@ initialize_stderr ()
   in = fds [0];
   out = fds [1];
 
-# ifdef O_NONBLOCK
-  flags = O_NONBLOCK;
-# else
-#  ifdef O_NDELAY
-  flags = O_NDELAY;
+# ifdef HAVE_FCNTL
+
+#  if defined(O_NONBLOCK)
+   flags = O_NONBLOCK;
+#  elif defined(O_NDELAY)
+   flags = O_NDELAY;
 #  else
-  ERROR!! neither O_NONBLOCK nor O_NDELAY are defined.
+   ERROR!! neither O_NONBLOCK nor O_NDELAY are defined.
 #  endif
-# endif
 
     /* Set both sides of the pipe to nonblocking - this is so that
        our reads (in stderr_callback) will terminate, and so that
@@ -273,6 +387,8 @@ initialize_stderr ()
       return;
     }
 
+# endif /* !HAVE_FCNTL */
+
   if (stderr_dialog_p)
     {
       FILE *new_stderr_file;
@@ -321,5 +437,6 @@ initialize_stderr ()
        }
     }
 
-  XtAppAddInput (app, in, (XtPointer) XtInputReadMask, stderr_callback, 0);
+  XtAppAddInput (si->app, in, (XtPointer) XtInputReadMask, stderr_callback,
+                (XtPointer) si);
 }