1 /* $Cambridge: exim/src/exim_monitor/em_StripChart.c,v 1.1 2004/10/07 10:39:01 ph10 Exp $ */
2 /* $XConsortium: StripChart.c,v 1.20 91/05/24 17:20:42 converse Exp $ */
4 /***********************************************************
5 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
6 and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
10 Permission to use, copy, modify, and distribute this software and its
11 documentation for any purpose and without fee is hereby granted,
12 provided that the above copyright notice appear in all copies and that
13 both that copyright notice and this permission notice appear in
14 supporting documentation, and that the names of Digital or MIT not be
15 used in advertising or publicity pertaining to distribution of the
16 software without specific, written prior permission.
18 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
19 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
20 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
21 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
23 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
26 ******************************************************************/
28 /* This is the Athena StripChart widget, slightly hacked by
29 Philip Hazel <ph10@cus.cam.ac.uk> in order to give access to
30 its repaint_window function so that a repaint can be forced.
32 The repaint_window function has also been nobbled so that it only
33 ever changes scale to 10. There is probably a better way to handle
34 this - such as inventing some new resources, but I'm not up to
35 that just at the moment.
37 On SunOS4 there are name clashes when trying to link this with the
38 Athena library. So to avoid them, rename a few things by inserting
39 "my" at the front of "strip". */
43 #include <X11/IntrinsicP.h>
44 #include <X11/StringDefs.h>
45 #include <X11/Xaw/XawInit.h>
46 #include <X11/Xaw/StripCharP.h>
47 #include <X11/Xfuncs.h>
49 #define MS_PER_SEC 1000
53 #define offset(field) XtOffsetOf(StripChartRec, field)
55 static XtResource resources[] = {
56 {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
57 offset(core.width), XtRImmediate, (XtPointer) 120},
58 {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
59 offset(core.height), XtRImmediate, (XtPointer) 120},
60 {XtNupdate, XtCInterval, XtRInt, sizeof(int),
61 offset(strip_chart.update), XtRImmediate, (XtPointer) 10},
62 {XtNminScale, XtCScale, XtRInt, sizeof(int),
63 offset(strip_chart.min_scale), XtRImmediate, (XtPointer) 1},
64 {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
65 offset(strip_chart.fgpixel), XtRString, XtDefaultForeground},
66 {XtNhighlight, XtCForeground, XtRPixel, sizeof(Pixel),
67 offset(strip_chart.hipixel), XtRString, XtDefaultForeground},
68 {XtNgetValue, XtCCallback, XtRCallback, sizeof(XtPointer),
69 offset(strip_chart.get_value), XtRImmediate, (XtPointer) NULL},
70 {XtNjumpScroll, XtCJumpScroll, XtRInt, sizeof(int),
71 offset(strip_chart.jump_val), XtRImmediate, (XtPointer) DEFAULT_JUMP},
76 /* Added argument types to these to shut picky compilers up. PH */
78 static void CreateGC(StripChartWidget, unsigned int);
79 static void DestroyGC(StripChartWidget, unsigned int);
80 static void Initialize(), Destroy(), Redisplay();
81 static void MoveChart(StripChartWidget, Boolean);
82 static void SetPoints(StripChartWidget);
83 static Boolean SetValues();
85 int repaint_window(StripChartWidget, int, int); /* PH hack */
86 /* static int repaint_window(); */
88 StripChartClassRec stripChartClassRec = {
90 /* superclass */ (WidgetClass) &simpleClassRec,
91 /* class_name */ "StripChart",
92 /* size */ sizeof(StripChartRec),
93 /* class_initialize */ XawInitializeWidgetSet,
94 /* class_part_initialize */ NULL,
95 /* class_inited */ FALSE,
96 /* initialize */ Initialize,
97 /* initialize_hook */ NULL,
98 /* realize */ XtInheritRealize,
101 /* resources */ resources,
102 /* num_resources */ XtNumber(resources),
103 /* xrm_class */ NULLQUARK,
104 /* compress_motion */ TRUE,
105 /* compress_exposure */ XtExposeCompressMultiple |
106 XtExposeGraphicsExposeMerged,
107 /* compress_enterleave */ TRUE,
108 /* visible_interest */ FALSE,
109 /* destroy */ Destroy,
110 /* resize */ (void (*)(Widget))SetPoints,
111 /* expose */ Redisplay,
112 /* set_values */ SetValues,
113 /* set_values_hook */ NULL,
114 /* set_values_almost */ NULL,
115 /* get_values_hook */ NULL,
116 /* accept_focus */ NULL,
117 /* version */ XtVersion,
118 /* callback_private */ NULL,
120 /* query_geometry */ XtInheritQueryGeometry,
121 /* display_accelerator */ XtInheritDisplayAccelerator,
124 { /* Simple class fields */
125 /* change_sensitive */ XtInheritChangeSensitive
129 WidgetClass mystripChartWidgetClass = (WidgetClass) &stripChartClassRec;
131 /****************************************************************
135 ****************************************************************/
137 static void draw_it();
139 /* Function Name: CreateGC
140 * Description: Creates the GC's
141 * Arguments: w - the strip chart widget.
142 * which - which GC's to create.
153 if (which & FOREGROUND) {
154 myXGCV.foreground = w->strip_chart.fgpixel;
155 w->strip_chart.fgGC = XtGetGC((Widget) w, GCForeground, &myXGCV);
158 if (which & HIGHLIGHT) {
159 myXGCV.foreground = w->strip_chart.hipixel;
160 w->strip_chart.hiGC = XtGetGC((Widget) w, GCForeground, &myXGCV);
164 /* Function Name: DestroyGC
165 * Description: Destroys the GC's
166 * Arguments: w - the strip chart widget.
167 * which - which GC's to destroy.
176 if (which & FOREGROUND)
177 XtReleaseGC((Widget) w, w->strip_chart.fgGC);
179 if (which & HIGHLIGHT)
180 XtReleaseGC((Widget) w, w->strip_chart.hiGC);
184 static void Initialize (greq, gnew)
187 StripChartWidget w = (StripChartWidget)gnew;
189 if (w->strip_chart.update > 0)
190 w->strip_chart.interval_id = XtAppAddTimeOut(
191 XtWidgetToApplicationContext(gnew),
192 w->strip_chart.update * MS_PER_SEC,
193 draw_it, (XtPointer) gnew);
194 CreateGC(w, (unsigned int) ALL_GCS);
196 w->strip_chart.scale = w->strip_chart.min_scale;
197 w->strip_chart.interval = 0;
198 w->strip_chart.max_value = 0.0;
199 w->strip_chart.points = NULL;
203 static void Destroy (gw)
206 StripChartWidget w = (StripChartWidget)gw;
208 if (w->strip_chart.update > 0)
209 XtRemoveTimeOut (w->strip_chart.interval_id);
210 if (w->strip_chart.points)
211 XtFree((char *) w->strip_chart.points);
212 DestroyGC(w, (unsigned int) ALL_GCS);
216 * NOTE: This function really needs to recieve graphics exposure
217 * events, but since this is not easily supported until R4 I am
218 * going to hold off until then.
222 static void Redisplay(w, event, region)
227 if (event->type == GraphicsExpose)
228 (void) repaint_window ((StripChartWidget)w, event->xgraphicsexpose.x,
229 event->xgraphicsexpose.width);
231 (void) repaint_window ((StripChartWidget)w, event->xexpose.x,
232 event->xexpose.width);
237 draw_it(client_data, id)
238 XtPointer client_data;
239 XtIntervalId *id; /* unused */
241 StripChartWidget w = (StripChartWidget)client_data;
244 if (w->strip_chart.update > 0)
245 w->strip_chart.interval_id =
246 XtAppAddTimeOut(XtWidgetToApplicationContext( (Widget) w),
247 w->strip_chart.update * MS_PER_SEC,draw_it,client_data);
249 if (w->strip_chart.interval >= (int)w->core.width)
250 MoveChart( (StripChartWidget) w, TRUE);
252 /* Get the value, stash the point and draw corresponding line. */
254 if (w->strip_chart.get_value == NULL)
257 XtCallCallbacks( (Widget)w, XtNgetValue, (XtPointer)&value );
260 * Keep w->strip_chart.max_value up to date, and if this data
261 * point is off the graph, change the scale to make it fit.
264 if (value > w->strip_chart.max_value) {
265 w->strip_chart.max_value = value;
266 if (w->strip_chart.max_value > w->strip_chart.scale) {
267 XClearWindow( XtDisplay (w), XtWindow (w));
268 w->strip_chart.interval = repaint_window(w, 0, (int) w->core.width);
272 w->strip_chart.valuedata[w->strip_chart.interval] = value;
273 if (XtIsRealized((Widget)w)) {
274 int y = (int) (w->core.height
275 - (int)(w->core.height * value) / w->strip_chart.scale);
277 XFillRectangle(XtDisplay(w), XtWindow(w), w->strip_chart.fgGC,
278 w->strip_chart.interval, y,
279 (unsigned int) 1, w->core.height - y);
281 * Fill in the graph lines we just painted over.
284 if (w->strip_chart.points != NULL) {
285 w->strip_chart.points[0].x = w->strip_chart.interval;
286 XDrawPoints(XtDisplay(w), XtWindow(w), w->strip_chart.hiGC,
287 w->strip_chart.points, w->strip_chart.scale - 1,
291 XFlush(XtDisplay(w)); /* Flush output buffers */
293 w->strip_chart.interval++; /* Next point */
296 /* Blts data according to current size, then redraws the stripChart window.
297 * Next represents the number of valid points in data. Returns the (possibly)
298 * adjusted value of next. If next is 0, this routine draws an empty window
299 * (scale - 1 lines for graph). If next is less than the current window width,
300 * the returned value is identical to the initial value of next and data is
301 * unchanged. Otherwise keeps half a window's worth of data. If data is
302 * changed, then w->strip_chart.max_value is updated to reflect the
303 * largest data point.
308 repaint_window(w, left, width)
313 register int next = w->strip_chart.interval;
314 int scale = w->strip_chart.scale;
317 /* Compute the minimum scale required to graph the data, but don't go
318 lower than min_scale. */
319 if (w->strip_chart.interval != 0 || scale <= (int)w->strip_chart.max_value)
320 scale = ((int) (w->strip_chart.max_value)) + 1;
321 if (scale < w->strip_chart.min_scale)
322 scale = w->strip_chart.min_scale;
324 /* if (scale != w->strip_chart.scale) { */
326 if (scale != w->strip_chart.scale && scale == 10) {
327 w->strip_chart.scale = scale;
330 scalewidth = w->core.width;
334 if (XtIsRealized ((Widget) w))
335 XClearWindow (XtDisplay (w), XtWindow (w));
339 if (XtIsRealized((Widget)w)) {
340 Display *dpy = XtDisplay(w);
341 Window win = XtWindow(w);
344 if (!scalewidth) scalewidth = width;
346 if (next < ++width) width = next;
348 /* Draw data point lines. */
349 for (i = left; i < width; i++) {
350 int y = (int) (w->core.height -
351 (int)(w->core.height * w->strip_chart.valuedata[i]) /
352 w->strip_chart.scale);
354 XFillRectangle(dpy, win, w->strip_chart.fgGC,
355 i, y, (unsigned int) 1,
356 (unsigned int) (w->core.height - y));
359 /* Draw graph reference lines */
360 for (i = 1; i < w->strip_chart.scale; i++) {
361 j = i * ((int)w->core.height / w->strip_chart.scale);
362 XDrawLine(dpy, win, w->strip_chart.hiGC, left, j, scalewidth, j);
368 /* Function Name: MoveChart
369 * Description: moves the chart over when it would run off the end.
370 * Arguments: w - the load widget.
371 * blit - blit the bits? (TRUE/FALSE).
376 MoveChart(StripChartWidget w, Boolean blit)
380 register int next = w->strip_chart.interval;
382 if (!XtIsRealized((Widget) w)) return;
384 if (w->strip_chart.jump_val == DEFAULT_JUMP)
385 j = w->core.width >> 1; /* Half the window width. */
387 j = w->core.width - w->strip_chart.jump_val;
391 bcopy((char *)(w->strip_chart.valuedata + next - j),
392 (char *)(w->strip_chart.valuedata), j * sizeof(double));
393 next = w->strip_chart.interval = j;
396 * Since we just lost some data, recompute the
397 * w->strip_chart.max_value.
400 old_max = w->strip_chart.max_value;
401 w->strip_chart.max_value = 0.0;
402 for (i = 0; i < next; i++) {
403 if (w->strip_chart.valuedata[i] > w->strip_chart.max_value)
404 w->strip_chart.max_value = w->strip_chart.valuedata[i];
407 if (!blit) return; /* we are done... */
409 if ( ((int) old_max) != ( (int) w->strip_chart.max_value) ) {
410 XClearWindow(XtDisplay(w), XtWindow(w));
411 repaint_window(w, 0, (int) w->core.width);
415 XCopyArea(XtDisplay((Widget)w), XtWindow((Widget)w), XtWindow((Widget)w),
416 w->strip_chart.hiGC, (int) w->core.width - j, 0,
417 (unsigned int) j, (unsigned int) w->core.height,
420 XClearArea(XtDisplay((Widget)w), XtWindow((Widget)w),
422 (unsigned int) w->core.width - j, (unsigned int)w->core.height,
425 /* Draw graph reference lines */
427 for (i = 1; i < w->strip_chart.scale; i++) {
428 j = i * ((int)w->core.height / w->strip_chart.scale);
429 XDrawLine(XtDisplay((Widget) w), XtWindow( (Widget) w),
430 w->strip_chart.hiGC, left, j, (int)w->core.width, j);
436 static Boolean SetValues (current, request, new)
437 Widget current, request, new;
439 StripChartWidget old = (StripChartWidget)current;
440 StripChartWidget w = (StripChartWidget)new;
441 Boolean ret_val = FALSE;
442 unsigned int new_gc = NO_GCS;
444 if (w->strip_chart.update != old->strip_chart.update) {
445 if (old->strip_chart.update > 0)
446 XtRemoveTimeOut (old->strip_chart.interval_id);
447 if (w->strip_chart.update > 0)
448 w->strip_chart.interval_id =
449 XtAppAddTimeOut(XtWidgetToApplicationContext(new),
450 w->strip_chart.update * MS_PER_SEC,
451 draw_it, (XtPointer)w);
454 if ( w->strip_chart.min_scale > (int) ((w->strip_chart.max_value) + 1) )
457 if ( w->strip_chart.fgpixel != old->strip_chart.fgpixel ) {
458 new_gc |= FOREGROUND;
462 if ( w->strip_chart.hipixel != old->strip_chart.hipixel ) {
467 DestroyGC(old, new_gc);
473 /* Function Name: SetPoints
474 * Description: Sets up the polypoint that will be used to draw in
476 * Arguments: w - the StripChart widget.
480 #define HEIGHT ( (unsigned int) w->core.height)
490 if (w->strip_chart.scale <= 1) { /* no scale lines. */
491 XtFree ((char *) w->strip_chart.points);
492 w->strip_chart.points = NULL;
496 size = sizeof(XPoint) * (w->strip_chart.scale - 1);
498 points = (XPoint *) XtRealloc( (XtPointer) w->strip_chart.points, size);
499 w->strip_chart.points = points;
501 /* Draw graph reference lines into clip mask */
503 for (i = 1; i < w->strip_chart.scale; i++) {
505 points[i - 1].y = HEIGHT / w->strip_chart.scale;