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