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
pt_sugg_add(char * text,int weight,char key,char * sb_msg,sugg_func_t * func)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
pt_sugg_remove(sugg_func_t * func)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
pt_sugg_pick(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 && !g_sig_resize)
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
pt_sugg_as_root(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, 0, NULL,
272 NULL);
273 }
274