Enabling multithreaded compilation.
[debian/lxpanel.git] / src / plugins / cpufreq / cpufreq.c
CommitLineData
bfba7517
DB
1/**
2 * CPUFreq plugin to lxpanel
3 *
4 * Copyright (C) 2009 by Daniel Kesler <kesler.daniel@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sys/types.h>
23#include <stdio.h>
24#include <stdlib.h>
24d886e1 25#include <glib.h>
bfba7517
DB
26#include <glib/gi18n.h>
27
28#include <string.h>
29
30#include "panel.h"
31#include "misc.h"
32#include "plugin.h"
33
34#include "dbg.h"
35
36#define PROC_ICON PACKAGE_DATA_DIR "/lxpanel/images/cpufreq-icon.png"
24d886e1 37#define SYSFS_CPU_DIRECTORY "/sys/devices/system/cpu"
bfba7517
DB
38#define SCALING_GOV "scaling_governor"
39#define SCALING_AGOV "scaling_available_governors"
40#define SCALING_AFREQ "scaling_available_frequencies"
24d886e1 41#define SCALING_CUR_FREQ "scaling_cur_freq"
bfba7517
DB
42#define SCALING_SETFREQ "scaling_setspeed"
43#define SCALING_MAX "scaling_max_freq"
44#define SCALING_MIN "scaling_min_freq"
45
46
47typedef struct {
48 GtkWidget *main;
49 GtkWidget *namew;
50 GtkTooltips *tip;
51 GList *governors;
52 GList *cpus;
53 int has_cpufreq;
54 char* cur_governor;
55 int cur_freq;
56 unsigned int timer;
57 gboolean remember;
58} cpufreq;
59
60typedef struct {
61 void *data;
62 cpufreq *cf;
63} Param;
64
65static void
66get_cur_governor(cpufreq *cf){
67 FILE *fp;
68 char buf[ 100 ], sstmp [ 256 ];
69
24d886e1 70 sprintf(sstmp,"%s/%s",cf->cpus->data, SCALING_GOV);
bfba7517
DB
71 if ((fp = fopen( sstmp, "r")) != NULL) {
72 fgets(buf, 100, fp);
73 buf[strlen(buf)-1] = '\0';
74 if(cf->cur_governor)
75 {
76 g_free(cf->cur_governor);
77 cf->cur_governor = NULL;
78 }
79 cf->cur_governor = strdup(buf);
80 fclose(fp);
81 }
82}
83
84static void
85get_cur_freq(cpufreq *cf){
86 FILE *fp;
87 char buf[ 100 ], sstmp [ 256 ];
88
24d886e1 89 sprintf(sstmp,"%s/%s",cf->cpus->data, SCALING_CUR_FREQ);
bfba7517
DB
90 if ((fp = fopen( sstmp, "r")) != NULL) {
91 fgets(buf, 100, fp);
92 buf[strlen(buf)-1] = '\0';
93 cf->cur_freq = atoi(buf);
94 fclose(fp);
95 }
96}
97
98static void
99get_governors(cpufreq *cf){
100 FILE *fp;
101 GList *l;
102 char buf[ 100 ], sstmp [ 256 ], c, bufl = 0;
103
104 g_list_free(cf->governors);
105 cf->governors = NULL;
106
107 get_cur_governor(cf);
108
109 if(cf->cpus == NULL){
110 cf->governors = NULL;
111 return;
112 }
24d886e1 113 sprintf(sstmp,"%s/%s",cf->cpus->data, SCALING_AGOV);
bfba7517
DB
114
115 if (!(fp = fopen( sstmp, "r"))) {
116 printf("cpufreq: cannot open %s\n",sstmp);
117 return;
118 }
119
120 while((c = fgetc(fp)) != EOF){
121 if(c == ' '){
122 if(bufl > 1){
123 buf[bufl] = '\0';
124 cf->governors = g_list_append(cf->governors, strdup(buf));
125 }
126 bufl = 0;
127 buf[0] = '\0';
128 }else{
129 buf[bufl++] = c;
130 }
131 }
132
133 fclose(fp);
134}
135
136static void
137cpufreq_set_freq(GtkWidget *widget, Param* p){
138 FILE *fp;
139 char buf[ 100 ], sstmp [ 256 ];
140
141 if(strcmp(p->cf->cur_governor, "userspace")) return;
142
24d886e1 143 sprintf(sstmp,"%s/%s",p->cf->cpus->data, SCALING_SETFREQ);
bfba7517
DB
144 if ((fp = fopen( sstmp, "w")) != NULL) {
145 fprintf(fp,"%s",p->data);
146 fclose(fp);
147 }
148}
149
150static GtkWidget *
151frequency_menu(cpufreq *cf){
152 FILE *fp;
153 Param* param;
154 char buf[ 100 ], sstmp [ 256 ], c, bufl = 0;
155
24d886e1 156 sprintf(sstmp,"%s/%s",cf->cpus->data, SCALING_AFREQ);
bfba7517
DB
157
158 if (!(fp = fopen( sstmp, "r"))) {
159 printf("cpufreq: cannot open %s\n",sstmp);
170c1e2e 160 return 0;
bfba7517
DB
161 }
162
163 GtkMenu* menu = GTK_MENU(gtk_menu_new());
164 GtkWidget* menuitem;
165
166 while((c = fgetc(fp)) != EOF){
167 if(c == ' '){
168 if(bufl > 1){
169 buf[bufl] = '\0';
f8c25730 170 menuitem = gtk_menu_item_new_with_label(strdup(buf));
bfba7517
DB
171 gtk_menu_append (GTK_MENU_SHELL (menu), menuitem);
172 gtk_widget_show (menuitem);
173 param = g_new0(Param, 1);
174 param->data = strdup(buf);
175 param->cf = cf;
176 g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(cpufreq_set_freq), param);
f8c25730 177 g_object_weak_ref(G_OBJECT(menuitem), (GWeakNotify)g_free, param);
bfba7517
DB
178 }
179 bufl = 0;
180 buf[0] = '\0';
181 }else{
182 buf[bufl++] = c;
183 }
184 }
185
186 fclose(fp);
f8c25730 187 return GTK_WIDGET(menu);
bfba7517
DB
188}
189
190static void
24d886e1
DB
191get_cpus(cpufreq *cf)
192{
193
bfba7517
DB
194 const char *cpu;
195 char cpu_path[100];
196
24d886e1
DB
197 GDir * cpuDirectory = g_dir_open(SYSFS_CPU_DIRECTORY, 0, NULL);
198 if (cpuDirectory == NULL)
bfba7517
DB
199 {
200 cf->cpus = NULL;
201 printf("cpufreq: no cpu found\n");
202 return;
203 }
204
24d886e1
DB
205 while ((cpu = g_dir_read_name(cpuDirectory)))
206 {
207 /* Look for directories of the form "cpu<n>", where "<n>" is a decimal integer. */
208 if ((strncmp(cpu, "cpu", 3) == 0) && (cpu[3] >= '0') && (cpu[3] <= '9'))
209 {
210 sprintf(cpu_path, "%s/%s/cpufreq", SYSFS_CPU_DIRECTORY, cpu);
bfba7517 211
24d886e1
DB
212 GDir * cpufreqDir = g_dir_open(SYSFS_CPU_DIRECTORY, 0, NULL);
213 if (cpufreqDir == NULL)
bfba7517
DB
214 {
215 cf->cpus = NULL;
216 cf->has_cpufreq = 0;
24d886e1 217 break;
bfba7517 218 }
24d886e1
DB
219
220 cf->has_cpufreq = 1;
221 cf->cpus = g_list_append(cf->cpus, strdup(cpu_path));
bfba7517
DB
222 }
223 }
224 g_dir_close(cpuDirectory);
225}
226
227static void
228cpufreq_set_governor(GtkWidget *widget, Param* p){
229 FILE *fp;
230 char buf[ 100 ], sstmp [ 256 ];
231
24d886e1 232 sprintf(sstmp, "%s/%s", p->cf->cpus->data, SCALING_GOV);
bfba7517
DB
233 if ((fp = fopen( sstmp, "w")) != NULL) {
234 fprintf(fp,"%s",p->data);
235 fclose(fp);
236 }
237}
238
239static GtkWidget *
240cpufreq_menu(cpufreq *cf){
241 GList *l;
242 GSList *group;
243 char buff[100];
244 GtkMenuItem* menuitem;
245 Param* param;
246
247 GtkMenu* menu = GTK_MENU(gtk_menu_new());
f8c25730 248 g_signal_connect(menu, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL);
bfba7517
DB
249
250 get_governors(cf);
251 group = NULL;
252
24d886e1 253 if((cf->governors == NULL) || (!cf->has_cpufreq) || (cf->cur_governor == NULL)){
bfba7517 254 menuitem = GTK_MENU_ITEM(gtk_menu_item_new_with_label("CPUFreq not supported"));
f8c25730
DB
255 gtk_menu_append (GTK_MENU_SHELL (menu), GTK_WIDGET (menuitem));
256 gtk_widget_show (GTK_WIDGET (menuitem));
257 return GTK_WIDGET(menu);
bfba7517
DB
258 }
259
260 if(strcmp(cf->cur_governor, "userspace") == 0){
261 menuitem = GTK_MENU_ITEM(gtk_menu_item_new_with_label(" Frequency"));
f8c25730
DB
262 gtk_menu_append (GTK_MENU_SHELL (menu), GTK_WIDGET (menuitem));
263 gtk_widget_show (GTK_WIDGET (menuitem));
bfba7517
DB
264 gtk_menu_item_set_submenu(menuitem, frequency_menu(cf));
265 menuitem = GTK_MENU_ITEM(gtk_separator_menu_item_new());
f8c25730 266 gtk_menu_append (GTK_MENU_SHELL (menu), GTK_WIDGET (menuitem));
bfba7517
DB
267 gtk_widget_show (GTK_WIDGET(menuitem));
268 }
269
270 for( l = cf->governors; l; l = l->next )
271 {
272 if(strcmp((char*)l->data, cf->cur_governor) == 0){
273 sprintf(buff,"> %s", l->data);
274 menuitem = GTK_MENU_ITEM(gtk_menu_item_new_with_label(strdup(buff)));
275 }else{
276 sprintf(buff," %s", l->data);
277 menuitem = GTK_MENU_ITEM(gtk_menu_item_new_with_label(strdup(buff)));
278 }
279
f8c25730
DB
280 gtk_menu_shell_append (GTK_MENU_SHELL (menu), GTK_WIDGET (menuitem));
281 gtk_widget_show (GTK_WIDGET (menuitem));
bfba7517
DB
282 param = g_new0(Param, 1);
283 param->data = l->data;
284 param->cf = cf;
285 g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(cpufreq_set_governor), param);
f8c25730 286 g_object_weak_ref(G_OBJECT(menuitem), (GWeakNotify) g_free, param);
bfba7517
DB
287 }
288
f8c25730 289 return GTK_WIDGET (menu);
bfba7517
DB
290}
291
292
293
294static gboolean
295clicked( GtkWidget *widget, GdkEventButton* evt, Plugin* plugin)
296{
297 ENTER2;
298 if( evt->button == 1 )
299 {
24d886e1
DB
300// Setting governor can't work without root privilege
301// gtk_menu_popup( cpufreq_menu((cpufreq*)plugin->priv), NULL, NULL, NULL, NULL,
302// evt->button, evt->time );
bfba7517
DB
303 return TRUE;
304 }else if ( evt->button == 3 )
305 {
306 GtkMenu* popup = lxpanel_get_panel_menu( plugin->panel, plugin, FALSE );
307 gtk_menu_popup( popup, NULL, NULL, NULL, NULL, evt->button, evt->time );
308 return TRUE;
309 return TRUE;
310 }
311
312 RET2(TRUE);
313}
314
315static gint
316update_tooltip(cpufreq *cf)
317{
318 char *tooltip;
319
320 get_cur_freq(cf);
321 get_cur_governor(cf);
322
323 ENTER;
324
24d886e1 325 tooltip = g_strdup_printf("Frequency: %d MHz\nGovernor: %s",
bfba7517
DB
326 cf->cur_freq / 1000, cf->cur_governor);
327 gtk_tooltips_set_tip(cf->tip, cf->main, tooltip, NULL);
328 g_free(tooltip);
329 RET(TRUE);
330}
331
332static int
333cpufreq_constructor(Plugin *p, char** fp)
334{
335 cpufreq *cf;
336 GtkWidget *button;
337
338 ENTER;
339 cf = g_new0(cpufreq, 1);
340 cf->governors = NULL;
341 cf->cpus = NULL;
342 g_return_val_if_fail(cf != NULL, 0);
343 p->priv = cf;
344
345 p->pwid = gtk_event_box_new();
346 GTK_WIDGET_SET_FLAGS( p->pwid, GTK_NO_WINDOW );
347 gtk_container_set_border_width( GTK_CONTAINER(p->pwid), 2 );
348
349 cf->namew = gtk_image_new_from_file(PROC_ICON);
350 gtk_container_add(GTK_CONTAINER(p->pwid), cf->namew);
351
352 cf->main = p->pwid;
353 cf->tip = gtk_tooltips_new();
354
355#if GLIB_CHECK_VERSION( 2, 10, 0 )
356 g_object_ref_sink( cf->tip );
357#else
358 g_object_ref( cf->tip );
359 gtk_object_sink( cf->tip );
360#endif
361
362 g_signal_connect (G_OBJECT (p->pwid), "button_press_event", G_CALLBACK (clicked), (gpointer) p);
363
364 cf->has_cpufreq = 0;
365
366 get_cpus(cf);
367
368/* line s;
369 s.len = 256;
370
371 if (fp) {
372 while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END) {
373 if (s.type == LINE_NONE) {
374 ERR( "cpufreq: illegal token %s\n", s.str);
375 goto error;
376 }
377 if (s.type == LINE_VAR) {
378 if (!g_ascii_strcasecmp(s.t[0], "DefaultGovernor")){
379 //cf->str_cl_normal = g_strdup(s.t[1]);
380 }else {
381 ERR( "cpufreq: unknown var %s\n", s.t[0]);
382 continue;
383 }
384 }
385 else {
386 ERR( "cpufreq: illegal in cfis context %s\n", s.str);
387 goto error;
388 }
389 }
390
391 }*/
392 update_tooltip(cf);
5d26221e 393 cf->timer = g_timeout_add_seconds(2, (GSourceFunc)update_tooltip, (gpointer)cf);
bfba7517
DB
394
395 gtk_widget_show(cf->namew);
396
397 RET(TRUE);
398
399/*error:
400 RET(FALSE);*/
401}
402
403static void applyConfig(Plugin* p) { }
404
405static void config(Plugin *p, GtkWindow* parent) {
406 ENTER;
407
408 GtkWidget *dialog;
409 cpufreq *cf = (cpufreq *) p->priv;
410 dialog = create_generic_config_dlg(_(p->class->name),
411 GTK_WIDGET(parent),
412 (GSourceFunc) applyConfig, (gpointer) p,
413 _("Remember governor and frequency"), &cf->remember, CONF_TYPE_BOOL,
414 NULL);
415 gtk_window_present(GTK_WINDOW(dialog));
416
417 RET();
418}
419
420static void
421cpufreq_destructor(Plugin *p)
422{
423 cpufreq *cf = (cpufreq *)p->priv;
424 g_list_free ( cf->cpus );
425 g_list_free ( cf->governors );
426 g_source_remove(cf->timer);
427 g_free(cf);
428}
429
430static void save_config( Plugin* p, FILE* fp )
431{
432 cpufreq *cf = (cpufreq *)p->priv;
433
434 lxpanel_put_bool( fp, "Remember", cf->remember);
435 lxpanel_put_str( fp, "Governor", cf->cur_governor );
436 lxpanel_put_int( fp, "Frequency", cf->cur_freq );
437}
438
439PluginClass cpufreq_plugin_class = {
440 PLUGINCLASS_VERSIONING,
441
442 type : "cpufreq",
443 name : N_("CPUFreq frontend"),
444 version: "0.1",
445 description : N_("Display CPU frequency and allow to change governors and frequency"),
446
447 constructor : cpufreq_constructor,
448 destructor : cpufreq_destructor,
449 config : config,
450 save : NULL,
451 panel_configuration_changed : NULL
452};