1 /* xscreensaver, Copyright (c) 1991-1995 Jamie Zawinski <jwz@mcom.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 (XtPointer closure, int *fd, XtIntervalId *id)
167 int read_this_time = 0;
169 if (stderr_tail == 0)
170 stderr_tail = stderr_buffer;
172 left = ((sizeof (stderr_buffer) - 2) - (stderr_tail - stderr_buffer));
177 /* Read as much data from the fd as we can, up to our buffer size. */
180 while ((size = read (*fd, (void *) s, left)) > 0)
184 read_this_time += size;
191 /* The buffer is full; flush the rest of it. */
192 while (read (*fd, (void *) buf2, sizeof (buf2)) > 0)
197 stderr_last_read = time ((time_t *) 0);
199 /* Now we have read some data that we would like to put up in a dialog
200 box. But more data may still be coming in - so don't pop up the
201 dialog right now, but instead, start a timer that will pop it up
202 a second from now. Should more data come in in the meantime, we
203 will be called again, and will reset that timer again. So the
204 dialog will only pop up when a second has elapsed with no new data
205 being written to stderr.
207 However, if the buffer is full (meaning lots of data has been written)
208 then we don't reset the timer.
210 if (read_this_time > 0)
212 if (stderr_popup_timer)
213 XtRemoveTimeOut (stderr_popup_timer);
216 XtAppAddTimeOut (app, 1 * 1000, stderr_popup_timer_fn, 0);
223 static Boolean done = False;
226 int new_stdout, new_stderr;
230 Boolean stderr_dialog_p = get_boolean_resource ("captureStderr", "Boolean");
231 Boolean stdout_dialog_p = get_boolean_resource ("captureStdout", "Boolean");
233 real_stderr = stderr;
234 real_stdout = stdout;
236 if (!stderr_dialog_p && !stdout_dialog_p)
244 perror ("error creating pipe:");
257 ERROR!! neither O_NONBLOCK nor O_NDELAY are defined.
261 /* Set both sides of the pipe to nonblocking - this is so that
262 our reads (in stderr_callback) will terminate, and so that
263 out writes (in the client programs) will silently fail when
264 the pipe is full, instead of hosing the program. */
265 if (fcntl (in, F_SETFL, flags) != 0)
270 if (fcntl (out, F_SETFL, flags) != 0)
278 FILE *new_stderr_file;
279 new_stderr = dup (stderr_fd);
282 perror ("could not dup() a stderr:");
285 if (! (new_stderr_file = fdopen (new_stderr, "w")))
287 perror ("could not fdopen() the new stderr:");
290 real_stderr = new_stderr_file;
293 if (dup2 (out, stderr_fd) < 0)
295 perror ("could not dup() a new stderr:");
302 FILE *new_stdout_file;
303 new_stdout = dup (stdout_fd);
306 perror ("could not dup() a stdout:");
309 if (! (new_stdout_file = fdopen (new_stdout, "w")))
311 perror ("could not fdopen() the new stdout:");
314 real_stdout = new_stdout_file;
317 if (dup2 (out, stdout_fd) < 0)
319 perror ("could not dup() a new stdout:");
324 XtAppAddInput (app, in, (XtPointer) XtInputReadMask, stderr_callback, 0);