/*
* Copyright (C) 1993 Rudolf Koenig
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (see the file COPYING); if not, write to the
* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <rpc/rpc.h>
#include <rpcsvc/rstat.h>
#include <xview/xview.h>
#include <xview/font.h>
#include <xview/canvas.h>
#include <xview/panel.h>
#include <xview/notify.h>
#include <xview/defaults.h>
#include <xview/icon.h>
#include "icon.xbm"
#include <stdio.h>
#include "version.h"
extern int fork();
#define PROGNAME "perf"
#define CPU 1
#define PKTS 2
#define PAGE 3
#define SWAP 4
#define INTR 5
#define DISK 6
#define CTXT 7
#define LOAD 8
#define COLL 9
#define ERRS 10
#ifdef RSTATVERS_MEM
#define TMEM 11
#define TSWP 12
#endif
#define NUMCOLS 7
#define WARN 4
#define WHITE 5
#define BLACK 6
struct pm
{
int offset;
int starttime;
int startvalidx;
int posx, posy, width;
GC colorgc[NUMCOLS];
Pixmap pm;
} pm;
struct values
{
int type;
char *name;
char *subname[4];
int numvalues;
int **values, *last;
int maxval, maxval_to_show;
int active;
unsigned int
special:1,
draw_line:1,
add_values:1,
no_smooth:1,
draw_one:1,
no_reset:1,
selected:1,
delta:1;
int scrollback;
int sec_perpixel,
lastsec; /* Amount to wait till next shift */
int xpos, ypos;
int validx;
struct pm *pm;
} values[] =
{
{ CPU, "cpu", {"usr","nice","sys",0},3,0,0,100,-1, },
{ DISK,"disk",{"1", "2", "3","4"},4,0,0, 1,-1, },
{ PAGE,"page",{"in", "out", 0, 0},2,0,0, 1,-1, },
{ SWAP,"swap",{"in", "out", 0, 0},2,0,0, 1,-1, },
{ INTR,"interrupts",{0,0, 0, 0},1,0,0, 1,-1, },
{ PKTS,"packets",{"in","out",0, 0},2,0,0, 1,-1, },
{ ERRS,"errors", {"in","out",0, 0},2,0,0, 1,-1, },
{ COLL,"collisions",{0,0, 0, 0},1,0,0, 1,-1, },
{ CTXT,"context",{0, 0, 0, 0},1,0,0, 1,-1, },
{ LOAD,"load",{0, 0, 0, 0},1,0,0,256, 1, },
#ifdef RSTATVERS_MEM
{ TMEM,"mem", {"used","buf","cache",0},3,0,0,1,-1, },
{ TSWP,"swapspace",{0,0, 0, 0},1,0,0, 1,-1, },
#endif
{ 0, 0, {0, 0, 0, 0},0,0,0, 0, 0, }
}, *active = 0;
Frame fr, pfr;
Canvas ca;
Panel pn;
Panel_item pi_sels, pi_mach, pi_check, pi_spp, pi_cols, pi_msg,
pi_apply, pi_hide, pi_fork, pi_nosp, pi_scbk;
Display *dpy;
Window win;
int screen;
Xv_Font warnfont, font;
XFontStruct *warn_info, *font_info;
GC bwingc, wingc;
int win_x, real_win_y, win_y = 0,
warnheight, fontheight, depth, nrcurr_active,
width1, width2, height1, lost_connection = 0,
nr_lost,nr_neg,nr_lt,nr_inv;
char **argv;
/* Options */
int sec_perpixel = 2, lastsec = 0, scrollback = 600, columns = 1,
add_values, noadd = 0, delta = 0,
no_reset = 0, draw_line = 0, no_smooth = 0, draw_one = 0;
char *warnfontname=0;
char *host = 0;
int defcol[NUMCOLS] =
{ 0x000000, 0xa0a0a0, 0xc0c0c0, 0xe0e0e0, 0xff0000, 0xffffff, 0x000000 };
int defidx[NUMCOLS];
struct opts
{
char *name;
int *param;
int needsarg;
} opts[] =
{
{ "drawline", &draw_line, 0 },
{ "nosmooth", &no_smooth, 0 },
{ "drawone", &draw_one, 0 },
{ "noadd", &noadd, 0 },
{ "sampletime", &sec_perpixel, 1 },
{ "noreset", &no_reset, 0 },
{ "scrollback", &scrollback, 1 },
{ "columns", &columns, 1 },
{ "delta", &delta, 0 },
{ "col1", &defcol[0], 1 },
{ "col2", &defcol[1], 1 },
{ "col3", &defcol[2], 1 },
{ "col4", &defcol[3], 1 },
{ "warncol", &defcol[4], 1 },
{ "warnfont", (int*)&warnfontname,-1},
{ "fgcolor", &defcol[BLACK], 1 },
{ "bgcolor", &defcol[WHITE], 1 },
{ 0, 0, 0 },
};
#define FSET(v, flag) (v->special ? v->flag : flag)
#define VALUES_LENGTH(v) (FSET(v, scrollback)+width2)
#ifdef RSTATVERS_MEM
#define rstattype statsmem
int ismem = -1;
#else
#define rstattype statstime
#endif
struct rstattype sx;
int just_started = 1, do_clear = 0, diffdisk, min_spp;
Notify_value update();
do_alarm(t)
int t;
{
struct itimerval timer;
notify_enable_rpc_svc(1);
timer.it_value.tv_sec = timer.it_interval.tv_sec = t;
timer.it_value.tv_usec = timer.it_interval.tv_usec = 0;
notify_set_itimer_func(fr, update, ITIMER_REAL, &timer, NULL);
}
/* indx is needed by repaint, scrollback... */
static void
DrawPixels(val, p, indx, col)
struct values *val;
struct pm *p;
int indx, col;
{
int x, y, i, oldv, newv, old, new,
**vals = val->values,
vl = VALUES_LENGTH(val);
old = new = 0;
x = val->xpos * width1 + col;
y = val->ypos * height1 + height1 - fontheight;
if(FSET(val, add_values))
{
for(i = 0; i < val->numvalues; i++)
{
new += vals[i][indx];
old += vals[i][(indx-1+vl) % vl];
}
if(new > val->maxval) new = val->maxval;
if(old > val->maxval) old = val->maxval;
}
for(i = 0; i < val->numvalues; i++)
{
if(!FSET(val, add_values))
{
new = vals[i][indx];
old = vals[i][(indx-1+vl) % vl];
}
newv = (double)((height1-fontheight) * new) / (double)val->maxval;
oldv = (double)((height1-fontheight) * old) / (double)val->maxval;
if(FSET(val, draw_line))
{
XDrawLine(dpy, p->pm, p->colorgc[i], x-1, y - oldv, x, y - newv);
}
else
{
XDrawLine(dpy, p->pm, p->colorgc[i], x, y, x, y - newv);
if(!FSET(val, no_smooth))
{
if(newv > oldv)
XDrawLine(dpy, p->pm, p->colorgc[i],
x - 1, y - oldv, x - 1, y - oldv - (newv - oldv ) / 2);
else
XDrawLine(dpy, p->pm, p->colorgc[i],
x, y - newv, x, y - newv - (oldv - newv ) / 2);
}
}
if(FSET(val, draw_one))
break;
if(FSET(val, add_values))
{
new -= vals[i][indx];
old -= vals[i][(indx-1+vl) % vl];
}
}
}
static int
nextmax(v)
int v;
{
int m;
for(m = 10; ; m *= 10)
if(m > v || m > (1<<25))
break;
m /= 10;
if(v > m * 5)
return m * 10;
if(v > m * 2)
return m * 5;
else if(v > m)
return m * 2;
else
return m;
}
/* from can be larger then to*/
static int
rescale(val, from, to)
struct values *val;
int from, to;
{
int j, k, sum, max, tlen;
int changed = 0;
if(val->type == CPU)
return 0;
tlen = VALUES_LENGTH(val);
max = (val->type == LOAD) ? 256 : 1;
for(j = from; ; j = (j+1) % tlen)
{
for(sum = 0, k = val->numvalues - 1; k >= 0; k--)
sum += val->values[k][j];
if(sum > max)
if(val->type == LOAD)
while(sum > max) max *= 2;
else
max = sum;
if(j == to)
break;
}
#ifdef RSTATVERS_MEM
if(val->type == TMEM || val->type == TSWP)
val->maxval_to_show = val->maxval / 1024;
else
#endif
if(val->type == LOAD)
{
val->maxval_to_show = max / 256;
changed = (val->maxval > max);
val->maxval = max;
}
else
{
changed = (val->maxval > nextmax(max));
val->maxval = nextmax(max);
}
return changed;
}
#define MAXDIFF 10000000
#define CHECK_IT(a, b) { if(b < 0) nr_neg++; if(b < a){b = a; nr_lt++;} if(b > a + MAXDIFF) { nr_neg++; return 1;} }
static int
check_val(sxp)
struct rstattype *sxp;
{
int i, j;
struct values *v;
for(i = 0; values[i].numvalues; i++)
{
v = &values[i];
switch(v->type)
{
case CPU:
for(j = 0; j < 4; j++)
CHECK_IT(v->last[j], sxp->cp_time[j])
break;
case DISK:
for(j = 0; j < 4; j++)
if(sxp->dk_xfer[j] < 0)
sxp->dk_xfer[j] = 0, nr_neg++;
break;
case PAGE:
CHECK_IT(v->last[0], sxp->v_pgpgin)
CHECK_IT(v->last[1], sxp->v_pgpgout)
break;
case SWAP:
CHECK_IT(v->last[0], sxp->v_pswpin)
CHECK_IT(v->last[1], sxp->v_pswpout)
break;
case INTR:
CHECK_IT(v->last[0], sxp->v_intr)
break;
case PKTS:
CHECK_IT(v->last[0], sxp->if_ipackets)
CHECK_IT(v->last[1], sxp->if_opackets)
break;
case ERRS:
CHECK_IT(v->last[0], sxp->if_ierrors)
CHECK_IT(v->last[1], sxp->if_oerrors)
break;
case COLL:
CHECK_IT(v->last[0], sxp->if_collisions)
break;
case CTXT:
CHECK_IT(v->last[0], sxp->v_swtch)
break;
case LOAD:
if(sx.avenrun[0] > (10000<<8))
{
nr_neg++;
return 1;
}
break;
#ifdef RSTATVERS_MEM
case TMEM:
for(j = 0; j < 4; j++)
if(sxp->mem[j] < 0)
sxp->mem[j] = 0, nr_neg++;
break;
case TSWP:
for(j = 0; j < 2; j++)
if(sxp->swap[j] < 0)
sxp->swap[j] = 0, nr_neg++;
break;
#endif
}
}
return 0;
}
static void
fill_last(sxp)
struct rstattype *sxp;
{
int i, j;
struct values *v;
for(i = 0; values[i].numvalues; i++)
{
v = &values[i];
if(v->special && v->lastsec)
continue;
switch(v->type)
{
case CPU:
for(j = 0; j < 4; j++)
v->last[j] = sxp->cp_time[j];
break;
case DISK:
for(j = 0; j < 4; j++)
v->last[j] = sxp->dk_xfer[j];
break;
case PAGE:
v->last[0] = sxp->v_pgpgin;
v->last[1] = sxp->v_pgpgout;
break;
case SWAP:
v->last[0] = sxp->v_pswpin;
v->last[1] = sxp->v_pswpout;
break;
case INTR:
v->last[0] = sxp->v_intr;
break;
case PKTS:
v->last[0] = sxp->if_ipackets;
v->last[1] = sxp->if_opackets;
break;
case ERRS:
v->last[0] = sxp->if_ierrors;
v->last[1] = sxp->if_oerrors;
break;
case COLL:
v->last[0] = sxp->if_collisions;
break;
case CTXT:
v->last[0] = sxp->v_swtch;
break;
case LOAD:
break;
#ifdef RSTATVERS_MEM
case TMEM:
for(j = 0; j < 4; j++)
v->last[j] = sxp->mem[j];
break;
case TSWP:
for(j = 0; j < 2; j++)
v->last[j] = sxp->swap[j];
break;
#endif
}
}
}
static void
inc()
{
int i;
struct values *v;
for(i = 0; values[i].numvalues; i++)
{
v = &values[i];
if(!FSET(v, lastsec))
v->validx = (v->validx+1) % VALUES_LENGTH(v);
if(v->special)
v->lastsec = (v->lastsec+min_spp) % v->sec_perpixel;
}
lastsec = (lastsec+min_spp) % sec_perpixel;
}
Notify_value
update()
{
int i, j, redraw, from, to,
sum, sum1, x, y, ret;
double d;
struct values *v;
static void dopaint();
redraw = 0;
if(!values[0].last) /* Called before initialization */
return;
#ifdef RSTATVERS_MEM
if(ismem)
{
ret = callrpc(host, RSTATPROG, RSTATVERS_MEM, RSTATPROC_STATS,
#ifndef linux
xdr_void, (char *)NULL, xdr_statsmem, (char *)&sx);
#else
(xdrproc_t)xdr_void, (char *)NULL,
(xdrproc_t)xdr_statsmem, (char *)&sx);
#endif
if(ismem == -1)
ismem = !ret;
}
#endif
ret = rstat(host, &sx);
/* Check for working rstatd */
if(ret || !sx.cp_time[3] || (!just_started && check_val(&sx)))
{
static char noconn[]="Lost connection";
static char badrstatd[]="Bad rstatd";
char *wtxt;
int dir, ascent, descent;
XCharStruct or;
nr_lost++;
/* Draw 'Lost Connection' in every field */
if(lost_connection)
return NOTIFY_DONE;
wtxt = ret ? noconn : badrstatd;
XTextExtents(warn_info,wtxt,strlen(wtxt),&dir,&ascent,&descent,&or);
for(i = 0; values[i].numvalues; i++)
if(values[i].active)
{
XDrawImageString(dpy, pm.pm, pm.colorgc[WARN],
values[i].xpos * width2 + (width2 - or.width)/2,
values[i].ypos * height1 + (height1 - warnheight + ascent)/2,
wtxt, strlen(wtxt));
}
lost_connection = 1;
XCopyArea(dpy, pm.pm, win, wingc, 0, 0, win_x, real_win_y, 0, 0);
XFlush(dpy);
return NOTIFY_DONE;
}
if(lost_connection || just_started) /* Connection alive again */
{
if(just_started)
{
do_alarm(min_spp);
if(sx.dk_xfer[0] + sx.dk_xfer[1] +
sx.dk_xfer[2] + sx.dk_xfer[3] > 200)
diffdisk = 0;
else
diffdisk = 1;
}
fill_last(&sx);
just_started = 1; dopaint(1);
just_started = lost_connection = 0;
return NOTIFY_DONE;
}
/* Let's update */
for(i = 0; values[i].numvalues; i++)
{
v = &values[i];
if(FSET(v, lastsec))
continue;
/*
printf("%s,", v->name); fflush(stdout);
*/
switch(v->type)
{
case CPU:
for(j = sum = 0; j < 4; j++)
sum += sx.cp_time[j] - v->last[j];
if(!sum) /* Huhh?? But it happens!! */
{
fill_last(&sx);
nr_inv++;
return;
}
for(j = 0; j < 3; j++)
{
d = 100.0 * (sx.cp_time[j] - v->last[j])/(double)sum;
v->values[j][v->validx] = (int)(d+0.5);
}
break;
case PKTS:
#define DODIFF(a, b) (FSET(v, delta) ? (a-b) : (a-b)/FSET(v, sec_perpixel))
#define CHECKMAX(a) if(a > v->maxval) { if(v->active) redraw = 1; v->maxval = nextmax(a); }
sum = DODIFF(sx.if_ipackets, v->last[0]);
sum1 = DODIFF(sx.if_opackets, v->last[1]);
v->values[0][v->validx] = sum;
v->values[1][v->validx] = sum1;
CHECKMAX(sum+sum1);
break;
case PAGE:
sum = DODIFF(sx.v_pgpgin, v->last[0]);
sum1 = DODIFF(sx.v_pgpgout, v->last[1]);
v->values[0][v->validx] = sum;
v->values[1][v->validx] = sum1;
CHECKMAX(sum+sum1);
break;
case SWAP:
sum = DODIFF(sx.v_pswpin, v->last[0]);
sum1 = DODIFF(sx.v_pswpout, v->last[1]);
v->values[0][v->validx] = sum;
v->values[1][v->validx] = sum1;
CHECKMAX(sum+sum1);
break;
case INTR:
v->values[0][v->validx] = DODIFF(sx.v_intr, v->last[0]);
CHECKMAX(v->values[0][v->validx]);
break;
case DISK:
for(sum = j = 0; j < 4; j++)
{
v->values[j][v->validx] = sx.dk_xfer[j];
if(!diffdisk)
{
v->values[j][v->validx] -= v->last[j];
if(v->values[j][v->validx] < 0)
{
/* FIXME: if it IS diffdisk, we should delete/reinterpret the data */
v->values[j][v->validx] += v->last[j];
diffdisk = 1;
}
}
sum += v->values[j][v->validx];
v->values[j][v->validx] = DODIFF(v->values[j][v->validx], 0);
}
CHECKMAX(sum);
break;
case CTXT:
v->values[0][v->validx] = DODIFF(sx.v_swtch, v->last[0]);
CHECKMAX(v->values[0][v->validx]);
break;
case COLL:
v->values[0][v->validx] = DODIFF(sx.if_collisions, v->last[0]);
CHECKMAX(v->values[0][v->validx]);
break;
case LOAD:
v->values[0][v->validx] = sx.avenrun[0];
while(v->values[0][v->validx] > v->maxval && v->maxval < (10000<<8))
{
v->maxval *= 2;
v->maxval_to_show *= 2;
if(v->active) redraw = 1;
}
break;
case ERRS:
sum = DODIFF(sx.if_ierrors, v->last[0]);
sum1 = DODIFF(sx.if_oerrors, v->last[1]);
v->values[0][v->validx] = sum;
v->values[1][v->validx] = sum1;
CHECKMAX(sum+sum1);
break;
#ifdef RSTATVERS_MEM
case TMEM:
if(v->maxval != sx.mem[0])
{
v->maxval = sx.mem[0];
v->maxval_to_show = sx.mem[0]/1024;
}
v->values[0][v->validx] = sx.mem[0]-(sx.mem[1]+sx.mem[2]+sx.mem[3]);
v->values[1][v->validx] = sx.mem[2];
v->values[2][v->validx] = sx.mem[3];
break;
case TSWP:
if(v->maxval != sx.swap[0])
{
v->maxval = sx.swap[0];
v->maxval_to_show = sx.swap[0]/1024;
}
v->values[0][v->validx] = sx.swap[0] - sx.swap[1];
break;
#endif
}
}
fill_last(&sx);
/* Let's scroll back */
for(i = 0; values[i].numvalues; i++)
{
v = &values[i];
if(v->active && !FSET(v, lastsec))
{
x = v->xpos * width1;
y = v->ypos * height1;
XCopyArea(dpy, pm.pm, pm.pm, pm.colorgc[BLACK],
x+1, y, width2-1, height1-fontheight+2, x, y);
XDrawLine(dpy, pm.pm, pm.colorgc[WHITE],
x+width2-1, y, x+width2-1, y+height1);
}
}
/* Let's rescale, if necessary */
for(i = j = 0; values[i].numvalues; i++)
{
v = &values[i];
if(FSET(v, lastsec))
continue;
from = (v->validx + 1 - width2 + VALUES_LENGTH(v)) % VALUES_LENGTH(v);
to = v->validx;
if(!(FSET(v, no_reset) || v->pm || (v->validx % 20)))
redraw += rescale(v, from, to);
}
if(redraw)
{
inc();
dopaint(1);
}
else
{
for(i = 0; values[i].numvalues; i++)
{
v = &values[i];
if(v->active && !FSET(v, lastsec))
{
DrawPixels(v, &pm, v->validx, width2-1);
if(!v->pm)
{
x = v->xpos * width1; y = v->ypos * height1;
XCopyArea(dpy, pm.pm, win, wingc,
x, y, width2, height1-fontheight+2, x, y);
}
}
}
inc();
XFlush(dpy);
}
return NOTIFY_DONE;
}
static void
FreePM(p)
struct pm *p;
{
int i;
if(p->pm)
XFreePixmap(dpy, p->pm);
for(i = 0; i < NUMCOLS; i++)
if(p->colorgc[i])
XFreeGC(dpy, p->colorgc[i]);
}
static void
CreatePM(p, x, y)
struct pm *p;
int x, y;
{
XGCValues gcv;
int i, v, t;
FreePM(p);
p->pm = XCreatePixmap(dpy, win, x, y, depth);
for(i = 0; i < NUMCOLS; i++)
{
if(i != WARN)
gcv.font = xv_get(font, XV_XID);
else
gcv.font = xv_get(warnfont, XV_XID);
if(i == WHITE)
gcv.background = defidx[BLACK];
else if(i == WARN)
gcv.background = defidx[i];
else
gcv.background = defidx[WHITE];
if(i == WARN)
{
t = (defcol[WARN] & 0xff0000) >> 16;
v = (t > 200) ? 2*t-100 : t;
t = (defcol[WARN] & 0xff00) >> 8;
v += (t > 180) ? 2*t-100 : t;
t = defcol[WARN] & 0xff;
v += (t > 220) ? 2*t-100 : t;
gcv.foreground = defidx[v > 0x180 ? BLACK : WHITE];
}
else
gcv.foreground = defidx[i];
p->colorgc[i] = XCreateGC(dpy, p->pm,
GCFont|GCBackground|GCForeground,&gcv);
}
XFillRectangle(dpy, p->pm, p->colorgc[WHITE], 0, 0, x, y);
}
static void
realloc_values(v, oldlen, newlen)
struct values *v;
int oldlen, newlen;
{
int j, l, k,
*np, *op;
if(oldlen == newlen)
return;
if(!v->values) /* Let's initialize */
{
v->values = (int **)malloc(sizeof(int *) * v->numvalues);
for(l = 0; l < v->numvalues; l++)
v->values[l] = (int *)calloc(sizeof(int), newlen);
v->last = (int *)malloc(sizeof(int) * (v->type==CPU ? 4 : v->numvalues));
v->validx = newlen - 1;
return;
}
/* Realloc a ringbuffer */
for(l = 0; l < v->numvalues; l++)
{
np = (int *)calloc(sizeof(int), newlen);
op = v->values[l];
if(newlen > oldlen)
{
k = newlen - oldlen;
for(j = 0; j < k; j++)
np[j] = 0;
for(k = v->validx; j < newlen; j++, k = (k+1) % oldlen)
np[j] = op[k];
}
else
{
k = (v->validx + oldlen - newlen + 1) % oldlen;
for(j = 0; j < newlen; j++)
np[j] = op[(k+j)%oldlen];
}
free(op);
v->values[l] = np;
}
v->validx = newlen - 1;
}
static void
DrawText(v, drawtime)
struct values *v;
int drawtime;
{
int j, where, dir, ascent, descent;
int drone = FSET(v, draw_one);
int height = (v->ypos+1) * height1;
XCharStruct or;
char *ti, buf[16];
if(drawtime)
{
ti = (char *)ctime((time_t *)&drawtime) + 11; ti[8] = '\0';
if(!pm.width)
{
XTextExtents(font_info, ti, 8, &dir, &ascent, &descent, &or);
v->pm->posx = width2 - 1 - or.width;
v->pm->posy = height1 - 1 - descent;
v->pm->width = or.width;
}
XDrawImageString(dpy, pm.pm, pm.colorgc[BLACK],
v->xpos*width1 + v->pm->posx,
v->ypos*height1 + v->pm->posy, ti, 8);
return;
}
/* Draw text (cpu) */
XTextExtents(font_info, v->name, strlen(v->name), &dir,&ascent,&descent,&or);
XDrawImageString(dpy, pm.pm, pm.colorgc[BLACK],
v->xpos*width1+2, height-descent-1, v->name, strlen(v->name));
where = v->xpos*width1 + 2+or.width;
/* Draw more text (sys nice usr) */
for(j = 0; !drone && j < 4 && v->subname[j]; j++)
{
char *str = v->subname[j];
XDrawImageString(dpy, pm.pm, pm.colorgc[j],
where + 5, height-descent-1, str, strlen(str));
XTextExtents(font_info, str, strlen(str),
&dir,&ascent,&descent,&or);
where += 5 + or.width;
}
sprintf(buf, "%d", v->maxval_to_show == -1 ? v->maxval : v->maxval_to_show);
XTextExtents(font_info,buf,strlen(buf),&dir,&ascent,&descent,&or);
XDrawImageString(dpy, pm.pm, pm.colorgc[BLACK],
v->xpos * width1 + width2 - 2 - or.width,
height-descent-1, buf, strlen(buf));
}
static void
dopaint(doit)
int doit;
{
int x, y, i, j, k, vl, oldwidth2,
size_changed, dir, ascent, descent;
XCharStruct or;
struct values *v;
x = xv_get(canvas_paint_window(ca), XV_WIDTH);
y = xv_get(canvas_paint_window(ca), XV_HEIGHT) -1;
size_changed = (win_x != x || real_win_y != y);
if(size_changed || doit)
{
CreatePM(&pm, x, y);
win_x = x; win_y = real_win_y = y;
if(strcmp(host, "localhost"))
{
win_y = real_win_y - fontheight;
XTextExtents(font_info, host, strlen(host),
&dir, &ascent, &descent, &or);
XDrawImageString(dpy, pm.pm, pm.colorgc[BLACK],
(x-or.width)/2, real_win_y-descent-2, host, strlen(host));
}
oldwidth2 = width2;
width1 = win_x / columns;
width2 = width1 - 3;
height1 = win_y / ((nrcurr_active + columns - 1) / columns);
for(i = 0; values[i].numvalues; i++)
{
v = &values[i];
vl = VALUES_LENGTH(v);
realloc_values(v, FSET(v, scrollback) + oldwidth2, vl);
if(v->active)
{
DrawText(v, 0);
k = (v->validx - width2 + 1 + vl) % vl;
for(j = 1; j < width2; j++)
{
DrawPixels(&values[i], &pm, k, j);
k = (k+1) % vl;
}
}
}
}
/* Copy the stripes */
if(size_changed || just_started || do_clear)
{
XFillRectangle(dpy, win, wingc, 0, 0, x+10, y+10);
do_clear = 0;
}
for(i = 0; values[i].numvalues; i++)
{
v = &values[i];
if(!v->active)
continue;
x = v->xpos * width1; y = v->ypos * height1;
if(!v->pm)
{
XCopyArea(dpy, pm.pm, win, wingc, x, y, width2, height1, x, y);
}
else
{
XCopyArea(dpy, pm.pm, win, wingc,
x, y+height1-fontheight+1, width2, fontheight,
x, y+height1-fontheight+1);
x = FSET(v, scrollback);
XCopyArea(dpy, v->pm->pm, win, wingc,
x-v->pm->offset, 0, width2, height1-fontheight+1,
v->xpos * width1, v->ypos * height1);
}
}
if(real_win_y - win_y)
XCopyArea(dpy, pm.pm, win, wingc, 0,win_y,win_x,real_win_y-win_y,0,win_y);
for(i = 1; i < columns; i++)
{
x = (width1 * (i-1)) + width2 + 1;
XDrawLine(dpy, win, bwingc, x, 0, x, win_y);
}
XFlush(dpy);
}
static void
compute_delta()
{
int i, j, k, s, to, *val;
struct values *v;
for(i = 0; values[i].name; i++)
{
v = &values[i];
if(v->type == LOAD | v->type == CPU)
continue;
s = FSET(v, sec_perpixel);
for(j = 0; j < v->numvalues; j++)
{
val = v->values[j];
to = VALUES_LENGTH(v);
if(FSET(v, delta))
{
for(k = 0; k < to; k++)
val[k] *= s;
}
else
{
for(k = 0; k < to; k++)
val[k] /= s;
}
}
}
}
static int
checkbox()
{
int i, v, oldval = 0, from, to, vl;
struct values *p;
v = xv_get(pi_check, PANEL_VALUE);
if(active)
{
oldval |= active->draw_line ? 0 : 1;
oldval |= active->no_smooth ? 0 : 2;
oldval |= active->draw_one ? 4 : 0;
oldval |= active->no_reset ? 0 : 8;
oldval |= active->add_values?16 : 0;
oldval |= active->delta ?32 : 0;
active->draw_line = (v & 1) ? 0 : 1;
active->no_smooth = (v & 2) ? 0 : 1;
active->draw_one = (v & 4) ? 1 : 0;
active->add_values= (v &16) ? 1 : 0;
active->delta = (v &32) ? 1 : 0;
if((v&8) && active->no_reset)
{
vl = VALUES_LENGTH(active);
from = (active->validx + 1 - width2 + vl) % vl;
to = active->validx-1;
rescale(active, from, to);
}
active->no_reset = (v & 8) ? 0 : 1;
if(!active->draw_line && depth == 1)
active->draw_one = 1;
if((v & 32) != (oldval & 32))
compute_delta();
if(v != oldval) do_clear = 1;
return (v != oldval);
}
else
{
oldval |= draw_line ? 0 : 1;
oldval |= no_smooth ? 0 : 2;
oldval |= draw_one ? 4 : 0;
oldval |= no_reset ? 0 : 8;
oldval |= add_values?16 : 0;
oldval |= delta ?32 : 0;
draw_line = !(v & 1);
no_smooth = !(v & 2);
draw_one = (v & 4);
add_values= (v & 16);
delta = (v & 32);
if((v&8) && no_reset)
{
for(i = 0; values[i].numvalues; i++)
{
p = &values[i];
if(p->special)
continue;
vl = VALUES_LENGTH(p);
from = (p->validx + 1 - width2 + vl) % vl;
to = p->validx-1;
rescale(p, from, to);
}
}
no_reset = !(v & 8);
if(!draw_line && depth == 1)
draw_one = 1;
if((v & 32) != (oldval & 32))
compute_delta();
if(v != oldval) do_clear = 1;
return (v != oldval);
}
}
static int
selection(pi, v, e)
Panel_item pi;
int v;
Event *e;
{
int i, j, max;
int oldnr, changed = 0;
if(!v)
{
v = 1;
xv_set(pi, PANEL_VALUE, v, NULL);
}
oldnr = nrcurr_active;
for(i = 0; values[i].numvalues; i++)
{
if(values[i].active && !(v & (1<<i)))
{
for(j = 0; values[j].numvalues; j++)
if(values[j].active > values[i].active)
values[j].active--;
values[i].active = 0;
nrcurr_active--;
changed++;
}
else if(!values[i].active && (v & (1<<i)))
{
for(max = j = 0; values[j].numvalues; j++)
if(values[j].active > max)
max = values[j].active;
values[i].active = max+1;
nrcurr_active++;
changed++;
}
}
if(oldnr != nrcurr_active)
{
int diff, newheight;
/* just_started = 1; */
if(nrcurr_active < columns)
columns = nrcurr_active;
if(xv_get(pi_cols, PANEL_VALUE) != columns)
return changed;
newheight = height1*((nrcurr_active+columns-1)/columns)+real_win_y-win_y;
diff = xv_get(fr, XV_HEIGHT) - xv_get(canvas_paint_window(ca), XV_HEIGHT);
xv_set(canvas_paint_window(ca), XV_HEIGHT, newheight+1, NULL);
xv_set(fr, XV_HEIGHT, newheight+1+diff, NULL);
if(nrcurr_active < columns)
{
diff = xv_get(fr,XV_WIDTH) - xv_get(canvas_paint_window(ca),XV_WIDTH);
xv_set(canvas_paint_window(ca),XV_WIDTH,width1*columns, NULL);
xv_set(fr, XV_WIDTH, width1*columns+diff, NULL);
}
}
if(changed) do_clear = 1;
return changed;
}
static void
spp()
{
int i, min, v = xv_get(pi_spp, PANEL_VALUE);
if(active)
{
active->sec_perpixel = v;
active->lastsec = 0;
}
else
{
sec_perpixel = v;
lastsec = 0;
}
/* Ahem.. correct gcd would be better... */
min = sec_perpixel;
for(i = 0; values[i].numvalues; i++)
if(values[i].special && min != values[i].sec_perpixel)
{
if(min % values[i].sec_perpixel == 0)
min = values[i].sec_perpixel;
else if(values[i].sec_perpixel % min != 0)
min = 1;
}
if(min != min_spp)
{
min_spp = min;
do_alarm(min_spp);
}
}
static int
machine()
{
char *s = (char *)xv_get(pi_mach, PANEL_VALUE);
int i, j;
struct values *v;
if(!s || !*s)
s = "localhost";
if(!strcmp(s, host))
return 0;
#ifdef RSTATVERS_MEM
ismem = -1;
#endif
free(host);
for(i = 0; values[i].numvalues; i++)
{
v = &values[i];
for(j = 0; j < v->numvalues; j++)
memset(v->values[j], 0, sizeof(int) * VALUES_LENGTH(v));
rescale(v, 0, VALUES_LENGTH(v)-1);
}
host = strdup(s);
just_started = 1;
return 1;
}
static void
set_columns()
{
int i;
for(i = 0; values[i].numvalues; i++)
if(values[i].active)
{
values[i].xpos = (values[i].active-1) % columns;
values[i].ypos = (values[i].active-1) / columns;
}
}
static int
docolumns()
{
int i, newheight, newwidth, diffw, diffh;
if((i = xv_get(pi_cols, PANEL_VALUE)) == columns)
return 0;
columns = i > nrcurr_active ? nrcurr_active : i;
newwidth = width1 * columns;
newheight = height1 * ((nrcurr_active+columns-1)/columns) + real_win_y-win_y;
diffh = xv_get(fr, XV_HEIGHT) - xv_get(canvas_paint_window(ca), XV_HEIGHT);
diffw = xv_get(fr, XV_WIDTH) - xv_get(canvas_paint_window(ca), XV_WIDTH);
xv_set(canvas_paint_window(ca),
XV_HEIGHT, newheight + 1, XV_WIDTH, newwidth, NULL);
xv_set(fr, XV_HEIGHT, newheight+diffh+1, XV_WIDTH, newwidth+diffw, NULL);
return 1;
}
static void
doscrollback()
{
int i, oldlen = 0, v = xv_get(pi_scbk, PANEL_VALUE);
struct values *val;
if(active)
{
oldlen = VALUES_LENGTH(active);
active->special = 1;
active->scrollback = v;
realloc_values(active, oldlen, VALUES_LENGTH(active));
}
else
{
for(i = 0; values[i].numvalues; i++)
{
val = &values[i];
if(!(val->special))
{
oldlen = VALUES_LENGTH(val);
break;
}
}
scrollback = v;
for(i = 0; values[i].numvalues; i++)
{
val = &values[i];
if(!(val->special))
realloc_values(val, oldlen, VALUES_LENGTH(val));
}
}
}
static int
apply(i, e)
Panel_item i;
Event *e;
{
int redraw = 0;
if(!active)
{
redraw += selection(pi_sels, xv_get(pi_sels, PANEL_VALUE), e);
redraw += docolumns();
redraw += machine();
set_columns();
}
doscrollback();
spp();
redraw += checkbox();
if(redraw)
dopaint(1);
return XV_OK;
}
static int oldval;
static int
switch_it(i, v, e)
Panel_item i;
int v;
Event *e;
{
if(event_shift_is_down(e))
{
if(oldval > v) /* Depressed */
v = 0;
else /* Pressed */
v = 0xffff;
xv_set(i, PANEL_VALUE, v, NULL);
}
oldval = v;
}
static int
hide(i, e)
Panel_item i;
Event *e;
{
xv_set(pfr, XV_SHOW, FALSE, NULL);
return XV_OK;
}
static int
nosp_proc()
{
int i;
if(active)
active->special = 0;
else
{
for(i = 0; values[i].numvalues; i++)
values[i].special = 0;
}
dopaint(1);
return XV_OK;
}
static int
dofork()
{
switch(fork())
{
case -1:
perror("fork");
return XV_OK;
case 0:
/* Not very nice, but xview isn't reentrant */
execvp(argv[0], argv);
perror(argv[0]);
return XV_OK;
default:
return XV_OK;
}
}
static void
create_pfr()
{
int i, v, y;
pfr = xv_create(fr, FRAME_CMD, FRAME_LABEL, PROGNAME, NULL);
pn = xv_get(pfr, FRAME_CMD_PANEL);
xv_set(pn, WIN_ROW_GAP, xv_get(pn, WIN_ROW_GAP)/3, NULL);
for(v = i = 0; values[i].numvalues; i++)
if(values[i].active)
v |= (1 << i);
pi_sels = xv_create(pn, PANEL_TOGGLE,
XV_X, xv_col(pn, 1),
XV_Y, xv_row(pn, 0),
PANEL_CHOICE_STRINGS,
values[0].name, values[1].name, values[2].name, values[3].name,
values[4].name, values[5].name, values[6].name, values[7].name,
values[8].name, values[9].name,
#ifdef RSTATVERS_MEM
values[10].name, values[11].name,
#endif
NULL,
PANEL_CHOICE_NCOLS, 5,
PANEL_VALUE, v,
PANEL_NOTIFY_PROC, switch_it,
NULL);
oldval = v;
y = xv_get(pi_sels, XV_Y) + xv_get(pi_sels, XV_HEIGHT) + xv_row(pn, 1);
pi_check = xv_create(pn, PANEL_CHECK_BOX,
XV_Y, y,
PANEL_LAYOUT, PANEL_VERTICAL,
PANEL_CHOICE_STRINGS,
"Solid graph (s)", "Smooth if solid (o)", "Show sum only (1)",
"Autoreset", "Add values (a)", "Show deltas (d)", NULL,
NULL);
xv_set(pi_check,
XV_X, xv_get(pi_sels, XV_X) + xv_get(pi_sels, XV_WIDTH) -
xv_get(pi_check, XV_WIDTH),
NULL);
pi_mach = xv_create(pn, PANEL_TEXT,
XV_Y, y, XV_X, xv_get(pi_sels, XV_X),
PANEL_LABEL_STRING, "Machine:",
PANEL_VALUE, host,
PANEL_VALUE_DISPLAY_LENGTH, 16,
NULL);
pi_spp = xv_create(pn, PANEL_NUMERIC_TEXT,
XV_Y, xv_get(pi_mach, XV_Y) + xv_get(pi_mach, XV_HEIGHT) + xv_row(pn, 1)/2,
XV_X, xv_get(pi_sels, XV_X),
PANEL_LABEL_STRING, "Sample time (sec):",
PANEL_VALUE, sec_perpixel,
PANEL_MIN_VALUE, 1,
PANEL_VALUE_DISPLAY_LENGTH, 4,
NULL);
pi_scbk = xv_create(pn, PANEL_NUMERIC_TEXT,
XV_Y, xv_get(pi_spp, XV_Y) + xv_get(pi_spp, XV_HEIGHT) + xv_row(pn, 1)/2,
XV_X, xv_get(pi_sels, XV_X),
PANEL_LABEL_STRING, "Scrollback (values):",
PANEL_MIN_VALUE, 0,
PANEL_MAX_VALUE, 20000,
PANEL_VALUE, scrollback,
PANEL_VALUE_DISPLAY_LENGTH, 5,
NULL);
pi_cols = xv_create(pn, PANEL_NUMERIC_TEXT,
XV_Y, xv_get(pi_scbk, XV_Y) + xv_get(pi_scbk, XV_HEIGHT) + xv_row(pn, 1)/2,
XV_X, xv_get(pi_sels, XV_X),
PANEL_LABEL_STRING, "Columns:",
PANEL_INACTIVE, TRUE,
PANEL_MAX_VALUE, 10, PANEL_MIN_VALUE, 1,
PANEL_VALUE, columns,
PANEL_VALUE_DISPLAY_LENGTH, 2,
NULL);
pi_nosp = xv_create(pn, PANEL_BUTTON,
XV_Y, xv_get(pi_cols, XV_Y) + xv_get(pi_cols, XV_HEIGHT) + xv_row(pn, 1)/2,
XV_X, xv_get(pi_sels, XV_X),
PANEL_LABEL_STRING, "No special flags",
PANEL_NOTIFY_PROC, nosp_proc,
NULL);
pi_fork = xv_create(pn, PANEL_BUTTON,
XV_Y, xv_get(pi_nosp, XV_Y),
XV_X, xv_get(pi_nosp, XV_X) + xv_get(pi_nosp, XV_WIDTH) + xv_col(pn, 1),
PANEL_LABEL_STRING, "Fork",
PANEL_NOTIFY_PROC, dofork,
NULL);
pi_msg = xv_create(pn, PANEL_MESSAGE,
XV_Y, xv_get(pi_nosp, XV_Y) + xv_get(pi_nosp, XV_HEIGHT) + xv_row(pn, 1)/2,
XV_X, xv_get(pi_sels, XV_X),
NULL);
window_fit_width(pn);
pi_apply = xv_create(pn, PANEL_BUTTON,
XV_Y, xv_get(pi_check, XV_Y) + xv_get(pi_check, XV_HEIGHT) + xv_row(pn, 1),
PANEL_LABEL_STRING, "Apply",
PANEL_NOTIFY_PROC, apply,
NULL);
xv_set(pi_apply,
XV_X, xv_get(pn, XV_WIDTH)/3 - xv_get(pi_apply, XV_WIDTH)/2,
NULL);
pi_hide = xv_create(pn, PANEL_BUTTON,
XV_Y, xv_get(pi_apply, XV_Y),
PANEL_LABEL_STRING, "Hide window",
PANEL_NOTIFY_PROC, hide,
NULL);
xv_set(pi_hide,
XV_X, 2*xv_get(pn, XV_WIDTH)/3 - xv_get(pi_hide, XV_WIDTH)/2,
NULL);
window_fit(pn);
window_fit(pfr);
}
static void
grayout(val)
struct values *val;
{
int v = val ? 1 : 0;
char buf[256];
xv_set(pi_sels, PANEL_INACTIVE, v, NULL);
xv_set(pi_mach, PANEL_INACTIVE, v, NULL);
xv_set(pi_cols, PANEL_INACTIVE, v, NULL);
xv_set(pi_fork, PANEL_INACTIVE, v, NULL);
if(strcmp(host, "localhost"))
sprintf(buf, "%s (%s)", val ? active->name : PROGNAME, host);
else
sprintf(buf, "%s", val ? active->name : PROGNAME);
xv_set(pfr, FRAME_LABEL, buf, NULL);
v = 0;
if(val && val->special)
{
if(!val->draw_line) v |= 1; if(!val->no_smooth) v |= 2;
if(val->draw_one) v |= 4; if(!val->no_reset) v |= 8;
if(val->add_values) v |= 16; if(val->delta) v |= 32;
}
else
{
if(!draw_line) v |= 1; if(!no_smooth) v |= 2;
if(draw_one) v |= 4; if(!no_reset) v |= 8;
if(add_values) v |= 16; if(delta) v |= 32;
}
xv_set(pi_check, PANEL_VALUE, v, NULL);
xv_set(pi_spp,
PANEL_VALUE, (val && val->special) ? val->sec_perpixel : sec_perpixel,
NULL);
xv_set(pi_scbk,
PANEL_VALUE, (val && val->special) ? val->scrollback : scrollback,
NULL);
xv_set(pi_msg, PANEL_LABEL_STRING, "", NULL);
}
static struct values *
postoval(e)
Event *e;
{
int i, j = event_y(e)/height1, k = event_x(e)/width1;
for(i = 0; values[i].numvalues; i++)
if(values[i].active && values[i].xpos == k && values[i].ypos == j)
break;
if(!values[i].numvalues)
return 0;
return &values[i];
}
static void
reset_scrolled(ifzero)
int ifzero;
{
int i, xx, yy;
struct values *v;
for(i = 0; values[i].numvalues; i++)
if(values[i].pm)
{
if(!(ifzero && values[i].pm->offset))
{
v = &values[i];
xx = v->xpos * width1; yy = v->ypos * height1;
XFillRectangle(dpy, pm.pm, pm.colorgc[WHITE],
xx + v->pm->posx, yy + height1 - fontheight + 1,
v->pm->width, fontheight);
DrawText(v, 0);
XCopyArea(dpy, pm.pm, win, wingc,
xx + v->pm->posx, yy + height1 - fontheight + 2,
v->pm->width,fontheight,
xx + v->pm->posx, yy + height1 - fontheight + 2);
v->selected = 0;
FreePM(v->pm);
free(v->pm);
v->pm = 0;
}
}
else if(values[i].selected)
values[i].selected = 0;
}
static void
event_proc(w, e)
Xv_window w;
Event *e;
{
static int lastx, dragged;
struct values *v;
char buf[64];
int i, x, y;
if(event_is_ascii(e))
{
if(event_is_up(e))
return;
switch(event_action(e))
{
case 'q': case 'Q':
exit(0);
break;
case 'D':
if(pi_msg)
{
char buf[64];
sprintf(buf, "lost:%d decr:%d neg:%d invalid:%d",
nr_lost, nr_lt, nr_neg, nr_inv);
xv_set(pi_msg, PANEL_LABEL_STRING, buf, NULL);
}
break;
case 's': case 'S':
draw_line = !draw_line;
if(!draw_line && depth == 1)
draw_one = 1;
dopaint(1);
break;
case 'o': case 'O':
no_smooth = !no_smooth;
dopaint(1);
break;
case 'a':
add_values = !add_values;
dopaint(1);
break;
case 'd':
delta = !delta;
compute_delta();
dopaint(1);
break;
case '1':
draw_one = !draw_one;
if(!draw_line && depth == 1)
draw_one = 1;
dopaint(1);
break;
case '?': case 'h':
if(!pfr)
create_pfr();
xv_set(pfr, XV_SHOW, TRUE, NULL);
break;
case 10: /* CR/NL */
case 13:
reset_scrolled(0);
dopaint(1);
return;
}
return;
}
switch(event_action(e))
{
case WIN_RESIZE:
lost_connection = 0;
x = e->ie_xevent->xconfigure.width;
y = e->ie_xevent->xconfigure.height;
if(x <= win_x && y <= real_win_y)
{
reset_scrolled(0);
dopaint(0);
}
break;
case WIN_REPAINT:
x = xv_get(canvas_paint_window(ca), XV_WIDTH);
y = xv_get(canvas_paint_window(ca), XV_HEIGHT) -1;
if(x != win_x || y != real_win_y)
reset_scrolled(0);
dopaint(0);
break;
case LOC_DRAG:
if(!dragged)
return;
dragged = 2;
for(i = 0; values[i].numvalues; i++)
if(values[i].selected)
{
int k, off;
v = &values[i];
if(!v->pm)
{
int mx, my, vl, j, k;
vl = VALUES_LENGTH(v);
if(!v->pm)
v->pm = (struct pm *)calloc(1, sizeof(pm));
CreatePM(v->pm, vl, height1-fontheight+2);
v->pm->width = v->pm->offset = 0;
v->pm->starttime = time(0);
v->pm->startvalidx = v->validx;
mx = v->xpos; my = v->ypos;
v->xpos = v->ypos = 0;
k = (v->validx + 1) % vl;
for(j = 1; j < vl; k %= vl)
DrawPixels(v, v->pm, k++, j++);
v->xpos = mx; v->ypos = my;
}
off = v->pm->offset + event_x(e) - lastx;
k = v->special ? v->scrollback : scrollback;
if(off < 0) off = 0;
if(off > k) off = k;
if(off != v->pm->offset)
{
int xx = v->xpos * width1,
yy = v->ypos * height1;
v->pm->offset = off;
DrawText(v, v->pm->starttime -
(off * FSET(v, sec_perpixel)));
XCopyArea(dpy, v->pm->pm, win, wingc,
k - off, 0, width2, height1-fontheight+2, xx, yy);
XCopyArea(dpy, pm.pm, win, wingc,
xx + v->pm->posx, yy + height1 - fontheight+2,
v->pm->width,fontheight,
xx + v->pm->posx, yy + height1 - fontheight+2);
}
}
lastx = event_x(e);
break;
case ACTION_ADJUST:
case MS_MIDDLE:
if(event_is_up(e) || !(v = postoval(e)))
return;
v->selected = 1;
break;
case ACTION_SELECT:
case MS_LEFT:
if(event_is_down(e))
{
lastx = event_x(e);
dragged = 1;
if(!(v = postoval(e)))
return;
if(event_shift_is_down(e))
{
for(i = 0; values[i].numvalues; i++)
if(values[i].active)
values[i].selected = 1;
}
else if(!v->selected)
{
for(i = 0; values[i].numvalues; i++)
values[i].selected = 0;
v->selected = 1;
}
}
else
{
char buf[128];
if(dragged)
{
lastx = -1;
if(dragged == 2)
{
reset_scrolled(1);
dragged = 0;
return;
}
dragged = 0;
}
if(!(v = postoval(e)))
return;
y = VALUES_LENGTH(v);
x = v->pm ? v->pm->startvalidx - v->pm->offset : v->validx;
x -= ((width1 * v->xpos) + width2 - event_x(e));
x = (x + y) % y;
sprintf(buf, "%s: ", v->name);
if(v->type == LOAD)
{
sprintf(buf+strlen(buf), "%.2f",
(double)v->values[0][x]/256.0);
}
else
{
for(y = 0; y < v->numvalues; y++)
sprintf(buf+strlen(buf), "%s %d ",
v->subname[y]?v->subname[y] : "", v->values[y][x]);
}
if(pi_msg)
xv_set(pi_msg, PANEL_LABEL_STRING, buf, NULL);
}
break;
case ACTION_MENU:
case MS_RIGHT:
if(event_is_up(e))
return;
if(!pfr)
create_pfr();
if(event_shift_is_down(e))
{
active = postoval(e);
grayout(active);
}
else
{
if(xv_get(pfr, XV_SHOW))
{
xv_set(pfr, XV_SHOW, FALSE, NULL);
return;
}
active = NULL;
grayout(0);
}
sprintf(buf, "%s %s, © 1993-1996 Rudolf König", PROGNAME, VERSION);
xv_set(pi_msg, PANEL_LABEL_STRING, buf, NULL);
xv_set(pfr, XV_SHOW, TRUE, NULL);
break;
}
}
void
getdefault(idx)
int idx;
{
static char none[] = "NONE";
char *str, buffer[128];
sprintf(buffer, "%s.%s", PROGNAME, opts[idx].name);
str = defaults_get_string(buffer, buffer, none);
if(!strcmp(str, none))
return;
if(!opts[idx].needsarg)
{
if(!strcmp(str, "True") || !strcmp(str, "true") ||
!strcmp(str, "On") || !strcmp(str, "on") ||
!strcmp(str, "Yes") || !strcmp(str, "yes"))
*(opts[idx].param) = 1;
else
*(opts[idx].param) = 0;
return;
}
if(opts[idx].needsarg > 0)
{
if(*str == '#')
*(opts[idx].param) = strtol(str+1, NULL, 16);
else
*(opts[idx].param) = strtol(str, NULL, 0);
return;
}
*(opts[idx].param) = (int)str;
}
void
main(ac, av)
int ac;
char *av[];
{
XColor col;
XGCValues gcv;
int i, rows, len;
argv = (char **)calloc(ac+1, sizeof(char *));
for(i = 0; i < ac; i++)
argv[i] = strdup(av[i]);
xv_init(XV_INIT_ARGC_PTR_ARGV, &ac, av, NULL);
/* X - Resources */
for(i = 0; opts[i].name; i++)
getdefault(i);
/* Argument parsing... */
for(av++; ac > 1; ac--, av++)
{
if(*av[0] != '-')
{
host = strdup(av[0]);
continue;
}
for(i = 0; opts[i].name; i++)
if(!strcmp(av[0]+1, opts[i].name))
{
if(opts[i].needsarg)
{
if(!av[1] || !*av[1])
{
fprintf(stderr, "%s: Option %s needs an argument\n",
PROGNAME, av[0]);
exit(-1);
}
if(opts[i].needsarg > 0)
{
if(*av[1] == '#')
*opts[i].param = strtol(av[1]+1, NULL, 16);
else
*opts[i].param = strtol(av[1], NULL, 0);
av++; ac--;
}
else
{
*opts[i].param = (int)av[1];
av++; ac--;
}
}
else
*opts[i].param = 1;
goto next;
}
if(!strcmp(av[0]+1, "a"))
{
for(i = 0; values[i].numvalues; i++)
if(!values[i].active)
values[i].active = ++nrcurr_active;
goto next;
}
for(i = 0; values[i].numvalues; i++)
if(!strcmp(av[0]+1, values[i].name))
{
if(!values[i].active)
values[i].active = ++nrcurr_active;
goto next;
}
/* No valid option: print usage */
usage:
fprintf(stderr, "Usage: %s [-a]\n\t", PROGNAME);
for(len = 8,i = 0; opts[i].name; i++)
{
fprintf(stderr, "[-%s%s] ",opts[i].name,opts[i].needsarg?" <arg>":"");
len += strlen(opts[i].name) + 4 + (opts[i].needsarg ? 6 : 0);
if(len > 60)
{
fprintf(stderr, "\n\t");
len = 8;
}
}
for(i = 0; values[i].numvalues; i++)
{
fprintf(stderr, "[-%s] ", values[i].name);
len += strlen(values[i].name) + 4;
if(len > 60)
{
fprintf(stderr, "\n\t");
len = 8;
}
}
fprintf(stderr,
"[host]\n\nKeyboard accelerators: a,q,s,o,1,?,NL\n");
exit(-1);
next:
continue;
}
add_values = !noadd;
if(!host)
host = strdup("localhost");
if(!nrcurr_active)
{
nrcurr_active = 1;
values[0].active =1;
}
if(scrollback < 0) scrollback = 0;
if(sec_perpixel < 1) sec_perpixel = 1;
if(columns < 1) columns = 1;
if(columns > 10) columns = 10;
min_spp = sec_perpixel;
set_columns();
rows = (nrcurr_active + columns - 1) / columns;
fr = xv_create(0, FRAME,
FRAME_LABEL, PROGNAME,
XV_WIDTH, (columns > 3 ? columns * 100 : columns * 200) + 3,
XV_HEIGHT, (rows > 3 ? rows * 60 : rows * 100) + 10,
FRAME_SHOW_FOOTER, FALSE,
FRAME_SHOW_RESIZE_CORNER, TRUE,
FRAME_SHOW_HEADER, FALSE,
NULL);
do_alarm(min_spp);
ca = xv_create(fr, CANVAS,
XV_X, 0, XV_Y, 0,
CANVAS_RETAINED, FALSE,
CANVAS_AUTO_CLEAR, FALSE,
CANVAS_AUTO_SHRINK, TRUE,
CANVAS_AUTO_EXPAND, TRUE,
NULL);
window_fit(fr);
xv_set(canvas_paint_window(ca),
WIN_EVENT_PROC, event_proc,
WIN_CONSUME_EVENTS,
WIN_ASCII_EVENTS, WIN_RESIZE, WIN_REPAINT,
WIN_MOUSE_BUTTONS, LOC_DRAG, NULL,
NULL);
dpy = (Display *)xv_get(fr, XV_DISPLAY);
win = xv_get(canvas_paint_window(ca), XV_XID);
screen = xv_get(xv_get(fr, XV_SCREEN), SCREEN_NUMBER);
font = xv_get(fr, XV_FONT);
font_info =(XFontStruct *)xv_get(font, FONT_INFO);
#if 0
/* Returns -66+4 for the 5x7 :-( */
fontheight = xv_get(font, FONT_SIZE) + 4;
#else
{
int dm, as, ds;
XCharStruct ov;
XTextExtents(font_info, "Cpgf", 4, &dm, &as, &ds, &ov);
fontheight = as+ds+4;
}
#endif
/* ICON */
{
Pixmap pm;
Server_image sim;
Icon icon;
pm = XCreatePixmapFromBitmapData(dpy, win,
icon_bits, icon_width, icon_height, 0, 1, 1);
sim = (Server_image)xv_create(0,
SERVER_IMAGE, SERVER_IMAGE_PIXMAP, pm, NULL);
icon = xv_create(fr, ICON, XV_WIDTH, icon_width, XV_HEIGHT, icon_height,
ICON_IMAGE, sim, ICON_MASK_IMAGE, sim, NULL);
xv_set(fr, FRAME_ICON, icon, NULL);
}
defidx[0] = defidx[1] = defidx[2] = defidx[3] =
defidx[BLACK] = BlackPixel(dpy, screen);
defidx[WHITE] = WhitePixel(dpy, screen);
if((depth = xv_get(fr, XV_DEPTH)) > 1)
{
col.flags = DoRed|DoGreen|DoBlue;
for(i = 0; i < NUMCOLS; i++)
{
col.pixel = BlackPixel(dpy, screen);
col.red = (defcol[i] & 0xff0000) >> 8;
col.green = (defcol[i] & 0x00ff00);
col.blue = (defcol[i] & 0x0000ff) << 8;
XAllocColor(dpy, DefaultColormap(dpy, screen), &col);
defidx[i] = col.pixel;
}
}
gcv.foreground = defidx[WHITE];
wingc = XCreateGC(dpy, win, GCForeground,&gcv);
gcv.foreground = defidx[BLACK];
bwingc = XCreateGC(dpy, win, GCForeground,&gcv);
if(warnfontname)
{
int dm, as, ds;
XCharStruct ov;
if(!(warnfont = xv_find(fr, FONT, FONT_NAME, warnfontname, NULL)))
{
printf("Can't find %s, using default\n", warnfont);
warnfont = font;
}
warn_info =(XFontStruct *)xv_get(warnfont, FONT_INFO);
XTextExtents(warn_info, "Cpgf", 4, &dm, &as, &ds, &ov);
warnheight = as+ds+4;
}
else
{
warn_info = font_info;
warnheight = fontheight;
warnfont = font;
}
if(!draw_line && depth == 1)
draw_one = 1;
xv_main_loop(fr);
}
syntax highlighted by Code2HTML, v. 0.9.1