xenocara/app/xlockmore/modes/xjack.c
2006-11-26 11:07:42 +00:00

470 lines
12 KiB
C

/* -*- Mode: C; tab-width: 4 -*- */
/* xjack -- Jack having one of those days */
#if !defined( lint ) && !defined( SABER )
static const char sccsid[] = "@(#)xjack.c 5.00 2000/11/01 xlockmore";
#endif
/* xscreensaver, Copyright (c) 1997 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation. No representations are made about the suitability of this
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*
* Wendy, let me explain something to you. Whenever you come in here and
* interrupt me, you're BREAKING my CONCENTRATION. You're DISTRACTING me!
* And it will then take me time to get back to where I was. You understand?
* Now, we're going to make a new rule. When you come in here and you hear
* me typing, or whether you DON'T hear me typing, or whatever the FUCK you
* hear me doing; when I'm in here, it means that I am working, THAT means
* don't come in! Now, do you think you can handle that?
*
* Revision History:
* 01-Nov-2000: Allocation checks
* 10-Oct-1998: revision history edited.
*/
#ifdef STANDALONE
#define MODE_xjack
#define PROGCLASS "XJack"
#define HACK_INIT init_xjack
#define HACK_DRAW draw_xjack
#define xjack_opts xlockmore_opts
#define DEFAULTS "*delay: 50000 \n" \
"*font: \n" \
"*text: \n" \
"*fullrandom: True \n"
#define DEF_FONT "-*-courier-medium-r-*-*-*-240-*-*-m-*-*-*",
#define DEF_TEXT "All work and no play makes Jack a dull boy. ";
#include "xlockmore.h" /* in xscreensaver distribution */
#else /* STANDALONE */
#include "xlock.h" /* in xlockmore distribution */
#endif
#include "iostuff.h"
#ifdef MODE_xjack
ModeSpecOpt xjack_opts =
{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
#ifdef USE_MODULES
ModStruct xjack_description =
{"xjack", "init_xjack", "draw_xjack", "release_xjack",
"init_xjack", "init_xjack", (char *) NULL, &xjack_opts,
50000, 1, 1, 1, 64, 1.0, "",
"Shows Jack having one of those days", 0, NULL};
#endif
#define font_height(f) ((f==None)?15:f->ascent + f->descent)
extern XFontStruct *getFont(Display * display);
typedef struct {
int word_length;
int sentences;
int paras;
Bool caps;
Bool break_para;
int mode, stage, busyloop;
int left, right; /* characters */
int x, y; /* characters */
int hspace, vspace; /* pixels */
int ascent;
int height;
int win_width, win_height;
int columns, rows; /* characters */
int char_width, line_height; /* pixels */
const char *s;
GC gc;
} jackstruct;
static jackstruct *jacks = (jackstruct *) NULL;
static XFontStruct *mode_font = None;
static const char *source = "All work and no play makes Jack a dull boy. ";
static const char *source_message;
extern char *message;
void
release_xjack(ModeInfo * mi)
{
if (jacks != NULL) {
int screen;
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
jackstruct *jp = &jacks[screen];
Display *display = MI_DISPLAY(mi);
if (jp->gc)
XFreeGC(display, jp->gc);
}
free(jacks);
jacks = (jackstruct *) NULL;
}
if (mode_font != None) {
XFreeFont(MI_DISPLAY(mi), mode_font);
mode_font = None;
}
}
void
init_xjack(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
jackstruct *jp;
XGCValues gcv;
if (jacks == NULL) {
if ((jacks = (jackstruct *) calloc(MI_NUM_SCREENS(mi),
sizeof (jackstruct))) == NULL)
return;
}
jp = &jacks[MI_SCREEN(mi)];
if (mode_font == None)
if ((mode_font = getFont(display)) == None) {
release_xjack(mi);
}
if (jp->gc == None) {
gcv.font = mode_font->fid;
XSetFont(display, MI_GC(mi), mode_font->fid);
gcv.graphics_exposures = False;
gcv.foreground = MI_WHITE_PIXEL(mi);
gcv.background = MI_BLACK_PIXEL(mi);
if ((jp->gc = XCreateGC(display, MI_WINDOW(mi),
GCForeground | GCBackground | GCGraphicsExposures | GCFont,
&gcv)) == None) {
return;
}
jp->ascent = mode_font->ascent;
jp->height = font_height(mode_font);
}
jp->win_width = MI_WIDTH(mi);
jp->win_height = MI_HEIGHT(mi);
jp->hspace = jp->vspace = 15; /* pixels */
jp->char_width = (mode_font->per_char
? mode_font->per_char['n' - mode_font->min_char_or_byte2].rbearing
: mode_font->min_bounds.rbearing);
if (!jp->char_width)
jp->char_width = 10;
if (!jp->height)
jp->height = 15;
jp->line_height = jp->height + 1;
jp->columns = MAX((jp->win_width - jp->hspace - jp->hspace) / jp->char_width, 2);
jp->rows = (MI_HEIGHT(mi) - jp->vspace - jp->vspace) / jp->line_height;
jp->left = 0xFF & (NRAND((jp->columns / 2) + 1));
if ( jp->columns - jp->left != 10 )
jp->right = jp->left + (0xFF & (NRAND(jp->columns - jp->left - 10) + 10));
else
jp->right = jp->left + 10;
jp->x = 0;
jp->y = 0;
jp->sentences = 0;
jp->paras = 0;
jp->caps = False;
jp->break_para = True;
jp->mode = 0;
jp->stage = 0;
jp->busyloop = 0;
if (!message || !*message)
source_message = source;
else
source_message = message;
jp->s = source_message;
MI_CLEARWINDOW(mi);
}
void
draw_xjack(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
const char *s2;
jackstruct *jp;
if (jacks == NULL)
return;
jp = &jacks[MI_SCREEN(mi)];
if (jp->gc == None)
return;
MI_IS_DRAWN(mi) = True;
jp->word_length = 0;
for (s2 = jp->s; *s2 && *s2 != ' '; s2++)
jp->word_length++;
if (jp->break_para || (*(jp->s) != ' ' &&
(jp->x + jp->word_length) >= jp->right)) {
jp->x = jp->left;
jp->y++;
if (jp->break_para)
jp->y++;
if (jp->mode == 1 || jp->mode == 2) {
/* 1 = left margin goes southwest; 2 = southeast */
jp->left += (jp->mode == 1 ? 1 : -1);
if (jp->left >= jp->right - 10) {
if ((jp->right < (jp->columns - 10)) && (LRAND() & 1))
jp->right += (0xFF & (NRAND(jp->columns - jp->right)));
else
jp->mode = 2;
} else if (jp->left <= 0) {
jp->left = 0;
jp->mode = 1;
}
} else if (jp->mode == 3 || jp->mode == 4) {
/* 3 = right margin goes southeast; 4 = southwest */
jp->right += (jp->mode == 3 ? 1 : -1);
if (jp->right >= jp->columns) {
jp->right = jp->columns;
jp->mode = 4;
} else if (jp->right <= jp->left + 10)
jp->mode = 3;
}
if (jp->y >= jp->rows) { /* bottom of page */
/* scroll by 1-5 lines */
int lines = ((NRAND(5)) ? 0 : (0xFF & (NRAND(5)))) + 1;
if (jp->break_para)
lines++;
/* but sometimes scroll by a whole page */
if (!NRAND(100))
lines += jp->rows;
while (lines > 0) {
XCopyArea(display, window, window, jp->gc,
0, jp->hspace + jp->line_height,
jp->win_width,
jp->win_height - jp->vspace - jp->vspace - jp->line_height,
0, jp->vspace);
XClearArea(display, window,
0, jp->win_height - jp->vspace - jp->line_height,
jp->win_width,
jp->line_height + jp->vspace + jp->vspace,
False);
XClearArea(display, window, 0, 0, jp->win_width, jp->vspace, False);
/* See? It's OK. He saw it on the television. */
XClearArea(display, window, 0, 0, jp->hspace, jp->win_height, False);
XClearArea(display, window, jp->win_width - jp->vspace, 0,
jp->hspace, jp->win_height, False);
jp->y--;
lines--;
#if 0
XFlush(display);
if (delay)
(void) usleep (delay * 10);
#endif
}
if (jp->y < 0)
jp->y = 0;
}
jp->break_para = False;
}
if (*(jp->s) != ' ') {
char c = *(jp->s);
int xshift = 0, yshift = 0;
if (!NRAND(50)) {
xshift = NRAND((jp->char_width / 3) + 1); /* mis-strike */
yshift = NRAND((jp->line_height / 6) + 1);
if (!NRAND(3))
yshift *= 2;
if (LRAND() & 1)
xshift = -xshift;
if (LRAND() & 1)
yshift = -yshift;
}
if (!NRAND(250)) { /* introduce adjascent-key typo */
static const char * const typo[] = {
"asqwz", "bghnv", "cdfvx", "dcefsrx", "edrsw34",
"fcdegrtv", "gbfhtvy", "hbgjnuy", "ijkou89", "jhikmnu",
"kijolm,", "lkop;.,", "mjkn,", "nbhjm", "oiklp09",
"plo;[-0", "qasw12", "redft45", "sadewxz", "tfgry56",
"uhijy78", "vbcfg", "waeqs23", "xcdsz", "yuhgt67",
"zasx", ".l,;/",
"ASQWZ", "BGHNV", "CDFVX", "DCEFSRX", "EDRSW#$",
"FCDEGRTV", "GBFHTVY", "HBGJNUY", "IJKOU*(", "JHIKMNU",
"KIJOLM,", "LKOP:><", "MJKN<", "NBHJM", "OIKLP)(",
"PLO:{_)", "QASW!@", "REDFT$%", "SADEWXZ", "TFGRY%^",
"UHIJY&*", "VBCFG", "WAEQS@#", "XCDSZ", "YUHGT^&",
"ZASX", 0 };
int i = 0;
while (typo[i] && typo[i][0] != c)
i++;
if (typo[i])
c = typo[i][0xFF & (NRAND(strlen(typo[i]+1)))];
}
/* caps typo */
if (c >= 'a' && c <= 'z' && (jp->caps || !NRAND(350))) {
c -= ('a' - 'A');
if (c == 'O' && LRAND() & 1)
c = '0';
}
{
Bool overstrike;
do {
(void) XDrawString (display, window, jp->gc,
(jp->x * jp->char_width) + jp->hspace + xshift,
(jp->y * jp->line_height) + jp->vspace + mode_font->ascent + yshift,
&c, 1);
overstrike = (xshift == 0 && yshift == 0 &&
(0 == (LRAND() & 3000)));
if (overstrike) {
if (LRAND() & 1)
xshift--;
else
yshift--;
}
} while (overstrike);
}
if ((tolower(c) != tolower(*(jp->s)))
? (!NRAND(10)) /* backup to correct */
: (!NRAND(400))) { /* fail to advance */
jp->x--;
jp->s--;
#if 0
XFlush(display);
if (delay)
(void) usleep (0xFFFF & (delay + (NRAND(delay * 10))));
#endif
}
}
jp->x++;
jp->s++;
if (!NRAND(200)) {
if (LRAND() & 1 && jp->s != source_message)
jp->s--; /* duplicate character */
else if (*(jp->s))
jp->s++; /* skip character */
}
if (*(jp->s) == 0) {
jp->sentences++;
jp->caps = (!NRAND(40)); /* capitalize sentence */
if (!NRAND(10) || /* randomly break paragraph */
(jp->mode == 0 && (NRAND(10) || jp->sentences > 20))) {
jp->break_para = True;
jp->sentences = 0;
jp->paras++;
if (LRAND() & 1) /* mode=0 50% of the time */
jp->mode = 0;
else
jp->mode = (0xFF & NRAND(5));
if (LRAND() & 1) { /* re-pick margins */
if (jp->columns < 3)
jp->columns = 3;
jp->left = 0xFF & (NRAND(jp->columns / 3));
jp->right = jp->columns - (0xFF & (NRAND(jp->columns / 3)));
if (!NRAND(3)) /* sometimes be wide */
jp->right = jp->left + ((jp->right - jp->left) / 2);
}
if (jp->right - jp->left <= 10) { /* introduce sanity */
jp->left = 0;
jp->right = jp->columns;
}
if (jp->right - jp->left > 50) { /* if wide, shrink and move */
jp->left += (0xFF & (NRAND((jp->columns - 50) + 1)));
jp->right = jp->left + (0xFF & (NRAND(40) + 10));
}
/* oh, gag. */
if (jp->mode == 0 && jp->right - jp->left < 25 && jp->columns > 40) {
jp->right += 20;
if (jp->right > jp->columns)
jp->left -= (jp->right - jp->columns);
}
}
jp->s = source_message;
}
#if 0
XFlush(display);
if (delay) {
(void) usleep (delay);
if (!NRAND(3))
(void) usleep(0xFFFFFF & ((NRAND(delay * 5)) + 1));
if (jp->break_para)
(void) usleep(0xFFFFFF & ((NRAND(delay * 15)) + 1));
}
#endif
#ifdef NFS_COMPLAINTS
if (jp->paras > 5 && (!NRAND(1000)) && jp->y < jp->rows-5) {
int i;
int n = NRAND(3);
jp->y++;
for (i = 0; i < n; i++) {
/* See also http://catalog.com/hopkins/unix-haters/login.html */
const char *n1 =
"NFS server overlook not responding, still trying...";
const char *n2 = "NFS server overlook ok.";
while (*n1) {
(void) XDrawString (display, window, jp->gc,
(jp->x * jp->char_width) + jp->hspace,
(jp->y * jp->line_height) + jp->vspace + mode_font->ascent,
n1, 1);
jp->x++;
if (jp->x >= jp->columns)
jp->x = 0, jp->y++;
n1++;
}
#if 0
XFlush(display);
(void) usleep (5000000);
#endif
while (*n2) {
(void) XDrawString (display, window, jp->gc,
(jp->x * jp->char_width) + jp->hspace,
(jp->y * jp->line_height) + jp->vspace + mode_font->ascent,
n2, 1);
jp->x++;
if (jp->x >= jp->columns)
jp->x = 0, jp->y++;
n2++;
}
jp->y++;
#if 0
XFlush(display);
(void) usleep (500000);
#endif
}
}
#endif
}
#endif /* MODE_xjack */