1 /* 2 * Copyright 2009, Intel Corporation 3 * Copyright 2009, Sun Microsystems, Inc 4 * 5 * This file is part of PowerTOP 6 * 7 * This program file is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the 9 * Free Software Foundation; version 2 of the License. 10 * 11 * This program is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program in a file named COPYING; if not, write to the 18 * Free Software Foundation, Inc., 19 * 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301 USA 21 * 22 * Authors: 23 * Arjan van de Ven <arjan@linux.intel.com> 24 * Eric C Saxe <eric.saxe@sun.com> 25 * Aubrey Li <aubrey.li@intel.com> 26 */ 27 28 /* 29 * GPL Disclaimer 30 * 31 * For the avoidance of doubt, except that if any license choice other 32 * than GPL or LGPL is available it will apply instead, Sun elects to 33 * use only the General Public License version 2 (GPLv2) at this time 34 * for any software where a choice of GPL license versions is made 35 * available with the language indicating that GPLv2 or any later 36 * version may be used, or where a choice of which version of the GPL 37 * is applied is otherwise unspecified. 38 */ 39 40 #include <unistd.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include "powertop.h" 45 46 /* 47 * Default number of intervals we display a suggestion before moving 48 * to the next. 49 */ 50 #define PT_SUGG_DEF_SLICE 3 51 52 /* 53 * Global pointer to the current suggestion. 54 */ 55 sugg_t *g_curr_sugg; 56 57 /* 58 * Head of the list of suggestions. 59 */ 60 static sugg_t *sugg; 61 62 /* 63 * Add a new suggestion. Only one suggestion per text allowed. 64 */ 65 void 66 pt_sugg_add(char *text, int weight, char key, char *sb_msg, sugg_func_t *func) 67 { 68 sugg_t *new, *n, *pos = NULL; 69 70 /* 71 * Text is a required field for suggestions 72 */ 73 if (text == NULL) 74 return; 75 76 if (sugg == NULL) { 77 /* 78 * Creating first element 79 */ 80 if ((new = calloc(1, sizeof (sugg_t))) == NULL) 81 return; 82 83 if (sb_msg != NULL) 84 new->sb_msg = strdup(sb_msg); 85 86 if (text != NULL) 87 new->text = strdup(text); 88 89 new->weight = weight; 90 new->key = key; 91 new->func = func; 92 new->slice = 0; 93 94 sugg = new; 95 new->prev = NULL; 96 new->next = NULL; 97 } else { 98 for (n = sugg; n != NULL; n = n->next) { 99 if (strcmp(n->text, text) == 0) 100 return; 101 102 if (weight > n->weight && pos == NULL) 103 pos = n; 104 } 105 /* 106 * Create a new element 107 */ 108 if ((new = calloc(1, sizeof (sugg_t))) == NULL) 109 return; 110 111 if (sb_msg != NULL) 112 new->sb_msg = strdup(sb_msg); 113 114 new->text = strdup(text); 115 116 new->weight = weight; 117 new->key = key; 118 new->func = func; 119 new->slice = 0; 120 121 if (pos == NULL) { 122 /* 123 * Ordering placed the new element at the end 124 */ 125 for (n = sugg; n->next != NULL; n = n->next) 126 ; 127 128 n->next = new; 129 new->prev = n; 130 new->next = NULL; 131 } else { 132 if (pos == sugg) { 133 /* 134 * Ordering placed the new element at the start 135 */ 136 new->next = sugg; 137 new->prev = sugg; 138 sugg->prev = new; 139 sugg = new; 140 } else { 141 /* 142 * Ordering placed the new element somewhere in 143 * the middle 144 */ 145 new->next = pos; 146 new->prev = pos->prev; 147 pos->prev->next = new; 148 pos->prev = new; 149 } 150 } 151 } 152 } 153 154 /* 155 * Removes a suggestion, returning 0 if not found and 1 if so. 156 */ 157 int 158 pt_sugg_remove(sugg_func_t *func) 159 { 160 sugg_t *n; 161 int ret = 0; 162 163 for (n = sugg; n != NULL; n = n->next) { 164 if (n->func == func) { 165 /* Removing the first element */ 166 if (n == sugg) { 167 if (sugg->next == NULL) { 168 /* Removing the only element */ 169 sugg = NULL; 170 } else { 171 sugg = n->next; 172 sugg->prev = NULL; 173 } 174 } else { 175 if (n->next == NULL) { 176 /* Removing the last element */ 177 n->prev->next = NULL; 178 } else { 179 /* Removing an intermediate element */ 180 n->prev->next = n->next; 181 n->next->prev = n->prev; 182 } 183 } 184 185 /* 186 * If this suggestions is currently being suggested, 187 * remove it and update the screen. 188 */ 189 if (n == g_curr_sugg) { 190 if (n->sb_msg != NULL) { 191 pt_display_mod_status_bar(n->sb_msg); 192 pt_display_status_bar(); 193 } 194 if (n->text != NULL) 195 pt_display_suggestions(NULL); 196 } 197 198 free(n); 199 ret = 1; 200 } 201 } 202 203 return (ret); 204 } 205 206 /* 207 * Chose a suggestion to display. The list of suggestions is ordered by weight, 208 * so we only worry about fariness here. Each suggestion, starting with the 209 * first (the 'heaviest') is displayed during PT_SUGG_DEF_SLICE intervals. 210 */ 211 void 212 pt_sugg_pick(void) 213 { 214 sugg_t *n; 215 216 if (sugg == NULL) { 217 g_curr_sugg = NULL; 218 return; 219 } 220 221 search: 222 for (n = sugg; n != NULL; n = n->next) { 223 224 if (n->slice++ < PT_SUGG_DEF_SLICE) { 225 226 /* 227 * Don't need to re-suggest the current suggestion. 228 */ 229 if (g_curr_sugg == n) 230 return; 231 232 /* 233 * Remove the current suggestion from screen. 234 */ 235 if (g_curr_sugg != NULL) { 236 if (g_curr_sugg->sb_msg != NULL) { 237 pt_display_mod_status_bar( 238 g_curr_sugg->sb_msg); 239 pt_display_status_bar(); 240 } 241 if (g_curr_sugg->text != NULL) 242 pt_display_suggestions(NULL); 243 } 244 245 if (n->sb_msg != NULL) { 246 pt_display_mod_status_bar(n->sb_msg); 247 pt_display_status_bar(); 248 } 249 250 pt_display_suggestions(n->text); 251 252 g_curr_sugg = n; 253 254 return; 255 } 256 } 257 258 /* 259 * All suggestions have run out of slice quotas, so we restart. 260 */ 261 for (n = sugg; n != NULL; n = n->next) 262 n->slice = 0; 263 264 goto search; 265 } 266 267 void 268 pt_sugg_as_root(void) 269 { 270 pt_sugg_add("Suggestion: run as root to get suggestions" 271 " for reducing system power consumption", 40, NULL, NULL, 272 NULL); 273 } 274