/* -*- 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 * * 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 */