1 /* -*- Mode: C; tab-width: 4 -*-
2 * flag --- a waving flag
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 DEF_FONT "Monaco 15"
38 # define DEF_FONT "fixed"
42 # define DEFAULTS "*delay: 50000 \n" \
47 "*font: " DEF_FONT "\n" \
49 "*fpsSolid: true \n" \
52 # define BRIGHT_COLORS
53 # define UNIFORM_COLORS
54 # define release_flag 0
55 # define reshape_flag 0
56 # define flag_handle_event 0
57 # include "xlockmore.h" /* from the xscreensaver distribution */
59 #include "ximage-loader.h"
60 #include "images/gen/bob_png.h"
62 #else /* !STANDALONE */
63 # include "xlock.h" /* from the xlockmore distribution */
65 #endif /* !STANDALONE */
69 # include <sys/utsname.h>
70 #endif /* HAVE_UNAME */
73 static XrmOptionDescRec opts[] =
75 { "-bitmap", ".flag.bitmap", XrmoptionSepArg, 0 },
76 { "-text", ".flag.text", XrmoptionSepArg, 0 }
79 #endif /* STANDALONE */
81 ENTRYPOINT ModeSpecOpt flag_opts = {
83 2, opts, 0, NULL, NULL
84 #else /* !STANDALONE */
85 0, NULL, 0, NULL, NULL
86 #endif /* STANDALONE */
96 #define MAXW(fp) (MAXSCALE * (fp)->image->width + 2 * MAXAMP + (fp)->pointsize)
97 #define MAXH(fp) (MAXSCALE * (fp)->image->height+ 2 * MAXAMP + (fp)->pointsize)
98 #define MINW(fp) (MINSCALE * (fp)->image->width + 2 * MINAMP + (fp)->pointsize)
99 #define MINH(fp) (MINSCALE * (fp)->image->height+ 2 * MINAMP + (fp)->pointsize)
120 static flagstruct *flags = NULL;
125 return ((int) (((float) LRAND() / MAXRAND) * (n + 1.0)));
129 initSintab(ModeInfo * mi)
131 flagstruct *fp = &flags[MI_SCREEN(mi)];
135 * change the periodicity of the sin formula : the maximum of the
136 * periocity seem to be 16 ( 2^4 ), after the drawing isn't good looking
138 int periodicity = random_num(4);
141 /* for (i=0;i<periodicity;i++) puissance*=2; */
142 puissance <<= periodicity;
143 for (i = 0; i < ANGLES; i++)
144 fp->stab[i] = (int) (SINF(i * puissance * M_PI / ANGLES) * fp->samp) +
149 affiche(ModeInfo * mi)
151 Display *display = MI_DISPLAY(mi);
153 flagstruct *fp = &flags[MI_SCREEN(mi)];
155 for (x = 0; x < fp->image->width; x++)
156 for (y = fp->image->height-1; y >= 0; y--) {
157 xp = (int) (fp->size * (float) x) +
158 fp->stab[(fp->sidx + x + y) % ANGLES];
159 yp = (int) (fp->size * (float) y) +
160 fp->stab[(fp->sidx + 4 * x + y + y) % ANGLES];
162 if (fp->image->depth > 1)
163 XSetForeground(display, MI_GC(mi),
164 XGetPixel(fp->image, x, y));
165 else if (XGetPixel(fp->image, x, y))
166 XSetForeground(display, MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
167 else if (MI_NPIXELS(mi) <= 2)
168 XSetForeground(display, MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
170 XSetForeground(display, MI_GC(mi),
171 MI_PIXEL(mi, (y + x + fp->sidx + fp->startcolor) % MI_NPIXELS(mi)));
173 if (fp->cache == MI_WINDOW(mi)) { /* not double-buffering */
178 if (fp->pointsize <= 1)
179 XDrawPoint(display, fp->cache, MI_GC(mi), xp, yp);
180 else if (fp->pointsize < 6)
181 XFillRectangle(display, fp->cache, MI_GC(mi), xp, yp,
182 fp->pointsize, fp->pointsize);
184 XFillArc(display, fp->cache, MI_GC(mi), xp, yp,
185 fp->pointsize, fp->pointsize, 0, 360*64);
192 make_flag_bits(ModeInfo *mi)
194 Display *dpy = MI_DISPLAY(mi);
195 flagstruct *fp = &flags[MI_SCREEN(mi)];
196 char *bitmap_name = get_string_resource (dpy, "bitmap", "Bitmap");
197 char *text = get_string_resource (dpy, "text", "Text");
200 bitmap_name = 0; /* #### always use default */
203 /* If neither a bitmap nor text are specified, randomly select either
204 the builtin bitmap or builtin text. */
205 if ((!bitmap_name || !*bitmap_name) && (!text || !*text))
210 bitmap_name = strdup("(default)");
215 text = strdup("(default)");
221 !!strcmp(bitmap_name, "(default)"))
227 bitmap = file_to_pixmap (dpy, MI_WINDOW (mi), bitmap_name,
231 fp->image = XGetImage(dpy, bitmap, 0, 0, width, height, ~0L,
233 XFreePixmap(dpy, bitmap);
236 else if (text && *text)
239 char *fn = get_string_resource (dpy, "font", "Font");
240 char *def_fn = "fixed";
253 if (!strcmp(text, "(default)"))
257 if (uname (&uts) < 0)
259 text = strdup("uname() failed");
264 if ((s = strchr(uts.nodename, '.')))
266 text = (char *) malloc(strlen(uts.nodename) +
267 strlen(uts.sysname) +
268 strlen(uts.version) +
269 strlen(uts.release) + 10);
271 sprintf(text, "%s\n%s %s.%s",
272 uts.nodename, uts.sysname, uts.version, uts.release);
273 # elif defined(__APPLE__) && !defined(USE_IPHONE) /* MacOS X + XDarwin */
276 "/System/Library/CoreServices/SystemVersion.plist";
277 FILE *f = fopen (file, "r");
278 char *pbv = 0, *pn = 0, *puvv = 0;
282 while (fgets (buf, sizeof(buf)-1, f)) {
284 if (strstr(buf, S)) { \
285 fgets (buf, sizeof(buf)-1, f); \
286 if ((s = strchr (buf, '>'))) V = strdup(s+1); \
287 if ((s = strchr (V, '<'))) *s = 0; \
289 GRAB ("ProductName", pn)
290 GRAB ("ProductBuildVersion", pbv)
291 GRAB ("ProductUserVisibleVersion", puvv)
296 sprintf (text, "%s\n%s\n%s",
297 uts.nodename, pn, puvv /*, uts.machine*/);
299 sprintf(text, "%s\n%s %s",
300 uts.nodename, uts.sysname, uts.release);
303 sprintf(text, "%s\n%s %s",
304 uts.nodename, uts.sysname, uts.release);
305 # endif /* special system types */
307 #else /* !HAVE_UNAME */
309 text = strdup(getenv("SYS$NODE"));
311 text = strdup("X\nScreen\nSaver");
313 #endif /* !HAVE_UNAME */
317 (text[strlen(text)-1] == '\r' ||
318 text[strlen(text)-1] == '\n'))
319 text[strlen(text)-1] = 0;
321 text2 = strdup(text);
323 if (!fn) fn = def_fn;
324 font = load_font_retry (dpy, fn);
326 memset(&overall, 0, sizeof(overall));
329 while ((line = strtok(token, "\r\n")))
332 int ascent, descent, direction;
334 XTextExtents(font, line, strlen(line),
335 &direction, &ascent, &descent, &o2);
336 overall.lbearing = MAX(overall.lbearing, o2.lbearing);
337 overall.rbearing = MAX(overall.rbearing, o2.rbearing);
341 width = overall.lbearing + overall.rbearing + margin + margin + 1;
342 height = ((font->ascent + font->descent) * lines) + margin + margin;
344 bitmap = XCreatePixmap(dpy, MI_WINDOW(mi), width, height, 1);
346 gcv.font = font->fid;
348 gc = XCreateGC (dpy, bitmap, (GCFont | GCForeground), &gcv);
349 XFillRectangle(dpy, bitmap, gc, 0, 0, width, height);
350 XSetForeground(dpy, gc, fg);
354 while ((line = strtok(token, "\r\n")))
357 int ascent, descent, direction, xoff;
360 XTextExtents(font, line, strlen(line),
361 &direction, &ascent, &descent, &o2);
362 xoff = ((overall.lbearing + overall.rbearing) -
363 (o2.lbearing + o2.rbearing)) / 2;
365 XDrawString(dpy, bitmap, gc,
366 overall.lbearing + margin + xoff,
367 ((font->ascent * (lines + 1)) +
368 (font->descent * lines) +
374 XUnloadFont(dpy, font->fid);
375 XFree((XPointer) font);
378 fp->image = XGetImage(dpy, bitmap, 0, 0, width, height, 1L, XYPixmap);
379 XFreePixmap(dpy, bitmap);
385 XImage *im = image_data_to_ximage (dpy, MI_VISUAL(mi),
386 bob_png, sizeof(bob_png));
389 fp->image = XCreateImage (dpy, MI_VISUAL(mi), 1, XYBitmap, 0,
390 0, im->width, im->height, 8, 0);
391 fp->image->data = malloc (fp->image->bytes_per_line * fp->image->height);
393 /* Convert deep image to 1 bit */
394 for (y = 0; y < im->height; y++)
396 for (x = 0; x < im->width; x++)
398 unsigned long p = XGetPixel (im, x, im->height-y-1);
399 if (! (p & 0xFF000000)) p = ~0; /* alpha -> white */
400 p = (p >> 16) & 0xFF; /* red */
401 XPutPixel (fp->image, x, y, p > 0x7F ? 0 : 1);
413 #else /* !STANDALONE */
416 make_flag_bits(ModeInfo *mi)
418 flagstruct *fp = &flags[MI_SCREEN(mi)];
424 XCreateImage(MI_DISPLAY(mi), MI_VISUAL(mi),
425 1, XYBitmap, 0, /* dpth, fmt, offset */
426 (char *) calloc ((w+8) / 8, h), /* data */
427 w, h, 8, 0); /* w, h, pad, bpl */
428 /* Geez, what kinda goofy bit order is this?? */
429 for (x = 0; x < w; x++)
430 for (y = h-1; y >= 0; y--)
431 XPutPixel (fp->image, x, y, flag_bits[i++]);
434 #endif /* !STANDALONE */
438 init_flag(ModeInfo * mi)
440 Display *display = MI_DISPLAY(mi);
441 int size = MI_SIZE(mi);
445 fp = &flags[MI_SCREEN(mi)];
448 if (!fp->image) abort();
450 fp->width = MI_WIN_WIDTH(mi);
451 fp->height = MI_WIN_HEIGHT(mi);
453 fp->samp = MAXAMP; /* Amplitude */
454 fp->sofs = 20; /* ???????? */
455 fp->pointsize = size;
457 fp->pointsize = NRAND(-size - MINSIZE + 1) + MINSIZE;
458 if (fp->pointsize < MINSIZE ||
459 fp->width <= MAXW(fp) || fp->height <= MAXH(fp))
460 fp->pointsize = MINSIZE;
461 fp->size = MAXINITSIZE; /* Initial distance between pts */
462 fp->inctaille = 0.05;
464 fp->sidx = fp->x_flag = fp->y_flag = 0;
466 if (!fp->initialized) {
468 # ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */
471 fp->initialized = True;
473 fp->cache = MI_WINDOW(mi); /* not double-buffering */
475 if (!(fp->cache = XCreatePixmap(display, MI_WINDOW(mi),
480 #else /* !STANDALONE */
481 error("%s: catastrophe memoire\n");
482 #endif /* !STANDALONE */
484 XSetForeground(display, MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
485 XFillRectangle(display, fp->cache, MI_GC(mi),
486 0, 0, MAXW(fp), MAXH(fp));
487 /* don't want any exposure events from XCopyArea */
488 XSetGraphicsExposures(display, MI_GC(mi), False);
489 if (MI_NPIXELS(mi) > 2)
490 fp->startcolor = NRAND(MI_NPIXELS(mi));
491 if (fp->width <= MAXW(fp) || fp->height <= MAXH(fp)) {
494 fp->x_flag = random_num(fp->width - MINW(fp));
495 fp->y_flag = random_num(fp->height - MINH(fp));
499 fp->x_flag = random_num(fp->width - MAXW(fp));
500 fp->y_flag = random_num(fp->height - MAXH(fp));
505 XClearWindow(display, MI_WINDOW(mi));
509 draw_flag(ModeInfo * mi)
511 Display *display = MI_DISPLAY(mi);
512 Window window = MI_WINDOW(mi);
513 flagstruct *fp = &flags[MI_SCREEN(mi)];
515 if (!fp->image) abort();
516 if (fp->cache == window) { /* not double-buffering */
517 XClearWindow (display, window);
518 } else if (fp->width <= MAXW(fp) || fp->height <= MAXH(fp)) {
519 fp->size = MININITSIZE;
520 /* fp->pointsize = MINPOINTSIZE; */
521 XCopyArea(display, fp->cache, window, MI_GC(mi),
522 0, 0, MINW(fp), MINH(fp), fp->x_flag, fp->y_flag);
524 if ((fp->size + fp->inctaille) > MAXSCALE)
525 fp->inctaille = -fp->inctaille;
526 if ((fp->size + fp->inctaille) < MINSCALE)
527 fp->inctaille = -fp->inctaille;
528 fp->size += fp->inctaille;
529 XCopyArea(display, fp->cache, window, MI_GC(mi),
530 0, 0, MAXW(fp), MAXH(fp), fp->x_flag, fp->y_flag);
532 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
533 XFillRectangle(display, fp->cache, MI_GC(mi),
534 0, 0, MAXW(fp), MAXH(fp));
537 fp->sidx %= (ANGLES * MI_NPIXELS(mi));
539 if ((MI_CYCLES(mi) > 0) && (fp->timer >= MI_CYCLES(mi)))
544 free_flag(ModeInfo * mi)
546 int screen = MI_SCREEN(mi);
551 if (flags[screen].cache && flags[screen].dbufp)
552 XFreePixmap(MI_DISPLAY(mi), flags[screen].cache);
553 if (flags[screen].image)
554 XDestroyImage(flags[screen].image);
559 refresh_flag(ModeInfo * mi)
561 /* Do nothing, it will refresh by itself */
565 XSCREENSAVER_MODULE ("Flag", flag)