1 /*************************************************
3 *************************************************/
5 /* Copyright (c) University of Cambridge 1995 - 2009 */
6 /* See the file NOTICE for conditions of use and distribution. */
11 /* This module contains functions for handling stripcharts */
14 /*************************************************
16 *************************************************/
18 static int queue_first_time = 1; /* flag for resetting time */
19 static int size_first_time = 1; /* and another */
21 static int stripchart_count = 0; /* count stripcharts created */
22 static int *stripchart_delay; /* vector of delay counts */
23 static Widget *stripchart_label; /* vector of label widgets */
24 static int *stripchart_last_total; /* vector of previous values */
25 static int *stripchart_max; /* vector of maxima */
26 static int *stripchart_middelay; /* vector of */
27 static int *stripchart_midmax; /* vector of */
28 static uschar **stripchart_name; /* vector of name strings */
29 static Widget stripchart_prev_chart = NULL; /* previously created chart */
30 static Widget stripchart_prev_label = NULL; /* previously created label */
34 /*************************************************
36 *************************************************/
38 void stripchart_init(void)
40 stripchart_delay = (int *)store_malloc(stripchart_number * sizeof(int));
41 stripchart_label = (Widget *)store_malloc(stripchart_number * sizeof(Widget));
42 stripchart_last_total = (int *)store_malloc(stripchart_number * sizeof(int));
43 stripchart_max = (int *)store_malloc(stripchart_number * sizeof(int));
44 stripchart_middelay = (int *)store_malloc(stripchart_number * sizeof(int));
45 stripchart_midmax = (int *)store_malloc(stripchart_number * sizeof(int));
46 stripchart_name = (uschar **)store_malloc(stripchart_number * sizeof(uschar *));
47 stripchart_total = (int *)store_malloc(stripchart_number * sizeof(int));
52 /*************************************************
53 * Stripchart callback function *
54 *************************************************/
56 /* The client data is the index of the stripchart. We have to play
57 a little game in order to ensure that the double value is correctly
58 passed back via the value pointer without the compiler doing an
62 stripchartAction(Widget w, XtPointer client_data, XtPointer value)
64 double * ptr = (double *)value;
65 static int thresholds[] =
66 {10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 0};
67 int num = (long)client_data;
73 /* For the queue stripchart, the value is the current vector value.
74 We reset the initial delay of 1 second to the normal value. */
78 newvalue = stripchart_total[0];
81 xs_SetValues(w, 1, "update", stripchart_update);
86 /* For the size monitoring stripchart, the value is the percentage
87 fullness of the partition. A similar fudge to the above is implemented
88 for the first time. Not all OS have statvfs(); for those that don't this
89 code is omitted. In fact it should never be obeyed, as we don't allow
90 size_stripchart to get set in that case. For some OS the old function
91 and struct name statfs is used; that is handled by a macro. */
93 else if (size_stripchart != NULL && num == 1)
96 struct statvfs statbuf;
97 if (statvfs(CS size_stripchart, &statbuf) == 0)
99 int used = statbuf.f_blocks - statbuf.f_bfree;
100 int max = used + statbuf.f_bavail;
101 double fraction = ((double)used) / ((double)max);
102 newvalue = (int)((fraction + 0.005) * 100.0);
107 xs_SetValues(w, 1, "update", stripchart_update);
112 /* For the configured stripcharts, the value to be set is
113 the difference from last time; save the current total for
118 newvalue = stripchart_total[num] - stripchart_last_total[num];
119 stripchart_last_total[num] = stripchart_total[num];
122 /* Adjust the scale of the stripchart according to the value;
123 we delay enlarging the scale for a while after the values
124 reduce. Keep the maximum value while delaying, and reset
125 down to that. For the size stripchart, the threshold is always
126 forced to be at least 100. */
128 while (thresholds[i] > 0)
130 int thresh = (size_stripchart != NULL && num == 1)? 100 : thresholds[i++];
131 if (newvalue < (double)thresh)
133 /* If the current maximum is less than required, or if it is
134 greater and we have delayed long enough, adjust the scale. */
136 if (stripchart_max[num] < thresh ||
137 (stripchart_max[num] > thresh && stripchart_delay[num]++ > 20))
140 newmax = (thresh > stripchart_midmax[num])?
141 thresh : stripchart_midmax[num];
142 if (newmax == 10) sprintf(CS buffer, "%s", stripchart_name[num]);
143 else sprintf(CS buffer, "%s x%d", stripchart_name[num], newmax/10);
144 if (size_stripchart != NULL && num == 1) Ustrcat(buffer, US"%");
145 xs_SetValues(stripchart_label[num], 1, "label", buffer);
146 oldmax = stripchart_max[num];
147 stripchart_max[num] = newmax;
148 stripchart_midmax[num] = 0;
149 stripchart_delay[num] -= stripchart_middelay[num];
152 /* Otherwise, if the current maximum is greater than required,
153 keep the highest value encountered during the delay, and its
154 position so we can adjust the delay when re-scaling. */
156 else if (stripchart_max[num] > thresh)
158 if (thresh > stripchart_midmax[num])
160 stripchart_midmax[num] = thresh;
161 stripchart_middelay[num] = stripchart_delay[num];
165 /* If the maximum is exactly what we need, reset the delay. */
167 if (stripchart_max[num] == thresh) stripchart_delay[num] = 0;
172 /* The vanilla Athena stripchart widget does not support change of
173 scale - it just draws scale lines closer and closer together, which
174 doesn't work when the number gets very large. However, we can cause
175 it to change scale quite simply by recomputing all the values and
176 then calling its repaint routine. I had to nobble the repaint routine
177 too, to stop it changing scale to anything other than 10. There's
178 probably a better way to do this, like adding some new resource, but
179 I'm not a widget programmer and want to get on with the rest of
185 StripChartWidget ww = (StripChartWidget)w;
186 ww->strip_chart.max_value = 0;
187 for (i = 0; i < (int)ww->strip_chart.interval; i++)
189 ww->strip_chart.valuedata[i] =
190 (ww->strip_chart.valuedata[i] * oldmax)/newmax;
191 if (ww->strip_chart.valuedata[i] > ww->strip_chart.max_value)
192 ww->strip_chart.max_value = ww->strip_chart.valuedata[i];
194 XClearWindow( XtDisplay(w), XtWindow(w));
195 ww->strip_chart.interval = repaint_window(ww, 0, (int)w->core.width);
198 /* Pass back the new value at the new scale */
200 *ptr = ((double)newvalue * 10.0)/(double)(stripchart_max[num]);
205 /*************************************************
206 * Create one stripchart *
207 *************************************************/
209 /* This function creates two widgets, one being the title and the other being
210 the stripchart. The client_data values for each stripchart are index into the
211 stripchart_values vector; each new stripchart just gets the next number. There
212 is a fudge for the very first stripchart, which is the queue length display,
213 and for the second if it is a partition size display; its update time is
214 initially set to 1 second so that it gives an immediate display of the queue.
215 The first time its callback function is obeyed, the update time gets reset. */
218 create_stripchart(Widget parent, uschar *title)
222 Widget label = XtCreateManagedWidget("label",
223 labelWidgetClass, parent, NULL, 0);
225 xs_SetValues(label, 10,
227 "width", stripchart_width + 2,
231 "left", XawChainLeft,
232 "right", XawChainLeft,
234 "bottom", XawChainTop,
235 XtNfromHoriz, stripchart_prev_label);
237 chart = XtCreateManagedWidget("stripchart",
238 mystripChartWidgetClass, parent, NULL, 0);
240 xs_SetValues(chart, 11,
242 "update", (stripchart_count < stripchart_varstart)? 1:stripchart_update,
244 "width", stripchart_width,
245 "height", stripchart_height,
246 "left", XawChainLeft,
247 "right", XawChainLeft,
249 "bottom", XawChainTop,
250 XtNfromHoriz, stripchart_prev_chart,
253 XtAddCallback(chart, "getValue", stripchartAction,
254 (XtPointer)(long)stripchart_count);
256 stripchart_last_total[stripchart_count] = 0;
257 stripchart_max[stripchart_count] = 10;
258 stripchart_midmax[stripchart_count] = 0;
259 stripchart_name[stripchart_count] = title;
260 stripchart_prev_label = stripchart_label[stripchart_count] = label;
261 stripchart_prev_chart = chart;
262 stripchart_total[stripchart_count] = 0;
266 /* End of em_strip.c */