sensors list reorderable
[psensor.git] / src / ui_sensorpref.c
1 /*
2  * Copyright (C) 2010-2013 jeanfi@gmail.com
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * 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 #include <stdlib.h>
20
21 #include <gtk/gtk.h>
22
23 #include "cfg.h"
24 #include "ui_pref.h"
25 #include "ui_sensorlist.h"
26 #include "ui_sensorpref.h"
27 #include "ui_color.h"
28
29 #if defined(HAVE_APPINDICATOR) || defined(HAVE_APPINDICATOR_029)
30 #include "ui_appindicator.h"
31 #endif
32
33 enum {
34         COL_NAME = 0,
35         COL_SENSOR
36 };
37
38 struct sensor_pref {
39         struct psensor *sensor;
40         char *name;
41         int enabled;
42         struct color *color;
43         int alarm_enabled;
44         int alarm_high_threshold;
45         int alarm_low_threshold;
46         unsigned int appindicator_enabled;
47 };
48
49 struct cb_data {
50         struct ui_psensor *ui;
51         GtkBuilder *builder;
52 };
53
54 static struct sensor_pref *sensor_pref_new(struct psensor *s,
55                                            struct config *cfg)
56 {
57         struct sensor_pref *p;
58
59         p = malloc(sizeof(struct sensor_pref));
60
61         p->sensor = s;
62         p->name = strdup(s->name);
63         p->enabled = s->enabled;
64         p->alarm_enabled = s->alarm_enabled;
65         p->color = color_dup(s->color);
66
67         if (cfg->temperature_unit == CELCIUS) {
68                 p->alarm_high_threshold = s->alarm_high_threshold;
69                 p->alarm_low_threshold = s->alarm_low_threshold;
70         } else {
71                 p->alarm_high_threshold
72                         = celcius_to_fahrenheit(s->alarm_high_threshold);
73                 p->alarm_low_threshold
74                         = celcius_to_fahrenheit(s->alarm_low_threshold);
75         }
76
77         p->appindicator_enabled = s->appindicator_enabled;
78
79         return p;
80 }
81
82 static void sensor_pref_free(struct sensor_pref *p)
83 {
84         if (!p)
85                 return ;
86
87         free(p->name);
88         free(p->color);
89
90         free(p);
91 }
92
93 static struct sensor_pref *
94 get_selected_sensor_pref(GtkBuilder *builder)
95 {
96         GtkTreeModel *model;
97         GtkTreeIter iter;
98         struct sensor_pref *pref;
99         GtkTreeSelection *selection;
100         GtkTreeView *tree;
101
102         tree = GTK_TREE_VIEW(gtk_builder_get_object(builder, "sensors_list"));
103
104         selection = gtk_tree_view_get_selection(tree);
105
106         pref = NULL;
107         if (gtk_tree_selection_get_selected(selection, &model, &iter))
108                 gtk_tree_model_get(model, &iter, COL_SENSOR, &pref, -1);
109
110         return pref;
111 }
112
113 static void on_name_changed(GtkEntry *entry, gpointer data)
114 {
115         struct cb_data *cbdata = data;
116         struct sensor_pref *p;
117         const char *str;
118
119         str = gtk_entry_get_text(entry);
120
121         p = get_selected_sensor_pref(cbdata->builder);
122
123         if (p && strcmp(p->name, str)) {
124                 free(p->name);
125                 p->name = strdup(str);
126         }
127 }
128
129 static void
130 on_drawed_toggled(GtkToggleButton *btn, gpointer data)
131 {
132         struct cb_data *cbdata = data;
133         struct sensor_pref *p;
134
135         p = get_selected_sensor_pref(cbdata->builder);
136
137         if (p)
138                 p->enabled = gtk_toggle_button_get_active(btn);
139 }
140
141 static void
142 on_alarm_toggled(GtkToggleButton *btn, gpointer data)
143 {
144         struct cb_data *cbdata = data;
145         struct sensor_pref *p;
146
147         p = get_selected_sensor_pref(cbdata->builder);
148
149         if (p)
150                 p->alarm_enabled = gtk_toggle_button_get_active(btn);
151 }
152
153 static void
154 on_appindicator_toggled(GtkToggleButton *btn, gpointer data)
155 {
156         struct cb_data *cbdata = data;
157         struct sensor_pref *p;
158
159         p = get_selected_sensor_pref(cbdata->builder);
160
161         if (p)
162                 p->appindicator_enabled = gtk_toggle_button_get_active(btn);
163 }
164
165 static void on_color_set(GtkColorButton *widget, gpointer data)
166 {
167         struct cb_data *cbdata = data;
168         struct sensor_pref *p;
169         GdkColor color;
170
171         p = get_selected_sensor_pref(cbdata->builder);
172
173         if (p) {
174                 gtk_color_button_get_color(widget, &color);
175                 color_set(p->color, color.red, color.green, color.blue);
176         }
177 }
178
179 static void on_alarm_high_threshold_changed(GtkSpinButton *btn, gpointer data)
180 {
181         struct cb_data *cbdata;
182         struct sensor_pref *p;
183
184         cbdata = data;
185
186         p = get_selected_sensor_pref(cbdata->builder);
187
188         if (p)
189                 p->alarm_high_threshold = gtk_spin_button_get_value(btn);
190 }
191
192 static void on_alarm_low_threshold_changed(GtkSpinButton *btn, gpointer data)
193 {
194         struct cb_data *cbdata;
195         struct sensor_pref *p;
196
197         cbdata = data;
198
199         p = get_selected_sensor_pref(cbdata->builder);
200
201         if (p)
202                 p->alarm_low_threshold = gtk_spin_button_get_value(btn);
203 }
204
205 static void connect_signals(GtkBuilder *builder, struct cb_data *cbdata)
206 {
207         g_signal_connect(gtk_builder_get_object(builder, "sensor_name"),
208                          "changed", G_CALLBACK(on_name_changed), cbdata);
209
210         g_signal_connect(gtk_builder_get_object(builder, "sensor_draw"),
211                          "toggled", G_CALLBACK(on_drawed_toggled), cbdata);
212
213         g_signal_connect(gtk_builder_get_object(builder, "sensor_color"),
214                          "color-set", G_CALLBACK(on_color_set), cbdata);
215
216         g_signal_connect(gtk_builder_get_object(builder, "sensor_alarm"),
217                          "toggled", G_CALLBACK(on_alarm_toggled), cbdata);
218
219         g_signal_connect(gtk_builder_get_object(builder,
220                                                 "sensor_alarm_high_threshold"),
221                          "value-changed",
222                          G_CALLBACK(on_alarm_high_threshold_changed),
223                          cbdata);
224
225         g_signal_connect(gtk_builder_get_object(builder,
226                                                 "sensor_alarm_low_threshold"),
227                          "value-changed",
228                          G_CALLBACK(on_alarm_low_threshold_changed),
229                          cbdata);
230
231         g_signal_connect(gtk_builder_get_object(builder,
232                                                 "indicator_checkbox"),
233                          "toggled",
234                          G_CALLBACK(on_appindicator_toggled),
235                          cbdata);
236 }
237
238 static void
239 update_pref(struct sensor_pref *p, struct config *cfg, GtkBuilder *builder)
240 {
241         GtkLabel *w_id, *w_type, *w_high_threshold_unit, *w_low_threshold_unit,
242                 *w_chipname;
243         GtkEntry *w_name;
244         GtkToggleButton *w_draw, *w_alarm, *w_appindicator_enabled;
245         GtkColorButton *w_color;
246         GtkSpinButton *w_high_threshold, *w_low_threshold;
247         GdkColor *color;
248         struct psensor *s;
249         int use_celcius;
250
251         s = p->sensor;
252
253         w_id = GTK_LABEL(gtk_builder_get_object(builder, "sensor_id"));
254         gtk_label_set_text(w_id, s->id);
255
256         w_type = GTK_LABEL(gtk_builder_get_object(builder, "sensor_type"));
257         gtk_label_set_text(w_type, psensor_type_to_str(s->type));
258
259         w_name = GTK_ENTRY(gtk_builder_get_object(builder, "sensor_name"));
260         gtk_entry_set_text(w_name, p->name);
261
262         w_chipname = GTK_LABEL(gtk_builder_get_object(builder, "chip_name"));
263         if (s->chip)
264                 gtk_label_set_text(w_chipname, s->chip);
265         else
266                 gtk_label_set_text(w_chipname, _("Unknown"));
267
268         w_draw = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder,
269                                                           "sensor_draw"));
270         gtk_toggle_button_set_active(w_draw, p->enabled);
271
272         color = color_to_gdkcolor(p->color);
273         w_color = GTK_COLOR_BUTTON(gtk_builder_get_object(builder,
274                                                           "sensor_color"));
275         gtk_color_button_set_color(w_color, color);
276
277         w_alarm = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder,
278                                                            "sensor_alarm"));
279         w_high_threshold = GTK_SPIN_BUTTON(gtk_builder_get_object
280                                           (builder,
281                                            "sensor_alarm_high_threshold"));
282         w_low_threshold = GTK_SPIN_BUTTON(gtk_builder_get_object
283                                          (builder,
284                                           "sensor_alarm_low_threshold"));
285
286         w_high_threshold_unit = GTK_LABEL(gtk_builder_get_object
287                                          (builder,
288                                           "sensor_alarm_high_threshold_unit"));
289         w_low_threshold_unit = GTK_LABEL(gtk_builder_get_object
290                                         (builder,
291                                          "sensor_alarm_low_threshold_unit"));
292
293         use_celcius = cfg->temperature_unit == CELCIUS ? 1 : 0;
294         gtk_label_set_text(w_high_threshold_unit,
295                            psensor_type_to_unit_str(s->type,
296                                                     use_celcius));
297         gtk_label_set_text(w_low_threshold_unit,
298                            psensor_type_to_unit_str(s->type,
299                                                     use_celcius));
300
301         w_appindicator_enabled = GTK_TOGGLE_BUTTON
302                 (gtk_builder_get_object(builder, "indicator_checkbox"));
303
304         if (is_temp_type(s->type) || is_fan_type(s->type)) {
305                 gtk_toggle_button_set_active(w_alarm, p->alarm_enabled);
306                 gtk_spin_button_set_value(w_high_threshold,
307                                           p->alarm_high_threshold);
308                 gtk_spin_button_set_value(w_low_threshold,
309                                           p->alarm_low_threshold);
310                 gtk_widget_set_sensitive(GTK_WIDGET(w_alarm), TRUE);
311                 gtk_widget_set_sensitive(GTK_WIDGET(w_high_threshold), TRUE);
312                 gtk_widget_set_sensitive(GTK_WIDGET(w_low_threshold), TRUE);
313         } else {
314                 gtk_toggle_button_set_active(w_alarm, 0);
315                 gtk_spin_button_set_value(w_high_threshold, 0);
316                 gtk_spin_button_set_value(w_low_threshold, 0);
317                 gtk_widget_set_sensitive(GTK_WIDGET(w_alarm), FALSE);
318                 gtk_widget_set_sensitive(GTK_WIDGET(w_high_threshold), FALSE);
319                 gtk_widget_set_sensitive(GTK_WIDGET(w_low_threshold), FALSE);
320         }
321
322         gtk_toggle_button_set_active(w_appindicator_enabled,
323                                      p->appindicator_enabled);
324
325 }
326
327 static void on_changed(GtkTreeSelection *selection, gpointer data)
328 {
329         struct cb_data *cbdata = data;
330         struct ui_psensor *ui = cbdata->ui;
331         struct sensor_pref *p;
332
333         p = get_selected_sensor_pref(cbdata->builder);
334         update_pref(p, ui->config, cbdata->builder);
335 }
336
337 static void
338 select_sensor(struct psensor *s, struct psensor **sensors, GtkTreeView *tree)
339 {
340         struct psensor **s_cur = sensors;
341         int i = 0;
342         GtkTreePath *p = NULL;
343
344         while (*s_cur) {
345                 if (s == *s_cur) {
346                         p = gtk_tree_path_new_from_indices(i, -1);
347                         break;
348                 }
349
350                 i++;
351                 s_cur++;
352         }
353
354         if (p) {
355                 GtkTreeSelection *s = gtk_tree_view_get_selection(tree);
356
357                 gtk_tree_selection_select_path(s, p);
358                 gtk_tree_path_free(p);
359         }
360 }
361
362 static void apply_pref(struct sensor_pref *p, struct config *cfg)
363 {
364         struct psensor *s;
365
366         s = p->sensor;
367
368         if (strcmp(p->name, s->name)) {
369                 free(s->name);
370                 s->name = strdup(p->name);
371                 config_set_sensor_name(s->id, s->name);
372         }
373
374         if (s->enabled != p->enabled) {
375                 s->enabled = p->enabled;
376                 config_set_sensor_enabled(s->id, s->enabled);
377         }
378
379         if (is_temp_type(s->type)
380             && cfg->temperature_unit == FAHRENHEIT) {
381                 s->alarm_high_threshold
382                         = fahrenheit_to_celcius(p->alarm_high_threshold);
383                 s->alarm_low_threshold
384                         = fahrenheit_to_celcius(p->alarm_low_threshold);
385         } else {
386                 s->alarm_high_threshold = p->alarm_high_threshold;
387                 s->alarm_low_threshold = p->alarm_low_threshold;
388         }
389
390         config_set_sensor_alarm_high_threshold(s->id, s->alarm_high_threshold);
391         config_set_sensor_alarm_low_threshold(s->id, s->alarm_low_threshold);
392
393         if (s->alarm_enabled != p->alarm_enabled) {
394                 s->alarm_enabled = p->alarm_enabled;
395                 config_set_sensor_alarm_enabled(s->id, s->alarm_enabled);
396         }
397
398         color_set(s->color, p->color->red, p->color->green, p->color->blue);
399         config_set_sensor_color(s->id, s->color);
400
401         if (s->appindicator_enabled != p->appindicator_enabled) {
402                 s->appindicator_enabled = p->appindicator_enabled;
403                 config_set_appindicator_enabled(s->id, s->appindicator_enabled);
404         }
405 }
406
407 static void
408 apply_prefs(GtkTreeModel *model, struct config *cfg)
409 {
410         gboolean valid;
411         struct sensor_pref *spref;
412         GtkTreeIter iter;
413
414         valid = gtk_tree_model_get_iter_first(model, &iter);
415         while (valid) {
416                 gtk_tree_model_get(model, &iter, COL_SENSOR, &spref, -1);
417                 apply_pref(spref, cfg);
418                 valid = gtk_tree_model_iter_next(model, &iter);
419         }
420 }
421
422 void ui_sensorpref_dialog_run(struct psensor *sensor, struct ui_psensor *ui)
423 {
424         GtkDialog *diag;
425         gint result;
426         GtkBuilder *builder;
427         GError *error = NULL;
428         GtkTreeView *w_sensors_list;
429         guint ok;
430         GtkListStore *store;
431         struct psensor **s_cur, *s;
432         GtkTreeSelection *selection;
433         struct cb_data cbdata;
434         GtkTreeIter iter;
435         struct sensor_pref *spref;
436         gboolean valid;
437         GtkTreeModel *model;
438
439         cbdata.ui = ui;
440
441         builder = gtk_builder_new();
442         cbdata.builder = builder;
443
444         ok = gtk_builder_add_from_file
445                 (builder,
446                  PACKAGE_DATA_DIR G_DIR_SEPARATOR_S "sensor-edit.glade",
447                  &error);
448
449         if (!ok) {
450                 log_printf(LOG_ERR, error->message);
451                 g_error_free(error);
452                 return ;
453         }
454
455         connect_signals(builder, &cbdata);
456
457         w_sensors_list
458                 = GTK_TREE_VIEW(gtk_builder_get_object(builder,
459                                                        "sensors_list"));
460
461         store = GTK_LIST_STORE(gtk_builder_get_object(builder,
462                                                       "sensors_liststore"));
463
464         for (s_cur = ui->sensors; *s_cur; s_cur++) {
465                 s = *s_cur;
466                 gtk_list_store_append(store, &iter);
467
468                 spref = sensor_pref_new(s, ui->config);
469                 gtk_list_store_set(store, &iter,
470                                    COL_NAME, s->name,
471                                    COL_SENSOR, spref,
472                                    -1);
473
474                 if (s == sensor)
475                         update_pref(spref, ui->config, builder);
476         }
477
478         selection = gtk_tree_view_get_selection(w_sensors_list);
479         g_signal_connect(selection, "changed", G_CALLBACK(on_changed), &cbdata);
480         select_sensor(sensor, ui->sensors, w_sensors_list);
481
482         diag = GTK_DIALOG(gtk_builder_get_object(builder, "dialog1"));
483         result = gtk_dialog_run(diag);
484
485         model = gtk_tree_view_get_model(w_sensors_list);
486
487         if (result == GTK_RESPONSE_ACCEPT) {
488                 apply_prefs(model, ui->config);
489                 ui_sensorlist_update(ui, 1);
490 #if defined(HAVE_APPINDICATOR) || defined(HAVE_APPINDICATOR_029)
491                 ui_appindicator_update_menu(ui);
492 #endif
493         }
494
495         valid = gtk_tree_model_get_iter_first(model, &iter);
496         while (valid) {
497                 gtk_tree_model_get(model, &iter, COL_SENSOR, &spref, -1);
498                 sensor_pref_free(spref);
499                 valid = gtk_tree_model_iter_next(model, &iter);
500         }
501
502         g_object_unref(G_OBJECT(builder));
503
504         gtk_widget_destroy(GTK_WIDGET(diag));
505 }