/* * MATE CPUFreq Applet * Copyright (C) 2004 Carlos Garcia Campos * * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Authors : Carlos GarcĂ­a Campos */ #include #include #include #include #include #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 = "" " " " " " " " " " " " " " " ""; #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; 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")); cpufreq_selector_set_frequency_async (selector, cpu, freq); } static void cpufreq_popup_governors_menu_activate (GtkAction *action, CPUFreqPopup *popup) { CPUFreqSelector *selector; const gchar *name; guint cpu; const gchar *governor; 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"); cpufreq_selector_set_governor_async (selector, cpu, governor); } 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; }