diff options
author | Perberos <[email protected]> | 2011-11-14 18:24:48 -0300 |
---|---|---|
committer | Perberos <[email protected]> | 2011-11-14 18:24:48 -0300 |
commit | 312ba610a1e98fc656fb58178227d7d45a64494e (patch) | |
tree | 54a3c2b6084c80e63fb0526c6e7b8e01627acbd7 /cpufreq/src | |
download | mate-applets-312ba610a1e98fc656fb58178227d7d45a64494e.tar.bz2 mate-applets-312ba610a1e98fc656fb58178227d7d45a64494e.tar.xz |
initial
Diffstat (limited to 'cpufreq/src')
41 files changed, 7189 insertions, 0 deletions
diff --git a/cpufreq/src/Makefile.am b/cpufreq/src/Makefile.am new file mode 100644 index 00000000..db5679d0 --- /dev/null +++ b/cpufreq/src/Makefile.am @@ -0,0 +1,40 @@ +if BUILD_CPUFREQ_SELECTOR +selector_SUBDIR = cpufreq-selector +endif + +SUBDIRS = $(selector_SUBDIR) + +INCLUDES = \ + -DCPUFREQ_MENU_UI_DIR=\""$(datadir)/mate-2.0/ui"\" \ + $(MATE_APPLETS3_CFLAGS) \ + $(LIBGLADE_CFLAGS) \ + $(DBUS_CFLAGS) + +libexec_PROGRAMS = cpufreq-applet + +if HAVE_LIBCPUFREQ +cpufreq_files=cpufreq-monitor-libcpufreq.c cpufreq-monitor-libcpufreq.h +endif + +cpufreq_applet_SOURCES = \ + cpufreq-applet.c cpufreq-applet.h \ + cpufreq-utils.c cpufreq-utils.h \ + cpufreq-prefs.c cpufreq-prefs.h \ + cpufreq-selector.c cpufreq-selector.h \ + cpufreq-popup.c cpufreq-popup.h \ + cpufreq-monitor.c cpufreq-monitor.h \ + cpufreq-monitor-factory.c cpufreq-monitor-factory.h \ + cpufreq-monitor-procfs.c cpufreq-monitor-procfs.h \ + cpufreq-monitor-sysfs.c cpufreq-monitor-sysfs.h \ + $(cpufreq_files) \ + cpufreq-monitor-cpuinfo.c cpufreq-monitor-cpuinfo.h + +cpufreq_applet_LDADD = \ + $(MATE_APPLETS3_LIBS) \ + $(LIBGLADE_LIBS) \ + $(LIBCPUFREQ_LIBS) \ + $(DBUS_LIBS) + + + +-include $(top_srcdir)/git.mk diff --git a/cpufreq/src/cpufreq-applet.c b/cpufreq/src/cpufreq-applet.c new file mode 100644 index 00000000..07a80339 --- /dev/null +++ b/cpufreq/src/cpufreq-applet.c @@ -0,0 +1,1032 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> +#include <mate-panel-applet.h> +#include <mate-panel-applet-mateconf.h> +#include <glib/gi18n.h> +#include <stdlib.h> +#include <string.h> + +#include "cpufreq-applet.h" +#include "cpufreq-prefs.h" +#include "cpufreq-popup.h" +#include "cpufreq-monitor.h" +#include "cpufreq-monitor-factory.h" +#include "cpufreq-utils.h" + +struct _CPUFreqApplet { + MatePanelApplet base; + + /* Visibility */ + CPUFreqShowMode show_mode; + CPUFreqShowTextMode show_text_mode; + gboolean show_freq; + gboolean show_perc; + gboolean show_unit; + gboolean show_icon; + + CPUFreqMonitor *monitor; + + MatePanelAppletOrient orient; + gint size; + + GtkWidget *label; + GtkWidget *unit_label; + GtkWidget *icon; + GtkWidget *box; + GtkWidget *labels_box; + GtkWidget *container; + GdkPixbuf *pixbufs[5]; + + gint max_label_width; + gint max_perc_width; + gint max_unit_width; + + gboolean need_refresh; + + CPUFreqPrefs *prefs; + CPUFreqPopup *popup; +}; + +struct _CPUFreqAppletClass { + MatePanelAppletClass parent_class; +}; + +static void cpufreq_applet_init (CPUFreqApplet *applet); +static void cpufreq_applet_class_init (CPUFreqAppletClass *klass); + +static void cpufreq_applet_preferences_cb (GtkAction *action, + CPUFreqApplet *applet); +static void cpufreq_applet_help_cb (GtkAction *action, + CPUFreqApplet *applet); +static void cpufreq_applet_about_cb (GtkAction *action, + CPUFreqApplet *applet); + +static void cpufreq_applet_pixmap_set_image (CPUFreqApplet *applet, + gint perc); + +static void cpufreq_applet_setup (CPUFreqApplet *applet); +static void cpufreq_applet_update (CPUFreqApplet *applet, + CPUFreqMonitor *monitor); +static void cpufreq_applet_refresh (CPUFreqApplet *applet); + +static void cpufreq_applet_destroy (GtkObject *widget); +static gboolean cpufreq_applet_button_press (GtkWidget *widget, + GdkEventButton *event); +static gboolean cpufreq_applet_key_press (GtkWidget *widget, + GdkEventKey *event); +static void cpufreq_applet_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void cpufreq_applet_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void cpufreq_applet_change_orient (MatePanelApplet *pa, + MatePanelAppletOrient orient); +static gboolean cpufreq_applet_factory (CPUFreqApplet *applet, + const gchar *iid, + gpointer gdata); + +static const gchar *const cpufreq_icons[] = { + MATE_PIXMAPSDIR"/cpufreq-applet/cpufreq-25.png", + MATE_PIXMAPSDIR"/cpufreq-applet/cpufreq-50.png", + MATE_PIXMAPSDIR"/cpufreq-applet/cpufreq-75.png", + MATE_PIXMAPSDIR"/cpufreq-applet/cpufreq-100.png", + MATE_PIXMAPSDIR"/cpufreq-applet/cpufreq-na.png", + NULL +}; + +static const GtkActionEntry cpufreq_applet_menu_actions[] = { + { "CPUFreqAppletPreferences", GTK_STOCK_PROPERTIES, N_("_Preferences"), + NULL, NULL, + G_CALLBACK (cpufreq_applet_preferences_cb) }, + { "CPUFreqAppletHelp", GTK_STOCK_HELP, N_("_Help"), + NULL, NULL, + G_CALLBACK (cpufreq_applet_help_cb) }, + { "CPUFreqAppletAbout", GTK_STOCK_ABOUT, N_("_About"), + NULL, NULL, + G_CALLBACK (cpufreq_applet_about_cb) } +}; + +G_DEFINE_TYPE (CPUFreqApplet, cpufreq_applet, PANEL_TYPE_APPLET) + +/* Enum Types */ +GType +cpufreq_applet_show_mode_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) { + static const GEnumValue values[] = { + { CPUFREQ_MODE_GRAPHIC, "CPUFREQ_MODE_GRAPHIC", "mode-graphic" }, + { CPUFREQ_MODE_TEXT, "CPUFREQ_MODE_TEXT", "mode-text" }, + { CPUFREQ_MODE_BOTH, "CPUFREQ_MODE_BOTH", "mode-both" }, + { 0, NULL, NULL } + }; + + etype = g_enum_register_static ("CPUFreqShowMode", values); + } + + return etype; +} + +GType +cpufreq_applet_show_text_mode_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) { + static const GEnumValue values[] = { + { CPUFREQ_MODE_TEXT_FREQUENCY, "CPUFREQ_MODE_TEXT_FREQUENCY", "mode-text-frequency" }, + { CPUFREQ_MODE_TEXT_FREQUENCY_UNIT, "CPUFREQ_MODE_TEXT_FREQUENCY_UNIT", "mode-text-frequency-unit" }, + { CPUFREQ_MODE_TEXT_PERCENTAGE, "CPUFREQ_MODE_TEXT_PERCENTAGE", "mode-text-percentage" }, + { 0, NULL, NULL } + }; + + etype = g_enum_register_static ("CPUFreqShowTextMode", values); + } + + return etype; +} + +static void +cpufreq_applet_init (CPUFreqApplet *applet) +{ + applet->prefs = NULL; + applet->popup = NULL; + applet->monitor = NULL; + + applet->label = gtk_label_new (NULL); + applet->unit_label = gtk_label_new (NULL); + applet->icon = gtk_image_new (); + applet->box = NULL; + + applet->show_mode = CPUFREQ_MODE_BOTH; + applet->show_text_mode = CPUFREQ_MODE_TEXT_FREQUENCY_UNIT; + + applet->need_refresh = TRUE; + + mate_panel_applet_set_flags (MATE_PANEL_APPLET (applet), MATE_PANEL_APPLET_EXPAND_MINOR); + mate_panel_applet_set_background_widget (MATE_PANEL_APPLET (applet), GTK_WIDGET (applet)); + + applet->size = mate_panel_applet_get_size (MATE_PANEL_APPLET (applet)); + applet->orient = mate_panel_applet_get_orient (MATE_PANEL_APPLET (applet)); + + switch (applet->orient) { + case MATE_PANEL_APPLET_ORIENT_LEFT: + case MATE_PANEL_APPLET_ORIENT_RIGHT: + applet->container = gtk_alignment_new (0.5, 0.5, 0, 0); + break; + case MATE_PANEL_APPLET_ORIENT_UP: + case MATE_PANEL_APPLET_ORIENT_DOWN: + applet->container = gtk_alignment_new (0, 0.5, 0, 0); + break; + } + + gtk_container_add (GTK_CONTAINER (applet), applet->container); + gtk_widget_show (applet->container); +} + +static void +cpufreq_applet_class_init (CPUFreqAppletClass *klass) +{ + MatePanelAppletClass *applet_class = MATE_PANEL_APPLET_CLASS (klass); + GtkObjectClass *gtkobject_class = GTK_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + gtkobject_class->destroy = cpufreq_applet_destroy; + + widget_class->size_allocate = cpufreq_applet_size_allocate; + widget_class->size_request = cpufreq_applet_size_request; + widget_class->button_press_event = cpufreq_applet_button_press; + widget_class->key_press_event = cpufreq_applet_key_press; + + applet_class->change_orient = cpufreq_applet_change_orient; +} + +static void +cpufreq_applet_destroy (GtkObject *widget) +{ + CPUFreqApplet *applet; + gint i; + + applet = CPUFREQ_APPLET (widget); + + if (applet->monitor) { + g_object_unref (G_OBJECT (applet->monitor)); + applet->monitor = NULL; + } + + for (i = 0; i <= 3; i++) { + if (applet->pixbufs[i]) { + g_object_unref (G_OBJECT (applet->pixbufs[i])); + applet->pixbufs[i] = NULL; + } + } + + if (applet->prefs) { + g_object_unref (applet->prefs); + applet->prefs = NULL; + } + + if (applet->popup) { + g_object_unref (applet->popup); + applet->popup = NULL; + } + + GTK_OBJECT_CLASS (cpufreq_applet_parent_class)->destroy (widget); +} + +static void +cpufreq_applet_size_allocate (GtkWidget *widget, GtkAllocation *allocation) +{ + CPUFreqApplet *applet; + gint size = 0; + + applet = CPUFREQ_APPLET (widget); + + GTK_WIDGET_CLASS (cpufreq_applet_parent_class)->size_allocate (widget, allocation); + + switch (applet->orient) { + case MATE_PANEL_APPLET_ORIENT_LEFT: + case MATE_PANEL_APPLET_ORIENT_RIGHT: + size = allocation->width; + break; + case MATE_PANEL_APPLET_ORIENT_UP: + case MATE_PANEL_APPLET_ORIENT_DOWN: + size = allocation->height; + break; + } + + if (size != applet->size) { + applet->size = size; + cpufreq_applet_refresh (applet); + } +} + +static gint +cpufreq_applet_get_max_label_width (CPUFreqApplet *applet) +{ + GList *available_freqs; + gint width = 0; + + if (applet->max_label_width > 0) + return applet->max_label_width; + + if (!CPUFREQ_IS_MONITOR (applet->monitor)) + return 0; + + available_freqs = cpufreq_monitor_get_available_frequencies (applet->monitor); + while (available_freqs) { + GtkWidget *label; + GtkRequisition req; + const gchar *text; + gchar *freq_text; + gint freq; + + text = (const gchar *) available_freqs->data; + freq = atoi (text); + + freq_text = cpufreq_utils_get_frequency_label (freq); + label = gtk_label_new (freq_text); + gtk_widget_size_request (label, &req); + + width = MAX (width, req.width); + + g_free (freq_text); + gtk_widget_destroy (label); + + available_freqs = g_list_next (available_freqs); + } + + applet->max_label_width = width; + + return width; +} + +static gint +cpufreq_applet_get_max_perc_width (CPUFreqApplet *applet) +{ + GtkWidget *label; + GtkRequisition req; + + if (applet->max_perc_width > 0) + return applet->max_perc_width; + + label = gtk_label_new ("100%"); + gtk_widget_size_request (label, &req); + applet->max_perc_width = req.width; + gtk_widget_destroy (label); + + return applet->max_perc_width; +} + +static gint +cpufreq_applet_get_max_unit_width (CPUFreqApplet *applet) +{ + GtkWidget *label; + GtkRequisition req; + gint w1, w2; + + if (applet->max_unit_width > 0) + return applet->max_unit_width; + + label = gtk_label_new ("GHz"); + gtk_widget_size_request (label, &req); + w1 = req.width; + + gtk_label_set_text (GTK_LABEL (label), "MHz"); + gtk_widget_size_request (label, &req); + w2 = req.width; + + gtk_widget_destroy (label); + + applet->max_unit_width = MAX (w1, w2); + + return applet->max_unit_width; +} + +static void +cpufreq_applet_size_request (GtkWidget *widget, GtkRequisition *requisition) +{ + CPUFreqApplet *applet; + gint labels_width = 0; + gint width; + + applet = CPUFREQ_APPLET (widget); + + GTK_WIDGET_CLASS (cpufreq_applet_parent_class)->size_request (widget, requisition); + + if (applet->orient == MATE_PANEL_APPLET_ORIENT_LEFT || + applet->orient == MATE_PANEL_APPLET_ORIENT_RIGHT) + return; + + if (applet->show_freq) { + labels_width += cpufreq_applet_get_max_label_width (applet) + 2; + } + + if (applet->show_perc) { + labels_width += cpufreq_applet_get_max_perc_width (applet); + } + + if (applet->show_unit) { + labels_width += cpufreq_applet_get_max_unit_width (applet); + } + + if (applet->show_icon) { + GtkRequisition req; + + gtk_widget_size_request (applet->icon, &req); + width = GTK_IS_HBOX (applet->box) ? + labels_width + req.width + 2 : + MAX (labels_width, req.width + 2); + } else { + width = labels_width; + } + + requisition->width = width; +} + +static void +cpufreq_applet_popup_position_menu (GtkMenu *menu, + int *x, + int *y, + gboolean *push_in, + gpointer gdata) +{ + GtkWidget *widget; + GtkRequisition requisition; + GtkAllocation allocation; + gint menu_xpos; + gint menu_ypos; + + widget = GTK_WIDGET (gdata); + + gtk_widget_size_request (GTK_WIDGET (menu), &requisition); + + gdk_window_get_origin (gtk_widget_get_window (widget), &menu_xpos, &menu_ypos); + + gtk_widget_get_allocation (widget, &allocation); + + menu_xpos += allocation.x; + menu_ypos += allocation.y; + + switch (mate_panel_applet_get_orient (MATE_PANEL_APPLET (widget))) { + case MATE_PANEL_APPLET_ORIENT_DOWN: + case MATE_PANEL_APPLET_ORIENT_UP: + if (menu_ypos > gdk_screen_get_height (gtk_widget_get_screen (widget)) / 2) + menu_ypos -= requisition.height; + else + menu_ypos += allocation.height; + break; + case MATE_PANEL_APPLET_ORIENT_RIGHT: + case MATE_PANEL_APPLET_ORIENT_LEFT: + if (menu_xpos > gdk_screen_get_width (gtk_widget_get_screen (widget)) / 2) + menu_xpos -= requisition.width; + else + menu_xpos += allocation.width; + break; + default: + g_assert_not_reached (); + } + + *x = menu_xpos; + *y = menu_ypos; + *push_in = TRUE; +} + +static void +cpufreq_applet_menu_popup (CPUFreqApplet *applet, + guint32 time) +{ + GtkWidget *menu; + + if (!cpufreq_utils_selector_is_available ()) + return; + + if (!applet->popup) { + applet->popup = cpufreq_popup_new (); + cpufreq_popup_set_monitor (applet->popup, applet->monitor); + cpufreq_popup_set_parent (applet->popup, GTK_WIDGET (applet)); + } + + menu = cpufreq_popup_get_menu (applet->popup); + + if (!menu) + return; + + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, + cpufreq_applet_popup_position_menu, + (gpointer) applet, + 1, time); +} + +static gboolean +cpufreq_applet_button_press (GtkWidget *widget, GdkEventButton *event) +{ + CPUFreqApplet *applet; + + applet = CPUFREQ_APPLET (widget); + + if (event->button == 2) + return FALSE; + + if (event->button == 1 && + event->type != GDK_2BUTTON_PRESS && + event->type != GDK_3BUTTON_PRESS) { + cpufreq_applet_menu_popup (applet, event->time); + + return TRUE; + } + + return GTK_WIDGET_CLASS (cpufreq_applet_parent_class)->button_press_event (widget, event); +} + +static gboolean +cpufreq_applet_key_press (GtkWidget *widget, GdkEventKey *event) +{ + CPUFreqApplet *applet; + + applet = CPUFREQ_APPLET (widget); + + switch (event->keyval) { + case GDK_KP_Enter: + case GDK_ISO_Enter: + case GDK_3270_Enter: + case GDK_Return: + case GDK_space: + case GDK_KP_Space: + cpufreq_applet_menu_popup (applet, event->time); + + return TRUE; + default: + break; + } + + return FALSE; +} + +static void +cpufreq_applet_change_orient (MatePanelApplet *pa, MatePanelAppletOrient orient) +{ + CPUFreqApplet *applet; + GtkAllocation allocation; + gint size; + + applet = CPUFREQ_APPLET (pa); + + applet->orient = orient; + + gtk_widget_get_allocation (GTK_WIDGET (applet), &allocation); + + if ((orient == MATE_PANEL_APPLET_ORIENT_LEFT) || + (orient == MATE_PANEL_APPLET_ORIENT_RIGHT)) { + size = allocation.width; + gtk_alignment_set (GTK_ALIGNMENT (applet->container), + 0.5, 0.5, 0, 0); + } else { + size = allocation.height; + gtk_alignment_set (GTK_ALIGNMENT (applet->container), + 0, 0.5, 0, 0); + } + + if (size != applet->size) { + applet->size = size; + cpufreq_applet_refresh (applet); + } +} + +static void +cpufreq_applet_preferences_cb (GtkAction *action, + CPUFreqApplet *applet) +{ + cpufreq_preferences_dialog_run (applet->prefs, + gtk_widget_get_screen (GTK_WIDGET (applet))); +} + +static void +cpufreq_applet_help_cb (GtkAction *action, + CPUFreqApplet *applet) +{ + GError *error = NULL; + + gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (applet)), + "ghelp:cpufreq-applet", + gtk_get_current_event_time (), + &error); + + if (error) { + cpufreq_utils_display_error (_("Could not open help document"), + error->message); + g_error_free (error); + } +} + +static void +cpufreq_applet_about_cb (GtkAction *action, + CPUFreqApplet *applet) +{ + static const gchar *const authors[] = { + "Carlos Garcia Campos <[email protected]>", + NULL + }; + static const gchar *const documenters[] = { + "Carlos Garcia Campos <[email protected]>", + "Davyd Madeley <[email protected]>", + NULL + }; + static const gchar *const artists[] = { + "Pablo Arroyo Loma <[email protected]>", + NULL + }; + + gtk_show_about_dialog (NULL, + "version", VERSION, + "copyright", "\xC2\xA9 2004 Carlos Garcia Campos", + "comments", _("This utility shows the current CPU " + "Frequency Scaling."), + "authors", authors, + "documenters", documenters, + "artists", artists, + "translator-credits", _("translator-credits"), + "logo-icon-name", "mate-cpu-frequency-applet", + NULL); +} + +static void +cpufreq_applet_pixmap_set_image (CPUFreqApplet *applet, gint perc) +{ + gint image; + + /* 0-29 -> 25% + * 30-69 -> 50% + * 70-89 -> 75% + * 90-100 -> 100% + */ + if (perc < 30) + image = 0; + else if ((perc >= 30) && (perc < 70)) + image = 1; + else if ((perc >= 70) && (perc < 90)) + image = 2; + else if ((perc >= 90) && (perc <= 100)) + image = 3; + else + image = 4; + + if (applet->pixbufs[image] == NULL) { + applet->pixbufs[image] = gdk_pixbuf_new_from_file_at_size (cpufreq_icons[image], + 24, 24, NULL); + } + + gtk_image_set_from_pixbuf (GTK_IMAGE (applet->icon), applet->pixbufs[image]); +} + +static gboolean +refresh_cb (CPUFreqApplet *applet) +{ + cpufreq_applet_refresh (applet); + + return FALSE; +} + +static void +cpufreq_applet_update_visibility (CPUFreqApplet *applet) +{ + CPUFreqShowMode show_mode; + CPUFreqShowTextMode show_text_mode; + gboolean show_freq = FALSE; + gboolean show_perc = FALSE; + gboolean show_unit = FALSE; + gboolean show_icon = FALSE; + gboolean changed = FALSE; + gboolean need_update = FALSE; + + show_mode = cpufreq_prefs_get_show_mode (applet->prefs); + show_text_mode = cpufreq_prefs_get_show_text_mode (applet->prefs); + + if (show_mode != CPUFREQ_MODE_GRAPHIC) { + show_icon = (show_mode == CPUFREQ_MODE_BOTH); + + switch (show_text_mode) { + case CPUFREQ_MODE_TEXT_FREQUENCY: + show_freq = TRUE; + break; + case CPUFREQ_MODE_TEXT_PERCENTAGE: + show_perc = TRUE; + break; + case CPUFREQ_MODE_TEXT_FREQUENCY_UNIT: + show_freq = TRUE; + show_unit = TRUE; + break; + } + } else { + show_icon = TRUE; + } + + if (applet->show_mode != show_mode) { + applet->show_mode = show_mode; + need_update = TRUE; + } + + if (applet->show_text_mode != show_text_mode) { + applet->show_text_mode = show_text_mode; + need_update = TRUE; + } + + if (show_freq != applet->show_freq) { + applet->show_freq = show_freq; + changed = TRUE; + } + + if (show_perc != applet->show_perc) { + applet->show_perc = show_perc; + changed = TRUE; + } + + if (changed) { + g_object_set (G_OBJECT (applet->label), + "visible", + applet->show_freq || applet->show_perc, + NULL); + } + + if (show_unit != applet->show_unit) { + applet->show_unit = show_unit; + changed = TRUE; + + g_object_set (G_OBJECT (applet->unit_label), + "visible", applet->show_unit, + NULL); + } + + if (show_icon != applet->show_icon) { + applet->show_icon = show_icon; + changed = TRUE; + + g_object_set (G_OBJECT (applet->icon), + "visible", applet->show_icon, + NULL); + } + + if (changed) + g_idle_add ((GSourceFunc)refresh_cb, applet); + + if (need_update) + cpufreq_applet_update (applet, applet->monitor); +} + +static void +cpufreq_applet_update (CPUFreqApplet *applet, CPUFreqMonitor *monitor) +{ + gchar *text_mode = NULL; + gchar *freq_label, *unit_label; + gint freq; + gint perc; + guint cpu; + const gchar *governor; + + cpu = cpufreq_monitor_get_cpu (monitor); + freq = cpufreq_monitor_get_frequency (monitor); + perc = cpufreq_monitor_get_percentage (monitor); + governor = cpufreq_monitor_get_governor (monitor); + + freq_label = cpufreq_utils_get_frequency_label (freq); + unit_label = cpufreq_utils_get_frequency_unit (freq); + + if (applet->show_freq) { + gtk_label_set_text (GTK_LABEL (applet->label), freq_label); + } + + if (applet->show_perc) { + gchar *text_perc; + + text_perc = g_strdup_printf ("%d%%", perc); + gtk_label_set_text (GTK_LABEL (applet->label), text_perc); + g_free (text_perc); + } + + if (applet->show_unit) { + gtk_label_set_text (GTK_LABEL (applet->unit_label), unit_label); + } + + if (applet->show_icon) { + cpufreq_applet_pixmap_set_image (applet, perc); + } + + if (governor) { + gchar *gov_text; + + gov_text = g_strdup (governor); + gov_text[0] = g_ascii_toupper (gov_text[0]); + text_mode = g_strdup_printf ("%s\n%s %s (%d%%)", + gov_text, freq_label, + unit_label, perc); + g_free (gov_text); + } + + g_free (freq_label); + g_free (unit_label); + + if (text_mode) { + gchar *text_tip; + + text_tip = cpufreq_utils_get_n_cpus () == 1 ? + g_strdup_printf ("%s", text_mode) : + g_strdup_printf ("CPU %u - %s", cpu, text_mode); + g_free (text_mode); + + gtk_widget_set_tooltip_text (GTK_WIDGET (applet), text_tip); + g_free (text_tip); + } + + /* Call refresh only the first time */ + if (applet->need_refresh) { + cpufreq_applet_refresh (applet); + applet->need_refresh = FALSE; + } +} + +static gint +cpufreq_applet_get_widget_size (CPUFreqApplet *applet, + GtkWidget *widget) +{ + GtkRequisition req; + gint size; + + if (!gtk_widget_get_visible (widget)) + return 0; + + gtk_widget_size_request (widget, &req); + + switch (applet->orient) { + case MATE_PANEL_APPLET_ORIENT_LEFT: + case MATE_PANEL_APPLET_ORIENT_RIGHT: + size = req.width; + break; + case MATE_PANEL_APPLET_ORIENT_UP: + case MATE_PANEL_APPLET_ORIENT_DOWN: + size = req.height; + break; + default: + g_assert_not_reached (); + } + + return size; +} + +static void +cpufreq_applet_refresh (CPUFreqApplet *applet) +{ + gint total_size = 0; + gint panel_size, label_size; + gint unit_label_size, pixmap_size; + gint size_step = 12; + gboolean horizontal; + gboolean do_unref = FALSE; + + panel_size = applet->size - 1; /* 1 pixel margin */ + + horizontal = (applet->orient == MATE_PANEL_APPLET_ORIENT_UP || + applet->orient == MATE_PANEL_APPLET_ORIENT_DOWN); + + /* We want a fixed label size, the biggest */ + if (horizontal) + label_size = cpufreq_applet_get_widget_size (applet, applet->label); + else + label_size = cpufreq_applet_get_max_label_width (applet); + total_size += label_size; + + if (horizontal) + unit_label_size = cpufreq_applet_get_widget_size (applet, applet->unit_label); + else + unit_label_size = cpufreq_applet_get_max_unit_width (applet); + total_size += unit_label_size; + + pixmap_size = cpufreq_applet_get_widget_size (applet, applet->icon); + total_size += pixmap_size; + + if (applet->box) { + do_unref = TRUE; + g_object_ref (applet->icon); + gtk_container_remove (GTK_CONTAINER (applet->box), applet->icon); + if (applet->labels_box) { + g_object_ref (applet->label); + gtk_container_remove (GTK_CONTAINER (applet->labels_box), applet->label); + g_object_ref (applet->unit_label); + gtk_container_remove (GTK_CONTAINER (applet->labels_box), applet->unit_label); + } + gtk_widget_destroy (applet->box); + } + + if (horizontal) { + applet->labels_box = gtk_hbox_new (FALSE, 2); + if ((label_size + pixmap_size) <= panel_size) + applet->box = gtk_vbox_new (FALSE, 2); + else + applet->box = gtk_hbox_new (FALSE, 2); + } else { + if (total_size <= panel_size) { + applet->box = gtk_hbox_new (FALSE, 2); + applet->labels_box = gtk_hbox_new (FALSE, 2); + } else if ((label_size + unit_label_size) <= (panel_size - size_step)) { + applet->box = gtk_vbox_new (FALSE, 2); + applet->labels_box = gtk_hbox_new (FALSE, 2); + } else { + applet->box = gtk_vbox_new (FALSE, 2); + applet->labels_box = gtk_vbox_new (FALSE, 2); + } + } + + gtk_box_pack_start (GTK_BOX (applet->labels_box), applet->label, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (applet->labels_box), applet->unit_label, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (applet->box), applet->icon, FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX (applet->box), applet->labels_box, FALSE, FALSE, 0); + gtk_widget_show (applet->labels_box); + + gtk_container_add (GTK_CONTAINER (applet->container), applet->box); + gtk_widget_show (applet->box); + + if (do_unref) { + g_object_unref (applet->label); + g_object_unref (applet->unit_label); + g_object_unref (applet->icon); + } +} + +/* Preferences callbacks */ +static void +cpufreq_applet_prefs_cpu_changed (CPUFreqPrefs *prefs, + GParamSpec *arg1, + CPUFreqApplet *applet) +{ + cpufreq_monitor_set_cpu (applet->monitor, + cpufreq_prefs_get_cpu (applet->prefs)); +} + +static void +cpufreq_applet_prefs_show_mode_changed (CPUFreqPrefs *prefs, + GParamSpec *arg1, + CPUFreqApplet *applet) +{ + cpufreq_applet_update_visibility (applet); +} + +static void +cpufreq_applet_setup (CPUFreqApplet *applet) +{ + GtkActionGroup *action_group; + gchar *ui_path; + AtkObject *atk_obj; + gchar *prefs_key; + + g_set_application_name (_("CPU Frequency Scaling Monitor")); + + gtk_window_set_default_icon_name ("mate-cpu-frequency-applet"); + + mate_panel_applet_add_preferences (MATE_PANEL_APPLET (applet), + "/schemas/apps/cpufreq-applet/prefs", NULL); + + /* Preferences */ + if (applet->prefs) + g_object_unref (applet->prefs); + + prefs_key = mate_panel_applet_get_preferences_key (MATE_PANEL_APPLET (applet)); + applet->prefs = cpufreq_prefs_new (prefs_key); + g_free (prefs_key); + + g_signal_connect (G_OBJECT (applet->prefs), + "notify::cpu", + G_CALLBACK (cpufreq_applet_prefs_cpu_changed), + (gpointer) applet); + g_signal_connect (G_OBJECT (applet->prefs), + "notify::show-mode", + G_CALLBACK (cpufreq_applet_prefs_show_mode_changed), + (gpointer) applet); + g_signal_connect (G_OBJECT (applet->prefs), + "notify::show-text-mode", + G_CALLBACK (cpufreq_applet_prefs_show_mode_changed), + (gpointer) applet); + + /* Monitor */ + applet->monitor = cpufreq_monitor_factory_create_monitor ( + cpufreq_prefs_get_cpu (applet->prefs)); + cpufreq_monitor_run (applet->monitor); + g_signal_connect_swapped (G_OBJECT (applet->monitor), "changed", + G_CALLBACK (cpufreq_applet_update), + (gpointer) applet); + + /* Setup the menus */ + action_group = gtk_action_group_new ("CPUFreq Applet Actions"); + gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE); + gtk_action_group_add_actions (action_group, + cpufreq_applet_menu_actions, + G_N_ELEMENTS (cpufreq_applet_menu_actions), + applet); + ui_path = g_build_filename (CPUFREQ_MENU_UI_DIR, "cpufreq-applet-menu.xml", NULL); + mate_panel_applet_setup_menu_from_file (MATE_PANEL_APPLET (applet), + ui_path, action_group); + g_free (ui_path); + + if (mate_panel_applet_get_locked_down (MATE_PANEL_APPLET (applet))) { + GtkAction *action; + + action = gtk_action_group_get_action (action_group, "CPUFreqPreferences"); + gtk_action_set_visible (action, FALSE); + } + g_object_unref (action_group); + + atk_obj = gtk_widget_get_accessible (GTK_WIDGET (applet)); + + if (GTK_IS_ACCESSIBLE (atk_obj)) { + atk_object_set_name (atk_obj, _("CPU Frequency Scaling Monitor")); + atk_object_set_description (atk_obj, _("This utility shows the current CPU Frequency")); + } + + cpufreq_applet_update_visibility (applet); + + gtk_widget_show (GTK_WIDGET (applet)); +} + +static gboolean +cpufreq_applet_factory (CPUFreqApplet *applet, const gchar *iid, gpointer gdata) +{ + gboolean retval = FALSE; + + if (!strcmp (iid, "CPUFreqApplet")) { + cpufreq_applet_setup (applet); + + retval = TRUE; + } + + return retval; +} + +MATE_PANEL_APPLET_OUT_PROCESS_FACTORY ("CPUFreqAppletFactory", + CPUFREQ_TYPE_APPLET, + "cpufreq-applet", + (MatePanelAppletFactoryCallback) cpufreq_applet_factory, + NULL) diff --git a/cpufreq/src/cpufreq-applet.h b/cpufreq/src/cpufreq-applet.h new file mode 100644 index 00000000..11d400a1 --- /dev/null +++ b/cpufreq/src/cpufreq-applet.h @@ -0,0 +1,61 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#ifndef CPUFREQ_APPLET_H +#define CPUFREQ_APPLET_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define CPUFREQ_TYPE_APPLET (cpufreq_applet_get_type ()) +#define CPUFREQ_APPLET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CPUFREQ_TYPE_APPLET, CPUFreqApplet)) +#define CPUFREQ_APPLET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), CPUFREQ_TYPE_APPLET, CPUFreqAppletClass)) +#define CPUFREQ_IS_APPLET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CPUFREQ_TYPE_APPLET)) +#define CPUFREQ_IS_APPLET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CPUFREQ_TYPE_APPLET)) +#define CPUFREQ_APPLET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CPUFREQ_TYPE_APPLET, CPUFreqAppletClass)) + +#define CPUFREQ_TYPE_SHOW_MODE (cpufreq_applet_show_mode_get_type ()) +#define CPUFREQ_TYPE_SHOW_TEXT_MODE (cpufreq_applet_show_text_mode_get_type ()) + +typedef struct _CPUFreqApplet CPUFreqApplet; +typedef struct _CPUFreqAppletClass CPUFreqAppletClass; + +typedef enum { + CPUFREQ_MODE_GRAPHIC, + CPUFREQ_MODE_TEXT, + CPUFREQ_MODE_BOTH +} CPUFreqShowMode; + +typedef enum { + CPUFREQ_MODE_TEXT_FREQUENCY, + CPUFREQ_MODE_TEXT_FREQUENCY_UNIT, + CPUFREQ_MODE_TEXT_PERCENTAGE +} CPUFreqShowTextMode; + +GType cpufreq_applet_get_type (void) G_GNUC_CONST; + +GType cpufreq_applet_show_mode_get_type (void) G_GNUC_CONST; +GType cpufreq_applet_show_text_mode_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* CPUFREQ_APPLET_H */ diff --git a/cpufreq/src/cpufreq-monitor-cpuinfo.c b/cpufreq/src/cpufreq-monitor-cpuinfo.c new file mode 100644 index 00000000..59585d8a --- /dev/null +++ b/cpufreq/src/cpufreq-monitor-cpuinfo.c @@ -0,0 +1,134 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#include <glib.h> +#include <glib/gi18n.h> + +#include <string.h> +#include <stdio.h> + +#include "cpufreq-monitor-cpuinfo.h" +#include "cpufreq-utils.h" + +static void cpufreq_monitor_cpuinfo_class_init (CPUFreqMonitorCPUInfoClass *klass); + +static gboolean cpufreq_monitor_cpuinfo_run (CPUFreqMonitor *monitor); + +G_DEFINE_TYPE (CPUFreqMonitorCPUInfo, cpufreq_monitor_cpuinfo, CPUFREQ_TYPE_MONITOR) + +static void +cpufreq_monitor_cpuinfo_init (CPUFreqMonitorCPUInfo *monitor) +{ +} + +static void +cpufreq_monitor_cpuinfo_class_init (CPUFreqMonitorCPUInfoClass *klass) +{ + CPUFreqMonitorClass *monitor_class = CPUFREQ_MONITOR_CLASS (klass); + + monitor_class->run = cpufreq_monitor_cpuinfo_run; +} + +CPUFreqMonitor * +cpufreq_monitor_cpuinfo_new (guint cpu) +{ + CPUFreqMonitorCPUInfo *monitor; + + monitor = g_object_new (CPUFREQ_TYPE_MONITOR_CPUINFO, "cpu", cpu, NULL); + + return CPUFREQ_MONITOR (monitor); +} + +static gboolean +cpufreq_monitor_cpuinfo_run (CPUFreqMonitor *monitor) +{ + gchar *file; + gchar **lines; + gchar *buffer = NULL; + gchar *p; + gint cpu, i; + gint cur_freq, max_freq; + gchar *governor; + GError *error = NULL; + + file = g_strdup ("/proc/cpuinfo"); + if (!cpufreq_file_get_contents (file, &buffer, NULL, &error)) { + g_warning ("%s", error->message); + g_error_free (error); + + g_free (file); + + return FALSE; + } + g_free (file); + + /* TODO: SMP support */ + lines = g_strsplit (buffer, "\n", -1); + for (i = 0; lines[i]; i++) { + if (g_ascii_strncasecmp ("cpu MHz", lines[i], strlen ("cpu MHz")) == 0) { + p = g_strrstr (lines[i], ":"); + + if (p == NULL) { + g_strfreev (lines); + g_free (buffer); + + return FALSE; + } + + if (strlen (lines[i]) < (size_t)(p - lines[i])) { + g_strfreev (lines); + g_free (buffer); + + return FALSE; + } + + if ((sscanf (p + 1, "%d.", &cpu)) != 1) { + g_strfreev (lines); + g_free (buffer); + + return FALSE; + } + + break; + } + } + + g_strfreev (lines); + g_free (buffer); + + governor = g_strdup (_("Frequency Scaling Unsupported")); + cur_freq = cpu * 1000; + max_freq = cur_freq; + + g_object_set (G_OBJECT (monitor), + "governor", governor, + "frequency", cur_freq, + "max-frequency", max_freq, + NULL); + + g_free (governor); + + return TRUE; +} + + + + diff --git a/cpufreq/src/cpufreq-monitor-cpuinfo.h b/cpufreq/src/cpufreq-monitor-cpuinfo.h new file mode 100644 index 00000000..ec58b405 --- /dev/null +++ b/cpufreq/src/cpufreq-monitor-cpuinfo.h @@ -0,0 +1,50 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#ifndef __CPUFREQ_MONITOR_CPUINFO_H__ +#define __CPUFREQ_MONITOR_CPUINFO_H__ + +#include <glib-object.h> + +#include "cpufreq-monitor.h" + +#define CPUFREQ_TYPE_MONITOR_CPUINFO (cpufreq_monitor_cpuinfo_get_type ()) +#define CPUFREQ_MONITOR_CPUINFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CPUFREQ_TYPE_MONITOR_CPUINFO, CPUFreqMonitorCPUInfo)) +#define CPUFREQ_MONITOR_CPUINFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), CPUFREQ_TYPE_MONITOR_CPUINFO, CPUFreqMonitorCPUInfoClass)) +#define CPUFREQ_IS_MONITOR_CPUINFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CPUFREQ_TYPE_MONITOR_CPUINFO)) +#define CPUFREQ_IS_MONITOR_CPUINFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CPUFREQ_TYPE_MONITOR_CPUINFO)) +#define CPUFREQ_MONITOR_CPUINFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CPUFREQ_TYPE_MONITOR_CPUINFO, CPUFreqMonitorCPUInfoClass)) + +typedef struct _CPUFreqMonitorCPUInfo CPUFreqMonitorCPUInfo; +typedef struct _CPUFreqMonitorCPUInfoClass CPUFreqMonitorCPUInfoClass; + +struct _CPUFreqMonitorCPUInfo { + CPUFreqMonitor parent; +}; + +struct _CPUFreqMonitorCPUInfoClass { + CPUFreqMonitorClass parent_class; +}; + +GType cpufreq_monitor_cpuinfo_get_type (void) G_GNUC_CONST; +CPUFreqMonitor *cpufreq_monitor_cpuinfo_new (guint cpu); + +#endif /* __CPUFREQ_MONITOR_CPUINFO_H__ */ diff --git a/cpufreq/src/cpufreq-monitor-factory.c b/cpufreq/src/cpufreq-monitor-factory.c new file mode 100644 index 00000000..8b68082c --- /dev/null +++ b/cpufreq/src/cpufreq-monitor-factory.c @@ -0,0 +1,69 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <glib.h> +#include <glib/gi18n.h> + +#include "cpufreq-applet.h" +#include "cpufreq-utils.h" +#include "cpufreq-monitor-sysfs.h" +#include "cpufreq-monitor-procfs.h" +#include "cpufreq-monitor-cpuinfo.h" +#ifdef HAVE_LIBCPUFREQ +#include "cpufreq-monitor-libcpufreq.h" +#endif +#include "cpufreq-monitor-factory.h" + +CPUFreqMonitor * +cpufreq_monitor_factory_create_monitor (guint cpu) +{ + CPUFreqMonitor *monitor = NULL; + +#ifdef HAVE_LIBCPUFREQ + monitor = cpufreq_monitor_libcpufreq_new (cpu); + return monitor; +#endif + + if (g_file_test ("/sys/devices/system/cpu/cpu0/cpufreq", G_FILE_TEST_EXISTS)) { /* 2.6 kernel */ + monitor = cpufreq_monitor_sysfs_new (cpu); + } else if (g_file_test ("/proc/cpufreq", G_FILE_TEST_EXISTS)) { /* 2.4 kernel (Deprecated)*/ + monitor = cpufreq_monitor_procfs_new (cpu); + } else if (g_file_test ("/proc/cpuinfo", G_FILE_TEST_EXISTS)) { + /* If there is no cpufreq support it shows only the cpu frequency, + * I think is better than do nothing. I have to notify it to the user, because + * he could think that cpufreq is supported but it doesn't work succesfully + */ + + cpufreq_utils_display_error (_("CPU frequency scaling unsupported"), + _("You will not be able to modify the frequency of your machine. " + "Your machine may be misconfigured or not have hardware support " + "for CPU frequency scaling.")); + + monitor = cpufreq_monitor_cpuinfo_new (cpu); + } + + return monitor; +} + diff --git a/cpufreq/src/cpufreq-monitor-factory.h b/cpufreq/src/cpufreq-monitor-factory.h new file mode 100644 index 00000000..6a14b5f1 --- /dev/null +++ b/cpufreq/src/cpufreq-monitor-factory.h @@ -0,0 +1,33 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#ifndef CPUFREQ_MONITOR_FACTORY_H +#define CPUFREQ_MONITOR_FACTORY_H + +#include "cpufreq-monitor.h" + +G_BEGIN_DECLS + +CPUFreqMonitor *cpufreq_monitor_factory_create_monitor (guint cpu); + +G_END_DECLS + +#endif /* CPUFREQ_MONITOR_FACTORY_H */ diff --git a/cpufreq/src/cpufreq-monitor-libcpufreq.c b/cpufreq/src/cpufreq-monitor-libcpufreq.c new file mode 100644 index 00000000..494d9a66 --- /dev/null +++ b/cpufreq/src/cpufreq-monitor-libcpufreq.c @@ -0,0 +1,199 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#include <glib.h> +#include <glib/gi18n.h> + +#include <stdlib.h> +#include <cpufreq.h> + +#include "cpufreq-monitor-libcpufreq.h" +#include "cpufreq-utils.h" + +static void cpufreq_monitor_libcpufreq_class_init (CPUFreqMonitorLibcpufreqClass *klass); + +static gboolean cpufreq_monitor_libcpufreq_run (CPUFreqMonitor *monitor); +static GList *cpufreq_monitor_libcpufreq_get_available_frequencies (CPUFreqMonitor *monitor); +static GList *cpufreq_monitor_libcpufreq_get_available_governors (CPUFreqMonitor *monitor); + +G_DEFINE_TYPE (CPUFreqMonitorLibcpufreq, cpufreq_monitor_libcpufreq, CPUFREQ_TYPE_MONITOR) + +typedef struct cpufreq_policy CPUFreqPolicy; +typedef struct cpufreq_available_frequencies CPUFreqFrequencyList; +typedef struct cpufreq_available_governors CPUFreqGovernorList; + +static void +cpufreq_monitor_libcpufreq_init (CPUFreqMonitorLibcpufreq *monitor) +{ +} + +static GObject * +cpufreq_monitor_libcpufreq_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_params) +{ + GObject *object; + gulong max_freq, min_freq; + guint cpu; + + object = G_OBJECT_CLASS ( + cpufreq_monitor_libcpufreq_parent_class)->constructor (type, + n_construct_properties, + construct_params); + g_object_get (G_OBJECT (object), + "cpu", &cpu, + NULL); + + if (cpufreq_get_hardware_limits (cpu, &min_freq, &max_freq) != 0) { + g_warning ("Error getting CPUINFO_MAX\n"); + max_freq = -1; + } + + g_object_set (G_OBJECT (object), + "max-frequency", max_freq, + NULL); + + return object; +} + +static void +cpufreq_monitor_libcpufreq_class_init (CPUFreqMonitorLibcpufreqClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CPUFreqMonitorClass *monitor_class = CPUFREQ_MONITOR_CLASS (klass); + + object_class->constructor = cpufreq_monitor_libcpufreq_constructor; + + monitor_class->run = cpufreq_monitor_libcpufreq_run; + monitor_class->get_available_frequencies = cpufreq_monitor_libcpufreq_get_available_frequencies; + monitor_class->get_available_governors = cpufreq_monitor_libcpufreq_get_available_governors; +} + +CPUFreqMonitor * +cpufreq_monitor_libcpufreq_new (guint cpu) +{ + CPUFreqMonitorLibcpufreq *monitor; + + monitor = g_object_new (CPUFREQ_TYPE_MONITOR_LIBCPUFREQ, + "cpu", cpu, NULL); + + return CPUFREQ_MONITOR (monitor); +} + +static gboolean +cpufreq_monitor_libcpufreq_run (CPUFreqMonitor *monitor) +{ + guint cpu; + CPUFreqPolicy *policy; + + g_object_get (G_OBJECT (monitor), "cpu", &cpu, NULL); + + policy = cpufreq_get_policy (cpu); + if (!policy) { + /* Check whether it failed because + * cpu is not online. + */ + if (!cpufreq_cpu_exists (cpu)) { + g_object_set (G_OBJECT (monitor), "online", FALSE, NULL); + return TRUE; + } + return FALSE; + } + + g_object_set (G_OBJECT (monitor), + "online", TRUE, + "governor", policy->governor, + "frequency", cpufreq_get_freq_kernel (cpu), + NULL); + + cpufreq_put_policy (policy); + + return TRUE; +} + +static gint +compare (gconstpointer a, gconstpointer b) +{ + gint aa, bb; + + aa = atoi ((gchar *) a); + bb = atoi ((gchar *) b); + + if (aa == bb) + return 0; + else if (aa > bb) + return -1; + else + return 1; +} + +static GList * +cpufreq_monitor_libcpufreq_get_available_frequencies (CPUFreqMonitor *monitor) +{ + GList *list = NULL; + guint cpu; + CPUFreqFrequencyList *freqs, *freq; + + g_object_get (G_OBJECT (monitor), + "cpu", &cpu, NULL); + + freqs = cpufreq_get_available_frequencies (cpu); + if (!freqs) + return NULL; + + for (freq = freqs; freq; freq = freq->next) { + gchar *frequency; + + frequency = g_strdup_printf ("%lu", freq->frequency); + + if (!g_list_find_custom (list, frequency, compare)) + list = g_list_prepend (list, frequency); + else + g_free (frequency); + } + + cpufreq_put_available_frequencies (freqs); + + return g_list_sort (list, compare); +} + +static GList * +cpufreq_monitor_libcpufreq_get_available_governors (CPUFreqMonitor *monitor) +{ + guint cpu; + GList *list = NULL; + CPUFreqGovernorList *govs, *gov; + + g_object_get (G_OBJECT (monitor), + "cpu", &cpu, NULL); + + govs = cpufreq_get_available_governors (cpu); + if (!govs) + return NULL; + + for (gov = govs; gov; gov = gov->next) { + list = g_list_prepend (list, g_strdup (gov->governor)); + } + + cpufreq_put_available_governors (govs); + + return list; +} diff --git a/cpufreq/src/cpufreq-monitor-libcpufreq.h b/cpufreq/src/cpufreq-monitor-libcpufreq.h new file mode 100644 index 00000000..7b41ea6b --- /dev/null +++ b/cpufreq/src/cpufreq-monitor-libcpufreq.h @@ -0,0 +1,56 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#ifndef __CPUFREQ_MONITOR_LIBCPUFREQ_H__ +#define __CPUFREQ_MONITOR_LIBCPUFREQ_H__ + +#include <glib-object.h> + +#include "cpufreq-monitor.h" + +#define CPUFREQ_TYPE_MONITOR_LIBCPUFREQ \ + (cpufreq_monitor_libcpufreq_get_type ()) +#define CPUFREQ_MONITOR_LIBCPUFREQ(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), CPUFREQ_TYPE_MONITOR_LIBCPUFREQ, CPUFreqMonitorLibcpufreq)) +#define CPUFREQ_MONITOR_LIBCPUFREQ_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), CPUFREQ_TYPE_MONITOR_LIBCPUFREQ, CPUFreqMonitorLibcpufreqClass)) +#define CPUFREQ_IS_MONITOR_LIBCPUFREQ(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CPUFREQ_TYPE_MONITOR_LIBCPUFREQ)) +#define CPUFREQ_IS_MONITOR_LIBCPUFREQ_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), CPUFREQ_TYPE_MONITOR_LIBCPUFREQ)) +#define CPUFREQ_MONITOR_LIBCPUFREQ_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), CPUFREQ_TYPE_MONITOR_LIBCPUFREQ, CPUFreqMonitorLibcpufreqClass)) + +typedef struct _CPUFreqMonitorLibcpufreq CPUFreqMonitorLibcpufreq; +typedef struct _CPUFreqMonitorLibcpufreqClass CPUFreqMonitorLibcpufreqClass; + +struct _CPUFreqMonitorLibcpufreq { + CPUFreqMonitor parent; +}; + +struct _CPUFreqMonitorLibcpufreqClass { + CPUFreqMonitorClass parent_class; +}; + +GType cpufreq_monitor_libcpufreq_get_type (void) G_GNUC_CONST; +CPUFreqMonitor *cpufreq_monitor_libcpufreq_new (guint cpu); + +#endif /* __CPUFREQ_MONITOR_LIBCPUFREQ_H__ */ diff --git a/cpufreq/src/cpufreq-monitor-procfs.c b/cpufreq/src/cpufreq-monitor-procfs.c new file mode 100644 index 00000000..97c635ba --- /dev/null +++ b/cpufreq/src/cpufreq-monitor-procfs.c @@ -0,0 +1,221 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#include <glib.h> +#include <glib/gi18n.h> + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include "cpufreq-monitor-procfs.h" +#include "cpufreq-utils.h" + +static void cpufreq_monitor_procfs_class_init (CPUFreqMonitorProcfsClass *klass); + +static gboolean cpufreq_monitor_procfs_run (CPUFreqMonitor *monitor); +static GList *cpufreq_monitor_procfs_get_available_frequencies (CPUFreqMonitor *monitor); + +G_DEFINE_TYPE (CPUFreqMonitorProcfs, cpufreq_monitor_procfs, CPUFREQ_TYPE_MONITOR) + +static void +cpufreq_monitor_procfs_init (CPUFreqMonitorProcfs *monitor) +{ +} + +static void +cpufreq_monitor_procfs_class_init (CPUFreqMonitorProcfsClass *klass) +{ + CPUFreqMonitorClass *monitor_class = CPUFREQ_MONITOR_CLASS (klass); + + monitor_class->run = cpufreq_monitor_procfs_run; + monitor_class->get_available_frequencies = cpufreq_monitor_procfs_get_available_frequencies; +} + +CPUFreqMonitor * +cpufreq_monitor_procfs_new (guint cpu) +{ + CPUFreqMonitorProcfs *monitor; + + monitor = g_object_new (TYPE_CPUFREQ_MONITOR_PROCFS, "cpu", cpu, NULL); + + return CPUFREQ_MONITOR (monitor); +} + +static gint +cpufreq_monitor_procfs_get_freq_from_userspace (guint cpu) +{ + gchar *buffer = NULL; + gchar *path; + gchar *p; + gchar *frequency; + gint freq; + gint len; + GError *error = NULL; + + path = g_strdup_printf ("/proc/sys/cpu/%u/speed", cpu); + + if (!cpufreq_file_get_contents (path, &buffer, NULL, &error)) { + g_warning ("%s", error->message); + g_error_free (error); + + g_free (path); + + return -1; + } + + g_free (path); + + /* Try to remove the '\n' */ + p = g_strrstr (buffer, "\n"); + len = strlen (buffer); + if (p) + len -= strlen (p); + + frequency = g_strndup (buffer, len); + g_free (buffer); + + freq = atoi (frequency); + g_free (frequency); + + return freq; +} + +static gboolean +cpufreq_monitor_procfs_parse (CPUFreqMonitorProcfs *monitor, + gint *cpu, + gint *fmax, + gint *pmin, + gint *pmax, + gint *fmin, + gchar *mode) +{ + gchar **lines; + gchar *buffer = NULL; + gint i, count; + guint mon_cpu; + GError *error = NULL; + + if (!cpufreq_file_get_contents ("/proc/cpufreq", &buffer, NULL, &error)) { + g_warning ("%s", error->message); + g_error_free (error); + + return FALSE; + } + + g_object_get (G_OBJECT (monitor), + "cpu", &mon_cpu, NULL); + + count = 0; + lines = g_strsplit (buffer, "\n", -1); + for (i = 0; lines[i]; i++) { + if (g_ascii_strncasecmp (lines[i], "CPU", 3) == 0) { + /* CPU 0 650000 kHz ( 81 %) - 800000 kHz (100 %) - powersave */ + count = sscanf (lines[i], "CPU %d %d kHz (%d %%) - %d kHz (%d %%) - %20s", + cpu, fmin, pmin, fmax, pmax, mode); + + if ((guint)(*cpu) == mon_cpu) + break; + } + } + + g_strfreev (lines); + g_free (buffer); + + return (count == 6); +} + +static gboolean +cpufreq_procfs_cpu_is_online (void) +{ + return g_file_test ("/proc/cpufreq", + G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR); +} + +static gboolean +cpufreq_monitor_procfs_run (CPUFreqMonitor *monitor) +{ + gint fmax, fmin, cpu; + gint pmin, pmax; + gchar mode[21]; + gint cur_freq, max_freq; + gchar *governor; + + if (!cpufreq_monitor_procfs_parse (CPUFREQ_MONITOR_PROCFS (monitor), + &cpu, &fmax, &pmin, &pmax, &fmin, mode)) { + /* Check whether it failed because + * cpu is not online. + */ + if (!cpufreq_procfs_cpu_is_online ()) { + g_object_set (G_OBJECT (monitor), "online", FALSE, NULL); + return TRUE; + } + return FALSE; + } + + governor = mode; + max_freq = fmax; + + if (g_ascii_strcasecmp (governor, "powersave") == 0) { + cur_freq = fmin; + } else if (g_ascii_strcasecmp (governor, "performance") == 0) { + cur_freq = fmax; + } else if (g_ascii_strcasecmp (governor, "userspace") == 0) { + cur_freq = cpufreq_monitor_procfs_get_freq_from_userspace (cpu); + } else { + cur_freq = fmax; + } + + g_object_set (G_OBJECT (monitor), + "online", TRUE, + "governor", governor, + "frequency", cur_freq, + "max-frequency", max_freq, + NULL); + + return TRUE; +} + +static GList * +cpufreq_monitor_procfs_get_available_frequencies (CPUFreqMonitor *monitor) +{ + gint fmax, fmin, cpu, freq; + gint pmin, pmax; + gchar mode[21]; + GList *list = NULL; + + if (!cpufreq_monitor_procfs_parse (CPUFREQ_MONITOR_PROCFS (monitor), &cpu, + &fmax, &pmin, &pmax, &fmin, mode)) { + return NULL; + } + + if ((pmax > 0) && (pmax != 100)) { + freq = (fmax * 100) / pmax; + list = g_list_prepend (list, g_strdup_printf ("%d", freq)); + } + + list = g_list_prepend (list, g_strdup_printf ("%d", fmax)); + if (fmax != fmin) + list = g_list_prepend (list, g_strdup_printf ("%d", fmin)); + + return g_list_reverse (list); +} + diff --git a/cpufreq/src/cpufreq-monitor-procfs.h b/cpufreq/src/cpufreq-monitor-procfs.h new file mode 100644 index 00000000..62649152 --- /dev/null +++ b/cpufreq/src/cpufreq-monitor-procfs.h @@ -0,0 +1,54 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#ifndef __CPUFREQ_MONITOR_PROCFS_H__ +#define __CPUFREQ_MONITOR_PROCFS_H__ + +#include <glib-object.h> + +#include "cpufreq-monitor.h" + +G_BEGIN_DECLS + +#define TYPE_CPUFREQ_MONITOR_PROCFS (cpufreq_monitor_procfs_get_type ()) +#define CPUFREQ_MONITOR_PROCFS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_CPUFREQ_MONITOR_PROCFS, CPUFreqMonitorProcfs)) +#define CPUFREQ_MONITOR_PROCFS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_CPUFREQ_MONITOR_PROCFS, CPUFreqMonitorProcfsClass)) +#define IS_CPUFREQ_MONITOR_PROCFS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_CPUFREQ_MONITOR_PROCFS)) +#define IS_CPUFREQ_MONITOR_PROCFS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_CPUFREQ_MONITOR_PROCFS)) +#define CPUFREQ_MONITOR_PROCFS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_CPUFREQ_MONITOR_PROCFS, CPUFreqMonitorProcfsClass)) + +typedef struct _CPUFreqMonitorProcfs CPUFreqMonitorProcfs; +typedef struct _CPUFreqMonitorProcfsClass CPUFreqMonitorProcfsClass; + +struct _CPUFreqMonitorProcfs { + CPUFreqMonitor parent; +}; + +struct _CPUFreqMonitorProcfsClass { + CPUFreqMonitorClass parent_class; +}; + +GType cpufreq_monitor_procfs_get_type (void) G_GNUC_CONST; +CPUFreqMonitor *cpufreq_monitor_procfs_new (guint cpu); + +G_END_DECLS + +#endif /* __CPUFREQ_MONITOR_PROCFS_H__ */ diff --git a/cpufreq/src/cpufreq-monitor-sysfs.c b/cpufreq/src/cpufreq-monitor-sysfs.c new file mode 100644 index 00000000..a123a36f --- /dev/null +++ b/cpufreq/src/cpufreq-monitor-sysfs.c @@ -0,0 +1,345 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#include <glib.h> +#include <glib/gi18n.h> + +#include <string.h> +#include <stdlib.h> + +#include "cpufreq-monitor-sysfs.h" +#include "cpufreq-utils.h" + +enum { + SCALING_MAX, + SCALING_MIN, + GOVERNOR, + CPUINFO_MAX, + SCALING_SETSPEED, + SCALING_CUR_FREQ, + N_FILES +}; + +static void cpufreq_monitor_sysfs_class_init (CPUFreqMonitorSysfsClass *klass); + +static gboolean cpufreq_monitor_sysfs_run (CPUFreqMonitor *monitor); +static GList *cpufreq_monitor_sysfs_get_available_frequencies (CPUFreqMonitor *monitor); +static GList *cpufreq_monitor_sysfs_get_available_governors (CPUFreqMonitor *monitor); + +static gchar *cpufreq_sysfs_read (const gchar *path, + GError **error); + +/* /sys/devices/system/cpu/cpu[0]/cpufreq/scaling_max_freq + * /sys/devices/system/cpu/cpu[0]/cpufreq/scaling_min_freq + * /sys/devices/system/cpu/cpu[0]/cpufreq/scaling_governor + * /sys/devices/system/cpu/cpu[0]/cpufreq/cpuinfo_max_freq + * /sys/devices/system/cpu/cpu[0]/cpufreq/scaling_setspeed (userspace) + * /sys/devices/system/cpu/cpu[0]/cpufreq/scaling_cur_freq (new governors) + */ +const gchar *monitor_sysfs_files[] = { + "scaling_max_freq", + "scaling_min_freq", + "scaling_governor", + "cpuinfo_max_freq", + "scaling_setspeed", + "scaling_cur_freq", + NULL +}; + +#define CPUFREQ_SYSFS_BASE_PATH "/sys/devices/system/cpu/cpu%u/cpufreq/%s" + +G_DEFINE_TYPE (CPUFreqMonitorSysfs, cpufreq_monitor_sysfs, CPUFREQ_TYPE_MONITOR) + +static void +cpufreq_monitor_sysfs_init (CPUFreqMonitorSysfs *monitor) +{ +} + +static GObject * +cpufreq_monitor_sysfs_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_params) +{ + GObject *object; + gchar *path; + gchar *frequency; + gint max_freq; + guint cpu; + GError *error = NULL; + + object = G_OBJECT_CLASS ( + cpufreq_monitor_sysfs_parent_class)->constructor (type, + n_construct_properties, + construct_params); + g_object_get (G_OBJECT (object), + "cpu", &cpu, + NULL); + + path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, + cpu, monitor_sysfs_files[CPUINFO_MAX]); + + frequency = cpufreq_sysfs_read (path, &error); + if (!frequency) { + g_warning ("%s", error->message); + g_error_free (error); + max_freq = -1; + } else { + max_freq = atoi (frequency); + } + + g_free (path); + g_free (frequency); + + g_object_set (G_OBJECT (object), + "max-frequency", max_freq, + NULL); + + return object; +} + +static void +cpufreq_monitor_sysfs_class_init (CPUFreqMonitorSysfsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CPUFreqMonitorClass *monitor_class = CPUFREQ_MONITOR_CLASS (klass); + + object_class->constructor = cpufreq_monitor_sysfs_constructor; + + monitor_class->run = cpufreq_monitor_sysfs_run; + monitor_class->get_available_frequencies = cpufreq_monitor_sysfs_get_available_frequencies; + monitor_class->get_available_governors = cpufreq_monitor_sysfs_get_available_governors; +} + +CPUFreqMonitor * +cpufreq_monitor_sysfs_new (guint cpu) +{ + CPUFreqMonitorSysfs *monitor; + + monitor = g_object_new (CPUFREQ_TYPE_MONITOR_SYSFS, + "cpu", cpu, NULL); + + return CPUFREQ_MONITOR (monitor); +} + +static gchar * +cpufreq_sysfs_read (const gchar *path, + GError **error) +{ + gchar *buffer = NULL; + + if (!cpufreq_file_get_contents (path, &buffer, NULL, error)) { + return NULL; + } + + return g_strchomp (buffer); +} + +static gboolean +cpufreq_sysfs_cpu_is_online (guint cpu) +{ + gchar *path; + gboolean retval; + + path = g_strdup_printf ("/sys/devices/system/cpu/cpu%u/", cpu); + retval = g_file_test (path, G_FILE_TEST_IS_DIR); + g_free (path); + + return retval; +} + +static gboolean +cpufreq_monitor_sysfs_run (CPUFreqMonitor *monitor) +{ + guint cpu; + gchar *frequency; + gchar *governor; + gchar *path; + GError *error = NULL; + + g_object_get (G_OBJECT (monitor), + "cpu", &cpu, + NULL); + + path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, + cpu, monitor_sysfs_files[GOVERNOR]); + governor = cpufreq_sysfs_read (path, &error); + if (!governor) { + gboolean retval = FALSE; + + /* Check whether it failed because + * cpu is not online. + */ + if (!cpufreq_sysfs_cpu_is_online (cpu)) { + g_object_set (G_OBJECT (monitor), "online", FALSE, NULL); + retval = TRUE; + } else { + g_warning ("%s", error->message); + } + + g_error_free (error); + g_free (path); + + return retval; + } + + g_free (path); + + if (g_ascii_strcasecmp (governor, "userspace") == 0) { + path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, + cpu, monitor_sysfs_files[SCALING_SETSPEED]); + } else if (g_ascii_strcasecmp (governor, "powersave") == 0) { + path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, + cpu, monitor_sysfs_files[SCALING_MIN]); + } else if (g_ascii_strcasecmp (governor, "performance") == 0) { + path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, + cpu, monitor_sysfs_files[SCALING_MAX]); + } else { /* Ondemand, Conservative, ... */ + path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, + cpu, monitor_sysfs_files[SCALING_CUR_FREQ]); + } + + frequency = cpufreq_sysfs_read (path, &error); + if (!frequency) { + g_warning ("%s", error->message); + g_error_free (error); + g_free (path); + g_free (governor); + + return FALSE; + } + + g_free (path); + + g_object_set (G_OBJECT (monitor), + "online", TRUE, + "governor", governor, + "frequency", atoi (frequency), + NULL); + + g_free (governor); + g_free (frequency); + + return TRUE; +} + +static gint +compare (gconstpointer a, gconstpointer b) +{ + gint aa, bb; + + aa = atoi ((gchar *) a); + bb = atoi ((gchar *) b); + + if (aa == bb) + return 0; + else if (aa > bb) + return -1; + else + return 1; +} + +static GList * +cpufreq_monitor_sysfs_get_available_frequencies (CPUFreqMonitor *monitor) +{ + gchar *path; + GList *list = NULL; + gchar **frequencies = NULL; + gint i; + guint cpu; + gchar *buffer = NULL; + GError *error = NULL; + + g_object_get (G_OBJECT (monitor), + "cpu", &cpu, NULL); + + path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, cpu, + "scaling_available_frequencies"); + + if (!cpufreq_file_get_contents (path, &buffer, NULL, &error)) { + g_warning ("%s", error->message); + g_error_free (error); + + g_free (path); + + return NULL; + } + + g_free (path); + + buffer = g_strchomp (buffer); + frequencies = g_strsplit (buffer, " ", -1); + + i = 0; + while (frequencies[i]) { + if (!g_list_find_custom (list, frequencies[i], compare)) + list = g_list_prepend (list, g_strdup (frequencies[i])); + i++; + } + + g_strfreev (frequencies); + g_free (buffer); + + return g_list_sort (list, compare); +} + +static GList * +cpufreq_monitor_sysfs_get_available_governors (CPUFreqMonitor *monitor) +{ + gchar *path; + GList *list = NULL; + gchar **governors = NULL; + gint i; + guint cpu; + gchar *buffer = NULL; + GError *error = NULL; + + g_object_get (G_OBJECT (monitor), + "cpu", &cpu, NULL); + + path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, cpu, + "scaling_available_governors"); + + if (!cpufreq_file_get_contents (path, &buffer, NULL, &error)) { + g_warning ("%s", error->message); + g_error_free (error); + + g_free (path); + + return NULL; + } + + g_free (path); + + buffer = g_strchomp (buffer); + + governors = g_strsplit (buffer, " ", -1); + + i = 0; + while (governors[i] != NULL) { + list = g_list_prepend (list, g_strdup (governors[i])); + i++; + } + + g_strfreev (governors); + g_free (buffer); + + return list; +} diff --git a/cpufreq/src/cpufreq-monitor-sysfs.h b/cpufreq/src/cpufreq-monitor-sysfs.h new file mode 100644 index 00000000..ee75dd9b --- /dev/null +++ b/cpufreq/src/cpufreq-monitor-sysfs.h @@ -0,0 +1,54 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#ifndef __CPUFREQ_MONITOR_SYSFS_H__ +#define __CPUFREQ_MONITOR_SYSFS_H__ + +#include <glib-object.h> + +#include "cpufreq-monitor.h" + +G_BEGIN_DECLS + +#define CPUFREQ_TYPE_MONITOR_SYSFS (cpufreq_monitor_sysfs_get_type ()) +#define CPUFREQ_MONITOR_SYSFS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CPUFREQ_TYPE_MONITOR_SYSFS, CPUFreqMonitorSysfs)) +#define CPUFREQ_MONITOR_SYSFS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), CPUFREQ_TYPE_MONITOR_SYSFS, CPUFreqMonitorSysfsClass)) +#define CPUFREQ_IS_MONITOR_SYSFS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CPUFREQ_TYPE_MONITOR_SYSFS)) +#define CPUFREQ_IS_MONITOR_SYSFS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CPUFREQ_TYPE_MONITOR_SYSFS)) +#define CPUFREQ_MONITOR_SYSFS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CPUFREQ_TYPE_MONITOR_SYSFS, CPUFreqMonitorSysfsClass)) + +typedef struct _CPUFreqMonitorSysfs CPUFreqMonitorSysfs; +typedef struct _CPUFreqMonitorSysfsClass CPUFreqMonitorSysfsClass; + +struct _CPUFreqMonitorSysfs { + CPUFreqMonitor parent; +}; + +struct _CPUFreqMonitorSysfsClass { + CPUFreqMonitorClass parent_class; +}; + +GType cpufreq_monitor_sysfs_get_type (void) G_GNUC_CONST; +CPUFreqMonitor *cpufreq_monitor_sysfs_new (guint cpu); + +G_END_DECLS + +#endif /* __CPUFREQ_MONITOR_SYSFS_H__ */ diff --git a/cpufreq/src/cpufreq-monitor.c b/cpufreq/src/cpufreq-monitor.c new file mode 100644 index 00000000..662c94a9 --- /dev/null +++ b/cpufreq/src/cpufreq-monitor.c @@ -0,0 +1,411 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#include "cpufreq-monitor.h" + +#define CPUFREQ_MONITOR_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), CPUFREQ_TYPE_MONITOR, CPUFreqMonitorPrivate)) + +#define CPUFREQ_MONITOR_INTERVAL 1 + +/* Properties */ +enum { + PROP_0, + PROP_CPU, + PROP_ONLINE, + PROP_FREQUENCY, + PROP_MAX_FREQUENCY, + PROP_GOVERNOR +}; + +/* Signals */ +enum { + SIGNAL_CHANGED, + N_SIGNALS +}; + +struct _CPUFreqMonitorPrivate { + guint cpu; + gboolean online; + gint cur_freq; + gint max_freq; + gchar *governor; + GList *available_freqs; + GList *available_govs; + guint timeout_handler; + + gboolean changed; +}; + +static void cpufreq_monitor_init (CPUFreqMonitor *monitor); +static void cpufreq_monitor_class_init (CPUFreqMonitorClass *klass); +static void cpufreq_monitor_finalize (GObject *object); + +static void cpufreq_monitor_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *spec); +static void cpufreq_monitor_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *spec); + +static guint signals[N_SIGNALS]; + +G_DEFINE_ABSTRACT_TYPE (CPUFreqMonitor, cpufreq_monitor, G_TYPE_OBJECT) + +static void +cpufreq_monitor_init (CPUFreqMonitor *monitor) +{ + monitor->priv = CPUFREQ_MONITOR_GET_PRIVATE (monitor); + + monitor->priv->governor = NULL; + monitor->priv->available_freqs = NULL; + monitor->priv->available_govs = NULL; + monitor->priv->timeout_handler = 0; + + monitor->priv->changed = FALSE; +} + +static void +cpufreq_monitor_class_init (CPUFreqMonitorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = cpufreq_monitor_set_property; + object_class->get_property = cpufreq_monitor_get_property; + + /* Public virtual methods */ + klass->run = NULL; + klass->get_available_frequencies = NULL; + klass->get_available_governors = NULL; + + g_type_class_add_private (klass, sizeof (CPUFreqMonitorPrivate)); + + /* Porperties */ + g_object_class_install_property (object_class, + PROP_CPU, + g_param_spec_uint ("cpu", + "CPU", + "The cpu to monitor", + 0, + G_MAXUINT, + 0, + G_PARAM_CONSTRUCT | + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_ONLINE, + g_param_spec_boolean ("online", + "Online", + "Whether cpu is online", + TRUE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_FREQUENCY, + g_param_spec_int ("frequency", + "Frequency", + "The current cpu frequency", + 0, + G_MAXINT, + 0, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_MAX_FREQUENCY, + g_param_spec_int ("max-frequency", + "MaxFrequency", + "The max cpu frequency", + 0, + G_MAXINT, + 0, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_GOVERNOR, + g_param_spec_string ("governor", + "Governor", + "The current cpufreq governor", + NULL, + G_PARAM_READWRITE)); + + /* Signals */ + signals[SIGNAL_CHANGED] = + g_signal_new ("changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CPUFreqMonitorClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + object_class->finalize = cpufreq_monitor_finalize; +} + +static void +cpufreq_monitor_finalize (GObject *object) +{ + CPUFreqMonitor *monitor = CPUFREQ_MONITOR (object); + + monitor->priv->online = FALSE; + + if (monitor->priv->timeout_handler > 0) { + g_source_remove (monitor->priv->timeout_handler); + monitor->priv->timeout_handler = 0; + } + + if (monitor->priv->governor) { + g_free (monitor->priv->governor); + monitor->priv->governor = NULL; + } + + if (monitor->priv->available_freqs) { + g_list_foreach (monitor->priv->available_freqs, + (GFunc) g_free, + NULL); + g_list_free (monitor->priv->available_freqs); + monitor->priv->available_freqs = NULL; + } + + if (monitor->priv->available_govs) { + g_list_foreach (monitor->priv->available_govs, + (GFunc) g_free, + NULL); + g_list_free (monitor->priv->available_govs); + monitor->priv->available_govs = NULL; + } + + G_OBJECT_CLASS (cpufreq_monitor_parent_class)->finalize (object); +} + +static void +cpufreq_monitor_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *spec) +{ + CPUFreqMonitor *monitor; + + monitor = CPUFREQ_MONITOR (object); + + switch (prop_id) { + case PROP_CPU: { + guint cpu = g_value_get_uint (value); + + if (cpu != monitor->priv->cpu) { + monitor->priv->cpu = cpu; + monitor->priv->changed = TRUE; + } + } + break; + case PROP_ONLINE: + monitor->priv->online = g_value_get_boolean (value); + + break; + case PROP_FREQUENCY: { + gint freq = g_value_get_int (value); + + if (freq != monitor->priv->cur_freq) { + monitor->priv->cur_freq = freq; + monitor->priv->changed = TRUE; + } + } + break; + case PROP_MAX_FREQUENCY: { + gint freq = g_value_get_int (value); + + if (freq != monitor->priv->max_freq) { + monitor->priv->max_freq = freq; + monitor->priv->changed = TRUE; + } + } + break; + case PROP_GOVERNOR: { + const gchar *gov = g_value_get_string (value); + + if (monitor->priv->governor) { + if (g_ascii_strcasecmp (gov, monitor->priv->governor) != 0) { + g_free (monitor->priv->governor); + monitor->priv->governor = gov ? g_strdup (gov) : NULL; + monitor->priv->changed = TRUE; + } + } else { + monitor->priv->governor = gov ? g_strdup (gov) : NULL; + monitor->priv->changed = TRUE; + } + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, spec); + break; + } +} + +static void +cpufreq_monitor_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *spec) +{ + CPUFreqMonitor *monitor; + + monitor = CPUFREQ_MONITOR (object); + + switch (prop_id) { + case PROP_CPU: + g_value_set_uint (value, monitor->priv->cpu); + break; + case PROP_ONLINE: + g_value_set_boolean (value, monitor->priv->online); + break; + case PROP_FREQUENCY: + g_value_set_int (value, monitor->priv->cur_freq); + break; + case PROP_MAX_FREQUENCY: + g_value_set_int (value, monitor->priv->max_freq); + break; + case PROP_GOVERNOR: + g_value_set_string (value, monitor->priv->governor); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, spec); + break; + } +} + +static gboolean +cpufreq_monitor_run_cb (CPUFreqMonitor *monitor) +{ + CPUFreqMonitorClass *class; + gboolean retval = FALSE; + + class = CPUFREQ_MONITOR_GET_CLASS (monitor); + + if (class->run) + retval = class->run (monitor); + + if (monitor->priv->changed) { + g_signal_emit (monitor, signals[SIGNAL_CHANGED], 0); + monitor->priv->changed = FALSE; + } + + return retval; +} + +void +cpufreq_monitor_run (CPUFreqMonitor *monitor) +{ + g_return_if_fail (CPUFREQ_IS_MONITOR (monitor)); + + if (monitor->priv->timeout_handler > 0) + return; + + monitor->priv->timeout_handler = + g_timeout_add_seconds (CPUFREQ_MONITOR_INTERVAL, + (GSourceFunc) cpufreq_monitor_run_cb, + (gpointer) monitor); +} + +GList * +cpufreq_monitor_get_available_frequencies (CPUFreqMonitor *monitor) +{ + CPUFreqMonitorClass *class; + + g_return_val_if_fail (CPUFREQ_IS_MONITOR (monitor), NULL); + + if (!monitor->priv->online) + return NULL; + + if (monitor->priv->available_freqs) + return monitor->priv->available_freqs; + + class = CPUFREQ_MONITOR_GET_CLASS (monitor); + + if (class->get_available_frequencies) { + monitor->priv->available_freqs = class->get_available_frequencies (monitor); + } + + return monitor->priv->available_freqs; +} + +GList * +cpufreq_monitor_get_available_governors (CPUFreqMonitor *monitor) +{ + CPUFreqMonitorClass *class; + + g_return_val_if_fail (CPUFREQ_IS_MONITOR (monitor), NULL); + + if (!monitor->priv->online) + return NULL; + + if (monitor->priv->available_govs) + return monitor->priv->available_govs; + + class = CPUFREQ_MONITOR_GET_CLASS (monitor); + + if (class->get_available_governors) { + monitor->priv->available_govs = class->get_available_governors (monitor); + } + + return monitor->priv->available_govs; +} + +guint +cpufreq_monitor_get_cpu (CPUFreqMonitor *monitor) +{ + g_return_val_if_fail (CPUFREQ_IS_MONITOR (monitor), 0); + + return monitor->priv->cpu; +} + +void +cpufreq_monitor_set_cpu (CPUFreqMonitor *monitor, guint cpu) +{ + g_return_if_fail (CPUFREQ_IS_MONITOR (monitor)); + + g_object_set (G_OBJECT (monitor), + "cpu", cpu, NULL); +} + +gint +cpufreq_monitor_get_frequency (CPUFreqMonitor *monitor) +{ + g_return_val_if_fail (CPUFREQ_IS_MONITOR (monitor), -1); + + return monitor->priv->cur_freq; +} + +const gchar * +cpufreq_monitor_get_governor (CPUFreqMonitor *monitor) +{ + g_return_val_if_fail (CPUFREQ_IS_MONITOR (monitor), NULL); + + return monitor->priv->governor; +} + +gint +cpufreq_monitor_get_percentage (CPUFreqMonitor *monitor) +{ + g_return_val_if_fail (CPUFREQ_IS_MONITOR (monitor), -1); + + if (monitor->priv->max_freq > 0) { + return ((monitor->priv->cur_freq * 100) / monitor->priv->max_freq); + } + + return -1; +} diff --git a/cpufreq/src/cpufreq-monitor.h b/cpufreq/src/cpufreq-monitor.h new file mode 100644 index 00000000..0b9ac508 --- /dev/null +++ b/cpufreq/src/cpufreq-monitor.h @@ -0,0 +1,72 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#ifndef __CPUFREQ_MONITOR_H__ +#define __CPUFREQ_MONITOR_H__ + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define CPUFREQ_TYPE_MONITOR (cpufreq_monitor_get_type ()) +#define CPUFREQ_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CPUFREQ_TYPE_MONITOR, CPUFreqMonitor)) +#define CPUFREQ_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), CPUFREQ_TYPE_MONITOR, CPUFreqMonitorClass)) +#define CPUFREQ_IS_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CPUFREQ_TYPE_MONITOR)) +#define CPUFREQ_IS_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CPUFREQ_TYPE_MONITOR)) +#define CPUFREQ_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CPUFREQ_TYPE_MONITOR, CPUFreqMonitorClass)) + +typedef struct _CPUFreqMonitor CPUFreqMonitor; +typedef struct _CPUFreqMonitorClass CPUFreqMonitorClass; +typedef struct _CPUFreqMonitorPrivate CPUFreqMonitorPrivate; + +struct _CPUFreqMonitor { + GObject parent; + + CPUFreqMonitorPrivate *priv; +}; + +struct _CPUFreqMonitorClass { + GObjectClass parent_class; + + gboolean (* run) (CPUFreqMonitor *monitor); + GList *(* get_available_frequencies) (CPUFreqMonitor *monitor); + GList *(* get_available_governors) (CPUFreqMonitor *monitor); + + /*< signals >*/ + void (* changed) (CPUFreqMonitor *monitor); +}; + +GType cpufreq_monitor_get_type (void) G_GNUC_CONST; + +void cpufreq_monitor_run (CPUFreqMonitor *monitor); +GList *cpufreq_monitor_get_available_frequencies (CPUFreqMonitor *monitor); +GList *cpufreq_monitor_get_available_governors (CPUFreqMonitor *monitor); + +guint cpufreq_monitor_get_cpu (CPUFreqMonitor *monitor); +void cpufreq_monitor_set_cpu (CPUFreqMonitor *monitor, + guint cpu); +const gchar *cpufreq_monitor_get_governor (CPUFreqMonitor *monitor); +gint cpufreq_monitor_get_frequency (CPUFreqMonitor *monitor); +gint cpufreq_monitor_get_percentage (CPUFreqMonitor *monitor); + +G_END_DECLS + +#endif /* __CPUFREQ_MONITOR_H__ */ diff --git a/cpufreq/src/cpufreq-popup.c b/cpufreq/src/cpufreq-popup.c new file mode 100644 index 00000000..8486c2b3 --- /dev/null +++ b/cpufreq/src/cpufreq-popup.c @@ -0,0 +1,509 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#include <glib/gi18n.h> + +#include <gtk/gtk.h> +#include <gdk/gdkx.h> +#include <stdlib.h> +#include <string.h> + +#include "cpufreq-popup.h" +#include "cpufreq-selector.h" +#include "cpufreq-utils.h" + +struct _CPUFreqPopupPrivate { + GtkUIManager *ui_manager; + GSList *radio_group; + + GtkActionGroup *freqs_group; + GSList *freqs_actions; + + GtkActionGroup *govs_group; + GSList *govs_actions; + + guint merge_id; + gboolean need_build; + gboolean show_freqs; + + CPUFreqMonitor *monitor; + GtkWidget *parent; +}; + +#define CPUFREQ_POPUP_GET_PRIVATE(object) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((object), CPUFREQ_TYPE_POPUP, CPUFreqPopupPrivate)) + +static void cpufreq_popup_init (CPUFreqPopup *popup); +static void cpufreq_popup_class_init (CPUFreqPopupClass *klass); +static void cpufreq_popup_finalize (GObject *object); + +G_DEFINE_TYPE (CPUFreqPopup, cpufreq_popup, G_TYPE_OBJECT) + +static const gchar *ui_popup = +"<ui>" +" <popup name=\"CPUFreqSelectorPopup\" action=\"PopupAction\">" +" <placeholder name=\"FreqsItemsGroup\">" +" </placeholder>" +" <separator />" +" <placeholder name=\"GovsItemsGroup\">" +" </placeholder>" +" </popup>" +"</ui>"; + +#define FREQS_PLACEHOLDER_PATH "/CPUFreqSelectorPopup/FreqsItemsGroup" +#define GOVS_PLACEHOLDER_PATH "/CPUFreqSelectorPopup/GovsItemsGroup" + +static void +cpufreq_popup_init (CPUFreqPopup *popup) +{ + popup->priv = CPUFREQ_POPUP_GET_PRIVATE (popup); + + popup->priv->ui_manager = gtk_ui_manager_new (); + popup->priv->radio_group = NULL; + + popup->priv->freqs_group = NULL; + popup->priv->freqs_actions = NULL; + + popup->priv->govs_group = NULL; + popup->priv->govs_actions = NULL; + + popup->priv->merge_id = 0; + popup->priv->need_build = TRUE; + popup->priv->show_freqs = FALSE; + + gtk_ui_manager_add_ui_from_string (popup->priv->ui_manager, + ui_popup, -1, NULL); + + popup->priv->monitor = NULL; +} + +static void +cpufreq_popup_class_init (CPUFreqPopupClass *klass) +{ + GObjectClass *g_object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (g_object_class, sizeof (CPUFreqPopupPrivate)); + + g_object_class->finalize = cpufreq_popup_finalize; +} + +static void +cpufreq_popup_finalize (GObject *object) +{ + CPUFreqPopup *popup = CPUFREQ_POPUP (object); + + if (popup->priv->ui_manager) { + g_object_unref (popup->priv->ui_manager); + popup->priv->ui_manager = NULL; + } + + if (popup->priv->freqs_group) { + g_object_unref (popup->priv->freqs_group); + popup->priv->freqs_group = NULL; + } + + if (popup->priv->freqs_actions) { + g_slist_free (popup->priv->freqs_actions); + popup->priv->freqs_actions = NULL; + } + + if (popup->priv->govs_group) { + g_object_unref (popup->priv->govs_group); + popup->priv->govs_group = NULL; + } + + if (popup->priv->govs_actions) { + g_slist_free (popup->priv->govs_actions); + popup->priv->govs_actions = NULL; + } + + if (popup->priv->monitor) { + g_object_unref (popup->priv->monitor); + popup->priv->monitor = NULL; + } + + G_OBJECT_CLASS (cpufreq_popup_parent_class)->finalize (object); +} + +CPUFreqPopup * +cpufreq_popup_new (void) +{ + CPUFreqPopup *popup; + + popup = CPUFREQ_POPUP (g_object_new (CPUFREQ_TYPE_POPUP, + NULL)); + + return popup; +} + +/* Public methods */ +void +cpufreq_popup_set_monitor (CPUFreqPopup *popup, + CPUFreqMonitor *monitor) +{ + g_return_if_fail (CPUFREQ_IS_POPUP (popup)); + g_return_if_fail (CPUFREQ_IS_MONITOR (monitor)); + + if (popup->priv->monitor == monitor) + return; + + if (popup->priv->monitor) + g_object_unref (popup->priv->monitor); + popup->priv->monitor = g_object_ref (monitor); +} + +void +cpufreq_popup_set_parent (CPUFreqPopup *popup, + GtkWidget *parent) +{ + g_return_if_fail (CPUFREQ_IS_POPUP (popup)); + g_return_if_fail (GTK_IS_WIDGET (parent)); + + popup->priv->parent = parent; +} + +static void +cpufreq_popup_frequencies_menu_activate (GtkAction *action, + CPUFreqPopup *popup) +{ + CPUFreqSelector *selector; + const gchar *name; + guint cpu; + guint freq; + guint32 parent; + + if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) + return; + + selector = cpufreq_selector_get_default (); + + cpu = cpufreq_monitor_get_cpu (popup->priv->monitor); + name = gtk_action_get_name (action); + freq = (guint) atoi (name + strlen ("Frequency")); + parent = GDK_WINDOW_XID (gtk_widget_get_window (popup->priv->parent)); + + + cpufreq_selector_set_frequency_async (selector, cpu, freq, parent); +} + +static void +cpufreq_popup_governors_menu_activate (GtkAction *action, + CPUFreqPopup *popup) +{ + CPUFreqSelector *selector; + const gchar *name; + guint cpu; + const gchar *governor; + guint32 parent; + + if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) + return; + + selector = cpufreq_selector_get_default (); + + cpu = cpufreq_monitor_get_cpu (popup->priv->monitor); + name = gtk_action_get_name (action); + governor = name + strlen ("Governor"); + parent = GDK_WINDOW_XID (gtk_widget_get_window (popup->priv->parent)); + + cpufreq_selector_set_governor_async (selector, cpu, governor, parent); +} + +static void +cpufreq_popup_menu_add_action (CPUFreqPopup *popup, + const gchar *menu, + GtkActionGroup *action_group, + const gchar *action_name, + const gchar *label, + gboolean sensitive) +{ + GtkToggleAction *action; + gchar *name; + + name = g_strdup_printf ("%s%s", menu, action_name); + + action = g_object_new (GTK_TYPE_RADIO_ACTION, + "name", name, + "label", label, + NULL); + + gtk_action_set_sensitive (GTK_ACTION (action), sensitive); + + gtk_radio_action_set_group (GTK_RADIO_ACTION (action), popup->priv->radio_group); + popup->priv->radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (action)); + + if (g_ascii_strcasecmp (menu, "Frequency") == 0) { + popup->priv->freqs_actions = g_slist_prepend (popup->priv->freqs_actions, + (gpointer) action); + + g_signal_connect (action, "activate", + G_CALLBACK (cpufreq_popup_frequencies_menu_activate), + (gpointer) popup); + } else if (g_ascii_strcasecmp (menu, "Governor") == 0) { + popup->priv->govs_actions = g_slist_prepend (popup->priv->govs_actions, + (gpointer) action); + + g_signal_connect (action, "activate", + G_CALLBACK (cpufreq_popup_governors_menu_activate), + (gpointer) popup); + } + + gtk_action_group_add_action (action_group, GTK_ACTION (action)); + g_object_unref (action); + + g_free (name); +} + +static void +frequencies_menu_create_actions (CPUFreqPopup *popup) +{ + GList *available_freqs; + + available_freqs = cpufreq_monitor_get_available_frequencies (popup->priv->monitor); + + while (available_freqs) { + const gchar *text; + gchar *freq_text; + gchar *label; + gchar *unit; + gint freq; + + text = (const gchar *) available_freqs->data; + freq = atoi (text); + + freq_text = cpufreq_utils_get_frequency_label (freq); + unit = cpufreq_utils_get_frequency_unit (freq); + + label = g_strdup_printf ("%s %s", freq_text, unit); + g_free (freq_text); + g_free (unit); + + cpufreq_popup_menu_add_action (popup, + "Frequency", + popup->priv->freqs_group, + text, label, TRUE); + g_free (label); + + available_freqs = g_list_next (available_freqs); + } +} + +static void +governors_menu_create_actions (CPUFreqPopup *popup) +{ + GList *available_govs; + + available_govs = cpufreq_monitor_get_available_governors (popup->priv->monitor); + available_govs = g_list_sort (available_govs, (GCompareFunc)g_ascii_strcasecmp); + + while (available_govs) { + const gchar *governor; + gchar *label; + + governor = (const gchar *) available_govs->data; + if (g_ascii_strcasecmp (governor, "userspace") == 0) { + popup->priv->show_freqs = TRUE; + available_govs = g_list_next (available_govs); + continue; + } + + label = g_strdup (governor); + label[0] = g_ascii_toupper (label[0]); + + cpufreq_popup_menu_add_action (popup, + "Governor", + popup->priv->govs_group, + governor, label, TRUE); + g_free (label); + + available_govs = g_list_next (available_govs); + } +} + +static void +cpufreq_popup_build_ui (CPUFreqPopup *popup, + GSList *actions, + const gchar *menu_path) +{ + GSList *l = NULL; + + for (l = actions; l && l->data; l = g_slist_next (l)) { + GtkAction *action; + gchar *name = NULL; + gchar *label = NULL; + + action = (GtkAction *) l->data; + + g_object_get (G_OBJECT (action), + "name", &name, + "label", &label, + NULL); + + gtk_ui_manager_add_ui (popup->priv->ui_manager, + popup->priv->merge_id, + menu_path, + label, name, + GTK_UI_MANAGER_MENUITEM, + FALSE); + + g_free (name); + g_free (label); + } +} + +static void +cpufreq_popup_build_frequencies_menu (CPUFreqPopup *popup, + const gchar *path) +{ + if (!popup->priv->freqs_group) { + GtkActionGroup *action_group; + + action_group = gtk_action_group_new ("FreqsActions"); + popup->priv->freqs_group = action_group; + gtk_action_group_set_translation_domain (action_group, NULL); + + frequencies_menu_create_actions (popup); + popup->priv->freqs_actions = g_slist_reverse (popup->priv->freqs_actions); + gtk_ui_manager_insert_action_group (popup->priv->ui_manager, + action_group, 0); + } + + cpufreq_popup_build_ui (popup, + popup->priv->freqs_actions, + path); +} + +static void +cpufreq_popup_build_governors_menu (CPUFreqPopup *popup, + const gchar *path) +{ + if (!popup->priv->govs_group) { + GtkActionGroup *action_group; + + action_group = gtk_action_group_new ("GovsActions"); + popup->priv->govs_group = action_group; + gtk_action_group_set_translation_domain (action_group, NULL); + + governors_menu_create_actions (popup); + popup->priv->govs_actions = g_slist_reverse (popup->priv->govs_actions); + gtk_ui_manager_insert_action_group (popup->priv->ui_manager, + action_group, 1); + } + + cpufreq_popup_build_ui (popup, + popup->priv->govs_actions, + path); +} + +static void +cpufreq_popup_build_menu (CPUFreqPopup *popup) +{ + if (popup->priv->merge_id > 0) { + gtk_ui_manager_remove_ui (popup->priv->ui_manager, + popup->priv->merge_id); + gtk_ui_manager_ensure_update (popup->priv->ui_manager); + } + + popup->priv->merge_id = gtk_ui_manager_new_merge_id (popup->priv->ui_manager); + + cpufreq_popup_build_frequencies_menu (popup, FREQS_PLACEHOLDER_PATH); + cpufreq_popup_build_governors_menu (popup, GOVS_PLACEHOLDER_PATH); + + gtk_action_group_set_visible (popup->priv->freqs_group, + popup->priv->show_freqs); +} + +static void +cpufreq_popup_menu_set_active_action (CPUFreqPopup *popup, + GtkActionGroup *action_group, + const gchar *prefix, + const gchar *item) +{ + gchar name[128]; + GtkAction *action; + + g_snprintf (name, sizeof (name), "%s%s", prefix, item); + action = gtk_action_group_get_action (action_group, name); + + g_signal_handlers_block_by_func (action, + cpufreq_popup_frequencies_menu_activate, + popup); + g_signal_handlers_block_by_func (action, + cpufreq_popup_governors_menu_activate, + popup); + + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE); + + g_signal_handlers_unblock_by_func (action, + cpufreq_popup_frequencies_menu_activate, + popup); + g_signal_handlers_unblock_by_func (action, + cpufreq_popup_governors_menu_activate, + popup); +} + +static void +cpufreq_popup_menu_set_active (CPUFreqPopup *popup) +{ + const gchar *governor; + + governor = cpufreq_monitor_get_governor (popup->priv->monitor); + + if (g_ascii_strcasecmp (governor, "userspace") == 0) { + gchar *active; + guint freq; + + freq = cpufreq_monitor_get_frequency (popup->priv->monitor); + active = g_strdup_printf ("%d", freq); + cpufreq_popup_menu_set_active_action (popup, + popup->priv->freqs_group, + "Frequency", active); + g_free (active); + } else { + cpufreq_popup_menu_set_active_action (popup, + popup->priv->govs_group, + "Governor", governor); + } +} + +GtkWidget * +cpufreq_popup_get_menu (CPUFreqPopup *popup) +{ + GtkWidget *menu; + + g_return_val_if_fail (CPUFREQ_IS_POPUP (popup), NULL); + g_return_val_if_fail (CPUFREQ_IS_MONITOR (popup->priv->monitor), NULL); + + if (!cpufreq_utils_selector_is_available ()) + return NULL; + + if (popup->priv->need_build) { + cpufreq_popup_build_menu (popup); + popup->priv->need_build = FALSE; + } + + cpufreq_popup_menu_set_active (popup); + + menu = gtk_ui_manager_get_widget (popup->priv->ui_manager, + "/CPUFreqSelectorPopup"); + + return menu; +} diff --git a/cpufreq/src/cpufreq-popup.h b/cpufreq/src/cpufreq-popup.h new file mode 100644 index 00000000..3a252d16 --- /dev/null +++ b/cpufreq/src/cpufreq-popup.h @@ -0,0 +1,66 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#ifndef CPUFREQ_POPUP_H +#define CPUFREQ_POPUP_H + +#include <glib-object.h> + +#include "cpufreq-monitor.h" +#include "cpufreq-prefs.h" + +G_BEGIN_DECLS + +#define CPUFREQ_TYPE_POPUP (cpufreq_popup_get_type ()) +#define CPUFREQ_POPUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CPUFREQ_TYPE_POPUP, CPUFreqPopup)) +#define CPUFREQ_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), CPUFREQ_TYPE_POPUP, CPUFreqPopupClass)) +#define CPUFREQ_IS_POPUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CPUFREQ_TYPE_POPUP)) +#define CPUFREQ_IS_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CPUFREQ_TYPE_POPUP)) +#define CPUFREQ_POPUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CPUFREQ_TYPE_POPUP, CPUFreqPopupClass)) + +typedef struct _CPUFreqPopup CPUFreqPopup; +typedef struct _CPUFreqPopupClass CPUFreqPopupClass; +typedef struct _CPUFreqPopupPrivate CPUFreqPopupPrivate; + +struct _CPUFreqPopup { + GObject base; + + CPUFreqPopupPrivate *priv; +}; + +struct _CPUFreqPopupClass { + GObjectClass parent_class; +}; + +GType cpufreq_popup_get_type (void) G_GNUC_CONST; +CPUFreqPopup *cpufreq_popup_new (void); + +void cpufreq_popup_set_preferences (CPUFreqPopup *popup, + CPUFreqPrefs *prefs); +void cpufreq_popup_set_monitor (CPUFreqPopup *popup, + CPUFreqMonitor *monitor); +void cpufreq_popup_set_parent (CPUFreqPopup *popup, + GtkWidget *parent); +GtkWidget *cpufreq_popup_get_menu (CPUFreqPopup *popup); + +G_END_DECLS + +#endif /* CPUFREQ_POPUP_H */ diff --git a/cpufreq/src/cpufreq-prefs.c b/cpufreq/src/cpufreq-prefs.c new file mode 100644 index 00000000..a57d02d9 --- /dev/null +++ b/cpufreq/src/cpufreq-prefs.c @@ -0,0 +1,705 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gtk/gtk.h> +#include <glib/gi18n.h> +#include <mateconf/mateconf-client.h> + +#include "cpufreq-prefs.h" +#include "cpufreq-utils.h" + +enum { + PROP_0, + PROP_MATECONF_KEY, + PROP_CPU, + PROP_SHOW_MODE, + PROP_SHOW_TEXT_MODE, +}; + +struct _CPUFreqPrefsPrivate { + MateConfClient *mateconf_client; + gchar *mateconf_key; + + guint cpu; + CPUFreqShowMode show_mode; + CPUFreqShowTextMode show_text_mode; + + /* Preferences dialog */ + GtkWidget *dialog; + GtkWidget *show_freq; + GtkWidget *show_unit; + GtkWidget *show_perc; + GtkWidget *cpu_combo; + GtkWidget *monitor_settings_box; + GtkWidget *show_mode_combo; +}; + +#define CPUFREQ_PREFS_GET_PRIVATE(object) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((object), CPUFREQ_TYPE_PREFS, CPUFreqPrefsPrivate)) + +static void cpufreq_prefs_init (CPUFreqPrefs *prefs); +static void cpufreq_prefs_class_init (CPUFreqPrefsClass *klass); +static void cpufreq_prefs_finalize (GObject *object); + +static void cpufreq_prefs_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void cpufreq_prefs_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +static void cpufreq_prefs_dialog_update_sensitivity (CPUFreqPrefs *prefs); + + +G_DEFINE_TYPE (CPUFreqPrefs, cpufreq_prefs, G_TYPE_OBJECT) + +static void +cpufreq_prefs_init (CPUFreqPrefs *prefs) +{ + prefs->priv = CPUFREQ_PREFS_GET_PRIVATE (prefs); + + prefs->priv->mateconf_client = mateconf_client_get_default (); + prefs->priv->mateconf_key = NULL; + + prefs->priv->cpu = 0; +} + +static void +cpufreq_prefs_class_init (CPUFreqPrefsClass *klass) +{ + GObjectClass *g_object_class = G_OBJECT_CLASS (klass); + + g_object_class->set_property = cpufreq_prefs_set_property; + g_object_class->get_property = cpufreq_prefs_get_property; + + g_type_class_add_private (g_object_class, sizeof (CPUFreqPrefsPrivate)); + + /* Properties */ + g_object_class_install_property (g_object_class, + PROP_MATECONF_KEY, + g_param_spec_string ("mateconf-key", + "MateConfKey", + "The applet mateconf key", + NULL, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (g_object_class, + PROP_CPU, + g_param_spec_uint ("cpu", + "CPU", + "The monitored cpu", + 0, + G_MAXUINT, + 0, + G_PARAM_READWRITE)); + g_object_class_install_property (g_object_class, + PROP_SHOW_MODE, + g_param_spec_enum ("show-mode", + "ShowMode", + "The applet show mode", + CPUFREQ_TYPE_SHOW_MODE, + CPUFREQ_MODE_BOTH, + G_PARAM_READWRITE)); + g_object_class_install_property (g_object_class, + PROP_SHOW_TEXT_MODE, + g_param_spec_enum ("show-text-mode", + "ShowTextMode", + "The applet show text mode", + CPUFREQ_TYPE_SHOW_TEXT_MODE, + CPUFREQ_MODE_TEXT_FREQUENCY_UNIT, + G_PARAM_READWRITE)); + + g_object_class->finalize = cpufreq_prefs_finalize; +} + +static void +cpufreq_prefs_finalize (GObject *object) +{ + CPUFreqPrefs *prefs = CPUFREQ_PREFS (object); + + if (prefs->priv->mateconf_client) { + g_object_unref (prefs->priv->mateconf_client); + prefs->priv->mateconf_client = NULL; + } + + if (prefs->priv->mateconf_key) { + g_free (prefs->priv->mateconf_key); + prefs->priv->mateconf_key = NULL; + } + + if (prefs->priv->dialog) { + gtk_widget_destroy (prefs->priv->dialog); + prefs->priv->dialog = NULL; + } + + G_OBJECT_CLASS (cpufreq_prefs_parent_class)->finalize (object); +} + +static void +cpufreq_prefs_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + CPUFreqPrefs *prefs = CPUFREQ_PREFS (object); + gboolean update_sensitivity = FALSE; + + switch (prop_id) { + case PROP_MATECONF_KEY: + prefs->priv->mateconf_key = g_value_dup_string (value); + break; + case PROP_CPU: { + guint cpu; + + cpu = g_value_get_uint (value); + if (prefs->priv->cpu != cpu) { + gchar *key; + + prefs->priv->cpu = cpu; + key = g_strjoin ("/", + prefs->priv->mateconf_key, + "cpu", + NULL); + mateconf_client_set_int (prefs->priv->mateconf_client, + key, prefs->priv->cpu, + NULL); + g_free (key); + } + } + break; + case PROP_SHOW_MODE: { + CPUFreqShowMode mode; + + mode = g_value_get_enum (value); + if (prefs->priv->show_mode != mode) { + gchar *key; + + update_sensitivity = TRUE; + prefs->priv->show_mode = mode; + key = g_strjoin ("/", + prefs->priv->mateconf_key, + "show_mode", + NULL); + mateconf_client_set_int (prefs->priv->mateconf_client, + key, prefs->priv->show_mode, + NULL); + g_free (key); + } + } + break; + case PROP_SHOW_TEXT_MODE: { + CPUFreqShowTextMode mode; + + mode = g_value_get_enum (value); + if (prefs->priv->show_text_mode != mode) { + gchar *key; + + update_sensitivity = TRUE; + prefs->priv->show_text_mode = mode; + key = g_strjoin ("/", + prefs->priv->mateconf_key, + "show_text_mode", + NULL); + mateconf_client_set_int (prefs->priv->mateconf_client, + key, prefs->priv->show_text_mode, + NULL); + g_free (key); + } + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } + + if (prefs->priv->dialog && update_sensitivity) + cpufreq_prefs_dialog_update_sensitivity (prefs); +} + +static void +cpufreq_prefs_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + CPUFreqPrefs *prefs = CPUFREQ_PREFS (object); + + switch (prop_id) { + case PROP_MATECONF_KEY: + /* Is not readable */ + break; + case PROP_CPU: + g_value_set_uint (value, prefs->priv->cpu); + break; + case PROP_SHOW_MODE: + g_value_set_enum (value, prefs->priv->show_mode); + break; + case PROP_SHOW_TEXT_MODE: + g_value_set_enum (value, prefs->priv->show_text_mode); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +cpufreq_prefs_setup (CPUFreqPrefs *prefs) +{ + guint cpu; + CPUFreqShowMode show_mode; + CPUFreqShowTextMode show_text_mode; + gchar *key; + GError *error = NULL; + + g_assert (MATECONF_IS_CLIENT (prefs->priv->mateconf_client)); + g_assert (prefs->priv->mateconf_key != NULL); + + key = g_strjoin ("/", prefs->priv->mateconf_key, "cpu", NULL); + cpu = mateconf_client_get_int (prefs->priv->mateconf_client, + key, &error); + g_free (key); + /* In case anything went wrong with mateconf, get back to the default */ + if (error) { + g_warning ("%s", error->message); + cpu = 0; + g_error_free (error); + error = NULL; + } + prefs->priv->cpu = cpu; + + key = g_strjoin ("/", prefs->priv->mateconf_key, "show_mode", NULL); + show_mode = mateconf_client_get_int (prefs->priv->mateconf_client, + key, &error); + g_free (key); + /* In case anything went wrong with mateconf, get back to the default */ + if (error || + show_mode < CPUFREQ_MODE_GRAPHIC || + show_mode > CPUFREQ_MODE_BOTH) { + show_mode = CPUFREQ_MODE_BOTH; + if (error) { + g_warning ("%s", error->message); + g_error_free (error); + error = NULL; + } + } + prefs->priv->show_mode = show_mode; + + key = g_strjoin ("/", prefs->priv->mateconf_key, "show_text_mode", NULL); + show_text_mode = mateconf_client_get_int (prefs->priv->mateconf_client, + key, &error); + g_free (key); + /* In case anything went wrong with mateconf, get back to the default */ + if (error || + show_text_mode < CPUFREQ_MODE_TEXT_FREQUENCY || + show_text_mode > CPUFREQ_MODE_TEXT_PERCENTAGE) { + show_text_mode = CPUFREQ_MODE_TEXT_FREQUENCY_UNIT; + if (error) { + g_warning ("%s", error->message); + g_error_free (error); + error = NULL; + } + } + prefs->priv->show_text_mode = show_text_mode; +} + +CPUFreqPrefs * +cpufreq_prefs_new (const gchar *mateconf_key) +{ + CPUFreqPrefs *prefs; + + g_return_val_if_fail (mateconf_key != NULL, NULL); + + prefs = CPUFREQ_PREFS (g_object_new (CPUFREQ_TYPE_PREFS, + "mateconf-key", mateconf_key, + NULL)); + + cpufreq_prefs_setup (prefs); + + return prefs; +} + +/* Public Methods */ +guint +cpufreq_prefs_get_cpu (CPUFreqPrefs *prefs) +{ + g_return_val_if_fail (CPUFREQ_IS_PREFS (prefs), 0); + + return MIN (prefs->priv->cpu, cpufreq_utils_get_n_cpus () - 1); +} + +CPUFreqShowMode +cpufreq_prefs_get_show_mode (CPUFreqPrefs *prefs) +{ + g_return_val_if_fail (CPUFREQ_IS_PREFS (prefs), + CPUFREQ_MODE_BOTH); + + return prefs->priv->show_mode; +} + +CPUFreqShowTextMode +cpufreq_prefs_get_show_text_mode (CPUFreqPrefs *prefs) +{ + g_return_val_if_fail (CPUFREQ_IS_PREFS (prefs), + CPUFREQ_MODE_TEXT_FREQUENCY_UNIT); + + return prefs->priv->show_text_mode; +} + +/* Preferences Dialog */ +static gboolean +cpufreq_prefs_key_is_writable (CPUFreqPrefs *prefs, const gchar *key) +{ + gboolean writable; + gchar *fullkey; + + g_assert (prefs->priv->mateconf_client != NULL); + + fullkey = g_strjoin ("/", prefs->priv->mateconf_key, key, NULL); + writable = mateconf_client_key_is_writable (prefs->priv->mateconf_client, + fullkey, NULL); + g_free (fullkey); + + return writable; +} + +static void +cpufreq_prefs_dialog_show_freq_toggled (GtkWidget *show_freq, CPUFreqPrefs *prefs) +{ + CPUFreqShowTextMode show_text_mode; + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (show_freq))) { + GtkWidget *show_unit = prefs->priv->show_unit; + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (show_unit))) + show_text_mode = CPUFREQ_MODE_TEXT_FREQUENCY_UNIT; + else + show_text_mode = CPUFREQ_MODE_TEXT_FREQUENCY; + + g_object_set (G_OBJECT (prefs), + "show-text-mode", show_text_mode, + NULL); + } +} + +static void +cpufreq_prefs_dialog_show_unit_toggled (GtkWidget *show_unit, CPUFreqPrefs *prefs) +{ + CPUFreqShowTextMode show_text_mode; + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (show_unit))) { + show_text_mode = CPUFREQ_MODE_TEXT_FREQUENCY_UNIT; + } else { + show_text_mode = CPUFREQ_MODE_TEXT_FREQUENCY; + } + + g_object_set (G_OBJECT (prefs), + "show-text-mode", show_text_mode, + NULL); +} + +static void +cpufreq_prefs_dialog_show_perc_toggled (GtkWidget *show_perc, CPUFreqPrefs *prefs) +{ + + CPUFreqShowTextMode show_text_mode; + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (show_perc))) { + /* Show cpu usage in percentage */ + show_text_mode = CPUFREQ_MODE_TEXT_PERCENTAGE; + + g_object_set (G_OBJECT (prefs), + "show-text-mode", show_text_mode, + NULL); + } +} + +static void +cpufreq_prefs_dialog_cpu_number_changed (GtkWidget *cpu_combo, CPUFreqPrefs *prefs) +{ + gint cpu; + + cpu = gtk_combo_box_get_active (GTK_COMBO_BOX (prefs->priv->cpu_combo)); + + if (cpu >= 0) { + g_object_set (G_OBJECT (prefs), + "cpu", cpu, + NULL); + } +} + +static void +cpufreq_prefs_dialog_show_mode_changed (GtkWidget *show_mode_combo, CPUFreqPrefs *prefs) +{ + CPUFreqShowMode show_mode; + + show_mode = gtk_combo_box_get_active (GTK_COMBO_BOX (show_mode_combo)); + g_object_set (G_OBJECT (prefs), + "show-mode", show_mode, + NULL); +} + +static void +cpufreq_prefs_dialog_response_cb (CPUFreqPrefs *prefs, + gint response, + GtkDialog *dialog) +{ + GError *error = NULL; + + if (response == GTK_RESPONSE_HELP) { + gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (prefs->priv->dialog)), + "ghelp:cpufreq-applet?cpufreq-applet-prefs", + gtk_get_current_event_time (), + &error); + + if (error) { + cpufreq_utils_display_error (_("Could not open help document"), + error->message); + g_error_free (error); + } + } else { + gtk_widget_destroy (prefs->priv->dialog); + prefs->priv->dialog = NULL; + } +} + +static void +cpufreq_prefs_dialog_update_visibility (CPUFreqPrefs *prefs) +{ + if (cpufreq_utils_get_n_cpus () > 1) + gtk_widget_show (prefs->priv->monitor_settings_box); + else + gtk_widget_hide (prefs->priv->monitor_settings_box); +} + +static void +cpufreq_prefs_dialog_update_sensitivity (CPUFreqPrefs *prefs) +{ + gtk_widget_set_sensitive (prefs->priv->show_mode_combo, + cpufreq_prefs_key_is_writable (prefs, "show_mode")); + + if (prefs->priv->show_mode != CPUFREQ_MODE_GRAPHIC) { + gboolean key_writable; + + key_writable = cpufreq_prefs_key_is_writable (prefs, "show_text_mode"); + + gtk_widget_set_sensitive (prefs->priv->show_freq, + (TRUE && key_writable)); + gtk_widget_set_sensitive (prefs->priv->show_perc, + (TRUE && key_writable)); + + if (prefs->priv->show_text_mode == CPUFREQ_MODE_TEXT_PERCENTAGE) + gtk_widget_set_sensitive (prefs->priv->show_unit, + FALSE); + else + gtk_widget_set_sensitive (prefs->priv->show_unit, + (TRUE && key_writable)); + } else { + gtk_widget_set_sensitive (prefs->priv->show_freq, FALSE); + gtk_widget_set_sensitive (prefs->priv->show_unit, FALSE); + gtk_widget_set_sensitive (prefs->priv->show_perc, FALSE); + } +} + +static void +cpufreq_prefs_dialog_update (CPUFreqPrefs *prefs) +{ + if (cpufreq_utils_get_n_cpus () > 1) { + gtk_combo_box_set_active (GTK_COMBO_BOX (prefs->priv->cpu_combo), + MIN (prefs->priv->cpu, cpufreq_utils_get_n_cpus () - 1)); + } + + gtk_combo_box_set_active (GTK_COMBO_BOX (prefs->priv->show_mode_combo), + prefs->priv->show_mode); + + switch (prefs->priv->show_text_mode) { + case CPUFREQ_MODE_TEXT_FREQUENCY: + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (prefs->priv->show_freq), + TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (prefs->priv->show_unit), + FALSE); + + break; + case CPUFREQ_MODE_TEXT_FREQUENCY_UNIT: + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (prefs->priv->show_freq), + TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (prefs->priv->show_unit), + TRUE); + + break; + case CPUFREQ_MODE_TEXT_PERCENTAGE: + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (prefs->priv->show_perc), + TRUE); + + break; + } +} + +static void +cpufreq_prefs_dialog_cpu_combo_setup (CPUFreqPrefs *prefs) +{ + GtkListStore *model; + GtkTreeIter iter; + GtkCellRenderer *renderer; + guint i; + guint n_cpus; + + model = gtk_list_store_new (1, G_TYPE_STRING); + gtk_combo_box_set_model (GTK_COMBO_BOX (prefs->priv->cpu_combo), + GTK_TREE_MODEL (model)); + + n_cpus = cpufreq_utils_get_n_cpus (); + + for (i = 0; i < n_cpus; i++) { + gchar *text_label; + + text_label = g_strdup_printf ("CPU %u", i); + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, + 0, text_label, + -1); + + g_free (text_label); + } + + g_object_unref (model); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_clear (GTK_CELL_LAYOUT (prefs->priv->cpu_combo)); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (prefs->priv->cpu_combo), + renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (prefs->priv->cpu_combo), + renderer, + "text", 0, + NULL); +} + +static void +cpufreq_prefs_dialog_show_mode_combo_setup (CPUFreqPrefs *prefs) +{ + GtkListStore *model; + GtkTreeIter iter; + GtkCellRenderer *renderer; + + model = gtk_list_store_new (1, G_TYPE_STRING); + gtk_combo_box_set_model (GTK_COMBO_BOX (prefs->priv->show_mode_combo), + GTK_TREE_MODEL (model)); + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, + 0, _("Graphic"), + -1); + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, + 0, _("Text"), + -1); + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, + 0, _("Graphic and Text"), + -1); + + g_object_unref (model); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_clear (GTK_CELL_LAYOUT (prefs->priv->show_mode_combo)); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (prefs->priv->show_mode_combo), + renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (prefs->priv->show_mode_combo), + renderer, + "text", 0, + NULL); +} + +static void +cpufreq_prefs_dialog_create (CPUFreqPrefs *prefs) +{ + GtkBuilder *builder; + + builder = gtk_builder_new (); + gtk_builder_add_from_file (builder, GTK_BUILDERDIR "/cpufreq-preferences.ui", NULL); + + prefs->priv->dialog = GTK_WIDGET (gtk_builder_get_object (builder, "prefs_dialog")); + + prefs->priv->cpu_combo = GTK_WIDGET (gtk_builder_get_object (builder, "prefs_cpu_number")); + + prefs->priv->show_mode_combo = GTK_WIDGET (gtk_builder_get_object (builder, "prefs_show_mode")); + + prefs->priv->show_freq = GTK_WIDGET (gtk_builder_get_object (builder, "prefs_show_freq")); + prefs->priv->show_unit = GTK_WIDGET (gtk_builder_get_object (builder, "prefs_show_unit")); + prefs->priv->show_perc = GTK_WIDGET (gtk_builder_get_object (builder, "prefs_show_perc")); + + prefs->priv->monitor_settings_box = GTK_WIDGET (gtk_builder_get_object (builder, "monitor_settings_box")); + + g_object_unref (builder); + + cpufreq_prefs_dialog_show_mode_combo_setup (prefs); + + if (cpufreq_utils_get_n_cpus () > 1) + cpufreq_prefs_dialog_cpu_combo_setup (prefs); + + g_signal_connect_swapped (G_OBJECT (prefs->priv->dialog), "response", + G_CALLBACK (cpufreq_prefs_dialog_response_cb), + (gpointer) prefs); + + g_signal_connect (G_OBJECT (prefs->priv->show_freq), "toggled", + G_CALLBACK (cpufreq_prefs_dialog_show_freq_toggled), + (gpointer) prefs); + g_signal_connect (G_OBJECT (prefs->priv->show_unit), "toggled", + G_CALLBACK (cpufreq_prefs_dialog_show_unit_toggled), + (gpointer) prefs); + g_signal_connect (G_OBJECT (prefs->priv->show_perc), "toggled", + G_CALLBACK (cpufreq_prefs_dialog_show_perc_toggled), + (gpointer) prefs); + g_signal_connect (G_OBJECT (prefs->priv->cpu_combo), "changed", + G_CALLBACK (cpufreq_prefs_dialog_cpu_number_changed), + (gpointer) prefs); + g_signal_connect (G_OBJECT (prefs->priv->show_mode_combo), "changed", + G_CALLBACK (cpufreq_prefs_dialog_show_mode_changed), + (gpointer) prefs); +} + +void +cpufreq_preferences_dialog_run (CPUFreqPrefs *prefs, GdkScreen *screen) +{ + g_return_if_fail (CPUFREQ_IS_PREFS (prefs)); + + if (prefs->priv->dialog) { + /* Dialog already exist, only show it */ + gtk_window_present (GTK_WINDOW (prefs->priv->dialog)); + return; + } + + cpufreq_prefs_dialog_create (prefs); + gtk_window_set_screen (GTK_WINDOW (prefs->priv->dialog), screen); + + cpufreq_prefs_dialog_update_sensitivity (prefs); + cpufreq_prefs_dialog_update_visibility (prefs); + cpufreq_prefs_dialog_update (prefs); + + gtk_widget_show (prefs->priv->dialog); +} diff --git a/cpufreq/src/cpufreq-prefs.h b/cpufreq/src/cpufreq-prefs.h new file mode 100644 index 00000000..8be9abe8 --- /dev/null +++ b/cpufreq/src/cpufreq-prefs.h @@ -0,0 +1,66 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#ifndef CPUFREQ_PREFS_H +#define CPUFREQ_PREFS_H + +#include <gdk/gdk.h> +#include <glib-object.h> +#include "cpufreq-applet.h" + +G_BEGIN_DECLS + +#define CPUFREQ_TYPE_PREFS (cpufreq_prefs_get_type ()) +#define CPUFREQ_PREFS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CPUFREQ_TYPE_PREFS, CPUFreqPrefs)) +#define CPUFREQ_PREFS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), CPUFREQ_TYPE_PREFS, CPUFreqPrefsClass)) +#define CPUFREQ_IS_PREFS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CPUFREQ_TYPE_PREFS)) +#define CPUFREQ_IS_PREFS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CPUFREQ_TYPE_PREFS)) +#define CPUFREQ_PREFS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CPUFREQ_TYPE_PREFS, CPUFreqPrefsClass)) + +typedef struct _CPUFreqPrefs CPUFreqPrefs; +typedef struct _CPUFreqPrefsClass CPUFreqPrefsClass; +typedef struct _CPUFreqPrefsPrivate CPUFreqPrefsPrivate; + +struct _CPUFreqPrefs { + GObject base; + + CPUFreqPrefsPrivate *priv; +}; + +struct _CPUFreqPrefsClass { + GObjectClass parent_class; +}; + +GType cpufreq_prefs_get_type (void) G_GNUC_CONST; + +CPUFreqPrefs *cpufreq_prefs_new (const gchar *mateconf_key); + +guint cpufreq_prefs_get_cpu (CPUFreqPrefs *prefs); +CPUFreqShowMode cpufreq_prefs_get_show_mode (CPUFreqPrefs *prefs); +CPUFreqShowTextMode cpufreq_prefs_get_show_text_mode (CPUFreqPrefs *prefs); + +/* Properties dialog */ +void cpufreq_preferences_dialog_run (CPUFreqPrefs *prefs, + GdkScreen *screen); + +G_END_DECLS + +#endif /* CPUFREQ_PREFS_H */ diff --git a/cpufreq/src/cpufreq-selector.c b/cpufreq/src/cpufreq-selector.c new file mode 100644 index 00000000..d5a37e15 --- /dev/null +++ b/cpufreq/src/cpufreq-selector.c @@ -0,0 +1,289 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2008 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <config.h> + +#ifdef HAVE_POLKIT +#include <dbus/dbus-glib.h> +#endif /* HAVE_POLKIT */ + +#include "cpufreq-selector.h" + +struct _CPUFreqSelector { + GObject parent; + +#ifdef HAVE_POLKIT + DBusGConnection *system_bus; +#endif /* HAVE_POLKIT */ +}; + +struct _CPUFreqSelectorClass { + GObjectClass parent_class; +}; + +G_DEFINE_TYPE (CPUFreqSelector, cpufreq_selector, G_TYPE_OBJECT) + +static void +cpufreq_selector_finalize (GObject *object) +{ + CPUFreqSelector *selector = CPUFREQ_SELECTOR (object); + +#ifdef HAVE_POLKIT + selector->system_bus = NULL; +#endif /* HAVE_POLKIT */ + + G_OBJECT_CLASS (cpufreq_selector_parent_class)->finalize (object); +} + +static void +cpufreq_selector_class_init (CPUFreqSelectorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = cpufreq_selector_finalize; +} + +static void +cpufreq_selector_init (CPUFreqSelector *selector) +{ +} + +CPUFreqSelector * +cpufreq_selector_get_default (void) +{ + static CPUFreqSelector *selector = NULL; + + if (!selector) + selector = CPUFREQ_SELECTOR (g_object_new (CPUFREQ_TYPE_SELECTOR, NULL)); + + return selector; +} + +#ifdef HAVE_POLKIT +typedef enum { + FREQUENCY, + GOVERNOR +} CPUFreqSelectorCall; + +typedef struct { + CPUFreqSelector *selector; + + CPUFreqSelectorCall call; + + guint cpu; + guint frequency; + gchar *governor; + + guint32 parent_xid; +} SelectorAsyncData; + +static void selector_set_frequency_async (SelectorAsyncData *data); +static void selector_set_governor_async (SelectorAsyncData *data); + +static void +selector_async_data_free (SelectorAsyncData *data) +{ + if (!data) + return; + + g_free (data->governor); + g_free (data); +} + +static gboolean +cpufreq_selector_connect_to_system_bus (CPUFreqSelector *selector, + GError **error) +{ + if (selector->system_bus) + return TRUE; + + selector->system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, error); + + return (selector->system_bus != NULL); +} + +static void +dbus_set_call_notify_cb (DBusGProxy *proxy, + DBusGProxyCall *call, + gpointer user_data) +{ + SelectorAsyncData *data; + GError *error = NULL; + + data = (SelectorAsyncData *)user_data; + + if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) { + selector_async_data_free (data); + return; + } + + selector_async_data_free (data); + g_warning ("%s", error->message); + g_error_free (error); +} + +static void +selector_set_frequency_async (SelectorAsyncData *data) +{ + DBusGProxy *proxy; + GError *error = NULL; + + if (!cpufreq_selector_connect_to_system_bus (data->selector, &error)) { + g_warning ("%s", error->message); + g_error_free (error); + + selector_async_data_free (data); + + return; + } + + proxy = dbus_g_proxy_new_for_name (data->selector->system_bus, + "org.mate.CPUFreqSelector", + "/org/mate/cpufreq_selector/selector", + "org.mate.CPUFreqSelector"); + + dbus_g_proxy_begin_call_with_timeout (proxy, "SetFrequency", + dbus_set_call_notify_cb, + data, NULL, + INT_MAX, + G_TYPE_UINT, data->cpu, + G_TYPE_UINT, data->frequency, + G_TYPE_INVALID, + G_TYPE_INVALID); +} + +void +cpufreq_selector_set_frequency_async (CPUFreqSelector *selector, + guint cpu, + guint frequency, + guint32 parent) +{ + SelectorAsyncData *data; + + data = g_new0 (SelectorAsyncData, 1); + + data->selector = selector; + data->call = FREQUENCY; + data->cpu = cpu; + data->frequency = frequency; + data->parent_xid = parent; + + selector_set_frequency_async (data); +} + +static void +selector_set_governor_async (SelectorAsyncData *data) +{ + DBusGProxy *proxy; + GError *error = NULL; + + if (!cpufreq_selector_connect_to_system_bus (data->selector, &error)) { + g_warning ("%s", error->message); + g_error_free (error); + + selector_async_data_free (data); + + return; + } + + proxy = dbus_g_proxy_new_for_name (data->selector->system_bus, + "org.mate.CPUFreqSelector", + "/org/mate/cpufreq_selector/selector", + "org.mate.CPUFreqSelector"); + + dbus_g_proxy_begin_call_with_timeout (proxy, "SetGovernor", + dbus_set_call_notify_cb, + data, NULL, + INT_MAX, + G_TYPE_UINT, data->cpu, + G_TYPE_STRING, data->governor, + G_TYPE_INVALID, + G_TYPE_INVALID); +} + +void +cpufreq_selector_set_governor_async (CPUFreqSelector *selector, + guint cpu, + const gchar *governor, + guint32 parent) +{ + SelectorAsyncData *data; + + data = g_new0 (SelectorAsyncData, 1); + + data->selector = selector; + data->call = GOVERNOR; + data->cpu = cpu; + data->governor = g_strdup (governor); + data->parent_xid = parent; + + selector_set_governor_async (data); +} +#else /* !HAVE_POLKIT */ +static void +cpufreq_selector_run_command (CPUFreqSelector *selector, + const gchar *args) +{ + gchar *command; + gchar *path; + GError *error = NULL; + + path = g_find_program_in_path ("cpufreq-selector"); + + if (!path) + return; + + command = g_strdup_printf ("%s %s", path, args); + g_free (path); + + g_spawn_command_line_async (command, &error); + g_free (command); + + if (error) { + g_warning ("%s", error->message); + g_error_free (error); + } +} + +void +cpufreq_selector_set_frequency_async (CPUFreqSelector *selector, + guint cpu, + guint frequency, + guint32 parent) +{ + gchar *args; + + args = g_strdup_printf ("-c %u -f %u", cpu, frequency); + cpufreq_selector_run_command (selector, args); + g_free (args); +} + +void +cpufreq_selector_set_governor_async (CPUFreqSelector *selector, + guint cpu, + const gchar *governor, + guint32 parent) +{ + gchar *args; + + args = g_strdup_printf ("-c %u -g %s", cpu, governor); + cpufreq_selector_run_command (selector, args); + g_free (args); +} +#endif /* HAVE_POLKIT */ diff --git a/cpufreq/src/cpufreq-selector.h b/cpufreq/src/cpufreq-selector.h new file mode 100644 index 00000000..5941d416 --- /dev/null +++ b/cpufreq/src/cpufreq-selector.h @@ -0,0 +1,51 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2008 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __CPUFREQ_SELECTOR_H__ +#define __CPUFREQ_SELECTOR_H__ + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define CPUFREQ_TYPE_SELECTOR (cpufreq_selector_get_type ()) +#define CPUFREQ_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CPUFREQ_TYPE_SELECTOR, CPUFreqSelector)) +#define CPUFREQ_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), CPUFREQ_TYPE_SELECTOR, CPUFreqSelectorClass)) +#define CPUFREQ_IS_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CPUFREQ_TYPE_SELECTOR)) +#define CPUFREQ_IS_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CPUFREQ_TYPE_SELECTOR)) +#define CPUFREQ_SELECTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CPUFREQ_TYPE_SELECTOR, CPUFreqSelectorClass)) + +typedef struct _CPUFreqSelector CPUFreqSelector; +typedef struct _CPUFreqSelectorClass CPUFreqSelectorClass; + +GType cpufreq_selector_get_type (void) G_GNUC_CONST; + +CPUFreqSelector *cpufreq_selector_get_default (void); +void cpufreq_selector_set_frequency_async (CPUFreqSelector *selector, + guint cpu, + guint frequency, + guint32 parent); +void cpufreq_selector_set_governor_async (CPUFreqSelector *selector, + guint cpu, + const gchar *governor, + guint32 parent); + +G_END_DECLS + +#endif /* __CPUFREQ_SELECTOR_H__ */ diff --git a/cpufreq/src/cpufreq-selector/Makefile.am b/cpufreq/src/cpufreq-selector/Makefile.am new file mode 100644 index 00000000..b2db7a97 --- /dev/null +++ b/cpufreq/src/cpufreq-selector/Makefile.am @@ -0,0 +1,89 @@ +cpufreqselectordir = $(bindir) + +INCLUDES = $(CPUFREQ_SELECTOR_CFLAGS) + +if HAVE_POLKIT +INCLUDES += \ + $(DBUS_CFLAGS) \ + $(POLKIT_CFLAGS) +endif + +bin_PROGRAMS = cpufreq-selector + +install-exec-hook: +if CPUFREQ_SELECTOR_SUID + chmod 4755 $(DESTDIR)$(bindir)/cpufreq-selector +endif + + +if HAVE_LIBCPUFREQ +cpufreq_files=cpufreq-selector-libcpufreq.c cpufreq-selector-libcpufreq.h +endif + +if HAVE_POLKIT +service_files=cpufreq-selector-service.c cpufreq-selector-service.h +endif + +cpufreq_selector_SOURCES = \ + cpufreq-selector.c cpufreq-selector.h \ + cpufreq-selector-sysfs.c cpufreq-selector-sysfs.h \ + cpufreq-selector-procfs.c cpufreq-selector-procfs.h \ + $(cpufreq_files) \ + $(service_files) \ + cpufreq-selector-factory.c cpufreq-selector-factory.h \ + $(BUILT_SOURCES) \ + main.c + +cpufreq_selector_LDADD = \ + $(CPUFREQ_SELECTOR_LIBS) \ + $(LIBCPUFREQ_LIBS) + +if HAVE_POLKIT +cpufreq_selector_LDADD += \ + $(DBUS_LIBS) \ + $(POLKIT_LIBS) +endif + +cpufreq_selector_LDFLAGS = $(LDFLAGS) -Wl,-z,now + +dbus_services_in_files = org.mate.CPUFreqSelector.service.in +polkit_in_files = org.mate.cpufreqselector.policy.in + +dbus_servicesdir = $(datadir)/dbus-1/system-services +dbus_confdir = $(sysconfdir)/dbus-1/system.d +polkitdir = $(datadir)/polkit-1/actions + +if HAVE_POLKIT +BUILT_SOURCES = cpufreq-selector-service-glue.h + +cpufreq-selector-service-glue.h: $(srcdir)/cpufreq-selector-service.xml + dbus-binding-tool --prefix=cpufreq_selector_service --mode=glib-server \ + --output=cpufreq-selector-service-glue.h \ + $(srcdir)/cpufreq-selector-service.xml + +dbus_services_DATA = $(dbus_services_in_files:.service.in=.service) +$(dbus_services_DATA): $(dbus_services_in_files) + sed -e "s|\@BINDIR\@|$(DESTDIR)$(bindir)|" $< > $@ +dbus_conf_DATA = org.mate.CPUFreqSelector.conf + +@INTLTOOL_POLICY_RULE@ +polkit_DATA = $(polkit_in_files:.policy.in=.policy) + +else +dbus_services_DATA= +dbus_conf_DATA= +polkit_DATA= +endif + +EXTRA_DIST = \ + cpufreq-selector-service.xml \ + $(dbus_services_in_files) \ + org.mate.CPUFreqSelector.conf \ + $(polkit_in_files) + +CLEANFILES = \ + $(BUILT_SOURCES) \ + $(dbus_services_DATA) \ + $(polkit_DATA) + +-include $(top_srcdir)/git.mk diff --git a/cpufreq/src/cpufreq-selector/cpufreq-selector-factory.c b/cpufreq/src/cpufreq-selector/cpufreq-selector-factory.c new file mode 100644 index 00000000..024b5cb7 --- /dev/null +++ b/cpufreq/src/cpufreq-selector/cpufreq-selector-factory.c @@ -0,0 +1,47 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2008 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cpufreq-selector-factory.h" +#include "cpufreq-selector-sysfs.h" +#include "cpufreq-selector-procfs.h" +#ifdef HAVE_LIBCPUFREQ +#include "cpufreq-selector-libcpufreq.h" +#endif + +CPUFreqSelector * +cpufreq_selector_factory_create_selector (guint cpu) +{ + CPUFreqSelector *selector = NULL; + +#ifdef HAVE_LIBCPUFREQ + selector = cpufreq_selector_libcpufreq_new (cpu); +#else + if (g_file_test ("/sys/devices/system/cpu/cpu0/cpufreq", G_FILE_TEST_EXISTS)) { /* 2.6 kernel */ + selector = cpufreq_selector_sysfs_new (cpu); + } else if (g_file_test ("/proc/cpufreq", G_FILE_TEST_EXISTS)) { /* 2.4 kernel */ + selector = cpufreq_selector_procfs_new (cpu); + } +#endif /* HAVE_LIBCPUFREQ */ + + return selector; +} diff --git a/cpufreq/src/cpufreq-selector/cpufreq-selector-factory.h b/cpufreq/src/cpufreq-selector/cpufreq-selector-factory.h new file mode 100644 index 00000000..fba0a8dc --- /dev/null +++ b/cpufreq/src/cpufreq-selector/cpufreq-selector-factory.h @@ -0,0 +1,31 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2008 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef CPUFREQ_SELECTOR_FACTORY +#define CPUFREQ_SELECTOR_FACTORY + +#include "cpufreq-selector.h" + +G_BEGIN_DECLS + +CPUFreqSelector *cpufreq_selector_factory_create_selector (guint cpu); + +G_END_DECLS + +#endif /* CPUFREQ_SELECTOR_FACTORY */ diff --git a/cpufreq/src/cpufreq-selector/cpufreq-selector-libcpufreq.c b/cpufreq/src/cpufreq-selector/cpufreq-selector-libcpufreq.c new file mode 100644 index 00000000..4b9573b3 --- /dev/null +++ b/cpufreq/src/cpufreq-selector/cpufreq-selector-libcpufreq.c @@ -0,0 +1,197 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#include <glib.h> +#include <glib/gstdio.h> +#include <cpufreq.h> +#include <stdlib.h> + +#include "cpufreq-selector-libcpufreq.h" + +static void cpufreq_selector_libcpufreq_init (CPUFreqSelectorLibcpufreq *selector); +static void cpufreq_selector_libcpufreq_class_init (CPUFreqSelectorLibcpufreqClass *klass); + +static gboolean cpufreq_selector_libcpufreq_set_frequency (CPUFreqSelector *selector, + guint frequency, + GError **error); +static gboolean cpufreq_selector_libcpufreq_set_governor (CPUFreqSelector *selector, + const gchar *governor, + GError **error); + +G_DEFINE_TYPE (CPUFreqSelectorLibcpufreq, cpufreq_selector_libcpufreq, CPUFREQ_TYPE_SELECTOR) + +typedef struct cpufreq_policy CPUFreqPolicy; +typedef struct cpufreq_available_frequencies CPUFreqFrequencyList; +typedef struct cpufreq_available_governors CPUFreqGovernorList; + +static void +cpufreq_selector_libcpufreq_init (CPUFreqSelectorLibcpufreq *selector) +{ +} + +static void +cpufreq_selector_libcpufreq_class_init (CPUFreqSelectorLibcpufreqClass *klass) +{ + CPUFreqSelectorClass *selector_class = CPUFREQ_SELECTOR_CLASS (klass); + + selector_class->set_frequency = cpufreq_selector_libcpufreq_set_frequency; + selector_class->set_governor = cpufreq_selector_libcpufreq_set_governor; +} + +CPUFreqSelector * +cpufreq_selector_libcpufreq_new (guint cpu) +{ + CPUFreqSelector *selector; + + selector = CPUFREQ_SELECTOR (g_object_new (CPUFREQ_TYPE_SELECTOR_LIBCPUFREQ, + "cpu", cpu, + NULL)); + + return selector; +} + +static guint +cpufreq_selector_libcpufreq_get_valid_frequency (CPUFreqSelectorLibcpufreq *selector, + guint frequency) +{ + guint cpu; + gint dist = G_MAXINT; + guint retval = 0; + CPUFreqFrequencyList *freqs, *freq; + + g_object_get (G_OBJECT (selector), + "cpu", &cpu, + NULL); + + freqs = cpufreq_get_available_frequencies (cpu); + if (!freqs) + return 0; + + for (freq = freqs; freq; freq = freq->next) { + guint current_dist; + + if (freq->frequency == frequency) { + cpufreq_put_available_frequencies (freqs); + + return frequency; + } + + current_dist = abs (freq->frequency - frequency); + if (current_dist < dist) { + dist = current_dist; + retval = freq->frequency; + } + } + + return retval; +} + +static gboolean +cpufreq_selector_libcpufreq_set_frequency (CPUFreqSelector *selector, + guint frequency, + GError **error) +{ + guint freq; + guint cpu; + + g_object_get (G_OBJECT (selector), + "cpu", &cpu, + NULL); + + freq = cpufreq_selector_libcpufreq_get_valid_frequency (CPUFREQ_SELECTOR_LIBCPUFREQ (selector), + frequency); + if (cpufreq_set_frequency (cpu, freq) != 0) { + g_set_error (error, + CPUFREQ_SELECTOR_ERROR, + SELECTOR_ERROR_SET_FREQUENCY, + "Cannot set frequency '%d'", + frequency); + + return FALSE; + } + + return TRUE; +} + +static gboolean +cpufreq_selector_libcpufreq_validate_governor (CPUFreqSelectorLibcpufreq *selector, + const gchar *governor) +{ + guint cpu; + CPUFreqGovernorList *govs, *gov; + + g_object_get (G_OBJECT (selector), + "cpu", &cpu, + NULL); + + govs = cpufreq_get_available_governors (cpu); + if (!govs) + return FALSE; + + for (gov = govs; gov; gov = gov->next) { + if (g_ascii_strcasecmp (gov->governor, governor) == 0) { + cpufreq_put_available_governors (govs); + + return TRUE; + } + } + + cpufreq_put_available_governors (govs); + + return FALSE; +} + +static gboolean +cpufreq_selector_libcpufreq_set_governor (CPUFreqSelector *selector, + const gchar *governor, + GError **error) +{ + CPUFreqSelectorLibcpufreq *selector_libcpufreq; + guint cpu; + + selector_libcpufreq = CPUFREQ_SELECTOR_LIBCPUFREQ (selector); + + if (!cpufreq_selector_libcpufreq_validate_governor (selector_libcpufreq, governor)) { + g_set_error (error, + CPUFREQ_SELECTOR_ERROR, + SELECTOR_ERROR_INVALID_GOVERNOR, + "Invalid governor '%s'", + governor); + + return FALSE; + } + + g_object_get (G_OBJECT (selector), + "cpu", &cpu, + NULL); + + if (cpufreq_modify_policy_governor (cpu, (gchar *)governor) != 0) { + g_set_error (error, + CPUFREQ_SELECTOR_ERROR, + SELECTOR_ERROR_INVALID_GOVERNOR, + "Invalid governor '%s'", + governor); + + return FALSE; + } + + return TRUE; +} diff --git a/cpufreq/src/cpufreq-selector/cpufreq-selector-libcpufreq.h b/cpufreq/src/cpufreq-selector/cpufreq-selector-libcpufreq.h new file mode 100644 index 00000000..37dcda63 --- /dev/null +++ b/cpufreq/src/cpufreq-selector/cpufreq-selector-libcpufreq.h @@ -0,0 +1,61 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#ifndef __CPUFREQ_SELECTOR_LIBCPUFREQ_H__ +#define __CPUFREQ_SELECTOR_LIBCPUFREQ_H__ + +#include <glib-object.h> + +#include "cpufreq-selector.h" + +G_BEGIN_DECLS + +#define CPUFREQ_TYPE_SELECTOR_LIBCPUFREQ \ + (cpufreq_selector_libcpufreq_get_type ()) +#define CPUFREQ_SELECTOR_LIBCPUFREQ(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), CPUFREQ_TYPE_SELECTOR_LIBCPUFREQ, CPUFreqSelectorLibcpufreq)) +#define CPUFREQ_SELECTOR_LIBCPUFREQ_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), CPUFREQ_TYPE_SELECTOR_LIBCPUFREQ, CPUFreqSelectorLibcpufreqClass)) +#define CPUFREQ_IS_SELECTOR_LIBCPUFREQ(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CPUFREQ_TYPE_SELECTOR_LIBCPUFREQ)) +#define CPUFREQ_IS_SELECTOR_LIBCPUFREQ_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), CPUFREQ_TYPE_SELECTOR_LIBCPUFREQ)) +#define CPUFREQ_SELECTOR_LIBCPUFREQ_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), CPUFREQ_TYPE_SELECTOR_LIBCPUFREQ, CPUFreqSelectorLibcpufreqClass)) + +typedef struct _CPUFreqSelectorLibcpufreq CPUFreqSelectorLibcpufreq; +typedef struct _CPUFreqSelectorLibcpufreqClass CPUFreqSelectorLibcpufreqClass; + +struct _CPUFreqSelectorLibcpufreq { + CPUFreqSelector parent; +}; + +struct _CPUFreqSelectorLibcpufreqClass { + CPUFreqSelectorClass parent_class; +}; + + +GType cpufreq_selector_libcpufreq_get_type (void) G_GNUC_CONST; +CPUFreqSelector *cpufreq_selector_libcpufreq_new (guint cpu); + +G_END_DECLS + +#endif /* __CPUFREQ_SELECTOR_SYSFS_H__ */ diff --git a/cpufreq/src/cpufreq-selector/cpufreq-selector-procfs.c b/cpufreq/src/cpufreq-selector/cpufreq-selector-procfs.c new file mode 100644 index 00000000..f08d681d --- /dev/null +++ b/cpufreq/src/cpufreq-selector/cpufreq-selector-procfs.c @@ -0,0 +1,243 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#include <glib.h> +#include <glib/gstdio.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#include "cpufreq-selector-procfs.h" + +static void cpufreq_selector_procfs_init (CPUFreqSelectorProcfs *selector); +static void cpufreq_selector_procfs_class_init (CPUFreqSelectorProcfsClass *klass); + +static gboolean cpufreq_selector_procfs_set_frequency (CPUFreqSelector *selector, + guint frequency, + GError **error); +static gboolean cpufreq_selector_procfs_set_governor (CPUFreqSelector *selector, + const gchar *governor, + GError **error); + +G_DEFINE_TYPE (CPUFreqSelectorProcfs, cpufreq_selector_procfs, CPUFREQ_TYPE_SELECTOR) + +static void +cpufreq_selector_procfs_init (CPUFreqSelectorProcfs *selector) +{ +} + +static void +cpufreq_selector_procfs_class_init (CPUFreqSelectorProcfsClass *klass) +{ + CPUFreqSelectorClass *selector_class = CPUFREQ_SELECTOR_CLASS (klass); + + selector_class->set_frequency = cpufreq_selector_procfs_set_frequency; + selector_class->set_governor = cpufreq_selector_procfs_set_governor; +} + +CPUFreqSelector * +cpufreq_selector_procfs_new (guint cpu) +{ + CPUFreqSelector *selector; + + selector = CPUFREQ_SELECTOR (g_object_new (CPUFREQ_TYPE_SELECTOR_PROCFS, + "cpu", cpu, + NULL)); + + return selector; +} + +static gboolean +cpufreq_procfs_read (guint selector_cpu, + guint *fmax, + guint *pmin, + guint *pmax, + guint *fmin, + gchar *mode, + GError **error) +{ + gchar **lines; + gchar *buffer = NULL; + gint i; + guint cpu; + gboolean found = FALSE; + + if (!g_file_get_contents ("/proc/cpufreq", &buffer, NULL, error)) { + return FALSE; + } + + lines = g_strsplit (buffer, "\n", -1); + for (i = 0; lines[i]; i++) { + if (g_ascii_strncasecmp (lines[i], "CPU", 3) == 0) { + /* CPU 0 650000 kHz ( 81 %) - 800000 kHz (100 %) - powersave */ + sscanf (lines[i], "CPU %u %u kHz (%u %%) - %u kHz (%u %%) - %20s", + &cpu, fmin, pmin, fmax, pmax, mode); + + if (cpu == selector_cpu) { + found = TRUE; + break; + } + } + } + + g_strfreev (lines); + g_free (buffer); + + if (!found) { + g_set_error (error, + CPUFREQ_SELECTOR_ERROR, + SELECTOR_ERROR_INVALID_CPU, + "Invalid CPU number '%d'", + selector_cpu); + + return FALSE; + } + + return TRUE; +} + +static gboolean +cpufreq_procfs_write (const gchar *path, + const gchar *setting, + GError **error) +{ + FILE *fd; + + fd = g_fopen (path, "w"); + + if (!fd) { + g_set_error (error, + G_FILE_ERROR, + g_file_error_from_errno (errno), + "Failed to open '%s' for writing: " + "g_fopen() failed: %s", + path, + g_strerror (errno)); + + return FALSE; + } + + if (g_fprintf (fd, "%s", setting) < 0) { + g_set_error (error, + G_FILE_ERROR, + g_file_error_from_errno (errno), + "Failed to write '%s': " + "g_fprintf() failed: %s", + path, + g_strerror (errno)); + + fclose (fd); + + return FALSE; + } + + fclose (fd); + + return TRUE; +} + +static gboolean +cpufreq_selector_procfs_set_frequency (CPUFreqSelector *selector, + guint frequency, + GError **error) +{ + gchar *str; + gchar *path; + guint freq; + guint cpu; + guint pmin, pmax; + guint sc_max, sc_min; + gchar mode[21]; + + g_object_get (G_OBJECT (selector), + "cpu", &cpu, + NULL); + + if (!cpufreq_procfs_read (cpu, &sc_max, &pmin, &pmax, &sc_min, mode, error)) { + return FALSE; + } + + if (g_ascii_strcasecmp (mode, "userspace") != 0) { + if (!cpufreq_selector_procfs_set_governor (selector, + "userspace", + error)) { + return FALSE; + } + } + + if (frequency != sc_max && frequency != sc_min) { + if (abs (sc_max - frequency) < abs (frequency - sc_min)) + freq = sc_max; + else + freq = sc_min; + } else { + freq = frequency; + } + + path = g_strdup_printf ("/proc/sys/cpu/%u/speed", cpu); + str = g_strdup_printf ("%u", freq); + if (!cpufreq_procfs_write (path, str, error)) { + g_free (path); + g_free (str); + + return FALSE; + } + + g_free (path); + g_free (str); + + return TRUE; +} + +static gboolean +cpufreq_selector_procfs_set_governor (CPUFreqSelector *selector, + const gchar *governor, + GError **error) +{ + gchar *str; + guint cpu; + guint pmin, pmax; + guint sc_max, sc_min; + gchar mode[21]; + + g_object_get (G_OBJECT (selector), + "cpu", &cpu, + NULL); + + if (!cpufreq_procfs_read (cpu, &sc_max, &pmin, &pmax, &sc_min, mode, error)) { + return FALSE; + } + + if (g_ascii_strcasecmp (governor, mode) == 0) + return TRUE; + + str = g_strdup_printf ("%u:%u:%u:%s", cpu, sc_min, sc_max, governor); + + if (!cpufreq_procfs_write ("/proc/cpufreq", str, error)) { + g_free (str); + + return FALSE; + } + + g_free (str); + + return TRUE; +} diff --git a/cpufreq/src/cpufreq-selector/cpufreq-selector-procfs.h b/cpufreq/src/cpufreq-selector/cpufreq-selector-procfs.h new file mode 100644 index 00000000..55193731 --- /dev/null +++ b/cpufreq/src/cpufreq-selector/cpufreq-selector-procfs.h @@ -0,0 +1,54 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#ifndef __CPUFREQ_SELECTOR_PROCFS_H__ +#define __CPUFREQ_SELECTOR_PROCFS_H__ + +#include <glib-object.h> + +#include "cpufreq-selector.h" + +G_BEGIN_DECLS + +#define CPUFREQ_TYPE_SELECTOR_PROCFS (cpufreq_selector_procfs_get_type ()) +#define CPUFREQ_SELECTOR_PROCFS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CPUFREQ_TYPE_SELECTOR_PROCFS, CPUFreqSelectorProcfs)) +#define CPUFREQ_SELECTOR_PROCFS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), CPUFREQ_TYPE_SELECTOR_PROCFS, CPUFreqSelectorProcfsClass)) +#define CPUFREQ_IS_SELECTOR_PROCFS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CPUFREQ_TYPE_SELECTOR_PROCFS)) +#define CPUFREQ_IS_SELECTOR_PROCFS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CPUFREQ_TYPE_SELECTOR_PROCFS)) +#define CPUFREQ_SELECTOR_PROCFS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CPUFREQ_TYPE_SELECTOR_PROCFS, CPUFreqSelectorProcfsClass)) + +typedef struct _CPUFreqSelectorProcfs CPUFreqSelectorProcfs; +typedef struct _CPUFreqSelectorProcfsClass CPUFreqSelectorProcfsClass; + +struct _CPUFreqSelectorProcfs { + CPUFreqSelector parent; +}; + +struct _CPUFreqSelectorProcfsClass { + CPUFreqSelectorClass parent_class; +}; + +GType cpufreq_selector_procfs_get_type (void) G_GNUC_CONST; +CPUFreqSelector *cpufreq_selector_procfs_new (guint cpu); + +G_END_DECLS + +#endif /* __CPUFREQ_SELECTOR_PROCFS_H__ */ diff --git a/cpufreq/src/cpufreq-selector/cpufreq-selector-service.c b/cpufreq/src/cpufreq-selector/cpufreq-selector-service.c new file mode 100644 index 00000000..696ff220 --- /dev/null +++ b/cpufreq/src/cpufreq-selector/cpufreq-selector-service.c @@ -0,0 +1,487 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2008 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <polkit/polkit.h> +#include <dbus/dbus-glib-lowlevel.h> + +#include "cpufreq-selector.h" +#include "cpufreq-selector-factory.h" +#include "cpufreq-selector-service.h" + +#include "cpufreq-selector-service-glue.h" + +#define MAX_CPUS 255 + +struct _CPUFreqSelectorService { + GObject parent; + + CPUFreqSelector *selectors[MAX_CPUS]; + gint selectors_max; + + DBusGConnection *system_bus; + + /* PolicyKit */ + PolkitAuthority *authority; +}; + +struct _CPUFreqSelectorServiceClass { + GObjectClass parent_class; +}; + +G_DEFINE_TYPE (CPUFreqSelectorService, cpufreq_selector_service, G_TYPE_OBJECT) + +#define BUS_NAME "org.mate.CPUFreqSelector" + +GType +cpufreq_selector_service_error_get_type (void) +{ + static GType etype = 0; + + if (G_UNLIKELY (etype == 0)) { + static const GEnumValue values[] = { + { SERVICE_ERROR_GENERAL, "SERVICE_ERROR_GENERAL", "GeneralError" }, + { SERVICE_ERROR_DBUS, "SERVICE_ERROR_DBUS", "DBUSError" }, + { SERVICE_ERROR_ALREADY_REGISTERED, "SERVICE_ERROR_ALREADY_REGISTERED", "AlreadyRegistered" }, + { SERVICE_ERROR_NOT_AUTHORIZED, "SERVICE_ERROR_NOT_AUTHORIZED", "NotAuthorized"}, + { 0, NULL, NULL} + }; + + etype = g_enum_register_static ("CPUFreqSelectorServiceError", values); + } + + return etype; +} + +GQuark +cpufreq_selector_service_error_quark (void) +{ + static GQuark error_quark = 0; + + if (G_UNLIKELY (error_quark == 0)) + error_quark = + g_quark_from_static_string ("cpufreq-selector-service-error-quark"); + + return error_quark; +} + +static void +cpufreq_selector_service_finalize (GObject *object) +{ + CPUFreqSelectorService *service = CPUFREQ_SELECTOR_SERVICE (object); + gint i; + + service->system_bus = NULL; + + if (service->selectors_max >= 0) { + for (i = 0; i < service->selectors_max; i++) { + if (service->selectors[i]) { + g_object_unref (service->selectors[i]); + service->selectors[i] = NULL; + } + } + + service->selectors_max = -1; + } + + if (service->authority) { + g_object_unref (service->authority); + service->authority = NULL; + } + + G_OBJECT_CLASS (cpufreq_selector_service_parent_class)->finalize (object); +} + +static void +cpufreq_selector_service_class_init (CPUFreqSelectorServiceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = cpufreq_selector_service_finalize; +} + +static void +cpufreq_selector_service_init (CPUFreqSelectorService *service) +{ + service->selectors_max = -1; +} + +CPUFreqSelectorService * +cpufreq_selector_service_get_instance (void) +{ + static CPUFreqSelectorService *service = NULL; + + if (!service) + service = CPUFREQ_SELECTOR_SERVICE (g_object_new (CPUFREQ_TYPE_SELECTOR_SERVICE, NULL)); + + return service; +} + +static gboolean +service_shutdown (gpointer user_data) +{ + g_object_unref (SELECTOR_SERVICE); + + return FALSE; +} + +static void +reset_killtimer (void) +{ + static guint timer_id = 0; + + if (timer_id > 0) + g_source_remove (timer_id); + + timer_id = g_timeout_add_seconds (30, + (GSourceFunc) service_shutdown, + NULL); +} + +gboolean +cpufreq_selector_service_register (CPUFreqSelectorService *service, + GError **error) +{ + DBusGConnection *connection; + DBusGProxy *bus_proxy; + gboolean res; + guint result; + GError *err = NULL; + + if (service->system_bus) { + g_set_error (error, + CPUFREQ_SELECTOR_SERVICE_ERROR, + SERVICE_ERROR_ALREADY_REGISTERED, + "Service %s already registered", BUS_NAME); + return FALSE; + } + + connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err); + if (!connection) { + g_set_error (error, + CPUFREQ_SELECTOR_SERVICE_ERROR, + SERVICE_ERROR_DBUS, + "Couldn't connect to system bus: %s", + err->message); + g_error_free (err); + + return FALSE; + } + + bus_proxy = dbus_g_proxy_new_for_name (connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS); + if (!bus_proxy) { + g_set_error (error, + CPUFREQ_SELECTOR_SERVICE_ERROR, + SERVICE_ERROR_DBUS, + "Could not construct bus_proxy object"); + return FALSE; + } + + res = dbus_g_proxy_call (bus_proxy, + "RequestName", + &err, + G_TYPE_STRING, BUS_NAME, + G_TYPE_UINT, DBUS_NAME_FLAG_DO_NOT_QUEUE, + G_TYPE_INVALID, + G_TYPE_UINT, &result, + G_TYPE_INVALID); + g_object_unref (bus_proxy); + + if (!res) { + if (err) { + g_set_error (error, + CPUFREQ_SELECTOR_SERVICE_ERROR, + SERVICE_ERROR_DBUS, + "Failed to acquire %s: %s", + BUS_NAME, err->message); + g_error_free (err); + } else { + g_set_error (error, + CPUFREQ_SELECTOR_SERVICE_ERROR, + SERVICE_ERROR_DBUS, + "Failed to acquire %s", BUS_NAME); + } + + return FALSE; + } + + if (result == DBUS_REQUEST_NAME_REPLY_EXISTS) { + g_set_error (error, + CPUFREQ_SELECTOR_SERVICE_ERROR, + SERVICE_ERROR_ALREADY_REGISTERED, + "Service %s already registered", BUS_NAME); + return FALSE; + } + + service->authority = polkit_authority_get (); + + service->system_bus = connection; + + dbus_g_object_type_install_info (CPUFREQ_TYPE_SELECTOR_SERVICE, + &dbus_glib_cpufreq_selector_service_object_info); + dbus_g_connection_register_g_object (connection, + "/org/mate/cpufreq_selector/selector", + G_OBJECT (service)); + dbus_g_error_domain_register (CPUFREQ_SELECTOR_SERVICE_ERROR, NULL, + CPUFREQ_TYPE_SELECTOR_SERVICE_ERROR); + + reset_killtimer (); + + return TRUE; +} + +static CPUFreqSelector * +get_selector_for_cpu (CPUFreqSelectorService *service, + guint cpu) +{ + if (!service->selectors[cpu]) { + service->selectors[cpu] = cpufreq_selector_factory_create_selector (cpu); + if (!service->selectors[cpu]) + return NULL; + + if (service->selectors_max < cpu) + service->selectors_max = cpu; + } + + return service->selectors[cpu]; +} + +/* PolicyKit */ +static gboolean +cpufreq_selector_service_check_policy (CPUFreqSelectorService *service, + DBusGMethodInvocation *context, + GError **error) +{ + PolkitSubject *subject; + PolkitAuthorizationResult *result; + gchar *sender; + gboolean ret; + + sender = dbus_g_method_get_sender (context); + subject = polkit_system_bus_name_new (sender); + g_free (sender); + + result = polkit_authority_check_authorization_sync (service->authority, + subject, + "org.mate.cpufreqselector", + NULL, + POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, + NULL, error); + g_object_unref (subject); + + if (*error) { + g_warning ("Check policy: %s", (*error)->message); + g_object_unref (result); + + return FALSE; + } + + ret = polkit_authorization_result_get_is_authorized (result); + if (!ret) { + g_set_error (error, + CPUFREQ_SELECTOR_SERVICE_ERROR, + SERVICE_ERROR_NOT_AUTHORIZED, + "Caller is not authorized"); + } + + g_object_unref (result); + + return ret; +} + +/* D-BUS interface */ +gboolean +cpufreq_selector_service_set_frequency (CPUFreqSelectorService *service, + guint cpu, + guint frequency, + DBusGMethodInvocation *context) +{ + CPUFreqSelector *selector; + GError *error = NULL; + + reset_killtimer (); + + if (!cpufreq_selector_service_check_policy (service, context, &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + + return FALSE; + } + + if (cpu > MAX_CPUS) { + GError *err; + + err = g_error_new (CPUFREQ_SELECTOR_SERVICE_ERROR, + SERVICE_ERROR_DBUS, + "Error setting frequency on cpu %d: Invalid cpu", + cpu); + dbus_g_method_return_error (context, err); + g_error_free (err); + + return FALSE; + } + + selector = get_selector_for_cpu (service, cpu); + if (!selector) { + GError *err; + + err = g_error_new (CPUFREQ_SELECTOR_SERVICE_ERROR, + SERVICE_ERROR_DBUS, + "Error setting frequency on cpu %d: No cpufreq support", + cpu); + dbus_g_method_return_error (context, err); + g_error_free (err); + + return FALSE; + } + + cpufreq_selector_set_frequency (selector, frequency, &error); + if (error) { + GError *err; + + err = g_error_new (CPUFREQ_SELECTOR_SERVICE_ERROR, + SERVICE_ERROR_DBUS, + "Error setting frequency %d on cpu %d: %s", + frequency, cpu, error->message); + dbus_g_method_return_error (context, err); + g_error_free (err); + g_error_free (error); + + return FALSE; + } + + dbus_g_method_return (context); + + return TRUE; +} + +gboolean +cpufreq_selector_service_set_governor (CPUFreqSelectorService *service, + guint cpu, + const gchar *governor, + DBusGMethodInvocation *context) +{ + CPUFreqSelector *selector; + GError *error = NULL; + + reset_killtimer (); + + if (!cpufreq_selector_service_check_policy (service, context, &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + + return FALSE; + } + + if (cpu > MAX_CPUS) { + GError *err; + + err = g_error_new (CPUFREQ_SELECTOR_SERVICE_ERROR, + SERVICE_ERROR_DBUS, + "Error setting governor on cpu %d: Invalid cpu", + cpu); + dbus_g_method_return_error (context, err); + g_error_free (err); + + return FALSE; + } + + selector = get_selector_for_cpu (service, cpu); + if (!selector) { + GError *err; + + err = g_error_new (CPUFREQ_SELECTOR_SERVICE_ERROR, + SERVICE_ERROR_DBUS, + "Error setting governor on cpu %d: No cpufreq support", + cpu); + dbus_g_method_return_error (context, err); + g_error_free (err); + + return FALSE; + } + + cpufreq_selector_set_governor (selector, governor, &error); + if (error) { + GError *err; + + err = g_error_new (CPUFREQ_SELECTOR_SERVICE_ERROR, + SERVICE_ERROR_DBUS, + "Error setting governor %s on cpu %d: %s", + governor, cpu, error->message); + dbus_g_method_return_error (context, err); + g_error_free (err); + g_error_free (error); + + return FALSE; + } + + dbus_g_method_return (context); + + return TRUE; +} + + +gboolean +cpufreq_selector_service_can_set (CPUFreqSelectorService *service, + DBusGMethodInvocation *context) +{ + PolkitSubject *subject; + PolkitAuthorizationResult *result; + gchar *sender; + gboolean ret; + GError *error = NULL; + + reset_killtimer (); + + sender = dbus_g_method_get_sender (context); + subject = polkit_system_bus_name_new (sender); + g_free (sender); + + result = polkit_authority_check_authorization_sync (service->authority, + subject, + "org.mate.cpufreqselector", + NULL, + 0, + NULL, + &error); + g_object_unref (subject); + + if (error) { + dbus_g_method_return_error (context, error); + g_error_free (error); + + return FALSE; + } + + if (polkit_authorization_result_get_is_authorized (result)) { + ret = TRUE; + } else if (polkit_authorization_result_get_is_challenge (result)) { + ret = TRUE; + } else { + ret = FALSE; + } + + g_object_unref (result); + + dbus_g_method_return (context, ret); + + return TRUE; +} diff --git a/cpufreq/src/cpufreq-selector/cpufreq-selector-service.h b/cpufreq/src/cpufreq-selector/cpufreq-selector-service.h new file mode 100644 index 00000000..a6bcc77b --- /dev/null +++ b/cpufreq/src/cpufreq-selector/cpufreq-selector-service.h @@ -0,0 +1,71 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2008 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __CPUFREQ_SELECTOR_SERVICE_H__ +#define __CPUFREQ_SELECTOR_SERVICE_H__ + +#include <glib-object.h> +#include <dbus/dbus-glib.h> + +G_BEGIN_DECLS + +#define CPUFREQ_TYPE_SELECTOR_SERVICE (cpufreq_selector_service_get_type ()) +#define CPUFREQ_SELECTOR_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CPUFREQ_TYPE_SELECTOR_SERVICE, CPUFreqSelectorService)) +#define CPUFREQ_SELECTOR_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), CPUFREQ_TYPE_SELECTOR_SERVICE, CPUFreqSelectorServiceClass)) +#define CPUFREQ_IS_SELECTOR_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CPUFREQ_TYPE_SELECTOR_SERVICE)) +#define CPUFREQ_IS_SELECTOR_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CPUFREQ_TYPE_SELECTOR_SERVICE)) +#define CPUFREQ_SELECTOR_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CPUFREQ_TYPE_SELECTOR_SERVICE, CPUFreqSelectorServiceClass)) + +#define SELECTOR_SERVICE (cpufreq_selector_service_get_instance ()) + +#define CPUFREQ_SELECTOR_SERVICE_ERROR (cpufreq_selector_service_error_quark ()) +#define CPUFREQ_TYPE_SELECTOR_SERVICE_ERROR (cpufreq_selector_service_error_get_type ()) + +enum { + SERVICE_ERROR_GENERAL, + SERVICE_ERROR_DBUS, + SERVICE_ERROR_ALREADY_REGISTERED, + SERVICE_ERROR_NOT_AUTHORIZED +}; + +typedef struct _CPUFreqSelectorService CPUFreqSelectorService; +typedef struct _CPUFreqSelectorServiceClass CPUFreqSelectorServiceClass; + +GType cpufreq_selector_service_get_type (void) G_GNUC_CONST; +GType cpufreq_selector_service_error_get_type (void) G_GNUC_CONST; +GQuark cpufreq_selector_service_error_quark (void) G_GNUC_CONST; +CPUFreqSelectorService *cpufreq_selector_service_get_instance (void); +gboolean cpufreq_selector_service_register (CPUFreqSelectorService *service, + GError **error); + +gboolean cpufreq_selector_service_set_frequency (CPUFreqSelectorService *service, + guint cpu, + guint frequency, + DBusGMethodInvocation *context); +gboolean cpufreq_selector_service_set_governor (CPUFreqSelectorService *service, + guint cpu, + const gchar *governor, + DBusGMethodInvocation *context); +gboolean cpufreq_selector_service_can_set (CPUFreqSelectorService *service, + DBusGMethodInvocation *context); + +G_END_DECLS + +#endif /* __CPUFREQ_SELECTOR_SERVICE_H__ */ + diff --git a/cpufreq/src/cpufreq-selector/cpufreq-selector-service.xml b/cpufreq/src/cpufreq-selector/cpufreq-selector-service.xml new file mode 100644 index 00000000..798dd5b2 --- /dev/null +++ b/cpufreq/src/cpufreq-selector/cpufreq-selector-service.xml @@ -0,0 +1,23 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> + +<node name="/org/mate/CPUFreqSelector"> + <interface name="org.mate.CPUFreqSelector"> + <method name="SetFrequency"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <arg name="cpu" direction="in" type="u"/> + <arg name="frequency" direction="in" type="u"/> + </method> + + <method name="SetGovernor"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <arg name="cpu" direction="in" type="u"/> + <arg name="governor" direction="in" type="s"/> + </method> + + <method name="CanSet"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <arg name="result" direction="out" type="b"/> + </method> + + </interface> +</node> diff --git a/cpufreq/src/cpufreq-selector/cpufreq-selector-sysfs.c b/cpufreq/src/cpufreq-selector/cpufreq-selector-sysfs.c new file mode 100644 index 00000000..ae790caf --- /dev/null +++ b/cpufreq/src/cpufreq-selector/cpufreq-selector-sysfs.c @@ -0,0 +1,430 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#include <glib.h> +#include <glib/gstdio.h> +#include <stdlib.h> +#include <errno.h> + +#include "cpufreq-selector-sysfs.h" + +#define CPUFREQ_SELECTOR_SYSFS_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), CPUFREQ_TYPE_SELECTOR_SYSFS, CPUFreqSelectorSysfsPrivate)) + +struct _CPUFreqSelectorSysfsPrivate { + GList *available_freqs; + GList *available_govs; +}; + +static void cpufreq_selector_sysfs_init (CPUFreqSelectorSysfs *selector); +static void cpufreq_selector_sysfs_class_init (CPUFreqSelectorSysfsClass *klass); +static void cpufreq_selector_sysfs_finalize (GObject *object); + +static gboolean cpufreq_selector_sysfs_set_frequency (CPUFreqSelector *selector, + guint frequency, + GError **error); +static gboolean cpufreq_selector_sysfs_set_governor (CPUFreqSelector *selector, + const gchar *governor, + GError **error); + +#define CPUFREQ_SYSFS_BASE_PATH "/sys/devices/system/cpu/cpu%u/cpufreq/%s" + +G_DEFINE_TYPE (CPUFreqSelectorSysfs, cpufreq_selector_sysfs, CPUFREQ_TYPE_SELECTOR) + +static void +cpufreq_selector_sysfs_init (CPUFreqSelectorSysfs *selector) +{ + selector->priv = CPUFREQ_SELECTOR_SYSFS_GET_PRIVATE (selector); + + selector->priv->available_freqs = NULL; + selector->priv->available_govs = NULL; +} + +static void +cpufreq_selector_sysfs_class_init (CPUFreqSelectorSysfsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CPUFreqSelectorClass *selector_class = CPUFREQ_SELECTOR_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CPUFreqSelectorSysfsPrivate)); + + selector_class->set_frequency = cpufreq_selector_sysfs_set_frequency; + selector_class->set_governor = cpufreq_selector_sysfs_set_governor; + + object_class->finalize = cpufreq_selector_sysfs_finalize; +} + +static void +cpufreq_selector_sysfs_finalize (GObject *object) +{ + CPUFreqSelectorSysfs *selector = CPUFREQ_SELECTOR_SYSFS (object); + + if (selector->priv->available_freqs) { + g_list_foreach (selector->priv->available_freqs, + (GFunc) g_free, + NULL); + g_list_free (selector->priv->available_freqs); + selector->priv->available_freqs = NULL; + } + + if (selector->priv->available_govs) { + g_list_foreach (selector->priv->available_govs, + (GFunc) g_free, + NULL); + g_list_free (selector->priv->available_govs); + selector->priv->available_govs = NULL; + } + + G_OBJECT_CLASS (cpufreq_selector_sysfs_parent_class)->finalize (object); +} + +CPUFreqSelector * +cpufreq_selector_sysfs_new (guint cpu) +{ + CPUFreqSelector *selector; + + selector = CPUFREQ_SELECTOR (g_object_new (CPUFREQ_TYPE_SELECTOR_SYSFS, + "cpu", cpu, + NULL)); + + return selector; +} + +static gchar * +cpufreq_sysfs_read (const gchar *path, + GError **error) +{ + gchar *buffer = NULL; + + if (!g_file_get_contents (path, &buffer, NULL, error)) { + return NULL; + } + + return g_strchomp (buffer); +} + +static gboolean +cpufreq_sysfs_write (const gchar *path, + const gchar *setting, + GError **error) +{ + FILE *fd; + + fd = g_fopen (path, "w"); + + if (!fd) { + g_set_error (error, + G_FILE_ERROR, + g_file_error_from_errno (errno), + "Failed to open '%s' for writing: " + "g_fopen() failed: %s", + path, + g_strerror (errno)); + + return FALSE; + } + + if (g_fprintf (fd, "%s", setting) < 0) { + g_set_error (error, + G_FILE_ERROR, + g_file_error_from_errno (errno), + "Failed to write '%s': " + "g_fprintf() failed: %s", + path, + g_strerror (errno)); + + fclose (fd); + + return FALSE; + } + + fclose (fd); + + return TRUE; +} + +static gint +compare (gconstpointer a, gconstpointer b) +{ + gint aa, bb; + + aa = atoi ((gchar *) a); + bb = atoi ((gchar *) b); + + if (aa == bb) + return 0; + else if (aa > bb) + return -1; + else + return 1; +} + +static GList * +cpufreq_selector_sysfs_get_freqs (CPUFreqSelectorSysfs *selector) +{ + gchar *buffer; + GList *list = NULL; + gchar **frequencies = NULL; + gint i; + gchar *path; + guint cpu; + GError *error = NULL; + + g_object_get (G_OBJECT (selector), + "cpu", &cpu, + NULL); + + path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, cpu, + "scaling_available_frequencies"); + + buffer = cpufreq_sysfs_read (path, &error); + if (!buffer) { + g_warning ("%s", error->message); + g_error_free (error); + + g_free (path); + + return NULL; + } + + g_free (path); + + frequencies = g_strsplit (buffer, " ", -1); + + i = 0; + while (frequencies[i]) { + if (!g_list_find_custom (list, frequencies[i], compare)) + list = g_list_prepend (list, g_strdup (frequencies[i])); + i++; + } + + g_strfreev (frequencies); + g_free (buffer); + + return g_list_sort (list, compare); +} + +static const gchar * +cpufreq_selector_sysfs_get_valid_frequency (CPUFreqSelectorSysfs *selector, + guint frequency) +{ + GList *list = NULL; + GList *l; + gint dist = G_MAXINT; + const gchar *retval = NULL; + + if (!selector->priv->available_freqs) { + list = cpufreq_selector_sysfs_get_freqs (selector); + selector->priv->available_freqs = list; + } else { + list = selector->priv->available_freqs; + } + + if (!list) + return NULL; + + for (l = list; l && l->data; l = g_list_next (l)) { + const gchar *freq; + guint f; + guint current_dist; + + freq = (const gchar *) l->data; + f = atoi (freq); + + if (f == frequency) + return freq; + + current_dist = abs (frequency - f); + if (current_dist < dist) { + dist = current_dist; + retval = freq; + } + } + + return retval; +} + +static gboolean +cpufreq_selector_sysfs_set_frequency (CPUFreqSelector *selector, + guint frequency, + GError **error) +{ + gchar *governor; + gchar *path; + const gchar *frequency_text; + guint cpu; + + g_object_get (G_OBJECT (selector), + "cpu", &cpu, + NULL); + + path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, cpu, + "scaling_governor"); + + governor = cpufreq_sysfs_read (path, error); + g_free (path); + + if (!governor) + return FALSE; + + if (g_ascii_strcasecmp (governor, "userspace") != 0) { + if (!cpufreq_selector_sysfs_set_governor (selector, + "userspace", + error)) { + g_free (governor); + + return FALSE; + } + } + + g_free (governor); + + frequency_text = + cpufreq_selector_sysfs_get_valid_frequency (CPUFREQ_SELECTOR_SYSFS (selector), + frequency); + if (!frequency_text) { + g_set_error (error, + CPUFREQ_SELECTOR_ERROR, + SELECTOR_ERROR_SET_FREQUENCY, + "Cannot set frequency '%d'", + frequency); + + return FALSE; + } + + path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, cpu, + "scaling_setspeed"); + if (!cpufreq_sysfs_write (path, frequency_text, error)) { + g_free (path); + + return FALSE; + } + + g_free (path); + + return TRUE; +} + +static GList * +cpufreq_selector_sysfs_get_govs (CPUFreqSelectorSysfs *selector) +{ + gchar *buffer; + GList *list = NULL; + gchar **governors = NULL; + gint i; + gchar *path; + guint cpu; + GError *error = NULL; + + g_object_get (G_OBJECT (selector), + "cpu", &cpu, + NULL); + + path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, cpu, + "scaling_available_governors"); + + buffer = cpufreq_sysfs_read (path, &error); + if (!buffer) { + g_warning ("%s", error->message); + g_error_free (error); + + g_free (path); + + return NULL; + } + + g_free (path); + + governors = g_strsplit (buffer, " ", -1); + + i = 0; + while (governors[i]) { + list = g_list_prepend (list, g_strdup (governors[i])); + i++; + } + + g_strfreev (governors); + g_free (buffer); + + return list; +} + +static gboolean +cpufreq_selector_sysfs_validate_governor (CPUFreqSelectorSysfs *selector, + const gchar *governor) +{ + GList *list = NULL; + + if (!selector->priv->available_govs) { + list = cpufreq_selector_sysfs_get_govs (selector); + selector->priv->available_govs = list; + } else { + list = selector->priv->available_govs; + } + + if (!list) + return FALSE; + + list = g_list_find_custom (selector->priv->available_govs, + governor, + (GCompareFunc) g_ascii_strcasecmp); + + return (list != NULL); +} + +static gboolean +cpufreq_selector_sysfs_set_governor (CPUFreqSelector *selector, + const gchar *governor, + GError **error) +{ + CPUFreqSelectorSysfs *selector_sysfs; + gchar *path; + guint cpu; + + selector_sysfs = CPUFREQ_SELECTOR_SYSFS (selector); + + if (!cpufreq_selector_sysfs_validate_governor (selector_sysfs, governor)) { + g_set_error (error, + CPUFREQ_SELECTOR_ERROR, + SELECTOR_ERROR_INVALID_GOVERNOR, + "Invalid governor '%s'", + governor); + + return FALSE; + } + + g_object_get (G_OBJECT (selector), + "cpu", &cpu, + NULL); + + path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, cpu, + "scaling_governor"); + + if (!cpufreq_sysfs_write (path, governor, error)) { + g_free (path); + + return FALSE; + } + + g_free (path); + + return TRUE; +} diff --git a/cpufreq/src/cpufreq-selector/cpufreq-selector-sysfs.h b/cpufreq/src/cpufreq-selector/cpufreq-selector-sysfs.h new file mode 100644 index 00000000..a2608bbc --- /dev/null +++ b/cpufreq/src/cpufreq-selector/cpufreq-selector-sysfs.h @@ -0,0 +1,58 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#ifndef __CPUFREQ_SELECTOR_SYSFS_H__ +#define __CPUFREQ_SELECTOR_SYSFS_H__ + +#include <glib-object.h> + +#include "cpufreq-selector.h" + +G_BEGIN_DECLS + +#define CPUFREQ_TYPE_SELECTOR_SYSFS (cpufreq_selector_sysfs_get_type ()) +#define CPUFREQ_SELECTOR_SYSFS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CPUFREQ_TYPE_SELECTOR_SYSFS, CPUFreqSelectorSysfs)) +#define CPUFREQ_SELECTOR_SYSFS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), CPUFREQ_TYPE_SELECTOR_SYSFS, CPUFreqSelectorSysfsClass)) +#define CPUFREQ_IS_SELECTOR_SYSFS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CPUFREQ_TYPE_SELECTOR_SYSFS)) +#define CPUFREQ_IS_SELECTOR_SYSFS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CPUFREQ_TYPE_SELECTOR_SYSFS)) +#define CPUFREQ_SELECTOR_SYSFS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CPUFREQ_TYPE_SELECTOR_SYSFS, CPUFreqSelectorSysfsClass)) + +typedef struct _CPUFreqSelectorSysfs CPUFreqSelectorSysfs; +typedef struct _CPUFreqSelectorSysfsClass CPUFreqSelectorSysfsClass; +typedef struct _CPUFreqSelectorSysfsPrivate CPUFreqSelectorSysfsPrivate; + +struct _CPUFreqSelectorSysfs { + CPUFreqSelector parent; + + CPUFreqSelectorSysfsPrivate *priv; +}; + +struct _CPUFreqSelectorSysfsClass { + CPUFreqSelectorClass parent_class; +}; + + +GType cpufreq_selector_sysfs_get_type (void) G_GNUC_CONST; +CPUFreqSelector *cpufreq_selector_sysfs_new (guint cpu); + +G_END_DECLS + +#endif /* __CPUFREQ_SELECTOR_SYSFS_H__ */ diff --git a/cpufreq/src/cpufreq-selector/cpufreq-selector.c b/cpufreq/src/cpufreq-selector/cpufreq-selector.c new file mode 100644 index 00000000..f019fec3 --- /dev/null +++ b/cpufreq/src/cpufreq-selector/cpufreq-selector.c @@ -0,0 +1,173 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#include <glib.h> +#include "cpufreq-selector.h" + +#define CPUFREQ_SELECTOR_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), CPUFREQ_TYPE_SELECTOR, CPUFreqSelectorPrivate)) + +enum { + PROP_0, + PROP_CPU +}; + +struct _CPUFreqSelectorPrivate { + guint cpu; +}; + +static void cpufreq_selector_init (CPUFreqSelector *selector); +static void cpufreq_selector_class_init (CPUFreqSelectorClass *klass); + +static void cpufreq_selector_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *spec); +static void cpufreq_selector_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *spec); + +G_DEFINE_ABSTRACT_TYPE (CPUFreqSelector, cpufreq_selector, G_TYPE_OBJECT) + +GQuark +cpufreq_selector_error_quark (void) +{ + static GQuark error_quark = 0; + + if (error_quark == 0) + error_quark = + g_quark_from_static_string ("cpufreq-selector-error-quark"); + + return error_quark; +} + +static void +cpufreq_selector_init (CPUFreqSelector *selector) +{ + + selector->priv = CPUFREQ_SELECTOR_GET_PRIVATE (selector); + + selector->priv->cpu = 0; +} + +static void +cpufreq_selector_class_init (CPUFreqSelectorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CPUFreqSelectorPrivate)); + + object_class->set_property = cpufreq_selector_set_property; + object_class->get_property = cpufreq_selector_get_property; + + /* Public virtual methods */ + klass->set_frequency = NULL; + klass->set_governor = NULL; + + /* Porperties */ + g_object_class_install_property (object_class, + PROP_CPU, + g_param_spec_uint ("cpu", + NULL, + NULL, + 0, + G_MAXUINT, + 0, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE)); +} + +static void +cpufreq_selector_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *spec) +{ + CPUFreqSelector *selector = CPUFREQ_SELECTOR (object); + + switch (prop_id) { + case PROP_CPU: + selector->priv->cpu = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, spec); + break; + } +} + +static void +cpufreq_selector_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *spec) +{ + CPUFreqSelector *selector = CPUFREQ_SELECTOR (object); + + switch (prop_id) { + case PROP_CPU: + g_value_set_uint (value, selector->priv->cpu); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, spec); + break; + } +} + +gboolean +cpufreq_selector_set_frequency (CPUFreqSelector *selector, + guint frequency, + GError **error) +{ + CPUFreqSelectorClass *class; + + g_return_val_if_fail (CPUFREQ_IS_SELECTOR (selector), FALSE); + g_return_val_if_fail (frequency > 0, FALSE); + + class = CPUFREQ_SELECTOR_GET_CLASS (selector); + + if (class->set_frequency) { + return class->set_frequency (selector, frequency, error); + } + + return FALSE; +} + +gboolean +cpufreq_selector_set_governor (CPUFreqSelector *selector, + const gchar *governor, + GError **error) +{ + CPUFreqSelectorClass *class; + + g_return_val_if_fail (CPUFREQ_IS_SELECTOR (selector), FALSE); + g_return_val_if_fail (governor != NULL, FALSE); + + class = CPUFREQ_SELECTOR_GET_CLASS (selector); + + if (class->set_governor) { + return class->set_governor (selector, governor, error); + } + + return FALSE; +} + + diff --git a/cpufreq/src/cpufreq-selector/cpufreq-selector.h b/cpufreq/src/cpufreq-selector/cpufreq-selector.h new file mode 100644 index 00000000..73e41054 --- /dev/null +++ b/cpufreq/src/cpufreq-selector/cpufreq-selector.h @@ -0,0 +1,74 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#ifndef __CPUFREQ_SELECTOR_H__ +#define __CPUFREQ_SELECTOR_H__ + +#include <glib-object.h> + +#define CPUFREQ_TYPE_SELECTOR (cpufreq_selector_get_type ()) +#define CPUFREQ_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CPUFREQ_TYPE_SELECTOR, CPUFreqSelector)) +#define CPUFREQ_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), CPUFREQ_TYPE_SELECTOR, CPUFreqSelectorClass)) +#define CPUFREQ_IS_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CPUFREQ_TYPE_SELECTOR)) +#define CPUFREQ_IS_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CPUFREQ_TYPE_SELECTOR)) +#define CPUFREQ_SELECTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CPUFREQ_TYPE_SELECTOR, CPUFreqSelectorClass)) + +#define CPUFREQ_SELECTOR_ERROR (cpufreq_selector_error_quark ()) + +enum { + SELECTOR_ERROR_INVALID_CPU, + SELECTOR_ERROR_INVALID_GOVERNOR, + SELECTOR_ERROR_SET_FREQUENCY +}; + +typedef struct _CPUFreqSelector CPUFreqSelector; +typedef struct _CPUFreqSelectorClass CPUFreqSelectorClass; +typedef struct _CPUFreqSelectorPrivate CPUFreqSelectorPrivate; + +struct _CPUFreqSelector { + GObject parent; + + CPUFreqSelectorPrivate *priv; +}; + +struct _CPUFreqSelectorClass { + GObjectClass parent_class; + + gboolean (* set_frequency) (CPUFreqSelector *selector, + guint frequency, + GError **error); + gboolean (* set_governor) (CPUFreqSelector *selector, + const gchar *governor, + GError **error); +}; + + +GType cpufreq_selector_get_type (void) G_GNUC_CONST; +GQuark cpufreq_selector_error_quark (void) G_GNUC_CONST; + +gboolean cpufreq_selector_set_frequency (CPUFreqSelector *selector, + guint frequency, + GError **error); +gboolean cpufreq_selector_set_governor (CPUFreqSelector *selector, + const gchar *governor, + GError **error); + +#endif /* __CPUFREQ_SELECTOR_H__ */ diff --git a/cpufreq/src/cpufreq-selector/main.c b/cpufreq/src/cpufreq-selector/main.c new file mode 100644 index 00000000..f0fbb7b1 --- /dev/null +++ b/cpufreq/src/cpufreq-selector/main.c @@ -0,0 +1,233 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <glib.h> +#include <glib-object.h> + +#ifdef HAVE_POLKIT +#include "cpufreq-selector-service.h" +#endif +#include "cpufreq-selector-factory.h" + + +static gint cpu = 0; +static gchar *governor = NULL; +static gulong frequency = 0; + +static const GOptionEntry options[] = { + { "cpu", 'c', 0, G_OPTION_ARG_INT, &cpu, "CPU Number", NULL }, + { "governor", 'g', 0, G_OPTION_ARG_STRING, &governor, "Governor", NULL }, + { "frequency", 'f', 0, G_OPTION_ARG_INT, &frequency, "Frequency in KHz", NULL }, + { NULL } +}; + +#ifdef HAVE_POLKIT +static void +do_exit (GMainLoop *loop, + GObject *object) +{ + if (g_main_loop_is_running (loop)) + g_main_loop_quit (loop); +} + +static void +cpufreq_selector_set_values_dbus (void) +{ + DBusGConnection *connection; + DBusGProxy *proxy; + gboolean res; + GError *error = NULL; + + connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (!connection) { + g_printerr ("Couldn't connect to system bus: %s\n", + error->message); + g_error_free (error); + + return; + } + + proxy = dbus_g_proxy_new_for_name (connection, + "org.mate.CPUFreqSelector", + "/org/mate/cpufreq_selector/selector", + "org.mate.CPUFreqSelector"); + if (!proxy) { + g_printerr ("Could not construct proxy object\n"); + + return; + } + + if (governor) { + res = dbus_g_proxy_call (proxy, "SetGovernor", &error, + G_TYPE_UINT, cpu, + G_TYPE_STRING, governor, + G_TYPE_INVALID, + G_TYPE_INVALID); + if (!res) { + if (error) { + g_printerr ("Error calling SetGovernor: %s\n", error->message); + g_error_free (error); + } else { + g_printerr ("Error calling SetGovernor\n"); + } + + g_object_unref (proxy); + + return; + } + } + + if (frequency != 0) { + res = dbus_g_proxy_call (proxy, "SetFrequency", &error, + G_TYPE_UINT, cpu, + G_TYPE_UINT, frequency, + G_TYPE_INVALID, + G_TYPE_INVALID); + if (!res) { + if (error) { + g_printerr ("Error calling SetFrequency: %s\n", error->message); + g_error_free (error); + } else { + g_printerr ("Error calling SetFrequency\n"); + } + + g_object_unref (proxy); + + return; + } + } + + g_object_unref (proxy); +} +#endif /* HAVE_POLKIT */ + +static void +cpufreq_selector_set_values (void) +{ + CPUFreqSelector *selector; + GError *error = NULL; + + selector = cpufreq_selector_factory_create_selector (cpu); + if (!selector) { + g_printerr ("No cpufreq support\n"); + + return; + } + + if (governor) { + cpufreq_selector_set_governor (selector, governor, &error); + + if (error) { + g_printerr ("%s\n", error->message); + g_error_free (error); + error = NULL; + } + } + + if (frequency != 0) { + cpufreq_selector_set_frequency (selector, frequency, &error); + + if (error) { + g_printerr ("%s\n", error->message); + g_error_free (error); + error = NULL; + } + } + + g_object_unref (selector); +} + +gint +main (gint argc, gchar **argv) +{ +#ifdef HAVE_POLKIT + GMainLoop *loop; +#endif + GOptionContext *context; + GError *error = NULL; + +#ifndef HAVE_POLKIT + if (geteuid () != 0) { + g_printerr ("You must be root\n"); + + return 1; + } + + if (argc < 2) { + g_printerr ("Missing operand after `cpufreq-selector'\n"); + g_printerr ("Try `cpufreq-selector --help' for more information.\n"); + + return 1; + } +#endif + + g_type_init (); + + context = g_option_context_new ("- CPUFreq Selector"); + g_option_context_add_main_entries (context, options, NULL); + + if (!g_option_context_parse (context, &argc, &argv, &error)) { + if (error) { + g_printerr ("%s\n", error->message); + g_error_free (error); + } + + g_option_context_free (context); + + return 1; + } + + g_option_context_free (context); + +#ifdef HAVE_POLKIT + if (!cpufreq_selector_service_register (SELECTOR_SERVICE, &error)) { + if (governor || frequency != 0) { + cpufreq_selector_set_values_dbus (); + + return 0; + } + + g_printerr ("%s\n", error->message); + g_error_free (error); + + return 1; + } + + cpufreq_selector_set_values (); + + loop = g_main_loop_new (NULL, FALSE); + g_object_weak_ref (G_OBJECT (SELECTOR_SERVICE), + (GWeakNotify) do_exit, + loop); + + g_main_loop_run (loop); + + g_main_loop_unref (loop); +#else /* !HAVE_POLKIT */ + cpufreq_selector_set_values (); +#endif /* HAVE_POLKIT */ + + return 0; +} diff --git a/cpufreq/src/cpufreq-selector/org.mate.CPUFreqSelector.conf b/cpufreq/src/cpufreq-selector/org.mate.CPUFreqSelector.conf new file mode 100644 index 00000000..c4b27a23 --- /dev/null +++ b/cpufreq/src/cpufreq-selector/org.mate.CPUFreqSelector.conf @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!DOCTYPE busconfig PUBLIC + "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> + +<busconfig> + + <!-- Only root can own the service --> + <policy user="root"> + <allow own="org.mate.CPUFreqSelector"/> + <allow send_interface="org.mate.CPUFreqSelector"/> + </policy> + + <policy context="default"> + <allow send_interface="org.mate.CPUFreqSelector"/> + </policy> + +</busconfig> + diff --git a/cpufreq/src/cpufreq-selector/org.mate.CPUFreqSelector.service.in b/cpufreq/src/cpufreq-selector/org.mate.CPUFreqSelector.service.in new file mode 100644 index 00000000..e402df2e --- /dev/null +++ b/cpufreq/src/cpufreq-selector/org.mate.CPUFreqSelector.service.in @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.mate.CPUFreqSelector +Exec=@BINDIR@/cpufreq-selector +User=root diff --git a/cpufreq/src/cpufreq-selector/org.mate.cpufreqselector.policy.in b/cpufreq/src/cpufreq-selector/org.mate.cpufreqselector.policy.in new file mode 100644 index 00000000..f1249cd2 --- /dev/null +++ b/cpufreq/src/cpufreq-selector/org.mate.cpufreqselector.policy.in @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!DOCTYPE policyconfig PUBLIC + "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN" + "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd"> + +<policyconfig> + + <vendor>The MATE Project</vendor> + <vendor_url>http://www.mate.org/</vendor_url> + <icon_name>mate-cpu-frequency-applet</icon_name> + + <action id="org.mate.cpufreqselector"> + <_description>Change CPU Frequency scaling</_description> + <_message>Privileges are required to change the CPU Frequency scaling.</_message> + <defaults> + <allow_inactive>no</allow_inactive> + <allow_active>auth_admin_keep</allow_active> + </defaults> + </action> + +</policyconfig> diff --git a/cpufreq/src/cpufreq-utils.c b/cpufreq/src/cpufreq-utils.c new file mode 100644 index 00000000..47b80c1f --- /dev/null +++ b/cpufreq/src/cpufreq-utils.c @@ -0,0 +1,311 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2006 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#include <config.h> + +#include <glib.h> +#include <gtk/gtk.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include "cpufreq-utils.h" + +#ifdef HAVE_POLKIT +#include <dbus/dbus-glib.h> +#endif /* HAVE_POLKIT */ + +guint +cpufreq_utils_get_n_cpus (void) +{ + gint mcpu = -1; + gchar *file = NULL; + static guint n_cpus = 0; + + if (n_cpus > 0) + return n_cpus; + + do { + if (file) + g_free (file); + mcpu ++; + file = g_strdup_printf ("/sys/devices/system/cpu/cpu%d", mcpu); + } while (g_file_test (file, G_FILE_TEST_EXISTS)); + g_free (file); + + if (mcpu >= 0) { + n_cpus = (guint)mcpu; + return mcpu; + } + + mcpu = -1; + file = NULL; + do { + if (file) + g_free (file); + mcpu ++; + file = g_strdup_printf ("/proc/sys/cpu/%d", mcpu); + } while (g_file_test (file, G_FILE_TEST_EXISTS)); + g_free (file); + + if (mcpu >= 0) { + n_cpus = (guint)mcpu; + return mcpu; + } + + n_cpus = 1; + + return 1; +} + +void +cpufreq_utils_display_error (const gchar *message, + const gchar *secondary) +{ + GtkWidget *dialog; + + g_return_if_fail (message != NULL); + + dialog = gtk_message_dialog_new (NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + "%s", message); + if (secondary) { + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", secondary); + } + + gtk_window_set_title (GTK_WINDOW (dialog), ""); /* as per HIG */ + gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), TRUE); + g_signal_connect (G_OBJECT (dialog), + "response", + G_CALLBACK (gtk_widget_destroy), NULL); + gtk_widget_show (dialog); +} + +#ifdef HAVE_POLKIT +#define CACHE_VALIDITY_SEC 2 + +static gboolean +selector_is_available (void) +{ + DBusGProxy *proxy; + static DBusGConnection *system_bus = NULL; + GError *error = NULL; + gboolean result; + + if (!system_bus) { + system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (!system_bus) { + g_warning ("%s", error->message); + g_error_free (error); + + return FALSE; + } + } + + proxy = dbus_g_proxy_new_for_name (system_bus, + "org.mate.CPUFreqSelector", + "/org/mate/cpufreq_selector/selector", + "org.mate.CPUFreqSelector"); + + if (!dbus_g_proxy_call (proxy, "CanSet", &error, + G_TYPE_INVALID, + G_TYPE_BOOLEAN, &result, + G_TYPE_INVALID)) { + g_warning ("Error calling org.mate.CPUFreqSelector.CanSet: %s", error->message); + g_error_free (error); + result = FALSE; + } + + g_object_unref (proxy); + + return result; +} + +gboolean +cpufreq_utils_selector_is_available (void) +{ + static gboolean cache = FALSE; + static time_t last_refreshed = 0; + time_t now; + + time (&now); + if (ABS (now - last_refreshed) > CACHE_VALIDITY_SEC) { + cache = selector_is_available (); + last_refreshed = now; + } + + return cache; +} +#else /* !HAVE_POLKIT */ +gboolean +cpufreq_utils_selector_is_available (void) +{ + struct stat *info; + gchar *path = NULL; + + path = g_find_program_in_path ("cpufreq-selector"); + if (!path) + return FALSE; + + if (geteuid () == 0) { + g_free (path); + return TRUE; + } + + info = (struct stat *) g_malloc (sizeof (struct stat)); + + if ((lstat (path, info)) != -1) { + if ((info->st_mode & S_ISUID) && (info->st_uid == 0)) { + g_free (info); + g_free (path); + + return TRUE; + } + } + + g_free (info); + g_free (path); + + return FALSE; +} +#endif /* HAVE_POLKIT_MATE */ + +gchar * +cpufreq_utils_get_frequency_label (guint freq) +{ + gint divisor; + + if (freq > 999999) /* freq (kHz) */ + divisor = (1000 * 1000); + else + divisor = 1000; + + if (((freq % divisor) == 0) || divisor == 1000) /* integer */ + return g_strdup_printf ("%d", freq / divisor); + else /* float */ + return g_strdup_printf ("%3.2f", ((gfloat)freq / divisor)); +} + +gchar * +cpufreq_utils_get_frequency_unit (guint freq) +{ + if (freq > 999999) /* freq (kHz) */ + return g_strdup ("GHz"); + else + return g_strdup ("MHz"); +} + +gboolean +cpufreq_utils_governor_is_automatic (const gchar *governor) +{ + g_return_val_if_fail (governor != NULL, FALSE); + + if (g_ascii_strcasecmp (governor, "userspace") == 0) + return FALSE; + + return TRUE; +} + +gboolean +cpufreq_file_get_contents (const gchar *filename, + gchar **contents, + gsize *length, + GError **error) +{ + gint fd; + GString *buffer = NULL; + gchar *display_filename; + + g_return_val_if_fail (filename != NULL, FALSE); + g_return_val_if_fail (contents != NULL, FALSE); + + display_filename = g_filename_display_name (filename); + + *contents = NULL; + if (length) + *length = 0; + + fd = open (filename, O_RDONLY); + if (fd < 0) { + gint save_errno = errno; + + g_set_error (error, + G_FILE_ERROR, + g_file_error_from_errno (save_errno), + "Failed to open file '%s': %s", + display_filename, + g_strerror (save_errno)); + g_free (display_filename); + + return FALSE; + } + + while (TRUE) { + ssize_t bytes_read; + gchar buf[1024]; + + bytes_read = read (fd, buf, sizeof (buf)); + if (bytes_read < 0) { /* Error */ + if (errno != EINTR) { + gint save_errno = errno; + + g_set_error (error, + G_FILE_ERROR, + g_file_error_from_errno (save_errno), + "Failed to read from file '%s': %s", + display_filename, + g_strerror (save_errno)); + + if (buffer) + g_string_free (buffer, TRUE); + + g_free (display_filename); + close (fd); + + return FALSE; + } + } else if (bytes_read == 0) { /* EOF */ + break; + } else { + if (!buffer) + buffer = g_string_sized_new (bytes_read); + buffer = g_string_append_len (buffer, buf, bytes_read); + } + } + + g_free (display_filename); + + if (buffer) + *contents = g_string_free (buffer, FALSE); + + if (length) + *length = strlen (*contents); + + close (fd); + + return TRUE; +} diff --git a/cpufreq/src/cpufreq-utils.h b/cpufreq/src/cpufreq-utils.h new file mode 100644 index 00000000..9420c651 --- /dev/null +++ b/cpufreq/src/cpufreq-utils.h @@ -0,0 +1,44 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2006 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#ifndef CPUFREQ_UTILS_H +#define CPUFREQ_UTILS_H + +#include <glib.h> + +G_BEGIN_DECLS + +/* Useful global methods */ +guint cpufreq_utils_get_n_cpus (void); +void cpufreq_utils_display_error (const gchar *message, + const gchar *secondary); +gboolean cpufreq_utils_selector_is_available (void); +gchar *cpufreq_utils_get_frequency_label (guint freq); +gchar *cpufreq_utils_get_frequency_unit (guint freq); +gboolean cpufreq_utils_governor_is_automatic (const gchar *governor); +gboolean cpufreq_file_get_contents (const gchar *filename, + gchar **contents, + gsize *length, + GError **error); + +G_END_DECLS + +#endif /* CPUFREQ_UTILS_H */ |