📄 bubblemon.c
字号:
/* * Bubbling Load Monitoring Applet * Copyright (C) 1999-2000 Johan Walles - d92-jwa@nada.kth.se * http://www.nada.kth.se/~d92-jwa/code/#bubblemon * * 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. *//* * This is a platform independent file that drives the program. */#include <stdio.h>#include <stdlib.h>#include <assert.h>#include <sys/time.h>#include <string.h>#include <math.h>#include <time.h>/* Natural language translation stuff */#ifdef ENABLE_NLS#include <libintl.h>#include <locale.h>#ifndef _#define _ gettext#endif#else#define _#endif // ENABLE_NLS#include "bubblemon.h"#include "ui.h"#include "meter.h"#include "mail.h"#include "config.h"#include "netload.h"// Bottle graphics#include "msgInBottle.c"static bubblemon_picture_t bubblePic;static bubblemon_Physics physics;static meter_sysload_t sysload;/* Set the dimensions of the bubble array */void bubblemon_setSize(int width, int height){ if ((width != bubblePic.width) || (height != bubblePic.height)) { bubblePic.width = width; bubblePic.height = height; if (bubblePic.airAndWater != NULL) { free(bubblePic.airAndWater); bubblePic.airAndWater = NULL; } if (bubblePic.pixels != NULL) { free(bubblePic.pixels); bubblePic.pixels = NULL; } if (physics.waterLevels != NULL) { free(physics.waterLevels); physics.waterLevels = NULL; } if (physics.weeds != NULL) { free(physics.weeds); physics.weeds = NULL; } physics.n_bubbles = 0; physics.max_bubbles = 0; if (physics.bubbles != NULL) { free(physics.bubbles); physics.bubbles = NULL; } }}static void usage2string(/*@out@*/ char *string, u_int64_t used, u_int64_t max){ /* Create a string of the form "35/64Mb" */ unsigned int shiftme = 0; char divisor_char = '\0'; if ((max >> 30) > 7000) { shiftme = 40; divisor_char = 'T'; } else if ((max >> 20) > 7000) { shiftme = 30; divisor_char = 'G'; } else if ((max >> 10) > 7000) { shiftme = 20; divisor_char = 'M'; } else if ((max >> 0) > 7000) { shiftme = 10; divisor_char = 'k'; } if (divisor_char == '\0') { sprintf(string, "%llu/%llu bytes", used >> shiftme, max >> shiftme); } else { sprintf(string, "%llu/%llu%cb", used >> shiftme, max >> shiftme, divisor_char); }}const char *bubblemon_getTooltip(void){ char memstring[20], swapstring[20], loadstring[50]; static char *tooltipstring = 0; int cpu_number; if (!tooltipstring) { /* Prevent the tooltipstring buffer from overflowing on a system with lots of CPUs */ tooltipstring = malloc(sizeof(char) * (sysload.nCpus * 50 + 100)); assert(tooltipstring != NULL); } usage2string(memstring, sysload.memoryUsed, sysload.memorySize); snprintf(tooltipstring, 90, _("Memory used: %s"), memstring); if (sysload.swapSize > 0) { usage2string(swapstring, sysload.swapUsed, sysload.swapSize); snprintf(loadstring, 90, _("\nSwap used: %s"), swapstring); strcat(tooltipstring, loadstring); } if (sysload.nCpus == 1) { snprintf(loadstring, 45, _("\nCPU load: %d%%"), bubblemon_getCpuLoadPercentage(0)); strcat(tooltipstring, loadstring); } else { for (cpu_number = 0; cpu_number < sysload.nCpus; cpu_number++) { snprintf(loadstring, 45, _("\nCPU #%d load: %d%%"), cpu_number, bubblemon_getCpuLoadPercentage(cpu_number)); strcat(tooltipstring, loadstring); } } return tooltipstring;}static int bubblemon_getMsecsSinceLastCall(){ /* Return the number of milliseconds that have passed since the last time this function was called, or -1 if this is the first call. If a long time has passed since last time, the result is undefined. */ static long last_sec = 0L; static long last_usec = 0L; int returnMe = -1; struct timeval currentTime; /* What time is it now? */ gettimeofday(¤tTime, NULL); if ((last_sec != 0L) || (last_usec != 0L)) { returnMe = 1000 * (int)(currentTime.tv_sec - last_sec); returnMe += ((int)(currentTime.tv_usec - last_usec)) / 1000L; } last_sec = currentTime.tv_sec; last_usec = currentTime.tv_usec; return returnMe;}static void bubblemon_updateWaterlevels(int msecsSinceLastCall){ float dt = msecsSinceLastCall / 30.0; /* Typing fingers savers */ int w = bubblePic.width; int h = bubblePic.height; int x; /* Where is the surface heading? */ float waterLevels_goal; /* How high can the surface be? */ float waterLevels_max = (h - 0.55); /* Move the water level with the current memory usage. The water * level goes from 0.0 to h so that you can get an integer height by * just chopping off the decimals. */ waterLevels_goal = ((float)sysload.memoryUsed / (float)sysload.memorySize) * waterLevels_max; physics.waterLevels[0].y = waterLevels_goal; physics.waterLevels[w - 1].y = waterLevels_goal; for (x = 1; x < (w - 1); x++) { /* Accelerate the current waterlevel towards its correct value */ float current_waterlevel_goal = (physics.waterLevels[x - 1].y + physics.waterLevels[x + 1].y) / 2.0; physics.waterLevels[x].dy += (current_waterlevel_goal - physics.waterLevels[x].y) * dt * VOLATILITY; physics.waterLevels[x].dy *= VISCOSITY; if (physics.waterLevels[x].dy > SPEED_LIMIT) physics.waterLevels[x].dy = SPEED_LIMIT; else if (physics.waterLevels[x].dy < -SPEED_LIMIT) physics.waterLevels[x].dy = -SPEED_LIMIT; } for (x = 1; x < (w - 1); x++) { /* Move the current water level */ physics.waterLevels[x].y += physics.waterLevels[x].dy * dt; if (physics.waterLevels[x].y > waterLevels_max) { /* Stop the wave if it hits the ceiling... */ physics.waterLevels[x].y = waterLevels_max; physics.waterLevels[x].dy = 0.0; } else if (physics.waterLevels[x].y < 0.0) { /* ... or the floor. */ physics.waterLevels[x].y = 0.0; physics.waterLevels[x].dy = 0.0; } }}static void bubblemon_addNourishment(bubblemon_Weed *weed, int percentage){ float heightLimit = (bubblePic.height * WEED_HEIGHT) / 100.0; weed->nourishment += (heightLimit * percentage) / 100.0; if (weed->nourishment + weed->height > heightLimit) { weed->nourishment = heightLimit - weed->height; }}static void bubblemon_updateWeeds(int msecsSinceLastCall){ static int timeToNextUpdate = 0; static int lastUpdatedWeed = 0; int w = bubblePic.width; int x; // If enough time has elapsed... timeToNextUpdate -= msecsSinceLastCall; while (timeToNextUpdate <= 0) { // ... update the nourishment level of our next weed lastUpdatedWeed--; if ((lastUpdatedWeed <= 0) || (lastUpdatedWeed >= bubblePic.width)) { lastUpdatedWeed = bubblePic.width - 1; } // Distribute the nourishment over several weeds if (lastUpdatedWeed > 0) { bubblemon_addNourishment(&(physics.weeds[lastUpdatedWeed - 1]), (netload_getLoadPercentage() * 8) / 10); } bubblemon_addNourishment(&(physics.weeds[lastUpdatedWeed]), netload_getLoadPercentage()); if (lastUpdatedWeed < (bubblePic.width - 1)) { bubblemon_addNourishment(&(physics.weeds[lastUpdatedWeed + 1]), (netload_getLoadPercentage() * 8) / 10); } timeToNextUpdate += NETLOAD_INTERVAL; } // For all weeds... for (x = 0; x < w; x++) { // ... grow / shrink them according to their nourishment level float speed; float delta; if (physics.weeds[x].nourishment <= 0.0) { speed = -WEED_MINSPEED; } else { speed = physics.weeds[x].nourishment * WEED_SPEEDFACTOR; if (speed > WEED_MAXSPEED) { speed = WEED_MAXSPEED; } else if (speed < WEED_MINSPEED) { speed = WEED_MINSPEED; } } delta = (speed * msecsSinceLastCall) / 1000.0; if (delta > physics.weeds[x].nourishment) { delta = physics.weeds[x].nourishment; } if (delta > 0.0) { physics.weeds[x].nourishment -= delta; } physics.weeds[x].height += delta; if (physics.weeds[x].height < 0.0) { physics.weeds[x].height = 0.0; } }}/* Update the bubbles (and possibly create new ones) */static void bubblemon_updateBubbles(int msecsSinceLastCall){ int i; static float createNNewBubbles; static bubblemon_layer_t lastNewBubbleLayer = BACKGROUND; float dt = msecsSinceLastCall / 30.0; /* Typing fingers saver */ int w = bubblePic.width; /* Create new bubble(s) if the planets are correctly aligned... */ createNNewBubbles += ((float)bubblemon_getAverageLoadPercentage() * (float)bubblePic.width * dt) / 2000.0; for (i = 0; i < createNNewBubbles; i++) { if (physics.n_bubbles < physics.max_bubbles) { lastNewBubbleLayer = (lastNewBubbleLayer == BACKGROUND) ? FOREGROUND : BACKGROUND; /* We don't allow bubbles on the edges 'cause we'd have to clip them */ physics.bubbles[physics.n_bubbles].x = (random() % (w - 2)) + 1; physics.bubbles[physics.n_bubbles].y = 0.0; physics.bubbles[physics.n_bubbles].dy = 0.0; /* Create alternately foreground and background bubbles */ physics.bubbles[physics.n_bubbles].layer = lastNewBubbleLayer; if (RIPPLES != 0.0) { /* Raise the water level above where the bubble is created */ if ((physics.bubbles[physics.n_bubbles].x - 2) >= 0) physics.waterLevels[physics.bubbles[physics.n_bubbles].x - 2].y += RIPPLES; physics.waterLevels[physics.bubbles[physics.n_bubbles].x - 1].y += RIPPLES; physics.waterLevels[physics.bubbles[physics.n_bubbles].x].y += RIPPLES; physics.waterLevels[physics.bubbles[physics.n_bubbles].x + 1].y += RIPPLES; if ((physics.bubbles[physics.n_bubbles].x + 2) < w) physics.waterLevels[physics.bubbles[physics.n_bubbles].x + 2].y += RIPPLES; } /* Count the new bubble */ physics.n_bubbles++; createNNewBubbles--; } } /* Move the bubbles */ for (i = 0; i < physics.n_bubbles; i++) { /* Accelerate the bubble upwards */ physics.bubbles[i].dy -= GRAVITY * dt; /* Move the bubble vertically */ physics.bubbles[i].y += physics.bubbles[i].dy * dt * ((physics.bubbles[i].layer == BACKGROUND) ? BGBUBBLE_SPEED : 1.0); /* Did we lose it? */ if (physics.bubbles[i].y > physics.waterLevels[physics.bubbles[i].x].y) { if (RIPPLES != 0.0) { /* Lower the water level around where the bubble is about to vanish */ physics.waterLevels[physics.bubbles[i].x - 1].y -= RIPPLES; physics.waterLevels[physics.bubbles[i].x].y -= 3 * RIPPLES; physics.waterLevels[physics.bubbles[i].x + 1].y -= RIPPLES; } /* We just lost it, so let's nuke it */ physics.bubbles[i].x = physics.bubbles[physics.n_bubbles - 1].x; physics.bubbles[i].y = physics.bubbles[physics.n_bubbles - 1].y; physics.bubbles[i].dy = physics.bubbles[physics.n_bubbles - 1].dy; physics.n_bubbles--; /* We must check the previously last bubble, which is now the current bubble, also. */ i--; continue; } }}#define MIN(a,b) (((a) < (b)) ? (a) : (b))/* Update the bottle */static void bubblemon_updateBottle(int msecsSinceLastCall, int youveGotMail){ float dt = msecsSinceLastCall / 30.0; float gravityDdy; float dragDdy; int isInWater; // The MIN stuff prevents the bottle from floating above the visible // area even when the water surface is at the top of the display isInWater = physics.bottle_y < MIN(physics.waterLevels[bubblePic.width / 2].y, bubblePic.height - msgInBottle.height / 2); if (youveGotMail) { if (physics.bottle_state == GONE) { // Drop a new bottle physics.bottle_y = bubblePic.height + msgInBottle.height; physics.bottle_dy = 0.0; physics.bottle_state = FALLING; } else if (physics.bottle_state == SINKING) { physics.bottle_state = FLOATING; } } else { /* No unread mail */ if ((physics.bottle_state == FALLING) || (physics.bottle_state == FLOATING)) { physics.bottle_state = SINKING; } } if (physics.bottle_state == GONE) { return; } /* Accelerate the bottle */ if ((physics.bottle_state == FALLING) || (physics.bottle_state == SINKING) || !isInWater) { // Gravity pulls the bottle down gravityDdy = 2.0 * GRAVITY * dt; } else { // Gravity floats the bottle up gravityDdy = 2.0 * -(GRAVITY * dt); } if (isInWater) { dragDdy = (physics.bottle_dy * physics.bottle_dy) * BOTTLE_DRAG; // If the speed is positive... if (physics.bottle_dy > 0.0) { // ... then the drag should be negative dragDdy = -dragDdy; } } else { dragDdy = 0.0; } physics.bottle_dy += gravityDdy + dragDdy; /* Move the bottle vertically */ physics.bottle_y += physics.bottle_dy * dt; // If the bottle has fallen on screen... if ((physics.bottle_state == FALLING) && (physics.bottle_y < bubblePic.height)) { // ... it should start floating instead of falling physics.bottle_state = FLOATING; } /* Did we lose it? */ if ((physics.bottle_state == SINKING) && (physics.bottle_y + msgInBottle.height < 0.0)) { physics.bottle_state = GONE; }}static const bubblemon_color_t bubblemon_constant2color(const unsigned int constant){ bubblemon_color_t returnMe; returnMe.components.r = (constant >> 24) & 0xff; returnMe.components.g = (constant >> 16) & 0xff; returnMe.components.b = (constant >> 8) & 0xff; returnMe.components.a = (constant >> 0) & 0xff; return returnMe;}/* The amount parameter is 0-255. */static inline bubblemon_color_t bubblemon_interpolateColor(const bubblemon_color_t c1, const bubblemon_color_t c2, const int amount){ int a, r, g, b; bubblemon_color_t returnme; assert(amount >= 0 && amount < 256);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -