/* BubbleMon dockapp 1.32
*
* - dockapp for Window Maker/Blackbox/E/Afterstep/SawBabble
* - Code outside of bubblemon_update copyright 2000, 2001
* timecop@japan.co.jp
* - oleg dashevskii <od@iclub.nsu.ru> made changes to collect memory
* and cpu information on FreeBSD. Some major performance improvements
* and other cool hacks. Useful ideas - memscreen, load screen, etc.
* - Adrian B <midnight@bigpond.net.au> came up with the idea of load
* meter.
* - tarzeau@space.ch sent in cute duck gfx and suggestions, plus some
* code and duck motion fixes.
* - Phil Lu <wplu13@netscape.net> Dan Price <dp@rampant.org> - Solaris/SunOS
* port
* - Everything else copyright one of the guys below
*
* TODO: Anything else? Add fish?
*
* *************************************************************************
*
* Bubbling Load Monitoring Applet
* - A GNOME panel applet that displays the CPU + memory load as a
* bubbling liquid.
* Copyright (C) 1999-2000 Johan Walles
* - d92-jwa@nada.kth.se
* Copyright (C) 1999 Merlin Hughes
* - merlin@merlin.org
* - http://nitric.com/freeware/
*
* 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 of the License, 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
*
*/
#define _GNU_SOURCE
#define VERSION "1.41"
/* general includes */
#include <stdio.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
/* x11 includes */
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <X11/Xresource.h>
#include "include/master.xpm"
#include "include/bubblemon.h"
#include "include/sys_include.h"
#ifdef ENABLE_DUCK
#include "include/ducks.h"
#endif
#if defined(ENABLE_CPU)
#include "include/digits.h"
#endif
#if defined(ENABLE_MEMSCREEN)
#include "include/load_screen.h"
#include "include/mem_screen.h"
#endif
/* #define DEBUG_DUCK 1 */
/* local prototypes *INDENT-OFF* */
static void bubblemon_setup_samples(void);
static void bubblemon_setup_colors(void);
static void bubblemon_allocate_buffers(void);
static void bubblemon_update(int proximity);
static void make_new_bubblemon_dockapp(void);
static void get_memory_load_percentage(void);
static void bubblemon_session_defaults(void);
static int get_screen_selection(void);
#if defined(ENABLE_CPU) || defined(ENABLE_MEMSCREEN)
/* draw functions for load average / memory screens */
static void draw_pixel(unsigned int x, unsigned int y, unsigned char *buf,
unsigned char *c);
static void draw_history(int num, int size, unsigned int *history,
unsigned char *buf);
static void draw_digit(int srcx, int srcy, int destx, int desty);
static void draw_string(char *string, int x, int y, int color);
static void draw_cpudigit(const int what, const int where,
unsigned char *kit);
static void render_secondary(void);
static void realtime_alpha_blend_of_cpu_usage(int cpu, int proximity);
static void roll_membuffer(void);
static void roll_history(void);
#endif
#ifdef ENABLE_DUCK
static int animate_correctly(void);
static void duck_set(int x, int y, int nr, int rev, int upsidedown);
static void duck_swimmer(int posy);
#endif
#ifdef __FreeBSD__
extern int init_stuff(); /* defined in sys_freebsd.c */
#endif
/* local prototypes end *INDENT-ON* */
/* global variables */
BubbleMonData bm;
/* compiled-in options string */
char options[1024];
#ifdef ENABLE_DUCK
int duck_enabled = 1;
#ifdef UPSIDE_DOWN_DUCK
int upside_down_duck_enabled = 1;
#endif /* UPSIDE_DOWN_DUCK */
#endif /* ENABLE_DUCK */
#ifdef ENABLE_CPU
int cpu_enabled = 1;
#endif /* ENABLE_CPU */
#ifdef ENABLE_MEMSCREEN
int memscreen_enabled = 1;
int memscreen_megabytes = 0;
#endif /* ENABLE_MEMSCREEN */
#define INT_VAL 0
#define DOUBLE_VAL 1
#define COLOR_VAL 2
static void bubblemon_session_defaults(void)
{
/* handy way to collect all this stuff in one place */
typedef struct {
char *name; /* name as appears in Xdefaults */
int type; /* int, double, or color, see up */
void *var; /* pointer to value - only handles INT atm */
} xrm_vars;
/* XResource stuff */
char name[BUFSIZ] = "", *ptr;
XrmDatabase db = NULL;
XrmValue val;
char *type;
int i;
xrm_vars tab[] = {
{"bubblemon.maxbubbles", INT_VAL, &bm.maxbubbles},
{"bubblemon.air_noswap", COLOR_VAL, &bm.air_noswap},
{"bubblemon.air_maxswap", COLOR_VAL, &bm.air_maxswap},
{"bubblemon.liquid_noswap", COLOR_VAL, &bm.liquid_noswap},
{"bubblemon.liquid_maxswap", COLOR_VAL, &bm.liquid_maxswap},
{"bubblemon.ripples", DOUBLE_VAL, &bm.ripples},
{"bubblemon.gravity", DOUBLE_VAL, &bm.gravity},
{"bubblemon.volatility", DOUBLE_VAL, &bm.volatility},
{"bubblemon.viscosity", DOUBLE_VAL, &bm.viscosity},
{"bubblemon.speed_limit", DOUBLE_VAL, &bm.speed_limit}
};
/* number of CPU load samples */
bm.samples = 16;
/* default colors. changeable from Xdefaults */
bm.air_noswap = 0x2299ff;
bm.liquid_noswap = 0x0055ff;
bm.air_maxswap = 0xff0000;
bm.liquid_maxswap = 0xaa0000;
/* default bubble engine parameters. Changeable from Xdefaults */
bm.maxbubbles = 100;
bm.ripples = 0.2;
bm.gravity = 0.01;
bm.volatility = 1.0;
bm.viscosity = 0.98;
bm.speed_limit = 1.0;
db = NULL;
XrmInitialize();
/* get users's local Xdefaults */
if ((ptr = getenv("HOME")) != NULL) {
snprintf(name, sizeof(name), "%s/.Xdefaults", ptr);
}
/* get the database and parse resources if we have some */
if ((db = XrmGetFileDatabase(name)) != NULL) {
for (i = 0; i < (sizeof(tab) / sizeof(tab[0])); i++) {
if (XrmGetResource(db, tab[i].name, tab[i].name, &type, &val)) {
if (val.size > 0) /* no empty strings and shit like that */
switch (tab[i].type) {
case INT_VAL:
*(int *) tab[i].var = atoi(val.addr);
break;
case DOUBLE_VAL:
*(double *) tab[i].var = atof(val.addr);
break;
case COLOR_VAL:
sscanf(val.addr, "#%x", (int *) tab[i].var);
break;
default:
/* WTF? */
break;
}
}
}
}
#define RANGE_CHECK(x, min, max, def) \
if ((x) > (max) || (x) < (min)) { \
fprintf(stderr, #x" value is out of range. Using default value ("#def")\n"); \
(x) = (def); \
}
/* range validation. 3l33t hackerz NO PASARAN */
RANGE_CHECK(bm.air_noswap, 0, 0xffffff, 0x2299ff);
RANGE_CHECK(bm.liquid_noswap, 0, 0xffffff, 0x0055ff);
RANGE_CHECK(bm.air_maxswap, 0, 0xffffff, 0xff0000);
RANGE_CHECK(bm.liquid_maxswap, 0, 0xffffff, 0xaa0000);
RANGE_CHECK(bm.maxbubbles, 10, 200, 100);
RANGE_CHECK(bm.ripples, 0, 1, 0.2);
RANGE_CHECK(bm.gravity, 0.005, 0.5, 0.01);
RANGE_CHECK(bm.volatility, 0.1, 2, 1.0);
RANGE_CHECK(bm.viscosity, 0, 1.0, 0.98);
RANGE_CHECK(bm.speed_limit, 0.5, 2, 1.0);
#undef RANGE_CHECK
/* convert doubles into integer representation */
bm.ripples_int = MAKE_INTEGER(bm.ripples);
bm.gravity_int = MAKE_INTEGER(bm.gravity);
bm.volatility_int = MAKE_INTEGER(bm.volatility);
bm.viscosity_int = MAKE_INTEGER(bm.viscosity);
bm.speed_limit_int = MAKE_INTEGER(bm.speed_limit);
}
#undef INT_VAL
#undef DOUBLE_VAL
#undef COLOR_VAL
/* *INDENT-OFF* */
static void print_usage(void)
{
printf( "BubbleMon version "VERSION", features: %s\n"
"Usage: bubblemon [switches] [program_1] [program_2]\n\n"
"Disable compiled-in features\n"
#ifdef ENABLE_DUCK
" -d\tdisable swimming duck\n"
#ifdef UPSIDE_DOWN_DUCK
" -u\tdisable upside-down duck\n"
#endif /* UPSIDE_DOWN_DUCK */
#endif /* ENABLE_DUCK */
#ifdef ENABLE_CPU
" -c\tdisable CPU meter\n"
#endif /* ENABLE_CPU */
#ifdef ENABLE_MEMSCREEN
" -m\tdisable memory screen\n"
#endif /* ENABLE_MEMSCREEN */
"\nGeneral options\n"
#ifdef ENABLE_MEMSCREEN
" -p\tuse alternative color scheme in memory info screen\n"
" -k\tdisplay memory and swap statistics in megabytes\n"
#endif
" -h\tdisplay this help\n",
options /* this is the global static string with compiled features */
);
}
/* *INDENT-ON* */
int main(int argc, char **argv)
{
char execute[256];
int proximity = 0;
int ch;
#ifdef FPS
int f, o;
time_t y;
#endif
#ifdef PRO
int cnt = 25000;
#endif
GdkEvent *event;
#ifdef FPS
o = f = y = 0;
#endif
/* initialize GDK */
if (!gdk_init_check(&argc, &argv)) {
fprintf(stderr,
"GDK init failed, bye bye. Check \"DISPLAY\" variable.\n");
exit(-1);
}
gdk_rgb_init();
/* dynamically generate getopt string depending on compile options
* we are going to borrow 256 char string from exec function, and
* also build up the "compiled features" string */
memset(execute, 0, 256);
strcat(execute, "h"); /* help, always in */
#ifdef ENABLE_DUCK
strcat(options, "DUCK ");
strcat(execute, "d");
#ifdef UPSIDE_DOWN_DUCK
strcat(options, "INVERT ");
strcat(execute, "u");
#endif /* UPSIDE_DOWN_DUCK */
#endif /* ENABLE_DUCK */
#ifdef ENABLE_CPU
strcat(options, "CPU ");
strcat(execute, "c");
#endif /* ENABLE_CPU */
#ifdef ENABLE_MEMSCREEN
strcat(options, "MEMSCREEN ");
strcat(execute, "pmk");
#endif /* ENABLE_MEMSCREEN */
/* command line options */
while ((ch = getopt(argc, argv, execute)) != -1) {
switch (ch) {
#ifdef ENABLE_DUCK
case 'd':
duck_enabled = 0;
break;
#ifdef UPSIDE_DOWN_DUCK
case 'u':
upside_down_duck_enabled = 0;
break;
#endif /* UPSIDE_DOWN_DUCK */
#endif /* ENABLE_DUCK */
#ifdef ENABLE_CPU
case 'c':
cpu_enabled = 0;
break;
#endif /* ENABLE_CPU */
#ifdef ENABLE_MEMSCREEN
case 'm':
memscreen_enabled = 0;
break;
case 'p':
{
/* no sense having -p if memscreen isn't compiled in, right?
* what we are going to do is to change the colors as follows:
*
* (48,140,240) replaced with (158,196,237) - more pale blue
* (237,23,23) replaced with (0,255,233) */
unsigned char *p = mem_screen;
while (p < mem_screen + sizeof(mem_screen))
if (*p == 48) { /* hopefully no other colors beginning with 48 */
*p++ = 158;
*p++ = 196;
*p++ = 237;
} else if (*p == 237) { /* hopefully no other colors beginning with 237 */
*p++ = 0;
*p++ = 255;
*p++ = 233;
} else
p += 3;
p = load_screen;
while (p < load_screen + sizeof(load_screen))
if (*p == 48) { /* hopefully no other colors beginning with 48 */
*p++ = 158;
*p++ = 196;
*p++ = 237;
} else
p += 3;
}
break;
case 'k':
memscreen_megabytes = 1;
break;
#endif /* ENABLE_MEMSCREEN */
default:
print_usage();
exit(-1);
break;
}
}
argc -= optind;
argv += optind;
/* zero data structure */
memset(&bm, 0, sizeof(bm));
#ifdef __FreeBSD__
if (init_stuff())
exit(-1);
#endif
/* set default things, from Xresources or compiled-in defaults */
bubblemon_session_defaults();
/* create dockapp window. creates windows, allocates memory, etc */
make_new_bubblemon_dockapp();
#ifdef PRO
while (cnt--) {
#else
while (1) {
#endif
while (gdk_events_pending()) {
event = gdk_event_get();
if (event) {
switch (event->type) {
case GDK_DESTROY:
gdk_exit(0);
exit(0);
break;
case GDK_BUTTON_PRESS:
if (event->button.button == 3) {
bm.picture_lock = 1;
break;
}
if (event->button.button <= argc) {
snprintf(execute, 250, "%s &",
argv[event->button.button - 1]);
system(execute);
}
break;
#if defined(ENABLE_CPU) || defined(ENABLE_MEMSCREEN)
case GDK_ENTER_NOTIFY:
/* mouse in: make it darker, and eventually bring up
* meminfo */
proximity = 1;
bm.screen_type = get_screen_selection();
bm.picture_lock = 0;
break;
case GDK_LEAVE_NOTIFY:
/* mouse out: back to light */
proximity = 0;
break;
#endif /* ENABLE_CPU || ENABLE_MEMSCREEN */
default:
break;
}
}
}
#ifndef PRO
usleep(15000);
#else
/* amazingly enough just calling this function takes insane
* amount of time.
usleep(0); */
#endif
/* get system statistics */
get_memory_load_percentage();
/* update main rgb buffer: bm.rgb_buf */
bubblemon_update(proximity);
/* *INDENT-OFF* */
#ifdef FPS
/* render frames per second on bottom-right corner :)
* This is GCC-specific (functions inside functions)
* and very unoptimized. this is obfuscated 'cause its ugly */
f++;{int b;void q(int sx,int sy,int dx,int dy){int i,j;char *from,*to;
for(j=0;j<8;j++){from=mem_screen+56*3*(sy+j)+sx*3;to=bm.rgb_buf+56*3*
(dy+j)+dx*3;i=12;while(i--)*to++=*from++;}}b=o;if(b>=100){q((b/100)*4,
60,43,46);b=b%100;}q((b/10)*4,60,47,46);q((b%10)*4,60,51,46);}if(time(
NULL)!=y){o=f;f=0;y=time(NULL);}
#endif
/* *INDENT-ON* */
/* actually draw the screen */
#ifndef BLACKBOX
gdk_draw_rgb_image(bm.win, bm.gc, 4, 4, 56, 56,
GDK_RGB_DITHER_NONE, bm.rgb_buf, 56 * 3);
#endif
gdk_draw_rgb_image(bm.iconwin, bm.gc, 4, 4, 56, 56,
GDK_RGB_DITHER_NONE, bm.rgb_buf, 56 * 3);
#ifdef ENABLE_MEMSCREEN
/* update graph histories */
if (memscreen_enabled)
roll_history();
#endif /* ENABLE_MEMSCREEN */
}
return 0;
} /* main */
/*
* This determines if the left or right shift keys are depressed.
*/
static int get_screen_selection(void)
{
static KeyCode lshift_code, rshift_code;
static int first_time = 1;
char keys[32];
if (first_time) {
first_time = 0;
lshift_code = XKeysymToKeycode(GDK_WINDOW_XDISPLAY(bm.win),
XStringToKeysym("Shift_L"));
rshift_code = XKeysymToKeycode(GDK_WINDOW_XDISPLAY(bm.win),
XStringToKeysym("Shift_R"));
}
XQueryKeymap(GDK_WINDOW_XDISPLAY(bm.win), keys);
#if 0
if (0) { /* debug */
int i = 0;
printf("lshift_code = 0x%x (index = %d, bit = %d\n", lshift_code,
lshift_code >> 3, lshift_code % 8);
printf("rshift_code = 0x%x (index = %d, bit = %d\n", rshift_code,
rshift_code >> 3, rshift_code % 8);
for (i = 0; i < (sizeof(keys) / sizeof(keys[0])); i++) {
if (0 == (i % 8)) {
printf("\n%2d:", i);
}
printf(" %2d", keys[i]);
}
printf("\n");
}
#endif
if ((keys[lshift_code >> 3] == (1 << (lshift_code % 8))) ||
(keys[rshift_code >> 3] == (1 << (rshift_code % 8)))) {
return 0;
} else {
return 1;
}
}
/* This is the function that actually creates the display widgets */
static void make_new_bubblemon_dockapp(void)
{
#define MASK GDK_BUTTON_PRESS_MASK | \
GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK
GdkWindowAttr attr;
GdkWindowAttr attri;
Window win;
Window iconwin;
XSizeHints sizehints;
XWMHints wmhints;
attr.width = 64;
attr.height = 64;
attr.title = "bubblemon";
attr.event_mask = MASK;
attr.wclass = GDK_INPUT_OUTPUT;
attr.visual = gdk_visual_get_system();
attr.colormap = gdk_colormap_get_system();
attr.wmclass_name = "bubblemon";
attr.wmclass_class = "bubblemon";
attr.window_type = GDK_WINDOW_TOPLEVEL;
sizehints.flags = USSize;
sizehints.width = 64;
sizehints.height = 64;
bm.win = gdk_window_new(NULL, &attr,
GDK_WA_TITLE | GDK_WA_WMCLASS |
GDK_WA_VISUAL | GDK_WA_COLORMAP);
if (!bm.win)
fprintf(stderr, "Cannot make toplevel window\n");
attri.width = 64;
attri.height = 64;
attri.title = "bubblemon";
attri.event_mask = MASK;
attri.wclass = GDK_INPUT_OUTPUT;
attri.visual = gdk_visual_get_system();
attri.colormap = gdk_colormap_get_system();
attri.wmclass_name = "bubblemon";
attri.wmclass_class = "bubblemon";
attri.window_type = GDK_WINDOW_TOPLEVEL;
bm.iconwin = gdk_window_new(bm.win, &attri,
GDK_WA_TITLE | GDK_WA_WMCLASS);
if (!bm.iconwin)
fprintf(stderr, "Cannot make icon window\n");
win = GDK_WINDOW_XWINDOW(bm.win);
iconwin = GDK_WINDOW_XWINDOW(bm.iconwin);
XSetWMNormalHints(GDK_WINDOW_XDISPLAY(bm.win), win, &sizehints);
wmhints.initial_state = WithdrawnState;
wmhints.icon_window = iconwin;
wmhints.icon_x = 0;
wmhints.icon_y = 0;
wmhints.window_group = win;
wmhints.flags =
StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
XSetWMHints(GDK_WINDOW_XDISPLAY(bm.win), win, &wmhints);
bm.gc = gdk_gc_new(bm.win);
bm.pixmap =
gdk_pixmap_create_from_xpm_d(bm.win, &(bm.mask), NULL, master_xpm);
gdk_window_shape_combine_mask(bm.win, bm.mask, 0, 0);
gdk_window_shape_combine_mask(bm.iconwin, bm.mask, 0, 0);
gdk_window_set_back_pixmap(bm.win, bm.pixmap, False);
gdk_window_set_back_pixmap(bm.iconwin, bm.pixmap, False);
gdk_window_show(bm.win);
#ifdef KDE_DOCKAPP
/* makes the dockapp visible inside KDE wm */
gdk_window_show(bm.iconwin);
#endif
/* We begin with zero bubbles */
bm.n_bubbles = 0;
/* Allocate memory for calculations */
bubblemon_allocate_buffers();
bubblemon_setup_samples();
bubblemon_setup_colors();
#undef MASK
} /* make_new_bubblemon_dockapp */
/*
* This function, bubblemon_update, gets the CPU usage and updates
* the bubble array and main rgb buffer.
*/
static void bubblemon_update(int proximity)
{
Bubble *bubbles = bm.bubbles;
unsigned int i, loadPercentage, *col, x, y;
unsigned char *ptr, *buf, *buf_ptr;
unsigned int aircolor, watercolor, aliascolor;
unsigned int waterlevels_goal;
/*int current_waterlevel_goal; */
/* These values are for keeping track of where we have to start
drawing water. */
unsigned int waterlevel_min, waterlevel_max;
unsigned int real_waterlevel_min, real_waterlevel_max;
/* These values are for keeping track how deep the duck is inside water */
unsigned int action_min = 56;
static unsigned int last_action_min = 0;
/* Find out the CPU load */
loadPercentage = system_cpu();
#ifdef ENABLE_MEMSCREEN
/* get loadavg */
if (memscreen_enabled)
system_loadavg();
#endif /* ENABLE_MEMSCREEN */
/*
The buf is made up of ints (0-(NUM_COLORS-1)), each pointing out
an entry in the color table. A pixel in the buf is accessed
using the formula buf[row * w + column].
*/
/* y coordinates are counted from here multiplied by 256 */
/* to get actual screen coordinate, divide by 256 */
buf = bm.bubblebuf;
col = bm.colors;
waterlevel_max = 0;
waterlevel_min = MAKEY(56);
/* Move the water level with the current memory usage. */
waterlevels_goal = MAKEY(56) - ((bm.mem_percent * MAKEY(56)) / 100);
/* Guard against boundary errors */
waterlevels_goal -= (1 << (POWER2 - 1));
bm.waterlevels[0] = waterlevels_goal;
bm.waterlevels[55] = waterlevels_goal;
for (x = 1; x < 55; x++) {
/* Accelerate the current waterlevel towards its correct value */
bm.waterlevels_dy[x] +=
(((bm.waterlevels[x - 1] + bm.waterlevels[x + 1] -
2 * bm.waterlevels[x]) * bm.volatility_int) >> (POWER2 +
1));
bm.waterlevels_dy[x] *= bm.viscosity_int;
bm.waterlevels_dy[x] >>= POWER2;
if (bm.waterlevels_dy[x] > bm.speed_limit_int)
bm.waterlevels_dy[x] = bm.speed_limit_int;
else if (bm.waterlevels_dy[x] < -bm.speed_limit_int)
bm.waterlevels_dy[x] = -bm.speed_limit_int;
}
for (x = 1; x < 55; x++) {
/* Move the current water level */
bm.waterlevels[x] = bm.waterlevels[x] + bm.waterlevels_dy[x];
if (bm.waterlevels[x] > MAKEY(56)) {
/* Stop the wave if it hits the floor... */
bm.waterlevels[x] = MAKEY(56);
bm.waterlevels_dy[x] = 0;
} else if (bm.waterlevels[x] < 0) {
/* ... or the ceiling. */
bm.waterlevels[x] = 0;
bm.waterlevels_dy[x] = 0;
}
/* Keep track of the highest and lowest water levels */
if (bm.waterlevels[x] > waterlevel_max)
waterlevel_max = bm.waterlevels[x];
if (bm.waterlevels[x] < waterlevel_min)
waterlevel_min = bm.waterlevels[x];
}
real_waterlevel_min = REALY(waterlevel_min);
real_waterlevel_max = REALY(waterlevel_max);
if (action_min > real_waterlevel_min)
action_min = real_waterlevel_min;
/*
Vary the colors of air and water with how many
percent of the available swap space that is in use.
32 = (99_numcolors / 3) - 1
*/
watercolor = ((32 * bm.swap_percent) / 100) * 3;
aliascolor = watercolor + 1;
aircolor = watercolor + 2;
/*
Draw the air-and-water background
The waterlevel_max is the HIGHEST VALUE for the water level, which is
actually the LOWEST VISUAL POINT of the water. Confusing enough?
So we want to draw from top to bottom:
Just air from (y == 0) to (y <= waterlevel_min)
Mixed air and water from (y == waterlevel_min) to (y <= waterlevel_max)
Just water from (y == waterlevel_max) to (y <= h)
Three loops is more code than one, but should be faster (fewer comparisons)
*/
/* Air only */
memset(buf, aircolor, real_waterlevel_min * 56);
/* Air and water */
for (x = 0; x < 56; x++) {
/* Air... */
for (y = real_waterlevel_min;
(signed) y < REALY(bm.waterlevels[x]); y++)
buf[y * 56 + x] = aircolor;
/* ... and water */
for (; y < real_waterlevel_max; y++)
buf[y * 56 + x] = watercolor;
}
/* Water only */
memset(buf + real_waterlevel_max * 56, watercolor,
(56 - real_waterlevel_max) * 56);
/*
Here comes the bubble magic. Pixels are drawn by setting values in
buf to 0-NUM_COLORS.
*/
/* Create a new bubble if the planets are correctly aligned... */
if ((bm.n_bubbles < bm.maxbubbles)
&& ((rand() % 101) <= loadPercentage)) {
/* We don't allow bubbles on the edges 'cause we'd have to clip them */
bubbles[bm.n_bubbles].x = (rand() % 54) + 1;
bubbles[bm.n_bubbles].y = MAKEY(56) - 256;
bubbles[bm.n_bubbles].dy = 0;
#ifdef DEBUG_DUCK
fprintf (stderr, "new bubble: bubbles[bm.n_bubbles].x = %i\n",
bubbles[bm.n_bubbles].x);
#endif
if (bm.ripples_int != 0) {
/* Raise the water level above where the bubble is created */
if (bubbles[bm.n_bubbles].x > 2)
bm.waterlevels[bubbles[bm.n_bubbles].x - 2] -=
bm.ripples_int;
bm.waterlevels[bubbles[bm.n_bubbles].x - 1] -= bm.ripples_int;
bm.waterlevels[bubbles[bm.n_bubbles].x] -= bm.ripples_int;
bm.waterlevels[bubbles[bm.n_bubbles].x + 1] -= bm.ripples_int;
if (bubbles[bm.n_bubbles].x < 53)
bm.waterlevels[bubbles[bm.n_bubbles].x + 2] -=
bm.ripples_int;
}
/* Count the new bubble */
bm.n_bubbles++;
}
/* Update and draw the bubbles */
for (i = 0; i < bm.n_bubbles; i++) {
/* Accelerate the bubble */
bubbles[i].dy -= bm.gravity_int;
/* Move the bubble vertically */
bubbles[i].y += bubbles[i].dy;
/* is the bubble grossly out of bounds? */
if (bubbles[i].x < 1 || bubbles[i].x > 54 ||
bubbles[i].y > MAKEY(56)) {
#ifdef DEBUG_DUCK
fprintf (stderr, "bubble out of bounds "
"bubbles[%i].x=%i, bubbles[%i].y=%i\n",
i, bubbles[i].x, i, bubbles[i].y);
#endif
/* Yes; nuke it */
bubbles[i].x = bubbles[bm.n_bubbles - 1].x;
bubbles[i].y = bubbles[bm.n_bubbles - 1].y;
bubbles[i].dy = bubbles[bm.n_bubbles - 1].dy;
bm.n_bubbles--;
/*
We must check the previously last bubble, which is
now the current bubble, also.
*/
i--;
continue;
}
/* Did we lose it? */
if (bubbles[i].y < bm.waterlevels[bubbles[i].x]) {
if (bm.ripples_int != 0) {
/* Lower the water level around where the bubble is
about to vanish */
bm.waterlevels[bubbles[i].x - 1] += bm.ripples_int;
bm.waterlevels[bubbles[i].x] += 3 * bm.ripples_int;
bm.waterlevels[bubbles[i].x + 1] += bm.ripples_int;
}
/* Yes; nuke it */
bubbles[i].x = bubbles[bm.n_bubbles - 1].x;
bubbles[i].y = bubbles[bm.n_bubbles - 1].y;
bubbles[i].dy = bubbles[bm.n_bubbles - 1].dy;
bm.n_bubbles--;
/*
We must check the previously last bubble, which is
now the current bubble, also.
*/
i--;
continue;
}
/* Draw the bubble */
x = bubbles[i].x;
y = bubbles[i].y;
/*
Clipping is not necessary for x, but it *is* for y.
To prevent ugliness, we draw aliascolor only on top of
watercolor, and aircolor on top of aliascolor.
*/
/* Top row */
buf_ptr = &(buf[(((REALY(y) - 1) * 56) + 56) + x - 1]);
if (y > bm.waterlevels[x]) {
if (*buf_ptr != aircolor) {
(*buf_ptr)++;
}
buf_ptr++;
*buf_ptr = aircolor;
buf_ptr++;
if (*buf_ptr != aircolor) {
(*buf_ptr)++;
}
buf_ptr += 54;
} else {
buf_ptr += 56;
}
/* Middle row - no clipping necessary */
*buf_ptr = aircolor;
buf_ptr++;
*buf_ptr = aircolor;
buf_ptr++;
*buf_ptr = aircolor;
buf_ptr += 54;
/* Bottom row */
if (y < (MAKEY(56) - 256)) {
if (*buf_ptr != aircolor) {
(*buf_ptr)++;
}
buf_ptr++;
*buf_ptr = aircolor;
buf_ptr++;
if (*buf_ptr != aircolor) {
(*buf_ptr)++;
}
}
}
/* Drawing magic resides below this point */
ptr = bm.rgb_buf;
buf_ptr = buf;
i = 56 * 56;
while (i--) {
unsigned char *rgb = (unsigned char *) &col[*buf_ptr++];
#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || (defined(_LITTLE_ENDIAN) && !defined(__FreeBSD__)) || (defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && (BYTE_ORDER == LITTLE_ENDIAN))
*ptr++ = rgb[2];
*ptr++ = rgb[1];
*ptr++ = rgb[0];
#else /* big-endian. */
*ptr++ = rgb[1];
*ptr++ = rgb[2];
*ptr++ = rgb[3];
#endif
}
#ifdef ENABLE_DUCK
if (duck_enabled) {
duck_swimmer((last_action_min <
action_min) ? last_action_min - 14 : action_min -
14);
}
#endif
/* damn, thats ugly. Of course, the first solution that comes to mind
* about this isn't the right one :) */
#if defined(ENABLE_CPU) && defined(ENABLE_MEMSCREEN)
if (cpu_enabled || memscreen_enabled) {
realtime_alpha_blend_of_cpu_usage(loadPercentage, proximity);
}
#endif
#if defined(ENABLE_CPU) && !defined(ENABLE_MEMSCREEN)
if (cpu_enabled) {
realtime_alpha_blend_of_cpu_usage(loadPercentage, proximity);
}
#endif
#if !defined(ENABLE_CPU) && defined(ENABLE_MEMSCREEN)
if (memscreen_enabled) {
realtime_alpha_blend_of_cpu_usage(loadPercentage, proximity);
}
#endif
/* Remember where we have been poking around this round */
last_action_min = action_min;
} /* bubblemon_update */
#ifdef ENABLE_MEMSCREEN
/* draws 4x8 digits for the memory/swap panel */
static void draw_digit(int srcx, int srcy, int destx, int desty)
{
int i, j;
char *from, *to;
for (j = 0; j < 8; j++) {
from = mem_screen + 56 * 3 * (srcy + j) + srcx * 3;
to = bm.mem_buf + 56 * 3 * (desty + j) + destx * 3;
i = 12;
while (i--)
*to++ = *from++;
}
}
/* draws a string using previous function. non-digits and non-K/M = space */
static void draw_string(char *string, int x, int y, int color)
{
unsigned char c;
while ((c = *string++)) {
if (c == 'K') {
draw_digit(40, (color) ? 69 : 60, x, y);
} else if (c == 'M') {
draw_digit(44, (color) ? 69 : 60, x, y);
} else if (c == ' ') {
draw_digit(50, 60, x, y); /* blank space */
} else {
c -= '0';
draw_digit(c * 4, (color) ? 69 : 60, x, y);
}
x += 4;
}
}
static void draw_pixel(unsigned int x, unsigned int y, unsigned char *buf,
unsigned char *c)
{
unsigned char *ptr;
ptr = buf + y * 56 * 3 + x * 3 + 6; /* +6 = x + 2 */
*ptr++ = *c++;
*ptr++ = *c++;
*ptr++ = *c++;
}
/* draw graph num x size, data taken from history, into rgb buffer buf.
* this is called not very often: only 1 time out of 250 */
static void draw_history(int num, int size, unsigned int *history,
unsigned char *buf)
{
int pixels_per_byte;
int j, k;
int *p;
int d;
pixels_per_byte = 100;
p = history;
for (j = 0; j < num; j++) {
if (p[0] > pixels_per_byte)
pixels_per_byte += 100;
p++;
}
p = history;
for (k = 0; k < num; k++) {
d = (1.0 * p[0] / pixels_per_byte) * size;
for (j = 0; j < size; j++) {
if (j < d - 2)
draw_pixel(k, size - j - 1, buf, "\x00\x7d\x71");
else if (j < d)
draw_pixel(k, size - j - 1, buf, "\x20\xb6\xae");
}
p++;
}
for (j = pixels_per_byte - 100; j > 0; j -= 100) {
for (k = 0; k < num; k++) {
d = ((float) size / pixels_per_byte) * j;
draw_pixel(k, size - d - 1, buf, "\x71\xe3\x71");
}
}
}
/* refreshes memory/swap screen */
static void render_secondary(void)
{
char percent[4];
char number[8];
int i;
/* mem: 2, 24
* mem %: 38, 24
* swap: 2, 43
* 38, 43
* digits: 0, 60 and 0, 69 */
/* make a clean buffer with blank spaces. */
memcpy(bm.mem_buf, bm.screen_type ? load_screen : mem_screen,
56 * 56 * 3);
if (bm.screen_type) {
for (i = 0; i < 3; i++) {
sprintf(number, "%2d", bm.loadavg[i].i);
draw_string(number, 19 * i, 8, 0);
sprintf(number, "%02d", bm.loadavg[i].f);
draw_string(number, 19 * i + 10, 8, 0);
}
/* copy history graph from previous rollover */
memcpy(bm.mem_buf + 19 * 56 * 3, bm.his_bufb, 56 * 33 * 3);
} else {
/* draw memory */
if (memscreen_megabytes)
snprintf(number, 8, "%6lluM", bm.mem_used >> 20);
else
snprintf(number, 8, "%6lluK", bm.mem_used >> 10);
snprintf(percent, 4, "%03d", bm.mem_percent);
draw_string(number, 2, 1, (bm.mem_percent > 90) ? 1 : 0);
draw_string(percent, 38, 1, (bm.mem_percent > 90) ? 1 : 0);
/* draw swap */
if (memscreen_megabytes)
snprintf(number, 8, "%6lluM", bm.swap_used >> 20);
else
snprintf(number, 8, "%6lluK", bm.swap_used >> 10);
snprintf(percent, 4, "%03d", bm.swap_percent);
draw_string(number, 2, 10, (bm.swap_percent > 90) ? 1 : 0);
draw_string(percent, 38, 10, (bm.swap_percent > 90) ? 1 : 0);
/* copy history graph from previous rollover */
memcpy(bm.mem_buf + 21 * 56 * 3, bm.his_bufa, 56 * 31 * 3);
}
}
static void roll_membuffer(void)
{
static int delay;
if (++delay < 30)
return;
delay = 0;
render_secondary();
}
static void roll_history(void)
{
unsigned int yep, j;
static int update, doit;
if (doit-- <= 0) {
doit = ROLLVALUE;
if (update-- <= 0) {
/* roll history buffers, averaging last 5 samples */
if (bm.history[52])
bm.history[52] /= bm.hisadd;
if (bm.memhist[52])
bm.memhist[52] /= bm.memadd;
for (j = 1; j < 53; j++) {
bm.history[j - 1] = bm.history[j];
bm.memhist[j - 1] = bm.memhist[j];
}
bm.history[52] = 0;
bm.hisadd = 0;
bm.memhist[52] = 0;
bm.memadd = 0;
/* refresh backgrounds */
memcpy(bm.his_bufa, mem_screen + 21 * 56 * 3, 31 * 56 * 3);
memcpy(bm.his_bufb, load_screen + 19 * 56 * 3, 33 * 56 * 3);
/* render memory graph */
draw_history(52, 31, bm.memhist, bm.his_bufa);
/* render load average graph */
draw_history(52, 33, bm.history, bm.his_bufb);
/* reset counter */
update = 5;
}
/* do load average history update */
yep = bm.loadavg[0].f + (bm.loadavg[0].i * 100);
bm.history[52] += yep;
bm.hisadd++;
/* do memory history update */
yep = bm.mem_percent;
bm.memhist[52] += yep;
bm.memadd++;
}
}
#endif /* ENABLE_MEMSCREEN */
#ifdef ENABLE_CPU
/* draws digits for the CPU meter. This function is very specific
* to the meter. Arguments it takes are not what they seem initially */
static void draw_cpudigit(const int what, const int where,
unsigned char *kit)
{
unsigned int len, y;
unsigned char *to, *from;
for (y = 0; y < 9; y++) {
len = 21;
to = kit + y * 75 + where;
from = digits + y * 285 + what;
while (len--)
*to++ = *from++;
}
}
#endif /* ENABLE_CPU */
#if defined(ENABLE_CPU) || defined(ENABLE_MEMSCREEN)
static void realtime_alpha_blend_of_cpu_usage(int cpu, int proximity)
{
/* where is the text going to be (now, bottom-center) */
#define POSX 16
#define POSY 46
int bob;
/* memory window */
static int blend = MAXBLEND;
#ifdef ENABLE_MEMSCREEN
static int memblend = 256;
static int showmem = 0;
#endif /* ENABLE_MEMSCREEN */
#ifdef ENABLE_CPU
static int yoh;
static int avg;
int hibyte, y, pos;
/* CPU load buffer */
static unsigned char kit[25 * 3 * 9 + 1];
unsigned char *kitptr;
/* the plan is simple. we don't want to redraw the digits every update
* because that doesn't look so good. so we average it, and draw only
* once every 10 updates. We alpha blend the static buffer so we still
* get cool transparency effects. */
avg += cpu;
while (++yoh > 10) {
cpu = avg / 10;
avg ^= avg; /* zero. Haha, I guess these are not */
yoh ^= yoh; /* register vars, optimizer just zeros them */
hibyte = cpu / 10; /* but it's cool to know it understands xor a, a */
if (hibyte == 10) {
draw_cpudigit(18, 0, kit);
draw_cpudigit(0, 18, kit);
draw_cpudigit(0, 36, kit);
} else {
draw_cpudigit(216, 0, kit);
draw_cpudigit(hibyte * 18, 18, kit);
draw_cpudigit((cpu % 10) * 18, 36, kit);
}
/* percent sign is always there */
draw_cpudigit(180, 54, kit);
}
#endif /* ENABLE_CPU */
/* sexy fade effect */
if (proximity) {
blend -= 4;
if (blend < MINBLEND) {
blend = MINBLEND;
#ifdef ENABLE_MEMSCREEN
if (memscreen_enabled) {
if (!showmem) {
/* first time here, update memory stats */
render_secondary();
}
showmem = 1;
if (!bm.picture_lock)
memblend -= 6;
if (memblend < 40) {
roll_membuffer();
memblend = 40;
}
}
#endif /* ENABLE_MEMSCREEN */
}
} else {
blend += 4;
#ifdef ENABLE_MEMSCREEN
if (bm.picture_lock)
roll_membuffer();
if (memscreen_enabled && !bm.picture_lock)
memblend += 10;
#endif /* ENABLE_MEMSCREEN */
if (blend > MAXBLEND) {
blend = MAXBLEND;
}
#ifdef ENABLE_MEMSCREEN
if (memscreen_enabled && memblend > 256) {
memblend = 256;
showmem = 0;
}
#endif /* ENABLE_MEMSCREEN */
}
#ifdef ENABLE_CPU
if (cpu_enabled) {
/* bit shifts result in smaller and faster code without an extra jns
* which appears if we / 128 instead of >> 7.
*/
kitptr = kit;
for (y = 0; y < 9; y++) {
unsigned char src;
pos = (y + POSY) * 56 * 3 + (POSX * 3);
bob = 75; /* 25 * 3 */
while (bob--) {
src = bm.rgb_buf[pos];
if (!src)
bm.rgb_buf[pos++] = *kitptr++;
else
bm.rgb_buf[pos++] =
(blend * src + (256 - blend) * *kitptr++) >> 8;
}
}
}
#endif /* ENABLE_CPU */
#ifdef ENABLE_MEMSCREEN
/* we hovered long enough to print some memory info */
if (memscreen_enabled && showmem) {
unsigned char *ptr, *ptr2, src;
ptr = bm.mem_buf;
ptr2 = bm.rgb_buf;
bob = 9408; /* 56 * 56 * 3 */
while (bob--) {
src = *ptr2;
*ptr2++ = (memblend * src + (256 - memblend) * *ptr++) >> 8;
}
}
#endif /* ENABLE_MEMSCREEN */
#undef POSY
#undef POSX
}
#endif
#ifdef ENABLE_DUCK
static void duck_set(int x, int y, int nr, int rev, int upsidedown)
{
int w, h;
int rw;
#ifdef UPSIDE_DOWN_DUCK
int rh;
#endif
int pos;
int dw, di, dh, ds;
int cmap; /* index into duck colors */
#define _R(idx) ((int)duck_cmap[idx][0])
#define _G(idx) ((int)duck_cmap[idx][1])
#define _B(idx) ((int)duck_cmap[idx][2])
#define GETME(x, y, idx) ((int)duck_data[idx][y * 18 + x])
ds = 0;
if (y < 0)
ds = -(y);
dh = 17;
if ((y + 17) > 56)
dh = 56 - y;
dw = 18;
if (x > 38)
dw = 18 - (x - 38);
di = 0;
if (x < 0)
di = -(x);
for (h = ds; h < dh; h++) {
/* calculate this only once */
int ypos = (h + y) * 56;
#ifdef UPSIDE_DOWN_DUCK
rh = (upsidedown && upside_down_duck_enabled) ? 17 - h : h;
#endif
for (w = di; w < dw; w++) {
rw = (rev) ? 17 - w : w;
#ifdef UPSIDE_DOWN_DUCK
if ((cmap = GETME(rw, rh, nr)) != 0) {
#else
if ((cmap = GETME(rw, h, nr)) != 0) {
#endif
unsigned char r, g, b;
pos = (ypos + w + x) * 3;
r = _R(cmap);
g = _G(cmap);
b = _B(cmap);
/* and now we'll blend the duck part that in water */
/* if we use integers here we speed up this function about
* 40%. */
if (h + y < REALY(bm.waterlevels[w + x])) {
bm.rgb_buf[pos++] = r;
bm.rgb_buf[pos++] = g;
bm.rgb_buf[pos] = b;
} else {
bm.rgb_buf[pos] = (DUCKBLEND * (int) bm.rgb_buf[pos]
+ (256 - DUCKBLEND) * (int) r) >> 8;
bm.rgb_buf[pos + 1] =
(DUCKBLEND * (int) bm.rgb_buf[pos + 1]
+ (256 - DUCKBLEND) * (int) g) >> 8;
bm.rgb_buf[pos + 2] =
(DUCKBLEND * (int) bm.rgb_buf[pos + 2]
+ (256 - DUCKBLEND) * (int) b) >> 8;
}
}
}
}
#undef _R
#undef _G
#undef _B
#undef GETME
}
static int animate_correctly(void)
{
/* returns the correct order of framenumber 0,1,2,1,0,1,2...
instead of 0,1,2,0,1,2 <- this way the duck looks really ugly
instead of keeping 2 counters we just made it longer */
static int outp[48] =
{ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0,
1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2,
2, 2, 1, 1, 1, 1
};
static int totalcounter = -1;
if (++totalcounter > 47)
totalcounter = 0;
return outp[totalcounter];
}
static void duck_swimmer(int posy)
{
static int tx = -19;
static int rp;
static int rev = 1;
static int upsidedown = 0;
#ifdef UPSIDE_DOWN_DUCK
/* dive */
if (upside_down_duck_enabled) {
if (upsidedown == 0 && posy < 2)
upsidedown = 1;
else if (upsidedown == 1 && posy > 5) /* jump out */
upsidedown = 0;
if (upsidedown)
posy += 10;
}
#endif
if (rp++ < 10) {
duck_set(tx, posy, animate_correctly(), rev, upsidedown);
return;
}
rp = 0;
if (!rev) {
if (tx-- < -18) {
tx = -18;
rev = 1;
}
} else {
if (tx++ > 57) {
tx = 57;
rev = 0;
}
}
duck_set(tx, posy, animate_correctly(), rev, upsidedown);
}
#endif /* ENABLE_DUCK */
static void bubblemon_setup_samples(void)
{
int i;
u_int64_t load = 0, total = 0;
if (bm.load) {
load = bm.load[bm.loadIndex];
free(bm.load);
}
if (bm.total) {
total = bm.total[bm.loadIndex];
free(bm.total);
}
bm.loadIndex = 0;
bm.load = malloc(bm.samples * sizeof(u_int64_t));
bm.total = malloc(bm.samples * sizeof(u_int64_t));
for (i = 0; i < bm.samples; i++) {
bm.load[i] = load;
bm.total[i] = total;
}
}
static void bubblemon_setup_colors(void)
{
#define NUM_COLORS 99
int i, j, *col;
int r_air_noswap, g_air_noswap, b_air_noswap;
int r_liquid_noswap, g_liquid_noswap, b_liquid_noswap;
int r_air_maxswap, g_air_maxswap, b_air_maxswap;
int r_liquid_maxswap, g_liquid_maxswap, b_liquid_maxswap;
int actual_colors = NUM_COLORS / 3;
if (!bm.colors)
bm.colors = malloc(NUM_COLORS * sizeof(int));
col = bm.colors;
r_air_noswap = (bm.air_noswap >> 16) & 0xff;
g_air_noswap = (bm.air_noswap >> 8) & 0xff;
b_air_noswap = (bm.air_noswap) & 0xff;
r_liquid_noswap = (bm.liquid_noswap >> 16) & 0xff;
g_liquid_noswap = (bm.liquid_noswap >> 8) & 0xff;
b_liquid_noswap = (bm.liquid_noswap) & 0xff;
r_air_maxswap = (bm.air_maxswap >> 16) & 0xff;
g_air_maxswap = (bm.air_maxswap >> 8) & 0xff;
b_air_maxswap = (bm.air_maxswap) & 0xff;
r_liquid_maxswap = (bm.liquid_maxswap >> 16) & 0xff;
g_liquid_maxswap = (bm.liquid_maxswap >> 8) & 0xff;
b_liquid_maxswap = (bm.liquid_maxswap) & 0xff;
for (i = 0; i < actual_colors; i++) {
int r, g, b;
int r_composite, g_composite, b_composite;
j = i >> 1;
/* Liquid */
r = (r_liquid_maxswap * j +
r_liquid_noswap * ((actual_colors - 1) -
j)) / (actual_colors - 1);
g = (g_liquid_maxswap * j +
g_liquid_noswap * ((actual_colors - 1) -
j)) / (actual_colors - 1);
b = (b_liquid_maxswap * j +
b_liquid_noswap * ((actual_colors - 1) -
j)) / (actual_colors - 1);
r_composite = r;
g_composite = g;
b_composite = b;
col[(i * 3)] = (r << 16) | (g << 8) | b;
/* Air */
r = (r_air_maxswap * j +
r_air_noswap * ((actual_colors - 1) - j)) / (actual_colors -
1);
g = (g_air_maxswap * j +
g_air_noswap * ((actual_colors - 1) - j)) / (actual_colors -
1);
b = (b_air_maxswap * j +
b_air_noswap * ((actual_colors - 1) - j)) / (actual_colors -
1);
r_composite += r;
g_composite += g;
b_composite += b;
col[(i * 3) + 2] = (r << 16) | (g << 8) | b;
/* Anti-alias */
r = r_composite >> 1;
g = g_composite >> 1;
b = b_composite >> 1;
col[(i * 3) + 1] = (r << 16) | (g << 8) | b;
}
#undef NUM_COLORS
}
static void bubblemon_allocate_buffers(void)
{
int i;
/* storage for bubbles */
bm.bubbles = (Bubble *) malloc(sizeof(Bubble) * bm.maxbubbles);
/* Allocate (zeroed) bubble memory */
if (bm.bubblebuf)
free(bm.bubblebuf);
bm.bubblebuf = calloc(56 * 60, sizeof(char));
/* Allocate water level memory */
if (bm.waterlevels)
free(bm.waterlevels);
bm.waterlevels = malloc(56 * sizeof(int));
for (i = 0; i < 56; i++) {
bm.waterlevels[i] = MAKEY(56);
}
/* Allocate water level velocity memory */
if (bm.waterlevels_dy)
free(bm.waterlevels_dy);
bm.waterlevels_dy = calloc(56, sizeof(int));
}
static void get_memory_load_percentage(void)
{
/* system_memory() will return true on initial run so that we get
* correct memory info, but may subsequently return 0 if memory
* is not changing */
if (system_memory()) {
/* new memory/swap data is in, calculate things */
bm.mem_percent = (100 * bm.mem_used) / bm.mem_max;
if (bm.swap_max != 0) {
bm.swap_percent = (100 * bm.swap_used) / bm.swap_max;
} else {
bm.swap_percent = 0;
}
}
}
/* ex:set ts=8: */
syntax highlighted by Code2HTML, v. 0.9.1