X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fbubbles.c;h=fe5ccef0585116a546358805185b045eb3529461;hb=a94197e76a5dea5cb60542840809d6c20d0abbf3;hp=5dffd2a29b20bfaa58d06bc5d73e34b06650c287;hpb=f3e0240915ed9f9b3a61781f5c7002d587563fe0;p=xscreensaver diff --git a/hacks/bubbles.c b/hacks/bubbles.c index 5dffd2a2..fe5ccef0 100644 --- a/hacks/bubbles.c +++ b/hacks/bubbles.c @@ -1,19 +1,17 @@ /* 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. */ /* @@ -38,23 +36,15 @@ * 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 #include "screenhack.h" -#include "bubbles.h" - -#ifdef BUBBLES_IO -# include -# include -# include -#endif /* BUBBLES_IO */ #include -#include + #include -#include #include #ifndef VMS @@ -69,52 +59,50 @@ # include #endif #include "yarandom.h" +#include "bubbles.h" +#include "xpm-pixmap.h" -#ifdef HAVE_XPM -#include +#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 } }; @@ -147,19 +135,16 @@ static Visual *defvisual; 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; @@ -167,6 +152,9 @@ 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; /* @@ -238,7 +226,7 @@ turned off if DEBUG isn't set. */ 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) || @@ -249,7 +237,7 @@ turned off if DEBUG isn't set. */ bb->radius, bb->x, bb->y, bb->magic, bb->cell_index); die_bad_bubble(bb); } -#endif /* HAVE_XPM */ +#endif } #endif /* DEBUG */ return 0; @@ -451,20 +439,20 @@ adjust_areas (void) 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; @@ -484,13 +472,13 @@ adjust_areas (void) #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); @@ -520,17 +508,17 @@ size. */ 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; @@ -553,7 +541,7 @@ show_bubble(Bubble *bb) (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)); @@ -564,7 +552,7 @@ show_bubble(Bubble *bb) (bb->radius * 2), (bb->x - bb->radius), (bb->y - bb->radius)); -#endif /* HAVE_XPM */ +#endif /* FANCY_BUBBLES */ } } } @@ -586,7 +574,7 @@ hide_bubble(Bubble *bb) (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)); @@ -597,7 +585,7 @@ hide_bubble(Bubble *bb) (bb->radius * 2), (bb->radius * 2)); } -#endif /* HAVE_XPM */ +#endif /* FANCY_BUBBLES */ } } } @@ -770,38 +758,50 @@ bubble_eat(Bubble *diner, Bubble *food) 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 */ @@ -860,7 +860,7 @@ merge_bubbles(Bubble *b1, Bubble *b2) break; } } else { - if ((ya_random() % 2) == 0) { + if ((random() % 2) == 0) { switch (bubble_eat(b1, b2)) { case 0: return 0; @@ -906,33 +906,133 @@ insert_new_bubble(Bubble *tmp) 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) @@ -954,52 +1054,7 @@ 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) @@ -1110,9 +1165,12 @@ make_pixmap_array(Bubble_Step *list) 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 @@ -1121,7 +1179,6 @@ make_pixmap_from_default(char **pixmap_data, Bubble_Step *bl) 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 @@ -1136,49 +1193,16 @@ changes made to either should be propagated onwards! */ 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; @@ -1200,21 +1224,7 @@ default_to_pixmaps (void) 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]; @@ -1236,406 +1246,8 @@ default_to_pixmaps (void) 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 @@ -1646,15 +1258,7 @@ static void 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); @@ -1677,6 +1281,17 @@ get_resources(Display *dpy, Window window) 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, @@ -1689,42 +1304,11 @@ get_resources(Display *dpy, Window window) 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 */ } } @@ -1734,15 +1318,10 @@ init_bubbles (Display *dpy, Window window) 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); @@ -1780,45 +1359,27 @@ init_bubbles (Display *dpy, Window window) 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??? */ } @@ -1852,7 +1413,7 @@ bubbles (Display *dpy, Window window) add_to_mesh(tmp); insert_new_bubble(tmp); - XSync (dpy, True); + XSync (dpy, False); } @@ -1862,6 +1423,7 @@ screenhack (Display *dpy, Window window) init_bubbles (dpy, window); while (1) { bubbles (dpy, window); + screenhack_handle_events (dpy); if (delay) usleep(delay); }