305 lines
7.4 KiB
C
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 */
|