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

305 lines
7.4 KiB
C

/* -*- Mode: C; tab-width: 4 -*- */
/* image --- image bouncer */
#if !defined( lint ) && !defined( SABER )
static const char sccsid[] = "@(#)image.c 5.00 2000/11/01 xlockmore";
#endif
/*-
* Copyright (c) 1991 by Patrick J. Naughton.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*
* This file is provided AS IS with no warranties of any kind. The author
* shall have no liability with respect to the infringement of copyrights,
* trade secrets or any patents by this file or any part thereof. In no
* event will the author be liable for any lost revenue or profits or
* other special, indirect and consequential damages.
*
* Revision History:
* 01-Nov-2000: Allocation checks
* 10-May-1997: Compatible with xscreensaver
* 03-Nov-1995: Patched to add an arbitrary xpm file.
* 21-Sep-1995: Patch if xpm fails to load <Markus.Zellner@anu.edu.au>.
* 17-Jun-1995: Pixmap stuff of Skip_Burrell@sterling.com added.
* 07-Dec-1994: Icons are now better centered if do not exactly fill an area.
* 29-Jul-1990: Written.
*/
#ifdef STANDALONE
#define MODE_image
#define PROGCLASS "Image"
#define HACK_INIT init_image
#define HACK_DRAW draw_image
#define image_opts xlockmore_opts
#define DEFAULTS "*delay: 2000000 \n" \
"*count: -10 \n" \
"*ncolors: 200 \n" \
"*bitmap: \n"
#include "xlockmore.h" /* in xscreensaver distribution */
#else /* STANDALONE */
#include "xlock.h" /* in xlockmore distribution */
#include "color.h"
#endif /* STANDALONE */
#include "iostuff.h"
#ifdef MODE_image
ModeSpecOpt image_opts =
{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
#ifdef USE_MODULES
ModStruct image_description =
{"image", "init_image", "draw_image", "release_image",
"refresh_image", "init_image", (char *) NULL, &image_opts,
2000000, -10, 1, 1, 64, 1.0, "",
"Shows randomly appearing logos", 0, NULL};
#endif
/* aliases for vars defined in the bitmap file */
#define IMAGE_WIDTH image_width
#define IMAGE_HEIGHT image_height
#define IMAGE_BITS image_bits
#include "image.xbm"
#ifdef HAVE_XPM
#define IMAGE_NAME image_name
#include "image.xpm"
#define DEFAULT_XPM 1
#endif
#define MINICONS 1
typedef struct {
int x, y;
int color;
} imagetype;
typedef struct {
int width, height;
int nrows, ncols;
XPoint image_offset;
int iconcount;
imagetype *icons;
int graphics_format;
GC backGC;
XImage *logo;
Colormap cmap;
unsigned long black;
} imagestruct;
static imagestruct *ims = (imagestruct *) NULL;
static void
free_stuff(Display * display, imagestruct * ip)
{
if (ip->cmap != None) {
XFreeColormap(display, ip->cmap);
if (ip->backGC != None) {
XFreeGC(display, ip->backGC);
ip->backGC = None;
}
ip->cmap = None;
} else
ip->backGC = None;
}
static void
free_image(Display * display, imagestruct * ip)
{
if (ip->icons != NULL) {
free(ip->icons);
ip->icons = (imagetype *) NULL;
}
free_stuff(display, ip);
if (ip->logo != None) {
destroyImage(&ip->logo, &ip->graphics_format);
ip->logo = None;
}
}
static Bool
init_stuff(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
imagestruct *ip = &ims[MI_SCREEN(mi)];
if (ip->logo == None) {
getImage(mi, &ip->logo, IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_BITS,
#ifdef HAVE_XPM
DEFAULT_XPM, IMAGE_NAME,
#endif
&ip->graphics_format, &ip->cmap, &ip->black);
if (ip->logo == None) {
free_image(display, ip);
return False;
}
}
#ifndef STANDALONE
if (ip->cmap != None) {
setColormap(display, window, ip->cmap, MI_IS_INWINDOW(mi));
if (ip->backGC == None) {
XGCValues xgcv;
xgcv.background = ip->black;
if ((ip->backGC = XCreateGC(display, window, GCBackground,
&xgcv)) == None) {
free_image(display, ip);
return False;
}
}
} else
#endif /* STANDALONE */
{
ip->black = MI_BLACK_PIXEL(mi);
ip->backGC = MI_GC(mi);
}
return True;
}
static void
drawimages(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
imagestruct *ip = &ims[MI_SCREEN(mi)];
int i;
MI_CLEARWINDOWCOLORMAPFAST(mi, ip->backGC, ip->black);
if (MI_NPIXELS(mi) <= 2)
XSetForeground(display, ip->backGC, MI_WHITE_PIXEL(mi));
for (i = 0; i < ip->iconcount; i++) {
if (ip->logo != NULL && ip->icons[i].x >= 0) {
if (MI_NPIXELS(mi) > 2 && ip->graphics_format < IS_XPM)
XSetForeground(display, ip->backGC, MI_PIXEL(mi, ip->icons[i].color));
(void) XPutImage(display, window, ip->backGC, ip->logo, 0, 0,
ip->logo->width * ip->icons[i].x + ip->image_offset.x,
ip->logo->height * ip->icons[i].y + ip->image_offset.y,
ip->logo->width, ip->logo->height);
}
}
}
void
init_image(ModeInfo * mi)
{
imagestruct *ip;
int i;
if (ims == NULL) {
if ((ims = (imagestruct *) calloc(MI_NUM_SCREENS(mi),
sizeof (imagestruct))) == NULL)
return;
}
ip = &ims[MI_SCREEN(mi)];
if (!init_stuff(mi))
return;
ip->width = MI_WIDTH(mi);
ip->height = MI_HEIGHT(mi);
if (ip->width > ip->logo->width)
ip->ncols = ip->width / ip->logo->width;
else
ip->ncols = 1;
if (ip->height > ip->logo->height)
ip->nrows = ip->height / ip->logo->height;
else
ip->nrows = 1;
ip->image_offset.x = (ip->width - ip->ncols * ip->logo->width) / 2;
ip->image_offset.y = (ip->height - ip->nrows * ip->logo->height) / 2;
ip->iconcount = MI_COUNT(mi);
if (ip->iconcount < -MINICONS)
ip->iconcount = NRAND(-ip->iconcount - MINICONS + 1) + MINICONS;
else if (ip->iconcount < MINICONS)
ip->iconcount = MINICONS;
if (ip->iconcount > ip->ncols * ip->nrows)
ip->iconcount = ip->ncols * ip->nrows;
if (ip->icons != NULL)
free(ip->icons);
if ((ip->icons = (imagetype *) malloc(ip->iconcount *
sizeof (imagetype))) == NULL) {
free_image(MI_DISPLAY(mi), ip);
return;
}
for (i = 0; i < ip->iconcount; i++)
ip->icons[i].x = -1;
MI_CLEARWINDOWCOLORMAP(mi, ip->backGC, ip->black);
}
void
draw_image(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
int i;
imagestruct *ip;
if (ims == NULL)
return;
ip = &ims[MI_SCREEN(mi)];
if (ip->icons == NULL)
return;
MI_IS_DRAWN(mi) = True;
XSetForeground(display, ip->backGC, ip->black);
for (i = 0; i < ip->iconcount; i++) {
if ((ip->ncols * ip->nrows > ip->iconcount) && ip->icons[i].x >= 0)
XFillRectangle(display, window, ip->backGC,
ip->logo->width * ip->icons[i].x + ip->image_offset.x,
ip->logo->height * ip->icons[i].y + ip->image_offset.y,
ip->logo->width, ip->logo->height);
ip->icons[i].x = NRAND(ip->ncols);
ip->icons[i].y = NRAND(ip->nrows);
ip->icons[i].color = NRAND(MI_NPIXELS(mi));
}
drawimages(mi);
}
void
release_image(ModeInfo * mi)
{
if (ims != NULL) {
int screen;
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
free_image(MI_DISPLAY(mi), &ims[screen]);
free(ims);
ims = (imagestruct *) NULL;
}
}
void
refresh_image(ModeInfo * mi)
{
#ifdef HAVE_XPM
imagestruct *ip;
if (ims == NULL)
return;
ip = &ims[MI_SCREEN(mi)];
if (ip->icons == NULL)
return;
if (ip->graphics_format >= IS_XPM) {
/* This is needed when another program changes the colormap. */
free_image(MI_DISPLAY(mi), ip);
init_image(mi);
return;
}
#endif
drawimages(mi);
}
#endif /* MODE_image */