X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fbubbles.c;h=9cb2678d2bed0c1d6efe4194702b9f10947e29c1;hb=78add6e627ee5f10e1fa6f3852602ea5066eee5a;hp=db87ffe492d04444ba07447a72d802d253538bcc;hpb=5b7bc6e70fb439cf4c4bf771ae9f94077fe4fe08;p=xscreensaver diff --git a/hacks/bubbles.c b/hacks/bubbles.c index db87ffe4..9cb2678d 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.10 1997/12/03 10:56:13 jwz Exp $*/ +/*$Id: bubbles.c,v 1.30 2008/07/31 19:27:48 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,29 +36,18 @@ * 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 HAVE_CONFIG_H +# include "config.h" +#endif -#ifdef BUBBLES_IO -# include -# include -# include -#endif /* BUBBLES_IO */ +#undef DEBUG /* doesn't compile */ +#include #include -#ifdef SIGNAL_NONSENSE /* what's this crap doing in here? */ -#include -#endif /* SIGNAL_NONSENSE */ - -#include -#include -#include - #ifndef VMS # include #else /* VMS */ @@ -72,53 +59,44 @@ #ifdef HAVE_UNISTD_H # include #endif + +#include "screenhack.h" #include "yarandom.h" +#include "bubbles.h" +#include "ximage-loader.h" -#ifdef HAVE_XPM -#include -#endif +#define FANCY_BUBBLES /* * Public variables */ -#ifndef NO_DEFAULT_BUBBLE -extern int num_default_bubbles; -extern char **default_bubbles[]; -#endif /* NO_DEFAULT_BUBBLE */ - -char *progclass = "Bubbles"; - -char *defaults [] = { - "*background: black", - "*foreground: white", - "*simple: false", - "*broken: false", - "*delay: 800", -#ifdef BUBBLES_IO - "*file: (default)", - "*directory: (default)", -#endif /* BUBBLES_IO */ - "*quiet: false", - "*nodelay: false", - "*3D: false", - "*geometry: 400x300", +static const char *bubbles_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*simple: false", + "*broken: false", + "*delay: 10000", + "*quiet: false", + "*mode: float", + "*trails: false", + "*3D: false", 0 }; -XrmOptionDescRec options [] = { +static XrmOptionDescRec bubbles_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 }, + { "-mode", ".mode", XrmoptionSepArg, 0 }, + { "-drop", ".mode", XrmoptionNoArg, "drop" }, + { "-rise", ".mode", XrmoptionNoArg, "rise" }, + { "-trails", ".trails", XrmoptionNoArg, "true" }, { 0, 0, 0, 0 } }; @@ -126,66 +104,59 @@ XrmOptionDescRec options [] = { * Private variables */ -static Bubble **mesh; -static int mesh_length; -static int mesh_width; -static int mesh_height; -static int mesh_cells; +struct state { + Display *dpy; + Window window; -static int **adjacent_list; + Bubble **mesh; + int mesh_length; + int mesh_width; + int mesh_height; + int mesh_cells; -static int screen_width; -static int screen_height; -static int screen_depth; -static unsigned int default_fg_pixel, default_bg_pixel; -/* - * I know it's not elegant to save this stuff in global variables - * but we need it for the signal handler. - */ -static Display *defdsp; -static Window defwin; -static Colormap defcmap; -static Visual *defvisual; - -/* For simple mode only */ -static int bubble_min_radius; -static int bubble_max_radius; -static long *bubble_areas; -static GC draw_gc, erase_gc; - -#ifdef HAVE_XPM -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 */ - -/* Options stuff */ -#ifdef HAVE_XPM -static Bool simple = False; -#else -static Bool simple = True; + int **adjacent_list; + + int screen_width; + int screen_height; + int screen_depth; + unsigned int default_fg_pixel, default_bg_pixel; + + int bubble_min_radius; /* For simple mode only */ + int bubble_max_radius; + long *bubble_areas; + int *bubble_droppages; + GC draw_gc, erase_gc; + +#ifdef FANCY_BUBBLES + int num_bubble_pixmaps; + Bubble_Step **step_pixmaps; #endif -static Bool broken = False; -static Bool quiet = False; -static Bool threed = False; -static int delay; + + Bool simple; + Bool broken; + Bool quiet; + Bool threed; + Bool drop; + Bool trails; + int drop_dir; + int delay; +}; + +static int drop_bubble( struct state *st, Bubble *bb ); /* * To prevent forward references, some stuff is up here */ static long -calc_bubble_area(int r) +calc_bubble_area(struct state *st, int r) /* Calculate the area of a bubble of radius r */ { #ifdef DEBUG printf("%d %g\n", r, 10.0 * PI * (double)r * (double)r * (double)r); #endif /* DEBUG */ - if (threed) + if (st->threed) return (long)(10.0 * PI * (double)r * (double)r * (double)r); else return (long)(10.0 * PI * (double)r * (double)r); @@ -224,7 +195,7 @@ turned off if DEBUG isn't set. */ if (bb == (Bubble *)NULL) return 1; #ifdef DEBUG - if ((bb->cell_index < 0) || (bb->cell_index > mesh_cells)) { + if ((bb->cell_index < 0) || (bb->cell_index > st->mesh_cells)) { fprintf(stderr, "cell_index = %d\n", bb->cell_index); die_bad_bubble(bb); } @@ -232,28 +203,28 @@ turned off if DEBUG isn't set. */ fprintf(stderr, "Magic = %d\n", bb->magic); die_bad_bubble(bb); } - if (simple) { - if ((bb->x < 0) || (bb->x > screen_width) || - (bb->y < 0) || (bb->y > screen_height) || - (bb->radius < bubble_min_radius) || (bb->radius > - bubble_max_radius)) { + if (st->simple) { + if ((bb->x < 0) || (bb->x > st->screen_width) || + (bb->y < 0) || (bb->y > st->screen_height) || + (bb->radius < st->bubble_min_radius) || (bb->radius > + st->bubble_max_radius)) { fprintf(stderr, "radius = %d, x = %d, y = %d, magic = %d, cell index = %d\n", 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 < step_pixmaps[0]->radius) || - (bb->radius > step_pixmaps[num_bubble_pixmaps-1]->radius)) { + if ((bb->x < 0) || (bb->x > st->screen_width) || + (bb->y < 0) || (bb->y > st->screen_height) || + (bb->radius < st->step_pixmaps[0]->radius) || + (bb->radius > st->step_pixmaps[st->num_bubble_pixmaps-1]->radius)) { fprintf(stderr, "radius = %d, x = %d, y = %d, magic = %d, cell index = %d\n", bb->radius, bb->x, bb->y, bb->magic, bb->cell_index); die_bad_bubble(bb); } -#endif /* HAVE_XPM */ +#endif } #endif /* DEBUG */ return 0; @@ -296,18 +267,18 @@ add_bubble_to_list(Bubble **list, Bubble *bb) static void -init_mesh (void) +init_mesh (struct state *st) /* Setup the mesh of bubbles */ { int i; - mesh = (Bubble **)xmalloc(mesh_cells * sizeof(Bubble *)); - for (i = 0; i < mesh_cells; i++) - mesh[i] = (Bubble *)NULL; + st->mesh = (Bubble **)xmalloc(st->mesh_cells * sizeof(Bubble *)); + for (i = 0; i < st->mesh_cells; i++) + st->mesh[i] = (Bubble *)NULL; } static int -cell_to_mesh(int x, int y) +cell_to_mesh(struct state *st, int x, int y) /* convert cell coordinates to mesh index */ { #ifdef DEBUG @@ -316,31 +287,31 @@ cell_to_mesh(int x, int y) exit(1); } #endif - return ((mesh_width * y) + x); + return ((st->mesh_width * y) + x); } static void -mesh_to_cell(int mi, int *cx, int *cy) +mesh_to_cell(struct state *st, int mi, int *cx, int *cy) /* convert mesh index into cell coordinates */ { - *cx = mi % mesh_width; - *cy = mi / mesh_width; + *cx = mi % st->mesh_width; + *cy = mi / st->mesh_width; } static int -pixel_to_mesh(int x, int y) +pixel_to_mesh(struct state *st, int x, int y) /* convert screen coordinates into mesh index */ { - return cell_to_mesh((x / mesh_length), (y / mesh_length)); + return cell_to_mesh(st, (x / st->mesh_length), (y / st->mesh_length)); } static int -verify_mesh_index(int x, int y) +verify_mesh_index(struct state *st, int x, int y) /* check to see if (x,y) is in the mesh */ { - if ((x < 0) || (y < 0) || (x >= mesh_width) || (y >= mesh_height)) + if ((x < 0) || (y < 0) || (x >= st->mesh_width) || (y >= st->mesh_height)) return (-1); - return (cell_to_mesh(x, y)); + return (cell_to_mesh(st, x, y)); } #ifdef DEBUG @@ -358,7 +329,7 @@ print_adjacents(int *adj) #endif /* DEBUG */ static void -add_to_mesh(Bubble *bb) +add_to_mesh(struct state *st, Bubble *bb) /* Add the given bubble to the mesh by sticking it on the front of the list. bb is already allocated so no need to malloc() anything, just adjust pointers. */ @@ -370,48 +341,48 @@ adjust pointers. */ } #endif /* DEBUG */ - add_bubble_to_list(&mesh[bb->cell_index], bb); + add_bubble_to_list(&st->mesh[bb->cell_index], bb); } #ifdef DEBUG static void -print_mesh (void) +print_mesh (struct state *st) /* Print the contents of the mesh */ { int i; - for (i = 0; i < mesh_cells; i++) { - if (! null_bubble(mesh[i])) { + for (i = 0; i < st->mesh_cells; i++) { + if (! null_bubble(st->mesh[i])) { printf("Mesh cell %d\n", i); - print_bubble_list(mesh[i]); + print_bubble_list(st->mesh[i]); } } } static void -valid_mesh (void) +valid_mesh (struct state *st) /* Check to see if the mesh is Okay. For debugging only. */ { int i; Bubble *b; - for (i = 0; i < mesh_cells; i++) { - b = mesh[i]; + for (i = 0; i < st->mesh_cells; i++) { + b = st->mesh[i]; while (! null_bubble(b)) b = b->next; } } static int -total_bubbles (void) +total_bubbles (struct state *st) /* Count how many bubbles there are in total. For debugging only. */ { int rv = 0; int i; Bubble *b; - for (i = 0; i < mesh_cells; i++) { - b = mesh[i]; + for (i = 0; i < st->mesh_cells; i++) { + b = st->mesh[i]; while (! null_bubble(b)) { rv++; b = b->next; @@ -423,31 +394,31 @@ total_bubbles (void) #endif /* DEBUG */ static void -calculate_adjacent_list (void) +calculate_adjacent_list (struct state *st) /* Calculate the list of cells adjacent to a particular cell for use later. */ { int i; int ix, iy; - adjacent_list = (int **)xmalloc(mesh_cells * sizeof(int *)); - for (i = 0; i < mesh_cells; i++) { - adjacent_list[i] = (int *)xmalloc(9 * sizeof(int)); - mesh_to_cell(i, &ix, &iy); - adjacent_list[i][0] = verify_mesh_index(--ix, --iy); - adjacent_list[i][1] = verify_mesh_index(++ix, iy); - adjacent_list[i][2] = verify_mesh_index(++ix, iy); - adjacent_list[i][3] = verify_mesh_index(ix, ++iy); - adjacent_list[i][4] = verify_mesh_index(ix, ++iy); - adjacent_list[i][5] = verify_mesh_index(--ix, iy); - adjacent_list[i][6] = verify_mesh_index(--ix, iy); - adjacent_list[i][7] = verify_mesh_index(ix, --iy); - adjacent_list[i][8] = i; + st->adjacent_list = (int **)xmalloc(st->mesh_cells * sizeof(int *)); + for (i = 0; i < st->mesh_cells; i++) { + st->adjacent_list[i] = (int *)xmalloc(9 * sizeof(int)); + mesh_to_cell(st, i, &ix, &iy); + st->adjacent_list[i][0] = verify_mesh_index(st, --ix, --iy); + st->adjacent_list[i][1] = verify_mesh_index(st, ++ix, iy); + st->adjacent_list[i][2] = verify_mesh_index(st, ++ix, iy); + st->adjacent_list[i][3] = verify_mesh_index(st, ix, ++iy); + st->adjacent_list[i][4] = verify_mesh_index(st, ix, ++iy); + st->adjacent_list[i][5] = verify_mesh_index(st, --ix, iy); + st->adjacent_list[i][6] = verify_mesh_index(st, --ix, iy); + st->adjacent_list[i][7] = verify_mesh_index(st, ix, --iy); + st->adjacent_list[i][8] = i; } } static void -adjust_areas (void) +adjust_areas (struct state *st) /* Adjust areas of bubbles so we don't get overflow in weighted_mean() */ { double maxvalue; @@ -455,46 +426,46 @@ adjust_areas (void) long factor; int i; -#ifdef HAVE_XPM - if (simple) - maxarea = bubble_areas[bubble_max_radius+1]; +#ifdef FANCY_BUBBLES + if (st->simple) + maxarea = st->bubble_areas[st->bubble_max_radius+1]; else - maxarea = step_pixmaps[num_bubble_pixmaps]->area; -#else - maxarea = bubble_areas[bubble_max_radius+1]; -#endif /* HAVE_XPM */ - maxvalue = (double)screen_width * 2.0 * (double)maxarea; + maxarea = st->step_pixmaps[st->num_bubble_pixmaps]->area; +#else /* !FANCY_BUBBLES */ + maxarea = st->bubble_areas[st->bubble_max_radius+1]; +#endif /* !FANCY_BUBBLES */ + maxvalue = (double)st->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 - if (simple) { - for (i = bubble_min_radius; i <= bubble_max_radius+1; i++) { - bubble_areas[i] /= factor; - if (bubble_areas[i] == 0) - bubble_areas[i] = 1; +#ifdef FANCY_BUBBLES + if (st->simple) { + for (i = st->bubble_min_radius; i <= st->bubble_max_radius+1; i++) { + st->bubble_areas[i] /= factor; + if (st->bubble_areas[i] == 0) + st->bubble_areas[i] = 1; } } else { - for (i = 0; i <= num_bubble_pixmaps; i++) { + for (i = 0; i <= st->num_bubble_pixmaps; i++) { #ifdef DEBUG - printf("area = %ld", step_pixmaps[i]->area); + printf("area = %ld", st->step_pixmaps[i]->area); #endif /* DEBUG */ - step_pixmaps[i]->area /= factor; - if (step_pixmaps[i]->area == 0) - step_pixmaps[i]->area = 1; + st->step_pixmaps[i]->area /= factor; + if (st->step_pixmaps[i]->area == 0) + st->step_pixmaps[i]->area = 1; #ifdef DEBUG - printf("-> %ld\n", step_pixmaps[i]->area); + printf("-> %ld\n", st->step_pixmaps[i]->area); #endif /* DEBUG */ } } -#else - for (i = bubble_min_radius; i <= bubble_max_radius+1; i++) { - bubble_areas[i] /= factor; - if (bubble_areas[i] == 0) - bubble_areas[i] = 1; +#else /* !FANCY_BUBBLES */ + for (i = st->bubble_min_radius; i <= st->bubble_max_radius+1; i++) { + st->bubble_areas[i] /= factor; + if (st->bubble_areas[i] == 0) + st->bubble_areas[i] = 1; } -#endif /* HAVE_XPM */ +#endif /* !FANCY_BUBBLES */ } #ifdef DEBUG printf("maxarea = %ld\n", maxarea); @@ -509,7 +480,7 @@ adjust_areas (void) */ static Bubble * -new_bubble (void) +new_bubble (struct state *st) /* Add a new bubble at some random position on the screen of the smallest size. */ { @@ -521,27 +492,27 @@ size. */ exit(1); } - if (simple) { - rv->radius = bubble_min_radius; - rv->area = bubble_areas[bubble_min_radius]; -#ifdef HAVE_XPM + if (st->simple) { + rv->radius = st->bubble_min_radius; + rv->area = st->bubble_areas[st->bubble_min_radius]; +#ifdef FANCY_BUBBLES } else { rv->step = 0; - rv->radius = step_pixmaps[0]->radius; - rv->area = step_pixmaps[0]->area; -#endif /* HAVE_XPM */ + rv->radius = st->step_pixmaps[0]->radius; + rv->area = st->step_pixmaps[0]->area; +#endif /* FANCY_BUBBLES */ } rv->visible = 0; rv->magic = BUBBLE_MAGIC; - rv->x = ya_random() % screen_width; - rv->y = ya_random() % screen_height; - rv->cell_index = pixel_to_mesh(rv->x, rv->y); + rv->x = random() % st->screen_width; + rv->y = random() % st->screen_height; + rv->cell_index = pixel_to_mesh(st, rv->x, rv->y); return rv; } static void -show_bubble(Bubble *bb) +show_bubble(struct state *st, Bubble *bb) /* paint the bubble on the screen */ { if (null_bubble(bb)) { @@ -552,29 +523,29 @@ show_bubble(Bubble *bb) if (! bb->visible) { bb->visible = 1; - if (simple) { - XDrawArc(defdsp, defwin, draw_gc, (bb->x - bb->radius), + if (st->simple) { + XDrawArc(st->dpy, st->window, st->draw_gc, (bb->x - bb->radius), (bb->y - bb->radius), bb->radius*2, bb->radius*2, 0, 360*64); } else { -#ifdef HAVE_XPM - XSetClipOrigin(defdsp, step_pixmaps[bb->step]->draw_gc, +#ifdef FANCY_BUBBLES + XSetClipOrigin(st->dpy, st->step_pixmaps[bb->step]->draw_gc, (bb->x - bb->radius), (bb->y - bb->radius)); - XCopyArea(defdsp, step_pixmaps[bb->step]->ball, defwin, - step_pixmaps[bb->step]->draw_gc, + XCopyArea(st->dpy, st->step_pixmaps[bb->step]->ball, st->window, + st->step_pixmaps[bb->step]->draw_gc, 0, 0, (bb->radius * 2), (bb->radius * 2), (bb->x - bb->radius), (bb->y - bb->radius)); -#endif /* HAVE_XPM */ +#endif /* FANCY_BUBBLES */ } } } static void -hide_bubble(Bubble *bb) +hide_bubble(struct state *st, Bubble *bb) /* erase the bubble */ { if (null_bubble(bb)) { @@ -585,29 +556,29 @@ hide_bubble(Bubble *bb) if (bb->visible) { bb->visible = 0; - if (simple) { - XDrawArc(defdsp, defwin, erase_gc, (bb->x - bb->radius), + if (st->simple) { + XDrawArc(st->dpy, st->window, st->erase_gc, (bb->x - bb->radius), (bb->y - bb->radius), bb->radius*2, bb->radius*2, 0, 360*64); } else { -#ifdef HAVE_XPM - if (! broken) { - XSetClipOrigin(defdsp, step_pixmaps[bb->step]->erase_gc, +#ifdef FANCY_BUBBLES + if (! st->broken) { + XSetClipOrigin(st->dpy, st->step_pixmaps[bb->step]->erase_gc, (bb->x - bb->radius), (bb->y - bb->radius)); - XFillRectangle(defdsp, defwin, step_pixmaps[bb->step]->erase_gc, + XFillRectangle(st->dpy, st->window, st->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 */ } } } static void -delete_bubble_in_mesh(Bubble *bb, int keep_bubble) +delete_bubble_in_mesh(struct state *st, Bubble *bb, int keep_bubble) /* Delete an individual bubble, adjusting list of bubbles around it. If keep_bubble is true then the bubble isn't actually deleted. We use this to allow bubbles to change mesh cells without reallocating, @@ -620,15 +591,15 @@ delete_bubble_in_mesh(Bubble *bb, int keep_bubble) } else if ((!null_bubble(bb->prev)) && (null_bubble(bb->next))) { bb->prev->next = (Bubble *)NULL; - bb->next = mesh[bb->cell_index]; + bb->next = st->mesh[bb->cell_index]; } else if ((null_bubble(bb->prev)) && (!null_bubble(bb->next))) { bb->next->prev = (Bubble *)NULL; - mesh[bb->cell_index] = bb->next; - bb->next = mesh[bb->cell_index]; + st->mesh[bb->cell_index] = bb->next; + bb->next = st->mesh[bb->cell_index]; } else { /* Only item on list */ - mesh[bb->cell_index] = (Bubble *)NULL; + st->mesh[bb->cell_index] = (Bubble *)NULL; } if (! keep_bubble) free(bb); @@ -642,7 +613,7 @@ ulongsqrint(int x) } static Bubble * -get_closest_bubble(Bubble *bb) +get_closest_bubble(struct state *st, Bubble *bb) /* Find the closest bubble touching the this bubble, NULL if none are touching. */ { @@ -664,14 +635,14 @@ get_closest_bubble(Bubble *bb) for (i = 0; i < 9; i++) { /* There is a bug here where bb->cell_index is negaitve.. */ #ifdef DEBUG - if ((bb->cell_index < 0) || (bb->cell_index >= mesh_cells)) { + if ((bb->cell_index < 0) || (bb->cell_index >= st->mesh_cells)) { fprintf(stderr, "bb->cell_index = %d\n", bb->cell_index); exit(1); } #endif /* DEBUG */ /* printf("%d,", bb->cell_index); */ - if (adjacent_list[bb->cell_index][i] != -1) { - tmp = mesh[adjacent_list[bb->cell_index][i]]; + if (st->adjacent_list[bb->cell_index][i] != -1) { + tmp = st->mesh[st->adjacent_list[bb->cell_index][i]]; while (! null_bubble(tmp)) { if (tmp != bb) { dx = tmp->x - bb->x; @@ -695,7 +666,7 @@ get_closest_bubble(Bubble *bb) #ifdef DEBUG static void -ldr_barf (void) +ldr_barf (struct state *st) { } #endif /* DEBUG */ @@ -746,7 +717,7 @@ weighted_mean(int n1, int n2, long w1, long w2) } static int -bubble_eat(Bubble *diner, Bubble *food) +bubble_eat(struct state *st, Bubble *diner, Bubble *food) /* The diner eats the food. Returns true (1) if the diner still exists */ { int i; @@ -766,60 +737,72 @@ bubble_eat(Bubble *diner, Bubble *food) would then not have to redraw bubbles which don't change in size. */ - hide_bubble(diner); - hide_bubble(food); + hide_bubble(st, diner); + hide_bubble(st, food); diner->x = weighted_mean(diner->x, food->x, diner->area, food->area); diner->y = weighted_mean(diner->y, food->y, diner->area, food->area); - newmi = pixel_to_mesh(diner->x, diner->y); + newmi = pixel_to_mesh(st, diner->x, diner->y); diner->area += food->area; - delete_bubble_in_mesh(food, DELETE_BUBBLE); + delete_bubble_in_mesh(st, food, DELETE_BUBBLE); - if ((simple) && (diner->area > bubble_areas[bubble_max_radius])) { - delete_bubble_in_mesh(diner, DELETE_BUBBLE); - return 0; + if (st->drop) { + if ((st->simple) && (diner->area > st->bubble_areas[st->bubble_max_radius])) { + diner->area = st->bubble_areas[st->bubble_max_radius]; + } +#ifdef FANCY_BUBBLES + if ((! st->simple) && (diner->area > st->step_pixmaps[st->num_bubble_pixmaps]->area)) { + diner->area = st->step_pixmaps[st->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 ((st->simple) && (diner->area > st->bubble_areas[st->bubble_max_radius])) { + delete_bubble_in_mesh(st, diner, DELETE_BUBBLE); + return 0; + } +#ifdef FANCY_BUBBLES + if ((! st->simple) && (diner->area > + st->step_pixmaps[st->num_bubble_pixmaps]->area)) { + delete_bubble_in_mesh(st, diner, DELETE_BUBBLE); + return 0; + } +#endif /* FANCY_BUBBLES */ } -#endif /* HAVE_XPM */ - if (simple) { - if (diner->area > bubble_areas[diner->radius + 1]) { + if (st->simple) { + if (diner->area > st->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 < st->bubble_max_radius - 1) && (diner->area > st->bubble_areas[i+1])) + ++i; diner->radius = i; } - show_bubble(diner); -#ifdef HAVE_XPM + show_bubble(st, diner); +#ifdef FANCY_BUBBLES } else { - if (diner->area > step_pixmaps[diner->step+1]->area) { + if (diner->area > st->step_pixmaps[diner->step+1]->area) { i = diner->step; - while (diner->area > step_pixmaps[i+1]->area) - ++i; + while ((i < st->num_bubble_pixmaps - 1) && (diner->area > st->step_pixmaps[i+1]->area)) + ++i; diner->step = i; - diner->radius = step_pixmaps[diner->step]->radius; + diner->radius = st->step_pixmaps[diner->step]->radius; } - show_bubble(diner); -#endif /* HAVE_XPM */ + show_bubble(st, diner); +#endif /* FANCY_BUBBLES */ } /* Now adjust locations and cells if need be */ if (newmi != diner->cell_index) { - delete_bubble_in_mesh(diner, KEEP_BUBBLE); + delete_bubble_in_mesh(st, diner, KEEP_BUBBLE); diner->cell_index = newmi; - add_to_mesh(diner); + add_to_mesh(st, diner); } return 1; } static int -merge_bubbles(Bubble *b1, Bubble *b2) +merge_bubbles(struct state *st, Bubble *b1, Bubble *b2) /* These two bubbles merge into one. If the first one wins out return 1 else return 2. If there is no winner (it explodes) then return 0 */ { @@ -836,13 +819,13 @@ merge_bubbles(Bubble *b1, Bubble *b2) #endif /* DEBUG */ if (b1 == b2) { - hide_bubble(b1); - delete_bubble_in_mesh(b1, DELETE_BUBBLE); + hide_bubble(st, b1); + delete_bubble_in_mesh(st, b1, DELETE_BUBBLE); return 0; } if (b1size > b2size) { - switch (bubble_eat(b1, b2)) { + switch (bubble_eat(st, b1, b2)) { case 0: return 0; break; @@ -853,7 +836,7 @@ merge_bubbles(Bubble *b1, Bubble *b2) break; } } else if (b1size < b2size) { - switch (bubble_eat(b2, b1)) { + switch (bubble_eat(st, b2, b1)) { case 0: return 0; break; @@ -864,8 +847,8 @@ merge_bubbles(Bubble *b1, Bubble *b2) break; } } else { - if ((ya_random() % 2) == 0) { - switch (bubble_eat(b1, b2)) { + if ((random() % 2) == 0) { + switch (bubble_eat(st, b1, b2)) { case 0: return 0; break; @@ -876,7 +859,7 @@ merge_bubbles(Bubble *b1, Bubble *b2) break; } } else { - switch (bubble_eat(b2, b1)) { + switch (bubble_eat(st, b2, b1)) { case 0: return 0; break; @@ -893,7 +876,7 @@ merge_bubbles(Bubble *b1, Bubble *b2) } static void -insert_new_bubble(Bubble *tmp) +insert_new_bubble(struct state *st, Bubble *tmp) /* Calculates which bubbles are eaten when a new bubble tmp is inserted. This is called recursively in case when a bubble grows it eats others. Careful to pick out disappearing bubbles. */ @@ -909,34 +892,134 @@ insert_new_bubble(Bubble *tmp) #endif /* DEBUG */ 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; + touch = get_closest_bubble(st, nextbub); + if (null_bubble(touch)) + return; + + while (1) { + + /* Merge all touching bubbles */ + while (! null_bubble(touch)) { + switch (merge_bubbles(st, 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(st, nextbub); + } + + if (null_bubble(nextbub)) + break; + + /* Shift bubble down. Break if we run off the screen. */ + if (st->drop) { + if (drop_bubble( st, 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(st, nextbub); + if (null_bubble(touch)) { + /* We also continue every so often if we're dropping and the bubble is at max size */ + if (st->drop) { + if (st->simple) { + if ((nextbub->area >= st->bubble_areas[st->bubble_max_radius - 1]) && (random() % 2 == 0)) + continue; + } +#ifdef FANCY_BUBBLES + else { + if ((nextbub->step >= st->num_bubble_pixmaps - 1) && (random() % 2 == 0)) + continue; + } +#endif /* FANCY_BUBBLES */ + } + break; + } + + } +} + + +static void +leave_trail(struct state *st, Bubble *bb ) +{ + Bubble *tmp; + + tmp = new_bubble(st); + tmp->x = bb->x; + tmp->y = bb->y - ((bb->radius + 10) * st->drop_dir); + tmp->cell_index = pixel_to_mesh(st, tmp->x, tmp->y); + add_to_mesh(st, tmp); + insert_new_bubble(st, tmp); + show_bubble( st, tmp ); +} + + +static int +drop_bubble( struct state *st, Bubble *bb ) +{ + int newmi; + + hide_bubble( st, bb ); + + if (st->simple) + (bb->y) += (st->bubble_droppages[bb->radius] * st->drop_dir); +#ifdef FANCY_BUBBLES + else + (bb->y) += (st->step_pixmaps[bb->step]->droppage * st->drop_dir); +#endif /* FANCY_BUBBLES */ + if ((bb->y < 0) || (bb->y > st->screen_height)) { + delete_bubble_in_mesh( st, bb, DELETE_BUBBLE ); + return -1; + } + + show_bubble( st, bb ); + + /* Now adjust locations and cells if need be */ + newmi = pixel_to_mesh(st, bb->x, bb->y); + if (newmi != bb->cell_index) { + delete_bubble_in_mesh(st, bb, KEEP_BUBBLE); + bb->cell_index = newmi; + add_to_mesh(st, bb); + } + + if (st->trails) { + if (st->simple) { + if ((bb->area >= st->bubble_areas[st->bubble_max_radius - 1]) && (random() % 2 == 0)) + leave_trail( st, bb ); + } +#ifdef FANCY_BUBBLES + else { + if ((bb->step >= st->num_bubble_pixmaps - 1) && (random() % 2 == 0)) + leave_trail( st, bb ); + } +#endif /* FANCY_BUBBLES */ } + + return 0; } + #ifdef DEBUG static int get_length_of_bubble_list(Bubble *bb) @@ -958,54 +1041,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); - } -} - -#ifdef SIGNAL_NONSENSE -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 */ -#endif /* SIGNAL_NONSENSE */ - +#ifdef FANCY_BUBBLES /* * Pixmaps without file I/O (but do have XPM) @@ -1045,7 +1081,7 @@ extrapolate(int i1, int i2) } static void -make_pixmap_array(Bubble_Step *list) +make_pixmap_array(struct state *st, Bubble_Step *list) /* From a linked list of bubbles construct the array step_pixmaps */ { Bubble_Step *tmp = list; @@ -1059,25 +1095,25 @@ make_pixmap_array(Bubble_Step *list) exit(1); } - num_bubble_pixmaps = 1; + st->num_bubble_pixmaps = 1; while(tmp->next != (Bubble_Step *)NULL) { tmp = tmp->next; - ++num_bubble_pixmaps; + ++st->num_bubble_pixmaps; } - if (num_bubble_pixmaps < 2) { + if (st->num_bubble_pixmaps < 2) { fprintf(stderr, "Must be at least two bubbles in file\n"); exit(1); } - step_pixmaps = (Bubble_Step **)xmalloc((num_bubble_pixmaps + 1) * + st->step_pixmaps = (Bubble_Step **)xmalloc((st->num_bubble_pixmaps + 1) * sizeof(Bubble_Step *)); /* Copy them blindly into the array for sorting. */ ind = 0; tmp = list; do { - step_pixmaps[ind++] = tmp; + st->step_pixmaps[ind++] = tmp; tmp = tmp->next; } while(tmp != (Bubble_Step *)NULL); @@ -1085,49 +1121,54 @@ make_pixmap_array(Bubble_Step *list) bubble hangs around and doesn't pop immediately. It's radius and area are found by extrapolating from the largest two bubbles with pixmaps. */ - step_pixmaps[num_bubble_pixmaps] = + st->step_pixmaps[st->num_bubble_pixmaps] = (Bubble_Step *)xmalloc(sizeof(Bubble_Step)); - step_pixmaps[num_bubble_pixmaps]->radius = INT_MAX; + st->step_pixmaps[st->num_bubble_pixmaps]->radius = INT_MAX; - pixmap_sort(step_pixmaps, (num_bubble_pixmaps + 1)); + pixmap_sort(st->step_pixmaps, (st->num_bubble_pixmaps + 1)); #ifdef DEBUG - if (step_pixmaps[num_bubble_pixmaps]->radius != INT_MAX) { + if (st->step_pixmaps[st->num_bubble_pixmaps]->radius != INT_MAX) { fprintf(stderr, "pixmap_sort() screwed up make_pixmap_array\n"); } #endif /* DEBUG */ - step_pixmaps[num_bubble_pixmaps]->radius = - extrapolate(step_pixmaps[num_bubble_pixmaps-2]->radius, - step_pixmaps[num_bubble_pixmaps-1]->radius); - step_pixmaps[num_bubble_pixmaps]->area = - calc_bubble_area(step_pixmaps[num_bubble_pixmaps]->radius); + st->step_pixmaps[st->num_bubble_pixmaps]->radius = + extrapolate(st->step_pixmaps[st->num_bubble_pixmaps-2]->radius, + st->step_pixmaps[st->num_bubble_pixmaps-1]->radius); + st->step_pixmaps[st->num_bubble_pixmaps]->area = + calc_bubble_area(st, st->step_pixmaps[st->num_bubble_pixmaps]->radius); #ifdef DEBUG /* Now check for correct order */ - for (ind = 0; ind < num_bubble_pixmaps; ind++) { + for (ind = 0; ind < st->num_bubble_pixmaps; ind++) { if (prevrad > 0) { - if (step_pixmaps[ind]->radius < prevrad) { + if (st->step_pixmaps[ind]->radius < prevrad) { fprintf(stderr, "Pixmaps not in ascending order of radius\n"); exit(1); } } - prevrad = step_pixmaps[ind]->radius; + prevrad = st->step_pixmaps[ind]->radius; } #endif /* DEBUG */ + + /* Now populate the droppage values */ + for (ind = 0; ind < st->num_bubble_pixmaps; ind++) + st->step_pixmaps[ind]->droppage = MAX_DROPPAGE * ind / st->num_bubble_pixmaps; } -#ifndef NO_DEFAULT_BUBBLE static void -make_pixmap_from_default(char **pixmap_data, Bubble_Step *bl) +make_pixmap_from_default(struct state *st, + const unsigned char *png_data, + unsigned long data_size, + Bubble_Step *bl) /* Read pixmap data which has been compiled into the program and a pointer to which has been passed. 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 @@ -1142,92 +1183,43 @@ 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; - 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); +#ifdef FANCY_BUBBLES + { + int w, h; + bl->ball = image_data_to_pixmap (st->dpy, st->window, png_data, data_size, + &w, &h, &bl->shape_mask); + bl->radius = MAX(w, h) / 2; + bl->area = calc_bubble_area(st, bl->radius); } - - gcv.plane_mask = AllPlanes; - gcv.foreground = default_fg_pixel; +#endif /* FANCY_BUBBLES */ + + gcv.foreground = st->default_fg_pixel; gcv.function = GXcopy; - bl->draw_gc = XCreateGC (defdsp, defwin, GCForeground, &gcv); - XSetClipMask(defdsp, bl->draw_gc, bl->shape_mask); + bl->draw_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + XSetClipMask(st->dpy, bl->draw_gc, bl->shape_mask); - gcv.foreground = default_bg_pixel; + gcv.foreground = st->default_bg_pixel; gcv.function = GXcopy; - bl->erase_gc = XCreateGC (defdsp, defwin, GCForeground, &gcv); - XSetClipMask(defdsp, bl->erase_gc, bl->shape_mask); + bl->erase_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + XSetClipMask(st->dpy, bl->erase_gc, bl->shape_mask); } static void -default_to_pixmaps (void) +default_to_pixmaps (struct state *st) /* Make pixmaps out of default ball data stored in bubbles_default.c */ { int i; Bubble_Step *pixmap_list = (Bubble_Step *)NULL; Bubble_Step *newpix, *tmppix; - char **pixpt; - - /* Make sure pixmaps are freed when program is terminated */ - /* This is when I hit ^C */ -#ifdef SIGNAL_NONSENSE - 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 */ -#endif /* SIGNAL_NONSENSE */ + + init_default_bubbles(); for (i = 0; i < num_default_bubbles; i++) { - pixpt = default_bubbles[i]; newpix = (Bubble_Step *)xmalloc(sizeof(Bubble_Step)); - make_pixmap_from_default(pixpt, newpix); + make_pixmap_from_default(st, + default_bubbles[i].png, + default_bubbles[i].size, + newpix); /* Now add to list */ if (pixmap_list == (Bubble_Step *)NULL) { pixmap_list = newpix; @@ -1241,411 +1233,11 @@ default_to_pixmaps (void) } /* Finally construct step_pixmaps[] */ - make_pixmap_array(pixmap_list); + make_pixmap_array(st, pixmap_list); } -#endif /* NO_DEFAULT_BUBBLE */ +#endif /* FANCY_BUBBLES */ -#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); - } - -#ifdef SIGNAL_NONSENSE - /* 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 */ -#endif /* SIGNAL_NONSENSE */ - - 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; - - 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 @@ -1653,227 +1245,193 @@ namebuf */ static void -get_resources(Display *dpy, Window window) +get_resources(struct state *st) /* 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 rise; XWindowAttributes xgwa; Colormap cmap; - XGetWindowAttributes (dpy, window, &xgwa); + char *s; + XGetWindowAttributes (st->dpy, st->window, &xgwa); cmap = xgwa.colormap; - threed = get_boolean_resource("3D", "Boolean"); - quiet = get_boolean_resource("quiet", "Boolean"); - simple = get_boolean_resource("simple", "Boolean"); + st->threed = get_boolean_resource(st->dpy, "3D", "Boolean"); + st->quiet = get_boolean_resource(st->dpy, "quiet", "Boolean"); + st->simple = get_boolean_resource(st->dpy, "simple", "Boolean"); /* Forbid rendered bubbles on monochrome displays */ - if ((mono_p) && (! simple)) { - if (! quiet) + if ((mono_p) && (! st->simple)) { + if (! st->quiet) fprintf(stderr, "Rendered bubbles not supported on monochrome displays\n"); - simple = True; - } - delay = get_integer_resource("delay", "Integer"); - nodelay = get_boolean_resource("nodelay", "Boolean"); - if (nodelay) - delay = 0; - if (delay < 0) - delay = 0; - - default_fg_pixel = get_pixel_resource ("foreground", "Foreground", dpy, - cmap); - default_bg_pixel = get_pixel_resource ("background", "Background", dpy, - cmap); - - if (simple) { + st->simple = True; + } + st->delay = get_integer_resource(st->dpy, "delay", "Integer"); + + s = get_string_resource (st->dpy, "mode", "Mode"); + rise = False; + if (!s || !*s || !strcasecmp (s, "float")) + ; + else if (!strcasecmp (s, "rise")) + rise = True; + else if (!strcasecmp (s, "drop")) + st->drop = True; + else + fprintf (stderr, "%s: bogus mode: \"%s\"\n", progname, s); + + st->trails = get_boolean_resource(st->dpy, "trails", "Boolean"); + st->drop_dir = (st->drop ? 1 : -1); + if (st->drop || rise) + st->drop = 1; + + st->default_fg_pixel = get_pixel_resource (st->dpy, + cmap, "foreground", "Foreground"); + st->default_bg_pixel = get_pixel_resource (st->dpy, + cmap, "background", "Background"); + + if (st->simple) { /* This is easy */ - broken = get_boolean_resource("broken", "Boolean"); - if (broken) - if (! quiet) + st->broken = get_boolean_resource(st->dpy, "broken", "Boolean"); + if (st->broken) + if (! st->quiet) fprintf(stderr, "-broken not available in simple mode\n"); } else { -#ifndef HAVE_XPM - simple = 1; -#else - 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 */ +#ifndef FANCY_BUBBLES + st->simple = 1; +#else /* FANCY_BUBBLES */ + st->broken = get_boolean_resource(st->dpy, "broken", "Boolean"); +#endif /* FANCY_BUBBLES */ } } -static void -init_bubbles (Display *dpy, Window window) +static void * +bubbles_init (Display *dpy, Window window) { + struct state *st = (struct state *) calloc (1, sizeof(*st)); XGCValues gcv; XWindowAttributes xgwa; int i; -#ifdef BUBBLES_IO - char uncompressed[1024]; -#endif /* BUBBLES_IO */ - - defdsp = dpy; - defwin = window; - ya_rand_init(0); + st->dpy = dpy; + st->window = window; - get_resources(dpy, window); + get_resources(st); - XGetWindowAttributes (dpy, window, &xgwa); + XGetWindowAttributes (st->dpy, st->window, &xgwa); #ifdef DEBUG printf("sizof(int) on this platform is %d\n", sizeof(int)); printf("sizof(long) on this platform is %d\n", sizeof(long)); #endif /* DEBUG */ - screen_width = xgwa.width; - screen_height = xgwa.height; - screen_depth = xgwa.depth; - defcmap = xgwa.colormap; - defvisual = xgwa.visual; + st->screen_width = xgwa.width; + st->screen_height = xgwa.height; + st->screen_depth = xgwa.depth; - if (simple) { + if (st->simple) { /* These are pretty much plucked out of the air */ - bubble_min_radius = (int)(0.006*(double)(MIN(screen_width, - screen_height))); - bubble_max_radius = (int)(0.045*(double)(MIN(screen_width, - screen_height))); + st->bubble_min_radius = (int)(0.006*(double)(MIN(st->screen_width, + st->screen_height))); + st->bubble_max_radius = (int)(0.045*(double)(MIN(st->screen_width, + st->screen_height))); /* Some trivial values */ - if (bubble_min_radius < 1) - bubble_min_radius = 1; - if (bubble_max_radius <= bubble_min_radius) - bubble_max_radius = bubble_min_radius + 1; + if (st->bubble_min_radius < 1) + st->bubble_min_radius = 1; + if (st->bubble_max_radius <= st->bubble_min_radius) + st->bubble_max_radius = st->bubble_min_radius + 1; - mesh_length = (2 * bubble_max_radius) + 3; + st->mesh_length = (2 * st->bubble_max_radius) + 3; /* store area of each bubble of certain radius as number of 1/10s of a pixel area. PI is defined in */ - bubble_areas = (long *)xmalloc((bubble_max_radius + 2) * sizeof(int)); - for (i = 0; i < bubble_min_radius; i++) - bubble_areas[i] = 0; - for (i = bubble_min_radius; i <= (bubble_max_radius+1); i++) - bubble_areas[i] = calc_bubble_area(i); - - mesh_length = (2 * bubble_max_radius) + 3; + st->bubble_areas = (long *)xmalloc((st->bubble_max_radius + 2) * sizeof(int)); + for (i = 0; i < st->bubble_min_radius; i++) + st->bubble_areas[i] = 0; + for (i = st->bubble_min_radius; i <= (st->bubble_max_radius+1); i++) + st->bubble_areas[i] = calc_bubble_area(st, i); + + /* Now populate the droppage values */ + st->bubble_droppages = (int *)xmalloc((st->bubble_max_radius + 2) * sizeof(int)); + for (i = 0; i < st->bubble_min_radius; i++) + st->bubble_droppages[i] = 0; + for (i = st->bubble_min_radius; i <= (st->bubble_max_radius+1); i++) + st->bubble_droppages[i] = MAX_DROPPAGE * (i - st->bubble_min_radius) / (st->bubble_max_radius - st->bubble_min_radius); + + st->mesh_length = (2 * st->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 */ + default_to_pixmaps(st); - /* 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); - - 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 */ + st->mesh_length = (2 * st->step_pixmaps[st->num_bubble_pixmaps-1]->radius) + 3; +#endif /* FANCY_BUBBLES */ /* Am I missing something in here??? */ } - mesh_width = (screen_width / mesh_length) + 1; - mesh_height = (screen_height / mesh_length) + 1; - mesh_cells = mesh_width * mesh_height; - init_mesh(); + st->mesh_width = (st->screen_width / st->mesh_length) + 1; + st->mesh_height = (st->screen_height / st->mesh_length) + 1; + st->mesh_cells = st->mesh_width * st->mesh_height; + init_mesh(st); - calculate_adjacent_list(); + calculate_adjacent_list(st); - adjust_areas(); + adjust_areas(st); /* Graphics contexts for simple mode */ - if (simple) { - gcv.foreground = default_fg_pixel; - draw_gc = XCreateGC (dpy, window, GCForeground, &gcv); - gcv.foreground = default_bg_pixel; - erase_gc = XCreateGC (dpy, window, GCForeground, &gcv); + if (st->simple) { + gcv.foreground = st->default_fg_pixel; + st->draw_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + gcv.foreground = st->default_bg_pixel; + st->erase_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); } - XClearWindow (dpy, window); + XClearWindow (st->dpy, st->window); + +# ifndef FANCY_BUBBLES + st->simple = True; +# endif + + return st; } -static void -bubbles (Display *dpy, Window window) +static unsigned long +bubbles_draw (Display *dpy, Window window, void *closure) { - Bubble *tmp; + struct state *st = (struct state *) closure; + int i; + for (i = 0; i < 5; i++) + { + Bubble *tmp = new_bubble(st); + add_to_mesh(st, tmp); + insert_new_bubble(st, tmp); + } + return st->delay; +} - tmp = new_bubble(); - add_to_mesh(tmp); - insert_new_bubble(tmp); - XSync (dpy, True); +static void +bubbles_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ } +static Bool +bubbles_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} -void -screenhack (Display *dpy, Window window) +static void +bubbles_free (Display *dpy, Window window, void *closure) { - init_bubbles (dpy, window); - while (1) { - bubbles (dpy, window); - if (delay) - usleep(delay); - } + struct state *st = (struct state *) closure; + free (st); } +XSCREENSAVER_MODULE ("Bubbles", bubbles)