xenocara/app/xlockmore/modes/nose.c

915 lines
27 KiB
C
Raw Normal View History

2006-11-26 04:07:42 -07:00
/* -*- Mode: C; tab-width: 4 -*- */
/*-
* nose --- a little guy with a big nose and a hat wanders around
* spewing out messages
*/
#if !defined( lint ) && !defined( SABER )
static const char sccsid[] = "@(#)nose.c 5.00 2000/11/01 xlockmore";
#endif
/*-
* 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
* 06-Jun-1997: Compatible with xscreensaver and now colorized (idea from
* xscreensaver but colors are random).
* 27-Feb-1996: Added new ModeInfo arg to init and callback hooks. Removed
* references to onepause, now uses MI_PAUSE(mi) interface.
* Ron Hitchens <ron@idiom.com>
* 10-Oct-1995: A better way of handling fortunes from a file, thanks to
* Jouk Jansen <joukj@hrem.stm.tudelft.nl>.
* 21-Sep-1995: font option added, debugged for multiscreens
* 12-Aug-1995: xlock version
* 1992: xscreensaver version, noseguy (Jamie Zawinski <jwz@jwz.org>)
* 1990: X11 version, xnlock (Dan Heller <argv@sun.com>)
*/
/*-
* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@mcom.com>
*
* 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.
*/
#ifdef STANDALONE
#define MODE_nose
#define PROGCLASS "Nose"
#define HACK_INIT init_nose
#define HACK_DRAW draw_nose
#define nose_opts xlockmore_opts
#define DEFAULTS "*delay: 100000 \n" \
"*ncolors: 64 \n" \
"*font: \n" \
"*text: \n" \
"*filename: \n" \
"*fortunefile: \n" \
"*program: \n"
#define UNIFORM_COLORS
#include "xlockmore.h" /* in xscreensaver distribution */
#else /* STANDALONE */
#include "xlock.h" /* in xlockmore distribution */
#endif /* STANDALONE */
#include "iostuff.h"
#ifdef MODE_nose
ModeSpecOpt nose_opts =
{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
#ifdef USE_MODULES
ModStruct nose_description =
{"nose", "init_nose", "draw_nose", "release_nose",
"refresh_nose", "init_nose", (char *) NULL, &nose_opts,
100000, 1, 1, 1, 64, 1.0, "",
"Shows a man with a big nose runs around spewing out messages", 0, NULL};
#endif
#include "bitmaps/nose-hat.xbm"
#include "bitmaps/nose-hatd.xbm"
#include "bitmaps/nose-facef.xbm"
#include "bitmaps/nose-faced.xbm"
#include "bitmaps/nose-facel.xbm"
#include "bitmaps/nose-facer.xbm"
#include "bitmaps/nose-shoef.xbm"
#include "bitmaps/nose-shoel.xbm"
#include "bitmaps/nose-shoer.xbm"
#include "bitmaps/nose-stepl.xbm"
#include "bitmaps/nose-stepr.xbm"
#define L 0
#define R 1
#define LSTEP 2
#define RSTEP 3
#define LF 4
#define RF 5
#define F 6
#define D 7
#define PIXMAPS 8
#define PIXMAP_SIZE 64
#define MOVE 0
#define TALK 1
#define FREEZE 2
#ifndef USE_MB
extern XFontStruct *getFont(Display * display);
#else
extern XFontSet getFontSet(Display * display);
#endif
extern char *getWords(int screen, int screens);
extern int isRibbon(void);
typedef struct {
int x, y, width, height;
} window_rect;
typedef struct {
int xs, ys;
int width, height;
GC text_fg_gc, text_bg_gc, noseGC[PIXMAPS];
char *words;
int x, y;
int tinymode; /* walking or getting passwd */
int length, dir, lastdir;
int up;
int busyLoop;
int frames;
int state;
Bool talking;
window_rect s;
Pixmap position[PIXMAPS];
} nosestruct;
static nosestruct *noses = (nosestruct *) NULL;
#ifdef USE_MB
static XFontSet mode_font = None;
#else
static XFontStruct *mode_font = None;
#endif
#ifdef USE_MB
static int font_height(XFontSet f) {
XRectangle ink, log;
if (f == None) {
return 8;
} else {
XmbTextExtents(mode_font, "M<EFBFBD><EFBFBD>", strlen("M<EFBFBD><EFBFBD>"), &ink, &log);
return log.height;
}
}
#else
#define font_height(f) ((f == None) ? 8 : f->ascent + f->descent)
#endif
#define LEFT 001
#define RIGHT 002
#define DOWN 004
#define UP 010
#define FRONT 020
#define X_INCR 3
#define Y_INCR 2
#define YELLOW (MI_NPIXELS(mi) / 6)
#define COPY(d,g,c,p,np,x,y,w,h) XSetForeground(d,g,c);\
XSetStipple(d,g,p); XSetTSOrigin(d,g,x,y);\
XFillRectangle(d,np,g,x,y,w,h)
static void
free_nose(Display *display, nosestruct *np)
{
int pix;
if (np->text_fg_gc != None) {
XFreeGC(display, np->text_fg_gc);
np->text_fg_gc = None;
}
if (np->text_bg_gc != None) {
XFreeGC(display, np->text_bg_gc);
np->text_bg_gc = None;
}
for (pix = 0; pix < PIXMAPS; pix++) {
if (np->position[pix] != None) {
XFreePixmap(display, np->position[pix]);
np->position[pix] = None;
}
if (np->noseGC[pix] != None) {
XFreeGC(display, np->noseGC[pix]);
np->noseGC[pix] = None;
}
}
}
static Bool
pickClothes(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
GC gc = MI_GC(mi);
nosestruct *np = &noses[MI_SCREEN(mi)];
XGCValues gcv;
Pixmap face_pix, hat_pix, shoe_pix, shoel_pix, shoer_pix;
unsigned long hat_color = (MI_NPIXELS(mi) <= 2) ?
MI_WHITE_PIXEL(mi) : MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
unsigned long face_color = (MI_NPIXELS(mi) <= 2) ?
MI_WHITE_PIXEL(mi) : MI_PIXEL(mi, (YELLOW)); /* Racism? */
unsigned long shoe_color = (MI_NPIXELS(mi) <= 2) ?
MI_WHITE_PIXEL(mi) : MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
int i;
gcv.graphics_exposures = False;
gcv.foreground = MI_BLACK_PIXEL(mi);
gcv.background = MI_BLACK_PIXEL(mi);
for (i = 0; i < PIXMAPS; i++) {
if ((np->position[i] = XCreatePixmap(display, window,
PIXMAP_SIZE, PIXMAP_SIZE, MI_DEPTH(mi))) == None)
return False;
if ((np->noseGC[i] = XCreateGC(display, np->position[i],
GCForeground | GCBackground | GCGraphicsExposures,
&gcv)) == None)
return False;
XFillRectangle(display, np->position[i], np->noseGC[i],
0, 0, PIXMAP_SIZE, PIXMAP_SIZE);
}
XSetBackground(display, gc, MI_BLACK_PIXEL(mi));
XSetFillStyle(display, gc, FillStippled);
/* DOWN NOSE GUY */
if ((shoe_pix = XCreateBitmapFromData(display, window,
(char *) nose_shoe_front_bits,
nose_shoe_front_width, nose_shoe_front_height)) == None){
return False;
}
COPY(display, gc, shoe_color, shoe_pix, np->position[D],
(PIXMAP_SIZE - nose_shoe_front_width) / 2,
nose_hat_height + nose_face_front_height + 3,
nose_shoe_front_width, nose_shoe_front_height);
if ((face_pix = XCreateBitmapFromData(display, window,
(char *) nose_face_down_bits,
nose_face_down_width, nose_face_down_height)) == None) {
XFreePixmap(display, shoe_pix);
return False;
}
COPY(display, gc, face_color, face_pix, np->position[D],
(PIXMAP_SIZE - nose_face_down_width) / 2, nose_hat_down_height + 7,
nose_face_down_width, nose_face_down_height);
XFreePixmap(display, face_pix);
if ((hat_pix = XCreateBitmapFromData(display, window,
(char *) nose_hat_down_bits,
nose_hat_down_width, nose_hat_down_height)) == None) {
XFreePixmap(display, shoe_pix);
return False;
}
COPY(display, gc, hat_color, hat_pix, np->position[D],
(PIXMAP_SIZE - nose_hat_down_width) / 2, 7,
nose_hat_down_width, nose_hat_down_height);
XFreePixmap(display, hat_pix);
if (MI_NPIXELS(mi) <= 2) {
XSetFillStyle(display, gc, FillSolid);
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
XFillRectangle(display, np->position[D], gc,
0, nose_hat_down_height + 6, PIXMAP_SIZE, 1);
XSetFillStyle(display, gc, FillStippled);
}
/* FRONT NOSE GUY */
COPY(display, gc, shoe_color, shoe_pix, np->position[F],
(PIXMAP_SIZE - nose_shoe_front_width) / 2,
nose_hat_height + nose_face_front_height + 3,
nose_shoe_front_width, nose_shoe_front_height);
XFreePixmap(display, shoe_pix);
if ((hat_pix = XCreateBitmapFromData(display, window,
(char *) nose_hat_bits,
nose_hat_width, nose_hat_height)) == None) {
return False;
}
COPY(display, gc, hat_color, hat_pix, np->position[F],
(PIXMAP_SIZE - nose_hat_width) / 2, 4,
nose_hat_width, nose_hat_height);
if (MI_NPIXELS(mi) <= 2) {
XSetFillStyle(display, gc, FillSolid);
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
XFillRectangle(display, np->position[F], gc,
0, nose_hat_height + 3, PIXMAP_SIZE, 1);
XSetFillStyle(display, gc, FillStippled);
}
if ((face_pix = XCreateBitmapFromData(display, window,
(char *) nose_face_front_bits,
nose_face_front_width, nose_face_front_height)) == None) {
XFreePixmap(display, hat_pix);
return False;
}
COPY(display, gc, face_color, face_pix, np->position[F],
(PIXMAP_SIZE - nose_face_front_width) / 2, nose_hat_height + 1,
nose_face_front_width, nose_face_front_height);
/* FRONT LEFT NOSE GUY */
if ((shoel_pix = XCreateBitmapFromData(display, window,
(char *) nose_shoe_left_bits,
nose_shoe_left_width, nose_shoe_left_height)) == None) {
XFreePixmap(display, hat_pix);
XFreePixmap(display, face_pix);
return False;
}
COPY(display, gc, shoe_color, shoel_pix, np->position[LF],
(PIXMAP_SIZE - nose_shoe_left_width) / 2 - 4,
nose_hat_height + nose_face_front_height + 3,
nose_shoe_left_width, nose_shoe_left_height);
COPY(display, gc, hat_color, hat_pix, np->position[LF],
(PIXMAP_SIZE - nose_hat_width) / 2, 4,
nose_hat_width, nose_hat_height);
if (MI_NPIXELS(mi) <= 2) {
XSetFillStyle(display, gc, FillSolid);
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
XFillRectangle(display, np->position[LF], gc,
0, nose_hat_height + 3, PIXMAP_SIZE, 1);
XSetFillStyle(display, gc, FillStippled);
}
COPY(display, gc, face_color, face_pix, np->position[LF],
(PIXMAP_SIZE - nose_face_front_width) / 2, nose_hat_height + 1,
nose_face_front_width, nose_face_front_height);
/* FRONT RIGHT NOSE GUY */
if ((shoer_pix = XCreateBitmapFromData(display, window,
(char *) nose_shoe_right_bits,
nose_shoe_right_width, nose_shoe_right_height)) == None) {
XFreePixmap(display, hat_pix);
XFreePixmap(display, shoel_pix);
XFreePixmap(display, face_pix);
return False;
}
COPY(display, gc, shoe_color, shoer_pix, np->position[RF],
(PIXMAP_SIZE - nose_shoe_right_width) / 2 + 4,
nose_hat_height + nose_face_front_height + 3,
nose_shoe_right_width, nose_shoe_right_height);
COPY(display, gc, hat_color, hat_pix, np->position[RF],
(PIXMAP_SIZE - nose_hat_width) / 2, 4,
nose_hat_width, nose_hat_height);
if (MI_NPIXELS(mi) <= 2) {
XSetFillStyle(display, gc, FillSolid);
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
XFillRectangle(display, np->position[RF], gc,
0, nose_hat_height + 3, PIXMAP_SIZE, 1);
XSetFillStyle(display, gc, FillStippled);
}
COPY(display, gc, face_color, face_pix, np->position[RF],
(PIXMAP_SIZE - nose_face_front_width) / 2, nose_hat_height + 1,
nose_face_front_width, nose_face_front_height);
XFreePixmap(display, face_pix);
/* LEFT NOSE GUY */
COPY(display, gc, shoe_color, shoel_pix, np->position[L],
(PIXMAP_SIZE - nose_shoe_left_width) / 2 - 4,
nose_hat_height + nose_face_front_height + 3,
nose_shoe_left_width, nose_shoe_left_height);
XFreePixmap(display, shoel_pix);
COPY(display, gc, hat_color, hat_pix, np->position[L],
(PIXMAP_SIZE - nose_hat_width) / 2, 4,
nose_hat_width, nose_hat_height);
if (MI_NPIXELS(mi) <= 2) {
XSetFillStyle(display, gc, FillSolid);
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
XFillRectangle(display, np->position[L], gc,
0, nose_hat_height + 3, PIXMAP_SIZE, 1);
XSetFillStyle(display, gc, FillStippled);
}
if ((face_pix = XCreateBitmapFromData(display, window,
(char *) nose_face_left_bits,
nose_face_left_width, nose_face_left_height)) == None) {
XFreePixmap(display, hat_pix);
XFreePixmap(display, shoer_pix);
return False;
}
COPY(display, gc, face_color, face_pix, np->position[L],
(PIXMAP_SIZE - nose_face_left_width) / 2 - 4, nose_hat_height + 4,
nose_face_left_width, nose_face_left_height);
/* LEFT NOSE GUY STEPPING */
if ((shoel_pix = XCreateBitmapFromData(display, window,
(char *) nose_step_left_bits,
nose_step_left_width, nose_step_left_height)) == None) {
XFreePixmap(display, hat_pix);
XFreePixmap(display, face_pix);
XFreePixmap(display, shoer_pix);
return False;
}
COPY(display, gc, shoe_color, shoel_pix, np->position[LSTEP],
(PIXMAP_SIZE - nose_step_left_width) / 2,
nose_hat_height + nose_face_front_height - 1,
nose_step_left_width, nose_step_left_height);
XFreePixmap(display, shoel_pix);
COPY(display, gc, hat_color, hat_pix, np->position[LSTEP],
(PIXMAP_SIZE - nose_hat_width) / 2, 4,
nose_hat_width, nose_hat_height);
if (MI_NPIXELS(mi) <= 2) {
XSetFillStyle(display, gc, FillSolid);
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
XFillRectangle(display, np->position[LSTEP], gc,
0, nose_hat_height + 3, PIXMAP_SIZE, 1);
XSetFillStyle(display, gc, FillStippled);
}
COPY(display, gc, face_color, face_pix, np->position[LSTEP],
(PIXMAP_SIZE - nose_face_left_width) / 2 - 4, nose_hat_height + 4,
nose_face_left_width, nose_face_left_height);
XFreePixmap(display, face_pix);
/* RIGHT NOSE GUY */
if ((face_pix = XCreateBitmapFromData(display, window,
(char *) nose_face_right_bits,
nose_face_right_width, nose_face_right_height)) == None) {
XFreePixmap(display, hat_pix);
XFreePixmap(display, shoer_pix);
return False;
}
COPY(display, gc, shoe_color, shoer_pix, np->position[R],
(PIXMAP_SIZE - nose_shoe_right_width) / 2 + 4,
nose_hat_height + nose_face_front_height + 3,
nose_shoe_right_width, nose_shoe_right_height);
XFreePixmap(display, shoer_pix);
COPY(display, gc, hat_color, hat_pix, np->position[R],
(PIXMAP_SIZE - nose_hat_width) / 2, 4,
nose_hat_width, nose_hat_height);
if (MI_NPIXELS(mi) <= 2) {
XSetFillStyle(display, gc, FillSolid);
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
XFillRectangle(display, np->position[R], gc,
0, nose_hat_height + 3, PIXMAP_SIZE, 1);
XSetFillStyle(display, gc, FillStippled);
}
COPY(display, gc, face_color, face_pix, np->position[R],
(PIXMAP_SIZE - nose_face_right_width) / 2 + 4, nose_hat_height + 4,
nose_face_right_width, nose_face_right_height);
/* RIGHT NOSE GUY STEPPING */
if ((shoer_pix = XCreateBitmapFromData(display, window,
(char *) nose_step_right_bits,
nose_step_right_width, nose_step_right_height)) == None) {
XFreePixmap(display, face_pix);
XFreePixmap(display, hat_pix);
return False;
}
COPY(display, gc, shoe_color, shoer_pix, np->position[RSTEP],
(PIXMAP_SIZE - nose_step_right_width) / 2,
nose_hat_height + nose_face_front_height - 1,
nose_step_right_width, nose_step_right_height);
XFreePixmap(display, shoer_pix);
COPY(display, gc, hat_color, hat_pix, np->position[RSTEP],
(PIXMAP_SIZE - nose_hat_width) / 2, 4,
nose_hat_width, nose_hat_height);
XFreePixmap(display, hat_pix);
if (MI_NPIXELS(mi) <= 2) {
XSetFillStyle(display, gc, FillSolid);
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
XFillRectangle(display, np->position[RSTEP], gc,
0, nose_hat_height + 3, PIXMAP_SIZE, 1);
XSetFillStyle(display, gc, FillStippled);
}
COPY(display, gc, face_color, face_pix, np->position[RSTEP],
(PIXMAP_SIZE - nose_face_right_width) / 2 + 4, nose_hat_height + 4,
nose_face_right_width, nose_face_right_height);
XFreePixmap(display, face_pix);
XSetFillStyle(display, gc, FillSolid);
return True;
}
static void
walk(ModeInfo * mi, register int dir)
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
nosestruct *np = &noses[MI_SCREEN(mi)];
register int incr = 0;
if (dir & (LEFT | RIGHT)) { /* left/right movement (mabye up/down too) */
np->up = -np->up; /* bouncing effect (even if hit a wall) */
if (dir & LEFT) {
incr = X_INCR;
np->frames = (np->up < 0) ? L : LSTEP;
} else {
incr = -X_INCR;
np->frames = (np->up < 0) ? R : RSTEP;
}
/* note that maybe neither UP nor DOWN is set! */
if (dir & UP && np->y > Y_INCR)
np->y -= Y_INCR;
else if (dir & DOWN && np->y < np->height - np->ys)
np->y += Y_INCR;
} else if (dir == UP) { /* Explicit up/down movement only (no left/right) */
np->y -= Y_INCR;
XCopyArea(display, np->position[F], window, np->noseGC[F],
0, 0, PIXMAP_SIZE, PIXMAP_SIZE, np->x, np->y);
} else if (dir == DOWN) {
np->y += Y_INCR;
XCopyArea(display, np->position[D], window, np->noseGC[D],
0, 0, PIXMAP_SIZE, PIXMAP_SIZE, np->x, np->y);
} else if (dir == FRONT && np->frames != F) {
if (np->up > 0)
np->up = -np->up;
if (np->lastdir & LEFT)
np->frames = LF;
else if (np->lastdir & RIGHT)
np->frames = RF;
else
np->frames = F;
XCopyArea(display, np->position[np->frames], window, np->noseGC[np->frames],
0, 0, PIXMAP_SIZE, PIXMAP_SIZE, np->x, np->y);
}
if (dir & LEFT)
while (--incr >= 0) {
--np->x;
XCopyArea(display, np->position[np->frames], window, np->noseGC[np->frames],
0, 0, PIXMAP_SIZE, PIXMAP_SIZE, np->x, np->y + np->up);
XFlush(display);
} else if (dir & RIGHT)
while (++incr <= 0) {
++np->x;
XCopyArea(display, np->position[np->frames], window, np->noseGC[np->frames],
0, 0, PIXMAP_SIZE, PIXMAP_SIZE, np->x, np->y + np->up);
XFlush(display);
}
np->lastdir = dir;
}
static int
think(ModeInfo * mi)
{
nosestruct *np = &noses[MI_SCREEN(mi)];
if (LRAND() & 1)
walk(mi, FRONT);
if (LRAND() & 1) {
np->words = getWords(MI_SCREEN(mi), MI_NUM_SCREENS(mi));
return 1;
}
return 0;
}
#define MAXLINES 40
#if 0
#define MAXWIDTH BUFSIZ
#else
#define MAXWIDTH 170
#endif
/*-
Strange but true:
On an HP Pa-RISC with gcc MAXLINES * MAXWIDTH should be <=
around 6800 (40 * 170) or
as: /usr/tmp/cca####.s line#3364 [err#13]
(warning) Use of GR3 when frame>=8192 may cause conflict
*/
static void
talk(ModeInfo * mi, Bool force_erase)
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
nosestruct *np = &noses[MI_SCREEN(mi)];
int width = 0, height, Y, Z, total = 0;
register char *p, *p2;
char buf[BUFSIZ], args[MAXLINES][MAXWIDTH];
#ifdef USE_MB
XRectangle ink, log;
#endif
/* clear what we've written */
if (np->talking || force_erase) {
if (!np->talking)
return;
XFillRectangle(display, window, np->text_bg_gc, np->s.x - 5, np->s.y - 5,
np->s.width + 10, np->s.height + 10);
np->talking = False;
if (!force_erase)
np->state = MOVE;
return;
}
np->talking = True;
walk(mi, FRONT);
p = strncpy(buf, np->words, BUFSIZ);
if (!(p2 = (char *) strchr(p, '\n')) || !p2[1]) {
(void) strncpy(args[0], np->words, MAXWIDTH - 1);
total = strlen(args[0]);
args[0][MAXWIDTH - 1] = '\0';
if (mode_font == None)
width = 8;
else {
#ifdef USE_MB
XmbTextExtents(mode_font, np->words, total, &ink, &log);
width = ink.width;
#else
width = XTextWidth(mode_font, np->words, total);
#endif
}
height = 0;
} else
/* p2 now points to the first '\n' */
for (height = 0; p && height < MAXLINES; height++) {
int w;
*p2 = 0;
#ifdef USE_MB
XmbTextExtents(mode_font, p, p2 - p, &ink, &log);
if (mode_font != None && (w = log.width) > width)
width = w;
#else
if (mode_font != None &&
(w = XTextWidth(mode_font, p, p2 - p)) > width)
width = w;
#endif
total += p2 - p; /* total chars; count to determine reading time */
(void) strncpy(args[height], p, MAXWIDTH - 1);
args[height][MAXWIDTH - 1] = '\0';
p = p2 + 1;
if (!(p2 = (char *) strchr(p, '\n')))
break;
}
height++;
/*
* Figure out the height and width in imagepixels (height, width) extend the
* new box by 15 pixels on the sides (30 total) top and bottom.
*/
np->s.width = width + 30;
np->s.height = height * font_height(mode_font) + 30;
if (np->x - np->s.width - 10 < 5)
np->s.x = 5;
else if ((np->s.x = np->x + 32 - (np->s.width + 15) / 2)
+ np->s.width + 15 > np->width - 5)
np->s.x = np->width - 15 - np->s.width;
if (np->y - np->s.height - 10 < 5)
np->s.y = np->y + np->ys + 5;
else
np->s.y = np->y - 5 - np->s.height;
XFillRectangle(display, window, np->text_bg_gc,
np->s.x, np->s.y, np->s.width, np->s.height);
/* make a box that's 5 pixels thick. Then add a thin box inside it */
XSetLineAttributes(display, np->text_fg_gc, 5, 0, 0, 0);
XDrawRectangle(display, window, np->text_fg_gc,
np->s.x, np->s.y, np->s.width - 1, np->s.height - 1);
XSetLineAttributes(display, np->text_fg_gc, 0, 0, 0, 0);
XDrawRectangle(display, window, np->text_fg_gc,
np->s.x + 7, np->s.y + 7, np->s.width - 15, np->s.height - 15);
Y = 15 + font_height(mode_font);
/* now print each string in reverse order (start at bottom of box) */
for (Z = 0; Z < height; Z++) {
#ifdef USE_MB
(void) XmbDrawString(display, window, mode_font, np->text_fg_gc,
np->s.x + 15, np->s.y + Y, args[Z], strlen(args[Z]));
#else
(void) XDrawString(display, window, np->text_fg_gc,
np->s.x + 15, np->s.y + Y, args[Z], strlen(args[Z]));
#endif
Y += font_height(mode_font);
}
np->busyLoop = (total / 15) * 10;
if (np->busyLoop < 30)
np->busyLoop = 30;
np->state = TALK;
}
static int
look(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
/*GC gc = MI_GC(mi); */
nosestruct *np = &noses[MI_SCREEN(mi)];
int i;
if (NRAND(3)) {
i = (LRAND() & 1) ? D : F;
XCopyArea(display, np->position[i], window, np->noseGC[i],
0, 0, PIXMAP_SIZE, PIXMAP_SIZE, np->x, np->y);
return 3;
}
if (!NRAND(5))
return 0;
if (NRAND(3)) {
i = (LRAND() & 1) ? LF : RF;
XCopyArea(display, np->position[i], window, np->noseGC[i],
0, 0, PIXMAP_SIZE, PIXMAP_SIZE, np->x, np->y);
return 3;
}
if (!NRAND(5))
return 0;
i = (LRAND() & 1) ? L : R;
XCopyArea(display, np->position[i], window, np->noseGC[i],
0, 0, PIXMAP_SIZE, PIXMAP_SIZE, np->x, np->y);
return 3;
}
static void
move(ModeInfo * mi)
{
nosestruct *np = &noses[MI_SCREEN(mi)];
if (!np->length) {
register int tries = 0;
np->dir = 0;
if ((LRAND() & 1) && think(mi)) {
talk(mi, False); /* sets timeout to itself */
return;
}
if (!NRAND(3) && (np->busyLoop = look(mi))) {
np->state = MOVE;
return;
}
np->busyLoop = 3 + NRAND(3);
do {
if (!tries)
np->length = np->width / 100 + NRAND(90), tries = 8;
else
tries--;
switch (NRAND(8)) {
case 0:
if (np->x - X_INCR * np->length >= 5)
np->dir = LEFT;
break;
case 1:
if (np->x + X_INCR * np->length <= np->width - np->xs - 6)
np->dir = RIGHT;
break;
case 2:
if (np->y - (Y_INCR * np->length) >= 5)
np->dir = UP;
break;
case 3:
if (np->y + Y_INCR * np->length <= np->height - np->ys - 6)
np->dir = DOWN;
break;
case 4:
if (np->x - X_INCR * np->length >= 5 &&
np->y - (Y_INCR * np->length) >= 5)
np->dir = (LEFT | UP);
break;
case 5:
if (np->x + X_INCR * np->length <= np->width - np->xs - 6 &&
np->y - Y_INCR * np->length >= 5)
np->dir = (RIGHT | UP);
break;
case 6:
if (np->x - X_INCR * np->length >= 5 &&
np->y + Y_INCR * np->length <= np->height - np->ys - 6)
np->dir = (LEFT | DOWN);
break;
case 7:
if (np->x + X_INCR * np->length <= np->width - np->xs - 6 &&
np->y + Y_INCR * np->length <= np->height - np->ys - 6)
np->dir = (RIGHT | DOWN);
break;
default:
/* No Defaults */
break;
}
} while (!np->dir);
}
walk(mi, np->dir);
--np->length;
np->state = MOVE;
}
void
init_nose(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
GC gc = MI_GC(mi);
XGCValues gcv;
nosestruct *np;
if (noses == NULL) {
if ((noses = (nosestruct *) calloc(MI_NUM_SCREENS(mi),
sizeof (nosestruct))) == NULL)
return;
}
np = &noses[MI_SCREEN(mi)];
np->width = MI_WIDTH(mi) + 2;
np->height = MI_HEIGHT(mi) + 2;
np->tinymode = (np->width + np->height < 4 * PIXMAP_SIZE);
np->xs = PIXMAP_SIZE;
np->ys = PIXMAP_SIZE;
MI_CLEARWINDOW(mi);
XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
/* do not want any exposure events from XCopyPlane */
XSetGraphicsExposures(display, gc, False);
if (mode_font == None) {
#ifdef USE_MB
mode_font = getFontSet(display);
#else
mode_font = getFont(display);
#endif
}
if (np->noseGC[0] == None)
if (!pickClothes(mi)) {
free_nose(display, np);
return;
}
np->words = getWords(MI_SCREEN(mi), MI_NUM_SCREENS(mi));
if (np->text_fg_gc == None && mode_font != None) {
#ifndef USE_MB
gcv.font = mode_font->fid;
XSetFont(display, gc, mode_font->fid);
#endif
gcv.graphics_exposures = False;
gcv.foreground = MI_WHITE_PIXEL(mi);
gcv.background = MI_BLACK_PIXEL(mi);
if ((np->text_fg_gc = XCreateGC(display, window,
#ifdef USE_MB
GCForeground | GCBackground | GCGraphicsExposures,
#else
GCForeground | GCBackground | GCGraphicsExposures | GCFont,
#endif
&gcv)) == None) {
free_nose(display, np);
return;
}
gcv.foreground = MI_BLACK_PIXEL(mi);
gcv.background = MI_WHITE_PIXEL(mi);
if ((np->text_bg_gc = XCreateGC(display, window,
#ifdef USE_MB
GCForeground | GCBackground | GCGraphicsExposures,
#else
GCForeground | GCBackground | GCGraphicsExposures | GCFont,
#endif
&gcv)) == None) {
free_nose(display, np);
return;
}
}
np->up = 1;
if (np->tinymode) {
int pos = NRAND(PIXMAPS);
np->x = 0;
np->y = 0;
XCopyArea(display, np->position[pos], window, np->noseGC[pos],
0, 0, PIXMAP_SIZE, PIXMAP_SIZE,
(np->width - PIXMAP_SIZE) / 2,
(np->height - PIXMAP_SIZE) / 2);
np->state = FREEZE;
} else {
np->x = np->width / 2;
np->y = np->height / 2;
np->state = MOVE;
}
XFlush(display);
}
void
draw_nose(ModeInfo * mi)
{
nosestruct *np;
if (noses == NULL)
return;
np = &noses[MI_SCREEN(mi)];
if (np->noseGC[0] == None)
return;
MI_IS_DRAWN(mi) = True;
if (np->busyLoop > 0) {
np->busyLoop--;
return;
}
switch (np->state) {
case MOVE:
move(mi);
break;
case TALK:
talk(mi, 0);
break;
}
}
void
release_nose(ModeInfo * mi)
{
if (noses != NULL) {
int screen;
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
free_nose(MI_DISPLAY(mi), &noses[screen]);
free(noses);
noses = (nosestruct *) NULL;
}
if (mode_font != None) {
#ifdef USE_MB
XFreeFontSet(MI_DISPLAY(mi), mode_font);
#else
XFreeFont(MI_DISPLAY(mi), mode_font);
#endif
mode_font = None;
}
}
void
refresh_nose(ModeInfo * mi)
{
MI_CLEARWINDOW(mi);
}
#endif /* MODE_nose */