Merging upstream version 0.7.0 (Closes: #493243, #510888, #567617, #699414, #709777...
[debian/lxpanel.git] / plugins / cpufreq / cpufreq.c
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>
25 #include <glib.h>
26 #include <glib/gi18n.h>
27
28 #include <string.h>
29
30 #include "plugin.h"
31
32 #include "dbg.h"
33
34 #define PROC_ICON PACKAGE_DATA_DIR "/images/cpufreq-icon.png"
35 #define SYSFS_CPU_DIRECTORY "/sys/devices/system/cpu"
36 #define SCALING_GOV "scaling_governor"
37 #define SCALING_AGOV "scaling_available_governors"
38 #define SCALING_AFREQ "scaling_available_frequencies"
39 #define SCALING_CUR_FREQ "scaling_cur_freq"
40 #define SCALING_SETFREQ "scaling_setspeed"
41 #define SCALING_MAX "scaling_max_freq"
42 #define SCALING_MIN "scaling_min_freq"
43
44
45 typedef struct {
46 GtkWidget *main;
47 config_setting_t *settings;
48 GtkWidget *namew;
49 GList *governors;
50 GList *cpus;
51 int has_cpufreq;
52 char* cur_governor;
53 int cur_freq;
54 unsigned int timer;
55 //gboolean remember;
56 } cpufreq;
57
58 typedef struct {
59 char *data;
60 cpufreq *cf;
61 } Param;
62
63 static void cpufreq_destructor(gpointer user_data);
64
65 static void
66 get_cur_governor(cpufreq *cf){
67 FILE *fp;
68 char buf[ 100 ], sstmp [ 256 ];
69
70 snprintf(sstmp, sizeof(sstmp), "%s/%s", (char*)cf->cpus->data, SCALING_GOV);
71 if ((fp = fopen( sstmp, "r")) != NULL) {
72 if(cf->cur_governor)
73 {
74 g_free(cf->cur_governor);
75 cf->cur_governor = NULL;
76 }
77 if (fgets(buf, 100, fp))
78 {
79 buf[strlen(buf)-1] = '\0';
80 cf->cur_governor = strdup(buf);
81 }
82 fclose(fp);
83 }
84 }
85
86 static void
87 get_cur_freq(cpufreq *cf){
88 FILE *fp;
89 char buf[ 100 ], sstmp [ 256 ];
90
91 snprintf(sstmp, sizeof(sstmp), "%s/%s", (char*)cf->cpus->data, SCALING_CUR_FREQ);
92 if ((fp = fopen( sstmp, "r")) != NULL) {
93 if (fgets(buf, 100, fp))
94 {
95 buf[strlen(buf)-1] = '\0';
96 cf->cur_freq = atoi(buf);
97 }
98 fclose(fp);
99 }
100 }
101
102 /*static void
103 get_governors(cpufreq *cf){
104 FILE *fp;
105 GList *l;
106 char buf[ 100 ], sstmp [ 256 ], c, bufl = 0;
107
108 g_list_free(cf->governors);
109 cf->governors = NULL;
110
111 get_cur_governor(cf);
112
113 if(cf->cpus == NULL){
114 cf->governors = NULL;
115 return;
116 }
117 sprintf(sstmp,"%s/%s",cf->cpus->data, SCALING_AGOV);
118
119 if (!(fp = fopen( sstmp, "r"))) {
120 printf("cpufreq: cannot open %s\n",sstmp);
121 return;
122 }
123
124 while((c = fgetc(fp)) != EOF){
125 if(c == ' '){
126 if(bufl > 1){
127 buf[bufl] = '\0';
128 cf->governors = g_list_append(cf->governors, strdup(buf));
129 }
130 bufl = 0;
131 buf[0] = '\0';
132 }else{
133 buf[bufl++] = c;
134 }
135 }
136
137 fclose(fp);
138 }
139
140 static void
141 cpufreq_set_freq(GtkWidget *widget, Param* p){
142 FILE *fp;
143 char buf[ 100 ], sstmp [ 256 ];
144
145 if(strcmp(p->cf->cur_governor, "userspace")) return;
146
147 sprintf(sstmp,"%s/%s",p->cf->cpus->data, SCALING_SETFREQ);
148 if ((fp = fopen( sstmp, "w")) != NULL) {
149 fprintf(fp,"%s",p->data);
150 fclose(fp);
151 }
152 }
153
154 static GtkWidget *
155 frequency_menu(cpufreq *cf){
156 FILE *fp;
157 Param* param;
158 char buf[ 100 ], sstmp [ 256 ], c, bufl = 0;
159
160 sprintf(sstmp,"%s/%s",cf->cpus->data, SCALING_AFREQ);
161
162 if (!(fp = fopen( sstmp, "r"))) {
163 printf("cpufreq: cannot open %s\n",sstmp);
164 return 0;
165 }
166
167 GtkMenu* menu = GTK_MENU(gtk_menu_new());
168 GtkWidget* menuitem;
169
170 while((c = fgetc(fp)) != EOF){
171 if(c == ' '){
172 if(bufl > 1){
173 buf[bufl] = '\0';
174 menuitem = gtk_menu_item_new_with_label(strdup(buf));
175 gtk_menu_append (GTK_MENU_SHELL (menu), menuitem);
176 gtk_widget_show (menuitem);
177 param = g_new0(Param, 1);
178 param->data = strdup(buf);
179 param->cf = cf;
180 g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(cpufreq_set_freq), param);
181 g_object_weak_ref(G_OBJECT(menuitem), (GWeakNotify)g_free, param);
182 }
183 bufl = 0;
184 buf[0] = '\0';
185 }else{
186 buf[bufl++] = c;
187 }
188 }
189
190 fclose(fp);
191 return GTK_WIDGET(menu);
192 }*/
193
194 static void
195 get_cpus(cpufreq *cf)
196 {
197
198 const char *cpu;
199 char cpu_path[100];
200
201 GDir * cpuDirectory = g_dir_open(SYSFS_CPU_DIRECTORY, 0, NULL);
202 if (cpuDirectory == NULL)
203 {
204 cf->cpus = NULL;
205 printf("cpufreq: no cpu found\n");
206 return;
207 }
208
209 while ((cpu = g_dir_read_name(cpuDirectory)))
210 {
211 /* Look for directories of the form "cpu<n>", where "<n>" is a decimal integer. */
212 if ((strncmp(cpu, "cpu", 3) == 0) && (cpu[3] >= '0') && (cpu[3] <= '9'))
213 {
214 snprintf(cpu_path, sizeof(cpu_path), "%s/%s/cpufreq", SYSFS_CPU_DIRECTORY, cpu);
215
216 GDir * cpufreqDir = g_dir_open(SYSFS_CPU_DIRECTORY, 0, NULL);
217 if (cpufreqDir == NULL)
218 {
219 cf->cpus = NULL;
220 cf->has_cpufreq = 0;
221 break;
222 }
223
224 cf->has_cpufreq = 1;
225 cf->cpus = g_list_append(cf->cpus, strdup(cpu_path));
226 }
227 }
228 g_dir_close(cpuDirectory);
229 }
230
231 /*static void
232 cpufreq_set_governor(GtkWidget *widget, Param* p){
233 FILE *fp;
234 char buf[ 100 ], sstmp [ 256 ];
235
236 sprintf(sstmp, "%s/%s", p->cf->cpus->data, SCALING_GOV);
237 if ((fp = fopen( sstmp, "w")) != NULL) {
238 fprintf(fp,"%s",p->data);
239 fclose(fp);
240 }
241 }
242
243 static GtkWidget *
244 cpufreq_menu(cpufreq *cf){
245 GList *l;
246 GSList *group;
247 char buff[100];
248 GtkMenuItem* menuitem;
249 Param* param;
250
251 GtkMenu* menu = GTK_MENU(gtk_menu_new());
252 g_signal_connect(menu, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL);
253
254 get_governors(cf);
255 group = NULL;
256
257 if((cf->governors == NULL) || (!cf->has_cpufreq) || (cf->cur_governor == NULL)){
258 menuitem = GTK_MENU_ITEM(gtk_menu_item_new_with_label("CPUFreq not supported"));
259 gtk_menu_append (GTK_MENU_SHELL (menu), GTK_WIDGET (menuitem));
260 gtk_widget_show (GTK_WIDGET (menuitem));
261 return GTK_WIDGET(menu);
262 }
263
264 if(strcmp(cf->cur_governor, "userspace") == 0){
265 menuitem = GTK_MENU_ITEM(gtk_menu_item_new_with_label(" Frequency"));
266 gtk_menu_append (GTK_MENU_SHELL (menu), GTK_WIDGET (menuitem));
267 gtk_widget_show (GTK_WIDGET (menuitem));
268 gtk_menu_item_set_submenu(menuitem, frequency_menu(cf));
269 menuitem = GTK_MENU_ITEM(gtk_separator_menu_item_new());
270 gtk_menu_append (GTK_MENU_SHELL (menu), GTK_WIDGET (menuitem));
271 gtk_widget_show (GTK_WIDGET(menuitem));
272 }
273
274 for( l = cf->governors; l; l = l->next )
275 {
276 if(strcmp((char*)l->data, cf->cur_governor) == 0){
277 sprintf(buff,"> %s", l->data);
278 menuitem = GTK_MENU_ITEM(gtk_menu_item_new_with_label(strdup(buff)));
279 }else{
280 sprintf(buff," %s", l->data);
281 menuitem = GTK_MENU_ITEM(gtk_menu_item_new_with_label(strdup(buff)));
282 }
283
284 gtk_menu_shell_append (GTK_MENU_SHELL (menu), GTK_WIDGET (menuitem));
285 gtk_widget_show (GTK_WIDGET (menuitem));
286 param = g_new0(Param, 1);
287 param->data = l->data;
288 param->cf = cf;
289 g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(cpufreq_set_governor), param);
290 g_object_weak_ref(G_OBJECT(menuitem), (GWeakNotify) g_free, param);
291 }
292
293 return GTK_WIDGET (menu);
294 }*/
295
296
297
298 static gboolean
299 clicked(GtkWidget *widget, GdkEventButton *evt, LXPanel *panel)
300 {
301 ENTER;
302
303 /* Standard right-click handling. */
304 if( evt->button == 1 )
305 {
306 // Setting governor can't work without root privilege
307 // gtk_menu_popup( cpufreq_menu((cpufreq*)plugin->priv), NULL, NULL, NULL, NULL,
308 // evt->button, evt->time );
309 return TRUE;
310 }
311
312 RET(FALSE);
313 }
314
315 static gboolean
316 _update_tooltip(cpufreq *cf)
317 {
318 char *tooltip;
319
320 get_cur_freq(cf);
321 get_cur_governor(cf);
322
323 ENTER;
324
325 tooltip = g_strdup_printf(_("Frequency: %d MHz\nGovernor: %s"),
326 cf->cur_freq / 1000, cf->cur_governor);
327 gtk_widget_set_tooltip_text(cf->main, tooltip);
328 g_free(tooltip);
329 RET(TRUE);
330 }
331
332 static gboolean update_tooltip(gpointer user_data)
333 {
334 if (g_source_is_destroyed(g_main_current_source()))
335 return FALSE;
336 return _update_tooltip(user_data);
337 }
338
339 static GtkWidget *cpufreq_constructor(LXPanel *panel, config_setting_t *settings)
340 {
341 cpufreq *cf;
342 //GtkWidget *button;
343
344 ENTER;
345 cf = g_new0(cpufreq, 1);
346 g_return_val_if_fail(cf != NULL, NULL);
347 cf->governors = NULL;
348 cf->cpus = NULL;
349 cf->settings = settings;
350
351 cf->main = gtk_event_box_new();
352 lxpanel_plugin_set_data(cf->main, cf, cpufreq_destructor);
353 gtk_widget_set_has_window(cf->main, FALSE);
354 gtk_container_set_border_width(GTK_CONTAINER(cf->main), 2);
355
356 cf->namew = gtk_image_new_from_file(PROC_ICON);
357 gtk_container_add(GTK_CONTAINER(cf->main), cf->namew);
358
359 cf->has_cpufreq = 0;
360
361 get_cpus(cf);
362
363 //if (config_setting_lookup_int(settings, "Remember", &tmp_int)) cf->remember = tmp_int != 0;
364 //if (config_setting_lookup_int(settings, "Governor", &tmp_str)) cf->cur_governor = g_strdup(tmp_str);
365 //config_setting_lookup_int(settings, "Frequency", &cf->cur_freq);
366
367 _update_tooltip(cf);
368 cf->timer = g_timeout_add_seconds(2, update_tooltip, (gpointer)cf);
369
370 gtk_widget_show(cf->namew);
371
372 RET(cf->main);
373 }
374
375 /*
376 static gboolean applyConfig(gpointer user_data)
377 {
378 cpufreq *cf = lxpanel_plugin_get_data(user_data);
379
380 config_group_set_int(cf->settings, "Remember", cf->remember);
381 return FALSE;
382 }
383
384 static GtkWidget *config(LXPanel *panel, GtkWidget *p, GtkWindow *parent)
385 {
386 cpufreq *cf = lxpanel_plugin_get_data(p);
387 return lxpanel_generic_config_dlg(_("CPUFreq frontend"), panel, applyConfig, p,
388 _("Remember governor and frequency"), &cf->remember, CONF_TYPE_BOOL,
389 NULL);
390 }
391 */
392
393 static void
394 cpufreq_destructor(gpointer user_data)
395 {
396 cpufreq *cf = (cpufreq *)user_data;
397 g_list_free ( cf->cpus );
398 g_list_free ( cf->governors );
399 g_source_remove(cf->timer);
400 g_free(cf);
401 }
402
403
404 FM_DEFINE_MODULE(lxpanel_gtk, cpufreq)
405
406 /* Plugin descriptor. */
407 LXPanelPluginInit fm_module_init_lxpanel_gtk = {
408 .name = N_("CPUFreq frontend"),
409 .description = N_("Display CPU frequency and allow to change governors and frequency"),
410
411 .new_instance = cpufreq_constructor,
412 //.config = config,
413 .button_press_event = clicked
414 };