status icon
[psensor.git] / src / main.c
1 /*
2     Copyright (C) 2010-2011 jeanfi@gmail.com
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17     02110-1301 USA
18 */
19
20 #include <locale.h>
21
22 #include <getopt.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29
30 #include <gtk/gtk.h>
31
32 #include "config.h"
33
34 #include "cfg.h"
35 #include "psensor.h"
36 #include "graph.h"
37 #include "ui.h"
38 #include "ui_sensorlist.h"
39 #include "ui_color.h"
40 #include "lmsensor.h"
41 #include "ui_pref.h"
42 #include "ui_graph.h"
43
44 #ifdef HAVE_UNITY
45 #include "ui_unity.h"
46 #endif
47
48 #ifdef HAVE_NVIDIA
49 #include "nvidia.h"
50 #endif
51
52 #ifdef HAVE_LIBATIADL
53 #include "amd.h"
54 #endif
55
56 #ifdef HAVE_REMOTE_SUPPORT
57 #include "rsensor.h"
58 #endif
59
60 #if defined(HAVE_APPINDICATOR) || defined(HAVE_APPINDICATOR_029)
61 #include "ui_appindicator.h"
62 #else
63 #include "ui_status.h"
64 #endif
65
66 #ifdef HAVE_LIBNOTIFY
67 #include "ui_notify.h"
68 #endif
69
70 #ifdef HAVE_GTOP
71 #include "cpu.h"
72 #endif
73
74 #include "compat.h"
75
76 static const char *program_name;
77
78 static void print_version()
79 {
80         printf("psensor %s\n", VERSION);
81         printf(_("Copyright (C) %s jeanfi@gmail.com\n\
82 License GPLv2: GNU GPL version 2 or later \
83 <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>\n\
84 This is free software: you are free to change and redistribute it.\n\
85 There is NO WARRANTY, to the extent permitted by law.\n"),
86                "2010-2011");
87 }
88
89 static void print_help()
90 {
91         printf(_("Usage: %s [OPTION]...\n"), program_name);
92
93         puts(_("psensor is a GTK application for monitoring hardware sensors, "
94                "including temperatures and fan speeds."));
95
96         puts("");
97         puts(_("Options:"));
98         puts(_("\
99   -h, --help          display this help and exit\n\
100   -v, --version       display version information and exit"));
101
102         puts("");
103
104         puts(_("\
105   -u, --url=URL       \
106 the URL of the psensor-server, example: http://hostname:3131"));
107
108         puts("");
109
110         printf(_("Report bugs to: %s\n"), PACKAGE_BUGREPORT);
111         puts("");
112         printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
113 }
114
115 /*
116   Updates the size of the sensor values if different than the
117   configuration.
118  */
119 void
120 update_psensor_values_size(struct psensor **sensors, struct config *cfg)
121 {
122         struct psensor **cur;
123
124         cur = sensors;
125         while (*cur) {
126                 struct psensor *s = *cur;
127
128                 if (s->values_max_length != cfg->sensor_values_max_length)
129                         psensor_values_resize(s,
130                                               cfg->sensor_values_max_length);
131
132                 cur++;
133         }
134 }
135
136 static void log_measures(struct psensor **sensors)
137 {
138         if (log_level == LOG_DEBUG)
139                 while (*sensors) {
140                         log_printf(LOG_DEBUG, "%s %.2f",
141                                    (*sensors)->name,
142                                    psensor_get_current_value(*sensors));
143
144                         sensors++;
145                 }
146 }
147
148 void update_psensor_measures(struct ui_psensor *ui)
149 {
150         struct psensor **sensors = ui->sensors;
151         struct config *cfg = ui->config;
152
153         while (1) {
154                 g_mutex_lock(ui->sensors_mutex);
155
156                 if (!sensors)
157                         return;
158
159                 update_psensor_values_size(sensors, ui->config);
160
161                 psensor_list_update_measures(sensors);
162 #ifdef HAVE_REMOTE_SUPPORT
163                 remote_psensor_list_update(sensors);
164 #endif
165 #ifdef HAVE_NVIDIA
166                 nvidia_psensor_list_update(sensors);
167 #endif
168 #ifdef HAVE_LIBATIADL
169                 amd_psensor_list_update(sensors);
170 #endif
171
172                 log_measures(sensors);
173
174                 g_mutex_unlock(ui->sensors_mutex);
175
176                 sleep(cfg->sensor_update_interval);
177         }
178 }
179
180 gboolean ui_refresh_thread(gpointer data)
181 {
182         struct config *cfg;
183         gboolean ret;
184         struct ui_psensor *ui = (struct ui_psensor *)data;
185
186         ret = TRUE;
187         cfg = ui->config;
188
189         g_mutex_lock(ui->sensors_mutex);
190
191         graph_update(ui->sensors, ui->w_graph, ui->config);
192
193         ui_sensorlist_update(ui);
194
195 #if defined(HAVE_APPINDICATOR) || defined(HAVE_APPINDICATOR_029)
196         ui_appindicator_update(ui);
197 #endif
198
199 #ifdef HAVE_UNITY
200         ui_unity_launcher_entry_update(ui->sensors,
201                                        !cfg->unity_launcher_count_disabled);
202 #endif
203
204         if (ui->graph_update_interval != cfg->graph_update_interval) {
205                 ui->graph_update_interval = cfg->graph_update_interval;
206                 ret = FALSE;
207         }
208
209         g_mutex_unlock(ui->sensors_mutex);
210
211         if (ret == FALSE)
212                 g_timeout_add(1000 * ui->graph_update_interval,
213                               ui_refresh_thread, ui);
214
215         return ret;
216 }
217
218 void cb_alarm_raised(struct psensor *sensor, void *data)
219 {
220 #ifdef HAVE_LIBNOTIFY
221         if (sensor->enabled)
222                 ui_notify(sensor, (struct ui_psensor *)data);
223 #endif
224 }
225
226 static void associate_colors(struct psensor **sensors)
227 {
228         /* number of uniq colors */
229 #define COLORS_COUNT 8
230
231         unsigned int colors[COLORS_COUNT][3] = {
232                 {0x0000, 0x0000, 0x0000},       /* black */
233                 {0xffff, 0x0000, 0x0000},       /* red */
234                 {0x0000, 0.0000, 0xffff},       /* blue */
235                 {0x0000, 0xffff, 0x0000},       /* green */
236
237                 {0x7fff, 0x7fff, 0x7fff},       /* grey */
238                 {0x7fff, 0x0000, 0x0000},       /* dark red */
239                 {0x0000, 0x0000, 0x7fff},       /* dark blue */
240                 {0x0000, 0x7fff, 0x0000}        /* dark green */
241         };
242
243         struct psensor **sensor_cur = sensors;
244         int i = 0;
245         while (*sensor_cur) {
246                 struct color default_color;
247                 color_set(&default_color,
248                           colors[i % COLORS_COUNT][0],
249                           colors[i % COLORS_COUNT][1],
250                           colors[i % COLORS_COUNT][2]);
251
252                 (*sensor_cur)->color
253                     = config_get_sensor_color((*sensor_cur)->id,
254                                               &default_color);
255
256                 sensor_cur++;
257                 i++;
258         }
259 }
260
261 static void
262 associate_cb_alarm_raised(struct psensor **sensors, struct ui_psensor *ui)
263 {
264         struct psensor **sensor_cur = sensors;
265         while (*sensor_cur) {
266                 struct psensor *s = *sensor_cur;
267
268                 s->cb_alarm_raised = cb_alarm_raised;
269                 s->cb_alarm_raised_data = ui;
270
271                 if (is_temp_type(s->type)) {
272                         s->alarm_limit
273                             = config_get_sensor_alarm_limit(s->id, 60);
274                         s->alarm_enabled
275                             = config_get_sensor_alarm_enabled(s->id);
276                 } else {
277                         s->alarm_limit = 0;
278                         s->alarm_enabled = 0;
279                 }
280
281                 sensor_cur++;
282         }
283 }
284
285 static void associate_preferences(struct psensor **sensors)
286 {
287         struct psensor **sensor_cur = sensors;
288         while (*sensor_cur) {
289                 char *n;
290                 struct psensor *s = *sensor_cur;
291
292                 s->enabled = config_is_sensor_enabled(s->id);
293
294                 n = config_get_sensor_name(s->id);
295
296                 if (n)
297                         s->name = n;
298
299                 sensor_cur++;
300         }
301 }
302
303 static void log_init()
304 {
305         char *home, *path, *dir;
306
307         home = getenv("HOME");
308
309         if (!home)
310                 return ;
311
312         dir = malloc(strlen(home)+1+strlen(".psensor")+1);
313         sprintf(dir, "%s/%s", home, ".psensor");
314         mkdir(dir, 0777);
315
316         path = malloc(strlen(dir)+1+strlen("log")+1);
317         sprintf(path, "%s/%s", dir, "log");
318
319         log_open(path);
320
321         free(dir);
322         free(path);
323 }
324
325 static struct option long_options[] = {
326         {"version", no_argument, 0, 'v'},
327         {"help", no_argument, 0, 'h'},
328         {"url", required_argument, 0, 'u'},
329         {"debug", no_argument, 0, 'd'},
330         {0, 0, 0, 0}
331 };
332
333 int main(int argc, char **argv)
334 {
335         struct ui_psensor ui;
336         GError *error;
337         GThread *thread;
338         int optc;
339         char *url = NULL;
340         int cmdok = 1;
341
342         program_name = argv[0];
343
344         setlocale(LC_ALL, "");
345
346 #if ENABLE_NLS
347         bindtextdomain(PACKAGE, LOCALEDIR);
348         textdomain(PACKAGE);
349 #endif
350
351         while ((optc = getopt_long(argc, argv, "vhdu:", long_options,
352                                    NULL)) != -1) {
353                 switch (optc) {
354                 case 'u':
355                         if (optarg)
356                                 url = strdup(optarg);
357                         break;
358                 case 'h':
359                         print_help();
360                         exit(EXIT_SUCCESS);
361                 case 'v':
362                         print_version();
363                         exit(EXIT_SUCCESS);
364                 case 'd':
365                         printf(_("Enables debug mode.\n"));
366                         log_level = LOG_DEBUG;
367                         break;
368                 default:
369                         cmdok = 0;
370                         break;
371                 }
372         }
373
374         if (!cmdok || optind != argc) {
375                 fprintf(stderr, _("Try `%s --help' for more information.\n"),
376                         program_name);
377                 exit(EXIT_FAILURE);
378         }
379
380         log_init();
381
382         g_thread_init(NULL);
383         gdk_threads_init();
384         /* gdk_threads_enter(); */
385
386         gtk_init(NULL, NULL);
387
388 #ifdef HAVE_LIBNOTIFY
389         ui.notification_last_time = NULL;
390 #endif
391
392         ui.sensors_mutex = g_mutex_new();
393
394         config_init();
395
396         ui.config = config_load();
397
398         psensor_init();
399
400         if (url) {
401 #ifdef HAVE_REMOTE_SUPPORT
402                 rsensor_init();
403                 ui.sensors = get_remote_sensors(url, 600);
404 #else
405                 fprintf(stderr,
406                         _("ERROR: Not compiled with remote sensor support.\n"));
407                 exit(EXIT_FAILURE);
408 #endif
409         } else {
410                 ui.sensors = get_all_sensors(600);
411 #ifdef HAVE_NVIDIA
412                 ui.sensors = nvidia_psensor_list_add(ui.sensors, 600);
413 #endif
414 #ifdef HAVE_LIBATIADL
415                 ui.sensors = amd_psensor_list_add(ui.sensors, 600);
416 #endif
417 #ifdef HAVE_GTOP
418                 ui.sensors = cpu_psensor_list_add(ui.sensors, 600);
419 #endif
420         }
421
422         associate_preferences(ui.sensors);
423         associate_colors(ui.sensors);
424         associate_cb_alarm_raised(ui.sensors, &ui);
425
426         /* main window */
427         ui_window_create(&ui);
428         ui.sensor_box = NULL;
429
430         /* drawing box */
431         ui.w_graph = ui_graph_create(&ui);
432
433         /* sensor list */
434         ui_sensorlist_create(&ui);
435
436         ui_window_update(&ui);
437
438         thread = g_thread_create((GThreadFunc) update_psensor_measures,
439                                  &ui, TRUE, &error);
440
441         if (!thread)
442                 g_error_free(error);
443
444         ui.graph_update_interval = ui.config->graph_update_interval;
445
446         g_timeout_add(1000 * ui.graph_update_interval, ui_refresh_thread, &ui);
447
448 #if defined(HAVE_APPINDICATOR) || defined(HAVE_APPINDICATOR_029)
449         ui_appindicator_init(&ui);
450 #else
451         ui_status_create();
452 #endif
453
454         gdk_notify_startup_complete();
455
456         /* main loop */
457         gtk_main();
458
459         g_mutex_lock(ui.sensors_mutex);
460
461         psensor_cleanup();
462
463 #ifdef HAVE_NVIDIA
464         nvidia_cleanup();
465 #endif
466 #ifdef HAVE_LIBATIADL
467         amd_cleanup();
468 #endif
469 #ifdef HAVE_REMOTE_SUPPORT
470         rsensor_cleanup();
471 #endif
472
473         psensor_list_free(ui.sensors);
474         ui.sensors = NULL;
475
476         g_mutex_unlock(ui.sensors_mutex);
477
478         config_cleanup();
479
480         log_close();
481
482         return 0;
483 }