1 /* -*- Mode: C; tab-width: 4 -*-
2 * flag --- a waving flag
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)flag.c 4.02 97/04/01 xlockmore";
8 /* Copyright (c) 1996 Charles Vidal <vidalc@univ-mlv.fr>.
9 * PEtite demo X11 de charles vidal 15 05 96
10 * tourne sous Linux et SOLARIS
11 * thank's to Bas van Gaalen, Holland, PD, for his sources
12 * in pascal vous devez rajouter une ligne dans mode.c
14 * Permission to use, copy, modify, and distribute this software and its
15 * documentation for any purpose and without fee is hereby granted,
16 * provided that the above copyright notice appear in all copies and that
17 * both that copyright notice and this permission notice appear in
18 * supporting documentation.
20 * This file is provided AS IS with no warranties of any kind. The author
21 * shall have no liability with respect to the infringement of copyrights,
22 * trade secrets or any patents by this file or any part thereof. In no
23 * event will the author be liable for any lost revenue or profits or
24 * other special, indirect and consequential damages.
27 * 22-Jan-98: jwz: made the flag wigglier; added xpm support.
28 * (I tried to do this by re-porting from xlockmore, but the
29 * current xlockmore version is completely inscrutable.)
30 * 13-May-97: jwz@jwz.org: turned into a standalone program.
31 * Made it able to animate arbitrary (runtime) text or bitmaps.
36 # define PROGCLASS "Flag"
37 # define HACK_INIT init_flag
38 # define HACK_DRAW draw_flag
39 # define flag_opts xlockmore_opts
40 # define DEFAULTS "*delay: 50000 \n" \
44 # define BRIGHT_COLORS
45 # define UNIFORM_COLORS
46 # define DEF_FONT "-*-helvetica-bold-r-*-240-*"
47 # define DEF_BITMAP ""
49 # include "xlockmore.h" /* from the xscreensaver distribution */
53 # ifndef PIXEL_ALREADY_TYPEDEFED
54 # define PIXEL_ALREADY_TYPEDEFED /* Sigh, Xmu/Drawing.h needs this... */
60 # include <X11/Xmu/Drawing.h>
62 # include <Xmu/Drawing.h>
66 #include "images/bob.xbm"
68 #else /* !STANDALONE */
69 # include "xlock.h" /* from the xlockmore distribution */
71 #endif /* !STANDALONE */
74 #if defined(VMS) && !defined(HAVE_UNAME) && (__VMS_VER >= 70000000)
79 # include <sys/utsname.h>
80 #endif /* HAVE_UNAME */
83 static XrmOptionDescRec opts[] =
85 { "-bitmap", ".flag.bitmap", XrmoptionSepArg, 0 },
86 { "-text", ".flag.text", XrmoptionSepArg, 0 }
89 #endif /* STANDALONE */
91 ModeSpecOpt flag_opts = {
93 2, opts, 0, NULL, NULL
94 #else /* !STANDALONE */
95 0, NULL, 0, NULL, NULL
96 #endif /* STANDALONE */
100 #include <X11/Xutil.h>
105 #define MAXINITSIZE 6
106 #define MININITSIZE 2
109 #define MAXW(fp) (MAXSCALE * (fp)->image->width + 2 * MAXAMP + (fp)->pointsize)
110 #define MAXH(fp) (MAXSCALE * (fp)->image->height+ 2 * MAXAMP + (fp)->pointsize)
111 #define MINW(fp) (MINSCALE * (fp)->image->width + 2 * MINAMP + (fp)->pointsize)
112 #define MINH(fp) (MINSCALE * (fp)->image->height+ 2 * MINAMP + (fp)->pointsize)
132 static flagstruct *flags = NULL;
137 return ((int) (((float) LRAND() / MAXRAND) * (n + 1.0)));
141 initSintab(ModeInfo * mi)
143 flagstruct *fp = &flags[MI_SCREEN(mi)];
147 * change the periodicity of the sin formula : the maximum of the
148 * periocity seem to be 16 ( 2^4 ), after the drawing isn't good looking
150 int periodicity = random_num(4);
153 /* for (i=0;i<periodicity;i++) puissance*=2; */
154 puissance <<= periodicity;
155 for (i = 0; i < ANGLES; i++)
156 fp->stab[i] = (int) (SINF(i * puissance * M_PI / ANGLES) * fp->samp) +
161 affiche(ModeInfo * mi)
163 Display *display = MI_DISPLAY(mi);
165 flagstruct *fp = &flags[MI_SCREEN(mi)];
167 for (x = 0; x < fp->image->width; x++)
168 for (y = fp->image->height-1; y >= 0; y--) {
169 xp = (int) (fp->size * (float) x) +
170 fp->stab[(fp->sidx + x + y) % ANGLES];
171 yp = (int) (fp->size * (float) y) +
172 fp->stab[(fp->sidx + 4 * x + y + y) % ANGLES];
174 if (fp->image->depth > 1)
175 XSetForeground(display, MI_GC(mi),
176 XGetPixel(fp->image, x, y));
177 else if (XGetPixel(fp->image, x, y))
178 XSetForeground(display, MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
179 else if (MI_NPIXELS(mi) <= 2)
180 XSetForeground(display, MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
182 XSetForeground(display, MI_GC(mi),
183 MI_PIXEL(mi, (y + x + fp->sidx + fp->startcolor) % MI_NPIXELS(mi)));
185 if (fp->pointsize <= 1)
186 XDrawPoint(display, fp->cache, MI_GC(mi), xp, yp);
187 else if (fp->pointsize < 6)
188 XFillRectangle(display, fp->cache, MI_GC(mi), xp, yp,
189 fp->pointsize, fp->pointsize);
191 XFillArc(display, fp->cache, MI_GC(mi), xp, yp,
192 fp->pointsize, fp->pointsize, 0, 360*64);
199 make_flag_bits(ModeInfo *mi)
201 Display *dpy = MI_DISPLAY(mi);
202 flagstruct *fp = &flags[MI_SCREEN(mi)];
203 char *bitmap_name = get_string_resource ("bitmap", "Bitmap");
204 char *text = get_string_resource ("text", "Text");
206 /* If neither a bitmap nor text are specified, randomly select either
207 the builtin bitmap or builtin text. */
208 if ((!bitmap_name || !*bitmap_name) && (!text || !*text))
213 bitmap_name = strdup("(default)");
218 text = strdup("(default)");
224 !!strcmp(bitmap_name, "(default)"))
227 Window window = MI_WINDOW(mi);
228 XWindowAttributes xgwa;
229 XpmAttributes xpmattrs;
232 int width = 0, height = 0;
233 xpmattrs.valuemask = 0;
235 XGetWindowAttributes (dpy, window, &xgwa);
238 xpmattrs.valuemask |= XpmCloseness;
239 xpmattrs.closeness = 40000;
242 xpmattrs.valuemask |= XpmVisual;
243 xpmattrs.visual = xgwa.visual;
246 xpmattrs.valuemask |= XpmDepth;
247 xpmattrs.depth = xgwa.depth;
250 xpmattrs.valuemask |= XpmColormap;
251 xpmattrs.colormap = xgwa.colormap;
254 /* Uh, we don't need these now. We use the colors from the xpm.
255 It kinda sucks that we already allocated them. */
256 XFreeColors(dpy, xgwa.colormap, mi->pixels, mi->npixels, 0L);
258 result = XpmReadFileToPixmap (dpy, window, bitmap_name, &bitmap, 0,
263 fprintf (stderr, "%s: warning: xpm color substitution performed\n",
267 width = xpmattrs.width;
268 height = xpmattrs.height;
275 fprintf (stderr, "%s: xpm: color allocation failed\n", progname);
278 fprintf (stderr, "%s: xpm: out of memory\n", progname);
281 fprintf (stderr, "%s: xpm: unknown error code %d\n", progname,
288 fp->image = XGetImage(dpy, bitmap, 0, 0, width, height, ~0L,
290 XFreePixmap(dpy, bitmap);
293 #endif /* HAVE_XPM */
297 int width, height, xh, yh;
299 XmuLocateBitmapFile (DefaultScreenOfDisplay (dpy),
300 bitmap_name, 0, 0, &width, &height, &xh, &yh);
303 fprintf(stderr, "%s: unable to load bitmap file %s\n",
304 progname, bitmap_name);
307 fp->image = XGetImage(dpy, bitmap, 0, 0, width, height,
309 XFreePixmap(dpy, bitmap);
314 "%s: your vendor doesn't ship the standard Xmu library.\n",
316 fprintf (stderr, "\tWe can't load XBM files without it.\n");
321 else if (text && *text)
324 char *fn = get_string_resource ("font", "Font");
325 char *def_fn = "fixed";
338 if (!strcmp(text, "(default)"))
342 if (uname (&uts) < 0)
344 text = strdup("uname() failed");
349 if ((s = strchr(uts.nodename, '.')))
351 text = (char *) malloc(strlen(uts.nodename) +
352 strlen(uts.sysname) +
353 strlen(uts.release) + 10);
354 sprintf(text, "%s\n%s %s",
355 uts.nodename, uts.sysname, uts.release);
357 #else /* !HAVE_UNAME */
359 text = strdup(getenv("SYS$NODE"));
361 text = strdup("X\nScreen\nSaver");
363 #endif /* !HAVE_UNAME */
367 (text[strlen(text)-1] == '\r' ||
368 text[strlen(text)-1] == '\n'))
369 text[strlen(text)-1] = 0;
371 text2 = strdup(text);
373 if (!fn) fn = def_fn;
374 font = XLoadQueryFont (dpy, fn);
377 fprintf(stderr, "%s: unable to load font %s; using %s\n",
378 progname, fn, def_fn);
379 font = XLoadQueryFont (dpy, def_fn);
382 memset(&overall, 0, sizeof(overall));
385 while ((line = strtok(token, "\r\n")))
388 int ascent, descent, direction;
390 XTextExtents(font, line, strlen(line),
391 &direction, &ascent, &descent, &o2);
392 overall.lbearing = MAX(overall.lbearing, o2.lbearing);
393 overall.rbearing = MAX(overall.rbearing, o2.rbearing);
397 width = overall.lbearing + overall.rbearing + margin + margin + 1;
398 height = ((font->ascent + font->descent) * lines) + margin + margin;
400 bitmap = XCreatePixmap(dpy, MI_WINDOW(mi), width, height, 1);
402 gcv.font = font->fid;
404 gc = XCreateGC (dpy, bitmap, (GCFont | GCForeground), &gcv);
405 XFillRectangle(dpy, bitmap, gc, 0, 0, width, height);
406 XSetForeground(dpy, gc, fg);
410 while ((line = strtok(token, "\r\n")))
413 int ascent, descent, direction, xoff;
416 XTextExtents(font, line, strlen(line),
417 &direction, &ascent, &descent, &o2);
418 xoff = ((overall.lbearing + overall.rbearing) -
419 (o2.lbearing + o2.rbearing)) / 2;
421 XDrawString(dpy, bitmap, gc,
422 overall.lbearing + margin + xoff,
423 ((font->ascent * (lines + 1)) +
424 (font->descent * lines) +
430 XUnloadFont(dpy, font->fid);
431 XFree((XPointer) font);
434 fp->image = XGetImage(dpy, bitmap, 0, 0, width, height, 1L, XYPixmap);
435 XFreePixmap(dpy, bitmap);
439 fp->image = XCreateImage (dpy, MI_VISUAL(mi), 1, XYBitmap, 0,
440 (char *) bob_bits, bob_width, bob_height,
442 fp->image->byte_order = LSBFirst;
443 fp->image->bitmap_bit_order = LSBFirst;
452 #else /* !STANDALONE */
455 make_flag_bits(ModeInfo *mi)
457 flagstruct *fp = &flags[MI_SCREEN(mi)];
463 XCreateImage(MI_DISPLAY(mi), MI_VISUAL(mi),
464 1, XYBitmap, 0, /* dpth, fmt, offset */
465 (char *) calloc ((w+8) / 8, h), /* data */
466 w, h, 8, 0); /* w, h, pad, bpl */
467 /* Geez, what kinda goofy bit order is this?? */
468 for (x = 0; x < w; x++)
469 for (y = h-1; y >= 0; y--)
470 XPutPixel (fp->image, x, y, flag_bits[i++]);
473 #endif /* !STANDALONE */
477 init_flag(ModeInfo * mi)
479 Display *display = MI_DISPLAY(mi);
480 int size = MI_SIZE(mi);
484 if ((flags = (flagstruct *) calloc(MI_NUM_SCREENS(mi),
485 sizeof (flagstruct))) == NULL)
488 fp = &flags[MI_SCREEN(mi)];
492 fp->width = MI_WIN_WIDTH(mi);
493 fp->height = MI_WIN_HEIGHT(mi);
495 fp->samp = MAXAMP; /* Amplitude */
496 fp->sofs = 20; /* ???????? */
497 fp->pointsize = size;
499 fp->pointsize = NRAND(-size - MINSIZE + 1) + MINSIZE;
500 if (fp->pointsize < MINSIZE ||
501 fp->width <= MAXW(fp) || fp->height <= MAXH(fp))
502 fp->pointsize = MINSIZE;
503 fp->size = MAXINITSIZE; /* Initial distance between pts */
504 fp->inctaille = 0.05;
506 fp->sidx = fp->x_flag = fp->y_flag = 0;
508 if (!fp->initialized) {
509 fp->initialized = True;
510 if (!(fp->cache = XCreatePixmap(display, MI_WINDOW(mi),
511 MAXW(fp), MAXH(fp), MI_WIN_DEPTH(mi))))
514 #else /* !STANDALONE */
515 error("%s: catastrophe memoire\n");
516 #endif /* !STANDALONE */
518 XSetForeground(display, MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
519 XFillRectangle(display, fp->cache, MI_GC(mi),
520 0, 0, MAXW(fp), MAXH(fp));
521 /* don't want any exposure events from XCopyArea */
522 XSetGraphicsExposures(display, MI_GC(mi), False);
523 if (MI_NPIXELS(mi) > 2)
524 fp->startcolor = NRAND(MI_NPIXELS(mi));
525 if (fp->width <= MAXW(fp) || fp->height <= MAXH(fp)) {
528 fp->x_flag = random_num(fp->width - MINW(fp));
529 fp->y_flag = random_num(fp->height - MINH(fp));
533 fp->x_flag = random_num(fp->width - MAXW(fp));
534 fp->y_flag = random_num(fp->height - MAXH(fp));
539 XClearWindow(display, MI_WINDOW(mi));
543 draw_flag(ModeInfo * mi)
545 Display *display = MI_DISPLAY(mi);
546 Window window = MI_WINDOW(mi);
547 flagstruct *fp = &flags[MI_SCREEN(mi)];
549 if (fp->width <= MAXW(fp) || fp->height <= MAXH(fp)) {
550 fp->size = MININITSIZE;
551 /* fp->pointsize = MINPOINTSIZE; */
552 XCopyArea(display, fp->cache, window, MI_GC(mi),
553 0, 0, MINW(fp), MINH(fp), fp->x_flag, fp->y_flag);
555 if ((fp->size + fp->inctaille) > MAXSCALE)
556 fp->inctaille = -fp->inctaille;
557 if ((fp->size + fp->inctaille) < MINSCALE)
558 fp->inctaille = -fp->inctaille;
559 fp->size += fp->inctaille;
560 XCopyArea(display, fp->cache, window, MI_GC(mi),
561 0, 0, MAXW(fp), MAXH(fp), fp->x_flag, fp->y_flag);
563 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
564 XFillRectangle(display, fp->cache, MI_GC(mi),
565 0, 0, MAXW(fp), MAXH(fp));
569 fp->sidx %= (ANGLES * MI_NPIXELS(mi));
572 if ((MI_CYCLES(mi) > 0) && (fp->timer >= MI_CYCLES(mi)))
577 release_flag(ModeInfo * mi)
582 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
584 if (flags[screen].cache)
585 XFreePixmap(MI_DISPLAY(mi), flags[screen].cache);
586 if (flags[screen].image)
587 XDestroyImage(flags[screen].image);
589 (void) free((void *) flags);
595 refresh_flag(ModeInfo * mi)
597 /* Do nothing, it will refresh by itself */