http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.14.tar.gz
[xscreensaver] / hacks / flag.c
1 /* -*- Mode: C; tab-width: 4 -*-
2  * flag --- a waving flag
3  */
4 #if 0
5 static const char sccsid[] = "@(#)flag.c        4.02 97/04/01 xlockmore";
6 #endif
7
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
13  *
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.
19  *
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.
25  *
26  * Revision History: 
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.
32  * 01-May-96: written.
33  */
34
35 #ifdef STANDALONE
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"                     \
41                                         "*cycles:               1000    \n"                     \
42                                         "*size:                 -7      \n"                     \
43                                         "*ncolors:              200     \n"
44 # define BRIGHT_COLORS
45 # define UNIFORM_COLORS
46 # define DEF_FONT                                       "-*-helvetica-bold-r-*-240-*"
47 # define DEF_BITMAP                                     ""
48 # define DEF_TEXT                                       ""
49 # include "xlockmore.h"                         /* from the xscreensaver distribution */
50
51 #include "xpm-pixmap.h"
52
53 #include "images/bob.xbm"
54
55 #else  /* !STANDALONE */
56 # include "xlock.h"                                     /* from the xlockmore distribution */
57 # include "flag.h"
58 #endif /* !STANDALONE */
59
60
61 #ifdef HAVE_UNAME
62 # include <sys/utsname.h>
63 #endif /* HAVE_UNAME */
64
65 #ifdef STANDALONE
66 static XrmOptionDescRec opts[] =
67 {
68   { "-bitmap", ".flag.bitmap", XrmoptionSepArg, 0 },
69   { "-text",   ".flag.text",   XrmoptionSepArg, 0 }
70 };
71
72 #endif /* STANDALONE */
73
74 ModeSpecOpt flag_opts = {
75 #ifdef STANDALONE
76   2, opts, 0, NULL, NULL
77 #else  /* !STANDALONE */
78   0, NULL, 0, NULL, NULL
79 #endif /* STANDALONE */
80 };
81
82 #include <string.h>
83 #include <X11/Xutil.h>
84
85 #define MINSIZE 1
86 #define MAXSCALE 8
87 #define MINSCALE 2
88 #define MAXINITSIZE 6
89 #define MININITSIZE 2
90 #define MINAMP 5
91 #define MAXAMP 20
92 #define MAXW(fp) (MAXSCALE * (fp)->image->width + 2 * MAXAMP + (fp)->pointsize)
93 #define MAXH(fp) (MAXSCALE * (fp)->image->height+ 2 * MAXAMP + (fp)->pointsize)
94 #define MINW(fp) (MINSCALE * (fp)->image->width + 2 * MINAMP + (fp)->pointsize)
95 #define MINH(fp) (MINSCALE * (fp)->image->height+ 2 * MINAMP + (fp)->pointsize)
96 #define ANGLES          360
97
98 typedef struct {
99         int         samp;
100         int         sofs;
101         int         sidx;
102         int         x_flag, y_flag;
103         int         timer;
104         int         initialized;
105         int         stab[ANGLES];
106         Pixmap      cache;
107         int         width, height;
108         int         pointsize;
109         float      size;
110         float      inctaille;
111         int         startcolor;
112     XImage     *image;
113 } flagstruct;
114
115 static flagstruct *flags = NULL;
116
117 static int
118 random_num(int n)
119 {
120         return ((int) (((float) LRAND() / MAXRAND) * (n + 1.0)));
121 }
122
123 static void
124 initSintab(ModeInfo * mi)
125 {
126         flagstruct *fp = &flags[MI_SCREEN(mi)];
127         int         i;
128
129   /*-
130    * change the periodicity of the sin formula : the maximum of the
131    * periocity seem to be 16 ( 2^4 ), after the drawing isn't good looking
132    */
133         int         periodicity = random_num(4);
134         int         puissance = 1;
135
136         /* for (i=0;i<periodicity;i++) puissance*=2; */
137         puissance <<= periodicity;
138         for (i = 0; i < ANGLES; i++)
139                 fp->stab[i] = (int) (SINF(i * puissance * M_PI / ANGLES) * fp->samp) +
140                         fp->sofs;
141 }
142
143 static void
144 affiche(ModeInfo * mi)
145 {
146         Display    *display = MI_DISPLAY(mi);
147         int         x, y, xp, yp;
148         flagstruct *fp = &flags[MI_SCREEN(mi)];
149
150         for (x = 0; x < fp->image->width; x++)
151                 for (y = fp->image->height-1; y >= 0; y--) {
152                         xp = (int) (fp->size * (float) x) +
153                                 fp->stab[(fp->sidx + x + y) % ANGLES];
154                         yp = (int) (fp->size * (float) y) +
155                                 fp->stab[(fp->sidx + 4 * x + y + y) % ANGLES];
156
157                         if (fp->image->depth > 1)
158                           XSetForeground(display, MI_GC(mi),
159                                                          XGetPixel(fp->image, x, y));
160                         else if (XGetPixel(fp->image, x, y))
161                                 XSetForeground(display, MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
162                         else if (MI_NPIXELS(mi) <= 2)
163                                 XSetForeground(display, MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
164                         else
165                                 XSetForeground(display, MI_GC(mi),
166                                                MI_PIXEL(mi, (y + x + fp->sidx + fp->startcolor) % MI_NPIXELS(mi)));
167
168                         if (fp->pointsize <= 1)
169                                 XDrawPoint(display, fp->cache, MI_GC(mi), xp, yp);
170                         else if (fp->pointsize < 6)
171                                 XFillRectangle(display, fp->cache, MI_GC(mi), xp, yp,
172                                                            fp->pointsize, fp->pointsize);
173                         else
174                                 XFillArc(display, fp->cache, MI_GC(mi), xp, yp,
175                                                  fp->pointsize, fp->pointsize, 0, 360*64);
176                 }
177 }
178
179 #ifdef STANDALONE
180
181 static void
182 make_flag_bits(ModeInfo *mi)
183 {
184   Display *dpy = MI_DISPLAY(mi);
185   flagstruct *fp = &flags[MI_SCREEN(mi)];
186   char *bitmap_name = get_string_resource ("bitmap", "Bitmap");
187   char *text = get_string_resource ("text", "Text");
188
189   /* If neither a bitmap nor text are specified, randomly select either
190          the builtin bitmap or builtin text. */
191   if ((!bitmap_name || !*bitmap_name) && (!text || !*text))
192         {
193           if (random() & 1)
194                 {
195                   free(bitmap_name);
196                   bitmap_name = strdup("(default)");
197                 }
198           else
199                 {
200                   free(text);
201                   text = strdup("(default)");
202                 }
203         }
204
205   if (bitmap_name &&
206           *bitmap_name &&
207           !!strcmp(bitmap_name, "(default)"))
208         {
209           Pixmap bitmap = 0;
210       int width = 0;
211       int height = 0;
212
213       bitmap = xpm_file_to_pixmap (dpy, MI_WINDOW (mi), bitmap_name,
214                                    &width, &height, 0);
215           if (bitmap)
216                 {
217                   fp->image = XGetImage(dpy, bitmap, 0, 0, width, height, ~0L,
218                                                                 ZPixmap);
219                   XFreePixmap(dpy, bitmap);
220                 }
221         }
222   else if (text && *text)
223         {
224           char *text2;
225           char *fn = get_string_resource ("font", "Font");
226           char *def_fn = "fixed";
227           char *line, *token;
228           int width, height;
229           int lines;
230           int margin = 2;
231           int fg = 1;
232           int bg = 0;
233           Pixmap bitmap;
234           XFontStruct *font;
235           XCharStruct overall;
236       XGCValues gcv;
237           GC gc;
238
239           if (!strcmp(text, "(default)"))
240                 {
241 # ifdef HAVE_UNAME
242                   struct utsname uts;
243                   if (uname (&uts) < 0)
244                         {
245                           text = strdup("uname() failed");
246                         }
247                   else
248                         {
249                           char *s;
250                           if ((s = strchr(uts.nodename, '.')))
251                                 *s = 0;
252                           text = (char *) malloc(strlen(uts.nodename) +
253                                                                          strlen(uts.sysname) +
254                                                                          strlen(uts.version) +
255                                                                          strlen(uts.release) + 10);
256 # ifdef _AIX
257                           sprintf(text, "%s\n%s %s.%s",
258                                           uts.nodename, uts.sysname, uts.version, uts.release);
259 # else  /* !_AIX */
260                           sprintf(text, "%s\n%s %s",
261                                           uts.nodename, uts.sysname, uts.release);
262 # endif /* !_AIX */
263                         }
264 #else   /* !HAVE_UNAME */
265 # ifdef VMS
266                   text = strdup(getenv("SYS$NODE"));
267 # else
268                   text = strdup("X\nScreen\nSaver");
269 # endif
270 #endif  /* !HAVE_UNAME */
271                 }
272
273           while (*text &&
274                          (text[strlen(text)-1] == '\r' ||
275                           text[strlen(text)-1] == '\n'))
276                 text[strlen(text)-1] = 0;
277
278           text2 = strdup(text);
279
280           if (!fn) fn = def_fn;
281       font = XLoadQueryFont (dpy, fn);
282       if (! font)
283                 {
284                   fprintf(stderr, "%s: unable to load font %s; using %s\n",
285                                   progname, fn, def_fn);
286                   font = XLoadQueryFont (dpy, def_fn);
287                 }
288
289           memset(&overall, 0, sizeof(overall));
290           token = text;
291           lines = 0;
292           while ((line = strtok(token, "\r\n")))
293                 {
294                   XCharStruct o2;
295                   int ascent, descent, direction;
296                   token = 0;
297                   XTextExtents(font, line, strlen(line),
298                                            &direction, &ascent, &descent, &o2);
299                   overall.lbearing = MAX(overall.lbearing, o2.lbearing);
300                   overall.rbearing = MAX(overall.rbearing, o2.rbearing);
301                   lines++;
302                 }
303
304           width = overall.lbearing + overall.rbearing + margin + margin + 1;
305           height = ((font->ascent + font->descent) * lines) + margin + margin;
306
307           bitmap = XCreatePixmap(dpy, MI_WINDOW(mi), width, height, 1);
308
309       gcv.font = font->fid;
310       gcv.foreground = bg;
311       gc = XCreateGC (dpy, bitmap, (GCFont | GCForeground), &gcv);
312           XFillRectangle(dpy, bitmap, gc, 0, 0, width, height);
313           XSetForeground(dpy, gc, fg);
314
315           token = text2;
316           lines = 0;
317           while ((line = strtok(token, "\r\n")))
318                 {
319                   XCharStruct o2;
320                   int ascent, descent, direction, xoff;
321                   token = 0;
322
323                   XTextExtents(font, line, strlen(line),
324                                            &direction, &ascent, &descent, &o2);
325                   xoff = ((overall.lbearing + overall.rbearing) -
326                                   (o2.lbearing + o2.rbearing)) / 2;
327
328                   XDrawString(dpy, bitmap, gc,
329                                           overall.lbearing + margin + xoff,
330                                           ((font->ascent * (lines + 1)) +
331                                            (font->descent * lines) +
332                                            margin),
333                                           line, strlen(line));
334                   lines++;
335                 }
336           free(text2);
337           XUnloadFont(dpy, font->fid);
338           XFree((XPointer) font);
339           XFreeGC(dpy, gc);
340
341           fp->image = XGetImage(dpy, bitmap, 0, 0, width, height, 1L, XYPixmap);
342           XFreePixmap(dpy, bitmap);
343         }
344   else
345         {
346       char *bits = (char *) malloc (sizeof(bob_bits));
347       memcpy (bits, bob_bits, sizeof(bob_bits));
348           fp->image = XCreateImage (dpy, MI_VISUAL(mi), 1, XYBitmap, 0,
349                                                                 bits, bob_width, bob_height,
350                                                                 8, 0);
351           fp->image->byte_order = LSBFirst;
352           fp->image->bitmap_bit_order = LSBFirst;
353         }
354
355   if (bitmap_name)
356         free (bitmap_name);
357   if (text)
358         free (text);
359 }
360
361 #else  /* !STANDALONE */
362
363 static void
364 make_flag_bits(ModeInfo *mi)
365 {
366   flagstruct *fp = &flags[MI_SCREEN(mi)];
367   int x, y;
368   int w = flag_width;
369   int h = flag_height;
370   int i = 0;
371   fp->image =
372         XCreateImage(MI_DISPLAY(mi), MI_VISUAL(mi),
373                                  1, XYBitmap, 0,                                        /* dpth, fmt, offset */
374                                  (char *) calloc ((w+8) / 8, h),        /* data */
375                                  w, h, 8, 0);                                           /* w, h, pad, bpl */
376   /* Geez, what kinda goofy bit order is this?? */
377   for (x = 0; x < w; x++)
378         for (y = h-1; y >= 0; y--)
379           XPutPixel (fp->image, x, y, flag_bits[i++]);
380 }
381
382 #endif /* !STANDALONE */
383
384
385 void
386 init_flag(ModeInfo * mi)
387 {
388         Display    *display = MI_DISPLAY(mi);
389         int         size = MI_SIZE(mi);
390         flagstruct *fp;
391
392         if (flags == NULL) {
393                 if ((flags = (flagstruct *) calloc(MI_NUM_SCREENS(mi),
394                                                sizeof (flagstruct))) == NULL)
395                         return;
396         }
397         fp = &flags[MI_SCREEN(mi)];
398
399         make_flag_bits(mi);
400
401         fp->width = MI_WIN_WIDTH(mi);
402         fp->height = MI_WIN_HEIGHT(mi);
403
404         fp->samp = MAXAMP;      /* Amplitude */
405         fp->sofs = 20;          /* ???????? */
406         fp->pointsize = size;
407         if (size < -MINSIZE)
408                 fp->pointsize = NRAND(-size - MINSIZE + 1) + MINSIZE;
409         if (fp->pointsize < MINSIZE ||
410         fp->width <= MAXW(fp) || fp->height <= MAXH(fp))
411                 fp->pointsize = MINSIZE;
412         fp->size = MAXINITSIZE; /* Initial distance between pts */
413         fp->inctaille = 0.05;
414         fp->timer = 0;
415         fp->sidx = fp->x_flag = fp->y_flag = 0;
416
417         if (!fp->initialized) {
418                 fp->initialized = True;
419                 if (!(fp->cache = XCreatePixmap(display, MI_WINDOW(mi),
420                 MAXW(fp), MAXH(fp), MI_WIN_DEPTH(mi))))
421 #ifdef STANDALONE
422                   exit(-1);
423 #else   /* !STANDALONE */
424                         error("%s: catastrophe memoire\n");
425 #endif /* !STANDALONE */
426         }
427         XSetForeground(display, MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
428         XFillRectangle(display, fp->cache, MI_GC(mi),
429                        0, 0, MAXW(fp), MAXH(fp));
430         /* don't want any exposure events from XCopyArea */
431         XSetGraphicsExposures(display, MI_GC(mi), False);
432         if (MI_NPIXELS(mi) > 2)
433                 fp->startcolor = NRAND(MI_NPIXELS(mi));
434         if (fp->width <= MAXW(fp) || fp->height <= MAXH(fp)) {
435                 fp->samp = MINAMP;
436                 fp->sofs = 0;
437                 fp->x_flag = random_num(fp->width - MINW(fp));
438                 fp->y_flag = random_num(fp->height - MINH(fp));
439         } else {
440                 fp->samp = MAXAMP;
441                 fp->sofs = 20;
442                 fp->x_flag = random_num(fp->width - MAXW(fp));
443                 fp->y_flag = random_num(fp->height - MAXH(fp));
444         }
445
446         initSintab(mi);
447
448         XClearWindow(display, MI_WINDOW(mi));
449 }
450
451 void release_flag(ModeInfo * mi);
452
453
454 void
455 draw_flag(ModeInfo * mi)
456 {
457         Display    *display = MI_DISPLAY(mi);
458         Window      window = MI_WINDOW(mi);
459         flagstruct *fp = &flags[MI_SCREEN(mi)];
460
461         if (fp->width <= MAXW(fp) || fp->height <= MAXH(fp)) {
462                 fp->size = MININITSIZE;
463                 /* fp->pointsize = MINPOINTSIZE; */
464                 XCopyArea(display, fp->cache, window, MI_GC(mi),
465                           0, 0, MINW(fp), MINH(fp), fp->x_flag, fp->y_flag);
466         } else {
467                 if ((fp->size + fp->inctaille) > MAXSCALE)
468                         fp->inctaille = -fp->inctaille;
469                 if ((fp->size + fp->inctaille) < MINSCALE)
470                         fp->inctaille = -fp->inctaille;
471                 fp->size += fp->inctaille;
472                 XCopyArea(display, fp->cache, window, MI_GC(mi),
473                           0, 0, MAXW(fp), MAXH(fp), fp->x_flag, fp->y_flag);
474         }
475         XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
476         XFillRectangle(display, fp->cache, MI_GC(mi),
477                        0, 0, MAXW(fp), MAXH(fp));
478         XFlush(display);
479         affiche(mi);
480         fp->sidx += 2;
481         fp->sidx %= (ANGLES * MI_NPIXELS(mi));
482         XFlush(display);
483         fp->timer++;
484         if ((MI_CYCLES(mi) > 0) && (fp->timer >= MI_CYCLES(mi)))
485       {
486         release_flag(mi);
487                 init_flag(mi);
488       }
489 }
490
491 void
492 release_flag(ModeInfo * mi)
493 {
494         if (flags != NULL) {
495                 int         screen;
496
497                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
498                   {
499                         if (flags[screen].cache)
500                                 XFreePixmap(MI_DISPLAY(mi), flags[screen].cache);
501                         if (flags[screen].image)
502                           XDestroyImage(flags[screen].image);
503                   }
504                 (void) free((void *) flags);
505                 flags = NULL;
506         }
507 }
508
509 void
510 refresh_flag(ModeInfo * mi)
511 {
512         /* Do nothing, it will refresh by itself */
513 }