/* * Copyright (C) 2005-2009 Alex Murray * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /** Contain the functions for operating on the SensorsApplet structure * (represents the applet itself, and its associated variables. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #include #include #include #include "sensors-applet.h" #include "active-sensor.h" #include "sensors-applet-settings.h" #include "sensors-applet-plugins.h" #ifdef HAVE_LIBNOTIFY #include "active-sensor-libnotify.h" #define DEFAULT_NOTIFY_TIMEOUT 3000 #endif #include "prefs-dialog.h" #include "about-dialog.h" #define SENSORS_APPLET_MENU_FILE "SensorsApplet.xml" /* initially set as sensors_applet->size to ensure a real value is stored */ #define DEFAULT_APPLET_SIZE 24 #define COLUMN_SPACING 2 #define ROW_SPACING 1 /* builder for sensor sorting verification */ static GVariantBuilder gvb_sensors_hash_list; /* callbacks for panel menu */ static void prefs_cb(GtkAction *action, gpointer *data) { SensorsApplet *sensors_applet; sensors_applet = (SensorsApplet *)data; if (sensors_applet->prefs_dialog) { gtk_window_present(GTK_WINDOW(sensors_applet->prefs_dialog->dialog)); return; } prefs_dialog_open(sensors_applet); } static void about_cb(GtkAction *action, gpointer data) { SensorsApplet *sensors_applet; sensors_applet = (SensorsApplet *)data; about_dialog_open(sensors_applet); } static void help_cb(GtkAction *action, gpointer data) { GError *error = NULL; gtk_show_uri_on_window(NULL, "help:mate-sensors-applet", gtk_get_current_event_time(), &error); if (error) { g_debug("Could not open help document: %s ",error->message); g_error_free(error); } } static void destroy_cb(GtkWidget *widget, gpointer data) { SensorsApplet *sensors_applet; sensors_applet = (SensorsApplet *)data; /* destroy dialogs, remove timeout and clear sensors tree and finally the applet */ if (sensors_applet->prefs_dialog != NULL) { /* destroy's dialog too */ prefs_dialog_close(sensors_applet); } if (sensors_applet->timeout_id) { g_source_remove(sensors_applet->timeout_id); } if (sensors_applet->settings) { g_object_unref (sensors_applet->settings); sensors_applet->settings = NULL; } /* destroy all active sensors */ g_list_foreach(sensors_applet->active_sensors, (GFunc)active_sensor_destroy, NULL); if (sensors_applet->sensors != NULL) { gtk_tree_store_clear(sensors_applet->sensors); } gtk_widget_destroy(GTK_WIDGET(sensors_applet->applet)); g_free(sensors_applet); return; } static void change_orient_cb (MatePanelApplet *applet, MatePanelAppletOrient orient, gpointer data) { SensorsApplet *sensors_applet; sensors_applet = (SensorsApplet *)data; sensors_applet_display_layout_changed(sensors_applet); } static void size_allocate_cb(MatePanelApplet *applet, GtkAllocation *allocation, gpointer data) { SensorsApplet *sensors_applet; MatePanelAppletOrient orient; sensors_applet = (SensorsApplet *)data; orient = mate_panel_applet_get_orient(sensors_applet->applet); if ((orient == MATE_PANEL_APPLET_ORIENT_LEFT) || (orient == MATE_PANEL_APPLET_ORIENT_RIGHT)) { if (sensors_applet->size == allocation->width) return; sensors_applet->size = allocation->width; } else { if (sensors_applet->size == allocation->height) return; sensors_applet->size = allocation->height; } /* update if new value */ sensors_applet_graph_size_changed(sensors_applet); sensors_applet_display_layout_changed(sensors_applet); } static void style_set_cb(GtkWidget *widget, GtkStyle *old_style, gpointer data) { /* update all icons in the sensors tree and update all active sensors */ GtkTreeIter interfaces_iter, sensors_iter; GtkTreePath *path; gboolean not_end_of_interfaces = TRUE, not_end_of_sensors = TRUE; IconType icon_type; GdkPixbuf *new_icon; gboolean enabled; SensorsApplet *sensors_applet; DisplayMode display_mode; sensors_applet = (SensorsApplet *)data; display_mode = g_settings_get_int (sensors_applet->settings, DISPLAY_MODE); if (sensors_applet->sensors) { for (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(sensors_applet->sensors), &interfaces_iter); not_end_of_interfaces; not_end_of_interfaces = gtk_tree_model_iter_next(GTK_TREE_MODEL(sensors_applet->sensors), &interfaces_iter)) { /* reset sensors sentinel */ not_end_of_sensors = TRUE; for (gtk_tree_model_iter_children(GTK_TREE_MODEL(sensors_applet->sensors), &sensors_iter, &interfaces_iter); not_end_of_sensors; not_end_of_sensors = gtk_tree_model_iter_next(GTK_TREE_MODEL(sensors_applet->sensors), &sensors_iter)) { gtk_tree_model_get(GTK_TREE_MODEL(sensors_applet->sensors), &sensors_iter, ENABLE_COLUMN, &enabled, ICON_TYPE_COLUMN, &icon_type, -1); /* update icons */ new_icon = sensors_applet_load_icon(icon_type); gtk_tree_store_set(sensors_applet->sensors, &sensors_iter, ICON_PIXBUF_COLUMN, new_icon, -1); g_object_unref(new_icon); /* update icons only if currently being displayed */ if (enabled && (display_mode == DISPLAY_ICON || display_mode == DISPLAY_ICON_WITH_VALUE)) { path = gtk_tree_model_get_path(GTK_TREE_MODEL(sensors_applet->sensors), &sensors_iter); sensors_applet_icon_changed(sensors_applet, path); gtk_tree_path_free(path); } } } /* now update layout as size may have changed */ sensors_applet_display_layout_changed(sensors_applet); } } static gboolean mouse_enter_cb(GtkWidget *widget, GdkEventCrossing *event, gpointer data) { SensorsApplet *sensor_applet = data; sensor_applet->show_tooltip = TRUE; sensors_applet_update_active_sensors(sensor_applet); return TRUE; } static gboolean mouse_leave_cb(GtkWidget *widget, GdkEventCrossing *event, gpointer data) { SensorsApplet *sensor_applet = data; sensor_applet->show_tooltip = FALSE; return TRUE; } static const GtkActionEntry sensors_applet_menu_actions[] = { { "Preferences", "document-properties", N_("_Preferences"), NULL, NULL, G_CALLBACK(prefs_cb) }, { "Help", "help-browser", N_("_Help"), NULL, NULL, G_CALLBACK(help_cb) }, { "About", "help-about", N_("_About"), NULL, NULL, G_CALLBACK(about_cb) } }; #ifdef HAVE_LIBNOTIFY static void notif_closed_cb(NotifyNotification *notification, SensorsApplet *sensors_applet) { g_assert(sensors_applet); sensors_applet->notification = NULL; } #endif // HAVE_LIBNOTIFY void sensors_applet_notify_active_sensor(ActiveSensor *active_sensor, NotifType notif_type) { #ifdef HAVE_LIBNOTIFY SensorsApplet *sensors_applet; gchar *summary, *message; gint timeout_msecs; gchar *sensor_label; gchar *sensor_path; SensorType sensor_type; TemperatureScale temp_scale; GtkTreeIter iter; GtkTreePath *path; const gchar *unit_type = NULL; const gchar *unit_type_title = NULL; const gchar *relation = NULL; const gchar *limit_type = NULL; const gchar *units = NULL; gdouble limit_value; gdouble seconds; gboolean show_notification = TRUE; sensors_applet = active_sensor->sensors_applet; if (!g_settings_get_boolean (sensors_applet->settings, DISPLAY_NOTIFICATIONS)) { g_debug("Wanted to display notification, but user has disabled them"); return; } path = gtk_tree_row_reference_get_path(active_sensor->sensor_row); if (gtk_tree_model_get_iter(GTK_TREE_MODEL(sensors_applet->sensors), &iter, path)) { gtk_tree_model_get(GTK_TREE_MODEL(sensors_applet->sensors), &iter, LABEL_COLUMN, &sensor_label, PATH_COLUMN, &sensor_path, SENSOR_TYPE_COLUMN, &sensor_type, -1); } else { g_warning("Error getting data from tree for notification..."); gtk_tree_path_free(path); return; } gtk_tree_path_free(path); /* do different stuff for different notif types */ switch (notif_type) { case LOW_ALARM: /* fall thru */ case HIGH_ALARM: if (active_sensor->sensor_values[0] <= active_sensor->sensor_low_value && notif_type == LOW_ALARM) { relation = _("is very low"); limit_type = _("lower limit"); limit_value = active_sensor->sensor_low_value; } else if (active_sensor->sensor_values[0] >= active_sensor->sensor_high_value && notif_type == HIGH_ALARM) { /* assume high alarm condition */ relation = _("is very high"); limit_type = _("upper limit"); limit_value = active_sensor->sensor_high_value; } else { g_warning("Alarm notify called when no alarm condition!"); g_free(sensor_path); g_free(sensor_label); return; } switch ((SensorType)sensor_type) { case TEMP_SENSOR: unit_type_title = _("Temperature"); unit_type = _("temperature"); temp_scale = (TemperatureScale) g_settings_get_int (active_sensor->sensors_applet->settings, TEMPERATURE_SCALE); switch (temp_scale) { case CELSIUS: units = UNITS_CELSIUS; break; case FAHRENHEIT: units = UNITS_FAHRENHEIT; break; case KELVIN: units = UNITS_KELVIN; break; default: units = NULL; } break; case VOLTAGE_SENSOR: unit_type_title = _("Voltage"); unit_type = _("voltage"); units = UNITS_VOLTAGE; break; case FAN_SENSOR: unit_type_title = _("Fan Speed"); unit_type = _("fan speed"); units = UNITS_RPM; break; case CURRENT_SENSOR: unit_type_title = _("Current"); unit_type = _("current"); units = UNITS_CURRENT; break; } timeout_msecs = (active_sensor->alarm_timeout ? MIN(DEFAULT_NOTIFY_TIMEOUT, (active_sensor->alarm_timeout * 1000)) : DEFAULT_NOTIFY_TIMEOUT); summary = g_strdup_printf("%s %s %s", sensor_label, unit_type_title, _("Alarm")); message = g_strdup_printf("%s %s %s (%s %2.0f%s)", sensor_label, unit_type, relation, limit_type, limit_value, units); break; case SENSOR_INTERFACE_ERROR: /* get time since the last error */ seconds = difftime(time(NULL), active_sensor->ierror_ts); /* if the last error happened less than 10 seconds ago, don't display this one * this should prevent recurring popups for removed sensors, like USB-HDDs */ if (seconds < 11.0) { show_notification = FALSE; } summary = g_strdup_printf(_("Error updating sensor %s"), sensor_label); message = g_strdup_printf(_("An error occurred while trying to update the value of the sensor %s located at %s."), sensor_label, sensor_path); timeout_msecs = g_settings_get_int (active_sensor->sensors_applet->settings, TIMEOUT); /* update timestamp */ time(&(active_sensor->ierror_ts)); break; default: g_assert_not_reached(); } if (show_notification) { active_sensor_libnotify_notify(active_sensor, notif_type, summary, message, "dialog-warning", timeout_msecs); } g_free(sensor_path); g_free(sensor_label); g_free(summary); g_free(message); #endif } void sensors_applet_notify_end(ActiveSensor *active_sensor, NotifType notif_type) { #ifdef HAVE_LIBNOTIFY active_sensor_libnotify_notify_end(active_sensor, notif_type); #endif } #ifdef HAVE_LIBNOTIFY static void sensors_applet_notify_end_all_gfunc(ActiveSensor *active_sensor, gpointer data) { active_sensor_libnotify_notify_end(active_sensor, LOW_ALARM); active_sensor_libnotify_notify_end(active_sensor, HIGH_ALARM); } #endif void sensors_applet_notify_end_all(SensorsApplet *sensors_applet) { #ifdef HAVE_LIBNOTIFY g_list_foreach(sensors_applet->active_sensors, (GFunc)sensors_applet_notify_end_all_gfunc, NULL); #endif } /* internal helper functions for updating display etc */ /* should be called as a g_container_foreach at the start of * pack_display if the grid already exists to remove but keep alive * all children of the grid before repacking it */ static void sensors_applet_pack_display_empty_grid_cb(GtkWidget *widget, gpointer data) { GtkContainer *container; container = GTK_CONTAINER(data); /* ref then remove widget */ g_object_ref(widget); gtk_container_remove(container, widget); } /* should be called as a g_container_foreach at the end of * pack_display to unref any of the old children that we have readdded * to the table to stop reference creep from the g_object_ref called * on each child at the start of pack labels */ static void sensors_applet_pack_display_cleanup_refs_cb(GtkWidget *widget, gpointer data) { GList *old_children; old_children = (GList *)data; if (g_list_find(old_children, widget)) { g_object_unref(widget); } } static void sensors_applet_pack_display(SensorsApplet *sensors_applet) { /* note the if () around each widget is to ensure we only * operate on those that actually exist */ GtkLabel *no_sensors_enabled_label = NULL; gint num_active_sensors = 0, num_sensors_per_group, rows, cols, i, j; GList *old_grid_children = NULL; GList *current_sensor; DisplayMode display_mode; LayoutMode layout_mode; gboolean horizontal; gint label_width, icon_width, value_width; gint label_height, icon_height, value_height; GtkRequisition req; ActiveSensor *first_sensor; /* it is possible that there could be no active sensors so * handle that case first - make sure we dont do a NULL * pointer access first though */ if (sensors_applet->active_sensors == NULL || g_list_length(sensors_applet->active_sensors) == 0) { g_debug("no active sensors to pack in grid"); no_sensors_enabled_label = g_object_new(GTK_TYPE_LABEL, "label", _("No sensors enabled!"), NULL); if (sensors_applet->grid == NULL) { /* only need 1 row and 1 col */ sensors_applet->grid = gtk_grid_new(); gtk_grid_set_column_spacing(GTK_GRID(sensors_applet->grid), COLUMN_SPACING); gtk_grid_set_row_spacing(GTK_GRID(sensors_applet->grid), ROW_SPACING); gtk_widget_set_halign(sensors_applet->grid, GTK_ALIGN_CENTER); gtk_widget_set_valign(sensors_applet->grid, GTK_ALIGN_CENTER); /* add grid to applet */ gtk_container_add(GTK_CONTAINER(sensors_applet->applet), sensors_applet->grid); } else { /* destroy existing widgets - could be an * existing version of no sensors label - okay * to just add again though if destroy first */ g_debug("destroying any existing widgets in container"); gtk_container_foreach(GTK_CONTAINER(sensors_applet->grid), (GtkCallback)gtk_widget_destroy, NULL); } g_debug("packing no sensors enabled label"); gtk_grid_attach(GTK_GRID(sensors_applet->grid), GTK_WIDGET(no_sensors_enabled_label), 0, 0, 1, 1); gtk_widget_show_all(GTK_WIDGET(sensors_applet->applet)); return; } /* otherwise can acess active_sensors without any worries */ num_active_sensors = g_list_length(sensors_applet->active_sensors); display_mode = (DisplayMode) g_settings_get_int (sensors_applet->settings, DISPLAY_MODE); layout_mode = (LayoutMode) g_settings_get_int (sensors_applet->settings, LAYOUT_MODE); horizontal = (((mate_panel_applet_get_orient(sensors_applet->applet) == MATE_PANEL_APPLET_ORIENT_UP) || (mate_panel_applet_get_orient(sensors_applet->applet) == MATE_PANEL_APPLET_ORIENT_DOWN))); /* figure out num rows / cols by how high / wide sensors * labels / icons are and how much size we have to put them in */ /* get the first active sensor */ first_sensor = (ActiveSensor *)sensors_applet->active_sensors->data; switch (display_mode) { case DISPLAY_VALUE: gtk_widget_get_preferred_size(GTK_WIDGET(first_sensor->value), &req, NULL); value_width = req.width + COLUMN_SPACING; value_height = req.height + ROW_SPACING; /* make sure all widths and heights are non zero, * otherwise will get a divide by zero exception below * - is a non critical error since can happen when * elements first added to list, so simply return - is * not a programming error */ if (value_width == 0 && value_height == 0) { return; } num_sensors_per_group = (sensors_applet->size / (horizontal ? value_height : value_width)); break; case DISPLAY_LABEL_WITH_VALUE: /* even though we end up packing the event boxes into the * panel, these dont give back request sizes, so need to ask * widgets directly */ gtk_widget_get_preferred_size(GTK_WIDGET(first_sensor->value), &req, NULL); value_width = req.width + COLUMN_SPACING; value_height = req.height + ROW_SPACING; gtk_widget_get_preferred_size(GTK_WIDGET(first_sensor->label), &req, NULL); label_width = req.width + COLUMN_SPACING; label_height = req.height + ROW_SPACING; /* make sure all widths and heights are non zero, otherwise * will get a divide by zero exception below * - is a non critical error since can happen when * elements first added to list, so simply return - is * not a programming error */ if (!(label_width && label_height && value_width && value_height)) { return; } switch (layout_mode) { case VALUE_BESIDE_LABEL: num_sensors_per_group = (sensors_applet->size / (horizontal ? MAX(label_height, value_height) : (label_width + value_width))); break; case VALUE_BELOW_LABEL: num_sensors_per_group = (sensors_applet->size / (horizontal ? (label_height + value_height) : MAX(label_width, value_width))); break; } break; case DISPLAY_ICON_WITH_VALUE: gtk_widget_get_preferred_size(GTK_WIDGET(first_sensor->value), &req, NULL); value_width = req.width + COLUMN_SPACING; value_height = req.height + ROW_SPACING; gtk_widget_get_preferred_size(GTK_WIDGET(first_sensor->icon), &req, NULL); icon_width = req.width + COLUMN_SPACING; icon_height = req.height + ROW_SPACING; if (!(icon_width && icon_height && value_width && value_height)) { return; } switch (layout_mode) { case VALUE_BESIDE_LABEL: num_sensors_per_group = (sensors_applet->size / (horizontal ? MAX(icon_height, value_height) : (icon_width + value_width))); break; case VALUE_BELOW_LABEL: num_sensors_per_group = (sensors_applet->size / (horizontal ? (icon_height + value_height) : MAX(icon_width, value_width))); break; } break; case DISPLAY_ICON: gtk_widget_get_preferred_size(GTK_WIDGET(first_sensor->icon), &req, NULL); icon_width = req.width + COLUMN_SPACING; icon_height = req.height + ROW_SPACING; if (!(icon_width && icon_height)) { return; } num_sensors_per_group = (sensors_applet->size / (horizontal ? icon_height : icon_width)); break; case DISPLAY_GRAPH: /* only show graphs in a line like System Monitor applet */ num_sensors_per_group = 1; break; } /* ensure always atleast 1 sensor per group */ if (num_sensors_per_group < 1) { /* force a better layout */ if (horizontal && layout_mode == VALUE_BELOW_LABEL) { layout_mode = VALUE_BESIDE_LABEL; } else if (!horizontal && layout_mode == VALUE_BESIDE_LABEL) { layout_mode = VALUE_BELOW_LABEL; } num_sensors_per_group = 1; } if (horizontal) { /* if oriented horizontally, want as many sensors per column as user has defined, then enough columns to hold all the widgets */ rows = num_sensors_per_group; cols = num_active_sensors / num_sensors_per_group; while (rows * cols < num_active_sensors || cols == 0) { cols++; } } else { /* if oriented vertically, want as many sensors per row as user has defined, then enough rows to hold all the widgets*/ cols = num_sensors_per_group; rows = num_active_sensors / num_sensors_per_group; while (rows * cols < num_active_sensors || rows == 0) { rows++; } } /* if displaying labels / icons and values need to modify number of rows / colums to accomodate this */ if (display_mode == DISPLAY_LABEL_WITH_VALUE || display_mode == DISPLAY_ICON_WITH_VALUE) { if (layout_mode == VALUE_BESIDE_LABEL) { /* to display labels next to values need twice as many columns */ cols *= 2; } else { /* to display labels above values, we need twice as many rows as without */ rows *= 2; } } if (sensors_applet->grid == NULL) { /* create grid and add to applet */ sensors_applet->grid = gtk_grid_new(); gtk_grid_set_column_spacing(GTK_GRID(sensors_applet->grid), COLUMN_SPACING); gtk_grid_set_row_spacing(GTK_GRID(sensors_applet->grid), ROW_SPACING); gtk_widget_set_halign(sensors_applet->grid, GTK_ALIGN_CENTER); gtk_widget_set_valign(sensors_applet->grid, GTK_ALIGN_CENTER); gtk_container_add(GTK_CONTAINER(sensors_applet->applet), sensors_applet->grid); } else { /* remove all children if grid already exists so we can start again */ /* save a list of the old children for later */ old_grid_children = gtk_container_get_children(GTK_CONTAINER(sensors_applet->grid)); gtk_container_foreach(GTK_CONTAINER(sensors_applet->grid), sensors_applet_pack_display_empty_grid_cb, sensors_applet->grid); } /* pack icons / labels and values into grid */ current_sensor = sensors_applet->active_sensors; /* if showing labels / icons and values, need to pack labels / icons these first */ if (display_mode == DISPLAY_ICON_WITH_VALUE || display_mode == DISPLAY_LABEL_WITH_VALUE) { /* loop through columns */ for (i = 0; current_sensor != NULL && i < cols; /* increments depends on how we lay them out - see below */) { /* loop through rows in a column */ for (j = 0; current_sensor && j < rows; /* see bottom of for loop*/) { /* attach label / icon at this point */ if (display_mode == DISPLAY_ICON_WITH_VALUE) { if (((ActiveSensor *)(current_sensor->data))->icon) { gtk_grid_attach(GTK_GRID(sensors_applet->grid), ((ActiveSensor *)(current_sensor->data))->icon, i, j, 1, 1); } } else { if (((ActiveSensor *)(current_sensor->data))->label) { gtk_grid_attach(GTK_GRID(sensors_applet->grid), ((ActiveSensor *)(current_sensor->data))->label, i, j, 1, 1); } } /* now attach sensor value to either row below or column next to */ if (layout_mode == VALUE_BESIDE_LABEL) { /* left align labels */ if (((ActiveSensor *)(current_sensor->data))->icon) { gtk_widget_set_halign (((ActiveSensor *)(current_sensor->data))->icon, GTK_ALIGN_START); gtk_widget_set_valign (((ActiveSensor *)(current_sensor->data))->icon, GTK_ALIGN_CENTER); } if (((ActiveSensor *)(current_sensor->data))->label) { gtk_label_set_xalign (GTK_LABEL(((ActiveSensor *)(current_sensor->data))->label), 0); gtk_label_set_yalign (GTK_LABEL(((ActiveSensor *)(current_sensor->data))->label), 0.5); } if (((ActiveSensor *)(current_sensor->data))->value) { gtk_widget_set_halign (((ActiveSensor *)(current_sensor->data))->value, GTK_ALIGN_START); gtk_widget_set_valign (((ActiveSensor *)(current_sensor->data))->value, GTK_ALIGN_CENTER); } /* place value next to label */ if (((ActiveSensor *)(current_sensor->data))->value) { gtk_grid_attach(GTK_GRID(sensors_applet->grid), ((ActiveSensor *)(current_sensor->data))->value, i + 1, j, 1, 1); } j++; } else { /* place value below label */ /* center align labels */ if (((ActiveSensor *)(current_sensor->data))->icon) { gtk_widget_set_halign (((ActiveSensor *)(current_sensor->data))->icon, GTK_ALIGN_CENTER); gtk_widget_set_valign (((ActiveSensor *)(current_sensor->data))->icon, GTK_ALIGN_CENTER); } if (((ActiveSensor *)(current_sensor->data))->label) { gtk_label_set_xalign (GTK_LABEL(((ActiveSensor *)(current_sensor->data))->label), 0.5); gtk_label_set_yalign (GTK_LABEL(((ActiveSensor *)(current_sensor->data))->label), 0.5); } if (((ActiveSensor *)(current_sensor->data))->value) { gtk_widget_set_halign (((ActiveSensor *)(current_sensor->data))->value, GTK_ALIGN_CENTER); gtk_widget_set_valign (((ActiveSensor *)(current_sensor->data))->value, GTK_ALIGN_CENTER); } if (((ActiveSensor *)(current_sensor->data))->value) { gtk_grid_attach(GTK_GRID(sensors_applet->grid), ((ActiveSensor *)(current_sensor->data))->value, i, j + 1, 1, 1); } j += 2; } current_sensor = g_list_next(current_sensor); } /* end row loop */ /* now increment column index as needed */ if (layout_mode == VALUE_BESIDE_LABEL) { /* place value next to label */ i += 2; } else { i++; } } /* end column loop */ } else { /* not showing labels and icons with values, so just pack either only icons or values */ for (i = 0; current_sensor != NULL && i < cols; ++i) { for (j = 0; current_sensor!= NULL && j < rows; ++j) { if (display_mode == DISPLAY_VALUE) { if (((ActiveSensor *)(current_sensor->data))->value) { gtk_grid_attach(GTK_GRID(sensors_applet->grid), ((ActiveSensor *)(current_sensor->data))->value, i, j, 1, 1); } } else if (display_mode == DISPLAY_ICON) { if (((ActiveSensor *)(current_sensor->data))->value) { gtk_grid_attach(GTK_GRID(sensors_applet->grid), ((ActiveSensor *)(current_sensor->data))->icon, i, j, 1, 1); } } else if (display_mode == DISPLAY_GRAPH) { if (((ActiveSensor *)(current_sensor->data))->graph) { gtk_grid_attach(GTK_GRID(sensors_applet->grid), ((ActiveSensor *)(current_sensor->data))->graph_frame, i, j, 1, 1); } } current_sensor = g_list_next(current_sensor); } } } if (old_grid_children != NULL) { gtk_container_foreach(GTK_CONTAINER(sensors_applet->grid), sensors_applet_pack_display_cleanup_refs_cb, old_grid_children); g_list_free(old_grid_children); } gtk_widget_show_all(GTK_WIDGET(sensors_applet->applet)); } /* must unref when done with returned pixbuf */ GdkPixbuf *sensors_applet_load_icon(IconType icon_type) { GtkIconTheme *icon_theme; GdkPixbuf *icon = NULL; GError *error = NULL; /* try to load the icon */ /* not allowed to unref or ref icon_theme once we have it */ icon_theme = gtk_icon_theme_get_default(); icon = gtk_icon_theme_load_icon(icon_theme, stock_icons[icon_type], DEFAULT_ICON_SIZE, GTK_ICON_LOOKUP_USE_BUILTIN, &error); if (error) { g_warning ("Could not load icon: %s", error->message); g_error_free(error); error = NULL; /* try again with default icon */ icon = gtk_icon_theme_load_icon(icon_theme, "image-missing", DEFAULT_ICON_SIZE, GTK_ICON_LOOKUP_USE_BUILTIN, &error); if (error) { /* this will quit sensors-applet but it is a pretty major error so may as well */ g_error("Could not load GTK_STOCK_MISSING_IMAGE - major error!!!: %s", error->message); g_error_free(error); error = NULL; } } return icon; } // MUST FREE STRINGS AFTER CALLING THIS FUNCTION!! gboolean sensors_applet_add_sensor(SensorsApplet *sensors_applet, const gchar *path, const gchar *id, const gchar *label, const gchar *interface, SensorType type, gboolean enable, gdouble low_value, gdouble high_value, gboolean alarm_enable, const gchar *low_alarm_command, const gchar *high_alarm_command, gint alarm_timeout, gdouble multiplier, gdouble offset, IconType icon_type, const gchar *graph_color) { GtkTreeIter interfaces_iter, sensors_iter; gboolean not_empty_tree; gchar *node_interface; gboolean not_end_of_interfaces = TRUE, interface_exists = FALSE; gboolean not_end_of_sensors = TRUE; gchar *sensor_id; gchar *sensor_path; SensorType sensor_type; GdkPixbuf *icon; GtkTreePath *tree_path; g_assert(sensors_applet); /* assume tree is not empty */ not_empty_tree = TRUE; if (NULL == sensors_applet->sensors) { sensors_applet->sensors = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, /* path */ G_TYPE_STRING, /* id */ G_TYPE_STRING, /* label */ G_TYPE_STRING, /* interface */ G_TYPE_UINT, /* sensor type */ G_TYPE_BOOLEAN, /* enable */ G_TYPE_BOOLEAN, /* visible */ G_TYPE_DOUBLE, /* low value */ G_TYPE_DOUBLE, /* high type */ G_TYPE_BOOLEAN, /* alarm enable */ G_TYPE_STRING, /* low alarm command */ G_TYPE_STRING, /* high alarm command */ G_TYPE_UINT, /* alarm timeout */ G_TYPE_DOUBLE, /* multiplier */ G_TYPE_DOUBLE, /* offset */ G_TYPE_UINT, /* icon type */ GDK_TYPE_PIXBUF, /* icon pixbuf */ G_TYPE_STRING); /* graph color */ g_debug("Sensor tree created."); /* we know tree is actually empty since we just created it */ not_empty_tree = FALSE; } /* search sensor tree for the parent interface to place this sensor under */ for (not_empty_tree = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(sensors_applet->sensors), &interfaces_iter); not_empty_tree && not_end_of_interfaces && !interface_exists; not_end_of_interfaces = gtk_tree_model_iter_next(GTK_TREE_MODEL(sensors_applet->sensors), &interfaces_iter)) { gtk_tree_model_get(GTK_TREE_MODEL(sensors_applet->sensors), &interfaces_iter, INTERFACE_COLUMN, &node_interface, -1); if (g_ascii_strcasecmp(interface, node_interface) == 0) { /* found interface in tree */ interface_exists = TRUE; /* now see if this actual sensor already exists within this interface - don't want to add duplicates */ /* see if have children */ for (not_end_of_sensors = gtk_tree_model_iter_children(GTK_TREE_MODEL(sensors_applet->sensors), &sensors_iter, &interfaces_iter); not_end_of_sensors; not_end_of_sensors = gtk_tree_model_iter_next(GTK_TREE_MODEL(sensors_applet->sensors), &sensors_iter)) { gtk_tree_model_get(GTK_TREE_MODEL(sensors_applet->sensors), &sensors_iter, PATH_COLUMN, &sensor_path, ID_COLUMN, &sensor_id, SENSOR_TYPE_COLUMN, &sensor_type, -1); if (g_ascii_strcasecmp(sensor_id, id) == 0 && g_ascii_strcasecmp(sensor_path, path) == 0 && sensor_type == type) { /* sensor already exists so dont add a second time */ g_debug("sensor with path: %s, id: %s already exists in tree, not adding a second time", sensor_path, sensor_id); g_free(sensor_id); g_free(sensor_path); g_free(node_interface); return FALSE; } g_free(sensor_id); g_free(sensor_path); } g_free(node_interface); break; } g_free(node_interface); } if (!interface_exists) { /* add to required plugins hash table so we ensure this plugin stays loaded to make sure we have a get sensor value function if possible */ g_hash_table_insert(sensors_applet->required_plugins, g_strdup(interface), GINT_TO_POINTER(TRUE)); g_debug("added interface %s to required plugins", interface); /* wasn't able to find interface root node so create it */ gtk_tree_store_append(sensors_applet->sensors, &interfaces_iter, NULL); gtk_tree_store_set(sensors_applet->sensors, &interfaces_iter, ID_COLUMN, interface, INTERFACE_COLUMN, interface, VISIBLE_COLUMN, FALSE, -1); g_debug("Added sensor interface %s to tree", interface); } /* then add sensor as a child under interface node - ie assume * we either found it or created it - the inteface node that is */ /* for now just add sensors all in a single list */ gtk_tree_store_append(sensors_applet->sensors, &sensors_iter, &interfaces_iter); /* if sensor is already in settings, load values from there */ gchar *applet_path = mate_panel_applet_get_preferences_path (sensors_applet->applet); gchar *gsuid = sensors_applet_settings_get_unique_id (interface, id, path); gchar *settings_path = g_strdup_printf ("%s%s/", applet_path, gsuid); GSettings *settings = g_settings_new_with_path ("org.mate.sensors-applet.sensor", settings_path); /* add hash to temp sorting list */ g_variant_builder_add (&gvb_sensors_hash_list, "s", gsuid); g_free (applet_path); g_free (gsuid); g_free (settings_path); gchar *settings_id = g_settings_get_string (settings, ID); if (settings_id != NULL && settings_id[0] != '\0') { enable = g_settings_get_boolean (settings, ENABLED); icon = sensors_applet_load_icon(g_settings_get_int (settings, ICON_TYPE)); gtk_tree_store_set(sensors_applet->sensors, &sensors_iter, PATH_COLUMN, g_settings_get_string (settings, PATH), ID_COLUMN, settings_id, LABEL_COLUMN, g_settings_get_string (settings, LABEL), INTERFACE_COLUMN, g_settings_get_string (settings, INTERFACE), SENSOR_TYPE_COLUMN, g_settings_get_int (settings, SENSOR_TYPE), ENABLE_COLUMN, enable, VISIBLE_COLUMN, TRUE, LOW_VALUE_COLUMN, g_settings_get_double (settings, LOW_VALUE), HIGH_VALUE_COLUMN, g_settings_get_double (settings, HIGH_VALUE), ALARM_ENABLE_COLUMN, g_settings_get_boolean (settings, ALARM_ENABLED), ALARM_TIMEOUT_COLUMN, g_settings_get_int (settings, ALARM_TIMEOUT), LOW_ALARM_COMMAND_COLUMN, g_settings_get_string (settings, LOW_ALARM_COMMAND), HIGH_ALARM_COMMAND_COLUMN, g_settings_get_string (settings, HIGH_ALARM_COMMAND), MULTIPLIER_COLUMN, g_settings_get_double (settings, MULTIPLIER), OFFSET_COLUMN, g_settings_get_double (settings, OFFSET), ICON_TYPE_COLUMN, g_settings_get_int (settings, ICON_TYPE), ICON_PIXBUF_COLUMN, icon, GRAPH_COLOR_COLUMN, g_settings_get_string (settings, GRAPH_COLOR), -1); g_free (settings_id); } else { icon = sensors_applet_load_icon(icon_type); gtk_tree_store_set(sensors_applet->sensors, &sensors_iter, PATH_COLUMN, path, ID_COLUMN, id, LABEL_COLUMN, label, INTERFACE_COLUMN, interface, SENSOR_TYPE_COLUMN, type, ENABLE_COLUMN, enable, VISIBLE_COLUMN, TRUE, LOW_VALUE_COLUMN, low_value, HIGH_VALUE_COLUMN, high_value, ALARM_ENABLE_COLUMN, alarm_enable, ALARM_TIMEOUT_COLUMN, alarm_timeout, LOW_ALARM_COMMAND_COLUMN, low_alarm_command, HIGH_ALARM_COMMAND_COLUMN, high_alarm_command, MULTIPLIER_COLUMN, multiplier, OFFSET_COLUMN, offset, ICON_TYPE_COLUMN, icon_type, ICON_PIXBUF_COLUMN, icon, GRAPH_COLOR_COLUMN, graph_color, -1); } g_object_unref (settings); g_debug("added sensor %s to tree", path); /* remove reference to icon as tree now has ref */ g_object_unref(icon); /* create the active sensor */ if (enable) { tree_path = gtk_tree_model_get_path(GTK_TREE_MODEL(sensors_applet->sensors), &sensors_iter); sensors_applet_sensor_enabled(sensors_applet, tree_path); gtk_tree_path_free(tree_path); } return TRUE; } static ActiveSensor *sensors_applet_find_active_sensor(SensorsApplet *sensors_applet, GtkTreePath *path) { GtkTreePath *sensor_tree_path; GList *current_sensor; for (current_sensor = sensors_applet->active_sensors; current_sensor != NULL; current_sensor = g_list_next(current_sensor)) { sensor_tree_path = gtk_tree_row_reference_get_path(((ActiveSensor *)(current_sensor->data))->sensor_row); if (gtk_tree_path_compare(path, sensor_tree_path) == 0) { gtk_tree_path_free(sensor_tree_path); return ((ActiveSensor *)(current_sensor->data)); } gtk_tree_path_free(sensor_tree_path); } return NULL; } /* path should be the full path to a file representing the sensor (eg * /dev/hda or /sys/devices/platform/i2c-0/0-0290/temp1_input) */ void sensors_applet_display_layout_changed(SensorsApplet *sensors_applet) { /* update sensors since will need to update icons / graphs etc * if weren't displayed before */ GList *list = NULL; for (list = sensors_applet->active_sensors; list != NULL; list = list->next) { ActiveSensor *as = (ActiveSensor *)list->data; as->updated = FALSE; } sensors_applet_update_active_sensors(sensors_applet); sensors_applet_pack_display(sensors_applet); } void sensors_applet_alarm_off(SensorsApplet *sensors_applet, GtkTreePath *path, NotifType notif_type) { ActiveSensor *active_sensor; if ((active_sensor = sensors_applet_find_active_sensor(sensors_applet, path)) != NULL) { active_sensor_alarm_off(active_sensor, notif_type); } } void sensors_applet_all_alarms_off(SensorsApplet *sensors_applet, GtkTreePath *path) { sensors_applet_alarm_off(sensors_applet, path, LOW_ALARM); sensors_applet_alarm_off(sensors_applet, path, HIGH_ALARM); } void sensors_applet_sensor_enabled(SensorsApplet *sensors_applet, GtkTreePath *path) { ActiveSensor *active_sensor; g_assert(sensors_applet); g_assert(path); active_sensor = active_sensor_new(sensors_applet, gtk_tree_row_reference_new(GTK_TREE_MODEL(sensors_applet->sensors), path)); active_sensor_update(active_sensor, sensors_applet); /* keep list sorted */ sensors_applet->active_sensors = g_list_insert_sorted(sensors_applet->active_sensors, active_sensor, (GCompareFunc)active_sensor_compare); sensors_applet_pack_display(sensors_applet); } void sensors_applet_reorder_sensors(SensorsApplet *sensors_applet) { sensors_applet->active_sensors = g_list_sort(sensors_applet->active_sensors, (GCompareFunc)active_sensor_compare); sensors_applet_pack_display(sensors_applet); } void sensors_applet_sensor_disabled(SensorsApplet *sensors_applet, GtkTreePath *path) { ActiveSensor *active_sensor; g_assert(sensors_applet); g_assert(path); if ((active_sensor = sensors_applet_find_active_sensor(sensors_applet, path)) != NULL) { g_debug("Destroying active sensor..."); g_debug("-- removing from list..."); sensors_applet->active_sensors = g_list_remove(sensors_applet->active_sensors, active_sensor); g_debug("-- repacking display...."); sensors_applet_pack_display(sensors_applet); active_sensor_destroy(active_sensor); } } void sensors_applet_update_sensor(SensorsApplet *sensors_applet, GtkTreePath *path) { ActiveSensor *active_sensor; g_assert(sensors_applet); g_assert(path); if ((active_sensor = sensors_applet_find_active_sensor(sensors_applet, path)) != NULL) { active_sensor_update(active_sensor, sensors_applet); } } void sensors_applet_icon_changed(SensorsApplet *sensors_applet, GtkTreePath *path) { ActiveSensor *active_sensor; g_assert(sensors_applet); g_assert(path); if ((active_sensor = sensors_applet_find_active_sensor(sensors_applet, path)) != NULL) { active_sensor_icon_changed(active_sensor, sensors_applet); } } /* Cycle thru ActiveSensors and update them all */ gboolean sensors_applet_update_active_sensors(SensorsApplet *sensors_applet) { g_assert(sensors_applet); if (sensors_applet->active_sensors) { g_list_foreach(sensors_applet->active_sensors, (GFunc)active_sensor_update, sensors_applet); return TRUE; } return FALSE; } /* Cycle thru ActiveSensors and set new graph dimensions */ void sensors_applet_graph_size_changed(SensorsApplet *sensors_applet) { gint dimensions[2]; gint graph_size; g_assert(sensors_applet); if (sensors_applet->active_sensors) { graph_size = g_settings_get_int (sensors_applet->settings, GRAPH_SIZE); if (mate_panel_applet_get_orient(sensors_applet->applet) == MATE_PANEL_APPLET_ORIENT_UP || mate_panel_applet_get_orient(sensors_applet->applet) == MATE_PANEL_APPLET_ORIENT_DOWN) { /* is horizontal so set graph_size as width */ dimensions[0] = graph_size; dimensions[1] = sensors_applet->size; } else { dimensions[0] = sensors_applet->size; dimensions[1] = graph_size; } g_list_foreach(sensors_applet->active_sensors, (GFunc)active_sensor_update_graph_dimensions, &dimensions); } } gdouble sensors_applet_convert_temperature(gdouble value, TemperatureScale old, TemperatureScale new) { switch (old) { case KELVIN: switch (new) { case CELSIUS: value = value - 273.0; break; case FAHRENHEIT: value = (9.0 * (value - 273) / 5.0) + 32.0; break; case KELVIN: break; } break; case CELSIUS: switch (new) { case FAHRENHEIT: value = (9.0 * value / 5.0) + 32.0; break; case KELVIN: value = value + 273.0; break; case CELSIUS: break; } break; case FAHRENHEIT: switch (new) { case CELSIUS: value = (5.0 * (value - 32.0) / 9.0); break; case KELVIN: value = (5.0 * (value - 32.0) / 9.0) + 273.0; break; case FAHRENHEIT: break; } break; } return value; } void sensors_applet_init(SensorsApplet *sensors_applet) { g_assert(sensors_applet); g_assert(sensors_applet->applet); GtkActionGroup *action_group; gchar *ui_path; /* Have our background automatically painted. */ mate_panel_applet_set_background_widget(MATE_PANEL_APPLET(sensors_applet->applet), GTK_WIDGET(sensors_applet->applet)); /* plugin functions are stored as name -> get_value_function pairs so * use standard string functions on hash table */ sensors_applet->plugins = g_hash_table_new(g_str_hash, g_str_equal); sensors_applet->required_plugins = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); /* initialise size */ sensors_applet->size = DEFAULT_APPLET_SIZE; mate_panel_applet_set_flags(sensors_applet->applet, MATE_PANEL_APPLET_EXPAND_MINOR); g_signal_connect(sensors_applet->applet, "destroy", G_CALLBACK(destroy_cb), sensors_applet); /* init gsettings */ sensors_applet->settings = mate_panel_applet_settings_new (sensors_applet->applet, "org.mate.sensors-applet"); /* set up builder for sorting verification */ g_variant_builder_init (&gvb_sensors_hash_list, G_VARIANT_TYPE ("as")); /* set up / load sensors from the plugins */ sensors_applet_plugins_load_all(sensors_applet); /* set sorting hash array */ GVariant *gv_temp = g_variant_builder_end (&gvb_sensors_hash_list); sensors_applet->sensors_hash_array = g_variant_dup_strv (gv_temp, NULL); g_variant_unref (gv_temp); /* sort sensors based on saved sorting */ sensors_applet_settings_sort_sensors(sensors_applet); /* free hash array */ g_strfreev (sensors_applet->sensors_hash_array); /* should have created sensors tree above, but if have not was because we couldn't find any sensors */ if (NULL == sensors_applet->sensors) { GtkWidget *label; label = gtk_label_new(_("No sensors found!")); gtk_container_add(GTK_CONTAINER(sensors_applet->applet), label); gtk_widget_show_all(GTK_WIDGET(sensors_applet->applet)); return; } /* only do menu and signal connections if sensors are found */ action_group = gtk_action_group_new ("Sensors Applet Actions"); gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE); gtk_action_group_add_actions (action_group, sensors_applet_menu_actions, G_N_ELEMENTS (sensors_applet_menu_actions), sensors_applet); ui_path = g_build_filename (UIDIR, SENSORS_APPLET_MENU_FILE, NULL); mate_panel_applet_setup_menu_from_file (sensors_applet->applet, ui_path, action_group); g_free (ui_path); g_object_unref (action_group); g_signal_connect(sensors_applet->applet, "style-set", G_CALLBACK(style_set_cb), sensors_applet); g_signal_connect(G_OBJECT(sensors_applet->applet), "change_orient", G_CALLBACK(change_orient_cb), sensors_applet); g_signal_connect(G_OBJECT(sensors_applet->applet), "size_allocate", G_CALLBACK(size_allocate_cb), sensors_applet); g_signal_connect(G_OBJECT(sensors_applet->applet), "leave_notify_event", G_CALLBACK(mouse_leave_cb), (gpointer)sensors_applet); g_signal_connect(G_OBJECT(sensors_applet->applet), "enter_notify_event", G_CALLBACK(mouse_enter_cb), (gpointer)sensors_applet); sensors_applet_update_active_sensors(sensors_applet); sensors_applet_pack_display(sensors_applet); sensors_applet->timeout_id = g_timeout_add_seconds(g_settings_get_int(sensors_applet->settings, TIMEOUT) / 1000, (GSourceFunc)sensors_applet_update_active_sensors, sensors_applet); gtk_widget_show_all(GTK_WIDGET(sensors_applet->applet)); }