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

389 lines
10 KiB
C

/* -*- Mode: C; tab-width: 4 -*- */
/* decay --- decayscreen */
#if !defined( lint ) && !defined( SABER )
static const char sccsid[] = "@(#)decay.c 5.00 2000/11/01 xlockmore";
#endif
/* xscreensaver, Copyright (c) 1992, 1993, 1994, 1996, 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.
*/
/*
* Revision History:
* 01-Nov-2000: Allocation checks
* 17-Mar-1999: Converted from xscreensaver's decayscreen
*
* decayscreen
*
* Based on slidescreen program from the xscreensaver application and the
* decay program for Sun framebuffers. This is the comment from the decay.c
* file:
* decay.c
* find the screen bitmap for the console and make it "decay" by
* randomly shifting random rectangles by one pixelwidth at a time.
*
* by David Wald, 1988
* rewritten by Natuerlich!
* based on a similar "utility" on the Apollo ring at Yale.
* X version by
*
* Vivek Khera <khera@cs.duke.edu>
* 5-AUG-1993
*
* Hacked by jwz, 28-Nov-97 (sped up and added new motion directions)
*/
#ifdef STANDALONE
#define MODE_decay
#define PROGCLASS "Decay"
#define HACK_INIT init_decay
#define HACK_DRAW draw_decay
#define decay_opts xlockmore_opts
#define DEFAULTS "*delay: 200000 \n" \
"*count: 6 \n" \
"*cycles: 30 \n" \
"*ncolors: 200 \n"
#include "xlockmore.h" /* in xscreensaver distribution */
#else /* STANDALONE */
#include "xlock.h" /* in xlockmore distribution */
#endif /* STANDALONE */
#include "iostuff.h"
#include "color.h"
#ifdef MODE_decay
extern Bool hide;
ModeSpecOpt decay_opts =
{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
#ifdef USE_MODULES
ModStruct decay_description =
{"decay", "init_decay", "draw_decay", "release_decay",
"refresh_decay", "init_decay", (char *) NULL, &decay_opts,
200000, 6, 30, 1, 64, 0.3, "",
"Shows a decaying screen", 0, NULL};
#endif
#define DECAY_WIDTH image_width
#define DECAY_HEIGHT image_height
#define DECAY_BITS image_bits
#include "decay.xbm"
#ifdef HAVE_XPM
#define DECAY_NAME image_name
#include "decay.xpm"
#define DEFAULT_XPM 1
#endif
typedef struct
{
XPoint windowsize;
int mode;
XPoint randompos, randpos;
XImage *logo;
GC backGC;
Colormap cmap;
int graphics_format;
unsigned long black;
Bool hide;
} decaystruct;
static decaystruct *decay_info = (decaystruct *) NULL;
#define SHUFFLE 0
#define UP 1
#define LEFT 2
#define RIGHT 3
#define DOWN 4
#define UPLEFT 5
#define DOWNLEFT 6
#define UPRIGHT 7
#define DOWNRIGHT 8
#define IN 9
#define OUT 10
#define DEGREE 1
static void
free_decay(Display * display, decaystruct * dp)
{
if (dp->cmap != None) {
XFreeColormap(display, dp->cmap);
if (dp->backGC != None) {
XFreeGC(display, dp->backGC);
dp->backGC = None;
}
dp->cmap = None;
} else
dp->backGC = None;
if (dp->hide && (dp->logo != None)) {
destroyImage(&dp->logo, &dp->graphics_format);
dp->logo = None;
}
}
static void
alloc_decay(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
decaystruct *dp = &decay_info[MI_SCREEN(mi)];
if (dp->hide) {
if (dp->logo == None) {
getImage(mi, &dp->logo, DECAY_WIDTH, DECAY_HEIGHT, DECAY_BITS,
#ifdef HAVE_XPM
DEFAULT_XPM, DECAY_NAME,
#endif
&dp->graphics_format, &dp->cmap, &dp->black);
if (dp->logo == None) {
free_decay(display, dp);
return;
}
}
#ifndef STANDALONE
if (dp->cmap != None) {
setColormap(display, window, dp->cmap, MI_IS_INWINDOW(mi));
if (dp->backGC == None) {
XGCValues xgcv;
xgcv.background = dp->black;
dp->backGC = XCreateGC(display, window, GCBackground, &xgcv);
if (dp->backGC == None) {
free_decay(display, dp);
return;
}
}
} else
#endif /* STANDALONE */
{
dp->black = MI_BLACK_PIXEL(mi);
dp->backGC = MI_GC(mi);
}
}
#ifndef STANDALONE
else {
setColormap(display, window, DefaultColormapOfScreen(MI_SCREENPTR(mi)), MI_IS_INWINDOW(mi));
dp->backGC = MI_GC(mi);
}
#endif /* STANDALONE */
}
void
init_decay(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
decaystruct *dp;
char *s = (char*) "random";
if (decay_info == NULL) {
if ((decay_info = (decaystruct *) calloc(MI_NUM_SCREENS(mi),
sizeof(decaystruct))) == NULL)
return;
}
dp = &decay_info[MI_SCREEN(mi)];
if (s && !strcmp(s, "shuffle")) dp->mode = SHUFFLE;
else if (s && !strcmp(s, "up")) dp->mode = UP;
else if (s && !strcmp(s, "left")) dp->mode = LEFT;
else if (s && !strcmp(s, "right")) dp->mode = RIGHT;
else if (s && !strcmp(s, "down")) dp->mode = DOWN;
else if (s && !strcmp(s, "upleft")) dp->mode = UPLEFT;
else if (s && !strcmp(s, "downleft")) dp->mode = DOWNLEFT;
else if (s && !strcmp(s, "upright")) dp->mode = UPRIGHT;
else if (s && !strcmp(s, "downright")) dp->mode = DOWNRIGHT;
else if (s && !strcmp(s, "in")) dp->mode = IN;
else if (s && !strcmp(s, "out")) dp->mode = OUT;
else {
if (s && *s && !!strcmp(s, "random"))
(void) fprintf(stderr, "%s: unknown mode %s\n", ProgramName, s);
dp->mode = (int) (LRAND() % (OUT+1));
}
if (MI_IS_FULLRANDOM(mi) && !hide)
dp->hide = (Bool) (LRAND() & 1);
else
dp->hide = hide;
dp->windowsize.x = MI_WIDTH(mi);
dp->windowsize.y = MI_HEIGHT(mi);
alloc_decay(mi);
if (!dp->backGC)
return;
if (dp->hide) {
/* do not want any exposure events from XCopyArea */
XSetGraphicsExposures(display, dp->backGC, False);
MI_CLEARWINDOWCOLORMAP(mi, dp->backGC, dp->black);
dp->randompos.x =
NRAND(MAX((dp->windowsize.x - dp->logo->width), 1));
dp->randompos.y =
NRAND(MAX((dp->windowsize.y - dp->logo->height), 1));
if (MI_NPIXELS(mi) <= 2)
XSetForeground(display, dp->backGC, MI_WHITE_PIXEL(mi));
else
XSetForeground(display, dp->backGC, MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
(void) XPutImage(display, window, dp->backGC, dp->logo,
(int) (NRAND(MAX(1, (dp->logo->width - dp->windowsize.x)))),
(int) (NRAND(MAX(1, (dp->logo->height - dp->windowsize.y)))),
dp->randompos.x, dp->randompos.y,
dp->windowsize.x, dp->windowsize.y);
} else {
XCopyArea (MI_DISPLAY(mi), MI_ROOT_PIXMAP(mi), MI_WINDOW(mi),
dp->backGC, 0, 0, MI_WIDTH(mi), MI_HEIGHT(mi),
0, 0);
XFlush(MI_DISPLAY(mi));
}
}
/*
* perform one iteration of decay
*/
void
draw_decay (ModeInfo * mi)
{
int left, top, width, height, toleft, totop;
#define L 101
#define R 102
#define U 103
#define D 104
static int no_bias[] = { L,L,L,L, R,R,R,R, U,U,U,U, D,D,D,D };
static int up_bias[] = { L,L,L,L, R,R,R,R, U,U,U,U, U,U,D,D };
static int down_bias[] = { L,L,L,L, R,R,R,R, U,U,D,D, D,D,D,D };
static int left_bias[] = { L,L,L,L, L,L,R,R, U,U,U,U, D,D,D,D };
static int right_bias[] = { L,L,R,R, R,R,R,R, U,U,U,U, D,D,D,D };
static int upleft_bias[] = { L,L,L,L, L,R,R,R, U,U,U,U, U,D,D,D };
static int downleft_bias[] = { L,L,L,L, L,R,R,R, U,U,U,D, D,D,D,D };
static int upright_bias[] = { L,L,L,R, R,R,R,R, U,U,U,U, U,D,D,D };
static int downright_bias[] = { L,L,L,R, R,R,R,R, U,U,U,D, D,D,D,D };
int *bias, side;
decaystruct * dp;
if (decay_info == NULL)
return;
dp = &decay_info[MI_SCREEN(mi)];
if (dp->backGC == None)
return;
MI_IS_DRAWN(mi) = True;
switch (dp->mode) {
case SHUFFLE: bias = no_bias; break;
case UP: bias = up_bias; break;
case LEFT: bias = left_bias; break;
case RIGHT: bias = right_bias; break;
case DOWN: bias = down_bias; break;
case UPLEFT: bias = upleft_bias; break;
case DOWNLEFT: bias = downleft_bias; break;
case UPRIGHT: bias = upright_bias; break;
case DOWNRIGHT: bias = downright_bias; break;
case IN: bias = no_bias; break;
case OUT: bias = no_bias; break;
default: bias = no_bias;
if (MI_IS_VERBOSE(mi)) {
(void) fprintf(stderr, "Weirdness in draw_decay()\n");
(void) fprintf(stderr, "dp->mode = %d\n", dp->mode);
}
}
left = NRAND(dp->windowsize.x);
top = NRAND(dp->windowsize.y);
width = NRAND(dp->windowsize.x - left);
height = NRAND(dp->windowsize.y - top);
toleft = left;
totop = top;
if (dp->mode == IN || dp->mode == OUT) {
int x = left+(width/2);
int y = top+(height/2);
int cx = dp->windowsize.x/2;
int cy = dp->windowsize.y/2;
if (dp->mode == IN) {
if (x > cx && y > cy) bias = upleft_bias;
else if (x < cx && y > cy) bias = upright_bias;
else if (x < cx && y < cy) bias = downright_bias;
else /* (x > cx && y < cy)*/ bias = downleft_bias;
} else {
if (x > cx && y > cy) bias = downright_bias;
else if (x < cx && y > cy) bias = downleft_bias;
else if (x < cx && y < cy) bias = upleft_bias;
else /* (x > cx && y < cy)*/ bias = upright_bias;
}
}
side = bias[LRAND() % (sizeof(no_bias)/sizeof(*no_bias))];
switch (side) {
case L: toleft = left-DEGREE; break;
case R: toleft = left+DEGREE; break;
case U: totop = top-DEGREE; break;
case D: totop = top+DEGREE; break;
default:
if (MI_IS_VERBOSE(mi)) {
(void) fprintf(stderr, "Weirdness in draw_decay()\n");
(void) fprintf(stderr, "side = %d\n", side);
}
}
XCopyArea (MI_DISPLAY(mi), MI_WINDOW(mi), MI_WINDOW(mi),
dp->backGC, left, top, width, height,
toleft, totop);
XFlush(MI_DISPLAY(mi));
}
void
refresh_decay(ModeInfo * mi)
{
#ifdef HAVE_XPM
decaystruct *dp;
if (decay_info == NULL)
return;
dp = &decay_info[MI_SCREEN(mi)];
if (dp->graphics_format >= IS_XPM) {
/* This is needed when another program changes the colormap. */
free_decay(MI_DISPLAY(mi), dp);
init_decay(mi);
return;
}
#endif
}
void
release_decay(ModeInfo * mi)
{
if (decay_info != NULL) {
int screen;
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
free_decay(MI_DISPLAY(mi), &decay_info[screen]);
free(decay_info);
decay_info = (decaystruct *) NULL;
}
}
#endif /* MODE_decay */