00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 #ifdef HAVE_CONFIG_H
00046 #include "config.h"
00047 #endif
00048
00049 #include <ctype.h>
00050 #include <errno.h>
00051 #include <math.h>
00052 #include <setjmp.h>
00053 #include <stdarg.h>
00054 #include <stddef.h>
00055 #include <stdio.h>
00056 #include <stdlib.h>
00057 #include <string.h>
00058 #include <sys/time.h>
00059 #include <unistd.h>
00060 #include <signal.h>
00061
00062 #include <X11/Xlib.h>
00063 #include <X11/Xutil.h>
00064
00065 #include <gnome.h>
00066
00067 #define NELS(a) (sizeof(a) / sizeof(*a))
00068
00069 #ifdef HAVE_LIBGTOP
00070 #include <glibtop.h>
00071 #include <glibtop/union.h>
00072 typedef struct
00073 {
00074 glibtop_cpu cpu;
00075 glibtop_mem mem;
00076 glibtop_swap swap;
00077 glibtop_uptime uptime;
00078 glibtop_loadavg loadavg;
00079 glibtop_netload netload;
00080 }
00081 gtop_struct;
00082 #endif
00083
00084 #include "emcglb.h"
00085
00086 static char *prog_name = "emcstripchart";
00087 static char *prog_version = "1.6";
00088 static char *config_file = NULL;
00089 static float chart_interval = 0.5;
00090 static float chart_filter = 0.0;
00091 static float slider_interval = 0.2;
00092 static float slider_filter = 0.0;
00093 static float update_interval = 0.01;
00094 static int include_menubar = 0;
00095 static int include_slider = 1;
00096 static int timingcomp = 0;
00097 static int status_outline = 0;
00098 static int minor_tick=100, major_tick=0;
00099 static int geometry_flags;
00100 static int geometry_w=300, geometry_h=100;
00101 static int geometry_x, geometry_y;
00102 static int root_width, root_height;
00103 static int update_count = 0;
00104 static int update_chart = 0;
00105 GtkWidget *drawing=NULL;
00106 GtkWidget *slider=NULL;
00107 int update_timer_count = 0;
00108
00109 extern double gstrip_nml_get(void *);
00110 extern void * gstrip_nml_open(const char *);
00111 extern int nml_new_data();
00112 extern double gstrip_emcmot_get(void *);
00113 extern void * gstrip_emcmot_open(const char *);
00114 extern int emcIniLoad(const char *filename);
00115
00116
00117
00118
00119
00120 static int
00121 streq(const char *s1, const char *s2)
00122 {
00123 return strcasecmp(s1, s2) == 0;
00124 }
00125
00126
00127
00128
00129 static int
00130 isident(int c)
00131 {
00132 return isalnum(c) || c=='-' || c=='_';
00133 }
00134
00135
00136
00137
00138 static void
00139 digit_shift(char *str, char *digits, int width, int dpos)
00140 {
00141 int w;
00142 if (++dpos <= 0)
00143 {
00144 *str++ = '.';
00145 for (w = 1; w < width; w++)
00146 *str++ = (++dpos <= 0) ? '0' : *digits++;
00147 }
00148 else
00149 for (w = 0; w < width; w++)
00150 {
00151 *str++ = *digits++;
00152 if (--dpos == 0)
00153 {
00154 *str++ = '.';
00155 w++;
00156 }
00157 }
00158 }
00159
00160
00161
00162
00163 static void
00164 hi_lo_fmt(double hv, char *hs, double lv, char *ls)
00165 {
00166 int e, p, t, f;
00167 char s[100];
00168
00169 sprintf(s, "% 22.16e", hv);
00170 e = atoi(s+20);
00171 s[2] = s[1]; s[1] = '0';
00172 t = 3 * ((e - (e < 0)) / 3);
00173 p = e - t;
00174 hs[0] = s[0];
00175 digit_shift(hs+1, s+2, 4, p);
00176 hs[6] = '\0';
00177 if (0 <= t && t <= 5)
00178 hs[5] = "\0KMGTP"[t/3];
00179 else
00180 sprintf(hs+5, "e%+d", t);
00181
00182 if (ls)
00183 {
00184 sprintf(s, "% 22.16e", lv);
00185 f = atoi(s+20);
00186 s[2] = s[1]; s[1] = '0';
00187 p = f - t;
00188 ls[0] = s[0];
00189 digit_shift(ls+1, s+2, 4, p);
00190 ls[6] = '\0';
00191 if (0 <= t && t <= 5)
00192 ls[5] = "\0KMGTP"[t/3];
00193 else
00194 sprintf(ls+5, "e%+d", t);
00195 }
00196 }
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207 typedef struct
00208 {
00209 char *eqn_base, *eqn_src;
00210 double t_diff;
00211 int vars;
00212
00213 char *s;
00214 jmp_buf err_jmp;
00215 float val;
00216
00217 double *last, *now;
00218 #ifdef HAVE_LIBGTOP
00219 gtop_struct *gtp_now, *gtp_last;
00220 #endif
00221 }
00222 Expr;
00223
00224
00225
00226
00227
00228
00229
00230
00231 static void
00232 eval_error(Expr *e, char *msg, ...)
00233 {
00234 va_list args;
00235 e->val = 0.0;
00236 if (update_chart)
00237 longjmp(e->err_jmp, 1);
00238 fflush(stdout);
00239 va_start(args, msg);
00240 fprintf(stderr, "%s: %s: ", prog_name, e->eqn_src? e->eqn_src: "");
00241 vfprintf(stderr, msg, args);
00242 fprintf(stderr, "\n");
00243 va_end(args);
00244 exit(EXIT_FAILURE);
00245 }
00246
00247
00248
00249
00250 static char *
00251 trimtb(char *s)
00252 {
00253 char *e = s + strlen(s) - 1;
00254 while (e >= s && isspace(*e))
00255 *e-- = '\0';
00256 return s;
00257 }
00258
00259
00260
00261
00262 static char *
00263 skipbl(char *s)
00264 {
00265 while (isspace(*s))
00266 s++;
00267 return s;
00268 }
00269
00270
00271
00272
00273 static void
00274 stripbl(Expr *e, int skip)
00275 {
00276 e->s = skipbl(e->s + skip);
00277 }
00278
00279 #ifdef HAVE_LIBGTOP
00280 typedef struct
00281 {
00282 char *name;
00283 char type;
00284 int *used;
00285 size_t off;
00286 }
00287 Gtop_data;
00288
00289
00290
00291
00292
00293
00294 static int gtop_cpu;
00295 static int gtop_mem;
00296 static int gtop_swap;
00297 static int gtop_uptime;
00298 static int gtop_loadavg;
00299 static int gtop_netload;
00300
00301 #define GTOP_OFF(el) offsetof(gtop_struct, el)
00302
00303 Gtop_data gtop_vars[] =
00304 {
00305
00306 { "cpu_total", 'L', >op_cpu, GTOP_OFF(cpu.total) },
00307 { "cpu_user", 'L', >op_cpu, GTOP_OFF(cpu.user) },
00308 { "cpu_nice", 'L', >op_cpu, GTOP_OFF(cpu.nice) },
00309 { "cpu_sys", 'L', >op_cpu, GTOP_OFF(cpu.sys) },
00310 { "cpu_idle", 'L', >op_cpu, GTOP_OFF(cpu.idle) },
00311 { "cpu_freq", 'L', >op_cpu, GTOP_OFF(cpu.frequency) },
00312
00313
00314 { "mem_total", 'L', >op_mem, GTOP_OFF(mem.total) },
00315 { "mem_used", 'L', >op_mem, GTOP_OFF(mem.used) },
00316 { "mem_free", 'L', >op_mem, GTOP_OFF(mem.free) },
00317 { "mem_shared", 'L', >op_mem, GTOP_OFF(mem.shared) },
00318 { "mem_buffer", 'L', >op_mem, GTOP_OFF(mem.buffer) },
00319 { "mem_cached", 'L', >op_mem, GTOP_OFF(mem.cached) },
00320 { "mem_user", 'L', >op_mem, GTOP_OFF(mem.user) },
00321 { "mem_locked", 'L', >op_mem, GTOP_OFF(mem.locked) },
00322
00323
00324 { "swap_total", 'L', >op_swap, GTOP_OFF(swap.total) },
00325 { "swap_used", 'L', >op_swap, GTOP_OFF(swap.used) },
00326 { "swap_free", 'L', >op_swap, GTOP_OFF(swap.free) },
00327 { "swap_pagein", 'L', >op_swap, GTOP_OFF(swap.pageout) },
00328 { "swap_pageout", 'L', >op_swap, GTOP_OFF(swap.pagein) },
00329
00330
00331 { "uptime", 'D', >op_uptime, GTOP_OFF(uptime.uptime) },
00332 { "idletime", 'D', >op_uptime, GTOP_OFF(uptime.idletime) },
00333
00334
00335 { "loadavg_running", 'L', >op_loadavg, GTOP_OFF(loadavg.nr_running) },
00336 { "loadavg_tasks", 'L', >op_loadavg, GTOP_OFF(loadavg.nr_tasks) },
00337 { "loadavg_1m", 'D', >op_loadavg, GTOP_OFF(loadavg.loadavg[0]) },
00338 { "loadavg_5m", 'D', >op_loadavg, GTOP_OFF(loadavg.loadavg[1]) },
00339 { "loadavg_15m", 'D', >op_loadavg, GTOP_OFF(loadavg.loadavg[2]) },
00340
00341
00342 { "net_pkts_in", 'L', >op_netload, GTOP_OFF(netload.packets_in) },
00343 { "net_pkts_out", 'L', >op_netload, GTOP_OFF(netload.packets_out) },
00344 { "net_pkts_total", 'L', >op_netload, GTOP_OFF(netload.packets_total) },
00345
00346 { "net_bytes_in", 'L', >op_netload, GTOP_OFF(netload.bytes_in) },
00347 { "net_bytes_out", 'L', >op_netload, GTOP_OFF(netload.bytes_out) },
00348 { "net_bytes_total", 'L', >op_netload, GTOP_OFF(netload.bytes_total) },
00349
00350 { "net_errs_in", 'L', >op_netload, GTOP_OFF(netload.errors_in) },
00351 { "net_errs_out", 'L', >op_netload, GTOP_OFF(netload.errors_out) },
00352 { "net_errs_total", 'L', >op_netload, GTOP_OFF(netload.errors_total) },
00353
00354
00355 { NULL, 0, NULL, 0 }
00356 };
00357
00358
00359
00360
00361 static int
00362 gtop_value(
00363 char *str, int delta,
00364 gtop_struct *gtp_now, gtop_struct *gtp_last, double *val)
00365 {
00366 int i;
00367 for (i=0; gtop_vars[i].name; i++)
00368 {
00369 if (streq(str, gtop_vars[i].name))
00370 {
00371 char *cp = ((char *)gtp_now) + gtop_vars[i].off;
00372 if (update_chart == 0)
00373 {
00374 (*gtop_vars[i].used)++;
00375 *val = 0;
00376 }
00377 else if (gtop_vars[i].type == 'D')
00378 {
00379 double df = *((double *)cp);
00380 if (delta)
00381 {
00382 cp = ((char *)gtp_last) + gtop_vars[i].off;
00383 df -= *((double *)cp);
00384 }
00385 *val = df;
00386 }
00387 else
00388 {
00389 unsigned long ul = *((unsigned long *)cp);
00390 if (delta)
00391 {
00392 cp = ((char *)gtp_last) + gtop_vars[i].off;
00393 ul -= *((unsigned long *)cp);
00394 }
00395 *val = ul;
00396 }
00397 return 1;
00398 }
00399 }
00400 return 0;
00401 }
00402
00403
00404
00405
00406
00407 static void
00408 get_all_netload(glibtop_netload *netload)
00409 {
00410 FILE *fd;
00411 memset(netload, 0, sizeof(*netload));
00412 if ((fd = fopen("/proc/net/dev", "r")) != NULL)
00413 {
00414 unsigned long bytes_in, pkts_in, errs_in, bytes_out, pkts_out, errs_out;
00415 fscanf(fd, "%*[^\n]\n%*[^\n]\n");
00416 while (fscanf(fd,
00417 "%*[^:]:%ld%ld%ld%*d%*d%*d%*d%*d%ld%ld%ld%*d%*d%*d%*d%*d",
00418 &bytes_in, &pkts_in, &errs_in, &bytes_out, &pkts_out, &errs_out) == 6)
00419 {
00420 netload->packets_in += pkts_in;
00421 netload->packets_out += pkts_out;
00422 netload->packets_total += pkts_in + pkts_out;
00423 netload->bytes_in += bytes_in;
00424 netload->bytes_out += bytes_out;
00425 netload->bytes_total += bytes_in + bytes_out;
00426 netload->errors_in += errs_in;
00427 netload->errors_out += errs_out;
00428 netload->errors_total += errs_in + errs_out;
00429 }
00430 fclose(fd);
00431 }
00432 }
00433 #endif
00434
00435
00436
00437
00438
00439 static double add_op(Expr *e);
00440
00441
00442
00443
00444
00445 static double
00446 num_op(Expr *e)
00447 {
00448 double val=0;
00449 if (isdigit(*e->s) || (*e->s && strchr("+-.", *e->s) && isdigit(e->s[1])))
00450 {
00451 char *r;
00452 val = strtod(e->s, &r);
00453 stripbl(e, (int)(r - e->s));
00454 }
00455 else if (*e->s == '(')
00456 {
00457 stripbl(e, 1);
00458 val = add_op(e);
00459 if (*e->s == ')')
00460 stripbl(e, 1);
00461 else
00462 eval_error(e, _("rparen expected"));
00463 }
00464 else if (*e->s == '$' || *e->s == '~')
00465 {
00466 int c, id_intro;
00467 char *idp, id[1000];
00468
00469 id_intro = *e->s++;
00470 for (idp = id; isalnum(c = (*idp++ = *e->s++)) || c == '_'; )
00471 ;
00472 idp[-1] = '\0';
00473 e->s--;
00474
00475 if (isdigit(*id))
00476 {
00477 int id_num = atoi(id);
00478 if (id_num > e->vars)
00479 eval_error(e, _("no such field: %d"), id_num);
00480 val = e->now[id_num-1];
00481 if (id_intro == '~')
00482 val -= e->last[id_num-1];
00483 }
00484 else if (streq(id, "i"))
00485 {
00486 val = chart_interval;
00487
00488 }
00489 else if (streq(id, "t"))
00490 {
00491 val = e->t_diff;
00492
00493 }
00494 else if (streq(id, "u"))
00495 {
00496 val = update_count;
00497 }
00498 else if (streq(id, "c"))
00499 {
00500 val = update_chart;
00501 }
00502 #ifdef HAVE_LIBGTOP
00503 else if (gtop_value(id, id_intro == '~', e->gtp_now, e->gtp_last, &val))
00504 ;
00505 #endif
00506 else if (!*id)
00507 eval_error(e, _("missing variable identifer"));
00508 else
00509 eval_error(e, _("invalid variable identifer: %s"), id);
00510 stripbl(e, 0);
00511 }
00512 else
00513 eval_error(e, _("number expected"));
00514 return val;
00515 }
00516
00517
00518
00519
00520 static double
00521 mul_op(Expr *e)
00522 {
00523 double val1 = num_op(e);
00524 while (*e->s=='*' || *e->s=='/' || *e->s=='%')
00525 {
00526 char c = *e->s;
00527 stripbl(e, 1);
00528 if (c == '*')
00529 val1 *= num_op(e);
00530 else
00531 {
00532 double val2 = num_op(e);
00533 if (val2 == 0)
00534 val1 = 0;
00535 else if (c == '/')
00536 val1 /= val2;
00537 else
00538 val1 = fmod(val1, val2);
00539 }
00540 }
00541 return val1;
00542 }
00543
00544
00545
00546
00547 static double
00548 add_op(Expr *e)
00549 {
00550 double val = mul_op(e);
00551 while (*e->s=='+' || *e->s=='-')
00552 {
00553 char c = *e->s;
00554 stripbl(e, 1);
00555 if (c == '+')
00556 val += mul_op(e);
00557 else
00558 val -= mul_op(e);
00559 }
00560 return val;
00561 }
00562
00563
00564
00565
00566 static double eval(
00567 char *eqn, char *src, double t_diff,
00568 #ifdef HAVE_LIBGTOP
00569 gtop_struct *gtp_now,
00570 gtop_struct *gtp_last,
00571 #endif
00572 int vars, double *last, double *now )
00573 {
00574 Expr e;
00575 e.eqn_base = e.s = eqn;
00576 e.eqn_src = src;
00577 e.vars = vars;
00578 e.last = last;
00579 e.now = now;
00580 e.t_diff = t_diff;
00581 #ifdef HAVE_LIBGTOP
00582 e.gtp_now = gtp_now;
00583 e.gtp_last = gtp_last;
00584 #endif
00585
00586 if (setjmp(e.err_jmp))
00587 return e.val;
00588
00589 stripbl(&e, 0);
00590 e.val = add_op(&e);
00591 if (*e.s)
00592 eval_error(&e, _("extra gunk at end: \"%s\""), e.s);
00593
00594 return e.val;
00595 }
00596
00597
00598
00599
00600 typedef struct
00601 {
00602 char active;
00603 char is_led;
00604 char id_char;
00605 char *ident;
00606 char *filename;
00607 char *pattern;
00608 char *eqn;
00609 char *eqn_src;
00610 float hi, lo;
00611 float top, bot;
00612 char *color_name;
00613 GdkColor gdk_color;
00614 GdkGC *gdk_gc;
00615 int num_leds;
00616 GdkColor *led_color;
00617 GdkGC **led_gc;
00618 int vars;
00619 double *last, *now;
00620 float *val;
00621 void *nml_data;
00622 void *emcmot_data;
00623 }
00624 Param;
00625
00626
00627
00628
00629 typedef struct
00630 {
00631 int params;
00632 Param **parray;
00633 int max_val;
00634 int num_val;
00635 int new_val;
00636 double lpf_const;
00637 double t_diff;
00638 struct timeval t_last, t_now;
00639 #ifdef HAVE_LIBGTOP
00640 gtop_struct gtop_now, gtop_last;
00641 #endif
00642 }
00643 Param_glob;
00644
00645 static Param_glob chart_glob, slider_glob;
00646
00647
00648
00649
00650 static void no_display(void);
00651 static void numeric_with_ident(void);
00652 static void numeric_with_graph(void);
00653 static void gtk_graph(void);
00654
00655
00656
00657
00658 static void (*display)(void) = gtk_graph;
00659
00660
00661
00662
00663 static void
00664 defns_error(char *fn, int ln, char *fmt, ...)
00665 {
00666 va_list args;
00667 fflush(stdout);
00668 va_start(args, fmt);
00669 fprintf(stderr, "%s: ", prog_name);
00670 if (fn)
00671 fprintf(stderr, _("%s, line %d: "), fn, ln);
00672 vfprintf(stderr, fmt, args);
00673 fprintf(stderr, "\n");
00674 va_end(args);
00675 exit(EXIT_FAILURE);
00676 }
00677
00678
00679
00680
00681
00682
00683
00684 static int
00685 split(char *str, char **key, char **val)
00686 {
00687 int p=0;
00688 *key = *val = NULL;
00689 str = skipbl(str);
00690 if (isalpha(*str))
00691 {
00692 p = 1;
00693 *key = str;
00694 while (isident(*str))
00695 str++;
00696 if (*str)
00697 {
00698 *str++ = '\0';
00699 while (isspace(*str))
00700 str++;
00701 if (*str)
00702 {
00703 *val = str;
00704 p = 2;
00705 }
00706 }
00707 }
00708 return p;
00709 }
00710
00711
00712
00713
00714 static int
00715 yes_no(char *str)
00716 {
00717 if (str)
00718 {
00719 str = skipbl(str);
00720 if (*str == '1' || *str == 'y' || *str == 'Y')
00721 return 1;
00722 if (streq("on", str) || streq("true", str))
00723 return 1;
00724 }
00725 return 0;
00726 }
00727
00728
00729
00730
00731
00732
00733 static int
00734 read_param_defns(Param_glob *pgp)
00735 {
00736 int i, j, lineno = 0, params = 0;
00737 Param **p = NULL;
00738 char fn[FILENAME_MAX], home_fn[FILENAME_MAX], etc_fn[FILENAME_MAX];
00739 #ifdef CONFDIR
00740 char conf_fn[FILENAME_MAX];
00741 #endif
00742 FILE *fd;
00743
00744 if (config_file)
00745 {
00746 strcpy(fn, config_file);
00747 if ((fd=fopen(fn, "r")) == NULL)
00748 defns_error(NULL, 0, _("can't open config file \"%s\""), config_file);
00749 }
00750 else
00751 {
00752
00753 sprintf(fn, "%s", "emcstripchart.conf");
00754 if ((fd=fopen(fn, "r")) == NULL)
00755 {
00756
00757 sprintf(fn, "%s/%s", getenv("HOME"), ".emcstripchart.conf");
00758 strcpy(home_fn, fn);
00759 if ((fd=fopen(fn, "r")) == NULL)
00760 {
00761
00762 strcpy(fn, "/etc/emcstripchart.conf");
00763 strcpy(etc_fn, fn);
00764 if ((fd=fopen(fn, "r")) == NULL)
00765 {
00766 #ifdef CONFDIR
00767
00768 sprintf(fn, "%s/%s", CONFDIR, "emcstripchart.conf");
00769 strcpy(conf_fn, fn);
00770 if ((fd=fopen(fn, "r")) == NULL)
00771 #endif
00772 {
00773 #ifdef CONFDIR
00774 defns_error(NULL, 0,
00775 _("can't open config file \"./emcstripchart.conf\", "
00776 "\"%s\", \"%s\", or \"%s\""),
00777 home_fn, etc_fn, conf_fn);
00778 #else
00779 defns_error(NULL, 0,
00780 _("can't open config file \"./emcstripchart.conf\", "
00781 "\"%s\", or \"%s\""),
00782 home_fn, etc_fn);
00783 #endif
00784 }
00785 }
00786 }
00787 }
00788 }
00789
00790 while (!feof(fd) && !ferror(fd))
00791 {
00792 char *bp, buf[1000];
00793 if (fgets(buf, sizeof(buf), fd))
00794 {
00795 lineno++;
00796 bp = skipbl(buf);
00797 if (*bp && *bp != '#')
00798 {
00799 char *key, *val;
00800 trimtb(bp);
00801 split(bp, &key, &val);
00802
00803
00804
00805
00806
00807 if (streq(key, "chart-interval"))
00808 chart_interval = atof(val);
00809 else if (streq(key, "chart-filter"))
00810 chart_filter = atof(val);
00811 else if (streq(key, "slider-interval"))
00812 slider_interval = atof(val);
00813 else if (streq(key, "update-interval"))
00814 {
00815 update_interval = atof(val);
00816 if(update_interval > 0.0005)
00817 {
00818 minor_tick = (int) (1.0/update_interval);
00819 minor_tick += (10 - minor_tick%10)%10;
00820 major_tick = minor_tick;
00821 }
00822 #if 0
00823 printf("update_interval = %f;\tminor_tick=%d\n",update_interval,minor_tick);
00824 #endif
00825 }
00826 else if (streq(key, "slider-filter"))
00827 slider_filter = atof(val);
00828 else if (streq(key, "menu"))
00829 include_menubar = yes_no(val);
00830 else if (streq(key, "timingcomp"))
00831 timingcomp = yes_no(val);
00832 else if (streq(key, "slider"))
00833 include_slider = yes_no(val);
00834 else if (streq(key, "status-outline"))
00835 status_outline = yes_no(val);
00836 else if (streq(key, "minor_ticks"))
00837 minor_tick = atoi(val);
00838 else if (streq(key, "major_ticks"))
00839 major_tick = atoi(val);
00840 else if (streq(key, "type"))
00841 {
00842 if (streq("none", val))
00843 display = no_display;
00844 else if (streq("text", val))
00845 display = numeric_with_ident;
00846 else if (streq("graph", val))
00847 display = numeric_with_graph;
00848 else if (streq("gtk", val))
00849 display = gtk_graph;
00850 else
00851 defns_error(
00852 fn, lineno, _("invalid display type: %s"), val);
00853 }
00854
00855
00856
00857
00858 else if (streq(key, "identifier") || streq(key, "begin"))
00859 {
00860 params++;
00861 p = realloc(p, params * sizeof(*p));
00862 p[params-1] = malloc(sizeof(*p[params-1]));
00863 p[params-1]->ident = strdup(val);
00864 p[params-1]->active = 1;
00865 p[params-1]->is_led = 0;
00866 p[params-1]->vars = 0;
00867 p[params-1]->id_char = '*';
00868 p[params-1]->pattern = NULL;
00869 p[params-1]->filename = NULL;
00870 p[params-1]->eqn = NULL;
00871 p[params-1]->eqn_src = NULL;
00872 p[params-1]->color_name = NULL;
00873 p[params-1]->num_leds = 0;
00874 p[params-1]->led_color = NULL;
00875 p[params-1]->led_gc = NULL;
00876 p[params-1]->nml_data=NULL;
00877 p[params-1]->emcmot_data=NULL;
00878 p[params-1]->hi = p[params-1]->top = 1.0;
00879 p[params-1]->lo = p[params-1]->bot = 0.0;
00880 }
00881 else if (streq(key, "end"))
00882 {
00883 if (!streq(p[params-1]->ident, val))
00884 defns_error(fn, lineno, "found %s when expecting %s",
00885 val, p[params-1]->ident);
00886 }
00887 else if (params == 0)
00888 defns_error(fn, lineno,_("identifier or begin must be first"));
00889 else if (streq(key, "id_char"))
00890 p[params-1]->id_char = val[0];
00891 else if (streq(key, "color"))
00892 {
00893 p[params-1]->color_name = strdup(val);
00894 if (!gdk_color_parse(val, &p[params-1]->gdk_color))
00895 defns_error(fn, lineno, _("unrecognized color: %s"), val);
00896 }
00897 else if (streq(key, "lights"))
00898 {
00899 int n;
00900 Param *pp = p[params-1];
00901 char *t = strtok(val, ",");
00902 for (n = 0; t != NULL; n++, t = strtok(NULL, ","))
00903 {
00904 char *cname = strdup(skipbl(t));
00905 trimtb(cname);
00906 pp->led_color = realloc(
00907 pp->led_color, (n+1) * sizeof(*pp->led_color));
00908 if (!gdk_color_parse(cname, &pp->led_color[n]))
00909 {
00910 defns_error(
00911 fn, lineno, _("unrecognized color: %s"), cname);
00912 }
00913 free(cname);
00914 }
00915 pp->num_leds = n;
00916 pp->is_led = 1;
00917 }
00918 else if (streq(key, "active"))
00919 p[params-1]->active = yes_no(val);
00920 else if (streq(key, "filename"))
00921 p[params-1]->filename = strdup(val);
00922 else if (streq(key, "pattern"))
00923 p[params-1]->pattern = strdup(val);
00924 else if (streq(key, "fields"))
00925 p[params-1]->vars = atoi(val);
00926 else if (streq(key, "equation"))
00927 {
00928 char src[FILENAME_MAX+20];
00929 sprintf(src, "%s, line %d", fn, lineno);
00930 p[params-1]->eqn_src = strdup(src);
00931 p[params-1]->eqn = strdup(val);
00932 }
00933 else if (streq(key, "maximum"))
00934 p[params-1]->hi = p[params-1]->top = atof(val);
00935 else if (streq(key, "minimum"))
00936 p[params-1]->lo = p[params-1]->bot = atof(val);
00937 else if (streq(key, "nml"))
00938 p[params-1]->nml_data = gstrip_nml_open(val);
00939 else if (streq(key, "emcmot"))
00940 p[params-1]->emcmot_data = gstrip_emcmot_open(val);
00941 else
00942 defns_error(fn, lineno, _("invalid option: \"%s\""), bp);
00943 }
00944 }
00945 }
00946 fclose(fd);
00947
00948
00949 for (i=0; i<params; i++)
00950 {
00951 p[i]->val = malloc(pgp->max_val * sizeof(p[i]->val[0]));
00952 p[i]->last = malloc(p[i]->vars * sizeof(p[i]->last[0]));
00953 p[i]->now = malloc(p[i]->vars * sizeof(p[i]->now[0]));
00954
00955
00956
00957 for (j = 0; j < p[i]->vars; j ++)
00958 p[i]->now[j] = 0;
00959 }
00960
00961 pgp->params = params;
00962 pgp->parray = p;
00963 return params;
00964 }
00965
00966
00967
00968
00969 static int
00970 split_and_extract(char *str, Param *p)
00971 {
00972 int i = 0;
00973 char *t = strtok(str, " \t:");
00974 while (t && i < p->vars)
00975 {
00976 p->now[i] = atof(t);
00977 t = strtok(NULL, " \t:");
00978 i++;
00979 }
00980 return i;
00981 }
00982
00983
00984
00985
00986 static double
00987 cap(double x)
00988 {
00989 static const double ranges[] = { .1,.2,.5, 1,2,5, 10,20,50 };
00990
00991 static const double pow10[] =
00992 {
00993 1e-30, 1e-29, 1e-28, 1e-27, 1e-26, 1e-25, 1e-24, 1e-23, 1e-22, 1e-21,
00994 1e-20, 1e-19, 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11,
00995 1e-10, 1e-09, 1e-08, 1e-07, 1e-06, 1e-05, 1e-04, 1e-03, 1e-02, 1e-01,
00996 1e+00, 1e+01, 1e+02, 1e+03, 1e+04, 1e+05, 1e+06, 1e+07, 1e+08, 1e+09,
00997 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19,
00998 1e+20, 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e30
00999 };
01000
01001 int e, f, j;
01002 double d;
01003
01004 if (x < pow10[1] || pow10[NELS(pow10)-2] < x)
01005 {
01006 errno = EDOM;
01007 return x;
01008 }
01009
01010 frexp( x, &e );
01011 f = e * 0.90308998699194;
01012 j = f % 3 + 3;
01013 d = pow10[ 30 + f / 3 ];
01014
01015 while (ranges[j] * d > x) --j;
01016 while (ranges[j] * d < x) ++j;
01017
01018 return ranges[j] * d;
01019 }
01020
01021 int redundant_timer_count =0;
01022 int old_data_count = 0;
01023
01024 static void
01025 update_values(Param_glob *pgp, Param_glob *slave_pgp)
01026 {
01027 int param_num, last_val_pos, next_val_pos, missed,i, new_data;
01028
01029 update_count++;
01030 pgp->t_last = pgp->t_now;
01031 gettimeofday(&pgp->t_now, NULL);
01032 pgp->t_diff = (pgp->t_now.tv_sec - pgp->t_last.tv_sec) +
01033 (pgp->t_now.tv_usec - pgp->t_last.tv_usec) / 1e6;
01034
01035 if(timingcomp)
01036 {
01037 if(pgp->t_diff < update_interval/2)
01038 {
01039 pgp->t_now = pgp->t_last;
01040 update_count--;
01041 update_timer_count--;
01042 redundant_timer_count++;
01043 return;
01044 }
01045 redundant_timer_count = 0;
01046 }
01047
01048 #ifdef HAVE_LIBGTOP
01049 pgp->gtop_last = pgp->gtop_now;
01050 if (gtop_cpu)
01051 glibtop_get_cpu(&pgp->gtop_now.cpu);
01052 if (gtop_mem)
01053 glibtop_get_mem(&pgp->gtop_now.mem);
01054 if (gtop_swap)
01055 glibtop_get_swap(&pgp->gtop_now.swap);
01056 if (gtop_uptime)
01057 glibtop_get_uptime(&pgp->gtop_now.uptime);
01058 if (gtop_loadavg)
01059 glibtop_get_loadavg(&pgp->gtop_now.loadavg);
01060 if (gtop_netload)
01061 get_all_netload(&pgp->gtop_now.netload);
01062 #endif
01063
01064 if (update_chart < 3)
01065 {
01066 last_val_pos = 0;
01067 pgp->num_val = next_val_pos = 1;
01068 }
01069 else
01070 {
01071 last_val_pos = pgp->new_val;
01072 if (pgp->num_val < pgp->max_val)
01073 pgp->num_val++;
01074 next_val_pos = ++pgp->new_val;
01075 if (next_val_pos >= pgp->max_val)
01076 next_val_pos = pgp->new_val = 0;
01077 }
01078 new_data = 0;
01079
01080 for (param_num = 0; param_num < pgp->params; param_num++)
01081 {
01082 if (pgp->parray[param_num]->active)
01083 {
01084 Param *p = pgp->parray[param_num];
01085 double prev, val = 0;
01086 FILE *pu = NULL;
01087 char buf[1000];
01088
01089 if (p->filename)
01090 {
01091 if (*p->filename == '|')
01092 pu = popen(p->filename+1, "r");
01093 else
01094 pu = fopen(p->filename, "r");
01095 }
01096
01097 *buf = '\0';
01098 if (pu)
01099 {
01100 fgets(buf, sizeof(buf), pu);
01101 if (p->pattern)
01102 while (!ferror(pu) && !feof(pu) && !strstr(buf, p->pattern))
01103 fgets(buf, sizeof(buf), pu);
01104 if (*p->filename == '|') pclose(pu); else fclose(pu);
01105 }
01106
01107
01108
01109 memcpy(p->last, p->now, p->vars * sizeof(p->last[0]));
01110 if(p->nml_data)
01111 {
01112 val = gstrip_nml_get(p->nml_data);
01113 if(p->eqn)
01114 {
01115 p->vars = 1;
01116 p->now[0] = val;
01117 val = eval(p->eqn, p->eqn_src, pgp->t_diff,
01118 p->vars, p->last, p->now);
01119 }
01120 if(nml_new_data())
01121 {
01122 new_data=1;
01123 }
01124 }
01125 else if(p->emcmot_data)
01126 {
01127 val = gstrip_emcmot_get(p->emcmot_data);
01128 if(p->eqn)
01129 {
01130 p->vars = 1;
01131 p->now[0] = val;
01132 val = eval(p->eqn, p->eqn_src, pgp->t_diff,
01133 p->vars, p->last, p->now);
01134 }
01135 new_data=1;
01136 }
01137 else if ((!p->pattern || strstr(buf, p->pattern))
01138 && p->vars <= split_and_extract(buf, p))
01139 {
01140 val = eval(
01141 p->eqn, p->eqn_src, pgp->t_diff,
01142 #ifdef HAVE_LIBGTOP
01143 &pgp->gtop_now, &pgp->gtop_last,
01144 #endif
01145 p->vars, p->last, p->now );
01146 }
01147
01148 prev = update_chart < 3 ? 0 : p->val[last_val_pos];
01149 if(!new_data)
01150 {
01151 if(fabs(prev-val) > fabs(p->top - p->bot)/2000.0)
01152 {
01153 new_data = 1;
01154 }
01155 }
01156 p->val[next_val_pos] = prev + pgp->lpf_const * (val - prev);
01157 }
01158 }
01159 if(timingcomp)
01160 {
01161 if(!new_data && old_data_count < (chart_interval/update_interval)/2)
01162 {
01163 pgp->t_now = pgp->t_last;
01164 update_count--;
01165 update_timer_count--;
01166 old_data_count++;
01167 pgp->new_val = last_val_pos;
01168 return;
01169 }
01170 old_data_count=0;
01171 missed = (int) ((pgp->t_diff+update_interval/2.0)/update_interval);
01172 if(missed > 1 && missed < pgp->max_val)
01173 {
01174 for (param_num = 0; param_num < pgp->params; param_num++)
01175 {
01176 Param *p = pgp->parray[param_num];
01177 double prev, val = 0;
01178 val = p->val[next_val_pos];
01179 prev = p->val[last_val_pos];
01180 #if 0
01181 if( missed > 3)
01182 {
01183 printf("missed = %d, prev = %f, val = %f, last_val_pos=%d, next_val_pos=%d\n",
01184 missed,prev,val, last_val_pos, next_val_pos);
01185 }
01186 #endif
01187 for(i = 0; i < missed; i++)
01188 {
01189 p->val[next_val_pos] = prev +
01190 pgp->lpf_const * (val - prev)*
01191 (((double)(i+1))/((double) missed));
01192 #if 0
01193 if(i == missed/2 && missed > 3)
01194 {
01195 printf("p->val[%d] = %f\n", next_val_pos, p->val[next_val_pos]);
01196 }
01197 #endif
01198 if( i + 1 < missed)
01199 {
01200 next_val_pos++;
01201 next_val_pos %= pgp->max_val;
01202 update_count++;
01203 update_timer_count++;
01204 }
01205 }
01206 if(param_num == pgp->params-1)
01207 {
01208 pgp->new_val = next_val_pos;
01209 }
01210 else
01211 {
01212 next_val_pos = pgp->new_val;
01213 }
01214 }
01215 }
01216 }
01217 }
01218
01219
01220
01221
01222 static void
01223 no_display(void)
01224 {
01225 while (1)
01226 {
01227 update_chart++;
01228 update_values(&chart_glob, NULL);
01229 usleep((int)(1e6 * chart_interval));
01230 }
01231 }
01232
01233
01234
01235
01236 static void
01237 numeric_with_ident(void)
01238 {
01239 int p;
01240
01241 while (1)
01242 {
01243 update_chart++;
01244 update_values(&chart_glob, NULL);
01245
01246 for (p=0; p<chart_glob.params; p++)
01247 if (chart_glob.parray[p]->active)
01248 fprintf(stdout, " %12.3f",
01249 chart_glob.parray[p]->val[chart_glob.new_val]);
01250 fprintf(stdout, "\n");
01251 for (p=0; p<chart_glob.params; p++)
01252 if (chart_glob.parray[p]->active)
01253 fprintf(stdout, " %12s", chart_glob.parray[p]->ident);
01254 fprintf(stdout, "\r");
01255 fflush(stdout);
01256 usleep((int)(1e6 * chart_interval));
01257 }
01258 }
01259
01260
01261
01262
01263 static void
01264 numeric_with_graph(void)
01265 {
01266 int p, width=76;
01267 char buf[79+1];
01268
01269 memset(buf, ' ', sizeof(buf));
01270 buf[sizeof(buf)-1] = '\0';
01271
01272 while (1)
01273 {
01274 update_chart++;
01275 update_values(&chart_glob, NULL);
01276
01277 for (p = 0; p < chart_glob.params; p++)
01278 if (chart_glob.parray[p]->active)
01279 {
01280 float v = chart_glob.parray[p]->val[chart_glob.new_val];
01281 float t = chart_glob.parray[p]->top;
01282 float s = (t<=0) ? 0 : v / t;
01283 char per[8];
01284 int i = (int)((width-1) * s + 0.5);
01285 buf[i] = chart_glob.parray[p]->id_char;
01286 sprintf(per, "%d", (int)(100*s));
01287 memcpy(buf+i+1, per, strlen(per));
01288 }
01289 trimtb(buf);
01290 fprintf(stdout, "%s\n", buf);
01291 usleep((int)(1e6 * chart_interval));
01292 }
01293 }
01294
01295 static int
01296 readjust_top_bottom_for_width(int width)
01297 {
01298 float hi, t, top;
01299 float b, bot,lo;
01300 int p, n, i, v, readjust = 0;
01301
01302 n = width < chart_glob.num_val ? width : chart_glob.num_val;
01303 for (p = 0; p < chart_glob.params; p++)
01304 {
01305
01306 v = chart_glob.new_val;
01307 b = t = chart_glob.parray[p]->val[v];
01308 for (i = 1; i < n; i++)
01309 {
01310 if (--v < 0)
01311 v = chart_glob.max_val - 1;
01312 if (t < chart_glob.parray[p]->val[v])
01313 t = chart_glob.parray[p]->val[v];
01314 if (b > chart_glob.parray[p]->val[v])
01315 b = chart_glob.parray[p]->val[v];
01316 }
01317
01318
01319
01320 hi = chart_glob.parray[p]->hi;
01321 lo = chart_glob.parray[p]->lo;
01322 top = hi<t ? t : hi;
01323 bot = lo>b ? b : lo;
01324 if(fabs((hi+lo)/(hi-lo)) < 0.001)
01325 {
01326 if(fabs(top) > fabs(bot))
01327 {
01328 bot = -top;
01329 }
01330 else
01331 {
01332 top = -bot;
01333 }
01334 }
01335 if (
01336 (fabs((chart_glob.parray[p]->top - top) / top) > 0.01) ||
01337 (fabs((chart_glob.parray[p]->bot - bot) / bot) > 0.01)
01338 )
01339 {
01340 chart_glob.parray[p]->top = top;
01341 chart_glob.parray[p]->bot = bot;
01342 if (include_slider)
01343 {
01344 slider_glob.parray[p]->top = top;
01345 slider_glob.parray[p]->bot = bot;
01346 }
01347 #if 0
01348 printf("top[%d] %s\t= %g\t=> %g\n",
01349 p, chart_glob.parray[p]->ident, t, chart_glob.parray[p]->top);
01350 printf("bot[%d] %s\t= %g\t=> %g\n",
01351 p, chart_glob.parray[p]->ident, t, chart_glob.parray[p]->bot);
01352 #endif
01353 readjust = 1;
01354 }
01355 }
01356 return readjust;
01357 }
01358
01359
01360
01361
01362 static GdkPixmap *pixmap;
01363 static GdkColormap *colormap;
01364
01365 static gint
01366 config_handler(GtkWidget *widget, GdkEventConfigure *e, gpointer whence)
01367 {
01368 int p, c, w = widget->allocation.width, h = widget->allocation.height;
01369
01370
01371
01372 if (colormap == NULL)
01373 {
01374 colormap = gdk_window_get_colormap(widget->window);
01375 for (p = 0; p < chart_glob.params; p++)
01376 {
01377 Param *cgp = chart_glob.parray[p];
01378 if (cgp->is_led)
01379 {
01380 cgp->led_gc = malloc(cgp->num_leds * sizeof(*cgp->led_gc));
01381 for (c = 0; c < cgp->num_leds; c++)
01382 {
01383 gdk_color_alloc(colormap, &cgp->led_color[c]);
01384 cgp->led_gc[c] = gdk_gc_new(widget->window);
01385 gdk_gc_set_foreground(cgp->led_gc[c], &cgp->led_color[c]);
01386 }
01387 }
01388 else
01389 {
01390 gdk_color_alloc(colormap, &cgp->gdk_color);
01391 cgp->gdk_gc = gdk_gc_new(widget->window);
01392 gdk_gc_set_foreground(cgp->gdk_gc, &cgp->gdk_color);
01393 if (include_slider)
01394 slider_glob.parray[p]->gdk_gc = cgp->gdk_gc;
01395 }
01396 }
01397 }
01398
01399
01400
01401 if (pixmap)
01402 gdk_pixmap_unref(pixmap);
01403 pixmap = gdk_pixmap_new(widget->window, w, h, -1);
01404 gdk_draw_rectangle(
01405 pixmap, widget->style->bg_gc[GTK_WIDGET_STATE(widget)], TRUE, 0,0, w,h);
01406
01407
01408 readjust_top_bottom_for_width(w);
01409
01410 return FALSE;
01411 }
01412
01413
01414
01415
01416
01417 static void
01418 overlay_tick_marks(GtkWidget *widget, int minor, int major)
01419 {
01420 int p, q, w = widget->allocation.width, c = widget->allocation.height / 2;
01421
01422 if (minor)
01423 for (q = 1, p = w-1; p >= 0; p -= minor)
01424 {
01425 int d = 1;
01426 if (major && --q == 0)
01427 d += 2, q = major;
01428 gdk_draw_line(widget->window, widget->style->black_gc,
01429 p, c-d, p, c+d);
01430 }
01431 }
01432
01433
01434
01435
01436
01437 static void
01438 overlay_status_box(GtkWidget *widget)
01439 {
01440 int p, x=0, y=0, s=10;
01441
01442 for (p = 0; p < chart_glob.params; p++)
01443 {
01444 Param *cgp = chart_glob.parray[p];
01445 if (cgp->is_led)
01446 {
01447 int c = cgp->val[chart_glob.new_val] + 0.5;
01448 if (status_outline)
01449 gdk_draw_rectangle(
01450 widget->window, widget->style->black_gc, FALSE, x,y, s,s);
01451 if (c > 0)
01452 {
01453 if (c > cgp->num_leds)
01454 c = cgp->num_leds;
01455 gdk_draw_rectangle(
01456 widget->window, cgp->led_gc[c-1], TRUE, x+1,y+1, s-1,s-1);
01457 }
01458 x += s;
01459 }
01460 }
01461 }
01462
01463
01464
01465
01466 static int
01467 val2y(float val, float top, int height)
01468 {
01469 return height - ((height-1) * val / top);
01470 }
01471
01472 static gint
01473 chart_expose_handler(GtkWidget *widget, GdkEventExpose *event)
01474 {
01475 int p, w = widget->allocation.width, h = widget->allocation.height;
01476
01477
01478
01479
01480 for (p = chart_glob.params; p--; )
01481 if (chart_glob.parray[p]->active && !chart_glob.parray[p]->is_led)
01482 {
01483 float top = chart_glob.parray[p]->top;
01484 float bot = chart_glob.parray[p]->bot;
01485 int n = w < chart_glob.num_val ? w : chart_glob.num_val;
01486 int i, j = chart_glob.new_val;
01487 int x0, x1 = w - 1;
01488 int y0, y1 = val2y(chart_glob.parray[p]->val[j]-bot,top-bot, h);
01489 for (i=0; i<n; i++)
01490 {
01491 if (--j < 0) j = chart_glob.max_val - 1;
01492 x0 = x1; y0 = y1;
01493 x1 = x0 - 1;
01494 y1 = val2y(chart_glob.parray[p]->val[j]-bot, top-bot, h);
01495 gdk_draw_line(pixmap, chart_glob.parray[p]->gdk_gc, x0,y0, x1,y1);
01496 }
01497 }
01498
01499
01500 gdk_draw_pixmap(
01501 widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], pixmap,
01502 event->area.x, event->area.y,
01503 event->area.x, event->area.y,
01504 event->area.width, event->area.height);
01505
01506 overlay_tick_marks(widget, minor_tick, major_tick);
01507 overlay_status_box(widget);
01508
01509 return FALSE;
01510 }
01511
01512
01513 static gint
01514 update_timer_handler(GtkWidget *widget)
01515 {
01516 update_chart++;
01517 update_timer_count++;
01518 update_values(&chart_glob, include_slider? &slider_glob: NULL);
01519 return(TRUE);
01520 }
01521 static gint
01522 chart_timer_handler(GtkWidget *widget)
01523 {
01524 int p, w = widget->allocation.width, h = widget->allocation.height;
01525
01526
01527
01528 update_chart++;
01529 #if 0
01530 update_values(&chart_glob, include_slider? &slider_glob: NULL);
01531 #endif
01532 if (readjust_top_bottom_for_width(w))
01533 {
01534 GdkEventExpose expose;
01535 expose.area.x = expose.area.y = 0;
01536 expose.area.width = w; expose.area.height = h;
01537 gdk_draw_rectangle(
01538 pixmap, widget->style->bg_gc[GTK_WIDGET_STATE(widget)],
01539 TRUE, 0,0, w-1,h-1);
01540 chart_expose_handler(widget, &expose);
01541 }
01542 else
01543 {
01544 if(update_timer_count > w)
01545 {
01546 update_timer_count = w;
01547 }
01548
01549 gdk_window_copy_area(
01550 pixmap, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], 0, 0,
01551 pixmap, update_timer_count, 0, w-update_timer_count, h);
01552 gdk_draw_rectangle(
01553 pixmap, widget->style->bg_gc[GTK_WIDGET_STATE(widget)],
01554 TRUE, w-update_timer_count, 0, update_timer_count, h);
01555 for (p = chart_glob.params; p--; )
01556 if (chart_glob.parray[p]->active && !chart_glob.parray[p]->is_led)
01557 {
01558 float top = chart_glob.parray[p]->top;
01559 float bot = chart_glob.parray[p]->bot;
01560 int i = chart_glob.new_val;
01561 int m = chart_glob.max_val;
01562 int j =0;
01563 for(j = 0; j < update_timer_count && j < m; j++)
01564 {
01565 int y1 = val2y(chart_glob.parray[p]->val[(i - update_timer_count +j +m)%m]-bot, top-bot, h);
01566 int y0 = val2y(chart_glob.parray[p]->val[(i-1 - update_timer_count + j +m)%m]-bot, top-bot, h);
01567 gdk_draw_line(pixmap, chart_glob.parray[p]->gdk_gc,
01568 w-2-update_timer_count+j,y0, w-1-update_timer_count +j,y1);
01569 }
01570 }
01571 gdk_draw_pixmap(
01572 widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
01573 pixmap, 0,0, 0,0, w,h);
01574 overlay_tick_marks(widget, minor_tick, major_tick);
01575 overlay_status_box(widget);
01576 }
01577 update_timer_count = 0;
01578 return TRUE;
01579 }
01580
01581 static gint
01582 slider_redraw(GtkWidget *widget)
01583 {
01584 int p, w = widget->allocation.width, h = widget->allocation.height;
01585 GdkGC *bg = widget->style->bg_gc[GTK_WIDGET_STATE(widget)];
01586 gdk_draw_rectangle(widget->window, bg, TRUE, 0,0, w,h);
01587 for (p = slider_glob.params; p--; )
01588 if (slider_glob.parray[p]->active && !chart_glob.parray[p]->is_led)
01589 {
01590 GdkPoint tri[3];
01591 int y = val2y(
01592 slider_glob.parray[p]->val[slider_glob.new_val]-slider_glob.parray[p]->bot,
01593 slider_glob.parray[p]->top-slider_glob.parray[p]->bot, h);
01594 tri[0].x = 0; tri[0].y = y;
01595 tri[1].x = w; tri[1].y = y-w/2;
01596 tri[2].x = w; tri[2].y = y+w/2;
01597 gdk_draw_polygon(
01598 widget->window, slider_glob.parray[p]->gdk_gc, TRUE, tri, 3);
01599 }
01600 return FALSE;
01601 }
01602
01603 static gint
01604 slider_expose_handler(GtkWidget *widget, GdkEventExpose *event)
01605 {
01606 slider_redraw(widget);
01607 return FALSE;
01608 }
01609
01610 static gint
01611 slider_timer_handler(GtkWidget *widget)
01612 {
01613 #if 0
01614 update_values(&slider_glob, NULL);
01615 #endif
01616 slider_redraw(widget);
01617 return TRUE;
01618 }
01619
01620 static gint
01621 exit_callback(void)
01622 {
01623 gtk_main_quit();
01624 return TRUE;
01625 }
01626
01627 GnomeUIInfo file_menu[] =
01628 {
01629 {
01630 GNOME_APP_UI_ITEM, N_("E_xit"), N_("Terminate the stripchart program"),
01631 exit_callback, NULL, NULL,
01632 GNOME_APP_PIXMAP_NONE, GNOME_STOCK_MENU_EXIT, 'x', GDK_CONTROL_MASK, NULL
01633 },
01634 GNOMEUIINFO_END
01635 };
01636
01637
01638
01639
01640 static gint
01641 about_callback(void)
01642 {
01643 const gchar *authors[] = { "John Kodis, kodis@jagunet.com -- Original gstripchart", "Will Shackleford, shackle@nist.gov -- EMC modifications.", NULL };
01644 GtkWidget *about = gnome_about_new(
01645 _(prog_name), prog_version,
01646 _("Copyright 1998 John Kodis"),
01647 authors,
01648 _("EMC stripchart is a modified version of GNOME stripchart. It plots EMC"
01649 "specific parameters like position and following error."
01650 "The GNOME stripchart program plots various user-specified parameters "
01651 "as a function of time. Its main use is to chart system performance "
01652 "parameters such as CPU load, CPU utilization, network traffic levels, "
01653 "and the like. Other more ingenious uses are left as an exercise for "
01654 "the interested user."),
01655 "/usr/local/share/pixmaps/gnoapp-logo.xpm");
01656 gtk_widget_show(about);
01657 return 1;
01658 }
01659
01660 GnomeUIInfo help_menu[] =
01661 {
01662 {
01663 GNOME_APP_UI_ITEM, N_("_About"), N_("Info about the stripchart program"),
01664 about_callback, NULL, NULL,
01665 GNOME_APP_PIXMAP_NONE, GNOME_STOCK_MENU_ABOUT, 0, 0, NULL
01666 },
01667 GNOMEUIINFO_SEPARATOR,
01668 GNOMEUIINFO_HELP("emcstripchart"),
01669 GNOMEUIINFO_END
01670 };
01671
01672 GnomeUIInfo mainmenu[] =
01673 {
01674 GNOMEUIINFO_SUBTREE(N_("_File"), file_menu),
01675 GNOMEUIINFO_SUBTREE(N_("_Help"), help_menu),
01676 GNOMEUIINFO_END
01677 };
01678
01679
01680
01681
01682
01683 static void
01684 help_menu_action(GtkWidget *menu)
01685 {
01686 static GnomeHelpMenuEntry help_entry = { "emcstripchart", "//./doc/emcstripchart.html" };
01687 char fname_buf[200];
01688 char cwd_buf[200];
01689 getcwd(cwd_buf,200);
01690 sprintf(fname_buf,"file://localhost%s/doc/emcstripchart.html",cwd_buf);
01691 gnome_help_goto(NULL, fname_buf);
01692 }
01693
01694
01695
01696
01697 static GtkWidget **param_active = NULL;
01698
01699 static void
01700 prefs_apply(GtkWidget *button, gpointer dialog)
01701 {
01702 int p;
01703 for (p = 0; p < chart_glob.params; p++)
01704 {
01705 chart_glob.parray[p]->active =
01706 GTK_TOGGLE_BUTTON(param_active[p])->active;
01707 if (include_slider)
01708 slider_glob.parray[p]->active =
01709 GTK_TOGGLE_BUTTON(param_active[p])->active;
01710 }
01711 }
01712
01713 static void
01714 prefs_cancel(GtkWidget *button, gpointer dialog)
01715 {
01716 gnome_dialog_close(GNOME_DIALOG(dialog));
01717 }
01718
01719 static void
01720 prefs_okay(GtkWidget *button, gpointer dialog)
01721 {
01722 prefs_apply(button, dialog);
01723 prefs_cancel(button, dialog);
01724 }
01725
01726
01727
01728
01729
01730 static gint
01731 prefs_callback(GtkWidget *chart, gpointer unused)
01732 {
01733 int p;
01734 GtkWidget *dialog, *notebook, *vbox, *clist, *active, *label;
01735
01736 notebook = gtk_notebook_new();
01737 param_active = realloc(param_active,
01738 chart_glob.params * sizeof(*param_active));
01739 for (p = 0; p < chart_glob.params; p++)
01740 {
01741 char lo[20], hi[20], range[100];
01742 char *row[2], *ttls[2];
01743 ttls[0] = _("Param"); ttls[1] = _("Value");
01744
01745 clist = gtk_clist_new_with_titles(NELS(ttls), ttls);
01746
01747 row[0] = _("Identifier"); row[1] = _(chart_glob.parray[p]->ident);
01748 gtk_clist_append(GTK_CLIST(clist), row);
01749 row[0] = _("Color"); row[1] = _(chart_glob.parray[p]->color_name);
01750 gtk_clist_append(GTK_CLIST(clist), row);
01751 row[0] = _("Filename"); row[1] = chart_glob.parray[p]->filename;
01752 gtk_clist_append(GTK_CLIST(clist), row);
01753 row[0] = _("Pattern"); row[1] = chart_glob.parray[p]->pattern;
01754 gtk_clist_append(GTK_CLIST(clist), row);
01755 row[0] = _("Equation"); row[1] = chart_glob.parray[p]->eqn;
01756 gtk_clist_append(GTK_CLIST(clist), row);
01757 row[0] = _("Expected range"); row[1] = range;
01758 hi_lo_fmt(chart_glob.parray[p]->lo, lo, chart_glob.parray[p]->hi, hi);
01759 sprintf(range, "%s ... %s", lo, hi);
01760 gtk_clist_append(GTK_CLIST(clist), row);
01761 row[0] = _("Displayed range"); row[1] = range;
01762 hi_lo_fmt(chart_glob.parray[p]->bot, lo, chart_glob.parray[p]->top, hi);
01763 sprintf(range, "%s ... %s", lo, hi);
01764 gtk_clist_append(GTK_CLIST(clist), row);
01765 row[0] = _("Current value"); row[1] = range;
01766 hi_lo_fmt(chart_glob.parray[p]->val[chart_glob.new_val], range, 0, NULL);
01767 gtk_clist_append(GTK_CLIST(clist), row);
01768
01769 gtk_clist_columns_autosize(GTK_CLIST(clist));
01770 gtk_widget_show(clist);
01771
01772 param_active[p] = active = gtk_check_button_new_with_label(_("Active"));
01773 gtk_toggle_button_set_active(
01774 GTK_TOGGLE_BUTTON(active), chart_glob.parray[p]->active);
01775 gtk_widget_show(active);
01776
01777 vbox = gtk_vbox_new(FALSE, 0);
01778 gtk_box_pack_start(GTK_BOX(vbox), clist, TRUE, TRUE, 0);
01779 gtk_box_pack_start(GTK_BOX(vbox), active, TRUE, TRUE, 0);
01780 gtk_widget_show(vbox);
01781
01782 label = gtk_label_new(_(chart_glob.parray[p]->ident));
01783 gtk_widget_show(label);
01784 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label);
01785 }
01786 gtk_widget_show(notebook);
01787
01788 dialog = gnome_dialog_new(_("Gnome Stripchart Parameters"),
01789 GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_APPLY,
01790 GNOME_STOCK_BUTTON_CANCEL, GNOME_STOCK_BUTTON_HELP, NULL);
01791 gnome_dialog_set_parent(GNOME_DIALOG(dialog), GTK_WINDOW(chart));
01792 gnome_dialog_button_connect(GNOME_DIALOG(dialog), 0,
01793 GTK_SIGNAL_FUNC(prefs_okay), GNOME_DIALOG(dialog));
01794 gnome_dialog_button_connect(GNOME_DIALOG(dialog), 1,
01795 GTK_SIGNAL_FUNC(prefs_apply), GNOME_DIALOG(dialog));
01796 gnome_dialog_button_connect(GNOME_DIALOG(dialog), 2,
01797 GTK_SIGNAL_FUNC(prefs_cancel), GNOME_DIALOG(dialog));
01798 gnome_dialog_button_connect(GNOME_DIALOG(dialog), 3,
01799 GTK_SIGNAL_FUNC(help_menu_action), GNOME_DIALOG(dialog));
01800 gtk_container_add(GTK_CONTAINER(GNOME_DIALOG(dialog)->vbox), notebook);
01801
01802 gtk_widget_show(dialog);
01803 return 1;
01804 }
01805
01806 int first_text_load_clist = 1;
01807
01808
01809
01810 static void
01811 text_load_clist(GtkWidget *txt, GtkWidget *box)
01812 {
01813 int n;
01814 gtk_clist_freeze(GTK_CLIST(txt));
01815 gtk_clist_clear(GTK_CLIST(txt));
01816 for (n = 0; n < chart_glob.params; n++)
01817 {
01818 Param *p = chart_glob.parray[n];
01819 char val_str[100], top_str[100],bot_str[100];
01820 char *row_strs[4];
01821
01822 row_strs[0] = _(p->ident);
01823 row_strs[1] = val_str;
01824 row_strs[2] = top_str;
01825 row_strs[3] = bot_str;
01826 hi_lo_fmt(p->top, top_str, p->val[chart_glob.new_val], val_str);
01827 hi_lo_fmt(p->top, top_str, p->bot, bot_str);
01828 gtk_clist_append(GTK_CLIST(txt), row_strs);
01829 gtk_clist_set_foreground(GTK_CLIST(txt), n, &p->gdk_color);
01830 gtk_clist_set_background(GTK_CLIST(txt), n, &box->style->bg[0]);
01831 }
01832 if(first_text_load_clist)
01833 {
01834 gtk_clist_columns_autosize(GTK_CLIST(txt));
01835 first_text_load_clist = 0;
01836 }
01837 gtk_clist_thaw(GTK_CLIST(txt));
01838 }
01839
01840
01841
01842
01843 static void
01844 text_update(GtkWidget *box, GdkEvent *event, GtkWidget *txt)
01845 {
01846 first_text_load_clist=1;
01847 text_load_clist(txt, box);
01848 }
01849
01850 GtkWidget *text_box =NULL;
01851 GtkWidget *text_box_txt=NULL;
01852 guint text_box_timer_id = 0;
01853 guint chart_timer_id = 0;
01854 guint slider_timer_id = 0;
01855 guint update_timer_id = 0;
01856
01857
01858
01859
01860
01861 static void
01862 textbox_close(GtkWidget *box, GdkEvent *event, GtkWidget *txt)
01863 {
01864 if(text_box_timer_id > 0)
01865 {
01866 gtk_timeout_remove(text_box_timer_id);
01867 text_box_timer_id=0;
01868 }
01869 if(text_box)
01870 {
01871 gtk_widget_destroy(GTK_WIDGET(text_box));
01872 }
01873 text_box_txt = NULL;
01874 text_box = NULL;
01875 }
01876
01877
01878 gint text_box_timer_handler(GtkWidget *widget)
01879 {
01880 if(NULL != text_box && NULL != text_box_txt)
01881 {
01882 text_load_clist(text_box_txt,text_box);
01883 return(TRUE);
01884 }
01885 return(FALSE);
01886 }
01887
01888
01889 void on_pause_button_clicked(GtkButton *button, gpointer user_data)
01890 {
01891 if(update_timer_id > 0)
01892 {
01893 gtk_timeout_remove(update_timer_id);
01894 update_timer_id=0;
01895 }
01896 if(chart_timer_id > 0)
01897 {
01898 gtk_timeout_remove(chart_timer_id);
01899 chart_timer_id=0;
01900 }
01901 if(text_box_timer_id > 0)
01902 {
01903 gtk_timeout_remove(text_box_timer_id);
01904 text_box_timer_id=0;
01905 }
01906 if(slider_timer_id > 0)
01907 {
01908 gtk_timeout_remove(slider_timer_id);
01909 slider_timer_id=0;
01910 }
01911 }
01912
01913
01914 void on_go_button_clicked(GtkButton *button, gpointer user_data)
01915 {
01916 if(update_timer_id == 0)
01917 {
01918 if(update_interval > 0.0005)
01919 {
01920 minor_tick = (int) (1.0/update_interval);
01921 minor_tick += (10 - minor_tick%10)%10;
01922 major_tick = minor_tick;
01923 }
01924 update_timer_id = gtk_timeout_add((int)(1000 * update_interval),
01925 (GtkFunction)update_timer_handler,
01926 drawing);
01927 }
01928 if(text_box_timer_id == 0)
01929 {
01930 text_box_timer_id = gtk_timeout_add((int)(2000),
01931 (GtkFunction)text_box_timer_handler,
01932 text_box);
01933 }
01934 if(chart_timer_id == 0)
01935 {
01936 chart_timer_id = gtk_timeout_add((int)(1000 * chart_interval),
01937 (GtkFunction)chart_timer_handler,
01938 drawing);
01939 }
01940 if(include_slider)
01941 {
01942 if(slider_timer_id == 0)
01943 {
01944 slider_timer_id = gtk_timeout_add((int)(1000 * slider_interval),
01945 (GtkFunction)slider_timer_handler,
01946 slider);
01947 }
01948 }
01949 }
01950
01951
01952
01953
01954
01955 static void
01956 text_popup(GtkWidget *widget, GdkEvent *event)
01957 {
01958 GdkEventButton *button = (GdkEventButton*)event;
01959 GtkWidget *vpaned1;
01960 GtkWidget *hbuttonbox1;
01961 GtkWidget *pause_button;
01962 GtkWidget *go_button;
01963 GtkWidget *list1;
01964
01965 if (text_box)
01966 {
01967 if(first_text_load_clist)
01968 {
01969 return;
01970 }
01971 if(text_box_timer_id > 0)
01972 {
01973 gtk_timeout_remove(text_box_timer_id);
01974 text_box_timer_id = 0;
01975 }
01976 gtk_widget_destroy(GTK_WIDGET(text_box));
01977 text_box_txt = NULL;
01978 text_box = NULL;
01979 }
01980 else
01981 {
01982 char *titles[4];
01983 titles[0] = _("Param"); titles[1] = _("Current"); titles[2] = _("Top"); titles[3] = _("Bottom");
01984 text_box_txt = gtk_clist_new_with_titles(NELS(titles), titles);
01985 gtk_widget_show(text_box_txt);
01986
01987 text_box = gtk_window_new(GTK_WINDOW_TOPLEVEL);
01988
01989 vpaned1 = gtk_vpaned_new ();
01990 gtk_widget_ref (vpaned1);
01991 gtk_object_set_data_full (GTK_OBJECT (text_box), "vpaned1", vpaned1,
01992 (GtkDestroyNotify) gtk_widget_unref);
01993 gtk_widget_show (vpaned1);
01994 gtk_container_add (GTK_CONTAINER (text_box), vpaned1);
01995
01996 hbuttonbox1 = gtk_hbutton_box_new ();
01997 gtk_widget_ref (hbuttonbox1);
01998 gtk_object_set_data_full (GTK_OBJECT (text_box), "hbuttonbox1", hbuttonbox1,
01999 (GtkDestroyNotify) gtk_widget_unref);
02000 gtk_widget_show (hbuttonbox1);
02001 gtk_container_add (GTK_CONTAINER (vpaned1), hbuttonbox1);
02002
02003 pause_button = gtk_button_new_with_label ("pause");
02004 gtk_widget_ref (pause_button);
02005 gtk_object_set_data_full (GTK_OBJECT (text_box), "pause_button", pause_button,
02006 (GtkDestroyNotify) gtk_widget_unref);
02007 gtk_widget_show (pause_button);
02008 gtk_container_add (GTK_CONTAINER (hbuttonbox1), pause_button);
02009 GTK_WIDGET_SET_FLAGS (pause_button, GTK_CAN_DEFAULT);
02010
02011 go_button = gtk_button_new_with_label ("go");
02012 gtk_widget_ref (go_button);
02013 gtk_object_set_data_full (GTK_OBJECT (text_box), "go_button", go_button,
02014 (GtkDestroyNotify) gtk_widget_unref);
02015 gtk_widget_show (go_button);
02016 gtk_container_add (GTK_CONTAINER (hbuttonbox1), go_button);
02017 GTK_WIDGET_SET_FLAGS (go_button, GTK_CAN_DEFAULT);
02018
02019 gtk_widget_ref (text_box_txt);
02020 gtk_object_set_data_full (GTK_OBJECT (text_box), "text_box_txt", text_box_txt,
02021 (GtkDestroyNotify) gtk_widget_unref);
02022 gtk_widget_show (text_box_txt);
02023 gtk_container_add (GTK_CONTAINER (vpaned1), text_box_txt);
02024
02025
02026 gtk_signal_connect (GTK_OBJECT (pause_button), "clicked",
02027 GTK_SIGNAL_FUNC (on_pause_button_clicked),
02028 NULL);
02029
02030 gtk_signal_connect (GTK_OBJECT (go_button), "clicked",
02031 GTK_SIGNAL_FUNC (on_go_button_clicked),
02032 NULL);
02033 gtk_signal_connect(GTK_OBJECT(text_box),
02034 "button_press_event", GTK_SIGNAL_FUNC(text_update), text_box_txt);
02035 gtk_signal_connect(GTK_OBJECT(text_box),
02036 "destroy", GTK_SIGNAL_FUNC(textbox_close), NULL);
02037 gtk_signal_connect(GTK_OBJECT(text_box),
02038 "delete_event", GTK_SIGNAL_FUNC(textbox_close), NULL);
02039
02040 first_text_load_clist = 1;
02041 text_load_clist(text_box_txt, widget);
02042 gtk_widget_show(text_box);
02043
02044 text_box_timer_id = gtk_timeout_add((int)(2000),
02045 (GtkFunction)text_box_timer_handler,
02046 text_box);
02047 }
02048 }
02049
02050
02051
02052
02053 static void
02054 menu_popup(GtkWidget *widget, GdkEvent *event)
02055 {
02056 static GtkWidget *menu_item, *menu;
02057
02058 if (menu == NULL)
02059 {
02060 menu = gtk_menu_new();
02061
02062 menu_item = gtk_menu_item_new_with_label(_("Key"));
02063 gtk_menu_append(GTK_MENU(menu), menu_item);
02064 gtk_signal_connect_object(GTK_OBJECT(menu_item), "activate",
02065 GTK_SIGNAL_FUNC(text_popup), GTK_OBJECT(widget));
02066 gtk_widget_show(menu_item);
02067 menu_item = gtk_menu_item_new_with_label(_("Help"));
02068 gtk_menu_append(GTK_MENU(menu), menu_item);
02069 gtk_signal_connect_object(GTK_OBJECT(menu_item), "activate",
02070 GTK_SIGNAL_FUNC(help_menu_action), GTK_OBJECT(widget));
02071 gtk_widget_show(menu_item);
02072 menu_item = gtk_menu_item_new_with_label(_("About"));
02073 gtk_menu_append(GTK_MENU(menu), menu_item);
02074 gtk_signal_connect_object(GTK_OBJECT(menu_item), "activate",
02075 GTK_SIGNAL_FUNC(about_callback), NULL);
02076 gtk_widget_show(menu_item);
02077
02078 menu_item = gtk_menu_item_new_with_label(_("Params"));
02079 gtk_menu_append(GTK_MENU(menu), menu_item);
02080 gtk_signal_connect_object(GTK_OBJECT(menu_item), "activate",
02081 GTK_SIGNAL_FUNC(prefs_callback), GTK_OBJECT(widget));
02082 gtk_widget_show(menu_item);
02083
02084 menu_item = gtk_menu_item_new_with_label(_("Exit"));
02085 gtk_menu_append(GTK_MENU(menu), menu_item);
02086 gtk_signal_connect_object(GTK_OBJECT(menu_item), "activate",
02087 GTK_SIGNAL_FUNC(exit_callback), NULL);
02088 gtk_widget_show(menu_item);
02089 }
02090
02091
02092 gtk_menu_popup(
02093 GTK_MENU(menu), NULL, NULL, NULL, NULL,
02094 ((GdkEventButton*)event)->button, ((GdkEventButton*)event)->time);
02095 }
02096
02097
02098
02099
02100
02101 static void
02102 click_handler(GtkWidget *widget, GdkEvent *event, gpointer unused)
02103 {
02104 GdkEventButton *button = (GdkEventButton*)event;
02105 switch (button->button)
02106 {
02107 case 1: text_popup(widget, event); break;
02108 case 3: menu_popup(widget, event); break;
02109 }
02110 }
02111
02112
02113
02114
02115 static int
02116 save_handler(GnomeClient *client,
02117 gint phase, GnomeRestartStyle restart,
02118 gint shutdown, GnomeInteractStyle interact,
02119 gint fast, GtkWidget *frame)
02120 {
02121 int i = 0;
02122 char *argv[20];
02123
02124 argv[i++] = program_invocation_name;
02125 argv[i++] = "-g";
02126 argv[i++] = gnome_geometry_string(frame->window);
02127 if (config_file)
02128 {
02129 argv[i++] = "-f";
02130 argv[i++] = config_file;
02131 }
02132 gnome_client_set_restart_command(client, i, argv);
02133
02134 return TRUE;
02135 }
02136
02137
02138
02139
02140
02141 static void
02142 gtk_graph(void)
02143 {
02144 GnomeClient *client;
02145 GtkWidget *frame, *h_box;
02146 const int slide_w=10;
02147
02148
02149
02150 drawing = gtk_drawing_area_new();
02151 gtk_drawing_area_size(GTK_DRAWING_AREA(drawing), geometry_w, geometry_h);
02152 gtk_widget_set_events(drawing, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
02153 gtk_widget_show(drawing);
02154
02155 h_box = gtk_hbox_new(FALSE, 0);
02156 gtk_box_pack_start(GTK_BOX(h_box), drawing, TRUE, TRUE, 0);
02157
02158 gtk_signal_connect(GTK_OBJECT(drawing),
02159 "configure_event", (GtkSignalFunc)config_handler, "draw");
02160 gtk_signal_connect(GTK_OBJECT(drawing),
02161 "expose_event", (GtkSignalFunc)chart_expose_handler, NULL);
02162 if (include_slider)
02163 {
02164 GtkWidget *sep = gtk_vseparator_new();
02165 slider = gtk_drawing_area_new();
02166
02167 gtk_box_pack_start(GTK_BOX(h_box), sep, FALSE, TRUE, 0);
02168 gtk_widget_show(sep);
02169
02170 gtk_drawing_area_size(GTK_DRAWING_AREA(slider), slide_w, geometry_h);
02171 gtk_box_pack_start(GTK_BOX(h_box), slider, FALSE, FALSE, 0);
02172 gtk_widget_show(slider);
02173
02174 gtk_widget_set_events(slider, GDK_EXPOSURE_MASK);
02175 gtk_signal_connect(GTK_OBJECT(slider),
02176 "expose_event", (GtkSignalFunc)slider_expose_handler, NULL);
02177
02178 slider_timer_id = gtk_timeout_add((int)(1000 * slider_interval),
02179 (GtkFunction)slider_timer_handler,
02180 slider);
02181 }
02182 gtk_widget_show(h_box);
02183
02184
02185
02186
02187 frame = gnome_app_new(_("emcstripchart"), _("EMC stripchart viewer"));
02188 gtk_widget_set_usize(frame, 1, 1);
02189 gtk_window_set_default_size(GTK_WINDOW(frame), geometry_w, geometry_h);
02190 gtk_signal_connect(GTK_OBJECT(frame),
02191 "destroy", GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
02192 gtk_signal_connect(GTK_OBJECT(frame),
02193 "delete_event", GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
02194
02195
02196
02197 gtk_signal_connect(GTK_OBJECT(frame),
02198 "button_press_event", GTK_SIGNAL_FUNC(click_handler), NULL);
02199 if (include_menubar)
02200 gnome_app_create_menus(GNOME_APP(frame), mainmenu);
02201 gnome_app_set_contents(GNOME_APP(frame), h_box);
02202
02203
02204 chart_timer_id = gtk_timeout_add((int)(1000 * chart_interval),
02205 (GtkFunction)chart_timer_handler,
02206 drawing);
02207
02208
02209
02210
02211
02212 if (geometry_flags & (XNegative | YNegative))
02213 {
02214 if (XNegative)
02215 geometry_x = root_width + geometry_x - geometry_w - slide_w;
02216 if (YNegative)
02217 geometry_y = root_height + geometry_y - geometry_h;
02218 }
02219 if (geometry_flags & (XValue | YValue))
02220 gtk_widget_set_uposition(frame, geometry_x, geometry_y);
02221
02222
02223 if ((client = gnome_master_client()) != NULL)
02224 {
02225 char cwd[PATH_MAX];
02226 getcwd(cwd, sizeof(cwd));
02227 gnome_client_set_current_directory(client, cwd);
02228 gtk_signal_connect(GTK_OBJECT(client),
02229 "save_yourself", GTK_SIGNAL_FUNC(save_handler), frame);
02230 }
02231
02232 if(update_interval > 0.0005)
02233 {
02234 minor_tick = (int) (1.0/update_interval);
02235 minor_tick += (10 - minor_tick%10)%10;
02236 major_tick = minor_tick;
02237 update_timer_id = gtk_timeout_add((int)(1000 * update_interval),
02238 (GtkFunction)update_timer_handler,
02239 drawing);
02240 }
02241 else
02242 {
02243 major_tick = minor_tick = 0;
02244 }
02245
02246
02247 gtk_widget_show(frame);
02248 gtk_main();
02249 }
02250
02251 static int
02252 proc_arg(int opt, const char *arg)
02253 {
02254 printf("opt=%c, arg=%s\n",opt,arg);
02255 switch (opt)
02256 {
02257 case 'f': config_file = strdup(arg); break;
02258 case 'i': chart_interval = atof(arg); break;
02259 case 'I': chart_filter = atof(arg); break;
02260 case 'j': slider_interval = atof(arg); break;
02261 case 'J': slider_filter = atof(arg); break;
02262 case 'M': include_menubar = 1; break;
02263 case 'T': timingcomp = 1; break;
02264 case 'S': include_slider = 0; break;
02265 case 'u':
02266 update_interval = atof(arg);
02267 if(update_interval > 0.0005)
02268 {
02269 minor_tick = (int) (1.0/update_interval);
02270 minor_tick += (10 - minor_tick%10)%10;
02271 major_tick = minor_tick;
02272 }
02273 #if 0
02274 printf("update_interval = %f;\tminor_tick=%d\n",update_interval,minor_tick);
02275 #endif
02276 break;
02277 case 'g':
02278 geometry_flags = XParseGeometry(arg,
02279 &geometry_x, &geometry_y, &geometry_w, &geometry_h);
02280 break;
02281 case 't':
02282 if (streq("gtk", arg))
02283 display = gtk_graph;
02284 else
02285 {
02286 gnome_client_disable_master_connection();
02287 if (streq("none", arg))
02288 display = no_display;
02289 else if (streq("text", arg))
02290 display = numeric_with_ident;
02291 else if (streq("graph", arg))
02292 display = numeric_with_graph;
02293 else
02294 {
02295 fprintf(stderr, _("invalid display type: %s\n"), arg);
02296 return -1;
02297 }
02298 }
02299 }
02300 return 0;
02301 }
02302
02303 static void
02304 popt_arg_extractor(
02305 poptContext state, enum poptCallbackReason reason,
02306 const struct poptOption *opt, const char *arg, void *data )
02307 {
02308 if (proc_arg(opt->val, arg))
02309 {
02310
02311
02312
02313 poptPrintUsage(state, stderr, 0);
02314 }
02315 }
02316
02317 static struct
02318 poptOption arglist[] =
02319 {
02320 { NULL, '\0', POPT_ARG_CALLBACK, popt_arg_extractor },
02321 { "geometry", 'g', POPT_ARG_STRING, NULL, 'g',
02322 N_("Geometry string: WxH+X+Y"), N_("GEO") },
02323 { "config-file", 'f', POPT_ARG_STRING, NULL, 'f',
02324 N_("Configuration file name"), N_("FILE") },
02325 { "chart-interval", 'i', POPT_ARG_STRING, NULL, 'i',
02326 N_("Chart redisplay interval"), N_("SECS") },
02327 { "chart-filter", 'I', POPT_ARG_STRING, NULL, 'I',
02328 N_("Chart low-pass filter time constant"), N_("SECS"), },
02329 { "slider-interval", 'j', POPT_ARG_STRING, NULL, 'j',
02330 N_("Slider redisplay interval"), N_("SECS") },
02331 { "slider-filter", 'J', POPT_ARG_STRING, NULL, 'J',
02332 N_("Slider low-pass filter time constant"), N_("SECS") },
02333 { "update-interval", 'u', POPT_ARG_STRING, NULL, 'u',
02334 N_("Interval at which data is actually polled."), N_("SECS") },
02335 { "menubar", 'M', POPT_ARG_NONE, NULL, 'M',
02336 N_("Adds a menubar to the main window"), NULL },
02337 { "timingcomp", 'T', POPT_ARG_NONE, NULL, 'T',
02338 N_("Attempt to compensate for irregularities in timing."), NULL },
02339 { "omit-slider", 'S', POPT_ARG_NONE, NULL, 'S',
02340 N_("Omits slider window"), NULL },
02341 { "display-type", 't', POPT_ARG_STRING, NULL, 't',
02342 N_("TYPE is one of gtk, text, graph, or none"), N_("TYPE") },
02343 { NULL, '\0', 0, NULL, 0 }
02344 };
02345
02346
02347 int first_control_c =0;
02348 void control_c_sighandler(int sig)
02349 {
02350 if(first_control_c)
02351 {
02352 gtk_main_quit();
02353 }
02354 else
02355 {
02356 exit(-1);
02357 }
02358 }
02359
02360
02361
02362
02363 int
02364 main(int argc, char **argv)
02365 {
02366 int c;
02367 poptContext popt_context;
02368
02369 signal(SIGINT, control_c_sighandler);
02370
02371 emcGetArgs(argc, argv);
02372 emcIniLoad(EMC_INIFILE);
02373
02374
02375
02376
02377 #if 0
02378 bindtextdomain(PACKAGE, GNOMELOCALEDIR);
02379 textdomain(PACKAGE);
02380 #endif
02381 #ifdef HAVE_LIBGTOP
02382 glibtop_init_r(&glibtop_global_server, 0, 0);
02383 #endif
02384
02385
02386
02387
02388
02389 gnome_init_with_popt_table(
02390 prog_name, prog_version, argc, argv, arglist, 0, &popt_context);
02391
02392 root_width = 1;
02393 if (display == gtk_graph)
02394 gdk_window_get_geometry(NULL, NULL, NULL, &root_width, &root_height, NULL);
02395
02396 chart_glob.max_val = root_width> 1000 ? root_width : 1000;
02397 chart_glob.new_val = chart_glob.num_val = 0;
02398 chart_glob.params = read_param_defns(&chart_glob);
02399 chart_glob.lpf_const = exp(-chart_filter / chart_interval);
02400 update_values(&chart_glob, NULL);
02401
02402
02403
02404 popt_context = poptGetContext(prog_name, argc, argv, arglist, 0);
02405 while ((c = poptGetNextOpt(popt_context)) != -1)
02406 if (c > 0)
02407 proc_arg(c, poptGetOptArg(popt_context));
02408
02409
02410
02411 if (display == gtk_graph && include_slider)
02412 {
02413 int p;
02414 slider_glob = chart_glob;
02415 slider_glob.max_val = 1;
02416 slider_glob.num_val = slider_glob.new_val = 0;
02417 slider_glob.parray =
02418 malloc(slider_glob.params * sizeof(*slider_glob.parray));
02419 for (p = 0; p < slider_glob.params; p++)
02420 {
02421 slider_glob.parray[p] = malloc(sizeof(*slider_glob.parray[p]));
02422 *slider_glob.parray[p] = *chart_glob.parray[p];
02423 slider_glob.parray[p]->val =
02424 calloc(slider_glob.max_val,
02425 sizeof(slider_glob.parray[p]->val[0]));
02426 slider_glob.parray[p]->now =
02427 calloc(slider_glob.parray[p]->vars,
02428 sizeof(slider_glob.parray[p]->now[0]));
02429 slider_glob.parray[p]->last =
02430 calloc(slider_glob.parray[p]->vars,
02431 sizeof(slider_glob.parray[p]->last[0]));
02432 }
02433 slider_glob.lpf_const = exp(-slider_filter / slider_interval);
02434 update_values(&slider_glob, NULL);
02435 }
02436
02437
02438
02439
02440
02441
02442
02443
02444
02445
02446
02447
02448 update_chart = 1;
02449 update_values(&chart_glob, NULL);
02450
02451
02452
02453
02454 update_chart = 2;
02455 usleep(1000000);
02456 update_values(&chart_glob, NULL);
02457
02458
02459
02460
02461
02462 usleep(1000000);
02463 display();
02464
02465 return EXIT_SUCCESS;
02466 }