diff --git a/src/bin/e_powersave.c b/src/bin/e_powersave.c index be5783aed..ecf4314ec 100644 --- a/src/bin/e_powersave.c +++ b/src/bin/e_powersave.c @@ -13,8 +13,10 @@ struct _E_Powersave_Deferred_Action /* local subsystem functions */ static int _e_powersave_cb_deferred_timer(void *data); static void _e_powersave_mode_eval(void); +static void _e_powersave_event_update_free(void *data __UNUSED__, void *event); /* local subsystem globals */ +EAPI int E_EVENT_POWERSAVE_UPDATE = 0; static int walking_deferred_actions = 0; static Eina_List *deferred_actions = NULL; static Ecore_Timer *deferred_timer = NULL; @@ -28,6 +30,7 @@ EAPI int e_powersave_init(void) { _e_powersave_mode_eval(); + E_EVENT_POWERSAVE_UPDATE = ecore_event_type_new(); return 1; } @@ -94,11 +97,17 @@ e_powersave_mode_max_set(E_Powersave_Mode mode) EAPI void e_powersave_mode_set(E_Powersave_Mode mode) { + E_Event_Powersave_Update *ev; + if (mode < powersave_mode_min) mode = powersave_mode_min; else if (mode > powersave_mode_max) mode = powersave_mode_max; if (powersave_mode == mode) return; printf("CHANGE PW SAVE MODE TO %i / %i\n", (int)mode, E_POWERSAVE_MODE_EXTREME); powersave_mode = mode; + + ev = E_NEW(E_Event_Powersave_Update, 1); + ev->mode = mode; + ecore_event_add(E_EVENT_POWERSAVE_UPDATE, ev, _e_powersave_event_update_free, NULL); _e_powersave_mode_eval(); } @@ -175,3 +184,9 @@ _e_powersave_mode_eval(void) NULL); } } + +static void +_e_powersave_event_update_free(void *data __UNUSED__, void *event) +{ + free(event); +} diff --git a/src/bin/e_powersave.h b/src/bin/e_powersave.h index 5795f36c0..d6d9e54f1 100644 --- a/src/bin/e_powersave.h +++ b/src/bin/e_powersave.h @@ -13,11 +13,19 @@ typedef enum _E_Powersave_Mode } E_Powersave_Mode; typedef struct _E_Powersave_Deferred_Action E_Powersave_Deferred_Action; +typedef struct _E_Event_Powersave_Update E_Event_Powersave_Update; #else #ifndef E_POWERSAVE_H #define E_POWERSAVE_H +extern EAPI int E_EVENT_POWERSAVE_UPDATE; + +struct _E_Event_Powersave_Update +{ + E_Powersave_Mode mode; +}; + EAPI int e_powersave_init(void); EAPI int e_powersave_shutdown(void); diff --git a/src/modules/cpufreq/e_mod_main.c b/src/modules/cpufreq/e_mod_main.c index b557c4b20..3dffa2eb0 100644 --- a/src/modules/cpufreq/e_mod_main.c +++ b/src/modules/cpufreq/e_mod_main.c @@ -57,6 +57,7 @@ static void _cpufreq_face_update_available(Instance *inst); static void _cpufreq_face_update_current(Instance *inst); static void _cpufreq_face_cb_set_frequency(void *data, Evas_Object *o, const char *emission, const char *source); static void _cpufreq_face_cb_set_governor(void *data, Evas_Object *o, const char *emission, const char *source); +static int _cpufreq_event_cb_powersave(void *data __UNUSED__, int type, void *event); static void _cpufreq_menu_fast(void *data, E_Menu *m, E_Menu_Item *mi); static void _cpufreq_menu_medium(void *data, E_Menu *m, E_Menu_Item *mi); @@ -64,7 +65,9 @@ static void _cpufreq_menu_normal(void *data, E_Menu *m, E_Menu_Item *mi); static void _cpufreq_menu_slow(void *data, E_Menu *m, E_Menu_Item *mi); static void _cpufreq_menu_very_slow(void *data, E_Menu *m, E_Menu_Item *mi); static void _cpufreq_menu_restore_governor(void *data, E_Menu *m, E_Menu_Item *mi); +static void _cpufreq_menu_auto_powersave(void *data, E_Menu *m, E_Menu_Item *mi); static void _cpufreq_menu_governor(void *data, E_Menu *m, E_Menu_Item *mi); +static void _cpufreq_menu_powersave_governor(void *data, E_Menu *m, E_Menu_Item *mi); static void _cpufreq_menu_frequency(void *data, E_Menu *m, E_Menu_Item *mi); static E_Config_DD *conf_edd = NULL; @@ -100,6 +103,9 @@ _gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style) cpufreq_config->status = _cpufreq_status_new(); _cpufreq_cb_check(NULL); _cpufreq_face_update_available(inst); + + cpufreq_config->handler = ecore_event_handler_add(E_EVENT_POWERSAVE_UPDATE, + _cpufreq_event_cb_powersave, NULL); return gcc; } @@ -112,6 +118,8 @@ _gc_shutdown(E_Gadcon_Client *gcc) cpufreq_config->instances = eina_list_remove(cpufreq_config->instances, inst); evas_object_del(inst->o_cpu); free(inst); + + if (cpufreq_config->handler) ecore_event_handler_del(cpufreq_config->handler); } static void @@ -232,6 +240,50 @@ _button_cb_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info) e_menu_item_toggle_set(mi, 1); e_menu_item_callback_set(mi, _cpufreq_menu_governor, l->data); } + + e_menu_item_separator_set(e_menu_item_new(mn), 1); + + mi = e_menu_item_new(mn); + e_menu_item_label_set(mi, _("Restore CPU Power Policy")); + e_menu_item_check_set(mi, 1); + e_menu_item_toggle_set(mi, cpufreq_config->restore_governor); + e_menu_item_callback_set(mi, _cpufreq_menu_restore_governor, NULL); + + mn = e_menu_new(); + cpufreq_config->menu_powersave = mn; + + e_menu_title_set(mn, _("Powersaving policy")); + + for (l = cpufreq_config->status->governors; l; l = l->next) + { + if (!strcmp(l->data, "userspace")) + continue; + + mi = e_menu_item_new(mn); + if (!strcmp(l->data, "ondemand")) + e_menu_item_label_set(mi, _("Automatic")); + else if (!strcmp(l->data, "conservative")) + e_menu_item_label_set(mi, _("Lower Power Automatic")); + else if (!strcmp(l->data, "powersave")) + e_menu_item_label_set(mi, _("Minimum Speed")); + else if (!strcmp(l->data, "performance")) + e_menu_item_label_set(mi, _("Maximum Speed")); + + e_menu_item_radio_set(mi, 1); + e_menu_item_radio_group_set(mi, 1); + if (cpufreq_config->powersave_governor + && !strcmp(cpufreq_config->powersave_governor, l->data)) + e_menu_item_toggle_set(mi, 1); + e_menu_item_callback_set(mi, _cpufreq_menu_powersave_governor, l->data); + } + + e_menu_item_separator_set(e_menu_item_new(mn), 1); + + mi = e_menu_item_new(mn); + e_menu_item_label_set(mi, _("Automatic powersaving")); + e_menu_item_check_set(mi, 1); + e_menu_item_toggle_set(mi, cpufreq_config->auto_powersave); + e_menu_item_callback_set(mi, _cpufreq_menu_auto_powersave, NULL); } if ((cpufreq_config->status->frequencies) && @@ -271,12 +323,6 @@ _button_cb_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info) if (cpufreq_config->menu_governor) { - mi = e_menu_item_new(mn); - e_menu_item_label_set(mi, _("Restore CPU Power Policy")); - e_menu_item_check_set(mi, 1); - e_menu_item_toggle_set(mi, cpufreq_config->restore_governor); - e_menu_item_callback_set(mi, _cpufreq_menu_restore_governor, NULL); - mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Set CPU Power Policy")); e_menu_item_submenu_set(mi, cpufreq_config->menu_governor); @@ -288,6 +334,12 @@ _button_cb_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info) e_menu_item_label_set(mi, _("Set CPU Speed")); e_menu_item_submenu_set(mi, cpufreq_config->menu_frequency); } + if (cpufreq_config->menu_powersave) + { + mi = e_menu_item_new(mn); + e_menu_item_label_set(mi, _("Powersaving behavior")); + e_menu_item_submenu_set(mi, cpufreq_config->menu_powersave); + } e_gadcon_client_util_menu_items_append(inst->gcc, mn, 0); @@ -313,6 +365,8 @@ _menu_cb_post(void *data, E_Menu *m) cpufreq_config->menu_governor = NULL; if (cpufreq_config->menu_frequency) e_object_del(E_OBJECT(cpufreq_config->menu_frequency)); cpufreq_config->menu_frequency = NULL; + if (cpufreq_config->menu_powersave) e_object_del(E_OBJECT(cpufreq_config->menu_powersave)); + cpufreq_config->menu_powersave = NULL; } static void @@ -442,6 +496,7 @@ _cpufreq_status_free(Status *s) eina_list_free(s->governors); } if (s->cur_governor) free(s->cur_governor); + if (s->orig_governor) eina_stringshare_del(s->orig_governor); free(s); } @@ -751,6 +806,55 @@ _cpufreq_face_cb_set_governor(void *data, Evas_Object *obj, const char *emission if (next_governor != NULL) _cpufreq_set_governor(next_governor); } +static int +_cpufreq_event_cb_powersave(void *data __UNUSED__, int type, void *event) +{ + E_Event_Powersave_Update *ev; + Eina_List *l; + Eina_Bool has_powersave, has_conservative; + + if (type != E_EVENT_POWERSAVE_UPDATE) return 1; + if (!cpufreq_config->auto_powersave) return 1; + + ev = event; + if (!cpufreq_config->status->orig_governor) + cpufreq_config->status->orig_governor = eina_stringshare_add(cpufreq_config->status->cur_governor); + + for (l = cpufreq_config->status->governors; l; l = l->next) + { + if (!strcmp(l->data, "conservative")) + has_conservative = EINA_TRUE; + else if (!strcmp(l->data, "powersave")) + has_powersave = EINA_TRUE; + } + + switch(ev->mode) + { + case E_POWERSAVE_MODE_NONE: + case E_POWERSAVE_MODE_LOW: + _cpufreq_set_governor(cpufreq_config->status->orig_governor); + eina_stringshare_del(cpufreq_config->status->orig_governor); + cpufreq_config->status->orig_governor = NULL; + break; + case E_POWERSAVE_MODE_MEDIUM: + case E_POWERSAVE_MODE_HIGH: + if (cpufreq_config->powersave_governor || has_conservative) + { + if (cpufreq_config->powersave_governor) + _cpufreq_set_governor(cpufreq_config->powersave_governor); + else + _cpufreq_set_governor("conservative"); + break; + } + case E_POWERSAVE_MODE_EXTREME: + if (has_powersave) + _cpufreq_set_governor("powersave"); + break; + } + + return 1; +} + static void _cpufreq_menu_fast(void *data, E_Menu *m, E_Menu_Item *mi) { @@ -819,10 +923,17 @@ _cpufreq_menu_restore_governor(void *data, E_Menu *m, E_Menu_Item *mi) e_config_save_queue(); } +static void +_cpufreq_menu_auto_powersave(void *data, E_Menu *m, E_Menu_Item *mi) +{ + cpufreq_config->auto_powersave = e_menu_item_toggle_get(mi); + e_config_save_queue(); +} + static void _cpufreq_menu_governor(void *data, E_Menu *m, E_Menu_Item *mi) { - char *governor; + const char *governor; governor = data; if (governor) @@ -834,6 +945,21 @@ _cpufreq_menu_governor(void *data, E_Menu *m, E_Menu_Item *mi) e_config_save_queue(); } +static void +_cpufreq_menu_powersave_governor(void *data, E_Menu *m, E_Menu_Item *mi) +{ + const char *governor; + + governor = data; + if (governor) + { + if (cpufreq_config->powersave_governor) + eina_stringshare_del(cpufreq_config->powersave_governor); + cpufreq_config->powersave_governor = eina_stringshare_add(governor); + } + e_config_save_queue(); +} + static void _cpufreq_menu_frequency(void * data, E_Menu *m, E_Menu_Item *mi) { @@ -863,16 +989,25 @@ e_modapi_init(E_Module *m) #undef D #define T Config #define D conf_edd + E_CONFIG_VAL(D, T, config_version, INT); E_CONFIG_VAL(D, T, poll_interval, INT); E_CONFIG_VAL(D, T, restore_governor, INT); + E_CONFIG_VAL(D, T, auto_powersave, INT); + E_CONFIG_VAL(D, T, powersave_governor, STR); E_CONFIG_VAL(D, T, governor, STR); cpufreq_config = e_config_domain_load("module.cpufreq", conf_edd); + if (cpufreq_config && cpufreq_config->config_version != CPUFREQ_CONFIG_VERSION) + E_FREE(cpufreq_config); + if (!cpufreq_config) { cpufreq_config = E_NEW(Config, 1); + cpufreq_config->config_version = CPUFREQ_CONFIG_VERSION; cpufreq_config->poll_interval = 32; cpufreq_config->restore_governor = 0; + cpufreq_config->auto_powersave = 1; + cpufreq_config->powersave_governor = NULL; cpufreq_config->governor = NULL; } E_CONFIG_LIMIT(cpufreq_config->poll_interval, 1, 1024); @@ -901,7 +1036,7 @@ e_modapi_init(E_Module *m) } cpufreq_config->module = m; - + e_gadcon_provider_register(&_gadcon_class); return m; } @@ -937,6 +1072,12 @@ e_modapi_shutdown(E_Module *m) e_object_del(E_OBJECT(cpufreq_config->menu_frequency)); cpufreq_config->menu_frequency = NULL; } + if (cpufreq_config->menu_powersave) + { + e_menu_post_deactivate_callback_set(cpufreq_config->menu_powersave, NULL, NULL); + e_object_del(E_OBJECT(cpufreq_config->menu_powersave)); + cpufreq_config->menu_powersave = NULL; + } if (cpufreq_config->governor) eina_stringshare_del(cpufreq_config->governor); if (cpufreq_config->status) _cpufreq_status_free(cpufreq_config->status); diff --git a/src/modules/cpufreq/e_mod_main.h b/src/modules/cpufreq/e_mod_main.h index 56ba66f1e..55b0647a3 100644 --- a/src/modules/cpufreq/e_mod_main.h +++ b/src/modules/cpufreq/e_mod_main.h @@ -4,6 +4,8 @@ typedef struct _Status Status; typedef struct _Config Config; +#define CPUFREQ_CONFIG_VERSION 1 + struct _Status { Eina_List *frequencies; @@ -11,14 +13,18 @@ struct _Status int cur_frequency; int can_set_frequency; char *cur_governor; + const char *orig_governor; unsigned char active; }; struct _Config { /* saved * loaded config values */ + int config_version; int poll_interval; int restore_governor; + int auto_powersave; + const char *powersave_governor; const char *governor; /* just config state */ E_Module *module; @@ -27,9 +33,11 @@ struct _Config E_Menu *menu_poll; E_Menu *menu_governor; E_Menu *menu_frequency; + E_Menu *menu_powersave; Status *status; char *set_exe_path; Ecore_Poller *frequency_check_poller; + Ecore_Event_Handler *handler; }; EAPI extern E_Module_Api e_modapi;