1 /* GKrellM
2 |  Copyright (C) 1999-2019 Bill Wilson
3 |
4 |  Author:  Bill Wilson    billw@gkrellm.net
5 |  Latest versions might be found at:  http://gkrellm.net
6 |
7 |
8 |  GKrellM is free software: you can redistribute it and/or modify it
9 |  under the terms of the GNU General Public License as published by
10 |  the Free Software Foundation, either version 3 of the License, or
11 |  (at your option) any later version.
12 |
13 |  GKrellM is distributed in the hope that it will be useful, but WITHOUT
14 |  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 |  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 |  License for more details.
17 |
18 |  You should have received a copy of the GNU General Public License
19 |  along with this program. If not, see http://www.gnu.org/licenses/
20 |
21 |
22 |  Additional permission under GNU GPL version 3 section 7
23 |
24 |  If you modify this program, or any covered work, by linking or
25 |  combining it with the OpenSSL project's OpenSSL library (or a
26 |  modified version of that library), containing parts covered by
27 |  the terms of the OpenSSL or SSLeay licenses, you are granted
28 |  additional permission to convey the resulting work.
29 |  Corresponding Source for a non-source form of such a combination
30 |  shall include the source code for the parts of OpenSSL used as well
31 |  as that of the covered work.
32 */
33 
34 #include "gkrellm.h"
35 #include "gkrellm-private.h"
36 #include "gkrellm-sysdeps.h"
37 
38 /* Useful info:
39 |  http://mbm.livewiredev.com/
40 |		Look up boards here for sensor chip and temperature sensor type
41 |		so sensor[1,2,3] can be set correctly in sensors.conf.
42 */
43 
44   /* On Linux, the sensor id_name includes the parent chip directory, so
45   |  "lm78/temp" will be a id_name, and not just "temp".  This is to
46   |  allow unique identification in case of multiple "temp" files.
47   |  ie, more than 1 chip directory, each with a "temp" file.
48   */
49 
50 typedef struct _sensor
51 	{
52 	gchar		*name;			/* cpuX, mb, Vx name mapped to this sensor */
53 	gchar		*name_locale;	/* gdk_draw compat */
54 	gchar		*default_label;	/* Only voltages have default labels */
55 	gchar		*path;			/* Pathname to sensor data or device file */
56 	gchar		*id_name;		/* Unique sensor identifier for config */
57 	gint		type;
58 
59 	gint		id;
60 	gint		iodev;
61 	gint		inter;
62 
63 	gint		enabled;
64 	gint		group;
65 	gint		location;		/* default, Proc panel, or cpu panel */
66 	gfloat		factor,			/* Scale sensor reading		*/
67 				offset;			/* Add to sensor reading	*/
68 	gfloat		default_factor,
69 				default_offset;
70 	gchar		*vref_name;
71 	struct _sensor
72 				*vref;			/* A neg volt may be function of a ref volt */
73 
74 	gboolean	has_config;
75 
76 	gfloat		value,
77 				raw_value;
78 	gboolean	value_valid;
79 
80 	GkrellmAlert *alert;
81 	void		(*cb_alert)();
82 	gpointer	cb_alert_data;
83 	gpointer	smon;
84 	}
85 	Sensor;
86 
87 
88 static GList	*sensor_list	= NULL;
89 
90 static GList	*temp_order_list,	/* For ordering from the config. */
91 				*fan_order_list,
92 				*volt_order_list;
93 
94 static gboolean	using_new_config,
95 				need_disk_temperature_update;
96 
97 static gboolean	(*get_temperature)(gchar *name, gint id,
98 			gint iodev, gint inter, gfloat *t);
99 static gboolean	(*get_fan)(gchar *name, gint id,
100 			gint iodev, gint inter, gfloat *f);
101 static gboolean	(*get_voltage)(gchar *name, gint id,
102 			gint iodev, gint inter, gfloat *v);
103 
104 static void read_sensors_config(void);
105 static gboolean	(*config_migrate)(gchar *current_name, gchar *config_name,
106 					gint current, gint config);
107 
108 static gint		sensor_config_version;
109 static gint		sensor_current_sysdep_private;
110 static gint		sensor_config_sysdep_private;
111 
112 void
gkrellm_sensors_client_divert(gboolean (* get_temp_func)(),gboolean (* get_fan_func)(),gboolean (* get_volt_func)())113 gkrellm_sensors_client_divert(gboolean (*get_temp_func)(),
114 			gboolean (*get_fan_func)(), gboolean (*get_volt_func)())
115 	{
116 	get_temperature = get_temp_func;
117 	get_fan = get_fan_func;
118 	get_voltage = get_volt_func;
119 	}
120 
121 void
gkrellm_sensors_config_migrate_connect(gboolean (* migrate_func)(),gint sysdep_private)122 gkrellm_sensors_config_migrate_connect(gboolean (*migrate_func)(),
123 			gint sysdep_private)
124 	{
125 	config_migrate = migrate_func;
126 	sensor_current_sysdep_private = sysdep_private;
127 	}
128 
129 static gboolean
setup_sensor_interface(void)130 setup_sensor_interface(void)
131 	{
132 	if (!get_temperature && !_GK.client_mode && gkrellm_sys_sensors_init())
133 		{
134 		get_temperature = gkrellm_sys_sensors_get_temperature;
135 		get_fan = gkrellm_sys_sensors_get_fan;
136 		get_voltage = gkrellm_sys_sensors_get_voltage;
137 		}
138 	return get_temperature ? TRUE : FALSE;
139 	}
140 
141 void
gkrellm_sensors_set_group(gpointer sr,gint group)142 gkrellm_sensors_set_group(gpointer sr, gint group)
143 	{
144 	Sensor	*sensor = (Sensor *) sr;
145 
146 	if (sensor)
147 		sensor->group = group;
148 	}
149 
150 gpointer
gkrellm_sensors_add_sensor(gint type,gchar * sensor_path,gchar * id_name,gint id,gint iodev,gint inter,gfloat factor,gfloat offset,gchar * vref,gchar * default_label)151 gkrellm_sensors_add_sensor(gint type, gchar *sensor_path, gchar *id_name,
152 		gint id, gint iodev, gint inter,
153 		gfloat factor, gfloat offset, gchar *vref, gchar *default_label)
154 	{
155 	Sensor	*sensor;
156 	gchar	*r;
157 
158 	if (!id_name || !*id_name || type < 0 || type > 2)
159 		return NULL;
160 
161 	sensor = g_new0(Sensor, 1);
162 	sensor->id_name = g_strdup(id_name);
163 
164 	if (sensor_path)
165 		sensor->path = g_strdup(sensor_path);
166 	else
167 		sensor->path = g_strdup(id_name);
168 	if (!default_label)
169 		{
170 		r = strrchr(id_name, '/');
171 		default_label = r ? r+1 : id_name;
172 		}
173 	gkrellm_locale_dup_string(&sensor->name, default_label,
174 				&sensor->name_locale);
175 	sensor->default_label = g_strdup(default_label);
176 
177 	sensor->default_factor = factor;
178 	sensor->factor
179 			= (sensor->default_factor != 0.0 ? sensor->default_factor : 1.0);
180 	sensor->default_offset = sensor->offset = offset;
181 	sensor->type = type;
182 	sensor->id = id;
183 	sensor->iodev = iodev;
184 	sensor->inter = inter;
185 	if (type == SENSOR_VOLTAGE && vref)
186 		sensor->vref_name = g_strdup(vref);
187 	sensor_list = g_list_append(sensor_list, sensor);
188 	return (gpointer) sensor;
189 	}
190 
191 /* ======================================================================== */
192 static gboolean	use_threads,
193 				thread_data_valid,
194 				units_fahrenheit,
195 				show_units = TRUE;
196 
197 static gboolean thread_busy;
198 
199 static gpointer
read_sensors_thread(void * data)200 read_sensors_thread(void *data)
201 	{
202 	GList	*list;
203 	Sensor	*sensor;
204 
205 	for (list = sensor_list; list; list = list->next)
206 		{
207 		sensor = (Sensor *) list->data;
208 		if (!sensor->enabled)
209 			continue;
210 		if (sensor->type == SENSOR_TEMPERATURE && get_temperature)
211 			(*get_temperature)(sensor->path, sensor->id,
212 				sensor->iodev, sensor->inter, &sensor->raw_value);
213 		if (sensor->type == SENSOR_FAN && get_fan)
214 			(*get_fan)(sensor->path, sensor->id,
215 				sensor->iodev, sensor->inter, &sensor->raw_value);
216 		if (sensor->type == SENSOR_VOLTAGE && get_voltage)
217 			(*get_voltage)(sensor->path, sensor->id,
218 				sensor->iodev, sensor->inter, &sensor->raw_value);
219 		}
220 	thread_busy = FALSE;
221 	return NULL;
222 	}
223 
224 static void
run_sensors_thread(void)225 run_sensors_thread(void)
226 	{
227 	GThread		*gth;
228 
229 	if (thread_busy)
230 		return;
231 	thread_busy = TRUE;
232 	gth = g_thread_new("read_sensors", read_sensors_thread, NULL);
233 	g_thread_unref(gth);
234 	}
235 
236   /* Sort so that sensors are ordered: temp, fan, voltage.
237   */
238 static gint
strcmp_sensor_path(Sensor * s1,Sensor * s2)239 strcmp_sensor_path(Sensor *s1, Sensor *s2)
240 	{
241 	if (s1->type == SENSOR_TEMPERATURE && s2->type != SENSOR_TEMPERATURE)
242 		return -1;
243 	if (s1->type != SENSOR_TEMPERATURE && s2->type == SENSOR_TEMPERATURE)
244 		return 1;
245 
246 	if (s1->type == SENSOR_FAN && s2->type != SENSOR_FAN)
247 		return -1;
248 	if (s1->type != SENSOR_FAN && s2->type == SENSOR_FAN)
249 		return 1;
250 
251 	return strcmp(s1->id_name, s2->id_name);
252 	}
253 
254 static void
append_sensor_to_order_list(Sensor * sr)255 append_sensor_to_order_list(Sensor *sr)
256 	{
257 	if (sr->type == SENSOR_TEMPERATURE)
258 		temp_order_list = g_list_append(temp_order_list, sr);
259 	else if (sr->type == SENSOR_FAN)
260 		fan_order_list = g_list_append(fan_order_list, sr);
261 	else if (sr->type == SENSOR_VOLTAGE)
262 		volt_order_list = g_list_append(volt_order_list, sr);
263 	}
264 
265 
266   /* This is called as sensors are read from the config and I will want to
267   |  re-order the sensors_list to reflect the config order. Re-ordering is
268   |  done by appending found sensors to type specific lists and later the
269   |  sensors_list will be rebuilt from the ordered type lists.  If the
270   |  id_name is found in the sensor_list, assign the label to it.
271   */
272 static Sensor *
map_sensor_label(gchar * label,gchar * name)273 map_sensor_label(gchar *label, gchar *name)
274 	{
275 	GList		*list;
276 	Sensor		*sr;
277 
278 	for (list = sensor_list; list; list = list->next)
279 		{
280 		sr = (Sensor *) list->data;
281 		if (   !sr->has_config
282 		    && (   !strcmp(sr->id_name, name)
283 		        || (   config_migrate
284 		            && (*config_migrate)(sr->id_name, name,
285 							sensor_current_sysdep_private,
286 							sensor_config_sysdep_private)
287 		           )
288 		       )
289 		   )
290 			{
291 			gkrellm_locale_dup_string(&sr->name, label, &sr->name_locale);
292 			append_sensor_to_order_list(sr);
293 			sr->has_config = TRUE;
294 			return sr;
295 			}
296 		}
297 	return NULL;
298 	}
299 
300 gboolean
gkrellm_sensors_available(void)301 gkrellm_sensors_available(void)
302 	{
303 	return (sensor_list || _GK.demo) ? TRUE : FALSE;
304 	}
305 
306   /* The cpu and proc monitors both need a couple of sensor decals
307   |  created on their panels.  The left one will only display fan speeds
308   |  while the right one will display both fan and temps depending on modes.
309   */
310 void
gkrellm_sensors_create_decals(GkrellmPanel * p,gint style_id,GkrellmDecal ** dsensor,GkrellmDecal ** dfan)311 gkrellm_sensors_create_decals(GkrellmPanel *p, gint style_id,
312 			GkrellmDecal **dsensor, GkrellmDecal **dfan)
313 	{
314 	GkrellmStyle		*style;
315 	GkrellmMargin		*m;
316 	GkrellmTextstyle	*ts;
317 	GkrellmDecal		*ds	= NULL,
318 						*df	= NULL;
319 	gint				w, w_avail;
320 
321 	if (sensor_list || _GK.demo)
322 		{
323 		style = gkrellm_panel_style(style_id);
324 		m = gkrellm_get_style_margins(style);
325 		ts = gkrellm_panel_alt_textstyle(style_id);
326 		w_avail = gkrellm_chart_width() - m->left - m->right;
327 
328 		df = gkrellm_create_decal_text(p, "8888", ts, style, -1, -1, 0);
329 
330 		/* Sensor decal (fan and/or temp) carves out space remaining to right.
331 		|  Try to get enough for .1 deg resolution, otherwise what is left.
332 		*/
333 		w = gkrellm_gdk_string_width(ts->font, "188.8F") + ts->effect;
334 		if (w > w_avail - df->w - 3)
335 			w = gkrellm_gdk_string_width(ts->font, "88.8C") + ts->effect;
336 
337 		ds = gkrellm_create_decal_text(p, "8.C", ts, style, -1, -1, w);
338 		ds->x = w_avail + m->left - w;
339 		df->x = m->left;
340 		}
341 	*dsensor = ds;
342 	*dfan = df;
343 	}
344 
345 void
gkrellm_sensor_draw_fan_decal(GkrellmPanel * p,GkrellmDecal * d,gfloat f)346 gkrellm_sensor_draw_fan_decal(GkrellmPanel *p, GkrellmDecal *d, gfloat f)
347 	{
348 	gchar	buf[8];
349 	gint	w;
350 
351 	if (!p || !d)
352 		return;
353 	snprintf(buf, sizeof(buf), "%.0f", f);
354 	w = gkrellm_gdk_string_width(d->text_style.font, buf)
355 				+ d->text_style.effect;
356 	d->x_off = d->w - w;
357 	if (d->x_off < 0)
358 		d->x_off = 0;
359 	gkrellm_draw_decal_text(p, d, buf, 0);
360 	}
361 
362 void
gkrellm_sensor_draw_temperature_decal(GkrellmPanel * p,GkrellmDecal * d,gfloat t,gchar units)363 gkrellm_sensor_draw_temperature_decal(GkrellmPanel *p, GkrellmDecal *d,
364 				gfloat t, gchar units)
365 	{
366 	gchar	*s, buf[8];
367 	gint	w;
368 
369 	if (!p || !d)
370 		return;
371 	snprintf(buf, sizeof(buf), "%.1f%c", t, units);
372 	if ((s = strchr(buf, '.')) == NULL)
373 		s = strchr(buf, ',');			/* Locale may use commas */
374 	w = gkrellm_gdk_string_width(d->text_style.font, buf)
375 				+ d->text_style.effect;
376 	if (w > d->w + 1)
377 		{
378 		snprintf(buf, sizeof(buf), "%.0f%c", t, units);
379 		w = gkrellm_gdk_string_width(d->text_style.font, buf)
380 				+ d->text_style.effect;
381 		}
382 
383 	d->x_off = d->w - w;
384 	if (d->x_off < 0)
385 		d->x_off = 0;
386 	gkrellm_draw_decal_text(p, d, buf, 0 /* no longer used */);
387 	}
388 
389 static Sensor *
lookup_sensor_from_id_name(gchar * name)390 lookup_sensor_from_id_name(gchar *name)
391 	{
392 	GList	*list;
393 	Sensor	*s;
394 
395 	if (!name)
396 		return NULL;
397 	for (list = sensor_list; list; list = list->next)
398 		{
399 		s = (Sensor *) list->data;
400 		if (   !strcmp(s->id_name, name)
401 		    || (   config_migrate
402 		        && (*config_migrate)(s->id_name, name,
403 							sensor_current_sysdep_private,
404 							sensor_config_sysdep_private)
405 		       )
406 		   )
407 			return s;
408 		}
409 	return NULL;
410 	}
411 
412   /* Given a in0, in1, ... name as a reference to use for a sensor,
413   |  find the sensor with that name for the same chip as sr.
414   */
415 static Sensor *
lookup_vref(Sensor * sr,gchar * name)416 lookup_vref(Sensor *sr, gchar *name)
417 	{
418 	GList	*list;
419 	Sensor	*sv;
420 	gchar	*s, buf[128];
421 
422 	snprintf(buf, 96, "%s", sr->id_name);
423 	s = strrchr(buf, '/');
424 	if (s)
425 		++s;
426 	else
427 		s = buf;
428 	snprintf(s, 31, "%s", name);
429 	for (list = sensor_list; list; list = list->next)
430 		{
431 		sv = (Sensor *) list->data;
432 		if (   sv->type == SENSOR_VOLTAGE
433 			&& !strcmp(sv->id_name, buf)
434 		   )
435 			return sv;
436 		}
437 	return NULL;
438 	}
439 
440 static void
cb_command_process(GkrellmAlert * alert,gchar * src,gchar * buf,gint size,Sensor * sensor)441 cb_command_process(GkrellmAlert *alert, gchar *src, gchar *buf, gint size,
442 			Sensor *sensor)
443 	{
444 	gchar		c, *s, *fmt;
445 	gint		len;
446 
447 	if (!buf || size < 1)
448 		return;
449 	--size;
450 	*buf = '\0';
451 	if (!src)
452 		return;
453 	for (s = src; *s != '\0' && size > 0; ++s)
454 		{
455 		len = 1;
456 		if (*s == '$' && *(s + 1) != '\0')
457 			{
458 			if ((c = *(s + 1)) == 'H')
459 				len = snprintf(buf, size, "%s", gkrellm_sys_get_host_name());
460 			else if (c == 's')
461 				{
462 				if (sensor->type == SENSOR_FAN)
463 					fmt = "%.0f";
464 				else if (sensor->type == SENSOR_TEMPERATURE)
465 					fmt = "%.1f";
466 				else				/* SENSOR_VOLTAGE */
467 					fmt = "%.2f";
468 				len = snprintf(buf, size, fmt, sensor->value);
469 				}
470 			else if (c == 'l' || c == 'L')
471 				len = snprintf(buf, size, "%s", sensor->name_locale);
472 			++s;
473 			}
474 		else
475 			*buf = *s;
476 		size -= len;
477 		buf += len;
478 		}
479 	*buf = '\0';
480 	}
481 
482 GkrellmAlert *
gkrellm_sensor_alert(gpointer sr)483 gkrellm_sensor_alert(gpointer sr)
484 	{
485 	if (!sr)
486 		return NULL;
487 	return ((Sensor *) sr)->alert;
488 	}
489 
490 void
gkrellm_sensor_alert_connect(gpointer sr,void (* cb_func)(),gpointer data)491 gkrellm_sensor_alert_connect(gpointer sr, void (*cb_func)(), gpointer data)
492 	{
493 	Sensor	*sensor = (Sensor *) sr;
494 
495 	if (!sensor)
496 		return;
497 	sensor->cb_alert = cb_func;
498 	sensor->cb_alert_data = data;
499 	gkrellm_alert_trigger_connect(sensor->alert, cb_func, data);
500 	gkrellm_alert_command_process_connect(sensor->alert,
501 				cb_command_process, sensor);
502 	gkrellm_reset_alert_soft(sensor->alert);
503 	}
504 
505 static gboolean
sensor_read_temperature(Sensor * sensor,gfloat * temp,gchar * units)506 sensor_read_temperature(Sensor *sensor, gfloat *temp, gchar *units)
507 	{
508 	gfloat	t = 0;
509 	gint	found_temp = FALSE;
510 
511 	if (sensor && get_temperature)
512 		{
513 		found_temp = thread_data_valid ? TRUE
514 			: (*get_temperature)(sensor->path, sensor->id,
515 					sensor->iodev, sensor->inter, &sensor->raw_value);
516 		sensor->value = sensor->raw_value * sensor->factor + sensor->offset;
517 		if (units_fahrenheit)
518 			sensor->value = 1.8 * sensor->value + 32.0;
519 		t = sensor->value;
520 		}
521 	if (! found_temp && _GK.demo)
522 		{
523 		t = 90.0 + (gfloat)(rand() & 0xf);
524 		found_temp = TRUE;
525 		}
526 	if (temp)
527 		*temp = t;
528 	if (units)
529 		{
530 		if (show_units)
531 			*units = units_fahrenheit ? 'F':'C';
532 	   	else
533 			*units = '\0';
534 		}
535 	if (sensor)
536 		gkrellm_debug(DEBUG_SENSORS, "sensor_temp: %s %s t=%.2f\n",
537 					sensor->name_locale, sensor->path, sensor->value);
538 	if (found_temp && sensor)
539 		gkrellm_check_alert(sensor->alert, sensor->value);
540 	return found_temp;
541 	}
542 
543 gboolean
gkrellm_sensor_read_temperature(gpointer sr,gfloat * temp,gchar * units)544 gkrellm_sensor_read_temperature(gpointer sr, gfloat *temp, gchar *units)
545 	{
546 	return sensor_read_temperature((Sensor *) sr, temp, units);
547 	}
548 
549 
550 static gboolean
sensor_read_fan(Sensor * sensor,gfloat * fan)551 sensor_read_fan(Sensor *sensor, gfloat *fan)
552 	{
553 	gfloat	f = 0;
554 	gint	found_fan = FALSE;
555 
556 	if (sensor && get_fan)
557 		{
558 		found_fan = thread_data_valid ? TRUE
559 				: (*get_fan)(sensor->path, sensor->id,
560 						sensor->iodev, sensor->inter, &sensor->raw_value);
561 		sensor->value = sensor->raw_value * sensor->factor;
562 		f = sensor->value;
563 		}
564 	if (! found_fan && _GK.demo)
565 		{
566 		f = 4980 + (gfloat)(rand() & 0x3f);
567 		found_fan = TRUE;
568 		}
569 	if (fan)
570 		*fan = f;
571 	if (sensor)
572 		gkrellm_debug(DEBUG_SENSORS, "sensor_fan: %s %s rpm=%.0f\n",
573 					sensor->name_locale, sensor->path, sensor->value);
574 	if (found_fan && sensor)
575 		gkrellm_check_alert(sensor->alert, sensor->value);
576 	return found_fan;
577 	}
578 
579 gboolean
gkrellm_sensor_read_fan(gpointer sr,gfloat * fan)580 gkrellm_sensor_read_fan(gpointer sr, gfloat *fan)
581 	{
582 	return sensor_read_fan((Sensor *) sr, fan);
583 	}
584 
585 
586 static gboolean
sensor_read_voltage(Sensor * sensor,gfloat * voltage)587 sensor_read_voltage(Sensor *sensor, gfloat *voltage)
588 	{
589 	gfloat		v = 0;
590 	gfloat		offset;
591 	gboolean	found_voltage = FALSE;
592 
593 	if (sensor && get_voltage)
594 		{
595 		found_voltage = thread_data_valid ? TRUE
596 			: (*get_voltage)(sensor->path, sensor->id,
597 					sensor->iodev, sensor->inter, &sensor->raw_value);
598 		offset = sensor->offset;
599 		if (sensor->vref)	/* A negative voltage is level shifted by vref */
600 			offset *= sensor->vref->value;
601 		sensor->value = sensor->raw_value * sensor->factor + offset;
602 		v = sensor->value;
603 		}
604 	if (! found_voltage && _GK.demo)
605 		{
606 		v = 2.9 + (gfloat)(rand() & 0x7) * 0.1;
607 		found_voltage = TRUE;
608 		}
609 	if (voltage)
610 		*voltage = v;
611 	if (sensor)
612 		gkrellm_debug(DEBUG_SENSORS, "sensor_voltage: %s %s v=%.2f\n",
613 				sensor->name_locale, sensor->path, sensor->value);
614 	if (found_voltage && sensor)
615 		gkrellm_check_alert(sensor->alert, sensor->value);
616 	return found_voltage;
617 	}
618 
619 gboolean
gkrellm_sensor_read_voltage(gpointer sr,gfloat * voltage)620 gkrellm_sensor_read_voltage(gpointer sr, gfloat *voltage)
621 	{
622 	return sensor_read_voltage((Sensor *) sr, voltage);
623 	}
624 
625 /* =================================================================== */
626 /* The sensors monitor */
627 
628 static void		sensor_reset_optionmenu(Sensor *sensor);
629 
630 #define	SENSOR_STYLE_NAME	"sensors"
631 
632 /* Temperature and fan sensors can be located on different panels depending
633 |  on the sensor group.
634 */
635 #define	SENSOR_PANEL_LOCATION	0
636 
637 #define	PROC_PANEL_LOCATION		1	/* SENSOR_GROUP_MAINBOARD */
638 #define	CPU_PANEL_LOCATION		2	/* cpu0 if smp */
639 
640 #define	DISK_PANEL_LOCATION		1	/* SENSOR_GROUP_DISK	*/
641 
642 
643 #define DO_TEMP	1
644 #define	DO_FAN	1
645 #define	DO_VOLT	1
646 
647 typedef struct
648 	{
649 	GkrellmPanel	**panel;
650 	GkrellmDecal	*name_decal,
651 					*sensor_decal;
652 	Sensor			*sensor;
653 	}
654 	SensorMon;
655 
656 static GtkWidget
657 				*temp_vbox,
658 				*fan_vbox,
659 				*volt_vbox;
660 
661 static GList	*volt_list,
662 				*temperature_list,
663 				*fan_list,
664 				*disk_temperature_list;
665 
666 static GkrellmPanel
667 				*pVolt,
668 				*pTemp,
669 				*pFan;
670 
671 static gint		style_id;
672 static gint		volt_mon_width,
673 				volt_mon_height,
674 				volt_name_width,
675 				volt_bezel_width;
676 
677 
678   /* Display modes */
679 #define	DIGITAL_WITH_LABELS	0
680 #define	DIGITAL_NO_LABELS	1
681 #define	N_DISPLAY_MODES		2
682 
683 #define	MONITOR_PAD		6
684 #define	NAME_PAD		4
685 
686 GkrellmMonitor	*mon_sensors;
687 GkrellmMonitor	*mon_config_sensors;
688 
689 static GkrellmPiximage
690 				*bezel_piximage;
691 
692 static GkrellmStyle
693 				*bezel_style;		/* Just for the bezel image border */
694 
695 static gint		display_mode,
696 				have_negative_volts;
697 
698 static gint		minus_width;		/* If will be drawing neg voltages */
699 
700   /* If drawing '-' sign, grub a pixel or two to tighten the layout */
701 static gint		pixel_grub;
702 
703 
704   /* Avoid writing decimal values into the config to avoid possible
705   |  locale changing decimal point breakage (decimal point can be '.' or ',')
706   */
707 #define	SENSOR_FLOAT_FACTOR		10000.0
708 static gfloat		sensor_float_factor = 1.0,
709 					gkrellm_float_factor = 1.0;
710 
711 gboolean
gkrellm_sensor_reset_location(gpointer sr)712 gkrellm_sensor_reset_location(gpointer sr)
713 	{
714 	GList		*list;
715 	Sensor		*sensor;
716 	gboolean	result = FALSE;
717 
718 	if (sr)
719 		{
720 		for (list = sensor_list; list; list = list->next)
721 			{
722 			sensor = (Sensor *) list->data;
723 			if (sr == sensor)
724 				{
725 				sensor->location = SENSOR_PANEL_LOCATION;
726 				sensor_reset_optionmenu(sensor);
727 				result = TRUE;
728 				break;
729 				}
730 			}
731 		}
732 	return result;
733 	}
734 
735 
736 static void
sensor_relocation_error(gchar * pname)737 sensor_relocation_error(gchar *pname)
738 	{
739 	gchar	*msg;
740 
741 	msg = g_strdup_printf(
742 				_("Can't find a %s panel to relocate sensor to."),
743 				pname ? pname : "?");
744 	gkrellm_config_message_dialog(NULL, msg);
745 	g_free(msg);
746 	}
747 
748   /* When moving off some other panel, reset that panel.
749   */
750 static void
sensor_reset_location(Sensor * sr)751 sensor_reset_location(Sensor *sr)
752 	{
753 	if (sr->group == SENSOR_GROUP_MAINBOARD)
754 		{
755 		if (sr->location == PROC_PANEL_LOCATION)
756 			gkrellm_proc_set_sensor(NULL, sr->type);
757 		else if (sr->location >= CPU_PANEL_LOCATION)
758 			gkrellm_cpu_set_sensor(NULL, sr->type,
759 						sr->location - CPU_PANEL_LOCATION);
760 		}
761 	else if (sr->group == SENSOR_GROUP_DISK)
762 		{
763 		if (sr->location == DISK_PANEL_LOCATION)
764 			gkrellm_disk_temperature_remove(sr->id_name);
765 		}
766 	}
767 
768 void
gkrellm_sensors_interface_remove(gint _interface)769 gkrellm_sensors_interface_remove(gint _interface)
770 	{
771 	GList		*list;
772 	Sensor		*sensor;
773 	gboolean	removed_one;
774 
775 	do
776 		{
777 		removed_one = FALSE;
778 		for (list = sensor_list; list; list = list->next)
779 			{
780 			sensor = (Sensor *) list->data;
781 			if (sensor->inter == _interface)
782 				{
783 				sensor_reset_location(sensor);
784 				g_free(sensor->id_name);
785 				g_free(sensor->path);
786 				g_free(sensor->name);
787 				g_free(sensor->default_label);
788 				g_free(sensor->vref_name);
789 				sensor_list = g_list_remove(sensor_list, sensor);
790 				g_free(sensor);
791 				removed_one = TRUE;
792 				break;
793 				}
794 			}
795 		}
796 	while (removed_one);
797 	}
798 
799 static void
add_sensor_monitor(Sensor * sr,GkrellmPanel ** p,GList ** smon_list)800 add_sensor_monitor(Sensor *sr, GkrellmPanel **p, GList **smon_list)
801 	{
802 	SensorMon		*smon;
803 	gfloat			t;
804 	gchar			units;
805 	gboolean		set_loc = FALSE;
806 
807 	sr->smon = NULL;
808 	if (!sr->enabled)
809 		return;
810 
811 	if (sr->location != SENSOR_PANEL_LOCATION)
812 		{
813 		if (sr->group == SENSOR_GROUP_MAINBOARD)
814 			{
815 			if (sr->location == PROC_PANEL_LOCATION)
816 				set_loc = gkrellm_proc_set_sensor(sr, sr->type);
817 			else
818 				set_loc = gkrellm_cpu_set_sensor(sr, sr->type,
819 							sr->location - CPU_PANEL_LOCATION);
820 			}
821 		else if (sr->group == SENSOR_GROUP_DISK)
822 			{
823 			if (sr->location == DISK_PANEL_LOCATION)
824 				{
825 				gkrellm_freeze_alert(sr->alert);
826 				sensor_read_temperature(sr, &t, &units);
827 				gkrellm_thaw_alert(sr->alert);
828 				set_loc = gkrellm_disk_temperature_display((gpointer) sr,
829 							sr->id_name, t, units);
830 				if (set_loc)
831 					disk_temperature_list =
832 							g_list_append(disk_temperature_list, sr);
833 				}
834 			}
835 		if (set_loc)
836 			return;
837 		sr->location = SENSOR_PANEL_LOCATION;
838 		}
839 	smon = g_new0(SensorMon, 1);
840 	smon->sensor = sr;
841 	smon->panel = p;		/* Alerts need a GkrellmPanel ** */
842 	*smon_list = g_list_append(*smon_list, smon);
843 	sr->smon = (gpointer) smon;
844 	}
845 
846 static void
make_sensor_monitor_lists(gboolean do_temp,gboolean do_fan,gboolean do_volt)847 make_sensor_monitor_lists(gboolean do_temp, gboolean do_fan, gboolean do_volt)
848 	{
849 	GList	*list;
850 	Sensor	*sr;
851 
852 	if (do_temp)
853 		{
854 		gkrellm_free_glist_and_data(&temperature_list);
855 		g_list_free(disk_temperature_list);
856 		disk_temperature_list = NULL;
857 		}
858 	if (do_fan)
859 		gkrellm_free_glist_and_data(&fan_list);
860 	if (do_volt)
861 		gkrellm_free_glist_and_data(&volt_list);
862 
863 	for (list = sensor_list; list; list = list->next)
864 		{
865 		sr = (Sensor *) list->data;
866 		if (do_temp && sr->type == SENSOR_TEMPERATURE)
867 			add_sensor_monitor(sr, &pTemp, &temperature_list);
868 		if (do_fan && sr->type == SENSOR_FAN)
869 			add_sensor_monitor(sr, &pFan, &fan_list);
870 		if (do_volt && sr->type == SENSOR_VOLTAGE)
871 			{
872 			if (!sr->has_config && sr->vref_name)
873 				sr->vref = lookup_vref(sr, sr->vref_name);
874 			add_sensor_monitor(sr, &pVolt, &volt_list);
875 			}
876 		}
877 	}
878 
879 #include "pixmaps/sensors/bg_volt.xpm"
880 
881 static void
cb_alert_trigger(GkrellmAlert * alert,SensorMon * smon)882 cb_alert_trigger(GkrellmAlert *alert, SensorMon *smon)
883 	{
884 	GkrellmAlertdecal	*ad;
885 	GkrellmDecal		*d;
886 
887 	ad = &alert->ad;
888 	alert->panel = *smon->panel;
889 
890 	/* Make the GkrellmAlertdecal show up under the sensor decal
891 	*/
892 	d = smon->sensor_decal;
893 	if (d)
894 		{
895 		ad->x = d->x - 2;
896 		ad->y = d->y - 2;
897 		ad->w = d->w + 3;
898 		ad->h = d->h + 4;
899 		gkrellm_render_default_alert_decal(alert);
900 		}
901 	}
902 
903 
904 static void
draw_bezels(GkrellmPanel * p,GList * smon_list,gint w,gint h,gint x_adjust)905 draw_bezels(GkrellmPanel *p, GList *smon_list, gint w, gint h, gint x_adjust)
906 	{
907 	GList			*list;
908 	GkrellmBorder	*b		= &bezel_style->border;
909 	SensorMon		*smon;
910 	GkrellmDecal	*dv;
911 	gint			x;
912 
913 	if (!bezel_piximage)
914 		return;
915 	for (list = smon_list; list; list = list->next)
916 		{
917 		smon = (SensorMon *) list->data;
918 		dv = smon->sensor_decal;
919 		x = dv->x + x_adjust;
920 		if (w == 0)
921 			w = b->left + dv->w + b->right - x_adjust;
922 		if (h == 0)
923 			h = b->top + b->bottom + dv->h;
924 		gkrellm_paste_piximage(bezel_piximage, p->bg_pixmap,
925 				x - b->left, dv->y - b->top, w, h);
926 		gkrellm_paste_piximage(bezel_piximage, p->pixmap,
927 				x - b->left, dv->y - b->top, w, h);
928 		}
929 	gdk_draw_drawable(p->bg_text_layer_pixmap, _GK.draw1_GC, p->bg_pixmap,
930 				0, 0,  0, 0,  p->w, p->h);
931 	}
932 
933 
934 static gboolean
any_negative_volts(void)935 any_negative_volts(void)
936 	{
937 	GList		*list;
938 	Sensor		*s;
939 	SensorMon	*volt;
940 	gfloat		v;
941 	gboolean	tmp, result = FALSE;
942 
943 	/* This routine can be called before any volt decals exist, but reading
944 	|  voltages can trigger alerts which expect to find decals.  Hence freeze.
945 	*/
946 	tmp = thread_data_valid;
947 	thread_data_valid = FALSE;	/* Need results immediately */
948 	for (list = volt_list; list; list = list->next)
949 		{
950 		volt = (SensorMon *) list->data;
951 		gkrellm_freeze_alert(volt->sensor->alert);
952 		s = volt->sensor->vref;
953 		if (s && s->value == 0)
954 			sensor_read_voltage(s, &v);
955 		sensor_read_voltage(volt->sensor, &v);
956 		gkrellm_thaw_alert(volt->sensor->alert);
957 		if (v < 0.0)
958 			{
959 			result = TRUE;
960 			break;
961 			}
962 		}
963 	thread_data_valid = tmp;
964 	return result;
965 	}
966 
967 static void
make_volt_decals(GkrellmPanel * p,GkrellmStyle * style)968 make_volt_decals(GkrellmPanel *p, GkrellmStyle *style)
969 	{
970 	GList				*list;
971 	GkrellmBorder		*b	= &bezel_style->border;
972 	Sensor				*sensor;
973 	SensorMon			*volt;
974 	GkrellmDecal		*dv, *dn;
975 	GkrellmTextstyle	*ts_volt, *ts_name;
976 	gchar				*fmt;
977 	gint				w_volt;
978 
979 	ts_name = gkrellm_meter_alt_textstyle(style_id);
980 	ts_volt = gkrellm_meter_textstyle(style_id);
981 
982 	volt_mon_width = 0;
983 	volt_mon_height = 0;
984 	volt_name_width = 0;
985 	w_volt = 0;
986 
987 	minus_width = 0;
988 	have_negative_volts = FALSE;
989 	fmt = "8.88";
990 	if (any_negative_volts())
991 		{
992 		have_negative_volts = TRUE;
993 		minus_width = 1;
994 		fmt = "-8.88";
995 		}
996 
997 	for (list = volt_list; list; list = list->next)
998 		{
999 		volt = (SensorMon *) list->data;
1000 		sensor = volt->sensor;
1001 		if (display_mode == DIGITAL_WITH_LABELS)
1002 			{
1003 			volt->name_decal = dn = gkrellm_create_decal_text(p,
1004 						volt->sensor->name_locale, ts_name, style, 0, 0, 0);
1005 			if (dn->w > volt_name_width)
1006 				volt_name_width = dn->w;
1007 			}
1008 		dv = gkrellm_create_decal_text(p, fmt, ts_volt, style, 0, 0, 0);
1009 		volt->sensor_decal = dv;
1010 		if (minus_width == 1)
1011 			minus_width = gkrellm_gdk_string_width(dv->text_style.font, "-");
1012 		w_volt = dv->w;			/* Same for all volt decals */
1013 		if (dv->h > volt_mon_height)
1014 			volt_mon_height = dv->h;
1015 
1016 		sensor->cb_alert = cb_alert_trigger;
1017 		sensor->cb_alert_data = volt;
1018 		gkrellm_alert_trigger_connect(sensor->alert, cb_alert_trigger, volt);
1019 		gkrellm_alert_command_process_connect(sensor->alert,
1020 					cb_command_process, sensor);
1021 		gkrellm_reset_alert_soft(sensor->alert);
1022 		}
1023 	pixel_grub = minus_width ? 1 : 0;
1024 	volt_bezel_width = b->left + w_volt + b->right - pixel_grub;
1025 	volt_mon_height += b->top + b->bottom;
1026 
1027 	/* If name decal I let bezel left border encroach into NAME_PAD space
1028 	*/
1029 	if (volt_name_width)
1030 		volt_mon_width = volt_name_width + NAME_PAD + w_volt + b->right;
1031 	else
1032 		volt_mon_width = w_volt;	/* borders encroach into MONITOR_PAD */
1033 	}
1034 
1035 static void
layout_volt_decals(GkrellmPanel * p,GkrellmStyle * style)1036 layout_volt_decals(GkrellmPanel *p, GkrellmStyle *style)
1037 	{
1038 	GList			*list;
1039 	SensorMon		*volt;
1040 	GkrellmDecal	*dv, *dn;
1041 	GkrellmMargin	*m;
1042 	gint			x, y, w, c, n, cols;
1043 
1044 	m = gkrellm_get_style_margins(style);
1045 	w = gkrellm_chart_width() - m->left - m->right;
1046 	cols = (w + MONITOR_PAD) / (volt_mon_width + MONITOR_PAD);
1047 	if (cols < 1)
1048 		cols = 1;
1049 	n = g_list_length(volt_list);
1050 	if (cols > n)
1051 		cols = n;;
1052 	volt_mon_width = w / cols;		/* spread them out */
1053 	x = (w - cols * volt_mon_width) / 2 + m->left;
1054 
1055 	gkrellm_get_top_bottom_margins(style, &y, NULL);
1056 	c = 0;
1057 	for (list = volt_list; list; list = list->next)
1058 		{
1059 		volt = (SensorMon *) list->data;
1060 		dn = volt->name_decal;
1061 		dv = volt->sensor_decal;
1062 		/* Right justify the volt decal in each volt_mon field
1063 		*/
1064 		dv->x = x + (c+1) * volt_mon_width - dv->w - bezel_style->border.right;
1065 		if (cols > 1 && !dn)
1066 			dv->x -= (volt_mon_width - volt_bezel_width) / 2;
1067 		dv->y = y + bezel_style->border.top;
1068 		if (dn)
1069 			{
1070 			if (cols == 1)
1071 				dn->x = m->left;
1072 			else
1073 				dn->x = dv->x - volt_name_width - NAME_PAD;
1074 			dn->y = y + bezel_style->border.top;
1075 			if (dn->h < dv->h)
1076 				dn->y += (dv->h - dn->h + 1) / 2;
1077 			}
1078 		if (++c >= cols)
1079 			{
1080 			c = 0;
1081 			y += volt_mon_height;
1082 			}
1083 		}
1084 	}
1085 
1086 static void
update_disk_temperatures(void)1087 update_disk_temperatures(void)
1088 	{
1089 	GList		*list;
1090 	Sensor		*sr;
1091 	gfloat		t;
1092 	gchar		units;
1093 	gboolean	display_failed = FALSE;
1094 
1095 	for (list = disk_temperature_list; list; list = list->next)
1096 		{
1097 		sr = (Sensor *) list->data;
1098 		sensor_read_temperature(sr, &t, &units);
1099 		if (!gkrellm_disk_temperature_display((gpointer) sr, sr->id_name,
1100 					t, units))
1101 			{
1102 			/* disk panel was disabled, so put temp back on sensors panel
1103 			*/
1104 			display_failed = TRUE;
1105 			sr->location = SENSOR_PANEL_LOCATION;
1106 			sensor_reset_optionmenu(sr);
1107 			}
1108 		}
1109 	if (display_failed)
1110 		gkrellm_sensors_rebuild(TRUE, FALSE, FALSE);
1111 	}
1112 
1113   /* Squeeze name decal text into a smaller font if it would overlap the
1114   |  sensor decal.  With smaller fonts, the y_ink value may be smaller which
1115   |  would bump the text upward.  So adjust decal offset by difference in
1116   |  y_ink value.  (GKrellM text decal heights don't include the y_ink
1117   |  space).
1118   */
1119 static gchar *
name_text_fit(Sensor * s,GkrellmDecal * dn,GkrellmDecal * ds)1120 name_text_fit(Sensor *s, GkrellmDecal *dn, GkrellmDecal *ds)
1121 	{
1122 	gchar	*string;
1123 	gint	x_limit, w0, w1, y_ink0, y_ink1, h0, h1;
1124 
1125 	x_limit = ds->x;
1126 
1127 	/* Check for '<' in case user is doing his own markup
1128 	*/
1129 	if (*(s->name_locale) != '<' && dn->x + dn->w > x_limit)
1130 		{
1131 		gkrellm_text_markup_extents(dn->text_style.font, s->name_locale,
1132 				strlen(s->name_locale), &w0, NULL, NULL, &y_ink0);
1133 		string = g_strdup_printf("<small>%s</small>", s->name_locale);
1134 		gkrellm_text_markup_extents(dn->text_style.font, string,
1135 				strlen(string), &w1, &h0, NULL, &y_ink1);
1136 		h1 = h0;
1137 		if (dn->x + w1 > x_limit)
1138 			{
1139 			g_free(string);
1140 			string = g_strdup_printf("<small><small>%s</small></small>",
1141 						s->name_locale);
1142 			gkrellm_text_markup_extents(dn->text_style.font, string,
1143 					strlen(string), &w1, &h1, NULL, &y_ink1);
1144 			}
1145 		gkrellm_decal_text_set_offset(dn, 0,
1146 					y_ink0 - y_ink1 + (h0 - h1 + 1) / 2);
1147 		}
1148 	else
1149 		{
1150 		gkrellm_decal_text_set_offset(dn, 0, 0);
1151 		string = g_strdup(s->name_locale);
1152 		}
1153 	return string;
1154 	}
1155 
1156 
1157 static void
draw_temperatures(gboolean draw_name)1158 draw_temperatures(gboolean draw_name)
1159 	{
1160 	GList		*list;
1161 	SensorMon	*smon;
1162 	Sensor		*sensor;
1163 	gfloat		t;
1164 	gchar		*name, units;
1165 
1166 	if (!pTemp)
1167 		return;
1168 	for (list = temperature_list; list; list = list->next)
1169 		{
1170 		smon = (SensorMon *) list->data;
1171 		sensor = smon->sensor;
1172 
1173 		if (draw_name && smon->name_decal)
1174 			{
1175 			name = name_text_fit(sensor, smon->name_decal, smon->sensor_decal);
1176 			gkrellm_draw_decal_markup(pTemp, smon->name_decal, name);
1177 			g_free(name);
1178 			}
1179 		if (smon->sensor_decal)
1180 			{
1181 			sensor_read_temperature(sensor, &t, &units);
1182 			gkrellm_sensor_draw_temperature_decal(pTemp, smon->sensor_decal,
1183 					t, units);
1184 			}
1185 		}
1186 	gkrellm_draw_panel_layers(pTemp);
1187 	}
1188 
1189 static void
draw_fans(gboolean draw_name)1190 draw_fans(gboolean draw_name)
1191 	{
1192 	GList		*list;
1193 	SensorMon	*smon;
1194 	Sensor		*sensor;
1195 	gchar		*name;
1196 	gfloat		f;
1197 
1198 	if (!pFan)
1199 		return;
1200 	for (list = fan_list; list; list = list->next)
1201 		{
1202 		smon = (SensorMon *) list->data;
1203 		sensor = smon->sensor;
1204 
1205 		if (draw_name && smon->name_decal)
1206 			{
1207 			name = name_text_fit(sensor, smon->name_decal, smon->sensor_decal);
1208 			gkrellm_draw_decal_markup(pFan, smon->name_decal, name);
1209 			g_free(name);
1210 			}
1211 		if (smon->sensor_decal)
1212 			{
1213 			sensor_read_fan(sensor, &f);
1214 			gkrellm_sensor_draw_fan_decal(pFan, smon->sensor_decal, f);
1215 			}
1216 		}
1217 	gkrellm_draw_panel_layers(pFan);
1218 	}
1219 
1220   /* If s is NULL, draw 'em all
1221   */
1222 static void
draw_voltages(Sensor * s,gint do_names)1223 draw_voltages(Sensor *s, gint do_names)
1224 	{
1225 	GList			*list;
1226 	SensorMon		*volt;
1227 	Sensor			*sensor;
1228 	GkrellmDecal	*ds, *dn;
1229 	gchar			*name, *fmt, buf[32];
1230 	gfloat			v;
1231 
1232 	if (!pVolt)
1233 		return;
1234 	for (list = volt_list; list; list = list->next)
1235 		{
1236 		volt = (SensorMon *) list->data;
1237 		sensor = volt->sensor;
1238 		if (s && s != sensor)
1239 			continue;
1240 		sensor->value_valid = FALSE;	/* In case vref monitoring stops */
1241 		dn = volt->name_decal;
1242 		ds = volt->sensor_decal;
1243 		if (do_names && dn)
1244 			{
1245 			name = name_text_fit(sensor, dn, ds);
1246 			gkrellm_draw_decal_markup(pVolt, dn, name);
1247 			g_free(name);
1248 			}
1249 		if (ds)
1250 			{
1251 			if (sensor->vref && !sensor->vref->value_valid)
1252 				sensor_read_voltage(sensor->vref, NULL);
1253 			sensor_read_voltage(sensor, &v);
1254 			sensor->value_valid = TRUE;
1255 			if ((v < 10.0 && v > 0.0) || (v > -10.0 && v < 0.0))
1256 				fmt = "%.2f";
1257 			else
1258 				fmt = "%.1f";
1259 			snprintf(buf, sizeof(buf), fmt, v);
1260 			ds->x_off = (v < 0.0) ? 0 : minus_width;
1261 			gkrellm_draw_decal_text(pVolt, ds, buf, -1);
1262 			}
1263 		}
1264 	gkrellm_draw_panel_layers(pVolt);
1265 	}
1266 
1267 static void
update_sensors(void)1268 update_sensors(void)
1269 	{
1270 	static gboolean		first_time_done;
1271 
1272 	if (!GK.five_second_tick && first_time_done)
1273 		{
1274 		if (need_disk_temperature_update)	/* delayed until disks created */
1275 			update_disk_temperatures();
1276 		need_disk_temperature_update = FALSE;
1277 		return;
1278 		}
1279 	if (use_threads)
1280 		{
1281 		thread_data_valid = TRUE;
1282 		run_sensors_thread();
1283 		}
1284 	draw_temperatures(FALSE);
1285 	draw_fans(FALSE);
1286 	draw_voltages(NULL, FALSE);
1287 	update_disk_temperatures();
1288 	first_time_done = TRUE;
1289 	}
1290 
1291 static gint
expose_event(GtkWidget * widget,GdkEventExpose * ev,GkrellmPanel * p)1292 expose_event(GtkWidget *widget, GdkEventExpose *ev, GkrellmPanel *p)
1293 	{
1294 	gdk_draw_drawable(widget->window, gkrellm_draw_GC(1), p->pixmap,
1295 				ev->area.x, ev->area.y, ev->area.x, ev->area.y,
1296 				ev->area.width, ev->area.height);
1297 	return FALSE;
1298 	}
1299 
1300 static gint
cb_panel_press(GtkWidget * widget,GdkEventButton * ev,GkrellmPanel * p)1301 cb_panel_press(GtkWidget *widget, GdkEventButton *ev, GkrellmPanel *p)
1302 	{
1303 	if (ev->button == 3)
1304 		gkrellm_open_config_window(mon_config_sensors);
1305 	return FALSE;
1306 	}
1307 
1308 static GkrellmBorder	default_bezel_border = {1,1,1,1};
1309 
1310 static void
assign_textstyles(GList * smon_list,GkrellmTextstyle ** ts_name,GkrellmTextstyle ** ts_sensor,gchar * format)1311 assign_textstyles(GList *smon_list, GkrellmTextstyle **ts_name, GkrellmTextstyle **ts_sensor,
1312 		gchar *format)
1313 	{
1314 	GList		*list;
1315 	GkrellmStyle *style;
1316 	GkrellmMargin *margin;
1317 	Sensor		*sensor;
1318 	SensorMon	*smon;
1319 	GkrellmTextstyle *ts, *ts_alt;
1320 	gint		w, w_name, w_sensor;
1321 
1322 	style = gkrellm_meter_style(style_id);
1323 	margin = gkrellm_get_style_margins(style);
1324 	ts = gkrellm_copy_textstyle(gkrellm_meter_textstyle(style_id));
1325 	ts_alt = gkrellm_copy_textstyle(gkrellm_meter_alt_textstyle(style_id));
1326 	w = gkrellm_chart_width() - margin->left - margin->right;
1327 	w_sensor = gkrellm_gdk_string_width(ts->font, format);
1328 	w_sensor += bezel_style->border.left + bezel_style->border.right;
1329 	for (list = smon_list; list; list = list->next)
1330 		{
1331 		smon = (SensorMon *)list->data;
1332 		sensor = smon->sensor;
1333 		w_name = gkrellm_gdk_string_width(ts_alt->font, sensor->name_locale);
1334 		if (w_name + w_sensor >  w - 2)
1335 			{
1336 			ts->font = ts_alt->font;	/* downsize the sensor font */
1337 			break;
1338 			}
1339 		}
1340 	*ts_name = ts_alt;		/* Caller must free these */
1341 	*ts_sensor = ts;
1342 	}
1343 
1344 static gint
adjust_decal_positions(SensorMon * smon)1345 adjust_decal_positions(SensorMon *smon)
1346 	{
1347 	gint	y, d, h_pad;
1348 
1349 	h_pad = bezel_style->border.top + bezel_style->border.bottom;
1350 	d = smon->sensor_decal->h - smon->name_decal->h;
1351 	y = smon->sensor_decal->y + smon->sensor_decal->h + h_pad;
1352 	if (d >= 0)
1353 		smon->name_decal->y += (d + 1) / 2;
1354 	else
1355 		{
1356 		if (h_pad < -d)
1357 			y = smon->name_decal->y + smon->name_decal->h;
1358 		smon->sensor_decal->y += -d / 2;
1359 		}
1360 	return y;
1361 	}
1362 
1363 static void
make_temperature_panel(GtkWidget * vbox,gint first_create)1364 make_temperature_panel(GtkWidget *vbox, gint first_create)
1365 	{
1366 	Sensor				*sensor;
1367 	SensorMon			*smon = NULL;
1368 	GkrellmStyle		*style;
1369 	GkrellmMargin		*m;
1370 	GkrellmDecal		*d;
1371 	GList				*list;
1372 	GkrellmTextstyle	*ts_sensor, *ts_name;
1373 	gchar				*format;
1374 	gint				y;
1375 
1376 	if (!pTemp)
1377 		return;
1378 	style = gkrellm_meter_style(style_id);
1379 	m = gkrellm_get_style_margins(style);
1380 	if (show_units)
1381 		format = units_fahrenheit ? "188.8F" : "88.8C";
1382 	else
1383 		format = units_fahrenheit ? "188.8" : "88.8";
1384 	assign_textstyles(temperature_list, &ts_name, &ts_sensor, format);
1385 	gkrellm_get_top_bottom_margins(style, &y, NULL);
1386 	y += bezel_style->border.top;
1387 	for (list = temperature_list; list; list = list->next)
1388 		{
1389 		smon = (SensorMon *) list->data;
1390 		sensor = smon->sensor;
1391 		d = gkrellm_create_decal_text(pTemp, format,
1392 				ts_sensor, style, -1, y, 0);
1393 		d->x = gkrellm_chart_width() - d->w - m->right - 1;
1394 		smon->sensor_decal = d;
1395 
1396 		smon->name_decal = gkrellm_create_decal_text(pTemp,
1397 					sensor->name_locale, ts_name, style, -1, y, 0);
1398 		y = adjust_decal_positions(smon);
1399 		sensor->cb_alert = cb_alert_trigger;
1400 		sensor->cb_alert_data = smon;
1401 		gkrellm_alert_trigger_connect(sensor->alert, cb_alert_trigger, smon);
1402 		gkrellm_alert_command_process_connect(sensor->alert,
1403 					cb_command_process, sensor);
1404 		gkrellm_reset_alert_soft(sensor->alert);
1405 		}
1406 	g_free(ts_name);
1407 	g_free(ts_sensor);
1408 	gkrellm_panel_configure(pTemp, NULL, style);
1409 	if (smon && smon->sensor_decal->y + smon->sensor_decal->h >
1410 		smon->name_decal->y + smon->name_decal->h - bezel_style->border.bottom
1411 	   )
1412 		gkrellm_panel_configure_add_height(pTemp, bezel_style->border.bottom);
1413 	gkrellm_panel_create(vbox, mon_sensors, pTemp);
1414 	draw_bezels(pTemp, temperature_list, 0, 0, 1);
1415 	if (first_create)
1416 		{
1417 		g_signal_connect(G_OBJECT(pTemp->drawing_area), "expose_event",
1418 				G_CALLBACK(expose_event), pTemp);
1419 		g_signal_connect(G_OBJECT(pTemp->drawing_area), "button_press_event",
1420 				G_CALLBACK(cb_panel_press), pTemp);
1421 		}
1422 	draw_temperatures(TRUE);
1423 	}
1424 
1425 static void
make_fan_panel(GtkWidget * vbox,gint first_create)1426 make_fan_panel(GtkWidget *vbox, gint first_create)
1427 	{
1428 	Sensor			*sensor;
1429 	SensorMon		*smon = NULL;
1430 	GkrellmStyle	*style;
1431 	GkrellmMargin	*m;
1432 	GkrellmDecal	*d;
1433 	GList			*list;
1434 	GkrellmTextstyle *ts_sensor, *ts_name;
1435 	gchar			*format;
1436 	gint			y;
1437 
1438 	if (!pFan)
1439 		return;
1440 	style = gkrellm_meter_style(style_id);
1441 	m = gkrellm_get_style_margins(style);
1442 	format = "8888";
1443 	assign_textstyles(temperature_list, &ts_name, &ts_sensor, format);
1444 	gkrellm_get_top_bottom_margins(style, &y, NULL);
1445 	y += bezel_style->border.top;
1446 	for (list = fan_list; list; list = list->next)
1447 		{
1448 		smon = (SensorMon *) list->data;
1449 		sensor = smon->sensor;
1450 		d = gkrellm_create_decal_text(pFan, format,
1451 				ts_sensor, style, -1, y, 0);
1452 		d->x = gkrellm_chart_width() - d->w - m->right - 1;
1453 		smon->sensor_decal = d;
1454 
1455 		smon->name_decal = gkrellm_create_decal_text(pFan, sensor->name_locale,
1456 					ts_name, style, -1, y, 0);
1457 		y = adjust_decal_positions(smon);
1458 		sensor->cb_alert = cb_alert_trigger;
1459 		sensor->cb_alert_data = smon;
1460 		gkrellm_alert_trigger_connect(sensor->alert, cb_alert_trigger, smon);
1461 		gkrellm_alert_command_process_connect(sensor->alert,
1462 					cb_command_process, sensor);
1463 		gkrellm_reset_alert_soft(sensor->alert);
1464 		}
1465 	g_free(ts_name);
1466 	g_free(ts_sensor);
1467 	gkrellm_panel_configure(pFan, NULL, style);
1468 	if (smon && smon->sensor_decal->y + smon->sensor_decal->h >
1469 		smon->name_decal->y + smon->name_decal->h - bezel_style->border.bottom
1470 	   )
1471 		gkrellm_panel_configure_add_height(pFan, bezel_style->border.bottom);
1472 	gkrellm_panel_create(vbox, mon_sensors, pFan);
1473 	draw_bezels(pFan, fan_list, 0, 0, 0);
1474 	if (first_create)
1475 		{
1476 		g_signal_connect(G_OBJECT(pFan->drawing_area), "expose_event",
1477 				G_CALLBACK(expose_event), pFan);
1478 		g_signal_connect(G_OBJECT(pFan->drawing_area), "button_press_event",
1479 				G_CALLBACK(cb_panel_press), pFan);
1480 		}
1481 	draw_fans(TRUE);
1482 	}
1483 
1484 static void
make_volt_panel(GtkWidget * vbox,gint first_create)1485 make_volt_panel(GtkWidget *vbox, gint first_create)
1486 	{
1487 	GkrellmStyle	*style;
1488 
1489 	if (!pVolt)
1490 		return;
1491 	style = gkrellm_meter_style(style_id);
1492 	make_volt_decals(pVolt, style);
1493 	layout_volt_decals(pVolt, style);
1494 
1495 	gkrellm_panel_configure(pVolt, NULL, style);
1496 
1497 	/* Make the bottom margin reference against the bottom volt decals
1498 	|  bezel image.  The volt decal height does not include the bezel so
1499 	|  gkrellm_panel_configure() did not account for the bezel.
1500 	*/
1501 	gkrellm_panel_configure_add_height(pVolt, bezel_style->border.bottom);
1502 	gkrellm_panel_create(vbox, mon_sensors, pVolt);
1503 
1504 	draw_bezels(pVolt, volt_list,
1505 			volt_bezel_width, volt_mon_height, pixel_grub);
1506 
1507 	if (first_create)
1508 		{
1509 		g_signal_connect(G_OBJECT(pVolt->drawing_area), "expose_event",
1510 				G_CALLBACK(expose_event), pVolt);
1511 		g_signal_connect(G_OBJECT(pVolt->drawing_area), "button_press_event",
1512 				G_CALLBACK(cb_panel_press), pVolt);
1513 		}
1514 	draw_voltages(NULL, TRUE);
1515 	}
1516 
1517 
1518 static void
destroy_sensors_monitor(gboolean do_temp,gboolean do_fan,gboolean do_volt)1519 destroy_sensors_monitor(gboolean do_temp, gboolean do_fan, gboolean do_volt)
1520 	{
1521 	if (do_temp)
1522 		{
1523 		gkrellm_panel_destroy(pTemp);
1524 		pTemp = NULL;
1525 		}
1526 	if (do_fan)
1527 		{
1528 		gkrellm_panel_destroy(pFan);
1529 		pFan = NULL;
1530 		}
1531 	if (do_volt)
1532 		{
1533 		gkrellm_panel_destroy(pVolt);
1534 		pVolt = NULL;
1535 		}
1536 	}
1537 
1538 static void
create_sensors_monitor(gboolean do_temp,gboolean do_fan,gboolean do_volt,gboolean first_create)1539 create_sensors_monitor(gboolean do_temp, gboolean do_fan, gboolean do_volt,
1540 			gboolean first_create)
1541 	{
1542 	make_sensor_monitor_lists(do_temp, do_fan, do_volt);
1543 	if (do_temp && temperature_list)
1544 		{
1545 		if (!pTemp)
1546 			pTemp = gkrellm_panel_new0();
1547 		make_temperature_panel(temp_vbox, first_create);
1548 		}
1549 	if (do_fan && fan_list)
1550 		{
1551 		if (!pFan)
1552 			pFan = gkrellm_panel_new0();
1553 		make_fan_panel(fan_vbox, first_create);
1554 		}
1555 	if (do_volt && volt_list)
1556 		{
1557 		if (!pVolt)
1558 			pVolt = gkrellm_panel_new0();
1559 		make_volt_panel(volt_vbox, first_create);
1560 		}
1561 	if (temperature_list || fan_list || volt_list)
1562 		gkrellm_spacers_show(mon_sensors);
1563 	else
1564 		gkrellm_spacers_hide(mon_sensors);
1565 	}
1566 
1567 void
gkrellm_sensors_rebuild(gboolean do_temp,gboolean do_fan,gboolean do_volt)1568 gkrellm_sensors_rebuild(gboolean do_temp, gboolean do_fan, gboolean do_volt)
1569 	{
1570 	destroy_sensors_monitor(do_temp, do_fan, do_volt);
1571 	create_sensors_monitor(do_temp, do_fan, do_volt, TRUE);
1572 	}
1573 
1574 static void
create_sensors(GtkWidget * vbox,gint first_create)1575 create_sensors(GtkWidget *vbox, gint first_create)
1576 	{
1577 	gchar			**xpm;
1578 	static gboolean	config_loaded;
1579 
1580 	if (!config_loaded)
1581 		read_sensors_config();
1582 	if (first_create)
1583 		{
1584 		temp_vbox = gtk_vbox_new(FALSE, 0);
1585 		gtk_box_pack_start(GTK_BOX(vbox), temp_vbox, FALSE, FALSE, 0);
1586 		gtk_widget_show(temp_vbox);
1587 
1588 		fan_vbox = gtk_vbox_new(FALSE, 0);
1589 		gtk_box_pack_start(GTK_BOX(vbox), fan_vbox, FALSE, FALSE, 0);
1590 		gtk_widget_show(fan_vbox);
1591 
1592 		volt_vbox = gtk_vbox_new(FALSE, 0);
1593 		gtk_box_pack_start(GTK_BOX(vbox), volt_vbox, FALSE, FALSE, 0);
1594 		gtk_widget_show(volt_vbox);
1595 
1596 		bezel_style = gkrellm_style_new0();
1597 		}
1598 	else		/* To be done after disk panels created */
1599 		need_disk_temperature_update = TRUE;
1600 
1601 	config_loaded = TRUE;
1602 
1603 	/* Here is where I define the volt panel theme image extensions.  I ask
1604 	|  for a theme extension image:
1605 	|      THEME_DIR/sensors/bg_volt.png
1606 	|  and for a border for it from the gkrellmrc in the format:
1607 	|      set_piximage_border sensors_bg_volt l,r,t,b
1608 	| There is no default for bg_volt image, ie it may end up being NULL.
1609 	*/
1610 	xpm = gkrellm_using_default_theme() ? bg_volt_xpm : NULL;
1611 	if (bezel_piximage)
1612 		gkrellm_destroy_piximage(bezel_piximage);
1613 	bezel_piximage = NULL;
1614 	gkrellm_load_piximage("bg_volt", xpm, &bezel_piximage, SENSOR_STYLE_NAME);
1615 	if (!gkrellm_set_gkrellmrc_piximage_border("sensors_bg_volt", bezel_piximage, bezel_style))
1616 		bezel_style->border = default_bezel_border;
1617 
1618 	create_sensors_monitor(DO_TEMP, DO_FAN, DO_VOLT, first_create);
1619 	}
1620 
1621   /* FIXME: monitor_sensors and monitor_config_sensors should be combined,
1622   |  but the issue is apply_sensors_config() must be called before the CPU
1623   |  and Proc apply, and I want create_sensors() called after the CPU and Proc
1624   |  create.  So for now, two GkrellmMonitor structs and have two sensor
1625   |  monitor add_builtins() in main.c.
1626   */
1627 static GkrellmMonitor	monitor_sensors =
1628 	{
1629 	N_("Sensors"),		/* Voltage config handled in Sensors tab */
1630 	MON_VOLTAGE,		/* Id,  0 if a plugin		*/
1631 	create_sensors,		/* The create function		*/
1632 	update_sensors,		/* The update function		*/
1633 	NULL,				/* The config tab create function	*/
1634 	NULL,				/* Voltage apply handled in sensors apply */
1635 
1636 	NULL,				/* Voltage save config is in sensors save */
1637 	NULL,				/* Voltage load config is in sensors load */
1638 	NULL,				/* config keyword - use sensors */
1639 
1640 	NULL,				/* Undef 2	*/
1641 	NULL,				/* Undef 1	*/
1642 	NULL,				/* Undef 0	*/
1643 
1644 	0,					/* insert_before_id - place plugin before this mon */
1645 
1646 	NULL,				/* Handle if a plugin, filled in by GKrellM		*/
1647 	NULL				/* path if a plugin, filled in by GKrellM		*/
1648 	};
1649 
1650 GkrellmMonitor *
gkrellm_init_sensor_monitor(void)1651 gkrellm_init_sensor_monitor(void)
1652 	{
1653 	if (!sensor_list)
1654 		return NULL;
1655 	monitor_sensors.name = _(monitor_sensors.name);
1656 	style_id = gkrellm_add_meter_style(&monitor_sensors, SENSOR_STYLE_NAME);
1657 	mon_sensors = &monitor_sensors;
1658 	return &monitor_sensors;
1659 	}
1660 
1661 /* =================================================================== */
1662 /* Config for sensors monitor */
1663 
1664   /* Don't use the user-config.  Save into sensors-config and only if there
1665   |  is a sensor_list.  This preserves configs across a possible sensors
1666   |  modules load screw up.
1667   |
1668   |  2.2.3 sets sensor_config_version to 1 to allow sensor relocation
1669   |  to composite CPU on a SMP machine.
1670   |
1671   |  2.1.15 scales sensor factor/offset values by SENSOR_FLOAT_FACTOR to avoid
1672   |  writing decimal points in the config.  This is not backwards compatible
1673   |  with the pre 2.1.15 sensor_config format hence the config file name
1674   |  change to sensor-config.  But sensor_config is forward compatible
1675   |  since the float factor defaults to 1.0.
1676   */
1677 #define	SENSOR_CONFIG_VERSION			1
1678 
1679 #define	SENSOR_CONFIG_KEYWORD		"sensor"
1680 #define	SENSOR_CONFIG_FILE			"sensor-config"
1681 #define	SENSOR_2_1_14_CONFIG_FILE	"sensors_config"
1682 
1683 typedef struct
1684 	{
1685 	gchar		*config_keyword,
1686 				*config_label;
1687 	gboolean	value;
1688 	void		(*func)(gboolean value);
1689 	}
1690 	SysdepOption;
1691 
1692 static void		cb_alert_config(GkrellmAlert *ap, Sensor *sr);
1693 
1694 static GList	*sysdep_option_list;
1695 
1696 static void
create_sensor_alert(Sensor * s)1697 create_sensor_alert(Sensor *s)
1698 	{
1699 	if (s->type == SENSOR_VOLTAGE)
1700 		s->alert = gkrellm_alert_create(NULL, s->name,
1701 				_("Sensor Volt Limits"),
1702 				TRUE, TRUE, TRUE, 20, -20, 0.01, 0.5, 2);
1703 	else if (s->type == SENSOR_TEMPERATURE)
1704 		s->alert = gkrellm_alert_create(NULL, s->name,
1705 				_("Sensor Temperature Limits (in displayed degree units)"),
1706 				TRUE, FALSE, TRUE, 300, 0, 1.0, 5.0, 1);
1707 	else if (s->type == SENSOR_FAN)
1708 		s->alert = gkrellm_alert_create(NULL, s->name,
1709 				_("Sensor Fan RPM Limits"),
1710 				FALSE, TRUE, TRUE, 20000, 0, 100, 1000, 0);
1711 	else
1712 		return;
1713 	gkrellm_alert_delay_config(s->alert, 5, 60, 0);
1714 	gkrellm_alert_trigger_connect(s->alert, s->cb_alert, s->cb_alert_data);
1715 	gkrellm_alert_command_process_connect(s->alert, cb_command_process, s);
1716 	gkrellm_alert_config_connect(s->alert, cb_alert_config, s);
1717 	}
1718 
1719 void
gkrellm_sensors_sysdep_option(gchar * keyword,gchar * label,void (* func)())1720 gkrellm_sensors_sysdep_option(gchar *keyword, gchar *label, void (*func)())
1721 	{
1722 	SysdepOption	*so = NULL;
1723 
1724 	so = g_new0(SysdepOption, 1);
1725 	sysdep_option_list = g_list_append(sysdep_option_list, so);
1726 	so->config_keyword = g_strdup(keyword);
1727 	so->config_label = g_strdup(label);
1728 	so->func = func;
1729 	}
1730 
1731 static void
save_sensors_config(FILE * f_not_used)1732 save_sensors_config(FILE *f_not_used)
1733 	{
1734 	FILE			*f;
1735 	GList			*list;
1736 	Sensor			*s;
1737 	SysdepOption	*so;
1738 	gchar			*config, quoted_name[128], buf[128];
1739 	gfloat			factor, offset;
1740 
1741 	if (!sensor_list || _GK.no_config)
1742 		return;
1743 	snprintf(buf, sizeof(buf), "%s/%s", GKRELLM_DIR, SENSOR_CONFIG_FILE);
1744 	config = gkrellm_make_config_file_name(gkrellm_homedir(), buf);
1745 	f = g_fopen(config, "w");
1746 	g_free(config);
1747 	if (!f)
1748 		return;
1749 
1750 	fprintf(f, "%s sensor_config_version %d\n",
1751 				SENSOR_CONFIG_KEYWORD, SENSOR_CONFIG_VERSION);
1752 	fprintf(f, "%s sensor_sysdep_private %d\n",
1753 				SENSOR_CONFIG_KEYWORD, sensor_current_sysdep_private);
1754 	fprintf(f, "%s sensor_float_factor %.0f\n",
1755 				SENSOR_CONFIG_KEYWORD, SENSOR_FLOAT_FACTOR);
1756 	fprintf(f, "%s gkrellm_float_factor %.0f\n",
1757 				SENSOR_CONFIG_KEYWORD, GKRELLM_FLOAT_FACTOR);
1758 	for (list = sysdep_option_list; list; list = list->next)
1759 		{
1760 		so = (SysdepOption *) list->data;
1761 		fprintf(f, "%s sysdep_option %s %d\n", SENSOR_CONFIG_KEYWORD,
1762 					so->config_keyword, so->value);
1763 		}
1764 
1765 	for (list = sensor_list; list; list = list->next)
1766 		{
1767 		s = (Sensor *) list->data;
1768 		if (s->name && *(s->name))
1769 			{
1770 			snprintf(quoted_name, sizeof(quoted_name), "\"%s\"", s->id_name);
1771 			factor = (s->default_factor != 0.0 ? s->factor : 0.0);
1772 			offset = (s->default_factor != 0.0 ? s->offset : 0.0);
1773 			fprintf(f, "%s \"%s\" %s %.0f %.0f %d %d\n",
1774 				SENSOR_CONFIG_KEYWORD,
1775 				s->name, quoted_name,
1776 				factor * SENSOR_FLOAT_FACTOR,
1777 				offset * SENSOR_FLOAT_FACTOR,
1778 				s->enabled, s->location);
1779 			if (s->alert)
1780 				gkrellm_save_alertconfig(f, s->alert,
1781 						SENSOR_CONFIG_KEYWORD, quoted_name);
1782 			}
1783 		}
1784 	for (list = sensor_list; list; list = list->next)
1785 		{
1786 		s = (Sensor *) list->data;
1787 		if (s->vref)
1788 			fprintf(f, "%s vref \"%s\" \"%s\"\n", SENSOR_CONFIG_KEYWORD,
1789 					s->id_name, s->vref->id_name);
1790 		}
1791 
1792 	fprintf(f, "%s units_fahrenheit %d\n", SENSOR_CONFIG_KEYWORD,
1793 				units_fahrenheit);
1794 	fprintf(f, "%s show_units %d\n", SENSOR_CONFIG_KEYWORD,
1795 				show_units);
1796 	fprintf(f, "%s volt_display_mode %d\n", SENSOR_CONFIG_KEYWORD,
1797 				display_mode);
1798 	/* _GK.mbmon_port is handled in config.c so that the port can be
1799 	|  loaded early for sensor initialization.
1800 	*/
1801 	fclose(f);
1802 	}
1803 
1804 static void
load_sensors_config(gchar * arg)1805 load_sensors_config(gchar *arg)
1806 	{
1807 	Sensor			*s;
1808 	SysdepOption	*so;
1809 	GList			*list;
1810 	gchar			config[32], item[CFG_BUFSIZE], item1[CFG_BUFSIZE];
1811 	gchar			label[64], id_name[CFG_BUFSIZE];
1812 	gint			n;
1813 	gfloat			f	= 1.0,
1814 					o	= 0.0;
1815 	gint			e	= 0,
1816 					location = 0;
1817 	gfloat			save_factor;
1818 
1819 	n = sscanf(arg, "%31s %[^\n]", config, item);
1820 	if (n != 2)
1821 		return;
1822 	gkrellm_debug(DEBUG_SENSORS, "load_sensors_config: <%s> <%s>\n", config,
1823 		item);
1824 	if (!strcmp(config, "sensor_config_version"))
1825 		sscanf(item, "%d", &sensor_config_version);
1826 	else if (!strcmp(config, "sensor_sysdep_private"))
1827 		sscanf(item, "%d", &sensor_config_sysdep_private);
1828 	else if (!strcmp(config, "units_fahrenheit"))
1829 		sscanf(item, "%d", &units_fahrenheit);
1830 	else if (!strcmp(config, "show_units"))
1831 		sscanf(item, "%d", &show_units);
1832 	else if (!strcmp(config, "volt_display_mode"))
1833 		sscanf(item, "%d", &display_mode);
1834 	else if (!strcmp(config, "sensor_float_factor"))
1835 		sscanf(item, "%f", &sensor_float_factor);
1836 	else if (!strcmp(config, "gkrellm_float_factor"))
1837 		sscanf(item, "%f", &gkrellm_float_factor);
1838 	else if (!strcmp(config, "vref"))
1839 		{
1840 		if (   sscanf(item, "\"%63[^\"]\" \"%64[^\"]\"", id_name, item1) == 2
1841 			&& (s = lookup_sensor_from_id_name(id_name)) != NULL
1842 		   )
1843 			s->vref = lookup_sensor_from_id_name(item1);
1844 		}
1845 	else if (!strcmp(config, "sysdep_option"))
1846 		{
1847 		if (sscanf(item, "%63s %[^\n]", id_name, item1) == 2)
1848 			{
1849 			so = NULL;
1850 			for (list = sysdep_option_list; list; list = list->next)
1851 				{
1852 				so = (SysdepOption *) list->data;
1853 				if (!strcmp(so->config_keyword, id_name))
1854 					break;
1855 				so = NULL;
1856 				}
1857 			if (so && so->func)
1858 				{
1859 				so->value = atoi(item1);
1860 				(*so->func)(so->value);
1861 				}
1862 			}
1863 		}
1864 	else if (!strcmp(config, GKRELLM_ALERTCONFIG_KEYWORD))
1865 		{
1866 		if (   sscanf(item, "\"%63[^\"]\" %[^\n]", id_name, item1) == 2
1867 			&& (s = lookup_sensor_from_id_name(id_name)) != NULL
1868 		   )
1869 			{
1870 			/* Since config files may be copied around, make sure to use the
1871 			|  gkrellm float factor in effect when the sensors config was
1872 			|  created.
1873 			*/
1874 			save_factor = _GK.float_factor;
1875 			_GK.float_factor = gkrellm_float_factor;
1876 			if (!s->alert)
1877 				create_sensor_alert(s);
1878 			gkrellm_load_alertconfig(&s->alert, item1);
1879 			_GK.float_factor = save_factor;
1880 			}
1881 		}
1882 	else if (   sscanf(arg, "\"%63[^\"]\" \"%[^\"]\" %f %f %d %d",
1883 						label, id_name, &f, &o, &e, &location) > 1
1884 			 && (s = map_sensor_label(label, id_name)) != NULL
1885 			)
1886 		{
1887 		if (f != 0.0 && s->default_factor != 0.0)
1888 			{
1889 			s->factor = f / sensor_float_factor;
1890 			s->offset = o / sensor_float_factor;
1891 			}
1892 		s->enabled = e;
1893 
1894 		if (s->type == SENSOR_VOLTAGE)
1895 			s->location = 0;
1896 		else
1897 			{
1898 			s->location = location;
1899 			if (   sensor_config_version == 0 && gkrellm_smp_cpus() > 0
1900 				&& location > PROC_PANEL_LOCATION
1901 			   )
1902 				/* gkrellm < 2.2.3 did not allow relocating to composite
1903 				|  CPU if on a SMP machine.  But with hyperthreading, user
1904 				|  may want to do this.
1905 				*/
1906 				s->location += 1;
1907 			}
1908 		if (!using_new_config && s->type != SENSOR_VOLTAGE)
1909 			s->enabled = TRUE;		/* Old config enabled with a label */
1910 		}
1911 	if (display_mode < 0 || display_mode >= N_DISPLAY_MODES)
1912 		display_mode = N_DISPLAY_MODES - 1;
1913 	}
1914 
1915 static void
read_sensors_config(void)1916 read_sensors_config(void)
1917 	{
1918 	FILE	*f;
1919 	Sensor	*sr;
1920 	GList	*list;
1921 	gchar	*config;
1922 	gchar	buf[CFG_BUFSIZE];
1923 
1924 	snprintf(buf, sizeof(buf), "%s/%s", GKRELLM_DIR, SENSOR_CONFIG_FILE);
1925 	config = gkrellm_make_config_file_name(gkrellm_homedir(), buf);
1926 	f = g_fopen(config, "r");
1927 	g_free(config);
1928 
1929 	if (!f)
1930 		{
1931 		snprintf(buf, sizeof(buf), "%s/%s", GKRELLM_DIR, SENSOR_2_1_14_CONFIG_FILE);
1932 		config = gkrellm_make_config_file_name(gkrellm_homedir(), buf);
1933 		f = g_fopen(config, "r");
1934 		g_free(config);
1935 		}
1936 	if (f)
1937 		{
1938 		using_new_config = TRUE;
1939 		while (fgets(buf, sizeof(buf), f))
1940 			load_sensors_config(buf + strlen(SENSOR_CONFIG_KEYWORD) + 1);
1941 		fclose(f);
1942 		}
1943 
1944 	/* In case not all sensors are in sensor_config (user edited?)
1945 	*/
1946 	for (list = sensor_list; list; list = list->next)
1947 		{
1948 		sr = (Sensor *) list->data;
1949 		if (sr->has_config)		/* Was in sensor_config and is already	*/
1950 			continue;			/* appended to an order_list			*/
1951 		append_sensor_to_order_list(sr);
1952 		}
1953 	g_list_free(sensor_list);
1954 	sensor_list = temp_order_list;
1955 	sensor_list = g_list_concat(sensor_list, fan_order_list);
1956 	sensor_list = g_list_concat(sensor_list, volt_order_list);
1957 	}
1958 
1959 enum
1960 	{
1961 	NAME_COLUMN,
1962 	ENABLE_COLUMN,
1963 	LABEL_COLUMN,
1964 	SENSOR_COLUMN,
1965 	VISIBLE_COLUMN,
1966 	IMAGE_COLUMN,
1967 	N_COLUMNS
1968 	};
1969 
1970 static GtkTreeModel			*sensor_model;
1971 static GtkTreeView			*treeview;
1972 static GtkTreeRowReference	*row_reference;
1973 static GtkTreeSelection		*selection;
1974 
1975 
1976 static GtkWidget	*optionmenu;
1977 
1978 static GtkWidget	*display_mode_button[2];
1979 static GtkWidget	*factor_spin_button,
1980 					*offset_spin_button;
1981 static GtkWidget	*alert_button,
1982 					*mbmon_port_entry;
1983 
1984 static Sensor		*dragged_sensor;
1985 
1986 static gint			sensor_last_group;
1987 
1988 static gboolean		(*original_row_drop_possible)();
1989 
1990 
1991 
1992 static void
set_tree_store_model_data(GtkTreeStore * tree,GtkTreeIter * iter,Sensor * s)1993 set_tree_store_model_data(GtkTreeStore *tree, GtkTreeIter *iter, Sensor *s)
1994 	{
1995 	if (!s)
1996 		return;
1997 	gtk_tree_store_set(tree, iter,
1998 			NAME_COLUMN, s->id_name ? s->id_name : "??",
1999 			ENABLE_COLUMN, s->enabled,
2000 			LABEL_COLUMN, s->name ? s->name : "??",
2001 			SENSOR_COLUMN, s,
2002 			VISIBLE_COLUMN, TRUE,
2003 			-1);
2004 	if (s->alert)
2005 		gtk_tree_store_set(tree, iter,
2006 				IMAGE_COLUMN, gkrellm_alert_pixbuf(),
2007 				-1);
2008 	}
2009 
2010 static void
append_sensors_to_model(GtkTreeStore * tree,GtkTreeIter * citer,GtkTreeIter * iter,gint type)2011 append_sensors_to_model(GtkTreeStore *tree, GtkTreeIter *citer,
2012 			GtkTreeIter *iter, gint type)
2013 	{
2014 	GList	*list;
2015 	Sensor	*s;
2016 
2017 	for (list = sensor_list; list; list = list->next)
2018 		{
2019 		s = (Sensor *) list->data;
2020 		if (s->type != type)
2021 			continue;
2022 		gtk_tree_store_append(tree, citer, iter);
2023 		set_tree_store_model_data(tree, citer, s);
2024 		}
2025 	}
2026 
2027 static GtkTreeModel *
create_model(void)2028 create_model(void)
2029 	{
2030 	GtkTreeStore	*tree;
2031 	GtkTreeIter		iter, citer;
2032 
2033 	tree = gtk_tree_store_new(N_COLUMNS,
2034 				G_TYPE_STRING,
2035                 G_TYPE_BOOLEAN,
2036                 G_TYPE_STRING,
2037                 G_TYPE_POINTER,
2038 				G_TYPE_BOOLEAN,
2039 				GDK_TYPE_PIXBUF
2040 				);
2041 
2042 	gtk_tree_store_append(tree, &iter, NULL);
2043 	gtk_tree_store_set(tree, &iter,
2044 				NAME_COLUMN, _("Temperatures"),
2045 				VISIBLE_COLUMN, FALSE,
2046 				-1);
2047 	append_sensors_to_model(tree, &citer, &iter, SENSOR_TEMPERATURE);
2048 
2049 	gtk_tree_store_append(tree, &iter, NULL);
2050 	gtk_tree_store_set(tree, &iter,
2051 				NAME_COLUMN, _("Fans"),
2052 				VISIBLE_COLUMN, FALSE,
2053 				-1);
2054 	append_sensors_to_model(tree, &citer, &iter, SENSOR_FAN);
2055 
2056 	gtk_tree_store_append(tree, &iter, NULL);
2057 	gtk_tree_store_set(tree, &iter,
2058 				NAME_COLUMN, _("Voltages"),
2059 				VISIBLE_COLUMN, FALSE,
2060 				-1);
2061 	append_sensors_to_model(tree, &citer, &iter, SENSOR_VOLTAGE);
2062 	return GTK_TREE_MODEL(tree);
2063 	}
2064 
2065 void
gkrellm_sensors_model_update(void)2066 gkrellm_sensors_model_update(void)
2067 	{
2068 	GtkTreeModel	*model;
2069 
2070 	if (!gkrellm_config_window_shown())
2071 		return;
2072 	model = sensor_model;
2073 	sensor_model = create_model();
2074 	gtk_tree_view_set_model(treeview, sensor_model);
2075 	if (model)
2076 		g_object_unref(G_OBJECT(model));
2077 	}
2078 
2079 static void
change_row_reference(GtkTreeModel * model,GtkTreePath * path)2080 change_row_reference(GtkTreeModel *model, GtkTreePath *path)
2081 	{
2082 	gtk_tree_row_reference_free(row_reference);
2083 	if (model && path)
2084 		row_reference = gtk_tree_row_reference_new(model, path);
2085 	else
2086 		row_reference = NULL;
2087 	}
2088 
2089 static Sensor *
get_referenced_sensor(void)2090 get_referenced_sensor(void)
2091 	{
2092 	GtkTreeModel	*model;
2093 	GtkTreePath		*path;
2094 	GtkTreeIter		iter;
2095 	Sensor			*s;
2096 
2097 	if (!row_reference)
2098 		return NULL;
2099 	model = gtk_tree_view_get_model(treeview);
2100 	path = gtk_tree_row_reference_get_path(row_reference);
2101 	gtk_tree_model_get_iter(model, &iter, path);
2102 	gtk_tree_model_get(model, &iter,
2103 			SENSOR_COLUMN, &s, -1);
2104 	return s;
2105 	}
2106 
2107 static gboolean
get_child_iter(GtkTreeModel * model,gchar * parent_node,GtkTreeIter * citer)2108 get_child_iter(GtkTreeModel *model, gchar *parent_node, GtkTreeIter *citer)
2109 	{
2110 	GtkTreePath		*path;
2111 	GtkTreeIter		iter;
2112 
2113 	path = gtk_tree_path_new_from_string(parent_node);
2114 	gtk_tree_model_get_iter(model, &iter, path);
2115 	gtk_tree_path_free(path);
2116 	return gtk_tree_model_iter_children(model, citer, &iter);
2117 	}
2118 
2119 
2120   /* Callback for a created or destroyed alert.  Find the sensor in the model
2121   |  and set the IMAGE_COLUMN.
2122   */
2123 static void
cb_alert_config(GkrellmAlert * ap,Sensor * sr)2124 cb_alert_config(GkrellmAlert *ap, Sensor *sr)
2125 	{
2126 	GtkTreeModel	*model;
2127 	GtkTreeIter		iter;
2128 	Sensor 			*s;
2129 	GdkPixbuf		*pixbuf;
2130 	gchar			node[2];
2131 	gint			i;
2132 
2133 	if (!gkrellm_config_window_shown())
2134 		return;
2135 	model = gtk_tree_view_get_model(treeview);
2136 	pixbuf = ap->activated ? gkrellm_alert_pixbuf() : NULL;
2137 	for (i = 0; i < 3; ++i)
2138 		{
2139 		node[0] = '0' + i;		/* toplevel temp, fan, or volt node */
2140 		node[1] = '\0';
2141 		if (get_child_iter(model, node, &iter))
2142 			do
2143 				{
2144 				gtk_tree_model_get(model, &iter, SENSOR_COLUMN, &s, -1);
2145 				if (s != sr)
2146 					continue;
2147 				gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
2148 								IMAGE_COLUMN, pixbuf, -1);
2149 				return;
2150 				}
2151 			while (gtk_tree_model_iter_next(model, &iter));
2152 		}
2153 	}
2154 
2155   /* Allow destination drops only on depth 2 paths and don't allow drops from
2156   |  source depths of 1 (top level nodes).  Also disallow drags from one sensor
2157   |  type to another. Note: from some reason if I allow drops on depth 3 nodes
2158   |  (destination is on top of a second level node) I am not getting
2159   |  "drag_end" callbacks.
2160   */
2161 static gboolean
row_drop_possible(GtkTreeDragDest * drag_dest,GtkTreePath * path,GtkSelectionData * selection_data)2162 row_drop_possible(GtkTreeDragDest *drag_dest, GtkTreePath *path,
2163 			GtkSelectionData *selection_data)
2164 	{
2165 	gint			*src_indices, *dst_indices;
2166 	GtkTreePath		*src_path;
2167 
2168 	if (!row_reference)
2169 		return FALSE;
2170 
2171 	src_path = gtk_tree_row_reference_get_path(row_reference);
2172 	src_indices = gtk_tree_path_get_indices(src_path);
2173 	dst_indices = gtk_tree_path_get_indices(path);
2174 //g_debug("drop path: indices=[%d,%d]:%d, path=%s\n",
2175 //	dst_indices[0], dst_indices[1], gtk_tree_path_get_depth(path),
2176 //	gtk_tree_path_to_string(path));
2177 
2178 	if (   gtk_tree_path_get_depth(src_path) == 1	/* Dragging top level */
2179 		|| gtk_tree_path_get_depth(path) != 2
2180 		|| src_indices[0] != dst_indices[0]		/* sensor types don't match */
2181 	   )
2182 		return FALSE;
2183 
2184 	return (*original_row_drop_possible)(drag_dest, path,
2185 									selection_data);
2186 	}
2187 
2188   /* At each drag, divert the original Gtk row_drop_possible function to my
2189   |  custom row_drop_possible so I can control tree structure.  The original
2190   |  row_drop_possible function must be restored at "drag_end" else other
2191   |  monitors doing drag n' drop could get screwed.
2192   */
2193 static gboolean
cb_drag_begin(GtkWidget * widget,GdkDragContext * context,gpointer data)2194 cb_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
2195 	{
2196 	GtkTreeModel			*model;
2197 	GtkTreePath				*path;
2198 	GtkTreeIter				iter;
2199 	GtkTreeDragDestIface	*dest_iface;
2200 
2201 	model = gtk_tree_view_get_model(treeview);
2202 	dest_iface = GTK_TREE_DRAG_DEST_GET_IFACE(GTK_TREE_DRAG_DEST(model));
2203 	if (!original_row_drop_possible)
2204 		original_row_drop_possible = dest_iface->row_drop_possible;
2205 	dest_iface->row_drop_possible = row_drop_possible;
2206 
2207 	if (row_reference)
2208 		{
2209 		path = gtk_tree_row_reference_get_path(row_reference);
2210 		gtk_tree_model_get_iter(model, &iter, path);
2211 		gtk_tree_model_get(model, &iter, SENSOR_COLUMN, &dragged_sensor, -1);
2212 		}
2213 	else
2214 		dragged_sensor = NULL;
2215 	return FALSE;
2216 	}
2217 
2218 static gboolean
cb_drag_end(GtkWidget * widget,GdkDragContext * context,gpointer data)2219 cb_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
2220 	{
2221 	GtkTreeModel			*model;
2222 	GtkTreeIter				iter;
2223 	GtkTreeDragDestIface	*dest_iface;
2224 	Sensor					*s;
2225 	gchar					node[2];
2226 	gint					i, type = -1;
2227 
2228 	model = gtk_tree_view_get_model(treeview);
2229 	dest_iface = GTK_TREE_DRAG_DEST_GET_IFACE(GTK_TREE_DRAG_DEST(model));
2230 	dest_iface->row_drop_possible = original_row_drop_possible;
2231 
2232 	change_row_reference(NULL, NULL);
2233 	gtk_tree_selection_unselect_all(selection);
2234 
2235 	g_list_free(sensor_list);
2236 	sensor_list = NULL;
2237 
2238 	/* Re-order the sensors list to match the model.
2239 	*/
2240 	model = gtk_tree_view_get_model(treeview);
2241 	for (i = 0; i < 3; ++i)
2242 		{
2243 		node[0] = '0' + i;		/* toplevel temp, fan, or volt node */
2244 		node[1] = '\0';
2245 		if (get_child_iter(model, node, &iter))
2246 			{
2247 			do
2248 				{
2249 				gtk_tree_model_get(model, &iter, SENSOR_COLUMN, &s, -1);
2250 				sensor_list = g_list_append(sensor_list, s);
2251 				}
2252 			while (gtk_tree_model_iter_next(model, &iter));
2253 			}
2254 		}
2255 
2256 	if (dragged_sensor)
2257 		type = dragged_sensor->type;
2258 	dragged_sensor = NULL;
2259 
2260 	if (type < 0)
2261 		gkrellm_sensors_rebuild(DO_TEMP, DO_FAN, DO_VOLT);
2262 	else
2263 		gkrellm_sensors_rebuild(type == SENSOR_TEMPERATURE,
2264 				type == SENSOR_FAN, type == SENSOR_VOLTAGE);
2265 
2266 	return FALSE;
2267 	}
2268 
2269 static void
sensor_reset_optionmenu(Sensor * sensor)2270 sensor_reset_optionmenu(Sensor *sensor)
2271 	{
2272 	Sensor	*sr;
2273 
2274 	if (!optionmenu)
2275 		return;
2276 	sr = get_referenced_sensor();
2277 	if (sr == sensor)
2278 		gtk_combo_box_set_active(GTK_COMBO_BOX(optionmenu),
2279 					SENSOR_PANEL_LOCATION);
2280 	}
2281 
2282 static void
cb_location_menu(GtkComboBox * om,gpointer data)2283 cb_location_menu(GtkComboBox *om, gpointer data)
2284 	{
2285 	GList		*list;
2286 	Sensor		*sr, *s;
2287 	gchar		*pname = NULL;
2288 	gint		location;
2289 
2290 	location = gtk_combo_box_get_active(om);
2291 	sr = get_referenced_sensor();
2292 	if (!sr || !sr->enabled || sr->location == location)
2293 		return;
2294 
2295 	/* If trying to relocate, get a dst panel name so can report failures.
2296 	*/
2297 	if (location != SENSOR_PANEL_LOCATION)
2298 		{
2299 		if (sr->group == SENSOR_GROUP_MAINBOARD)
2300 			pname = (location == PROC_PANEL_LOCATION)
2301 				? gkrellm_proc_get_sensor_panel_label()
2302 				: gkrellm_cpu_get_sensor_panel_label(
2303 							location - CPU_PANEL_LOCATION);
2304 		else if (sr->group == SENSOR_GROUP_DISK)
2305 			pname = _("Disk");
2306 		}
2307 
2308 	/* If moving off some other panel, reset that panel.
2309 	*/
2310 	sensor_reset_location(sr);
2311 
2312 	/* For mainboard sensor group, if relocating to a panel with some other
2313 	|  sensor of same type on it, auto restore the other sensor to the sensor
2314 	|  panel.  Disk sensor group should never conflict.
2315 	*/
2316 	sr->location = location;
2317 	if (   location != SENSOR_PANEL_LOCATION
2318 		&& sr->group == SENSOR_GROUP_MAINBOARD
2319 	   )
2320 		for (list = sensor_list; list; list = list->next)
2321 			{
2322 			s = (Sensor *) list->data;
2323 			if (   s->group == SENSOR_GROUP_MAINBOARD
2324 				&& s != sr
2325 				&& s->type == sr->type
2326 				&& s->location == sr->location
2327 			   )
2328 				s->location = SENSOR_PANEL_LOCATION;	/* is being replaced */
2329 			}
2330 	gkrellm_sensors_rebuild(DO_TEMP, DO_FAN, FALSE);
2331 
2332 	if (sr->location != location)	/* location failed */
2333 		{
2334 		gtk_combo_box_set_active(GTK_COMBO_BOX(optionmenu),
2335 					SENSOR_PANEL_LOCATION);
2336 		sensor_relocation_error(pname);
2337 		}
2338 	}
2339 
2340 
2341 static void
create_location_menu(gint group)2342 create_location_menu(gint group)
2343 	{
2344 	gchar		*label;
2345 	gint		n, n_cpus;
2346 
2347 	if (group == sensor_last_group)
2348 		return;
2349 	sensor_last_group = group;
2350 
2351 	gtk_combo_box_append_text(GTK_COMBO_BOX(optionmenu), "default");
2352 
2353 	if (group == SENSOR_GROUP_MAINBOARD)
2354 		{
2355 		label = gkrellm_proc_get_sensor_panel_label();
2356 		if (label)
2357 			gtk_combo_box_append_text(GTK_COMBO_BOX(optionmenu), label);
2358 
2359 		n_cpus = gkrellm_smp_cpus() + 1;
2360 		for (n = 0; n < n_cpus; ++n)
2361 			{
2362 			label = gkrellm_cpu_get_sensor_panel_label(n);
2363 			if (label)
2364 				gtk_combo_box_append_text(GTK_COMBO_BOX(optionmenu), label);
2365 			}
2366 		}
2367 	else if (group == SENSOR_GROUP_DISK)
2368 		{
2369 		gtk_combo_box_append_text(GTK_COMBO_BOX(optionmenu), _("Disk"));
2370 		}
2371 	g_signal_connect(G_OBJECT(optionmenu), "changed",
2372 				G_CALLBACK(cb_location_menu), NULL);
2373 	}
2374 
2375 static void
set_sensor_widget_states(Sensor * s)2376 set_sensor_widget_states(Sensor *s)
2377 	{
2378 	gboolean	f_sensitive = FALSE,
2379 				o_sensitive = FALSE,
2380 				p_sensitive = FALSE;
2381 	gfloat		factor = 1.0,
2382 				offset = 0.0;
2383 	gint		location = SENSOR_PANEL_LOCATION;
2384 
2385 	if (s && s->enabled)
2386 		{
2387 		f_sensitive = TRUE;
2388 		if (s->type != SENSOR_FAN)
2389 			{
2390 			o_sensitive = TRUE;
2391 			offset = s->offset;
2392 			}
2393 		factor = s->factor;
2394 		if (s->type != SENSOR_VOLTAGE)
2395 			{
2396 			location = s->location;
2397 			p_sensitive = TRUE;
2398 			}
2399 		}
2400 	create_location_menu(s ? s->group : 0);
2401 	gtk_combo_box_set_active(GTK_COMBO_BOX(optionmenu), location);
2402 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(factor_spin_button), factor);
2403 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(offset_spin_button), offset);
2404 	gtk_widget_set_sensitive(optionmenu, p_sensitive);
2405 	gtk_widget_set_sensitive(alert_button, f_sensitive);
2406 
2407 	if (s && s->default_factor == 0.0)
2408 		f_sensitive = o_sensitive = FALSE;
2409 
2410 	gtk_widget_set_sensitive(factor_spin_button, f_sensitive);
2411 	gtk_widget_set_sensitive(offset_spin_button, o_sensitive);
2412 	}
2413 
2414 static void
cb_correction_modified(void)2415 cb_correction_modified(void)
2416 	{
2417 	Sensor			*s;
2418 
2419 	s = get_referenced_sensor();
2420 	if (!s || !s->enabled)
2421 		return;
2422 	s->factor = gtk_spin_button_get_value(GTK_SPIN_BUTTON(factor_spin_button));
2423 	s->offset = gtk_spin_button_get_value(GTK_SPIN_BUTTON(offset_spin_button));
2424 
2425 	if (s->factor == 0)
2426 		{
2427 		s->factor = s->default_factor;
2428 		s->offset = s->default_offset;
2429 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(factor_spin_button),
2430 					s->factor);
2431 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(offset_spin_button),
2432 					s->offset);
2433 		}
2434 	if (s->type == SENSOR_VOLTAGE)
2435 		draw_voltages(s, FALSE);
2436 	else
2437 		{
2438 		gkrellm_cpu_draw_sensors(s);
2439 		gkrellm_proc_draw_sensors(s);
2440 		draw_temperatures(FALSE);
2441 		}
2442 	}
2443 
2444 static void
cb_tree_selection_changed(GtkTreeSelection * selection,gpointer data)2445 cb_tree_selection_changed(GtkTreeSelection *selection, gpointer data)
2446 	{
2447 	GtkTreeIter		iter;
2448 	GtkTreeModel	*model;
2449 	GtkTreePath		*path;
2450 	Sensor			*s;
2451 	gint            depth;
2452 
2453 	if (!gtk_tree_selection_get_selected(selection, &model, &iter))
2454 		{
2455 	    change_row_reference(NULL, NULL);
2456 		set_sensor_widget_states(NULL);
2457 		return;
2458 		}
2459 	path = gtk_tree_model_get_path(model, &iter);
2460 	depth = gtk_tree_path_get_depth(path);
2461     change_row_reference(model, path);
2462     gtk_tree_path_free(path);
2463 
2464 	if (depth == 1)
2465 		{
2466 		set_sensor_widget_states(NULL);
2467 		return;
2468 		}
2469 	s = get_referenced_sensor();
2470 	set_sensor_widget_states(s);
2471 	}
2472 
2473 static void
label_edited_cb(GtkCellRendererText * cell,gchar * path_string,gchar * new_label,gpointer data)2474 label_edited_cb(GtkCellRendererText *cell, gchar *path_string,
2475 			gchar *new_label, gpointer data)
2476 	{
2477 	GtkTreeModel	*model;
2478 	GtkTreeIter		iter;
2479 	GtkTreePath		*path;
2480 	Sensor			*s;
2481 
2482 	model = sensor_model;
2483 	path = gtk_tree_path_new_from_string(path_string);
2484 	gtk_tree_model_get_iter(model, &iter, path);
2485 	gtk_tree_path_free(path);
2486 
2487 	gtk_tree_model_get(model, &iter,
2488 				SENSOR_COLUMN, &s,
2489 				-1);
2490 	if (!*new_label)
2491 		new_label = s->default_label;
2492 
2493 	gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
2494 				LABEL_COLUMN, new_label, -1);
2495 
2496 	if (gkrellm_locale_dup_string(&s->name, new_label, &s->name_locale))
2497 		{
2498 		gkrellm_sensors_rebuild(s->type == SENSOR_TEMPERATURE,
2499 				s->type == SENSOR_FAN, s->type == SENSOR_VOLTAGE);
2500 		if (s->alert)
2501 			{
2502 			g_free(s->alert->name);
2503 			s->alert->name = g_strdup(s->name);
2504 //			gkrellm_reset_alert(s->alert);
2505 			}
2506 		}
2507 	}
2508 
2509 static void
enable_cb(GtkCellRendererText * cell,gchar * path_string,gpointer data)2510 enable_cb(GtkCellRendererText *cell, gchar *path_string, gpointer data)
2511 	{
2512 	GtkTreeModel	*model;
2513 	GtkTreeIter		iter;
2514 	GtkTreePath		*path;
2515 	Sensor			*s;
2516 	gboolean		enabled;
2517 
2518 	model = sensor_model;
2519 	path = gtk_tree_path_new_from_string(path_string);
2520 	gtk_tree_model_get_iter(model, &iter, path);
2521 
2522 	gtk_tree_model_get(model, &iter,
2523 				ENABLE_COLUMN, &enabled,
2524 				SENSOR_COLUMN, &s,
2525 				-1);
2526 	s->enabled = !enabled;
2527 	gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
2528 				ENABLE_COLUMN, s->enabled,
2529 				-1);
2530     change_row_reference(model, path);
2531 	gtk_tree_path_free(path);
2532 
2533 	gkrellm_sensors_rebuild(s->type == SENSOR_TEMPERATURE,
2534 				s->type == SENSOR_FAN, s->type == SENSOR_VOLTAGE);
2535 
2536 	set_sensor_widget_states(s);
2537 	}
2538 
2539 static void
fix_temp_alert(Sensor * s)2540 fix_temp_alert(Sensor *s)
2541 	{
2542 	GkrellmAlert	*a = s->alert;
2543 
2544 	if (s->type != SENSOR_TEMPERATURE || !a)
2545 		return;
2546 	if (units_fahrenheit)
2547 		{
2548 		if (a->high.warn_limit > 0)
2549 			a->high.warn_limit = a->high.warn_limit * 9.0 / 5.0 + 32.0;
2550 		if (a->high.alarm_limit > 0)
2551 			a->high.alarm_limit = a->high.alarm_limit * 9.0 / 5.0 + 32.0;
2552 		}
2553 	else
2554 		{
2555 		if (a->high.warn_limit > 0)
2556 			a->high.warn_limit = (a->high.warn_limit - 32.0) * 5.0 / 9.0;
2557 		if (a->high.alarm_limit > 0)
2558 			a->high.alarm_limit = (a->high.alarm_limit - 32.0) * 5.0 / 9.0;
2559 		}
2560 	gkrellm_alert_window_destroy(&s->alert);
2561 	}
2562 
2563 static void
sysdep_option_cb(GtkWidget * button,SysdepOption * so)2564 sysdep_option_cb(GtkWidget *button, SysdepOption *so)
2565 	{
2566 	if (!so)
2567 		return;
2568 	so->value = GTK_TOGGLE_BUTTON(button)->active;
2569 	}
2570 
2571 static void
cb_temperature_units(GtkWidget * button,gpointer data)2572 cb_temperature_units(GtkWidget *button, gpointer data)
2573 	{
2574 	GList	*list;
2575 	gint	units;
2576 
2577 	units = GTK_TOGGLE_BUTTON(button)->active;
2578 	if (units == units_fahrenheit)
2579 		return;
2580 	units_fahrenheit = units;
2581 
2582 	for (list = sensor_list; list; list = list->next)
2583 		fix_temp_alert((Sensor *) list->data);
2584 
2585 	gkrellm_sensors_rebuild(DO_TEMP, FALSE, FALSE);
2586 	gkrellm_cpu_draw_sensors(NULL);
2587 	gkrellm_proc_draw_sensors(NULL);
2588 	}
2589 
2590 static void
cb_show_units(GtkWidget * button,gpointer data)2591 cb_show_units(GtkWidget *button, gpointer data)
2592 	{
2593 	gint	show;
2594 
2595 	show = GTK_TOGGLE_BUTTON(button)->active;
2596 	if (show == show_units)
2597 		return;
2598 	show_units = show;
2599 
2600 	gkrellm_sensors_rebuild(DO_TEMP, FALSE, FALSE);
2601 	gkrellm_cpu_draw_sensors(NULL);
2602 	gkrellm_proc_draw_sensors(NULL);
2603 	}
2604 
2605 static void
cb_voltages_display(GtkWidget * entry,gpointer data)2606 cb_voltages_display(GtkWidget *entry, gpointer data)
2607 	{
2608 	gint	i;
2609 
2610 	for (i = 0; i < N_DISPLAY_MODES; ++i)
2611 		if (GTK_TOGGLE_BUTTON(display_mode_button[i])->active)
2612 			display_mode = i;
2613 	gkrellm_sensors_rebuild(FALSE, FALSE, DO_VOLT);
2614 	}
2615 
2616 static void
cb_set_alert(GtkWidget * widget,gpointer data)2617 cb_set_alert(GtkWidget *widget, gpointer data)
2618 	{
2619 	Sensor	*s;
2620 
2621 	s = get_referenced_sensor();
2622 	if (!s || !s->enabled)
2623 		return;
2624 	if (!s->alert)
2625 		create_sensor_alert(s);
2626 	gkrellm_alert_config_window(&s->alert);
2627 	}
2628 
2629 
2630 static void
sensors_apply(void)2631 sensors_apply(void)
2632 	{
2633 	gchar	*str;
2634 	gint	port;
2635 
2636 	if (mbmon_port_entry)
2637 		{
2638 		str = gkrellm_gtk_entry_get_text(&mbmon_port_entry);
2639 		if (isdigit((unsigned char)*str))
2640 			{
2641 			port = atoi(str);
2642 			if (_GK.mbmon_port != port)
2643 				{
2644 				if (!gkrellm_sys_sensors_mbmon_port_change(port) && port > 0)
2645 					gkrellm_message_dialog(NULL,
2646 				_("Can't read sensor data from mbmon daemon.\n"
2647 				  "Check mbmon port number and '-r' option.\n"
2648 				  "Run gkrellm -d 0x80 for debug output.\n"));
2649 				}
2650 			}
2651 		}
2652 	}
2653 
2654 static void
mbmon_port_entry_activate_cb(GtkWidget * widget,gpointer data)2655 mbmon_port_entry_activate_cb(GtkWidget *widget, gpointer data)
2656 	{
2657 	sensors_apply();
2658 	}
2659 
2660 static void
cb_config_deleted(gpointer data)2661 cb_config_deleted(gpointer data)
2662 	{
2663 	treeview = NULL;
2664 	}
2665 
2666 static gchar	*sensor_info_text0[] =
2667 	{
2668 	N_("<b>No sensors detected.\n"),
2669 	"\n",
2670 	};
2671 
2672 static gchar	*sensor_info_text1[] =
2673 	{
2674 N_("<h>Setup\n"),
2675 N_("Enter data scaling factors and offsets for the sensors if the default\n"
2676 "values are not correct for your motherboard.  Do a man gkrellm or\n"
2677 "see the GKrellM README for more information.\n"),
2678 N_("Enter a zero factor and a blank label to restore default values.\n"),
2679 "\n",
2680 N_("Drag and drop sensor rows to change the displayed order.\n"),
2681 "\n",
2682 N_("Temperature offset values must be in centigrade units.\n"),
2683 "\n",
2684 N_("If you use Pango markup for any custom labels, do not use double quotes.\n"),
2685 N_("For example, to set a colored CPU label, use single quotes:\n"),
2686 N_("    <span foreground='cyan'>CPU</span>\n"),
2687 "\n",
2688 N_("Substitution variables may be used in alert commands.\n"),
2689 N_("\t$s    current sensor value.\n"),
2690 N_("\t$l    sensor label.\n"),
2691 	};
2692 
2693 static void
sensors_tab_destroy(GtkWidget * w,gpointer data)2694 sensors_tab_destroy(GtkWidget *w, gpointer data)
2695 	{
2696 	optionmenu = NULL;
2697 	}
2698 
2699 static void
create_sensors_tab(GtkWidget * tab_vbox)2700 create_sensors_tab(GtkWidget *tab_vbox)
2701 	{
2702 	GtkWidget				*tabs;
2703 	GtkWidget				*button;
2704 	GtkWidget				*text;
2705 	GtkWidget				*vbox, *vbox1, *hbox, *box;
2706 	GtkWidget				*scrolled;
2707 	GtkWidget				*image;
2708 	GtkWidget				*label, *entry;
2709 	GtkTreeModel			*model;
2710 	GtkCellRenderer			*renderer;
2711 	GList					*list;
2712 	SysdepOption			*so;
2713 	gchar					buf[32];
2714 	gint					i;
2715 
2716 	row_reference = NULL;
2717 	sensor_last_group = -1;
2718 
2719 	tabs = gtk_notebook_new();
2720 	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(tabs), GTK_POS_TOP);
2721 	gtk_box_pack_start(GTK_BOX(tab_vbox), tabs, TRUE, TRUE, 0);
2722 
2723 	g_signal_connect(GTK_OBJECT(tabs), "destroy",
2724 				G_CALLBACK(sensors_tab_destroy), NULL);
2725 
2726 /* --Setup tab */
2727 	vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Setup"));
2728 	hbox = gtk_hbox_new(FALSE, 2);
2729 	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
2730 	vbox1 = gtk_vbox_new(FALSE, 0);
2731 	gtk_box_pack_end(GTK_BOX(hbox), vbox1, FALSE, FALSE, 5);
2732 
2733 	scrolled = gtk_scrolled_window_new(NULL, NULL);
2734 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2735 				GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2736 	gtk_box_pack_start(GTK_BOX(hbox), scrolled, TRUE, TRUE, 0);
2737 
2738 	model = create_model();
2739 	sensor_model = model;
2740 
2741 	treeview = GTK_TREE_VIEW(gtk_tree_view_new_with_model(model));
2742 	gtk_tree_view_set_rules_hint(treeview, TRUE);
2743 	gtk_tree_view_set_reorderable(treeview, TRUE);
2744 	g_signal_connect(G_OBJECT(treeview), "drag_begin",
2745 				G_CALLBACK(cb_drag_begin), NULL);
2746 	g_signal_connect(G_OBJECT(treeview), "drag_end",
2747 				G_CALLBACK(cb_drag_end), NULL);
2748 	g_signal_connect(G_OBJECT(treeview), "delete_event",
2749 				G_CALLBACK(cb_config_deleted), NULL);
2750 
2751 	renderer = gtk_cell_renderer_text_new();
2752 	gtk_tree_view_insert_column_with_attributes(treeview, -1, _("Sensor"),
2753 				renderer,
2754 				"text", NAME_COLUMN,
2755 				NULL);
2756 
2757 	renderer = gtk_cell_renderer_toggle_new();
2758 	gtk_tree_view_insert_column_with_attributes(treeview, -1, _("Enable"),
2759 				renderer,
2760 				"active", ENABLE_COLUMN,
2761 				"visible", VISIBLE_COLUMN,
2762 				NULL);
2763 	g_signal_connect(G_OBJECT(renderer), "toggled",
2764 				G_CALLBACK(enable_cb), NULL);
2765 
2766 	renderer = gtk_cell_renderer_text_new();
2767 	gtk_tree_view_insert_column_with_attributes(treeview, -1, _("Label"),
2768 				renderer,
2769 				"text", LABEL_COLUMN,
2770 				"editable", TRUE,
2771 				"visible", VISIBLE_COLUMN,
2772 				NULL);
2773 	g_signal_connect(G_OBJECT(renderer), "edited",
2774 				G_CALLBACK(label_edited_cb), NULL);
2775 
2776 	renderer = gtk_cell_renderer_pixbuf_new();
2777 	gtk_tree_view_insert_column_with_attributes(treeview, -1, "",
2778 				renderer,
2779 				"pixbuf", IMAGE_COLUMN,
2780 				NULL);
2781 
2782 
2783 	gtk_container_add(GTK_CONTAINER(scrolled), GTK_WIDGET(treeview));
2784 
2785 	selection = gtk_tree_view_get_selection(treeview);
2786 	gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
2787 	g_signal_connect(G_OBJECT(selection), "changed",
2788 				G_CALLBACK(cb_tree_selection_changed), NULL);
2789 
2790 	box = gkrellm_gtk_framed_vbox(vbox1, _("Factor"), 4, FALSE, 0, 2);
2791 	gkrellm_gtk_spin_button(box, &factor_spin_button, 1.0,
2792 				-1000.0, 1000.0, 0.01, 1.0, 4, 60,
2793 				cb_correction_modified, NULL, FALSE, NULL);
2794 
2795 	box = gkrellm_gtk_framed_vbox(vbox1, _("Offset"), 4, FALSE, 0, 2);
2796 	gkrellm_gtk_spin_button(box, &offset_spin_button, 0.0,
2797 				-10000.0, 10000.0, 1.0, 5.0, 3, 60,
2798 				cb_correction_modified, NULL, FALSE, NULL);
2799 
2800 	box = gkrellm_gtk_framed_vbox(vbox1, _("Location"), 2, FALSE, 0, 2);
2801 
2802 	optionmenu = gtk_combo_box_new_text();
2803 
2804 	gtk_box_pack_start(GTK_BOX(box), optionmenu, FALSE, FALSE, 4);
2805 
2806 	box = gtk_hbox_new(FALSE, 0);
2807 	gtk_container_set_border_width(GTK_CONTAINER(box), 2);
2808 	image = gtk_image_new_from_pixbuf(gkrellm_alert_pixbuf());
2809 	label = gtk_label_new(_("Alerts"));
2810 	gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 3);
2811 	gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 3);
2812 	alert_button = gtk_button_new();
2813 	g_signal_connect(G_OBJECT(alert_button), "clicked",
2814 				G_CALLBACK(cb_set_alert), NULL);
2815 	gtk_widget_show_all(box);
2816 	gtk_container_add(GTK_CONTAINER(alert_button), box);
2817 	gtk_box_pack_end(GTK_BOX(vbox1), alert_button, FALSE, FALSE, 4);
2818 
2819 //	gkrellm_gtk_button_connected(vbox1, &alert_button, FALSE, FALSE, -5,
2820 //				cb_set_alert, NULL, "Alerts");
2821 
2822 	set_sensor_widget_states(NULL);
2823 
2824 /* -- Options tab */
2825 	vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Options"));
2826 //	box = gkrellm_gtk_framed_vbox(vbox, _("Temperatures"), 4, FALSE, 0, 2);
2827 	box = gkrellm_gtk_category_vbox(vbox, _("Temperatures"), 4, 0, TRUE);
2828 	gkrellm_gtk_check_button_connected(box, &button,
2829 				units_fahrenheit, FALSE, FALSE, 0,
2830 				cb_temperature_units, NULL,
2831 				_("Display fahrenheit"));
2832 	gkrellm_gtk_check_button_connected(box, &button,
2833 				show_units, FALSE, FALSE, 0,
2834 				cb_show_units, NULL,
2835 				_("Show units"));
2836 	if (!sensor_list)
2837 		gtk_widget_set_sensitive(button, FALSE);
2838 
2839 //	box = gkrellm_gtk_framed_vbox(vbox, _("Voltages"), 6, FALSE, 0, 2);
2840 	box = gkrellm_gtk_category_vbox(vbox, _("Voltages"), 4, 0, TRUE);
2841 	button = gtk_radio_button_new_with_label(NULL,
2842 				_("Normal with labels"));
2843 	gtk_box_pack_start(GTK_BOX(box), button, FALSE, TRUE, 0);
2844 	display_mode_button[DIGITAL_WITH_LABELS] = button;
2845 	g_signal_connect(G_OBJECT(button), "toggled",
2846 				G_CALLBACK(cb_voltages_display), NULL);
2847 	if (!sensor_list)
2848 		gtk_widget_set_sensitive(button, FALSE);
2849 
2850 	button = gtk_radio_button_new_with_label(
2851 				gtk_radio_button_get_group(GTK_RADIO_BUTTON (button)),
2852 				_("Compact with no labels"));
2853 	gtk_box_pack_start(GTK_BOX(box), button, FALSE, TRUE, 0);
2854 	display_mode_button[DIGITAL_NO_LABELS] = button;
2855 	if (!sensor_list)
2856 		gtk_widget_set_sensitive(button, FALSE);
2857 
2858 	if (sysdep_option_list)
2859 		{
2860 		box = gkrellm_gtk_category_vbox(vbox, _("Options"), 4, 0, TRUE);
2861 		for (list = sysdep_option_list; list; list = list->next)
2862 			{
2863 			so= (SysdepOption *) list->data;
2864 			if (so->config_label)
2865 				gkrellm_gtk_check_button_connected(box, NULL,
2866 						so->value, FALSE, FALSE, 0,
2867 						sysdep_option_cb, so,
2868 						so->config_label);
2869 			}
2870 		}
2871 
2872 	button = display_mode_button[display_mode];
2873 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
2874 
2875 	if (gkrellm_sys_sensors_mbmon_supported())
2876 		{
2877 		box = gkrellm_gtk_category_vbox(vbox, _("MBmon Daemon Port"),
2878 					4, 0, TRUE);
2879 		label = gtk_label_new("");
2880 		gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
2881 		gtk_label_set_markup(GTK_LABEL(label),
2882 			_("<small>Daemon command must be: <b>mbmon -r -P port</b>\n"
2883 			 "where 'port' must match the port number entered here:</small>"));
2884 		gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
2885 		hbox = gtk_hbox_new(FALSE, 2);
2886 		gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 0);
2887 		entry = gtk_entry_new();
2888 		gtk_entry_set_max_length(GTK_ENTRY(entry), 6);
2889 		mbmon_port_entry = entry;
2890 		if (_GK.mbmon_port > 0)
2891 			{
2892 			snprintf(buf, sizeof(buf), "%d", _GK.mbmon_port);
2893 			gtk_entry_set_text(GTK_ENTRY(entry), buf);
2894 			}
2895 		gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 4);
2896 		label = gtk_label_new(
2897 			_("See the README or do a \"man gkrellm\" for more information.\n"));
2898 		gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
2899 		gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 4);
2900 
2901 		g_signal_connect(G_OBJECT(mbmon_port_entry), "activate",
2902 	                G_CALLBACK(mbmon_port_entry_activate_cb), NULL);
2903 		}
2904 
2905 /* --Info tab */
2906 	vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Info"));
2907 	text = gkrellm_gtk_scrolled_text_view(vbox, NULL,
2908 				GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2909 
2910 	if (!sensor_list)
2911 		for (i = 0; i < sizeof(sensor_info_text0) / sizeof(gchar *); ++i)
2912 			gkrellm_gtk_text_view_append(text, _(sensor_info_text0[i]));
2913 
2914 	for (i = 0; i < sizeof(sensor_info_text1) / sizeof(gchar *); ++i)
2915 		gkrellm_gtk_text_view_append(text, _(sensor_info_text1[i]));
2916 
2917 	/* Present as instant apply, but still get our apply function called.
2918 	*/
2919 	gkrellm_config_instant_apply(mon_config_sensors);
2920 	}
2921 
2922 GkrellmMonitor *
gkrellm_get_sensors_mon(void)2923 gkrellm_get_sensors_mon(void)
2924 	{
2925 	return mon_config_sensors;
2926 	}
2927 
2928 static GkrellmMonitor	monitor_config_sensors =
2929 	{
2930 	N_("Sensors"),		/* Name, for config tab.	*/
2931 	-1,					/* Id,  0 if a plugin		*/
2932 	NULL,				/* The create function		*/
2933 	NULL,				/* The update function		*/
2934 	create_sensors_tab,	/* The config tab create function	*/
2935 	sensors_apply,
2936 
2937 	save_sensors_config, /* Save user conifg			*/
2938 	load_sensors_config, /* Load user config			*/
2939 	SENSOR_CONFIG_KEYWORD,	/* config keyword			*/
2940 
2941 	NULL,				/* Undef 2	*/
2942 	NULL,				/* Undef 1	*/
2943 	NULL,				/* Undef 0	*/
2944 
2945 	0,					/* insert_before_id - place plugin before this mon */
2946 
2947 	NULL,				/* Handle if a plugin, filled in by GKrellM		*/
2948 	NULL				/* path if a plugin, filled in by GKrellM		*/
2949 	};
2950 
2951 GkrellmMonitor *
gkrellm_init_sensors_config_monitor(void)2952 gkrellm_init_sensors_config_monitor(void)
2953 	{
2954 	if (!setup_sensor_interface() && !_GK.demo)
2955 		return NULL;
2956 	if (!_GK.client_mode)
2957 		use_threads = TRUE;
2958 	sensor_list = g_list_sort(sensor_list, (GCompareFunc) strcmp_sensor_path);
2959     monitor_config_sensors.name = _(monitor_config_sensors.name);
2960 	mon_config_sensors = &monitor_config_sensors;
2961 	return &monitor_config_sensors;
2962 	}
2963 
2964