|
|
1.1 root 1: /* $Header: Load.c,v 1.2 87/09/12 12:43:16 swick Exp $ */
2: #ifndef lint
3: static char *sccsid = "@(#)Load.c 1.15 2/25/87";
4: #endif lint
5:
6: /*
7: * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
8: *
9: * All Rights Reserved
10: *
11: * Permission to use, copy, modify, and distribute this software and its
12: * documentation for any purpose and without fee is hereby granted,
13: * provided that the above copyright notice appear in all copies and that
14: * both that copyright notice and this permission notice appear in
15: * supporting documentation, and that the name of Digital Equipment
16: * Corporation not be used in advertising or publicity pertaining to
17: * distribution of the software without specific, written prior permission.
18: *
19: *
20: * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
21: * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
22: * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
23: * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
24: * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
25: * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
26: * SOFTWARE.
27: */
28:
29:
30: #include <stdio.h>
31: #include <strings.h>
32: #include "Xlib.h"
33: #include "Xutil.h"
34: #include "Intrinsic.h"
35: #include "Load.h"
36: #include "Atoms.h"
37: #include <nlist.h>
1.1.1.2 ! root 38: #include <time.h>
1.1 root 39: #include <sys/param.h>
40:
41: extern long lseek();
42:
43: /* Private Definitions */
44:
45: typedef struct WidgetDataRec {
46: Display *dpy; /* widget display connection */
47: Window window; /* widget window */
48: Dimension brwidth; /* border width in pixels */
49: Dimension width, height; /* width/height in pixels */
50: Position x, y;
51: Pixel fgpixel; /* color index for text */
52: Pixel bgpixel; /* color index for background */
53: Pixel brpixel; /* pixel for border */
54: XFontStruct *fontstruct; /* font for text */
55: GC myGC; /* pointer to GraphicsContext */
56: /* start of graph stuff */
57: int update; /* update frequence */
58: int scale; /* scale factor */
59: int min_scale; /* smallest scale factor */
60: int interval; /* data point interval */
61: char *text; /* label */
62: double max_value; /* Max Value in window */
63: int mapped; /* is exposed */
64: double valuedata[2048];/* record of data points */
65: /* start of xload stuff
66: char *vmunix; /* path of namelist */
67: caddr_t cookie;
68: } WidgetDataRec, *WidgetData;
69:
70:
71: /* Private Data */
72:
73: static WidgetDataRec globaldata;
74:
75: static int initDone = 0; /* initialization flag */
76: static XContext widgetContext;
77: static int def_border = 1;
78: static int def_width = 120;
79: static int def_height = 120;
80: static int def_update = 5;
81: static int def_x = 0;
82: static int def_y = 0;
83: static int def_scale = 1;
84:
85: static Resource resourcelist[] = {
86: {XtNwindow, XtCWindow, XrmRWindow,
87: sizeof(Window), (caddr_t)&globaldata.window, (caddr_t)NULL},
88: {XtNborderWidth, XtCBorderWidth, XrmRInt,
89: sizeof(int), (caddr_t)&globaldata.brwidth, (caddr_t) &def_border},
90: {XtNwidth, XtCWidth, XrmRInt,
91: sizeof(int), (caddr_t)&globaldata.width, (caddr_t) &def_width},
92: {XtNheight, XtCHeight, XrmRInt,
93: sizeof(int), (caddr_t)&globaldata.height, (caddr_t) &def_height },
94: {XtNx, XtCX, XrmRInt,
95: sizeof(int), (caddr_t)&globaldata.x, (caddr_t) &def_x },
96: {XtNy, XtCX, XrmRInt,
97: sizeof(int), (caddr_t)&globaldata.y, (caddr_t) &def_y },
98: {XtNupdate, XtCInterval, XrmRInt,
99: sizeof(int), (caddr_t)&globaldata.update, (caddr_t) &def_update },
100: {XtNscale, XtCScale, XrmRInt,
101: sizeof(int), (caddr_t)&globaldata.scale, (caddr_t) &def_scale },
102: {XtNminScale, XtCScale, XrmRInt,
103: sizeof(int), (caddr_t)&globaldata.min_scale, (caddr_t) &def_scale },
104: {XtNlabel, XtCLabel, XrmRString,
105: sizeof(char *), (caddr_t)&globaldata.text, (caddr_t) "Amnesia" },
106: {XtNforeground, XtCColor, XrmRPixel,
107: sizeof(int), (caddr_t)&globaldata.fgpixel, (caddr_t)&XtDefaultFGPixel},
108: {XtNbackground, XtCColor, XrmRPixel,
109: sizeof(int), (caddr_t)&globaldata.bgpixel, (caddr_t)&XtDefaultBGPixel},
110: {XtNborder, XtCColor, XrmRPixel,
111: sizeof(int),(caddr_t)&globaldata.brpixel, (caddr_t)&XtDefaultFGPixel},
112: {XtNfont, XtCFont, XrmRFontStruct,
113: sizeof(XFontStruct *), (caddr_t)&globaldata.fontstruct, (caddr_t)NULL}
114: };
115:
116:
117: /****************************************************************
118: *
119: * Private Procedures
120: *
121: ****************************************************************/
122:
123: static void LoadInitialize (dpy)
124: Display *dpy;
125: {
126: if(!initDone)
127: globaldata.fontstruct = XLoadQueryFont(dpy,"fixed");
128: widgetContext = XUniqueContext();
129:
130: initDone = 1;
131: }
132:
133:
134: /*
135: * Given a display and window, get the widget data.
136: */
137:
138: static WidgetData DataFromWindow(dpy, window)
139: Display *dpy;
140: Window window;
141: {
142: WidgetData result;
143: if (XFindContext(dpy, window, widgetContext, (caddr_t *)&result))
144: return NULL;
145: return result;
146: }
147:
148: static void Destroy();
149:
150: /*
151: *
152: * Generic widget event handler
153: *
154: */
155:
156:
157: static XtEventReturnCode EventHandler(event, eventdata)
158: XEvent *event;
159: caddr_t eventdata;
160: {
161: WidgetData data = (WidgetData ) eventdata;
162:
163: switch (event->type) {
164: case ConfigureNotify:
165: data->height = event->xconfigure.height;
166: data->width = event->xconfigure.width;
167: break;
168:
169: case DestroyNotify:
170: Destroy(data);
171: break;
172:
173: case ClientMessage:
174: if (((XClientMessageEvent *)event)->message_type ==
175: (unsigned) XtTimerExpired)
176: draw_it(data);
177: break;
178:
179: case Expose:
180: data->mapped = 1;
181: if( ((XExposeEvent *)event)->count == 0)
182: data->interval = repaint_window(data);
183: break;
184:
185: case NoExpose:
186: data->mapped = 0;
187: break;
188: }
189:
190: return (XteventHandled);
191: }
192:
193: /*
194: *
195: * Destroy the widget
196: *
197: */
198:
199: static void Destroy(data)
200: WidgetData data;
201: {
202:
203: XtClearEventHandlers(data->dpy, data->window);
204: (void) XtClearTimeOut(data->window, data->cookie);
205: XtFree ((char *) data);
206: }
207:
208:
209:
210: /****************************************************************
211: *
212: * Public Procedures
213: *
214: ****************************************************************/
215:
216: Window XtLoadCreate(dpy, pw, arglist, argCount)
217: Display *dpy;
218: Window pw; /* parent window */
219: ArgList arglist;
220: int argCount;
221: {
222: WidgetData data;
223: int eventmask;
224: GCMask valuemask;
225: XrmNameList names;
226: XrmClassList classes;
227: XGCValues myXGCV;
228: if (!initDone)LoadInitialize (dpy);
229:
230: data = (WidgetData ) XtMalloc (sizeof (WidgetDataRec));
231:
232: /* Set Default Values */
233: globaldata.dpy = dpy;
234: XtGetResources(dpy, resourcelist, XtNumber(resourcelist), arglist, argCount, pw,
235: "load", "Load", &names, &classes);
236: *data = globaldata;
237: valuemask = GCForeground | GCFont | GCBackground;
238: myXGCV.foreground = (*data).fgpixel;
239: myXGCV.font = (*data).fontstruct->fid;
240: myXGCV.background = data->bgpixel;
241: (*data).myGC = XtGetGC(data->dpy, widgetContext, pw, valuemask, &myXGCV);
242:
243: if (data->window != NULL) {
244: XWindowAttributes wi;
245: /* set global data from window parameters */
246: if (! XGetWindowAttributes(data->dpy,data->window, &wi)) {
247: data->window = NULL;
248: } else {
249: data->brwidth = wi.border_width;
250: data->width = wi.width;
251: data->height = wi.height;
252: }
253: }
254: if (data->window == NULL) {
255: /* create the Load window */
256: if(data->width >= 2048) data->width = 2047;
257: data->window = XCreateSimpleWindow(data->dpy, pw, data->x, data->y,
258: data->width, data->height,
259: data->brwidth, data->brpixel, data->bgpixel);
260: }
261:
262: XtSetNameAndClass(data->dpy, data->window, names, classes);
263: XrmFreeNameList(names);
264: XrmFreeClassList(classes);
265:
266: (void)XSaveContext(data->dpy, data->window, widgetContext, (caddr_t)data);
267:
268: /* set handler for expose, resize, and message events */
269:
270: eventmask = ExposureMask+StructureNotifyMask;
271: XtSetEventHandler (
272: data->dpy, data->window, (XtEventHandler)EventHandler,
273: (unsigned long) eventmask, (caddr_t)data);
274:
275: XtSetTimeOut(data->window, XtNLoad,data->update*1000);
276:
277: return (data->window);
278: }
279:
280: /*
281: * Get Attributes
282: */
283:
284: void XtLoadGetValues (dpy, window, arglist, argCount)
285: Display *dpy;
286: Window window;
287: ArgList arglist;
288: int argCount;
289: {
290: WidgetData data;
291: data = DataFromWindow(dpy, window);
292: if (data) {
293: globaldata = *data;
294: XtGetValues(resourcelist, XtNumber(resourcelist), arglist, argCount);
295: }
296: }
297:
298: /*
299: * Set Attributes
300: */
301:
302: void XtLoadSetValues (dpy, window, arglist, argCount)
303: Display *dpy;
304: Window window;
305: ArgList arglist;
306: int argCount;
307: {
308: WidgetData data;
309: data = DataFromWindow(dpy, window);
310: globaldata = *data;
311: if (data == NULL) return;
312:
313: XtSetValues(resourcelist, XtNumber(resourcelist), arglist, argCount);
314:
315: if (globaldata.update != data->update) {
316: (void) XtClearTimeOut(data->window, data->cookie);
317: XtSetTimeOut(data->window, data->cookie, globaldata.update*1000);
318: data->update = globaldata.update;
319: }
320: if (globaldata.brpixel != data->brpixel) {
321: data->brpixel = globaldata.brpixel;
322: if (data->brwidth != 0)
323: XSetWindowBorder(data->dpy, data->window, data->brpixel);
324: }
325: if(!strcmp(globaldata.text, data->text)) {
326: data->interval = repaint_window(data);
327: }
328: if(data->width >= 2048) data->width = 2047;
329:
330: *data = globaldata;
331: }
332:
333:
334: static draw_it(data)
335: WidgetDataRec *data;
336: {
337: double value, GetLoadPoint();
338:
339: if (data->interval >= data->width)
340: data->interval =
341: repaint_window(data);
342: /* Get the value, stash the point and draw corresponding line. */
343:
344: value = GetLoadPoint();
345: /* Keep data->max_value up to date, and if this data point is off the
346: graph, change the scale to make it fit. */
347: if (value > data->max_value) {
348: data->max_value = value;
349: if (data->max_value > data->scale) {
350: data->scale = ((int)data->max_value) + 1;
351: data->interval =
352: repaint_window(data);
353: }
354: }
355:
356: data->valuedata[data->interval] = value;
357: if (data->mapped) {
358:
359: XDrawLine(data->dpy, data->window, data->myGC,
360: data->interval, (int)data->height, data->interval,
361: (int)(data->height - (data->height * value) /data->scale));
362: XFlush(data->dpy); /* Flush output buffers */
363: }
364: data->interval++; /* Next point */
365: } /* draw_it */
366:
367: /* Blts data according to current size, then redraws the load average window.
368: * Next represents the number of valid points in data. Returns the (possibly)
369: * adjusted value of next. If next is 0, this routine draws an empty window
370: * (scale - 1 lines for graph). If next is less than the current window width,
371: * the returned value is identical to the initial value of next and data is
372: * unchanged. Otherwise keeps half a window's worth of data. If data is
373: * changed, then data->max_value is updated to reflect the largest data point.
374: */
375:
376: static int repaint_window(data)
377: WidgetDataRec *data;
378: {
379: register int i, j;
380: register int next = data->interval;
381: extern void bcopy(), exit();
382:
383: if (data->mapped)
384: XClearWindow(data->dpy, data->window);
385: if (next >= data->width) {
386: j = data->width >> 1;
387: bcopy((char *)(data->valuedata + next - j),
388: (char *)(data->valuedata), j * sizeof(double));
389: next = j;
390: /* Since we just lost some data, recompute the data->max_value. */
391: data->max_value = 0.0;
392: for (i = 0; i < next; i++) {
393: if (data->valuedata[i] > data->max_value)
394: data->max_value = data->valuedata[i];
395: }
396: }
397:
398: /* Compute the minimum scale required to graph the data, but don't go
399: lower than min_scale. */
400: if (data->max_value > data->min_scale)
401: data->scale = ((int)data->max_value) + 1;
402: else
403: data->scale = data->min_scale;
404:
405: if (!data->mapped) return(next);
406:
407: /* Print hostname */
408: XDrawString(data->dpy, data->window, data->myGC, 2,
409: 2 + data->fontstruct->ascent, data->text, strlen(data->text));
410:
411: /* Draw graph reference lines */
412: for (i = 1; i < data->scale; i++) {
413: j = (i * data->height) / data->scale;
414: XDrawLine(data->dpy, data->window, data->myGC, 0, j,
415: (int)data->width, j);
416: }
417:
418: /* Draw data point lines. */
419: for (i = 0; i < next; i++)
420: XDrawLine(data->dpy, data->window, data->myGC , i, (int)data->height,
421: i, (int)(data->height-(data->valuedata[i] * data->height)
422: /data->scale));
423: return(next);
424: }
425:
426: #define KMEM_FILE "/dev/kmem"
427: #define KMEM_ERROR "cannot open /dev/kmem"
428:
429: static struct nlist namelist[] = { /* namelist for vmunix grubbing */
430: #define LOADAV 0
431: {"_avenrun"},
432: {0}
433: };
434:
435: static double GetLoadPoint()
436: {
1.1.1.2 ! root 437: float loadavg;
1.1 root 438: static int init = 0;
439: static kmem;
440: static long loadavg_seek;
441: extern void nlist();
442:
443: if(!init) {
1.1.1.2 ! root 444: nlist( "/unix", namelist);
1.1 root 445: if (namelist[LOADAV].n_type == 0){
446: xload_error("xload: cannot get name list");
447: exit(-1);
448: }
449: loadavg_seek = namelist[LOADAV].n_value;
1.1.1.2 ! root 450: kmem = open(KMEM_FILE, 0);
1.1 root 451: if (kmem < 0) xload_error(KMEM_ERROR);
452: init = 1;
453: }
454:
455:
456: (void) lseek(kmem, loadavg_seek, 0);
1.1.1.2 ! root 457: (void) read(kmem, (char *)&loadavg, sizeof(float));
! 458: return((double)loadavg);
1.1 root 459: }
460:
461: static xload_error(str)
462: char *str;
463: {
464: extern void exit();
465:
466: (void) fprintf(stderr,"xload: %s\n",str);
467: exit(-1);
468: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.