/* * Copyright 2009, Intel Corporation * Copyright 2009, Sun Microsystems, Inc * * This file is part of PowerTOP * * This program file 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; version 2 of the License. * * 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 in a file named COPYING; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA * * Authors: * Arjan van de Ven * Eric C Saxe * Aubrey Li */ /* * GPL Disclaimer * * For the avoidance of doubt, except that if any license choice other * than GPL or LGPL is available it will apply instead, Sun elects to * use only the General Public License version 2 (GPLv2) at this time * for any software where a choice of GPL license versions is made * available with the language indicating that GPLv2 or any later * version may be used, or where a choice of which version of the GPL * is applied is otherwise unspecified. */ #include #include #include #include #include "powertop.h" /* * Default number of intervals we display a suggestion before moving * to the next. */ #define PT_SUGG_DEF_SLICE 3 /* * Global pointer to the current suggestion. */ sugg_t *g_curr_sugg; /* * Head of the list of suggestions. */ static sugg_t *sugg; /* * Add a new suggestion. Only one suggestion per text allowed. */ void pt_sugg_add(char *text, int weight, char key, char *sb_msg, sugg_func_t *func) { sugg_t *new, *n, *pos = NULL; /* * Text is a required field for suggestions */ if (text == NULL) return; if (sugg == NULL) { /* * Creating first element */ if ((new = calloc(1, sizeof (sugg_t))) == NULL) return; if (sb_msg != NULL) new->sb_msg = strdup(sb_msg); if (text != NULL) new->text = strdup(text); new->weight = weight; new->key = key; new->func = func; new->slice = 0; sugg = new; new->prev = NULL; new->next = NULL; } else { for (n = sugg; n != NULL; n = n->next) { if (strcmp(n->text, text) == 0) return; if (weight > n->weight && pos == NULL) pos = n; } /* * Create a new element */ if ((new = calloc(1, sizeof (sugg_t))) == NULL) return; if (sb_msg != NULL) new->sb_msg = strdup(sb_msg); new->text = strdup(text); new->weight = weight; new->key = key; new->func = func; new->slice = 0; if (pos == NULL) { /* * Ordering placed the new element at the end */ for (n = sugg; n->next != NULL; n = n->next) ; n->next = new; new->prev = n; new->next = NULL; } else { if (pos == sugg) { /* * Ordering placed the new element at the start */ new->next = sugg; new->prev = sugg; sugg->prev = new; sugg = new; } else { /* * Ordering placed the new element somewhere in * the middle */ new->next = pos; new->prev = pos->prev; pos->prev->next = new; pos->prev = new; } } } } /* * Removes a suggestion, returning 0 if not found and 1 if so. */ int pt_sugg_remove(sugg_func_t *func) { sugg_t *n; int ret = 0; for (n = sugg; n != NULL; n = n->next) { if (n->func == func) { /* Removing the first element */ if (n == sugg) { if (sugg->next == NULL) { /* Removing the only element */ sugg = NULL; } else { sugg = n->next; sugg->prev = NULL; } } else { if (n->next == NULL) { /* Removing the last element */ n->prev->next = NULL; } else { /* Removing an intermediate element */ n->prev->next = n->next; n->next->prev = n->prev; } } /* * If this suggestions is currently being suggested, * remove it and update the screen. */ if (n == g_curr_sugg) { if (n->sb_msg != NULL) { pt_display_mod_status_bar(n->sb_msg); pt_display_status_bar(); } if (n->text != NULL) pt_display_suggestions(NULL); } free(n); ret = 1; } } return (ret); } /* * Chose a suggestion to display. The list of suggestions is ordered by weight, * so we only worry about fariness here. Each suggestion, starting with the * first (the 'heaviest') is displayed during PT_SUGG_DEF_SLICE intervals. */ void pt_sugg_pick(void) { sugg_t *n; if (sugg == NULL) { g_curr_sugg = NULL; return; } search: for (n = sugg; n != NULL; n = n->next) { if (n->slice++ < PT_SUGG_DEF_SLICE) { /* * Don't need to re-suggest the current suggestion. */ if (g_curr_sugg == n) return; /* * Remove the current suggestion from screen. */ if (g_curr_sugg != NULL) { if (g_curr_sugg->sb_msg != NULL) { pt_display_mod_status_bar( g_curr_sugg->sb_msg); pt_display_status_bar(); } if (g_curr_sugg->text != NULL) pt_display_suggestions(NULL); } if (n->sb_msg != NULL) { pt_display_mod_status_bar(n->sb_msg); pt_display_status_bar(); } pt_display_suggestions(n->text); g_curr_sugg = n; return; } } /* * All suggestions have run out of slice quotas, so we restart. */ for (n = sugg; n != NULL; n = n->next) n->slice = 0; goto search; } void pt_sugg_as_root(void) { pt_sugg_add("Suggestion: run as root to get suggestions" " for reducing system power consumption", 40, NULL, NULL, NULL); }