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