/* wmcube.c Version 0.98 (2000-10-20) Robert Kling (robkli-8@student.luth.se) http://boombox.campus.luth.se/projects.php Contributions: -n option patch by Thorsten Jens (thodi@et-inf.fho-emden.de) (2000-05-12) Various bugfixes and optimizations by Jakob Borg (2000-05-13) Solaris Port by Dan Price (dp@rampant.org) (2000-07-16) OpenBSD Port by Brian Joseph Czapiga (rys@godsey.net) (2000-07-19) FreeBSD Port by Tai-hwa Liang (avatar@mmlab.cse.yzu.edu.tw) (2000-07-20) NetBSD Port by Jared Smolens (2000-09-23) gdk gfx, dynamic colors, etc timecop@japan.co.jp (2001-02-13) This software is licensed through the GNU General Public Licence. See http://www.BenSinclair.com/dockapp/ for more wm dock apps. If you want to port wmcube to another OS the system specific code is sectioned the bottom of this file. See instructions there. */ #define _GNU_SOURCE #define WMCUBE_VERSION "0.99" #define REV_DATE "2001-02-13" #include #include #include #include #include #include #include #include #ifdef LINUX /* forgotten includes */ #include #include #endif #include #include #include #include #include #include #include #include #include #include #ifdef FREEBSD #include #endif /* this is a somewhat compressed version of "digits[96 * 9]" * each 1/4 hex digit is a colormap entry. */ /* *INDENT-OFF* */ static unsigned char c0de[24 * 9 + 1] = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x05\x40\x08\x25\x62\x56\x20\x22\x56\x25\x62\x56\x25\x62\x56\x00\x00\x00\x00\x00\x03\xc0\x0a\x00" "\x10\x10\x04\x00\x10\x01\x10\x11\x00\x10\x00\x01\x10\x11\x01\x10\x10\x00\x00\x00\x03\xc0\x0a\x00" "\x10\x10\x04\x00\x10\x01\x10\x11\x00\x10\x00\x01\x10\x11\x01\x00\x43\xff\xca\xaa\x3f\xfc\xaa\xa0" "\x20\x20\x08\x25\x60\x56\x25\x62\x56\x25\x60\x02\x35\x72\x56\x01\x03\xff\xca\xaa\x3f\xfc\xaa\xa0" "\x10\x10\x04\x10\x00\x01\x00\x10\x01\x10\x10\x01\x10\x10\x01\x04\x00\x00\x00\x00\x03\xc0\x0a\x00" "\x10\x10\x04\x10\x00\x01\x00\x10\x01\x10\x10\x01\x10\x10\x01\x10\x10\x00\x00\x00\x03\xc0\x0a\x00" "\x05\x40\x04\x25\x62\x56\x00\x22\x56\x25\x60\x02\x25\x62\x56\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; /* "\x90/bin/sh" oops just kidding */ /* *INDENT-ON* */ typedef struct { /* dockapp info structure */ Display *d; int screen; GdkWindow *win; GdkWindow *iconwin; GdkGC *gc; GdkGC *dgc; /* drawing gc for lines and shit */ /* there is a off-by-one error in one of the line/hline functions */ unsigned char rgb[57 * 57]; /* main image buffer */ unsigned char buf[57 * 57]; /* secondary image buffer */ GdkRgbCmap cmap; /* main colormap */ /* The colormap is divided like this: * 0 .. 240 cube shades (actually only use 0..26 right now * 241 .. 254 misc colors (label, buttons, etc) * 255 background color (0x202020) */ } Dockapp; typedef struct { /* mouse regions */ int enable; int x; int y; int width; int height; } MRegion; #define CHAR_WIDTH 5 #define CHAR_HEIGHT 7 #define PI 3.1415926535 /**** Graphics ***********************************/ void redraw_window(void); void new_window(void); void setupcolor(short R, short G, short B); int add_mr(int index, int x, int y, int width, int height); int check_mr(int x, int y); static void copy_xpm_area(int x, int y, int w, int h, int dx, int dy); static void putpixel(int x, int y, int c); void line(int x1, int y1, int x2, int y2, int c); static void hline(int x1, int x2, int y, int c); void trcopy(void); void triangle(int x1, int y1, int x2, int y2, int x3, int y3, int c); void draw_cpu(int num, int x, int y); void update_buffer(unsigned int cpu_usage); void draw(int color); void startup_seq(); /**** 3d specific ********************************/ void setupobj(char *filename); void setUpAngles(); void rotate(int xang, int yang, int zang); int normal(float p1[], float p2[], float p3[]); int luminate(float p1[], float p2[], float p3[]); void sortz(int nofelements); /**** Application Management, I/O etc. ***********/ void prep_digits(void); void print_help(void); int loadobj(char *filename); void mem_alloc_error(void *block); int scan4objects(char *dir); int next_object(void); void die(void); /**** System specific functions ******************/ int init_calc_cpu(void); int calc_cpu_total(void); /**** Global variables ***************************/ Dockapp dockapp; /* dockapp info structure */ /* digits for the CPU load + buttons - filled in prep_digits */ static unsigned char digits[96 * 9]; MRegion mr[16]; /* mouse regions */ int xcenter, ycenter, zoff; double cost[361], sint[361]; double acost[100]; float **matrix; float **rmatrix; int **planes; int *plane_color; int *zorder; int *cline; int nofcoords, noflines, nofplanes; char *objects[1000]; int nof_objects = 0; int show_load = 1; int use_nice = 1; int which_cpu = -1; int planesORlines = 1; char *pname; float lum_vector[3] = { 0, 0, 100 }; /* Lightsource vector */ #ifdef FREEBSD static kvm_t *kd; static struct nlist nlst[] = { {"_cp_time"}, {0} }; #endif void prep_digits(void) { int i, k; unsigned char you, *cant, *c, me; cant = digits; c = c0de; for (i = 0; i < 216; i++) { you = *c++; for (k = 3; k >= 0; k--) { me = (you >> 6) & 0x3; *cant++ = (me) ? 240 + me : 255; you <<= 2; } } } static void copy_xpm_area(x, y, w, h, dx, dy) { int i, j; int spos, dpos; for (j = 0; j < h; j++) { spos = x + (96 * (y + j)); dpos = dx + (56 * (dy + j)); for (i = 0; i < w; i++) { dockapp.buf[dpos++] = digits[spos++]; } } } void redraw_window(void) { gdk_draw_indexed_image(dockapp.win, dockapp.gc, 4, 4, 56, 56, GDK_RGB_DITHER_NORMAL, dockapp.rgb, 56, &dockapp.cmap); gdk_draw_indexed_image(dockapp.iconwin, dockapp.gc, 4, 4, 56, 56, GDK_RGB_DITHER_NORMAL, dockapp.rgb, 56, &dockapp.cmap); } void new_window(void) { GdkWindowAttr attr; Window win, iconwin; XSizeHints sizehints; XWMHints wmhints; /* for mask */ GdkBitmap *mask; unsigned char mask_data[8 * 64]; int i; GdkColor bright; /* for that stupid shadow line */ GdkColormap *map2; attr.width = 64; attr.height = 64; attr.title = "wmcube"; attr.event_mask = GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK; attr.wclass = GDK_INPUT_OUTPUT; attr.visual = gdk_visual_get_system(); attr.colormap = gdk_colormap_get_system(); attr.wmclass_name = "wmcube"; attr.wmclass_class = "wmcube"; attr.window_type = GDK_WINDOW_TOPLEVEL; sizehints.flags = USSize; sizehints.width = 64; sizehints.height = 64; dockapp.win = gdk_window_new(NULL, &attr, GDK_WA_TITLE | GDK_WA_WMCLASS | GDK_WA_VISUAL | GDK_WA_COLORMAP); if (!dockapp.win) { fprintf(stderr, "Can't make toplevel window\n"); exit(1); } memset(&attr, 0, sizeof(attr)); attr.width = 64; attr.height = 64; attr.title = "wmcube"; attr.event_mask = GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK; attr.wclass = GDK_INPUT_OUTPUT; attr.visual = gdk_visual_get_system(); attr.colormap = gdk_colormap_get_system(); attr.wmclass_name = "wmcube"; attr.wmclass_class = "wmcube"; attr.window_type = GDK_WINDOW_TOPLEVEL; dockapp.iconwin = gdk_window_new(dockapp.win, &attr, GDK_WA_TITLE | GDK_WA_WMCLASS); if (!dockapp.iconwin) { fprintf(stderr, "Cannot make icon window\n"); exit(1); } win = GDK_WINDOW_XWINDOW(dockapp.win); iconwin = GDK_WINDOW_XWINDOW(dockapp.iconwin); XSetWMNormalHints(GDK_WINDOW_XDISPLAY(dockapp.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(dockapp.win), win, &wmhints); /* make the mask rectangle */ memset(mask_data, 0x00, 8 * 64); for (i = 3; i < 61; i++) { memset((mask_data + (i * 8)) + 1, 0xFF, 7); mask_data[i * 8] = 0xf8; mask_data[i * 8 + 7] = 0x1f; } mask = gdk_bitmap_create_from_data(dockapp.win, mask_data, 64, 64); dockapp.gc = gdk_gc_new(dockapp.win); dockapp.dgc = gdk_gc_new(dockapp.win); /* bwahaha, look at the shit we have to go through just to make a damn * color. fucking colormaps */ map2 = gdk_colormap_get_system(); gdk_color_parse("#c7c3c7", &bright); gdk_colormap_alloc_color(map2, &bright, False, True); gdk_gc_set_foreground(dockapp.dgc, &bright); /* combine mask with window */ gdk_window_shape_combine_mask(dockapp.win, mask, 0, 0); gdk_window_shape_combine_mask(dockapp.iconwin, mask, 0, 0); gdk_window_show(dockapp.win); } int add_mr(int index, int x, int y, int width, int height) { mr[index].enable = 1; mr[index].x = x; mr[index].y = y; mr[index].width = width; mr[index].height = height; return 0; } int check_mr(int x, int y) { register int i; register int found = 0; for (i = 0; i < 32 && !found; i++) { if (mr[i].enable && x >= mr[i].x && x <= mr[i].x + mr[i].width && y >= mr[i].y && y <= mr[i].y + mr[i].height) found = 1; } if (!found) return -1; return (i - 1); } int main(int argc, char **argv) { int j, i = 0, rot_speed = 0, cpu_usage = 0, rot_step = 1; #ifdef PRO int count = 2500; #endif long screen_speed = 10000; /* microseconds between screen updates (approx.) */ long cpu_update = 490000; /* microseconds between cpu update (approx.) */ int loop; GdkEvent *event; GdkColor shade = { 0, 0, 0, 0 }; char *tmp = NULL; char *rotdiv = { "25" }; char *rotstep = { "1" }; char *obj_filename = { "" }; int rot; /* a little further into colormap, darker */ int cube_color = 20; int c = 0; int invert_speed = 0; pname = strrchr(argv[0], '/'); if (pname == NULL) pname = argv[0]; srand((unsigned) time(NULL)); opterr = 0; while ((c = getopt(argc, argv, "d:nhpbir:o:c:s:")) != -1) { switch (c) { case 'c': which_cpu = atoi(optarg); break; case 'd': rotstep = optarg; break; case 'h': print_help(); return 1; case 'i': invert_speed = 1; break; case 'p': show_load = 0; break; case 'b': /* this is an index into our colormap. */ cube_color = 0; break; case 'r': rotdiv = optarg; break; case 'o': obj_filename = optarg; break; case 'n': use_nice = 0; break; case 's': tmp = strdup(optarg); break; case '?': print_help(); return 1; default: abort(); } } /* * Validate that wmcube can run on this system given the parameters, * then setup the statistics gathering subsystem. */ if (init_calc_cpu() != 0) die(); /* unpack font + button images */ prep_digits(); /* * Scan directory for .wmc files and choose one randomly. If the user * specified a particular file, load that one. */ #ifndef SOLARIS /* scan4objects doesnt work on Solaris, load object immediatly */ scan4objects(obj_filename); if (nof_objects != 0) next_object(); else #endif setupobj(obj_filename); /* * Various initializion stuff for the 3d-engine etc. */ setUpAngles(); rot = atoi(rotdiv); if ((rot >= 1) && (rot <= 100)); else rot = 25; rot_step = atoi(rotstep); if (rot_step < 0) rot_step = -rot_step; if (calc_cpu_total() == -1) die(); cpu_update /= screen_speed; loop = cpu_update; if (!gdk_init_check(&argc, &argv)) { fprintf(stderr, "GDK init failed\n"); exit(1); } gdk_rgb_init(); memset(dockapp.buf, 0xFF, 56 * 56); if (tmp) { if (!gdk_color_parse(tmp, &shade)) { fprintf(stderr, "Incorrect color specification\n"); exit(1); } free(tmp); setupcolor(shade.red >> 8, shade.green >> 8, shade.blue >> 8); } else { setupcolor(0x20, 0xB2, 0xAE); } new_window(); if (calc_cpu_total() == -1) die(); /* index, left, top, right, bottom */ add_mr(1, 51, 51, 6, 6); /* + Zoom In */ add_mr(5, 7, 51, 6, 6); /* - Zoom Out */ add_mr(3, 21, 51, 24, 7); /* Show cpu-load */ add_mr(2, 4, 4, 56, 46); /* Everywhere else (almost) to change object */ /* * Main loop begins here */ zoff = 3600; #ifndef PRO while (1) { #else while (count--) { #endif i = (i + rot_speed + rot_step) % 360; rotate(i, i, i); memset(dockapp.rgb, 0xff, 56 * 56); draw(cube_color); trcopy(); if (loop++ > cpu_update) { loop = 0; /* * call calc_cpu_total to update statistics. If some * sort of bad event occurs, calc_cpu_total will return * -1, and we exit. */ if ((cpu_usage = calc_cpu_total()) == -1) { die(); } rot_speed = abs(invert_speed * (100 / rot) - cpu_usage / rot); /* redraw the CPU usage and update screen */ update_buffer(cpu_usage); } /* X Events */ while (gdk_events_pending()) { event = gdk_event_get(); if (event) { switch (event->type) { case GDK_EXPOSE: /* redraw the shade + 3d window. This doesn't * happen too often. Infact if you don't cover up * the dock, only once */ gdk_draw_line(dockapp.win, dockapp.dgc, 60, 4, 60, 60); gdk_draw_line(dockapp.iconwin, dockapp.dgc, 60, 4, 60, 60); gdk_draw_line(dockapp.win, dockapp.dgc, 3, 60, 60, 60); gdk_draw_line(dockapp.iconwin, dockapp.dgc, 3, 60, 60, 60); redraw_window(); break; case GDK_DESTROY: gdk_exit(0); exit(0); break; case GDK_BUTTON_PRESS: j = check_mr(event->button.x, event->button.y); switch (j) { case 1: if (zoff > 750) { copy_xpm_area(88, 0, 6, 9, 47, 46); zoff -= 150; } break; case 2: next_object(); break; case 3: if (show_load == 1) show_load = 0; else show_load = 1; ycenter = 14 - 2 * show_load; break; case 5: copy_xpm_area(74, 0, 6, 9, 2, 46); zoff += 150; break; } break; default: break; } } } redraw_window(); #ifndef PRO usleep(screen_speed); #endif } /* * Free up memory used by the object (dirty...) (also never gets here) */ free(matrix); free(rmatrix); free(cline); return 0; } /**** Graphics *********************************** ************************************************/ void trcopy(void) { unsigned int i = 56 * 56; while (i--) if (dockapp.buf[i] != 0xff) dockapp.rgb[i] = dockapp.buf[i]; } void update_buffer(unsigned int cpu_usage) { memset(dockapp.buf, 0xFF, 56 * 56); if (show_load) draw_cpu(cpu_usage, 22, 46); copy_xpm_area(67, 0, 6, 9, 2, 46); copy_xpm_area(81, 0, 6, 9, 47, 46); } void draw(int color) { int i; if (planesORlines) { sortz(nofplanes); for (i = 0; i < nofplanes; i++) { if (normal (rmatrix[planes[zorder[i]][0]], rmatrix[planes[zorder[i]][1]], rmatrix[planes[zorder[i]][2]]) > 0) { triangle(xcenter + rmatrix[planes[zorder[i]][0]][0], ycenter + rmatrix[planes[zorder[i]][0]][1], xcenter + rmatrix[planes[zorder[i]][1]][0], ycenter + rmatrix[planes[zorder[i]][1]][1], xcenter + rmatrix[planes[zorder[i]][2]][0], ycenter + rmatrix[planes[zorder[i]][2]][1], plane_color[zorder[i]]); } } } else { for (i = 0; i < noflines; i += 2) line(xcenter + rmatrix[cline[i] - 1][0], ycenter + rmatrix[cline[i] - 1][1], xcenter + rmatrix[cline[i + 1] - 1][0], ycenter + rmatrix[cline[i + 1] - 1][1], color); } } static void putpixel(int x, int y, int c) { int pos; if ((x >= 0) && (x < 56) && (y >= 0) && (y <= 56)) { pos = x + (y * 56); dockapp.rgb[pos] = c; } } static void hline(int x1, int x2, int y, int c) { register int i; if (c > 25) c = 25; if ((y >= 0) && (y <= 56)) { if (x1 < 0) x1 = 0; else if (x1 > 56) return; if (x2 > 56) x2 = 56; else if (x2 < 0) return; for (i = x1; i < x2; i++) { register unsigned int pos; pos = y * 56 + i; dockapp.rgb[pos] = c; } } } void triangle(int x1, int y1, int x2, int y2, int x3, int y3, int c) { /* Draws a filled triangle */ int k, k2, x, x_2, i, tmp1; int x1t, x2t; if (y3 < y2) { tmp1 = y2; y2 = y3; y3 = tmp1; tmp1 = x2; x2 = x3; x3 = tmp1; } if (y2 < y1) { tmp1 = y1; y1 = y2; y2 = tmp1; tmp1 = x1; x1 = x2; x2 = tmp1; } if (y3 < y2) { tmp1 = y2; y2 = y3; y3 = tmp1; tmp1 = x2; x2 = x3; x3 = tmp1; } if (y1 != y3) k = ((x1 - x3) << 6) / (y1 - y3); else k = (x1 - x3) << 6; if (y1 != y2) k2 = ((x1 - x2) << 6) / (y1 - y2); else k2 = (x1 - x2) << 6; x = x1 << 6; x_2 = x; i = y1; if (i != y2) do { x += k; x_2 += k2; i++; if ((x1t = x >> 6) > (x2t = x_2 >> 6)) hline(x2t, x1t, i, c); else hline(x1t, x2t, i, c); } while (i != y2); if (i == y3) return; if (y2 != y3) k2 = ((x2 - x3) << 6) / (y2 - y3); else k2 = ((x2 - x3) << 6); x_2 = x2 << 6; i = y2; do { x += k; x_2 += k2; i++; if ((x1t = x >> 6) > (x2t = x_2 >> 6)) hline(x2t, x1t, i, c); else hline(x1t, x2t, i, c); } while (i != y3); } void draw_cpu(int num, int x, int y) { char buf[5]; int newx = x; int i; int c; if (num > 99) { newx -= CHAR_WIDTH; } if (num > 999) { newx -= CHAR_WIDTH; } snprintf(buf, 5, "%02i%%", num); for (i = 0; (c = buf[i]); i++) { if (c == '%') copy_xpm_area(60, 0, 7, 9, newx, y); else { c -= '0'; copy_xpm_area(c * 6, 0, 7, 9, newx, y); } newx += 6; } } void line(int x1, int y1, int x2, int y2, int c) { int i, deltax, deltay, numpixels, d, dinc1, dinc2, x, xinc1, xinc2, y, yinc1, yinc2; deltax = abs(x2 - x1); deltay = abs(y2 - y1); if (deltax >= deltay) { numpixels = deltax + 1; d = (deltay << 1) - deltax; dinc1 = deltay << 1; dinc2 = (deltay - deltax) << 1; xinc1 = 1; xinc2 = 1; yinc1 = 0; yinc2 = 1; } else { numpixels = deltay + 1; d = (deltax << 1) - deltay; dinc1 = deltax << 1; dinc2 = (deltax - deltay) << 1; xinc1 = 0; xinc2 = 1; yinc1 = 1; yinc2 = 1; } if (x1 > x2) { xinc1 = -xinc1; xinc2 = -xinc2; } if (y1 > y2) { yinc1 = -yinc1; yinc2 = -yinc2; } x = x1; y = y1; for (i = 1; i < numpixels; i++) { putpixel(x, y, c); if (d < 0) { d = d + dinc1; x = x + xinc1; y = y + yinc1; } else { d = d + dinc2; x = x + xinc2; y = y + yinc2; } } } /**** 3d specific ******************************** ************************************************/ void rotate(int xang, int yang, int zang) { float tx, ty, tz; int i; for (i = 0; i < nofcoords; i++) { tx = cost[yang] * matrix[i][0] - sint[yang] * matrix[i][2]; tz = sint[yang] * matrix[i][0] + cost[yang] * matrix[i][2]; ty = cost[zang] * matrix[i][1] - sint[zang] * tx; rmatrix[i][0] = (cost[zang] * tx + sint[zang] * matrix[i][1]); rmatrix[i][1] = (sint[xang] * tz + cost[xang] * ty); rmatrix[i][2] = (cost[xang] * tz - sint[xang] * ty); } if (planesORlines) for (i = 0; i < nofplanes; i++) if (normal (rmatrix[planes[i][0]], rmatrix[planes[i][1]], rmatrix[planes[i][2]]) > 0) plane_color[i] = luminate(rmatrix[planes[i][0]], rmatrix[planes[i][1]], rmatrix[planes[i][2]]); for (i = 0; i < nofcoords; i++) { /* Perspective correcting lines... */ rmatrix[i][0] = (rmatrix[i][0] * 256) / (2 * rmatrix[i][2] - zoff) + xcenter; rmatrix[i][1] = (rmatrix[i][1] * 256) / (2 * rmatrix[i][2] - zoff) + ycenter; } } void sortz(int nofelements) { /* Insertion-sort the planes in increasing z-distance */ int i, j, k; float key; float temparr[nofelements]; for (i = 0; i < nofelements; i++) { zorder[i] = i; temparr[i] = rmatrix[planes[i][0]][2] + rmatrix[planes[i][1]][2] + rmatrix[planes[i][2]][2]; } for (j = 1; j < nofelements; j++) { key = temparr[j]; k = zorder[j]; i = j - 1; while ((i > -1) && (temparr[i] > key)) { temparr[i + 1] = temparr[i]; zorder[i + 1] = zorder[i--]; } zorder[i + 1] = k; temparr[i + 1] = key; } } int normal(float p1[], float p2[], float p3[]) { return ((p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1])); } int luminate(float p1[], float p2[], float p3[]) { double x1 = (float) (p1[0] - p3[0]), y1 = (float) (p1[1] - p3[1]), z1 = (float) (p1[2] - p3[2]); double x2 = (float) (p2[0] - p3[0]), y2 = (float) (p2[1] - p3[1]), z2 = (float) (p2[2] - p3[2]); double nx = y1 * z2 - y2 * z1, ny = -(x1 * z2 - x2 * z1), nz = x1 * y2 - y1 * x2; return (int) (53 * (acost[(int) (50 + 50 * (nx * lum_vector[0] + ny * lum_vector[1] + nz * lum_vector[2]) / (sqrt(nx * nx + ny * ny + nz * nz) * sqrt(lum_vector [0] * lum_vector [0] + lum_vector [1] * lum_vector [1] + lum_vector [2] * lum_vector [2])))] / PI)); /* Do I smell optimization? :-) */ } void setUpAngles(void) { int i; for (i = 0; i < 361; i++) { cost[i] = cos((double) i * (2 * PI / (double) 360)); sint[i] = sin((double) i * (2 * PI / (double) 360)); } for (i = 0; i < 100; i++) acost[i] = acos((double) (-50 + i) / 50); } void setupcolor(short R, short G, short B) { int i; int logi; unsigned char r, g, b; for (i = 0; i < 26; i++) { /* feel free to come up with a better formula here. * I chose log due to lack of any better ideas. */ logi = i * log(i + 1); r = MAX(0, R - logi); /* R */ g = MAX(0, G - logi); /* G */ b = MAX(0, B - logi); /* B */ dockapp.cmap.colors[i] = r << 16 | g << 8 | b; } /* setup misc colors */ dockapp.cmap.colors[255] = 0x202020; /* background */ dockapp.cmap.colors[241] = 0x00b1ad; /* load digit #1 */ dockapp.cmap.colors[242] = 0x007571; /* load digit #2 */ dockapp.cmap.colors[243] = 0x004941; /* icon dark */ } void setupobj(char *filename) { int i, j = 0; int biggest = 0; float scale = 1; xcenter = 14; ycenter = 14 - 2 * show_load; if (strcmp(filename, "") != 0) loadobj(filename); else { nofcoords = 8; noflines = 24; nofplanes = 12; planesORlines = 1; matrix = (float **) malloc(nofcoords * sizeof(float *)); mem_alloc_error(matrix); planes = (int **) malloc(nofplanes * sizeof(int *)); mem_alloc_error(planes); plane_color = (int *) malloc(nofplanes * sizeof(int)); mem_alloc_error(plane_color); zorder = (int *) malloc(nofplanes * sizeof(int)); mem_alloc_error(zorder); for (i = 0; i < nofplanes; i++) zorder[i] = i; for (i = 0; i < nofcoords; i++) { matrix[i] = (float *) malloc(3 * sizeof(float)); mem_alloc_error(matrix[i]); } for (i = 0; i < nofplanes; i++) { planes[i] = (int *) malloc(3 * sizeof(int)); mem_alloc_error(planes[i]); } cline = (int *) malloc((noflines + 1) * sizeof(int)); mem_alloc_error(cline); matrix[0][0] = -180; matrix[0][1] = -180; matrix[0][2] = 180; /* 0 */ matrix[1][0] = 180; matrix[1][1] = -180; matrix[1][2] = 180; /* 1 */ matrix[2][0] = 180; matrix[2][1] = 180; matrix[2][2] = 180; /* 2 */ matrix[3][0] = -180; matrix[3][1] = 180; matrix[3][2] = 180; /* 3 */ matrix[4][0] = -180; matrix[4][1] = -180; matrix[4][2] = -180; /* 4 */ matrix[5][0] = 180; matrix[5][1] = -180; matrix[5][2] = -180; /* 5 */ matrix[6][0] = 180; matrix[6][1] = 180; matrix[6][2] = -180; /* 6 */ matrix[7][0] = -180; matrix[7][1] = 180; matrix[7][2] = -180; /* 7 */ cline[0] = 1; cline[1] = 2; cline[2] = 2; cline[3] = 3; cline[4] = 3; cline[5] = 4; cline[6] = 4; cline[7] = 1; cline[8] = 5; cline[9] = 6; cline[10] = 6; cline[11] = 7; cline[12] = 7; cline[13] = 8; cline[14] = 8; cline[15] = 5; cline[16] = 1; cline[17] = 5; cline[18] = 2; cline[19] = 6; cline[20] = 3; cline[21] = 7; cline[22] = 4; cline[23] = 8; planes[0][0] = 0; planes[0][1] = 1; planes[0][2] = 3; planes[1][0] = 1; planes[1][1] = 2; planes[1][2] = 3; planes[2][0] = 1; planes[2][1] = 5; planes[2][2] = 6; planes[3][0] = 1; planes[3][1] = 6; planes[3][2] = 2; planes[4][0] = 4; planes[4][1] = 0; planes[4][2] = 3; planes[5][0] = 4; planes[5][1] = 3; planes[5][2] = 7; planes[6][0] = 3; planes[6][1] = 2; planes[6][2] = 7; planes[7][0] = 7; planes[7][1] = 2; planes[7][2] = 6; planes[8][0] = 4; planes[8][1] = 1; planes[8][2] = 0; planes[9][0] = 4; planes[9][1] = 5; planes[9][2] = 1; planes[10][0] = 5; planes[10][1] = 4; planes[10][2] = 7; planes[11][0] = 5; planes[11][1] = 7; planes[11][2] = 6; } rmatrix = (float **) realloc(rmatrix, nofcoords * sizeof(float *)); mem_alloc_error(rmatrix); for (i = 0; i < nofcoords; i++) { rmatrix[i] = (float *) malloc(3 * sizeof(float)); mem_alloc_error(rmatrix[i]); } /* * Find the longest discance between all coordinates relative to the origin */ for (i = 0; i < nofcoords; i++) { j = (int) sqrt((pow(matrix[i][0], 2) + pow(matrix[i][1], 2) + pow(matrix[i][2], 2))); if (j > biggest) biggest = j; } /* * Scale every coordinate using the calculated factor */ scale = 280 / (float) biggest; for (i = 0; i < nofcoords; i++) { matrix[i][0] *= scale; matrix[i][1] *= scale; matrix[i][2] *= scale; } } /**** Application Management, I/O etc. *********** ************************************************/ void print_help(void) { printf("\nwmCube %s (%s)\n\n", WMCUBE_VERSION, REV_DATE); #ifndef SOLARIS printf (" -o : load external 3d-object(s).\n\n"); #else printf(" -o : load external 3d-object.\n\n"); #endif printf (" -d x: rotate x degrees/step when the cpu is idle. (default 1)\n"); printf (" -r x: rotate 1 degree faster every x percent of cpu-usage. (default 25)\n"); #ifdef LINUX printf (" -c x: which cpu (0,1,2..) to monitor. (default average over all)\n"); printf(" -n : exclude \"nice\" processes. (default OFF)\n"); #endif #ifdef SOLARIS printf (" -c x: which cpu (0,1,2..) to monitor. (default average over all)\n"); #endif #ifdef FREEBSD printf(" -n : exclude \"nice\" processes. (default OFF)\n"); #endif #ifdef NETBSD printf(" -n : exclude \"nice\" processes. (default OFF)\n"); #endif #ifdef OPENBSD printf(" -n : exclude \"nice\" processes. (default OFF)\n"); #endif printf(" -b : draw the cube in a brighter color. (default OFF)\n"); printf(" -s x: parse color 'x' and use to draw 3D shaded objects\n"); printf(" -i : invert cube speed. (default OFF)\n"); printf(" -p : do not display cpu-load (default OFF)\n"); printf(" -h : display this helptext.\n\n"); } void die(void) { fprintf(stderr, "%s: exiting", pname); exit(1); } #ifndef SOLARIS /* scan4objects doesnt work on Solaris because of alphasort */ int scan4objects(char *dir) { struct dirent **names; int n; n = scandir(dir, &names, 0, alphasort); while (n-- > 0) if (strstr(names[n]->d_name, ".wmc") != NULL) { objects[nof_objects] = (char *) malloc(strlen(dir) + strlen(names[n]->d_name) + 2); strcpy(objects[nof_objects], dir); if (dir[strlen(dir)] != '/') strcat(objects[nof_objects], "/"); strcat(objects[nof_objects++], names[n]->d_name); } return nof_objects; } #endif int next_object(void) { if (nof_objects == 0) return -1; setupobj(objects[rand() % (nof_objects)]); return 0; } int loadobj(char *filename) { FILE *fp; char tmp[64] = { "" }; int i = 0, counter = 1; /* printf("\nLoading file %s...",filename); fflush(stdout); */ if ((fp = fopen(filename, "rt")) == NULL) { printf("\nERROR: wmCube object-file not found (%s).\n\n", filename); exit(0); } fscanf(fp, "%63s", tmp); if (strcmp(tmp, "WMCUBE_COORDINATES") != 0) { printf ("\nError in objectfile: it must start with WMCUBE_COORDINATES\n\n"); fclose(fp); exit(0); } fscanf(fp, "%63s", tmp); counter = atoi(tmp); while ((strcmp(tmp, "WMCUBE_LINES") != 0) && (strcmp(tmp, "WMCUBE_PLANES") != 0)) { matrix = (float **) realloc(matrix, (i + 1) * sizeof(float *)); mem_alloc_error(matrix); matrix[i] = (float *) malloc(3 * sizeof(float)); mem_alloc_error(matrix[i]); fscanf(fp, "%f %f %f", &matrix[i][0], &matrix[i][1], &matrix[i][2]); /* printf("\n%d: %f %f %f",atoi(tmp), matrix[i][0],matrix[i][1],matrix[i][2]); */ if (atoi(tmp) != (++i)) { printf("\nError in objectfile (WMCUBE_COORDINATES section):\n" "the coordinates must be listed in order 1..n\n\n"); fclose(fp); exit(0); } fscanf(fp, "%63s", tmp); if (feof(fp)) { printf ("\nError in objectfile: you must have a section WMCUBE_LINES or WMCUBE_PLANES\n\n"); fclose(fp); exit(0); } } nofcoords = i; i = 0; if (strcmp(tmp, "WMCUBE_LINES") == 0) { planesORlines = 0; while (1) { cline = (int *) realloc(cline, (i + 2) * sizeof(int)); mem_alloc_error(cline); fscanf(fp, "%d %d", &cline[i++], &cline[i++]); /* printf("\n%d %d",cline[i-2],cline[i-1]); */ if (feof(fp)) break; if (cline[i - 2] > nofcoords || cline[i - 1] > nofcoords) { printf("\nError in objectfile (WMCUBE_LINES section):\n" "coordinates %d or/and %d doesnt exist\n\n", cline[i - 2], cline[i - 1]); fclose(fp); exit(0); } } noflines = i - 2; } else if (strcmp(tmp, "WMCUBE_PLANES") == 0) { planesORlines = 1; while (1) { planes = (int **) realloc(planes, (i + 1) * sizeof(int *)); mem_alloc_error(planes); planes[i] = (int *) malloc(3 * sizeof(int)); mem_alloc_error(planes[i]); fscanf(fp, "%d %d %d", &planes[i][0], &planes[i][1], &planes[i][2]); /* printf("\n%d: %d %d %d",i,planes[i][0],planes[i][1],planes[i][2]); */ planes[i][0]--; planes[i][1]--; planes[i][2]--; /* printf("\n%d: %d %d %d\n",i,planes[i][0],planes[i][1],planes[i][2]); */ if (feof(fp)) break; if (planes[i][0] > nofcoords || planes[i][1] > nofcoords || planes[i][2] > nofcoords) { printf("\nError in objectfile (WMCUBE_PLANES section):\n" "coordinates %d or/and %d or/and %d doesnt exist\n\n", planes[i][0], planes[i][1], planes[i][2]); fclose(fp); exit(0); } i++; } nofplanes = i; plane_color = (int *) malloc(nofplanes * sizeof(int)); mem_alloc_error(plane_color); zorder = (int *) malloc(nofplanes * sizeof(int)); mem_alloc_error(zorder); for (i = 0; i < nofplanes; i++) zorder[i] = i; } else { printf ("\nError in objectfile: you must have a section WMCUBE_LINES or WMCUBE_PLANES\n\n"); fclose(fp); exit(0); } fclose(fp); return 1; } void mem_alloc_error(void *block) { if (block == NULL) { printf("\nError allocating memory!\n\n"); exit(1); } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Begin System Specific Code. If you wish to port wmcube to a new platform, * you'll need to implement the following operations: * * int init_calc_cpu(); * Perform feature tests to determine whether wmcube can run, and set up * any files/data structures/etc. to gather statistics. * * int calc_cpu_total(); * return an integer reflecting the current CPU load */ #if defined LINUX /* * init_calc_cpu doesn't have much to do on Linux, but it can check to see if * /proc/stat is available; if the user selected to monitor a particular CPU, * it can check it's existence. */ int init_calc_cpu() { FILE *fp; int i; char cpuid[6]; char check_cpu[6]; snprintf(check_cpu, 6, "cpu%d", which_cpu); if ((fp = fopen("/proc/stat", "rb")) == NULL) { perror("/proc/stat required for this system"); return -1; } if (which_cpu == -1) return 0; for (i = -2; i < which_cpu; i++) { fscanf(fp, "%5s", cpuid); } if (strcmp(check_cpu, cpuid) != 0) { fprintf(stderr, "ERROR: could not read cpu-load on %s. Are you " "sure you have an SMP system?\n", check_cpu); return -1; } return (0); } int calc_cpu_total() { int total, used, t = 0, i; static int previous_total = 0, previous_used = 0; char cpuid[6]; int cpu, nice, system, idle; FILE *fp; fp = fopen("/proc/stat", "rt"); for (i = -2; i < which_cpu; i++) { fscanf(fp, "%5s %d %d %d %d", cpuid, &cpu, &nice, &system, &idle); } fclose(fp); used = cpu + system + use_nice * nice; total = used + idle + (1 - use_nice) * nice; t = 100 * (double) (used - previous_used) / (double) (total - previous_total); previous_total = total; previous_used = used; return t; } #elif defined SOLARIS #include #include #include static kstat_ctl_t *kc; static kstat_t **cpu_ksp_list; static kstat_t *the_cpu; static int ncpus; /* * The biggest subtlety of the Solaris port is that init_calc_cpu can be called * after the initial program setup. This occurs when a 'kstat state change' * occurs. Usually this means that a CPU has been taken on or off-line using * the psradm command. Another possibility is that on server systems, a new * CPU might have been hot-added to a running system. * * As a result, init_calc_cpu frees any resources it might have setup if needed, * and reinitializes everything. */ int init_calc_cpu() { kstat_t *ksp; int i = 0; if (kc == NULL) { if ((kc = kstat_open()) == NULL) { fprintf(stderr, "wmcube: can't open /dev/kstat\n"); return -1; } } if (which_cpu != -1) { /* * User selected to monitor a particular CPU. find it... */ for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { if ((strcmp(ksp->ks_module, "cpu_stat") == 0) && (ksp->ks_instance == which_cpu)) { the_cpu = ksp; break; } } if (the_cpu == NULL) { fprintf(stderr, "CPU %d not found\n", which_cpu); return -1; } } else { /* * User selected to monitor all CPUs. First, count them. */ for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { if (strcmp(ksp->ks_module, "cpu_stat") == 0) i++; } if (cpu_ksp_list) { free(cpu_ksp_list); } cpu_ksp_list = (kstat_t **) calloc(i * sizeof(kstat_t *), 1); ncpus = i; /* * stash the ksp for each CPU. */ i = 0; for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { if (strcmp(ksp->ks_module, "cpu_stat") == 0) { cpu_ksp_list[i] = ksp; i++; } } } return 0; } int calc_cpu_total() { int i; cpu_stat_t stat; static int previous_total = 0, previous_used = 0; int used, total, t, user = 0, wait = 0, kern = 0, idle = 0; /* * Read each cpu's data. If the kstat chain has changed (a state change * has happened, maybe a new cpu was added to the system or one went * away), then reinitialize everything with init_calc_cpu(). Finally, * recursively call calc_cpu_total. * * We'll need to do a little better than this in the future, since we * could recurse too much in the pathological case here. */ if (which_cpu == -1) { for (i = 0; i < ncpus; i++) { if (kstat_read(kc, cpu_ksp_list[i], (void *) &stat) == -1) { if (init_calc_cpu() != 0) { fprintf(stderr, "failed to " "reinitialize following state " "change\n"); return (-1); } return (calc_cpu_total()); } user += stat.cpu_sysinfo.cpu[CPU_USER]; /* user */ wait += stat.cpu_sysinfo.cpu[CPU_WAIT]; /* io wait */ kern += stat.cpu_sysinfo.cpu[CPU_KERNEL]; /* sys */ idle += stat.cpu_sysinfo.cpu[CPU_IDLE]; /*idle("free") */ } } else { if (kstat_read(kc, the_cpu, (void *) &stat) == -1) { if (init_calc_cpu() != 0) { fprintf(stderr, "failed to reinitialize " "following state change\n"); return (-1); } return (calc_cpu_total()); } user += stat.cpu_sysinfo.cpu[CPU_USER]; /* user */ wait += stat.cpu_sysinfo.cpu[CPU_WAIT]; /* io wait */ kern += stat.cpu_sysinfo.cpu[CPU_KERNEL]; /* sys */ idle += stat.cpu_sysinfo.cpu[CPU_IDLE]; /* idle("free") */ } used = user + wait + kern; total = used + idle; t = 100 * (double) (used - previous_used) / (double) (total - previous_total); previous_total = total; previous_used = used; return (t); } #elif defined FREEBSD #include #include #include int init_calc_cpu() { if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) == NULL) { printf("\nError: unable to open kvm\n\n"); exit(0); } kvm_nlist(kd, nlst); if (nlst[0].n_type == 0) { printf("\nError: unable to get nlist\n\n"); exit(1); } /* drop setgid & setuid (hi GOBBLES, who the fuck are you? */ seteuid(getuid()); setegid(getgid()); if (geteuid() != getuid() || getegid() != getgid()) { printf("Unable to drop privileges\n"); exit(1); } return 0; } int calc_cpu_total() { int total, used, t = 0; static int previous_total = 0, previous_used = 0; int cpu, nice, system, idle; unsigned long int cpu_time[CPUSTATES]; if (kvm_read(kd, nlst[0].n_value, &cpu_time, sizeof(cpu_time)) != sizeof(cpu_time)) { printf("\nError reading kvm\n\n"); exit(0); } cpu = cpu_time[CP_USER]; nice = cpu_time[CP_NICE]; system = cpu_time[CP_SYS]; idle = cpu_time[CP_IDLE]; used = cpu + system + use_nice * nice; total = used + idle + (1 - use_nice) * nice; t = 100 * (double) (used - previous_used) / (double) (total - previous_total); previous_total = total; previous_used = used; return t; } #elif defined OPENBSD #include #include #include int init_calc_cpu() { return 0; } int calc_cpu_total() { int total, used, t=0; static int previous_total = 0, previous_used = 0; int cpu,nice,system,idle; unsigned long int cpu_time[CPUSTATES]; int mib[2]; size_t size; mib[0] = CTL_KERN; mib[1] = KERN_CPTIME; size = sizeof (cpu_time); if (sysctl(mib, 2, &cpu_time, &size, NULL, 0) < 0) return 0; cpu = cpu_time[CP_USER]; nice = cpu_time[CP_NICE]; system = cpu_time[CP_SYS]; idle = cpu_time[CP_IDLE]; used = cpu + system + use_nice*nice; total = used + idle + (1-use_nice)*nice; t = 100 * (double)(used - previous_used) / (double)(total - previous_total); previous_total = total; previous_used = used; return t; } #elif defined NETBSD /* END OPENBSD */ #include #include int init_calc_cpu() { return 0; } int calc_cpu_total() { static u_int64_t last_cp_time[CPUSTATES] = { 0, 0, 0, 0, 0 }; u_int64_t curr_cp_time[CPUSTATES]; u_int64_t total_time = 0, idle_time = 0; int mib[2]; int i; size_t ssize; const int IDLE_TIME = 4; const int NICE_TIME = 1; ssize = sizeof(curr_cp_time); mib[0] = CTL_KERN; mib[1] = KERN_CP_TIME; if (sysctl(mib, 2, curr_cp_time, &ssize, NULL, 0)) { fprintf(stderr, "wmcube: unable to read CP_TIME from sysctl()\n"); exit(0); } if (!use_nice) curr_cp_time[NICE_TIME] = 0; /* NetBSD gives 5 CPUSTATES - * User, Nice, System, Interrupt, Idle */ idle_time = curr_cp_time[IDLE_TIME] - last_cp_time[IDLE_TIME]; for (i = 0; i < CPUSTATES; i++) { total_time += (curr_cp_time[i] - last_cp_time[i]); last_cp_time[i] = curr_cp_time[i]; } /* Calculate the % CPU usage as the User+Nice+System+Interrupt/Total * for the interval */ return (100 * (int) (total_time - idle_time) / total_time); } #else /* END NETBSD */ /* * This is a stub which will compile for platforms other than LINUX or SOLARIS. * Use these to start your port to a new platform. */ int init_calc_cpu() { return 0; } int calc_cpu_total() { return 0; } #endif /* OS SPECIFIC CODE */