/* bubbles.c - frying pan / soft drink in a glass simulation */
-/*$Id: bubbles.c,v 1.8 1997/07/26 19:16:33 jwz Exp $*/
+/*$Id: bubbles.c,v 1.18 2002/01/17 02:16:04 jwz Exp $*/
/*
* Copyright (C) 1995-1996 James Macnicol
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
+ * 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.
*/
/*
* and things are _much_ nicer.)
*
* Author: James Macnicol
- * Internet E-mail : J.Macnicol@student.anu.edu.au
+ * Internet E-mail : j-macnicol@adfa.edu.au
*/
#include <math.h>
#include "screenhack.h"
-#include "bubbles.h"
-
-#ifdef BUBBLES_IO
-# include <dirent.h>
-# include <fcntl.h>
-# include <sys/types.h>
-#endif /* BUBBLES_IO */
#include <limits.h>
-#include <signal.h>
+
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
#ifndef VMS
# include <unistd.h>
#endif
#include "yarandom.h"
+#include "bubbles.h"
+#include "xpm-pixmap.h"
-#ifdef HAVE_XPM
-#include <X11/xpm.h>
+#if defined(HAVE_GDK_PIXBUF) || defined(HAVE_XPM)
+# define FANCY_BUBBLES
#endif
/*
* Public variables
*/
-#ifndef NO_DEFAULT_BUBBLE
+extern void init_default_bubbles(void);
extern int num_default_bubbles;
extern char **default_bubbles[];
-#endif /* NO_DEFAULT_BUBBLE */
+static int drop_bubble( Bubble *bb );
char *progclass = "Bubbles";
char *defaults [] = {
- "*background: black",
- "*foreground: white",
- "*simple: false",
- "*broken: false",
- "*delay: 2000",
-#ifdef BUBBLES_IO
- "*file: (default)",
- "*directory: (default)",
-#endif /* BUBBLES_IO */
- "*quiet: false",
- "*nodelay: false",
- "*3D: false",
- "*geometry: 400x300",
+ ".background: black",
+ ".foreground: white",
+ "*simple: false",
+ "*broken: false",
+ "*delay: 800",
+ "*quiet: false",
+ "*nodelay: false",
+ "*drop: false",
+ "*trails: false",
+ "*3D: false",
0
};
XrmOptionDescRec options [] = {
{ "-simple", ".simple", XrmoptionNoArg, "true" },
-#ifdef HAVE_XPM
+#ifdef FANCY_BUBBLES
{ "-broken", ".broken", XrmoptionNoArg, "true" },
-#endif /* HAVE_XPM */
+#endif
{ "-quiet", ".quiet", XrmoptionNoArg, "true" },
{ "-nodelay", ".nodelay", XrmoptionNoArg, "true" },
{ "-3D", ".3D", XrmoptionNoArg, "true" },
-#ifdef BUBBLES_IO
- { "-file", ".file", XrmoptionSepArg, 0 },
- { "-directory", ".directory", XrmoptionSepArg, 0 },
-#endif /* BUBBLES_IO */
{ "-delay", ".delay", XrmoptionSepArg, 0 },
+ { "-drop", ".drop", XrmoptionNoArg, "true" },
+ { "-rise", ".rise", XrmoptionNoArg, "true" },
+ { "-trails", ".trails", XrmoptionNoArg, "true" },
{ 0, 0, 0, 0 }
};
static int bubble_min_radius;
static int bubble_max_radius;
static long *bubble_areas;
+static int *bubble_droppages;
static GC draw_gc, erase_gc;
-#ifdef HAVE_XPM
+#ifdef FANCY_BUBBLES
static int num_bubble_pixmaps;
static Bubble_Step **step_pixmaps;
-#ifdef BUBBLES_IO
-static char *pixmap_file;
-#endif /* BUBBLES_IO */
-static int use_default_bubble;
-#endif /* HAVE_XPM */
+#endif
/* Options stuff */
-#ifdef HAVE_XPM
+#ifdef FANCY_BUBBLES
static Bool simple = False;
#else
static Bool simple = True;
static Bool broken = False;
static Bool quiet = False;
static Bool threed = False;
+static Bool drop = False;
+static Bool trails = False;
+static int drop_dir;
static int delay;
/*
bb->radius, bb->x, bb->y, bb->magic, bb->cell_index);
die_bad_bubble(bb);
}
-#ifdef HAVE_XPM
+#ifdef FANCY_BUBBLES
} else {
if ((bb->x < 0) || (bb->x > screen_width) ||
(bb->y < 0) || (bb->y > screen_height) ||
bb->radius, bb->x, bb->y, bb->magic, bb->cell_index);
die_bad_bubble(bb);
}
-#endif /* HAVE_XPM */
+#endif
}
#endif /* DEBUG */
return 0;
long factor;
int i;
-#ifdef HAVE_XPM
+#ifdef FANCY_BUBBLES
if (simple)
maxarea = bubble_areas[bubble_max_radius+1];
else
maxarea = step_pixmaps[num_bubble_pixmaps]->area;
-#else
+#else /* !FANCY_BUBBLES */
maxarea = bubble_areas[bubble_max_radius+1];
-#endif /* HAVE_XPM */
+#endif /* !FANCY_BUBBLES */
maxvalue = (double)screen_width * 2.0 * (double)maxarea;
factor = (long)ceil(maxvalue / (double)LONG_MAX);
if (factor > 1) {
/* Overflow will occur in weighted_mean(). We must divide areas
each by factor so it will never do so. */
-#ifdef HAVE_XPM
+#ifdef FANCY_BUBBLES
if (simple) {
for (i = bubble_min_radius; i <= bubble_max_radius+1; i++) {
bubble_areas[i] /= factor;
#endif /* DEBUG */
}
}
-#else
+#else /* !FANCY_BUBBLES */
for (i = bubble_min_radius; i <= bubble_max_radius+1; i++) {
bubble_areas[i] /= factor;
if (bubble_areas[i] == 0)
bubble_areas[i] = 1;
}
-#endif /* HAVE_XPM */
+#endif /* !FANCY_BUBBLES */
}
#ifdef DEBUG
printf("maxarea = %ld\n", maxarea);
if (simple) {
rv->radius = bubble_min_radius;
rv->area = bubble_areas[bubble_min_radius];
-#ifdef HAVE_XPM
+#ifdef FANCY_BUBBLES
} else {
rv->step = 0;
rv->radius = step_pixmaps[0]->radius;
rv->area = step_pixmaps[0]->area;
-#endif /* HAVE_XPM */
+#endif /* FANCY_BUBBLES */
}
rv->visible = 0;
rv->magic = BUBBLE_MAGIC;
- rv->x = ya_random() % screen_width;
- rv->y = ya_random() % screen_height;
+ rv->x = random() % screen_width;
+ rv->y = random() % screen_height;
rv->cell_index = pixel_to_mesh(rv->x, rv->y);
return rv;
(bb->y - bb->radius), bb->radius*2, bb->radius*2, 0,
360*64);
} else {
-#ifdef HAVE_XPM
+#ifdef FANCY_BUBBLES
XSetClipOrigin(defdsp, step_pixmaps[bb->step]->draw_gc,
(bb->x - bb->radius),
(bb->y - bb->radius));
(bb->radius * 2),
(bb->x - bb->radius),
(bb->y - bb->radius));
-#endif /* HAVE_XPM */
+#endif /* FANCY_BUBBLES */
}
}
}
(bb->y - bb->radius), bb->radius*2, bb->radius*2, 0,
360*64);
} else {
-#ifdef HAVE_XPM
+#ifdef FANCY_BUBBLES
if (! broken) {
XSetClipOrigin(defdsp, step_pixmaps[bb->step]->erase_gc,
(bb->x - bb->radius), (bb->y - bb->radius));
(bb->radius * 2),
(bb->radius * 2));
}
-#endif /* HAVE_XPM */
+#endif /* FANCY_BUBBLES */
}
}
}
diner->area += food->area;
delete_bubble_in_mesh(food, DELETE_BUBBLE);
- if ((simple) && (diner->area > bubble_areas[bubble_max_radius])) {
- delete_bubble_in_mesh(diner, DELETE_BUBBLE);
- return 0;
+ if (drop) {
+ if ((simple) && (diner->area > bubble_areas[bubble_max_radius])) {
+ diner->area = bubble_areas[bubble_max_radius];
+ }
+#ifdef FANCY_BUBBLES
+ if ((! simple) && (diner->area > step_pixmaps[num_bubble_pixmaps]->area)) {
+ diner->area = step_pixmaps[num_bubble_pixmaps]->area;
+ }
+#endif /* FANCY_BUBBLES */
}
-#ifdef HAVE_XPM
- if ((! simple) && (diner->area >
- step_pixmaps[num_bubble_pixmaps]->area)) {
- delete_bubble_in_mesh(diner, DELETE_BUBBLE);
- return 0;
+ else {
+ if ((simple) && (diner->area > bubble_areas[bubble_max_radius])) {
+ delete_bubble_in_mesh(diner, DELETE_BUBBLE);
+ return 0;
+ }
+#ifdef FANCY_BUBBLES
+ if ((! simple) && (diner->area >
+ step_pixmaps[num_bubble_pixmaps]->area)) {
+ delete_bubble_in_mesh(diner, DELETE_BUBBLE);
+ return 0;
+ }
+#endif /* FANCY_BUBBLES */
}
-#endif /* HAVE_XPM */
if (simple) {
if (diner->area > bubble_areas[diner->radius + 1]) {
/* Move the bubble to a new radius */
i = diner->radius;
- while (diner->area > bubble_areas[i+1])
- ++i;
+ while ((i < bubble_max_radius - 1) && (diner->area > bubble_areas[i+1]))
+ ++i;
diner->radius = i;
}
show_bubble(diner);
-#ifdef HAVE_XPM
+#ifdef FANCY_BUBBLES
} else {
if (diner->area > step_pixmaps[diner->step+1]->area) {
i = diner->step;
- while (diner->area > step_pixmaps[i+1]->area)
- ++i;
+ while ((i < num_bubble_pixmaps - 1) && (diner->area > step_pixmaps[i+1]->area))
+ ++i;
diner->step = i;
diner->radius = step_pixmaps[diner->step]->radius;
}
show_bubble(diner);
-#endif /* HAVE_XPM */
+#endif /* FANCY_BUBBLES */
}
/* Now adjust locations and cells if need be */
break;
}
} else {
- if ((ya_random() % 2) == 0) {
+ if ((random() % 2) == 0) {
switch (bubble_eat(b1, b2)) {
case 0:
return 0;
nextbub = tmp;
touch = get_closest_bubble(nextbub);
- while (! null_bubble(touch)) {
- switch (merge_bubbles(nextbub, touch)) {
- case 2:
- /* touch ate nextbub and survived */
- nextbub = touch;
- break;
- case 1:
- /* nextbub ate touch and survived */
- break;
- case 0:
- /* somebody ate someone else but they exploded */
- nextbub = (Bubble *)NULL;
- break;
- default:
- /* something went wrong */
- fprintf(stderr, "Error occurred in insert_new_bubble()\n");
- exit(1);
- }
- /* Check to see if there are any other bubbles still in the area
- and if we need to do this all over again for them. */
- if (! null_bubble(nextbub))
- touch = get_closest_bubble(nextbub);
- else
- touch = (Bubble *)NULL;
+ if (null_bubble(touch))
+ return;
+
+ while (1) {
+
+ /* Merge all touching bubbles */
+ while (! null_bubble(touch)) {
+ switch (merge_bubbles(nextbub, touch)) {
+ case 2:
+ /* touch ate nextbub and survived */
+ nextbub = touch;
+ break;
+ case 1:
+ /* nextbub ate touch and survived */
+ break;
+ case 0:
+ /* somebody ate someone else but they exploded */
+ nextbub = (Bubble *)NULL;
+ break;
+ default:
+ /* something went wrong */
+ fprintf(stderr, "Error occurred in insert_new_bubble()\n");
+ exit(1);
+ }
+
+ /* Check to see if any bubble survived. */
+ if (null_bubble(nextbub))
+ break;
+
+ /* Check to see if there are any other bubbles still in the area
+ and if we need to do this all over again for them. */
+ touch = get_closest_bubble(nextbub);
+ }
+
+ if (null_bubble(nextbub))
+ break;
+
+ /* Shift bubble down. Break if we run off the screen. */
+ if (drop) {
+ if (drop_bubble( nextbub ) == -1)
+ break;
+ }
+
+ /* Check to see if there are any other bubbles still in the area
+ and if we need to do this all over again for them. */
+ touch = get_closest_bubble(nextbub);
+ if (null_bubble(touch)) {
+ /* We also continue every so often if we're dropping and the bubble is at max size */
+ if (drop) {
+ if (simple) {
+ if ((nextbub->area >= bubble_areas[bubble_max_radius - 1]) && (random() % 2 == 0))
+ continue;
+ }
+#ifdef FANCY_BUBBLES
+ else {
+ if ((nextbub->step >= num_bubble_pixmaps - 1) && (random() % 2 == 0))
+ continue;
+ }
+#endif /* FANCY_BUBBLES */
+ }
+ break;
+ }
+
+ }
+}
+
+
+static void
+leave_trail( Bubble *bb )
+{
+ Bubble *tmp;
+
+ tmp = new_bubble();
+ tmp->x = bb->x;
+ tmp->y = bb->y - ((bb->radius + 10) * drop_dir);
+ tmp->cell_index = pixel_to_mesh(tmp->x, tmp->y);
+ add_to_mesh(tmp);
+ insert_new_bubble(tmp);
+ show_bubble( tmp );
+}
+
+
+static int
+drop_bubble( Bubble *bb )
+{
+ int newmi;
+
+ hide_bubble( bb );
+
+ if (simple)
+ (bb->y) += (bubble_droppages[bb->radius] * drop_dir);
+#ifdef FANCY_BUBBLES
+ else
+ (bb->y) += (step_pixmaps[bb->step]->droppage * drop_dir);
+#endif /* FANCY_BUBBLES */
+ if ((bb->y < 0) || (bb->y > screen_height)) {
+ delete_bubble_in_mesh( bb, DELETE_BUBBLE );
+ return -1;
+ }
+
+ show_bubble( bb );
+
+ /* Now adjust locations and cells if need be */
+ newmi = pixel_to_mesh(bb->x, bb->y);
+ if (newmi != bb->cell_index) {
+ delete_bubble_in_mesh(bb, KEEP_BUBBLE);
+ bb->cell_index = newmi;
+ add_to_mesh(bb);
+ }
+
+ if (trails) {
+ if (simple) {
+ if ((bb->area >= bubble_areas[bubble_max_radius - 1]) && (random() % 2 == 0))
+ leave_trail( bb );
+ }
+#ifdef FANCY_BUBBLES
+ else {
+ if ((bb->step >= num_bubble_pixmaps - 1) && (random() % 2 == 0))
+ leave_trail( bb );
+ }
+#endif /* FANCY_BUBBLES */
}
+
+ return 0;
}
+
#ifdef DEBUG
static int
get_length_of_bubble_list(Bubble *bb)
* still check for XPM, though!
*/
-#ifdef HAVE_XPM
-
-static void
-free_pixmaps (void)
-/* Free resources associated with XPM */
-{
- int i;
-
-#ifdef DEBUG
- if (simple) {
- fprintf(stderr, "free_pixmaps() called in simple mode\n");
- exit(1);
- }
- printf("free_pixmaps()\n");
-#endif /* DEBUG */
-
- for(i = 0; i < (num_bubble_pixmaps - 1); i++) {
- XFreePixmap(defdsp, step_pixmaps[i]->ball);
- XFreePixmap(defdsp, step_pixmaps[i]->shape_mask);
- XFreeGC(defdsp, step_pixmaps[i]->draw_gc);
- XFreeGC(defdsp, step_pixmaps[i]->erase_gc);
- XFreeColors(defdsp, defcmap, step_pixmaps[i]->xpmattrs.pixels,
- step_pixmaps[i]->xpmattrs.npixels, 0);
- XpmFreeAttributes(&step_pixmaps[i]->xpmattrs);
- }
-}
-
-static void
-onintr(int a)
-/* This gets called when SIGINT or SIGTERM is received */
-{
- free_pixmaps();
- exit(0);
-}
-
-#ifdef DEBUG
-static void
-onsegv(int a)
-/* Called when SEGV detected. Hmmmmm.... */
-{
- fflush(stdout);
- fprintf(stderr, "SEGV detected! : %d\n", a);
- exit(1);
-}
-#endif /* DEBUG */
-
+#ifdef FANCY_BUBBLES
/*
* Pixmaps without file I/O (but do have XPM)
prevrad = step_pixmaps[ind]->radius;
}
#endif /* DEBUG */
+
+ /* Now populate the droppage values */
+ for (ind = 0; ind < num_bubble_pixmaps; ind++)
+ step_pixmaps[ind]->droppage = MAX_DROPPAGE * ind / num_bubble_pixmaps;
}
-#ifndef NO_DEFAULT_BUBBLE
static void
make_pixmap_from_default(char **pixmap_data, Bubble_Step *bl)
/* Read pixmap data which has been compiled into the program and a pointer
This is virtually copied verbatim from make_pixmap_from_file() above and
changes made to either should be propagated onwards! */
{
- int result;
XGCValues gcv;
#ifdef DEBUG
exit(1);
}
- bl->xpmattrs.valuemask = 0;
-
-#ifdef XpmCloseness
- bl->xpmattrs.valuemask |= XpmCloseness;
- bl->xpmattrs.closeness = 40000;
-#endif
-#ifdef XpmVisual
- bl->xpmattrs.valuemask |= XpmVisual;
- bl->xpmattrs.visual = defvisual;
-#endif
-#ifdef XpmDepth
- bl->xpmattrs.valuemask |= XpmDepth;
- bl->xpmattrs.depth = screen_depth;
-#endif
-#ifdef XpmColormap
- bl->xpmattrs.valuemask |= XpmColormap;
- bl->xpmattrs.colormap = defcmap;
-#endif
-
-
- /* This is the only line which is different from make_pixmap_from_file() */
- result = XpmCreatePixmapFromData(defdsp, defwin, pixmap_data, &bl->ball,
- &bl->shape_mask, &bl->xpmattrs);
-
- switch(result) {
- case XpmColorError:
- fprintf(stderr, "xpm: color substitution performed\n");
- /* fall through */
- case XpmSuccess:
- bl->radius = MAX(bl->xpmattrs.width, bl->xpmattrs.height) / 2;
+#ifdef FANCY_BUBBLES
+ {
+ int w, h;
+ bl->ball = xpm_data_to_pixmap (defdsp, defwin, (char **) pixmap_data,
+ &w, &h, &bl->shape_mask);
+ bl->radius = MAX(w, h) / 2;
bl->area = calc_bubble_area(bl->radius);
- break;
- case XpmColorFailed:
- fprintf(stderr, "xpm: color allocation failed\n");
- exit(1);
- case XpmNoMemory:
- fprintf(stderr, "xpm: out of memory\n");
- exit(1);
- default:
- fprintf(stderr, "xpm: unknown error code %d\n", result);
- exit(1);
}
-
+#endif /* FANCY_BUBBLES */
+
gcv.plane_mask = AllPlanes;
gcv.foreground = default_fg_pixel;
gcv.function = GXcopy;
Bubble_Step *newpix, *tmppix;
char **pixpt;
- /* Make sure pixmaps are freed when program is terminated */
- /* This is when I hit ^C */
- if (signal(SIGINT, SIG_IGN) != SIG_IGN)
- signal(SIGINT, onintr);
- /* xscreensaver sends SIGTERM */
- if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
- signal(SIGTERM, onintr);
-#ifdef DEBUG
- if (signal(SIGSEGV, SIG_IGN) != SIG_IGN) {
- printf("Setting signal handler for SIGSEGV\n");
- signal(SIGSEGV, onsegv);
- } else {
- printf("Didn't set signal hanlder for SIGSEGV\n");
- }
-#endif /* DEBUG */
+ init_default_bubbles();
for (i = 0; i < num_default_bubbles; i++) {
pixpt = default_bubbles[i];
make_pixmap_array(pixmap_list);
}
-#endif /* NO_DEFAULT_BUBBLE */
-
-#endif /* HAVE_XPM */
-
-/*
- * File I/O stuff
- */
-
-#ifdef BUBBLES_IO
-
-static DIR *
-my_opendir(char *name)
-/* Like opendir() but checks for things so we don't have to do it multiple
-times in the code. */
-{
- DIR *rv;
-
- if (name == (char *)NULL) {
- fprintf(stderr, "NULL directory name\n");
- return (DIR *)NULL;
- }
-
- if ((rv = opendir(name)) == NULL) {
- perror(name);
- return (DIR *)NULL;
- }
-
- return rv;
-}
-
-static int
-regular_file(char *name)
-/* Check to see if we can use the named file. This was broken under Linux
-1.3.45 but seems to be okay under 1.3.54. The parameter "name" was being
-trashed if the file didn't exist. Yeah, I know 1.3.x are development
-kernels....
-*/
-{
- int fd;
-
- if ((fd = open(name, O_RDONLY)) == -1) {
- perror(name);
- return 0;
- } else {
- close(fd);
- return 1;
- }
-}
-
-static char *
-get_random_name(char *dir)
-/* Pick an appropriate file at random out of the files in the directory dir */
-{
- STRUCT_DIRENT *dp;
- DIR *dfd;
- int numentries = 0;
- int entnum;
- int x;
- char buf[PATH_BUF_SIZE];
- char *rv;
-
- if ((dfd = my_opendir(dir)) == (DIR *)NULL)
- return (char *)NULL;
-
- while ((dp = readdir(dfd)) != NULL) {
- if ((strcmp(DIRENT_NAME, ".") == 0) || (strcmp(DIRENT_NAME, "..") == 0))
- continue;
- if ((strlen(dir)+strlen(DIRENT_NAME)+2) > 1024) {
- fprintf(stderr, "name %s/%s too long\n", dir, DIRENT_NAME);
- continue;
- }
- if (sprintf(buf, "%s/%s", dir, DIRENT_NAME) > (PATH_BUF_SIZE-1)) {
- fprintf(stderr, "path buffer overflowed in get_random_name()\n");
- continue;
- }
- if (regular_file(buf))
- ++numentries;
- }
- closedir(dfd);
- if (numentries == 0) {
- fprintf(stderr, "No suitable files found in %s\n", dir);
- return (char *)NULL;
- }
- entnum = ya_random() % numentries;
- x = 0;
-
- if ((dfd = my_opendir(dir)) == (DIR *)NULL)
- return (char *)NULL;
- while ((dp = readdir(dfd)) != NULL) {
- if ((strcmp(DIRENT_NAME, ".") == 0) || (strcmp(DIRENT_NAME, "..") == 0))
- continue;
- if ((strlen(dir)+strlen(DIRENT_NAME)+2) > 1024) {
- /* We warned about this previously */
- continue;
- }
- if (sprintf(buf, "%s/%s", dir, DIRENT_NAME) > (PATH_BUF_SIZE-1)) {
- fprintf(stderr, "path buffer overflowed in get_random_name()\n");
- continue;
- }
- if (regular_file(buf)) {
- if (x == entnum) {
- rv = (char *)xmalloc(1024 * sizeof(char));
- strcpy(rv, buf);
- closedir(dfd);
- return rv;
- }
- ++x;
- }
- }
- /* We've screwed up if we reach here - someone must have deleted all the
- files while we were counting them... */
- fprintf(stderr, "get_random_name(): Oops!\n");
- exit(1);
-}
-
-static int
-read_line(int fd, char **buf, int bufsize)
-/* A line is read from fd until a '\n' is found or EOF is reached. (*buf)
-is initially of length bufsize and is extended by bufsize chars if need
-be (for as many times as it takes). */
-{
- char x;
- int pos = 0;
- int size = bufsize;
- int rv;
- char *newbuf;
-
- while (1) {
- rv = read(fd, &x, 1);
- if (rv == -1) {
- perror("read_line(): ");
- return IO_ERROR;
- } else if (rv == 0) {
- (*buf)[pos] = '\0';
- return EOF_REACHED;
- } else if (x == '\n') {
- (*buf)[pos] = '\0';
- return LINE_READ;
- } else {
- (*buf)[pos++] = x;
- if (pos == (size - 1)) {
- /* We've come to the end of the space */
- newbuf = (char *)xmalloc((size+bufsize) * sizeof(char));
- strncpy(newbuf, *buf, (size - 1));
- free(*buf);
- *buf = newbuf;
- size += bufsize;
- }
- }
- }
-}
-
-static int
-create_temp_file(char **name)
-/* Create a temporary file in /tmp and return a filedescriptor to it */
-{
- int rv;
-
- if (*name != (char *)NULL)
- free(*name);
-
- if ((*name = tempnam("/tmp", "abxdfes")) == (char *)NULL) {
- fprintf(stderr, "Couldn't make new temporary file\n");
- exit(1);
- }
-/* printf("Temp file created : %s\n", *name); */
- if ((rv = creat(*name, 0644)) == -1) {
- fprintf(stderr, "Couldn't open temporary file\n");
- exit(1);
- }
-
- return rv;
-}
-
-
-#ifdef BUBBLES_IO
-static void
-make_pixmap_from_file(char *fname, Bubble_Step *bl)
-/* Read the pixmap in file fname into structure bl which must already
- be allocated. */
-{
- int result;
- XGCValues gcv;
-
- if (bl == (Bubble_Step *)NULL) {
- fprintf(stderr, "NULL pointer passed to make_pixmap()\n");
- exit(1);
- }
-
- bl->xpmattrs.closeness = 40000;
- bl->xpmattrs.valuemask = XpmColormap | XpmCloseness;
- bl->xpmattrs.colormap = defcmap;
-
- result = XpmReadFileToPixmap(defdsp, defwin, fname, &bl->ball,
- &bl->shape_mask, &bl->xpmattrs);
-
- switch(result) {
- case XpmColorError:
- fprintf(stderr, "xpm: color substitution performed\n");
- /* fall through */
- case XpmSuccess:
- bl->radius = MAX(bl->xpmattrs.width, bl->xpmattrs.height) / 2;
- bl->area = calc_bubble_area(bl->radius);
- break;
- case XpmColorFailed:
- fprintf(stderr, "xpm: color allocation failed\n");
- exit(1);
- case XpmNoMemory:
- fprintf(stderr, "xpm: out of memory\n");
- exit(1);
- default:
- fprintf(stderr, "xpm: unknown error code %d\n", result);
- exit(1);
- }
-
- gcv.plane_mask = AllPlanes;
- gcv.foreground = default_fg_pixel;
- gcv.function = GXcopy;
- bl->draw_gc = XCreateGC (defdsp, defwin, GCForeground, &gcv);
- XSetClipMask(defdsp, bl->draw_gc, bl->shape_mask);
-
- gcv.foreground = default_bg_pixel;
- gcv.function = GXcopy;
- bl->erase_gc = XCreateGC (defdsp, defwin, GCForeground, &gcv);
- XSetClipMask(defdsp, bl->erase_gc, bl->shape_mask);
-}
-#endif /* BUBBLES_IO */
-
-static void
-read_file_to_pixmaps(char *fname)
-/* Read the pixmaps contained in the file fname into memory. THESE SHOULD
-BE UNCOMPRESSED AND READY TO GO! */
-{
- int fd, tmpfd=0, rv;
- int inxpm = 0;
- int xpmseen = 0;
- char *buf = (char *)NULL;
- char *tmpname = (char *)NULL;
- Bubble_Step *pixmap_list = (Bubble_Step *)NULL;
- Bubble_Step *newpix, *tmppix;
-
- /* We first create a linked list of pixmaps before allocating
- memory for the array */
-
- if ((fd = open(fname, O_RDONLY)) == -1) {
- fprintf(stderr, "Couldn't open %s\n", fname);
- exit(1);
- }
-
- /* Make sure pixmaps are freed when program is terminated */
- /* This is when I hit ^C */
- if (signal(SIGINT, SIG_IGN) != SIG_IGN)
- signal(SIGINT, onintr);
- /* xscreensaver sends SIGTERM */
- if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
- signal(SIGTERM, onintr);
-#ifdef DEBUG
- if (signal(SIGSEGV, SIGN_IGN) != SIG_IGN)
- signal(SIGSEGV, onsegv);
-#endif /* DEBUG */
-
- while (1) {
- if (inxpm == 2)
- break;
-
- buf = (char *)malloc(READ_LINE_BUF_SIZE * sizeof(char));
-
- switch ((rv = read_line(fd, &buf, READ_LINE_BUF_SIZE))) {
- case IO_ERROR:
- fprintf(stderr, "An I/O error occurred\n");
- exit(1);
- case EOF_REACHED:
- if (inxpm) {
- fprintf(stderr, "EOF occurred inside an XPM block\n");
- exit(1);
- } else
- inxpm = 2;
- break;
- case LINE_READ:
- if (inxpm) {
- if (strncmp("};", buf, 2) == 0) {
- inxpm = 0;
- write(tmpfd, buf, strlen(buf));
- write(tmpfd, "\n", 1);
- close(tmpfd);
- /* Now process the tmpfile */
- newpix = (Bubble_Step *)xmalloc(sizeof(Bubble_Step));
- make_pixmap_from_file(tmpname, newpix);
- /* Now add to list */
- if (pixmap_list == (Bubble_Step *)NULL) {
- pixmap_list = newpix;
- } else {
- tmppix = pixmap_list;
- while (tmppix->next != (Bubble_Step *)NULL)
- tmppix = tmppix->next;
- tmppix->next = newpix;
- }
- newpix->next = (Bubble_Step *)NULL;
- unlink(tmpname);
- } else {
- write(tmpfd, buf, strlen(buf));
- write(tmpfd, "\n", 1);
- }
- } else {
- if (strncmp("/* XPM */", buf, 9) == 0) {
- tmpfd = create_temp_file(&tmpname);
-/* This proves XPM's performance is kinda pathetic */
-#ifdef DEBUG
- printf("New XPM detected : %s, fd=%d\n", tmpname, tmpfd);
-#endif /* DEBUG */
- inxpm = 1;
- xpmseen = 1;
- }
- write(tmpfd, buf, strlen(buf));
- write(tmpfd, "\n", 1);
- }
- break;
- default:
- fprintf(stderr, "read_line returned unknown code %d\n", rv);
- exit(1);
- }
-
- free(buf);
- }
-
- close(fd);
- if (buf != (char *)NULL)
- free(buf);
- if (tmpname != (char *)NULL)
- free(tmpname);
-
- if (! xpmseen) {
- fprintf(stderr, "There was no XPM data in the file %s\n", fname);
- exit(1);
- }
-
- /* Finally construct step_pixmaps[] */
- make_pixmap_array(pixmap_list);
-}
-
-static void
-shell_exec(char *command)
-/* Forks a shell to execute "command" then waits for command to finish */
-{
- int pid, status, wval;
+#endif /* FANCY_BUBBLES */
- switch(pid=fork()) {
- case 0:
- if (execlp(BOURNESH, BOURNESH, "-c", command, (char *)NULL) == -1) {
- fprintf(stderr, "Couldn't exec shell %s\n", BOURNESH);
- exit(1);
- }
- /* fall through if execlp() fails */
- case -1:
- /* Couldn't fork */
- perror(progname);
- exit(1);
- default:
- while ((wval = wait(&status)) != pid)
- if (wval == -1) {
- perror(progname);
- exit(1);
- }
- }
-}
-
-static void
-uncompress_file(char *current, char *namebuf)
-/* If the file current is compressed (i.e. its name ends in .gz or .Z,
-no check is made to see if it is actually a compressed file...) then a
-new temporary file is created for it and it is decompressed into there,
-returning the name of the file to namebuf, else current is returned in
-namebuf */
-{
- int fd;
- char *tname = (char *)NULL;
- char argbuf[COMMAND_BUF_SIZE];
-
- if (((strlen(current) >=4) &&
- (strncmp(¤t[strlen(current)-3], ".gz", 3) == 0)) ||
- ((strlen(current) >=3) &&
- (strncmp(¤t[strlen(current)-2], ".Z", 2) == 0))) {
- fd = create_temp_file(&tname);
- /* close immediately but don't unlink so we should have a zero length
- file in /tmp which we can append to */
- close(fd);
- if (sprintf(argbuf, "%s -dc %s > %s", GZIP, current, tname) >
- (COMMAND_BUF_SIZE-1)) {
- fprintf(stderr, "command buffer overflowed in uncompress_file()\n");
- exit(1);
- }
- shell_exec(argbuf);
- strcpy(namebuf, tname);
- } else {
- strcpy(namebuf, current);
- }
- return;
-}
-
-#endif /* BUBBLES_IO */
/*
* Main stuff
get_resources(Display *dpy, Window window)
/* Get the appropriate X resources and warn about any inconsistencies. */
{
- Bool nodelay;
-#ifdef BUBBLES_IO
-#ifdef HAVE_XPM
- char *dirname;
-#else
- char *foo, *bar;
-#endif /* HAVE_XPM */
-#endif /* BUBBLES_IO */
-
+ Bool nodelay, rise;
XWindowAttributes xgwa;
Colormap cmap;
XGetWindowAttributes (dpy, window, &xgwa);
if (delay < 0)
delay = 0;
+ drop = get_boolean_resource("drop", "Boolean");
+ rise = get_boolean_resource("rise", "Boolean");
+ trails = get_boolean_resource("trails", "Boolean");
+ if (drop && rise) {
+ fprintf( stderr, "Sorry, bubbles can't both drop and rise\n" );
+ exit(1);
+ }
+ drop_dir = (drop ? 1 : -1);
+ if (drop || rise)
+ drop = 1;
+
default_fg_pixel = get_pixel_resource ("foreground", "Foreground", dpy,
cmap);
default_bg_pixel = get_pixel_resource ("background", "Background", dpy,
if (! quiet)
fprintf(stderr, "-broken not available in simple mode\n");
} else {
-#ifndef HAVE_XPM
+#ifndef FANCY_BUBBLES
simple = 1;
-#else
+#else /* FANCY_BUBBLES */
broken = get_boolean_resource("broken", "Boolean");
-#ifdef BUBBLES_IO
- pixmap_file = get_string_resource("file", "File");
- dirname = get_string_resource("directory", "Directory");
-#ifdef NO_DEFAULT_BUBBLE
- /* Must specify -file or -directory if no default bubble compiled in */
- if (strcmp(pixmap_file, "(default)") != 0) {
- } else if (strcmp(dirname, "(default)") != 0) {
- if ((pixmap_file = get_random_name(dirname)) == (char *)NULL) {
- /* Die if we can't open directory - make it consistent with -file
- when it fails, rather than falling back to default. */
- exit(1);
- }
- } else {
- fprintf(stderr,
- "No default bubble compiled in - use -file or -directory\n");
- exit(1);
- }
-#else
- if (strcmp(pixmap_file, "(default)") != 0) {
- } else if (strcmp(dirname, "(default)") != 0) {
- if ((pixmap_file = get_random_name(dirname)) == (char *)NULL) {
- exit(1);
- }
- } else {
- /* Use default bubble */
- use_default_bubble = 1;
- }
-#endif /* NO_DEFAULT_BUBBLE */
-#else
- use_default_bubble = 1;
-#endif /* BUBBLES_IO */
-#endif /* HAVE_XPM */
+#endif /* FANCY_BUBBLES */
}
}
XGCValues gcv;
XWindowAttributes xgwa;
int i;
-#ifdef BUBBLES_IO
- char uncompressed[1024];
-#endif /* BUBBLES_IO */
defdsp = dpy;
defwin = window;
- ya_rand_init(0);
-
get_resources(dpy, window);
XGetWindowAttributes (dpy, window, &xgwa);
for (i = bubble_min_radius; i <= (bubble_max_radius+1); i++)
bubble_areas[i] = calc_bubble_area(i);
+ /* Now populate the droppage values */
+ bubble_droppages = (int *)xmalloc((bubble_max_radius + 2) * sizeof(int));
+ for (i = 0; i < bubble_min_radius; i++)
+ bubble_droppages[i] = 0;
+ for (i = bubble_min_radius; i <= (bubble_max_radius+1); i++)
+ bubble_droppages[i] = MAX_DROPPAGE * (i - bubble_min_radius) / (bubble_max_radius - bubble_min_radius);
+
mesh_length = (2 * bubble_max_radius) + 3;
} else {
-#ifndef HAVE_XPM
+#ifndef FANCY_BUBBLES
fprintf(stderr,
- "Bug: simple mode code not set but HAVE_XPM not defined\n");
+ "Bug: simple mode code not set but FANCY_BUBBLES not defined\n");
exit(1);
-#else
+#else /* FANCY_BUBBLES */
/* Make sure all #ifdef sort of things have been taken care of in
get_resources(). */
- if (use_default_bubble) {
-#ifdef NO_DEFAULT_BUBBLE
- fprintf(stderr,
- "Bug: use_default_bubble and NO_DEFAULT_BUBBLE both defined\n");
- exit(1);
-#else
- default_to_pixmaps();
-#endif /* NO_DEFAULT_BUBBLE */
-
- /* Set mesh length */
- mesh_length = (2 * step_pixmaps[num_bubble_pixmaps-1]->radius) + 3;
- } else {
-#ifdef BUBBLES_IO
- if (! regular_file(pixmap_file)) {
- /* perror() in regular_file printed error message */
- exit(1);
- }
- uncompress_file(pixmap_file, uncompressed);
- read_file_to_pixmaps(uncompressed);
- if (strcmp(pixmap_file, uncompressed))
- unlink(uncompressed);
+ default_to_pixmaps();
- mesh_length = (2 * step_pixmaps[num_bubble_pixmaps-1]->radius) + 3;
-#else
- fprintf(stderr,
- "Bug: use_default_bubble is not defined yet I/O is not compiled in\n");
- exit(1);
-#endif /* BUBBLES_IO */
- }
-#endif /* HAVE_XPM */
+ /* Set mesh length */
+ mesh_length = (2 * step_pixmaps[num_bubble_pixmaps-1]->radius) + 3;
+#endif /* FANCY_BUBBLES */
/* Am I missing something in here??? */
}
add_to_mesh(tmp);
insert_new_bubble(tmp);
- XSync (dpy, True);
+ XSync (dpy, False);
}
init_bubbles (dpy, window);
while (1) {
bubbles (dpy, window);
+ screenhack_handle_events (dpy);
if (delay)
usleep(delay);
}