ftp://ftp.smr.ru/pub/0/FreeBSD/releases/distfiles/xscreensaver-3.16.tar.gz
[xscreensaver] / hacks / xjack.c
1 /* xscreensaver, Copyright (c) 1997 Jamie Zawinski <jwz@jwz.org>
2  *
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 
9  * implied warranty.
10  *
11  * Wendy, let me explain something to you.  Whenever you come in here and
12  * interrupt me, you're BREAKING my CONCENTRATION.  You're DISTRACTING me!
13  * And it will then take me time to get back to where I was. You understand?
14  * Now, we're going to make a new rule.  When you come in here and you hear
15  * me typing, or whether you DON'T hear me typing, or whatever the FUCK you
16  * hear me doing; when I'm in here, it means that I am working, THAT means
17  * don't come in!  Now, do you think you can handle that?
18  */
19
20 #include <ctype.h>
21 #include "screenhack.h"
22
23 char *progclass = "XJack";
24
25 char *defaults [] = {
26   ".background:         #FFF0B4",
27   ".foreground:         #000000",
28   "XJack.font:          -*-courier-medium-r-*-*-*-240-*-*-m-*-*-*",
29   "*delay:              50000",
30   0
31 };
32
33 XrmOptionDescRec options [] = {
34   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
35   { "-font",            ".font",        XrmoptionSepArg, 0 },
36   { 0, 0, 0, 0 }
37 };
38
39 void
40 screenhack (Display *dpy, Window window)
41 {
42   static const char *source = "All work and no play makes Jack a dull boy.  ";
43   /* If you're here because you're thinking about making the above string be
44      customizable, then you don't get the joke.  You loser. */
45   const char *s = source;
46   int columns, rows;            /* characters */
47   int left, right;              /* characters */
48   int char_width, line_height;  /* pixels */
49   int x, y;                     /* characters */
50   int mode = 0;
51   int hspace = 15;              /* pixels */
52   int vspace = 15;              /* pixels */
53   Bool break_para = True;
54   Bool caps = False;
55   int sentences = 0;
56   int paras = 0;
57
58   XWindowAttributes xgwa;
59   XGCValues gcv;
60   GC gc;
61   int delay = get_integer_resource ("delay", "Integer");
62   char *fontname = get_string_resource ("font", "Font");
63   XFontStruct *font = XLoadQueryFont (dpy, fontname);
64
65   if (!font)
66     font = XLoadQueryFont (dpy, "-*-*-medium-r-*-*-*-240-*-*-m-*-*-*");
67   if (!font)
68     font = XLoadQueryFont (dpy, "-*-courier-medium-r-*-*-*-180-*-*-m-*-*-*");
69   if (!font)
70     font = XLoadQueryFont (dpy, "-*-*-*-r-*-*-*-240-*-*-m-*-*-*");
71   if (!font)
72     {
73       fprintf(stderr, "no big fixed-width font like \"%s\"\n", fontname);
74       exit(1);
75     }
76
77   XGetWindowAttributes (dpy, window, &xgwa);
78
79   gcv.font = font->fid;
80   gcv.foreground = get_pixel_resource ("foreground", "Foreground", dpy,
81                                        xgwa.colormap);
82   gcv.background = get_pixel_resource ("background", "Background", dpy,
83                                        xgwa.colormap);
84   gc = XCreateGC (dpy, window, (GCFont | GCForeground | GCBackground), &gcv);
85
86   char_width = (font->per_char
87                 ? font->per_char['n'-font->min_char_or_byte2].rbearing
88                 : font->min_bounds.rbearing);
89   line_height = font->ascent + font->descent + 1;
90
91   columns = (xgwa.width - hspace - hspace) / char_width;
92   rows = (xgwa.height - vspace - vspace) / line_height;
93
94   left = 0xFF & (random() % ((columns / 2)+1));
95   right = left + (0xFF & (random() % (columns - left - 10)+10));
96   x = 0;
97   y = 0;
98
99   while (1)
100     {
101       int word_length = 0;
102       const char *s2;
103       for (s2 = s; *s2 && *s2 != ' '; s2++)
104         word_length++;
105
106       if (break_para ||
107           (*s != ' ' &&
108            (x + word_length) >= right))
109         {
110           x = left;
111           y++;
112
113           if (break_para)
114             y++;
115
116           if (mode == 1 || mode == 2)
117             {
118               /* 1 = left margin goes southwest; 2 = southeast */
119               left += (mode == 1 ? 1 : -1);
120               if (left >= right - 10)
121                 {
122                   if ((right < (columns - 10)) && (random() & 1))
123                     right += (0xFF & (random() % (columns - right)));
124                   else
125                     mode = 2;
126                 }
127               else if (left <= 0)
128                 {
129                   left = 0;
130                   mode = 1;
131                 }
132             }
133           else if (mode == 3 || mode == 4)
134             {
135               /* 3 = right margin goes southeast; 4 = southwest */
136               right += (mode == 3 ? 1 : -1);
137               if (right >= columns)
138                 {
139                   right = columns;
140                   mode = 4;
141                 }
142               else if (right <= left + 10)
143                 mode = 3;
144             }
145
146           if (y >= rows)        /* bottom of page */
147             {
148               /* scroll by 1-5 lines */
149               int lines = (random() % 5 ? 0 : (0xFF & (random() % 5))) + 1;
150               if (break_para)
151                 lines++;
152
153               /* but sometimes scroll by a whole page */
154               if (0 == (random() % 100))
155                 lines += rows;
156
157               while (lines > 0)
158                 {
159                   int i;
160                   int inc = line_height / 7;
161                   int pix_delay = delay / 1000;
162                   if (inc <= 0) inc = 1;
163                   for (i = 0; i < line_height; i += inc)
164                     {
165                       if (i > line_height)
166                         i = line_height;
167                       XCopyArea (dpy, window, window, gc,
168                                  0, inc,
169                                  xgwa.width, xgwa.height - inc,
170                                  0, 0);
171                       XSync (dpy, False);
172                       if (pix_delay) usleep (pix_delay);
173                     }
174                   y--;
175                   lines--;
176
177                   /* See? It's OK. He saw it on the television. */
178                   XClearArea (dpy, window,
179                               0, xgwa.height - vspace - line_height,
180                               xgwa.width, line_height + vspace + vspace,
181                               False);
182                   XSync (dpy, False);
183
184                   XGetWindowAttributes (dpy, window, &xgwa);
185                   columns = (xgwa.width - hspace - hspace) / char_width;
186                   rows = (xgwa.height - vspace - vspace) / line_height;
187                   if (y > rows) y = rows-1;
188                   if (x > columns) x = columns-2;
189
190                   if (delay) usleep (delay);
191                 }
192               if (y < 0) y = 0;
193             }
194
195           break_para = False;
196         }
197
198       if (*s != ' ')
199         {
200           char c = *s;
201           int xshift = 0, yshift = 0;
202           if (0 == random() % 50)
203             {
204               xshift = random() % ((char_width / 3) + 1);      /* mis-strike */
205               yshift = random() % ((line_height / 6) + 1);
206               if (0 == (random() % 3))
207                 yshift *= 2;
208               if (random() & 1)
209                 xshift = -xshift;
210               if (random() & 1)
211                 yshift = -yshift;
212             }
213
214           if (0 == (random() % 250))    /* introduce adjascent-key typo */
215             {
216               static const char * const typo[] = {
217                 "asqw", "ASQW", "bgvhn", "cxdfv", "dserfcx", "ewsdrf",
218                 "Jhuikmn", "kjiol,m", "lkop;.,", "mnjk,", "nbhjm", "oiklp09",
219                 "pol;(-0", "redft54", "sawedxz", "uyhji87", "wqase32",
220                 "yuhgt67", ".,l;/", 0 };
221               int i = 0;
222               while (typo[i] && typo[i][0] != c)
223                 i++;
224               if (typo[i])
225                 c = typo[i][0xFF & (random() % strlen(typo[i]+1))];
226             }
227
228           /* caps typo */
229           if (c >= 'a' && c <= 'z' && (caps || 0 == (random() % 350)))
230             {
231               c -= ('a'-'A');
232               if (c == 'O' && random() & 1)
233                 c = '0';
234             }
235
236         OVERSTRIKE:
237           XDrawString (dpy, window, gc,
238                        (x * char_width) + hspace + xshift,
239                        (y * line_height) + vspace + font->ascent + yshift,
240                        &c, 1);
241           if (xshift == 0 && yshift == 0 && (0 == (random() & 3000)))
242             {
243               if (random() & 1)
244                 xshift--;
245               else
246                 yshift--;
247               goto OVERSTRIKE;
248             }
249
250           if ((tolower(c) != tolower(*s))
251               ? (0 == (random() % 10))          /* backup to correct */
252               : (0 == (random() % 400)))        /* fail to advance */
253             {
254               x--;
255               s--;
256               XSync (dpy, False);
257               if (delay) usleep (0xFFFF & (delay + (random() % (delay * 10))));
258             }
259         }
260
261       x++;
262       s++;
263
264       if (0 == random() % 200)
265         {
266           if (random() & 1 && s != source)
267             s--;        /* duplicate character */
268           else if (*s)
269             s++;        /* skip character */
270         }
271
272       if (*s == 0)
273         {
274           sentences++;
275           caps = (0 == random() % 40);  /* capitalize sentence */
276
277           if (0 == (random() % 10) ||   /* randomly break paragraph */
278               (mode == 0 &&
279                ((0 == (random() % 10)) || sentences > 20)))
280             {
281               break_para = True;
282               sentences = 0;
283               paras++;
284
285               if (random() & 1)         /* mode=0 50% of the time */
286                 mode = 0;
287               else
288                 mode = (0xFF & (random() % 5));
289
290               if (0 == (random() % 2))  /* re-pick margins */
291                 {
292                   left = 0xFF & (random() % (columns / 3));
293                   right = columns - (0xFF & (random() % (columns / 3)));
294
295                   if (0 == random() % 3)        /* sometimes be wide */
296                     right = left + ((right - left) / 2);
297                 }
298
299               if (right - left <= 10)   /* introduce sanity */
300                 {
301                   left = 0;
302                   right = columns;
303                 }
304
305               if (right - left > 50)    /* if wide, shrink and move */
306                 {
307                   left += (0xFF & (random() % ((columns - 50) + 1)));
308                   right = left + (0xFF & ((random() % 40) + 10));
309                 }
310
311               /* oh, gag. */
312               if (mode == 0 &&
313                   right - left < 25 &&
314                   columns > 40)
315                 {
316                   right += 20;
317                   if (right > columns)
318                     left -= (right - columns);
319                 }
320             }
321           s = source;
322         }
323
324       XSync (dpy, False);
325       if (delay)
326         {
327           usleep (delay);
328           if (0 == random() % 3)
329             usleep(0xFFFFFF & ((random() % (delay * 5)) + 1));
330
331           if (break_para)
332             usleep(0xFFFFFF & ((random() % (delay * 15)) + 1));
333         }
334
335       if (paras > 5 &&
336           (0 == (random() % 1000)) &&
337           y < rows-5)
338         {
339           int i;
340           int n = random() & 3;
341           y++;
342           for (i = 0; i < n; i++)
343             {
344               /* See also http://catalog.com/hopkins/unix-haters/login.html */
345               const char *n1 =
346                 "NFS server overlook not responding, still trying...";
347               const char *n2 = "NFS server overlook ok.";
348               while (*n1)
349                 {
350                   XDrawString (dpy, window, gc,
351                                (x * char_width) + hspace,
352                                (y * line_height) + vspace + font->ascent,
353                                n1, 1);
354                   x++;
355                   if (x >= columns) x = 0, y++;
356                   n1++;
357                 }
358               XSync (dpy, False);
359               usleep (5000000);
360               while (*n2)
361                 {
362                   XDrawString (dpy, window, gc,
363                                (x * char_width) + hspace,
364                                (y * line_height) + vspace + font->ascent,
365                                n2, 1);
366                   x++;
367                   if (x >= columns) x = 0, y++;
368                   n2++;
369                 }
370               y++;
371               XSync (dpy, False);
372               usleep (500000);
373             }
374         }
375       screenhack_handle_events (dpy);
376     }
377 }