suggestions.c revision 9908:4b4177fc63d9
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 */
55sugg_t	*g_curr_sugg;
56
57/*
58 * Head of the list of suggestions.
59 */
60static sugg_t *sugg;
61
62/*
63 * Add a new suggestion. Only one suggestion per text allowed.
64 */
65void
66pt_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 */
157int
158pt_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 */
211void
212pt_sugg_pick(void)
213{
214	sugg_t *n;
215
216	if (sugg == NULL) {
217		g_curr_sugg = NULL;
218		return;
219	}
220
221search:
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
267void
268pt_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