1 /* xscreensaver, Copyright (c) 1991-1995 Jamie Zawinski <jwz@netscape.com>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
12 /* stderr hackery - Why Unix Sucks, reason number 32767.
24 #include <X11/Intrinsic.h>
26 #include "xscreensaver.h"
28 extern XtAppContext app;
30 extern Window screensaver_window;
32 extern char *get_string_resource P((char *, char *));
33 extern Bool get_boolean_resource P((char *, char *));
34 extern unsigned int get_pixel_resource P((char *, char *,
35 Display *, Colormap));
37 static char stderr_buffer [1024];
38 static char *stderr_tail = 0;
39 static time_t stderr_last_read = 0;
40 static XtIntervalId stderr_popup_timer = 0;
42 FILE *real_stderr = 0;
43 FILE *real_stdout = 0;
45 static int text_x = 0;
46 static int text_y = 0;
60 static int line_height;
61 static XFontStruct *font = 0;
66 /* In verbose mode, copy it to stderr as well. */
68 fprintf (real_stderr, "%s", string);
74 char *font_name = get_string_resource ("font", "Font");
75 if (!font_name) font_name = "fixed";
76 font = XLoadQueryFont (dpy, font_name);
77 if (! font) font = XLoadQueryFont (dpy, "fixed");
78 line_height = font->ascent + font->descent;
79 fg = get_pixel_resource ("textForeground", "Foreground", dpy, cmap);
80 bg = get_pixel_resource ("textBackground", "Background", dpy, cmap);
84 gc = XCreateGC (dpy, screensaver_window,
85 (GCFont | GCForeground | GCBackground), &gcv);
88 for (tail = string; *tail; tail++)
90 if (*tail == '\n' || *tail == '\r')
92 int maxy = HeightOfScreen (screen) - v_border - v_border;
94 XDrawImageString (dpy, screensaver_window, gc,
96 text_y + v_border + font->ascent,
99 text_y += line_height;
101 if (*tail == '\r' && *head == '\n')
104 if (text_y > maxy - line_height)
109 int offset = line_height * 5;
110 XCopyArea (dpy, screensaver_window, screensaver_window, gc,
111 0, v_border + offset,
112 WidthOfScreen (screen),
113 (HeightOfScreen (screen) - v_border - v_border
116 XClearArea (dpy, screensaver_window,
117 0, HeightOfScreen (screen) - v_border - offset,
118 WidthOfScreen (screen), offset, False);
126 int direction, ascent, descent;
128 XDrawImageString (dpy, screensaver_window, gc,
129 text_x + h_border, text_y + v_border + font->ascent,
131 XTextExtents (font, tail, tail - head,
132 &direction, &ascent, &descent, &overall);
133 text_x += overall.width;
139 stderr_popup_timer_fn (closure, id)
143 char *s = stderr_buffer;
146 /* If too much data was printed, then something has gone haywire,
148 char *trailer = "\n\n<< stderr diagnostics have been truncated >>\n\n";
149 int max = sizeof (stderr_buffer) - strlen (trailer) - 5;
150 if (strlen (s) > max)
151 strcpy (s + max, trailer);
152 /* Now show the user. */
156 stderr_tail = stderr_buffer;
157 stderr_popup_timer = 0;
162 stderr_callback (closure, fd, id)
170 int read_this_time = 0;
172 if (stderr_tail == 0)
173 stderr_tail = stderr_buffer;
175 left = ((sizeof (stderr_buffer) - 2) - (stderr_tail - stderr_buffer));
180 /* Read as much data from the fd as we can, up to our buffer size. */
183 while ((size = read (*fd, (void *) s, left)) > 0)
187 read_this_time += size;
194 /* The buffer is full; flush the rest of it. */
195 while (read (*fd, (void *) buf2, sizeof (buf2)) > 0)
200 stderr_last_read = time ((time_t *) 0);
202 /* Now we have read some data that we would like to put up in a dialog
203 box. But more data may still be coming in - so don't pop up the
204 dialog right now, but instead, start a timer that will pop it up
205 a second from now. Should more data come in in the meantime, we
206 will be called again, and will reset that timer again. So the
207 dialog will only pop up when a second has elapsed with no new data
208 being written to stderr.
210 However, if the buffer is full (meaning lots of data has been written)
211 then we don't reset the timer.
213 if (read_this_time > 0)
215 if (stderr_popup_timer)
216 XtRemoveTimeOut (stderr_popup_timer);
219 XtAppAddTimeOut (app, 1 * 1000, stderr_popup_timer_fn, 0);
226 static Boolean done = False;
229 int new_stdout, new_stderr;
233 Boolean stderr_dialog_p = get_boolean_resource ("captureStderr", "Boolean");
234 Boolean stdout_dialog_p = get_boolean_resource ("captureStdout", "Boolean");
236 real_stderr = stderr;
237 real_stdout = stdout;
239 if (!stderr_dialog_p && !stdout_dialog_p)
247 perror ("error creating pipe:");
260 ERROR!! neither O_NONBLOCK nor O_NDELAY are defined.
264 /* Set both sides of the pipe to nonblocking - this is so that
265 our reads (in stderr_callback) will terminate, and so that
266 out writes (in the client programs) will silently fail when
267 the pipe is full, instead of hosing the program. */
268 if (fcntl (in, F_SETFL, flags) != 0)
273 if (fcntl (out, F_SETFL, flags) != 0)
281 FILE *new_stderr_file;
282 new_stderr = dup (stderr_fd);
285 perror ("could not dup() a stderr:");
288 if (! (new_stderr_file = fdopen (new_stderr, "w")))
290 perror ("could not fdopen() the new stderr:");
293 real_stderr = new_stderr_file;
296 if (dup2 (out, stderr_fd) < 0)
298 perror ("could not dup() a new stderr:");
305 FILE *new_stdout_file;
306 new_stdout = dup (stdout_fd);
309 perror ("could not dup() a stdout:");
312 if (! (new_stdout_file = fdopen (new_stdout, "w")))
314 perror ("could not fdopen() the new stdout:");
317 real_stdout = new_stdout_file;
320 if (dup2 (out, stdout_fd) < 0)
322 perror ("could not dup() a new stdout:");
327 XtAppAddInput (app, in, (XtPointer) XtInputReadMask, stderr_callback, 0);