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