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 prevous 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
61 static void stripchartAction(Widget w
, XtPointer client_data
, XtPointer value
)
63 double *ptr
= (double *)value
;
64 static int thresholds
[] =
65 {10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 0};
66 int num
= (int)client_data
;
72 /* For the queue stripchart, the value is the current vector value.
73 We reset the initial delay of 1 second to the normal value. */
77 newvalue
= stripchart_total
[0];
80 xs_SetValues(w
, 1, "update", stripchart_update
);
85 /* For the size monitoring stripchart, the value is the percentage
86 fullness of the partition. A similar fudge to the above is implemented
87 for the first time. Not all OS have statvfs(); for those that don't this
88 code is omitted. In fact it should never be obeyed, as we don't allow
89 size_stripchart to get set in that case. For some OS the old function
90 and struct name statfs is used; that is handled by a macro. */
92 else if (size_stripchart
!= NULL
&& num
== 1)
95 struct statvfs statbuf
;
96 if (statvfs(CS size_stripchart
, &statbuf
) == 0)
98 int used
= statbuf
.f_blocks
- statbuf
.f_bfree
;
99 int max
= used
+ statbuf
.f_bavail
;
100 double fraction
= ((double)used
) / ((double)max
);
101 newvalue
= (int)((fraction
+ 0.005) * 100.0);
106 xs_SetValues(w
, 1, "update", stripchart_update
);
111 /* For the configured stripcharts, the value to be set is
112 the difference from last time; save the current total for
117 newvalue
= stripchart_total
[num
] - stripchart_last_total
[num
];
118 stripchart_last_total
[num
] = stripchart_total
[num
];
121 /* Adjust the scale of the stripchart according to the value;
122 we delay enlarging the scale for a while after the values
123 reduce. Keep the maximum value while delaying, and reset
124 down to that. For the size stripchart, the threshold is always
125 forced to be at least 100. */
127 while (thresholds
[i
] > 0)
129 int thresh
= (size_stripchart
!= NULL
&& num
== 1)? 100 : thresholds
[i
++];
130 if (newvalue
< (double)thresh
)
132 /* If the current maximum is less than required, or if it is
133 greater and we have delayed long enough, adjust the scale. */
135 if (stripchart_max
[num
] < thresh
||
136 (stripchart_max
[num
] > thresh
&& stripchart_delay
[num
]++ > 20))
139 newmax
= (thresh
> stripchart_midmax
[num
])?
140 thresh
: stripchart_midmax
[num
];
141 if (newmax
== 10) sprintf(CS buffer
, "%s", stripchart_name
[num
]);
142 else sprintf(CS buffer
, "%s x%d", stripchart_name
[num
], newmax
/10);
143 if (size_stripchart
!= NULL
&& num
== 1) Ustrcat(buffer
, "%");
144 xs_SetValues(stripchart_label
[num
], 1, "label", buffer
);
145 oldmax
= stripchart_max
[num
];
146 stripchart_max
[num
] = newmax
;
147 stripchart_midmax
[num
] = 0;
148 stripchart_delay
[num
] -= stripchart_middelay
[num
];
151 /* Otherwise, if the current maximum is greater than required,
152 keep the highest value encountered during the delay, and its
153 position so we can adjust the delay when re-scaling. */
155 else if (stripchart_max
[num
] > thresh
)
157 if (thresh
> stripchart_midmax
[num
])
159 stripchart_midmax
[num
] = thresh
;
160 stripchart_middelay
[num
] = stripchart_delay
[num
];
164 /* If the maximum is exactly what we need, reset the delay. */
166 if (stripchart_max
[num
] == thresh
) stripchart_delay
[num
] = 0;
171 /* The vanilla Athena stripchart widget does not support change of
172 scale - it just draws scale lines closer and closer together, which
173 doesn't work when the number gets very large. However, we can cause
174 it to change scale quite simply by recomputing all the values and
175 then calling its repaint routine. I had to nobble the repaint routine
176 too, to stop it changing scale to anything other than 10. There's
177 probably a better way to do this, like adding some new resource, but
178 I'm not a widget programmer and want to get on with the rest of
184 StripChartWidget ww
= (StripChartWidget
)w
;
185 ww
->strip_chart
.max_value
= 0;
186 for (i
= 0; i
< (int)ww
->strip_chart
.interval
; i
++)
188 ww
->strip_chart
.valuedata
[i
] =
189 (ww
->strip_chart
.valuedata
[i
] * oldmax
)/newmax
;
190 if (ww
->strip_chart
.valuedata
[i
] > ww
->strip_chart
.max_value
)
191 ww
->strip_chart
.max_value
= ww
->strip_chart
.valuedata
[i
];
193 XClearWindow( XtDisplay(w
), XtWindow(w
));
194 ww
->strip_chart
.interval
= repaint_window(ww
, 0, (int)w
->core
.width
);
197 /* Pass back the new value at the new scale */
199 *ptr
= ((double)newvalue
* 10.0)/(double)(stripchart_max
[num
]);
204 /*************************************************
205 * Create one stripchart *
206 *************************************************/
208 /* This function creates two widgets, one being the title and the other being
209 the stripchart. The client_data values for each stripchart are index into the
210 stripchart_values vector; each new stripchart just gets the next number. There
211 is a fudge for the very first stripchart, which is the queue length display,
212 and for the second if it is a partition size display; its update time is
213 initially set to 1 second so that it gives an immediate display of the queue.
214 The first time its callback function is obeyed, the update time gets reset. */
216 void create_stripchart(Widget parent
, uschar
*title
)
220 Widget label
= XtCreateManagedWidget("label",
221 labelWidgetClass
, parent
, NULL
, 0);
223 xs_SetValues(label
, 10,
225 "width", stripchart_width
+ 2,
229 "left", XawChainLeft
,
230 "right", XawChainLeft
,
232 "bottom", XawChainTop
,
233 XtNfromHoriz
, stripchart_prev_label
);
235 chart
= XtCreateManagedWidget("stripchart",
236 mystripChartWidgetClass
, parent
, NULL
, 0);
238 xs_SetValues(chart
, 11,
240 "update", (stripchart_count
< stripchart_varstart
)? 1:stripchart_update
,
242 "width", stripchart_width
,
243 "height", stripchart_height
,
244 "left", XawChainLeft
,
245 "right", XawChainLeft
,
247 "bottom", XawChainTop
,
248 XtNfromHoriz
, stripchart_prev_chart
,
251 XtAddCallback(chart
, "getValue", stripchartAction
,
252 (XtPointer
)stripchart_count
);
254 stripchart_last_total
[stripchart_count
] = 0;
255 stripchart_max
[stripchart_count
] = 10;
256 stripchart_midmax
[stripchart_count
] = 0;
257 stripchart_name
[stripchart_count
] = title
;
258 stripchart_prev_label
= stripchart_label
[stripchart_count
] = label
;
259 stripchart_prev_chart
= chart
;
260 stripchart_total
[stripchart_count
] = 0;
264 /* End of em_strip.c */