6bc76ff27c43af1bbd9df24fe39c39ecac4acc3b
[xscreensaver] / hacks / xjack.c
1 /* xscreensaver, Copyright (c) 1997 Jamie Zawinski <jwz@netscape.com>
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:         black",
27   "*foreground:         #00EE00",
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   const char *s = source;
44   int columns, rows;            /* characters */
45   int left, right;              /* characters */
46   int char_width, line_height;  /* pixels */
47   int x, y;                     /* characters */
48   int mode = 0;
49   int hspace = 15;              /* pixels */
50   int vspace = 15;              /* pixels */
51   Bool break_para = True;
52   Bool caps = False;
53   int sentences = 0;
54   int paras = 0;
55
56   XWindowAttributes xgwa;
57   XGCValues gcv;
58   GC gc;
59   int delay = get_integer_resource ("delay", "Integer");
60   char *fontname = get_string_resource ("font", "Font");
61   XFontStruct *font = XLoadQueryFont (dpy, fontname);
62
63   if (!font)
64     font = XLoadQueryFont (dpy, "-*-*-medium-r-*-*-*-240-*-*-m-*-*-*");
65   if (!font)
66     font = XLoadQueryFont (dpy, "-*-courier-medium-r-*-*-*-180-*-*-m-*-*-*");
67   if (!font)
68     font = XLoadQueryFont (dpy, "-*-*-*-r-*-*-*-240-*-*-m-*-*-*");
69   if (!font)
70     {
71       fprintf(stderr, "no big fixed-width font like \"%s\"\n", fontname);
72       exit(1);
73     }
74
75   XGetWindowAttributes (dpy, window, &xgwa);
76
77   gcv.font = font->fid;
78   gcv.foreground = get_pixel_resource ("foreground", "Foreground", dpy,
79                                        xgwa.colormap);
80   gcv.background = get_pixel_resource ("background", "Background", dpy,
81                                        xgwa.colormap);
82   gc = XCreateGC (dpy, window, (GCFont | GCForeground | GCBackground), &gcv);
83
84   char_width = (font->per_char
85                 ? font->per_char['n'-font->min_char_or_byte2].rbearing
86                 : font->min_bounds.rbearing);
87   line_height = font->ascent + font->descent + 1;
88
89   columns = (xgwa.width - hspace - hspace) / char_width;
90   rows = (xgwa.height - vspace - vspace) / line_height;
91
92   left = 0xFF & (random() % ((columns / 2)+1));
93   right = left + (0xFF & (random() % (columns - left - 10)+10));
94   x = 0;
95   y = 0;
96
97   while (1)
98     {
99       int word_length = 0;
100       const char *s2;
101       for (s2 = s; *s2 && *s2 != ' '; s2++)
102         word_length++;
103
104       if (break_para ||
105           (*s != ' ' &&
106            (x + word_length) >= right))
107         {
108           x = left;
109           y++;
110
111           if (break_para)
112             y++;
113
114           if (mode == 1 || mode == 2)
115             {
116               /* 1 = left margin goes southwest; 2 = southeast */
117               left += (mode == 1 ? 1 : -1);
118               if (left >= right - 10)
119                 {
120                   if ((right < (columns - 10)) && (random() & 1))
121                     right += (0xFF & (random() % (columns - right)));
122                   else
123                     mode = 2;
124                 }
125               else if (left <= 0)
126                 {
127                   left = 0;
128                   mode = 1;
129                 }
130             }
131           else if (mode == 3 || mode == 4)
132             {
133               /* 3 = right margin goes southeast; 4 = southwest */
134               right += (mode == 3 ? 1 : -1);
135               if (right >= columns)
136                 {
137                   right = columns;
138                   mode = 4;
139                 }
140               else if (right <= left + 10)
141                 mode = 3;
142             }
143
144           if (y >= rows)        /* bottom of page */
145             {
146               /* scroll by 1-5 lines */
147               int lines = (random() % 5 ? 0 : (0xFF & (random() % 5))) + 1;
148               if (break_para)
149                 lines++;
150
151               /* but sometimes scroll by a whole page */
152               if (0 == (random() % 100))
153                 lines += rows;
154
155               while (lines > 0)
156                 {
157                   XCopyArea (dpy, window, window, gc,
158                              0, hspace + line_height,
159                              xgwa.width,
160                              xgwa.height - vspace - vspace - line_height,
161                              0, vspace);
162                   XClearArea (dpy, window,
163                               0, xgwa.height - vspace - line_height,
164                               xgwa.width,
165                               line_height + vspace + vspace,
166                               False);
167                   XClearArea (dpy, window, 0, 0, xgwa.width, vspace, False);
168                   /* See? It's OK. He saw it on the television. */
169                   XClearArea (dpy, window, 0, 0, hspace, xgwa.height, False);
170                   XClearArea (dpy, window, xgwa.width - vspace, 0,
171                               hspace, xgwa.height, False);
172                   y--;
173                   lines--;
174                   XSync (dpy, True);
175                   if (delay) usleep (delay * 10);
176                 }
177               if (y < 0) y = 0;
178             }
179
180           break_para = False;
181         }
182
183       if (*s != ' ')
184         {
185           char c = *s;
186           int xshift = 0, yshift = 0;
187           if (0 == random() % 50)
188             {
189               xshift = random() % ((char_width / 3) + 1);      /* mis-strike */
190               yshift = random() % ((line_height / 6) + 1);
191               if (0 == (random() % 3))
192                 yshift *= 2;
193               if (random() & 1)
194                 xshift = -xshift;
195               if (random() & 1)
196                 yshift = -yshift;
197             }
198
199           if (0 == (random() % 250))    /* introduce adjascent-key typo */
200             {
201               static const char * const typo[] = {
202                 "asqw", "ASQW", "bgvhn", "cxdfv", "dserfcx", "ewsdrf",
203                 "Jhuikmn", "kjiol,m", "lkop;.,", "mnjk,", "nbhjm", "oiklp09",
204                 "pol;(-0", "redft54", "sawedxz", "uyhji87", "wqase32",
205                 "yuhgt67", ".,l;/", 0 };
206               int i = 0;
207               while (typo[i] && typo[i][0] != c)
208                 i++;
209               if (typo[i])
210                 c = typo[i][0xFF & (random() % strlen(typo[i]+1))];
211             }
212
213           /* caps typo */
214           if (c >= 'a' && c <= 'z' && (caps || 0 == (random() % 350)))
215             {
216               c -= ('a'-'A');
217               if (c == 'O' && random() & 1)
218                 c = '0';
219             }
220
221         OVERSTRIKE:
222           XDrawString (dpy, window, gc,
223                        (x * char_width) + hspace + xshift,
224                        (y * line_height) + vspace + font->ascent + yshift,
225                        &c, 1);
226           if (xshift == 0 && yshift == 0 && (0 == (random() & 3000)))
227             {
228               if (random() & 1)
229                 xshift--;
230               else
231                 yshift--;
232               goto OVERSTRIKE;
233             }
234
235           if ((tolower(c) != tolower(*s))
236               ? (0 == (random() % 10))          /* backup to correct */
237               : (0 == (random() % 400)))        /* fail to advance */
238             {
239               x--;
240               s--;
241               XSync (dpy, True);
242               if (delay) usleep (0xFFFF & (delay + (random() % (delay * 10))));
243             }
244         }
245
246       x++;
247       s++;
248
249       if (0 == random() % 200)
250         {
251           if (random() & 1 && s != source)
252             s--;        /* duplicate character */
253           else if (*s)
254             s++;        /* skip character */
255         }
256
257       if (*s == 0)
258         {
259           sentences++;
260           caps = (0 == random() % 40);  /* capitalize sentence */
261
262           if (0 == (random() % 10) ||   /* randomly break paragraph */
263               (mode == 0 &&
264                ((0 == (random() % 10)) || sentences > 20)))
265             {
266               break_para = True;
267               sentences = 0;
268               paras++;
269
270               if (random() & 1)         /* mode=0 50% of the time */
271                 mode = 0;
272               else
273                 mode = (0xFF & (random() % 5));
274
275               if (0 == (random() % 2))  /* re-pick margins */
276                 {
277                   left = 0xFF & (random() % (columns / 3));
278                   right = columns - (0xFF & (random() % (columns / 3)));
279
280                   if (0 == random() % 3)        /* sometimes be wide */
281                     right = left + ((right - left) / 2);
282                 }
283
284               if (right - left <= 10)   /* introduce sanity */
285                 {
286                   left = 0;
287                   right = columns;
288                 }
289
290               if (right - left > 50)    /* if wide, shrink and move */
291                 {
292                   left += (0xFF & (random() % ((columns - 50) + 1)));
293                   right = left + (0xFF & ((random() % 40) + 10));
294                 }
295
296               /* oh, gag. */
297               if (mode == 0 &&
298                   right - left < 25 &&
299                   columns > 40)
300                 {
301                   right += 20;
302                   if (right > columns)
303                     left -= (right - columns);
304                 }
305             }
306           s = source;
307         }
308
309       XSync (dpy, True);
310       if (delay)
311         {
312           usleep (delay);
313           if (0 == random() % 3)
314             usleep(0xFFFFFF & ((random() % (delay * 5)) + 1));
315
316           if (break_para)
317             usleep(0xFFFFFF & ((random() % (delay * 15)) + 1));
318         }
319
320       if (paras > 5 &&
321           (0 == (random() % 1000)) &&
322           y < rows-5)
323         {
324           int i;
325           int n = random() & 3;
326           y++;
327           for (i = 0; i < n; i++)
328             {
329               /* See also http://catalog.com/hopkins/unix-haters/login.html */
330               const char *n1 =
331                 "NFS server overlook not responding, still trying...";
332               const char *n2 = "NFS server overlook ok.";
333               while (*n1)
334                 {
335                   XDrawString (dpy, window, gc,
336                                (x * char_width) + hspace,
337                                (y * line_height) + vspace + font->ascent,
338                                n1, 1);
339                   x++;
340                   if (x >= columns) x = 0, y++;
341                   n1++;
342                 }
343               XSync (dpy, True);
344               usleep (5000000);
345               while (*n2)
346                 {
347                   XDrawString (dpy, window, gc,
348                                (x * char_width) + hspace,
349                                (y * line_height) + vspace + font->ascent,
350                                n2, 1);
351                   x++;
352                   if (x >= columns) x = 0, y++;
353                   n2++;
354                 }
355               y++;
356               XSync (dpy, True);
357               usleep (500000);
358             }
359         }
360     }
361 }