1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* xjack -- Jack having one of those days */
3
4 #if 0
5 static const char sccsid[] = "@(#)xjack.c 5.00 2000/11/01 xlockmore";
6
7 #endif
8
9 /* xscreensaver, Copyright (c) 1997 Jamie Zawinski <jwz AT jwz.org>
10 *
11 * Permission to use, copy, modify, distribute, and sell this software and its
12 * documentation for any purpose is hereby granted without fee, provided that
13 * the above copyright notice appear in all copies and that both that
14 * copyright notice and this permission notice appear in supporting
15 * documentation. No representations are made about the suitability of this
16 * software for any purpose. It is provided "as is" without express or
17 * implied warranty.
18 *
19 * Wendy, let me explain something to you. Whenever you come in here and
20 * interrupt me, you're BREAKING my CONCENTRATION. You're DISTRACTING me!
21 * And it will then take me time to get back to where I was. You understand?
22 * Now, we're going to make a new rule. When you come in here and you hear
23 * me typing, or whether you DON'T hear me typing, or whatever the FUCK you
24 * hear me doing; when I'm in here, it means that I am working, THAT means
25 * don't come in! Now, do you think you can handle that?
26 *
27 * Revision History:
28 * 01-Nov-2000: Allocation checks
29 * 10-Oct-1998: revision history edited.
30 */
31
32 #ifdef STANDALONE
33 #define MODE_xjack
34 #define DEFAULTS "*delay: 50000 \n" \
35 "*font: fixed\n" \
36 "*text: \n" \
37 "*fullrandom: True \n" \
38
39 # define free_xjack 0
40 # define reshape_xjack 0
41 # define xjack_handle_event 0
42 #define DEF_FONT "-*-courier-medium-r-*-*-*-240-*-*-m-*-*-*",
43 #define DEF_TEXT "All work and no play makes Jack a dull boy. ";
44 #include "xlockmore.h" /* in xscreensaver distribution */
45
46 #else /* STANDALONE */
47 #include "xlock.h" /* in xlockmore distribution */
48 #include "iostuff.h"
49 #endif
50 #include <ctype.h>
51
52 #ifdef MODE_xjack
53
54 ENTRYPOINT ModeSpecOpt xjack_opts =
55 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
56
57 #ifdef USE_MODULES
58 ModStruct xjack_description =
59 {"xjack", "init_xjack", "draw_xjack", "release_xjack",
60 "init_xjack", "init_xjack", (char *) NULL, &xjack_opts,
61 50000, 1, 1, 1, 64, 1.0, "",
62 "Shows Jack having one of those days", 0, NULL};
63
64 #endif
65
66 #ifdef USE_MB
font_height(XFontStruct * f)67 static int font_height(XFontStruct *f)
68 {
69 XRectangle mbRect;
70
71 XmbTextExtents(fontset, "Aj", 1, NULL, &mbRect);
72 return mbRect.height;
73 }
74 #define font_ascent(f) (font_height(f)*4/5)
char_width(XFontStruct * f)75 static int char_width(XFontStruct *f)
76 {
77 XRectangle mbRect;
78
79 XmbTextExtents(fontset, "A", 1, NULL, &mbRect);
80 return mbRect.width;
81 }
82
83 #else
84 #define font_height(f) ((f==None)?15:f->ascent + f->descent)
85 #define font_ascent(f) ((f==None)?12:f->ascent)
86 #define char_width(f) ((mode_font->per_char?mode_font->per_char['n' - mode_font->min_char_or_byte2].rbearing:mode_font->min_bounds.rbearing))
87 #endif
88
89 extern XFontStruct *getFont(Display * display);
90
91 typedef struct {
92 int word_length;
93 int sentences;
94 int paras;
95 Bool caps;
96 Bool break_para;
97 int mode, stage, busyloop;
98 int left, right; /* characters */
99 int x, y; /* characters */
100 int hspace, vspace; /* pixels */
101 int ascent;
102 int height;
103 int win_width, win_height;
104 int columns, rows; /* characters */
105 int char_width, line_height; /* pixels */
106 const char *s;
107 GC gc;
108 } jackstruct;
109
110 static jackstruct *jacks = (jackstruct *) NULL;
111
112 static XFontStruct *mode_font = None;
113 static const char *source = "All work and no play makes Jack a dull boy. ";
114 static const char *source_message;
115
116 extern char *message;
117
118 static void
free_xjack_screen(Display * display,jackstruct * jp)119 free_xjack_screen(Display *display, jackstruct *jp)
120 {
121 if (jp == NULL) {
122 return;
123 }
124 if (jp->gc != None)
125 XFreeGC(display, jp->gc);
126 jp = NULL;
127 }
128
129 ENTRYPOINT void
release_xjack(ModeInfo * mi)130 release_xjack(ModeInfo * mi)
131 {
132 if (jacks != NULL) {
133 int screen;
134
135 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
136 free_xjack_screen(MI_DISPLAY(mi), &jacks[screen]);
137 }
138 free(jacks);
139 jacks = (jackstruct *) NULL;
140 }
141 if (mode_font != None) {
142 XFreeFont(MI_DISPLAY(mi), mode_font);
143 mode_font = None;
144 }
145 }
146
147 ENTRYPOINT void
init_xjack(ModeInfo * mi)148 init_xjack(ModeInfo * mi)
149 {
150 Display *display = MI_DISPLAY(mi);
151 jackstruct *jp;
152 XGCValues gcv;
153
154 MI_INIT(mi, jacks);
155 jp = &jacks[MI_SCREEN(mi)];
156 if (mode_font == None)
157 if ((mode_font = getFont(display)) == None) {
158 release_xjack(mi);
159 }
160
161 if (jp->gc == None) {
162 gcv.font = mode_font->fid;
163 gcv.graphics_exposures = False;
164 gcv.foreground = MI_WHITE_PIXEL(mi);
165 gcv.background = MI_BLACK_PIXEL(mi);
166 if ((jp->gc = XCreateGC(display, MI_WINDOW(mi),
167 GCForeground | GCBackground | GCGraphicsExposures | GCFont,
168 &gcv)) == None) {
169 return;
170 }
171 jp->ascent = font_ascent(mode_font);
172 jp->height = font_height(mode_font);
173 }
174
175 jp->win_width = MI_WIDTH(mi);
176 jp->win_height = MI_HEIGHT(mi);
177
178 jp->hspace = jp->vspace = 15; /* pixels */
179 jp->char_width = char_width(mode_font);
180 if (!jp->char_width)
181 jp->char_width = 10;
182 if (!jp->height)
183 jp->height = 15;
184 jp->line_height = jp->height + 1;
185
186 jp->columns = MAX((jp->win_width - jp->hspace - jp->hspace) / jp->char_width, 2);
187 jp->rows = (MI_HEIGHT(mi) - jp->vspace - jp->vspace) / jp->line_height;
188
189 jp->left = 0xFF & (NRAND((jp->columns / 2) + 1));
190 if ( jp->columns - jp->left != 10 )
191 jp->right = jp->left + (0xFF & (NRAND(jp->columns - jp->left - 10) + 10));
192 else
193 jp->right = jp->left + 10;
194 jp->x = 0;
195 jp->y = 0;
196 jp->sentences = 0;
197 jp->paras = 0;
198 jp->caps = False;
199 jp->break_para = True;
200 jp->mode = 0;
201 jp->stage = 0;
202 jp->busyloop = 0;
203 #ifdef STANDALONE
204 source_message = source;
205 #else
206 if (!message || !*message)
207 source_message = source;
208 else
209 source_message = message;
210 #endif
211 jp->s = source_message;
212 MI_CLEARWINDOW(mi);
213 }
214
215 ENTRYPOINT void
draw_xjack(ModeInfo * mi)216 draw_xjack(ModeInfo * mi)
217 {
218 Display *display = MI_DISPLAY(mi);
219 Window window = MI_WINDOW(mi);
220 const char *s2;
221 jackstruct *jp;
222
223 if (jacks == NULL)
224 return;
225 jp = &jacks[MI_SCREEN(mi)];
226 if (jp->gc == None)
227 return;
228
229 MI_IS_DRAWN(mi) = True;
230
231 jp->word_length = 0;
232 for (s2 = jp->s; *s2 && *s2 != ' '; s2++)
233 jp->word_length++;
234
235 if (jp->break_para || (*(jp->s) != ' ' &&
236 (jp->x + jp->word_length) >= jp->right)) {
237 jp->x = jp->left;
238 jp->y++;
239
240 if (jp->break_para)
241 jp->y++;
242
243 if (jp->mode == 1 || jp->mode == 2) {
244 /* 1 = left margin goes southwest; 2 = southeast */
245 jp->left += (jp->mode == 1 ? 1 : -1);
246 if (jp->left >= jp->right - 10) {
247 if ((jp->right < (jp->columns - 10)) && (LRAND() & 1))
248 jp->right += (0xFF & (NRAND(jp->columns - jp->right)));
249 else
250 jp->mode = 2;
251 } else if (jp->left <= 0) {
252 jp->left = 0;
253 jp->mode = 1;
254 }
255 } else if (jp->mode == 3 || jp->mode == 4) {
256 /* 3 = right margin goes southeast; 4 = southwest */
257 jp->right += (jp->mode == 3 ? 1 : -1);
258 if (jp->right >= jp->columns) {
259 jp->right = jp->columns;
260 jp->mode = 4;
261 } else if (jp->right <= jp->left + 10)
262 jp->mode = 3;
263 }
264
265 if (jp->y >= jp->rows) { /* bottom of page */
266 /* scroll by 1-5 lines */
267 int lines = ((NRAND(5)) ? 0 : (0xFF & (NRAND(5)))) + 1;
268
269 if (jp->break_para)
270 lines++;
271
272 /* but sometimes scroll by a whole page */
273 if (!NRAND(100))
274 lines += jp->rows;
275
276 while (lines > 0) {
277 XCopyArea(display, window, window, jp->gc,
278 0, jp->hspace + jp->line_height,
279 jp->win_width,
280 jp->win_height - jp->vspace - jp->vspace - jp->line_height,
281 0, jp->vspace);
282 XClearArea(display, window,
283 0, jp->win_height - jp->vspace - jp->line_height,
284 jp->win_width,
285 jp->line_height + jp->vspace + jp->vspace,
286 False);
287 XClearArea(display, window, 0, 0, jp->win_width, jp->vspace, False);
288 /* See? It's OK. He saw it on the television. */
289 XClearArea(display, window, 0, 0, jp->hspace, jp->win_height, False);
290 XClearArea(display, window, jp->win_width - jp->vspace, 0,
291 jp->hspace, jp->win_height, False);
292 jp->y--;
293 lines--;
294 #if 0
295 XFlush(display);
296 if (delay)
297 (void) usleep (delay * 10);
298 #endif
299 }
300 if (jp->y < 0)
301 jp->y = 0;
302 }
303
304 jp->break_para = False;
305 }
306
307 if (*(jp->s) != ' ') {
308 char c = *(jp->s);
309 int xshift = 0, yshift = 0;
310
311 if (!NRAND(50)) {
312 xshift = NRAND((jp->char_width / 3) + 1); /* mis-strike */
313 yshift = NRAND((jp->line_height / 6) + 1);
314 if (!NRAND(3))
315 yshift *= 2;
316 if (LRAND() & 1)
317 xshift = -xshift;
318 if (LRAND() & 1)
319 yshift = -yshift;
320 }
321
322 if (!NRAND(250)) { /* introduce adjascent-key typo */
323 static const char * const typo[] = {
324 "asqwz", "bghnv", "cdfvx", "dcefsrx", "edrsw34",
325 "fcdegrtv", "gbfhtvy", "hbgjnuy", "ijkou89", "jhikmnu",
326 "kijolm,", "lkop;.,", "mjkn,", "nbhjm", "oiklp09",
327 "plo;[-0", "qasw12", "redft45", "sadewxz", "tfgry56",
328 "uhijy78", "vbcfg", "waeqs23", "xcdsz", "yuhgt67",
329 "zasx", ".l,;/",
330 "ASQWZ", "BGHNV", "CDFVX", "DCEFSRX", "EDRSW#$",
331 "FCDEGRTV", "GBFHTVY", "HBGJNUY", "IJKOU*(", "JHIKMNU",
332 "KIJOLM,", "LKOP:><", "MJKN<", "NBHJM", "OIKLP)(",
333 "PLO:{_)", "QASW!@", "REDFT$%", "SADEWXZ", "TFGRY%^",
334 "UHIJY&*", "VBCFG", "WAEQS@#", "XCDSZ", "YUHGT^&",
335 "ZASX", 0 };
336 int i = 0;
337
338 while (typo[i] && typo[i][0] != c)
339 i++;
340 if (typo[i])
341 c = typo[i][0xFF & (NRAND(strlen(typo[i]+1)))];
342 }
343
344 /* caps typo */
345 if (c >= 'a' && c <= 'z' && (jp->caps || !NRAND(350))) {
346 c -= ('a' - 'A');
347 if (c == 'O' && (LRAND() & 1))
348 c = '0';
349 }
350
351 {
352 Bool overstrike;
353
354 do {
355 (void) XDrawString (display, window, jp->gc,
356 (jp->x * jp->char_width) + jp->hspace + xshift,
357 (jp->y * jp->line_height) + jp->vspace + jp->ascent + yshift,
358 &c, 1);
359 overstrike = (xshift == 0 && yshift == 0 &&
360 (0 == (LRAND() & 3000)));
361 if (overstrike) {
362 if (LRAND() & 1)
363 xshift--;
364 else
365 yshift--;
366 }
367 } while (overstrike);
368 }
369 if ((tolower(c) != tolower(*(jp->s)))
370 ? (!NRAND(10)) /* backup to correct */
371 : (!NRAND(400))) { /* fail to advance */
372 jp->x--;
373 jp->s--;
374 #if 0
375 XFlush(display);
376 if (delay)
377 (void) usleep (0xFFFF & (delay + (NRAND(delay * 10))));
378 #endif
379 }
380 }
381
382 jp->x++;
383 jp->s++;
384
385 if (!NRAND(200)) {
386 if ((LRAND() & 1) && jp->s != source_message)
387 jp->s--; /* duplicate character */
388 else if (*(jp->s))
389 jp->s++; /* skip character */
390 }
391
392 if (*(jp->s) == 0) {
393 jp->sentences++;
394 jp->caps = (!NRAND(40)); /* capitalize sentence */
395
396 if (!NRAND(10) || /* randomly break paragraph */
397 (jp->mode == 0 && (NRAND(10) || jp->sentences > 20))) {
398 jp->break_para = True;
399 jp->sentences = 0;
400 jp->paras++;
401
402 if (LRAND() & 1) /* mode=0 50% of the time */
403 jp->mode = 0;
404 else
405 jp->mode = (0xFF & NRAND(5));
406
407 if (LRAND() & 1) { /* re-pick margins */
408 if (jp->columns < 3)
409 jp->columns = 3;
410 jp->left = 0xFF & (NRAND(jp->columns / 3));
411 jp->right = jp->columns - (0xFF & (NRAND(jp->columns / 3)));
412
413 if (!NRAND(3)) /* sometimes be wide */
414 jp->right = jp->left + ((jp->right - jp->left) / 2);
415 }
416
417 if (jp->right - jp->left <= 10) { /* introduce sanity */
418 jp->left = 0;
419 jp->right = jp->columns;
420 }
421
422 if (jp->right - jp->left > 50) { /* if wide, shrink and move */
423 jp->left += (0xFF & (NRAND((jp->columns - 50) + 1)));
424 jp->right = jp->left + (0xFF & (NRAND(40) + 10));
425 }
426
427 /* oh, gag. */
428 if (jp->mode == 0 && jp->right - jp->left < 25 && jp->columns > 40) {
429 jp->right += 20;
430 if (jp->right > jp->columns)
431 jp->left -= (jp->right - jp->columns);
432 }
433 }
434 jp->s = source_message;
435 }
436
437 #if 0
438 XFlush(display);
439 if (delay) {
440 (void) usleep (delay);
441 if (!NRAND(3))
442 (void) usleep(0xFFFFFF & ((NRAND(delay * 5)) + 1));
443
444 if (jp->break_para)
445 (void) usleep(0xFFFFFF & ((NRAND(delay * 15)) + 1));
446 }
447 #endif
448
449 #ifdef NFS_COMPLAINTS
450 if (jp->paras > 5 && (!NRAND(1000)) && jp->y < jp->rows-5) {
451 int i;
452 int n = NRAND(3);
453
454 jp->y++;
455 for (i = 0; i < n; i++) {
456 /* See also http://catalog.com/hopkins/unix-haters/login.html */
457 const char *n1 =
458 "NFS server overlook not responding, still trying...";
459 const char *n2 = "NFS server overlook ok.";
460
461 while (*n1) {
462 (void) XDrawString (display, window, jp->gc,
463 (jp->x * jp->char_width) + jp->hspace,
464 (jp->y * jp->line_height) + jp->vspace + jp->ascent,
465 n1, 1);
466 jp->x++;
467 if (jp->x >= jp->columns)
468 jp->x = 0, jp->y++;
469 n1++;
470 }
471 #if 0
472 XFlush(display);
473 (void) usleep (5000000);
474 #endif
475 while (*n2) {
476 (void) XDrawString (display, window, jp->gc,
477 (jp->x * jp->char_width) + jp->hspace,
478 (jp->y * jp->line_height) + jp->vspace + jp->ascent,
479 n2, 1);
480 jp->x++;
481 if (jp->x >= jp->columns)
482 jp->x = 0, jp->y++;
483 n2++;
484 }
485 jp->y++;
486 #if 0
487 XFlush(display);
488 (void) usleep (500000);
489 #endif
490 }
491 }
492 #endif
493 }
494
495 XSCREENSAVER_MODULE ("Xjack", xjack)
496
497 #endif /* MODE_xjack */
498