Merging upstream version 0.5.9.
[debian/lxpanel.git] / src / plugins / thermal / thermal.c
CommitLineData
bfba7517
DB
1/**
2 * Thermal plugin to lxpanel
3 *
4 * Copyright (C) 2007 by Daniel Kesler <kesler.daniel@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
10862fa6
DB
21
22#include <sys/types.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <glib/gi18n.h>
26
27#include <string.h>
28
29#include "panel.h"
30#include "misc.h"
31#include "plugin.h"
32
33#include "dbg.h"
34
f8c25730
DB
35#define PROC_THERMAL_DIRECTORY "/proc/acpi/thermal_zone/" /* must be slash-terminated */
36#define PROC_THERMAL_TEMPF "temperature"
37#define PROC_THERMAL_TRIP "trip_points"
38#define PROC_TRIP_CRITICAL "critical (S5):"
10862fa6 39
f8c25730
DB
40#define SYSFS_THERMAL_DIRECTORY "/sys/class/thermal/" /* must be slash-terminated */
41#define SYSFS_THERMAL_SUBDIR_PREFIX "thermal_zone"
42#define SYSFS_THERMAL_TEMPF "temp"
43#define SYSFS_THERMAL_TRIP "trip_point_0_temp"
44
45
46typedef struct thermal {
1ea75322 47 Plugin * plugin;
10862fa6
DB
48 GtkWidget *main;
49 GtkWidget *namew;
50 GtkTooltips *tip;
51 int critical;
52 int warning1;
53 int warning2;
f8c25730 54 int not_custom_levels, auto_sensor;
10862fa6
DB
55 char *sensor,
56 *str_cl_normal,
57 *str_cl_warning1,
58 *str_cl_warning2;
59 unsigned int timer;
60 GdkColor cl_normal,
61 cl_warning1,
62 cl_warning2;
f8c25730
DB
63 gint (*get_temperature)(struct thermal *th);
64 gint (*get_critical)(struct thermal *th);
10862fa6
DB
65} thermal;
66
f8c25730 67
10862fa6 68static gint
f8c25730 69proc_get_critical(thermal *th){
10862fa6
DB
70 FILE *state;
71 char buf[ 256 ], sstmp [ 100 ];
72 char* pstr;
73
74 if(th->sensor == NULL) return -1;
75
f8c25730 76 sprintf(sstmp,"%s%s",th->sensor,PROC_THERMAL_TRIP);
10862fa6
DB
77
78 if (!(state = fopen( sstmp, "r"))) {
79 //printf("cannot open %s\n",sstmp);
80 return -1;
81 }
82
83 while( fgets(buf, 256, state) &&
f8c25730 84 ! ( pstr = strstr(buf, PROC_TRIP_CRITICAL) ) );
10862fa6
DB
85 if( pstr )
86 {
f8c25730 87 pstr += strlen(PROC_TRIP_CRITICAL);
10862fa6
DB
88 while( *pstr && *pstr == ' ' )
89 ++pstr;
90
91 pstr[strlen(pstr)-3] = '\0';
f8c25730 92 //printf("Critical: [%s]\n",pstr);
10862fa6
DB
93 fclose(state);
94 return atoi(pstr);
95 }
96
97 fclose(state);
98 return -1;
99}
100
101static gint
f8c25730 102proc_get_temperature(thermal *th){
10862fa6
DB
103 FILE *state;
104 char buf[ 256 ], sstmp [ 100 ];
105 char* pstr;
106
107 if(th->sensor == NULL) return -1;
108
f8c25730 109 sprintf(sstmp,"%s%s",th->sensor,PROC_THERMAL_TEMPF);
10862fa6
DB
110
111 if (!(state = fopen( sstmp, "r"))) {
112 //printf("cannot open %s\n",sstmp);
113 return -1;
114 }
115
116 while( fgets(buf, 256, state) &&
117 ! ( pstr = strstr(buf, "temperature:") ) );
118 if( pstr )
119 {
120 pstr += 12;
121 while( *pstr && *pstr == ' ' )
122 ++pstr;
123
124 pstr[strlen(pstr)-3] = '\0';
125 fclose(state);
126 return atoi(pstr);
127 }
128
129 fclose(state);
130 return -1;
131}
132
133static gint
f8c25730
DB
134sysfs_get_critical(thermal *th){
135 FILE *state;
136 char buf[ 256 ], sstmp [ 100 ];
137 char* pstr;
138
139 if(th->sensor == NULL) return -1;
140
141 sprintf(sstmp,"%s%s",th->sensor,SYSFS_THERMAL_TRIP);
142
143 if (!(state = fopen( sstmp, "r"))) {
144 //printf("cannot open %s\n",sstmp);
145 return -1;
146 }
147
148 while( fgets(buf, 256, state) &&
149 ! ( pstr = buf ) );
150 if( pstr )
151 {
152 fclose(state);
153 return atoi(pstr)/1000;
154 }
155
156 fclose(state);
157 return -1;
158}
159
160static gint
161sysfs_get_temperature(thermal *th){
162 FILE *state;
163 char buf[ 256 ], sstmp [ 100 ];
164 char* pstr;
165
166 if(th->sensor == NULL) return -1;
167
168 sprintf(sstmp,"%s%s",th->sensor,SYSFS_THERMAL_TEMPF);
169
170 if (!(state = fopen( sstmp, "r"))) {
171 //printf("cannot open %s\n",sstmp);
172 return -1;
173 }
174
175 while (fgets(buf, 256, state) &&
176 ! ( pstr = buf ) );
177 if( pstr )
178 {
179 fclose(state);
180 return atoi(pstr)/1000;
181 }
182
183 fclose(state);
184 return -1;
185}
186
187
188static void
189set_get_functions(thermal *th)
190{
191 if (th->sensor && strncmp(th->sensor, "/sys/", 5) == 0){
192 th->get_temperature = sysfs_get_temperature;
193 th->get_critical = sysfs_get_critical;
194 } else {
195 th->get_temperature = proc_get_temperature;
196 th->get_critical = proc_get_critical;
197 }
198}
199
200static gint
10862fa6
DB
201update_display(thermal *th)
202{
203 char buffer [60];
f8c25730 204 int temp = th->get_temperature(th);
10862fa6
DB
205 GdkColor color;
206
207 if(temp >= th->warning2)
208 color = th->cl_warning2;
209 else if(temp >= th->warning1)
210 color = th->cl_warning1;
211 else
212 color = th->cl_normal;
213
214 ENTER;
215 if(temp == -1)
1ea75322 216 panel_draw_label_text(th->plugin->panel, th->namew, "NA", TRUE, TRUE);
10862fa6 217 else
1ea75322 218 {
f8c25730 219 sprintf(buffer, "<span color=\"#%06x\"><b>%02d</b></span>", gcolor2rgb24(&color), temp);
1ea75322
DB
220 gtk_label_set_markup (GTK_LABEL(th->namew), buffer) ;
221 }
10862fa6 222
10862fa6
DB
223 RET(TRUE);
224}
225
f8c25730
DB
226
227/* get_sensor():
228 * - Get the sensor directory, and store it in '*sensor'.
229 * - It is searched for in 'directory'.
230 * - Only the subdirectories starting with 'subdir_prefix' are accepted as sensors.
231 * - 'subdir_prefix' may be NULL, in which case any subdir is considered a sensor. */
10862fa6 232static void
f8c25730 233get_sensor(char** sensor, char const* directory, char const* subdir_prefix)
10862fa6
DB
234{
235 GDir *sensorsDirectory;
236 const char *sensor_name;
237 char sensor_path[100];
238
f8c25730 239 if (! (sensorsDirectory = g_dir_open(directory, 0, NULL)))
10862fa6 240 {
f8c25730 241 *sensor = NULL;
10862fa6
DB
242 return;
243 }
244
245 /* Scan the thermal_zone directory for available sensors */
246 while ((sensor_name = g_dir_read_name(sensorsDirectory))) {
247 if (sensor_name[0] != '.') {
f8c25730
DB
248 if (subdir_prefix) {
249 if (strncmp(sensor_name, subdir_prefix, strlen(subdir_prefix)) != 0)
250 continue;
10862fa6 251 }
f8c25730
DB
252 sprintf(sensor_path,"%s%s/", directory, sensor_name);
253 if(*sensor) {
254 g_free(*sensor);
255 *sensor = NULL;
256 }
257 *sensor = strdup(sensor_path);
10862fa6
DB
258 break;
259 }
260 }
261 g_dir_close(sensorsDirectory);
262}
263
f8c25730
DB
264static void
265check_sensors( thermal *th )
266{
267 if(th->sensor) {
268 g_free(th->sensor);
269 th->sensor = NULL;
270 }
271
272 get_sensor(&th->sensor, PROC_THERMAL_DIRECTORY, NULL);
273
274 if (!th->sensor)
275 get_sensor(&th->sensor, SYSFS_THERMAL_DIRECTORY, SYSFS_THERMAL_SUBDIR_PREFIX);
276
277 //printf("thermal sensor: %s\n", th->sensor);
278}
279
280
281static void applyConfig(Plugin* p)
282{
283 thermal *th = p->priv;
284 ENTER;
285
286 if (th->str_cl_normal) gdk_color_parse(th->str_cl_normal, &th->cl_normal);
287 if (th->str_cl_warning1) gdk_color_parse(th->str_cl_warning1, &th->cl_warning1);
288 if (th->str_cl_warning2) gdk_color_parse(th->str_cl_warning2, &th->cl_warning2);
289
290 if(th->sensor == NULL) th->auto_sensor = TRUE;
291 if(th->auto_sensor) check_sensors(th);
292
293 set_get_functions(th);
294
295 th->critical = th->get_critical(th);
296
297 if(th->not_custom_levels){
298 th->warning1 = th->critical - 10;
299 th->warning2 = th->critical - 5;
300 }
301
302 RET();
303}
304
10862fa6
DB
305static int
306thermal_constructor(Plugin *p, char** fp)
307{
308 thermal *th;
10862fa6
DB
309
310 ENTER;
311 th = g_new0(thermal, 1);
1ea75322 312 th->plugin = p;
10862fa6
DB
313 p->priv = th;
314
315 p->pwid = gtk_event_box_new();
316 GTK_WIDGET_SET_FLAGS( p->pwid, GTK_NO_WINDOW );
317 gtk_container_set_border_width( GTK_CONTAINER(p->pwid), 2 );
318
319 th->namew = gtk_label_new("ww");
320 gtk_container_add(GTK_CONTAINER(p->pwid), th->namew);
321
bfba7517 322 th->main = p->pwid;
10862fa6
DB
323 th->tip = gtk_tooltips_new();
324
f8c25730
DB
325 /* By default, use automatic, that is, "not custom" temperature levels. If
326 * we were using custom levels, they would be 0°C at startup, so we would
327 * display in warning colors by default. */
328 th->not_custom_levels = TRUE;
329
10862fa6 330 g_signal_connect (G_OBJECT (p->pwid), "button_press_event",
1ea75322 331 G_CALLBACK (plugin_button_press_event), (gpointer) p);
10862fa6
DB
332
333 line s;
334 s.len = 256;
335
336 if (fp) {
337 /* Apply options */
338 while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END) {
339 if (s.type == LINE_NONE) {
340 ERR( "thermal: illegal token %s\n", s.str);
341 goto error;
342 }
343 if (s.type == LINE_VAR) {
344 if (!g_ascii_strcasecmp(s.t[0], "NormalColor")){
345 th->str_cl_normal = g_strdup(s.t[1]);
346 }else if (!g_ascii_strcasecmp(s.t[0], "Warning1Color")){
347 th->str_cl_warning1 = g_strdup(s.t[1]);
348 }else if (!g_ascii_strcasecmp(s.t[0], "Warning2Color")){
349 th->str_cl_warning2 = g_strdup(s.t[1]);
350 }else if (!g_ascii_strcasecmp(s.t[0], "AutomaticSensor")){
351 th->auto_sensor= atoi(s.t[1]);
352 }else if (!g_ascii_strcasecmp(s.t[0], "CustomLevels")){
f8c25730 353 th->not_custom_levels= atoi(s.t[1]);
10862fa6
DB
354 }else if (!g_ascii_strcasecmp(s.t[0], "Sensor")){
355 th->sensor= g_strdup(s.t[1]);
356 }else if (!g_ascii_strcasecmp(s.t[0], "Warning1Temp")){
357 th->warning1 = atoi(s.t[1]);
358 }else if (!g_ascii_strcasecmp(s.t[0], "Warning2Temp")){
359 th->warning2 = atoi(s.t[1]);
360 }else {
361 ERR( "thermal: unknown var %s\n", s.t[0]);
10862fa6
DB
362 }
363 }
364 else {
365 ERR( "thermal: illegal in this context %s\n", s.str);
366 goto error;
367 }
368 }
10862fa6
DB
369 }
370
371 if(!th->str_cl_normal)
372 th->str_cl_normal = g_strdup("#00ff00");
373 if(!th->str_cl_warning1)
374 th->str_cl_warning1 = g_strdup("#fff000");
375 if(!th->str_cl_warning2)
376 th->str_cl_warning2 = g_strdup("#ff0000");
377
f8c25730 378 applyConfig(p);
10862fa6 379
bfba7517
DB
380 gtk_widget_show(th->namew);
381
10862fa6
DB
382 update_display(th);
383 th->timer = g_timeout_add(1000, (GSourceFunc) update_display, (gpointer)th);
384
385 RET(TRUE);
386
387error:
10862fa6
DB
388 RET(FALSE);
389}
390
10862fa6
DB
391static void config(Plugin *p, GtkWindow* parent) {
392 ENTER;
393
394 GtkWidget *dialog;
395 thermal *th = (thermal *) p->priv;
396 dialog = create_generic_config_dlg(_(p->class->name),
397 GTK_WIDGET(parent),
398 (GSourceFunc) applyConfig, (gpointer) p,
399 _("Normal"), &th->str_cl_normal, CONF_TYPE_STR,
400 _("Warning1"), &th->str_cl_warning1, CONF_TYPE_STR,
401 _("Warning2"), &th->str_cl_warning2, CONF_TYPE_STR,
402 _("Automatic sensor location"), &th->auto_sensor, CONF_TYPE_BOOL,
403 _("Sensor"), &th->sensor, CONF_TYPE_STR,
f8c25730 404 _("Automatic temperature levels"), &th->not_custom_levels, CONF_TYPE_BOOL,
10862fa6
DB
405 _("Warning1 Temperature"), &th->warning1, CONF_TYPE_INT,
406 _("Warning2 Temperature"), &th->warning2, CONF_TYPE_INT,
407 NULL);
408 gtk_window_present(GTK_WINDOW(dialog));
409
410 RET();
411}
412
413static void
414thermal_destructor(Plugin *p)
415{
416 thermal *th = (thermal *)p->priv;
417
418 ENTER;
419 th = (thermal *) p->priv;
420 g_free(th->sensor);
421 g_free(th->str_cl_normal);
422 g_free(th->str_cl_warning1);
423 g_free(th->str_cl_warning2);
424 g_source_remove(th->timer);
425 g_free(th);
426 RET();
427}
428
429static void save_config( Plugin* p, FILE* fp )
430{
431 thermal *th = (thermal *)p->priv;
432
433 lxpanel_put_str( fp, "NormalColor", th->str_cl_normal );
434 lxpanel_put_str( fp, "Warning1Color", th->str_cl_warning1 );
435 lxpanel_put_str( fp, "Warning2Color", th->str_cl_warning2 );
f8c25730 436 lxpanel_put_int( fp, "CustomLevels", th->not_custom_levels );
10862fa6
DB
437 lxpanel_put_int( fp, "Warning1Temp", th->warning1 );
438 lxpanel_put_int( fp, "Warning2Temp", th->warning2 );
439 lxpanel_put_int( fp, "AutomaticSensor", th->auto_sensor );
440 lxpanel_put_str( fp, "Sensor", th->sensor );
441}
442
443PluginClass thermal_plugin_class = {
1ea75322
DB
444
445 PLUGINCLASS_VERSIONING,
10862fa6
DB
446
447 type : "thermal",
448 name : N_("Temperature Monitor"),
449 version: "0.6",
bfba7517 450 description : N_("Display system temperature"),
10862fa6
DB
451
452 constructor : thermal_constructor,
453 destructor : thermal_destructor,
454 config : config,
bfba7517
DB
455 save : save_config,
456 panel_configuration_changed : NULL
10862fa6 457};