Fix eximon build (tls_sni)
[exim.git] / src / exim_monitor / em_strip.c
CommitLineData
059ec3d9
PH
1/*************************************************
2* Exim Monitor *
3*************************************************/
4
0a49a7a4 5/* Copyright (c) University of Cambridge 1995 - 2009 */
059ec3d9
PH
6/* See the file NOTICE for conditions of use and distribution. */
7
8
9#include "em_hdr.h"
10
11/* This module contains functions for handling stripcharts */
12
13
14/*************************************************
15* Static variables *
16*************************************************/
17
18static int queue_first_time = 1; /* flag for resetting time */
19static int size_first_time = 1; /* and another */
20
21static int stripchart_count = 0; /* count stripcharts created */
22static int *stripchart_delay; /* vector of delay counts */
23static Widget *stripchart_label; /* vector of label widgets */
24static int *stripchart_last_total; /* vector of prevous values */
25static int *stripchart_max; /* vector of maxima */
26static int *stripchart_middelay; /* vector of */
27static int *stripchart_midmax; /* vector of */
28static uschar **stripchart_name; /* vector of name strings */
29static Widget stripchart_prev_chart = NULL; /* previously created chart */
30static Widget stripchart_prev_label = NULL; /* previously created label */
31
32
33
34/*************************************************
35* Initialize *
36*************************************************/
37
38void stripchart_init(void)
39{
40stripchart_delay = (int *)store_malloc(stripchart_number * sizeof(int));
41stripchart_label = (Widget *)store_malloc(stripchart_number * sizeof(Widget));
42stripchart_last_total = (int *)store_malloc(stripchart_number * sizeof(int));
43stripchart_max = (int *)store_malloc(stripchart_number * sizeof(int));
44stripchart_middelay = (int *)store_malloc(stripchart_number * sizeof(int));
45stripchart_midmax = (int *)store_malloc(stripchart_number * sizeof(int));
46stripchart_name = (uschar **)store_malloc(stripchart_number * sizeof(uschar *));
47stripchart_total = (int *)store_malloc(stripchart_number * sizeof(int));
48}
49
50
51
52/*************************************************
53* Stripchart callback function *
54*************************************************/
55
56/* The client data is the index of the stripchart. We have to play
57a little game in order to ensure that the double value is correctly
58passed back via the value pointer without the compiler doing an
59unwanted cast. */
60
61static void stripchartAction(Widget w, XtPointer client_data, XtPointer value)
62{
63double *ptr = (double *)value;
64static int thresholds[] =
65 {10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 0};
66int num = (int)client_data;
67int oldmax = 0;
68int newmax = 0;
69int newvalue = 0;
70int i = 0;
71
72/* For the queue stripchart, the value is the current vector value.
73We reset the initial delay of 1 second to the normal value. */
74
75if (num == 0)
76 {
77 newvalue = stripchart_total[0];
78 if (queue_first_time)
79 {
80 xs_SetValues(w, 1, "update", stripchart_update);
81 queue_first_time = 0;
82 }
83 }
84
85/* For the size monitoring stripchart, the value is the percentage
86fullness of the partition. A similar fudge to the above is implemented
87for the first time. Not all OS have statvfs(); for those that don't this
88code is omitted. In fact it should never be obeyed, as we don't allow
89size_stripchart to get set in that case. For some OS the old function
90and struct name statfs is used; that is handled by a macro. */
91
92else if (size_stripchart != NULL && num == 1)
93 {
94#ifdef HAVE_STATFS
95 struct statvfs statbuf;
96 if (statvfs(CS size_stripchart, &statbuf) == 0)
97 {
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);
102 }
103#endif
104 if (size_first_time)
105 {
106 xs_SetValues(w, 1, "update", stripchart_update);
107 size_first_time = 0;
108 }
109 }
110
111/* For the configured stripcharts, the value to be set is
112the difference from last time; save the current total for
113next time. */
114
115else
116 {
117 newvalue = stripchart_total[num] - stripchart_last_total[num];
118 stripchart_last_total[num] = stripchart_total[num];
119 }
120
121/* Adjust the scale of the stripchart according to the value;
122we delay enlarging the scale for a while after the values
123reduce. Keep the maximum value while delaying, and reset
124down to that. For the size stripchart, the threshold is always
125forced to be at least 100. */
126
127while (thresholds[i] > 0)
128 {
129 int thresh = (size_stripchart != NULL && num == 1)? 100 : thresholds[i++];
130 if (newvalue < (double)thresh)
131 {
132 /* If the current maximum is less than required, or if it is
133 greater and we have delayed long enough, adjust the scale. */
134
135 if (stripchart_max[num] < thresh ||
136 (stripchart_max[num] > thresh && stripchart_delay[num]++ > 20))
137 {
138 uschar buffer[128];
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];
149 }
150
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. */
154
155 else if (stripchart_max[num] > thresh)
156 {
157 if (thresh > stripchart_midmax[num])
158 {
159 stripchart_midmax[num] = thresh;
160 stripchart_middelay[num] = stripchart_delay[num];
161 }
162 }
163
164 /* If the maximum is exactly what we need, reset the delay. */
165
166 if (stripchart_max[num] == thresh) stripchart_delay[num] = 0;
167 break;
168 }
169 }
170
171/* The vanilla Athena stripchart widget does not support change of
172scale - it just draws scale lines closer and closer together, which
173doesn't work when the number gets very large. However, we can cause
174it to change scale quite simply by recomputing all the values and
175then calling its repaint routine. I had to nobble the repaint routine
176too, to stop it changing scale to anything other than 10. There's
177probably a better way to do this, like adding some new resource, but
178I'm not a widget programmer and want to get on with the rest of
179eximon... */
180
181if (oldmax > 0)
182 {
183 int i;
184 StripChartWidget ww = (StripChartWidget)w;
185 ww->strip_chart.max_value = 0;
186 for (i = 0; i < (int)ww->strip_chart.interval; i++)
187 {
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];
192 }
193 XClearWindow( XtDisplay(w), XtWindow(w));
194 ww->strip_chart.interval = repaint_window(ww, 0, (int)w->core.width);
195 }
196
197/* Pass back the new value at the new scale */
198
199*ptr = ((double)newvalue * 10.0)/(double)(stripchart_max[num]);
200}
201
202
203
204/*************************************************
205* Create one stripchart *
206*************************************************/
207
208/* This function creates two widgets, one being the title and the other being
209the stripchart. The client_data values for each stripchart are index into the
210stripchart_values vector; each new stripchart just gets the next number. There
211is a fudge for the very first stripchart, which is the queue length display,
212and for the second if it is a partition size display; its update time is
213initially set to 1 second so that it gives an immediate display of the queue.
214The first time its callback function is obeyed, the update time gets reset. */
215
216void create_stripchart(Widget parent, uschar *title)
217{
218Widget chart;
219
220Widget label = XtCreateManagedWidget("label",
221 labelWidgetClass, parent, NULL, 0);
222
223xs_SetValues(label, 10,
224 "label", title,
225 "width", stripchart_width + 2,
226 "borderWidth", 0,
227 "internalHeight", 0,
228 "internalWidth", 0,
229 "left", XawChainLeft,
230 "right", XawChainLeft,
231 "top", XawChainTop,
232 "bottom", XawChainTop,
233 XtNfromHoriz, stripchart_prev_label);
234
235chart = XtCreateManagedWidget("stripchart",
236 mystripChartWidgetClass, parent, NULL, 0);
237
238xs_SetValues(chart, 11,
239 "jumpScroll", 1,
240 "update", (stripchart_count < stripchart_varstart)? 1:stripchart_update,
241 "minScale", 10,
242 "width", stripchart_width,
243 "height", stripchart_height,
244 "left", XawChainLeft,
245 "right", XawChainLeft,
246 "top", XawChainTop,
247 "bottom", XawChainTop,
248 XtNfromHoriz, stripchart_prev_chart,
249 XtNfromVert, label);
250
251XtAddCallback(chart, "getValue", stripchartAction,
252 (XtPointer)stripchart_count);
253
254stripchart_last_total[stripchart_count] = 0;
255stripchart_max[stripchart_count] = 10;
256stripchart_midmax[stripchart_count] = 0;
257stripchart_name[stripchart_count] = title;
258stripchart_prev_label = stripchart_label[stripchart_count] = label;
259stripchart_prev_chart = chart;
260stripchart_total[stripchart_count] = 0;
261stripchart_count++;
262}
263
264/* End of em_strip.c */