#include "cpuclock.h" #if defined(__OpenBSD__) || defined(__NetBSD__) #include #include #endif #if defined(__FreeBSD__) || defined(__DragonFly__) #include #include #endif EINTERN void _cpuclock_poll_interval_update(Instance *inst); typedef struct _Thread_Config Thread_Config; struct _Thread_Config { int interval; Instance *inst; E_Powersave_Sleeper *sleeper; }; typedef struct _Pstate_Config Pstate_Config; struct _Pstate_Config { Instance *inst; int min; int max; int turbo; }; static Cpu_Status * _cpuclock_status_new(void) { Cpu_Status *s; s = E_NEW(Cpu_Status, 1); if (!s) return NULL; s->active = -1; return s; } static void _cpuclock_status_free(Cpu_Status *s) { Eina_List *l; if (eina_list_count(s->frequencies)) eina_list_free(s->frequencies); if (s->governors) { for (l = s->governors; l; l = l->next) E_FREE(l->data); eina_list_free(s->governors); } E_FREE(s->cur_governor); if (s->orig_governor) eina_stringshare_del(s->orig_governor); E_FREE(s); } #if defined(__linux__) static int _cpuclock_cb_sort(const void *item1, const void *item2) { int a, b; a = (long)item1; b = (long)item2; if (a < b) return -1; else if (a > b) return 1; return 0; } #endif void _cpuclock_set_governor(const char *governor) { e_system_send("cpufreq-governor", "%s", governor); } void _cpuclock_set_frequency(int frequency) { #if defined(__FreeBSD__) || defined(__DragonFly__) frequency /= 1000; #endif e_system_send("cpufreq-freq", "%i", frequency); } void _cpuclock_set_pstate(int min, int max, int turbo) { e_system_send("cpufreq-pstate", "%i %i %i", min, max, turbo); } static void _cpuclock_face_cb_set_frequency(void *data, Evas_Object *obj EINA_UNUSED, const char *emission, const char *src EINA_UNUSED) { Eina_List *l; int next_frequency = 0; Instance *inst = data; for (l = inst->cfg->cpuclock.status->frequencies; l; l = l->next) { if (inst->cfg->cpuclock.status->cur_frequency == (long)l->data) { if (!strcmp(emission, "e,action,frequency,increase")) { if (l->next) next_frequency = (long)l->next->data; break; } else if (!strcmp(emission, "e,action,frequency,decrease")) { if (l->prev) next_frequency = (long)l->prev->data; break; } else break; } } if (inst->cfg->cpuclock.status->can_set_frequency && next_frequency) _cpuclock_set_frequency(next_frequency); } static void _cpuclock_face_cb_set_governor(void *data, Evas_Object *obj EINA_UNUSED, const char *emission EINA_UNUSED, const char *src EINA_UNUSED) { Eina_List *l; char *next_governor = NULL; Instance *inst = data; for (l = inst->cfg->cpuclock.status->governors; l; l = l->next) { if (!strcmp(l->data, inst->cfg->cpuclock.status->cur_governor)) { if (l->next) next_governor = l->next->data; else next_governor = inst->cfg->cpuclock.status->governors->data; break; } } if (next_governor) _cpuclock_set_governor(next_governor); } static Eina_Bool _cpuclock_event_cb_powersave(void *data, int type, void *event) { Instance *inst = data; E_Event_Powersave_Update *ev; Eina_List *l; Eina_Bool has_powersave = EINA_FALSE; Eina_Bool has_conservative = EINA_FALSE; if (type != E_EVENT_POWERSAVE_UPDATE) return ECORE_CALLBACK_PASS_ON; if (!inst->cfg->cpuclock.auto_powersave) return ECORE_CALLBACK_PASS_ON; if (inst->cfg->id == -1) return ECORE_CALLBACK_RENEW; ev = event; if (!inst->cfg->cpuclock.status->orig_governor) inst->cfg->cpuclock.status->orig_governor = eina_stringshare_add(inst->cfg->cpuclock.status->cur_governor); for (l = inst->cfg->cpuclock.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; else if (!strcmp(l->data, "interactive")) has_powersave = EINA_TRUE; } switch (ev->mode) { case E_POWERSAVE_MODE_NONE: case E_POWERSAVE_MODE_LOW: _cpuclock_set_governor(inst->cfg->cpuclock.status->orig_governor); eina_stringshare_del(inst->cfg->cpuclock.status->orig_governor); inst->cfg->cpuclock.status->orig_governor = NULL; break; case E_POWERSAVE_MODE_MEDIUM: case E_POWERSAVE_MODE_HIGH: if ((inst->cfg->cpuclock.powersave_governor) || (has_conservative)) { if (inst->cfg->cpuclock.powersave_governor) _cpuclock_set_governor(inst->cfg->cpuclock.powersave_governor); else _cpuclock_set_governor("conservative"); break; } EINA_FALLTHROUGH; /* no break */ case E_POWERSAVE_MODE_EXTREME: default: if (has_powersave) _cpuclock_set_governor("powersave"); break; } return ECORE_CALLBACK_PASS_ON; } static Evas_Object * _cpuclock_configure_cb(Evas_Object *g) { Instance *inst = evas_object_data_get(g, "Instance"); if (!sysinfo_config) return NULL; if (inst->cfg->cpuclock.popup) return NULL; return cpuclock_configure(inst); } static void _cpuclock_popup_dismissed(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) { Instance *inst = data; E_FREE_FUNC(obj, evas_object_del); inst->cfg->cpuclock.popup = NULL; inst->cfg->cpuclock.popup_pbar = NULL; } static void _cpuclock_popup_deleted(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { Instance *inst = data; inst->cfg->cpuclock.popup = NULL; } static Evas_Object * _cpuclock_popup_create(Instance *inst) { Evas_Object *popup, *table, *label, *pbar; double f = inst->cfg->cpuclock.status->cur_frequency; char buf[4096], text[4096], *u; if (f < 1000000) { f += 500; f /= 1000; u = _("MHz"); } else { f += 50000; f /= 1000000; u = _("GHz"); } popup = elm_ctxpopup_add(e_comp->elm); elm_object_style_set(popup, "noblock"); evas_object_smart_callback_add(popup, "dismissed", _cpuclock_popup_dismissed, inst); evas_object_event_callback_add(popup, EVAS_CALLBACK_DEL, _cpuclock_popup_deleted, inst); table = elm_table_add(popup); E_EXPAND(table); E_FILL(table); elm_object_content_set(popup, table); evas_object_show(table); snprintf(text, sizeof(text), "%s", _("Frequency")); label = elm_label_add(table); E_EXPAND(label); E_ALIGN(label, 0.5, 0.5); elm_object_text_set(label, text); elm_table_pack(table, label, 0, 0, 2, 1); evas_object_show(label); snprintf(buf, sizeof(buf), "%1.1f %s (%d %%%%)", f, u, inst->cfg->cpuclock.percent); pbar = elm_progressbar_add(table); E_EXPAND(pbar); E_FILL(pbar); elm_progressbar_span_size_set(pbar, 200 * e_scale); elm_progressbar_unit_format_set(pbar, buf); elm_progressbar_value_set(pbar, (float)inst->cfg->cpuclock.percent / 100); elm_table_pack(table, pbar, 0, 1, 2, 1); evas_object_show(pbar); inst->cfg->cpuclock.popup_pbar = pbar; e_gadget_util_ctxpopup_place(inst->o_main, popup, inst->cfg->cpuclock.o_gadget); evas_object_show(popup); return popup; } static void _cpuclock_mouse_up_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_data) { Evas_Event_Mouse_Up *ev = event_data; Instance *inst = data; if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; if (ev->button == 1) { if (inst->cfg->cpuclock.popup) elm_ctxpopup_dismiss(inst->cfg->cpuclock.popup); else inst->cfg->cpuclock.popup = _cpuclock_popup_create(inst); } } void _cpuclock_config_updated(Instance *inst) { Edje_Message_Int_Set *frequency_msg; Edje_Message_String_Set *governor_msg; Eina_List *l; int i; unsigned int count; if (inst->cfg->id == -1) { inst->cfg->cpuclock.status->cur_frequency = 3000000; inst->cfg->cpuclock.status->can_set_frequency = 1000000; inst->cfg->cpuclock.status->cur_min_frequency = 500000; inst->cfg->cpuclock.status->cur_max_frequency = 3500000; return; } if (inst->cfg->cpuclock.status->frequencies) { count = eina_list_count(inst->cfg->cpuclock.status->frequencies); frequency_msg = malloc(sizeof(Edje_Message_Int_Set) + (count - 1) * sizeof(int)); EINA_SAFETY_ON_NULL_RETURN(frequency_msg); frequency_msg->count = count; for (l = inst->cfg->cpuclock.status->frequencies, i = 0; l; l = l->next, i++) frequency_msg->val[i] = (long)l->data; edje_object_message_send(elm_layout_edje_get(inst->cfg->cpuclock.o_gadget), EDJE_MESSAGE_INT_SET, 1, frequency_msg); E_FREE(frequency_msg); } if (inst->cfg->cpuclock.status->governors) { count = eina_list_count(inst->cfg->cpuclock.status->governors); governor_msg = malloc(sizeof(Edje_Message_String_Set) + (count - 1) * sizeof(char *)); governor_msg->count = count; for (l = inst->cfg->cpuclock.status->governors, i = 0; l; l = l->next, i++) governor_msg->str[i] = (char *)l->data; edje_object_message_send(elm_layout_edje_get(inst->cfg->cpuclock.o_gadget), EDJE_MESSAGE_STRING_SET, 2, governor_msg); E_FREE(governor_msg); } _cpuclock_poll_interval_update(inst); } static void _cpuclock_face_update_current(Instance *inst) { Edje_Message_Int_Set *frequency_msg; Edje_Message_String governor_msg; frequency_msg = malloc(sizeof(Edje_Message_Int_Set) + (sizeof(int) * 4)); EINA_SAFETY_ON_NULL_RETURN(frequency_msg); frequency_msg->count = 5; frequency_msg->val[0] = inst->cfg->cpuclock.status->cur_frequency; frequency_msg->val[1] = inst->cfg->cpuclock.status->can_set_frequency; frequency_msg->val[2] = inst->cfg->cpuclock.status->cur_min_frequency; frequency_msg->val[3] = inst->cfg->cpuclock.status->cur_max_frequency; frequency_msg->val[4] = 0; // pad edje_object_message_send(elm_layout_edje_get(inst->cfg->cpuclock.o_gadget), EDJE_MESSAGE_INT_SET, 3, frequency_msg); E_FREE(frequency_msg); if (inst->cfg->cpuclock.tot_min_frequency == 0) inst->cfg->cpuclock.tot_min_frequency = inst->cfg->cpuclock.status->cur_frequency; if (inst->cfg->cpuclock.status->cur_frequency > inst->cfg->cpuclock.tot_max_frequency) { inst->cfg->cpuclock.tot_max_frequency = inst->cfg->cpuclock.status->cur_frequency; inst->cfg->cpuclock.percent = 100; } if (inst->cfg->cpuclock.status->cur_frequency < inst->cfg->cpuclock.tot_min_frequency) { inst->cfg->cpuclock.tot_min_frequency = inst->cfg->cpuclock.status->cur_frequency; inst->cfg->cpuclock.percent = 0; } if ((inst->cfg->cpuclock.tot_min_frequency > 0) && (inst->cfg->cpuclock.tot_max_frequency >= inst->cfg->cpuclock.tot_min_frequency)) { inst->cfg->cpuclock.percent = ((double)(inst->cfg->cpuclock.status->cur_frequency - inst->cfg->cpuclock.tot_min_frequency) / (double)(inst->cfg->cpuclock.tot_max_frequency - inst->cfg->cpuclock.tot_min_frequency)) * 100; } else inst->cfg->cpuclock.percent = 0; #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) inst->cfg->cpuclock.percent = inst->cfg->cpuclock.status->cur_percent; #endif /* BSD crashes here without the if-condition * since it has no governors (yet) */ if (inst->cfg->cpuclock.status->cur_governor) { governor_msg.str = inst->cfg->cpuclock.status->cur_governor; edje_object_message_send(elm_layout_edje_get(inst->cfg->cpuclock.o_gadget), EDJE_MESSAGE_STRING, 4, &governor_msg); } if (inst->cfg->cpuclock.popup) { double f = inst->cfg->cpuclock.status->cur_frequency; char buf[4096], *u; if (f < 1000000) { f += 500; f /= 1000; u = _("MHz"); } else { f += 50000; f /= 1000000; u = _("GHz"); } snprintf(buf, sizeof(buf), "%1.1f %s (%d %%%%)", f, u, inst->cfg->cpuclock.percent); elm_progressbar_unit_format_set(inst->cfg->cpuclock.popup_pbar, buf); elm_progressbar_value_set(inst->cfg->cpuclock.popup_pbar, (float)inst->cfg->cpuclock.percent / 100); } } static void _cpuclock_status_check_available(Cpu_Status *s) { #if !defined(__OpenBSD__) char buf[4096]; Eina_List *l; #endif // FIXME: this assumes all cores accept the same freqs/ might be wrong #if defined(__OpenBSD__) int p; if (s->frequencies) { eina_list_free(s->frequencies); s->frequencies = NULL; } /* storing percents */ p = 100; s->frequencies = eina_list_append(s->frequencies, (void *)(long int)p); p = 75; s->frequencies = eina_list_append(s->frequencies, (void *)(long int)p); p = 50; s->frequencies = eina_list_append(s->frequencies, (void *)(long int)p); p = 25; s->frequencies = eina_list_append(s->frequencies, (void *)(long int)p); #elif defined(__FreeBSD__) || defined(__DragonFly__) int freq; size_t len = sizeof(buf); char *pos, *q; /* read freq_levels sysctl and store it in freq */ if (sysctlbyname("dev.cpu.0.freq_levels", buf, &len, NULL, 0) == 0) { /* sysctl returns 0 on success */ if (s->frequencies) { eina_list_free(s->frequencies); s->frequencies = NULL; } /* parse freqs and store the frequencies in s->frequencies */ pos = buf; while (pos) { q = strchr(pos, '/'); if (!q) break; *q = '\0'; freq = atoi(pos); freq *= 1000; s->frequencies = eina_list_append(s->frequencies, (void *)(long)freq); pos = q + 1; pos = strchr(pos, ' '); } } /* sort is not necessary because freq_levels is already sorted */ /* freebsd doesn't have governors */ if (s->governors) { for (l = s->governors; l; l = l->next) E_FREE(l->data); eina_list_free(s->governors); s->governors = NULL; } #else FILE *f; f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies", "r"); if (f) { char *freq; if (s->frequencies) { eina_list_free(s->frequencies); s->frequencies = NULL; } if (fgets(buf, sizeof(buf), f) == NULL) { fclose(f); return; } fclose(f); freq = strtok(buf, " "); do { if (atoi(freq) != 0) { s->frequencies = eina_list_append(s->frequencies, (void *)(long)atoi(freq)); } freq = strtok(NULL, " "); } while (freq); s->frequencies = eina_list_sort(s->frequencies, eina_list_count(s->frequencies), _cpuclock_cb_sort); } else do { #define CPUFREQ_SYSFSDIR "/sys/devices/system/cpu/cpu0/cpufreq" f = fopen(CPUFREQ_SYSFSDIR "/scaling_cur_freq", "r"); if (!f) break; fclose(f); f = fopen(CPUFREQ_SYSFSDIR "/scaling_driver", "r"); if (!f) break; if (fgets(buf, sizeof(buf), f) == NULL) { fclose(f); break; } fclose(f); if (strcmp(buf, "intel_pstate\n")) break; if (s->frequencies) { eina_list_free(s->frequencies); s->frequencies = NULL; } #define CPUFREQ_ADDF(filename) \ f = fopen(CPUFREQ_SYSFSDIR filename, "r"); \ if (f) \ { \ if (fgets(buf, sizeof(buf), f) != NULL) \ s->frequencies = eina_list_append(s->frequencies, \ (void *)(long)(atoi(buf))); \ fclose(f); \ } CPUFREQ_ADDF("/cpuinfo_min_freq"); CPUFREQ_ADDF("/cpuinfo_max_freq"); } while (0); f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors", "r"); if (f) { char *gov; int len; if (s->governors) { for (l = s->governors; l; l = l->next) E_FREE(l->data); eina_list_free(s->governors); s->governors = NULL; } if (fgets(buf, sizeof(buf), f) == NULL) { fclose(f); return; } fclose(f); len = strlen(buf); if (len > 0) { gov = buf + len - 1; while ((gov > buf) && (isspace(*gov))) { *gov = 0; gov--; } } gov = strtok(buf, " "); do { while ((*gov) && (isspace(*gov))) gov++; if (strlen(gov) != 0) s->governors = eina_list_append(s->governors, strdup(gov)); gov = strtok(NULL, " "); } while (gov); s->governors = eina_list_sort(s->governors, eina_list_count(s->governors), (int (*)(const void *, const void *))strcmp); } #endif } static int _cpuclock_status_check_current(Cpu_Status *s) { int ret = 0; int frequency = 0; #if defined(__OpenBSD__) size_t len = sizeof(frequency); int percent, mib[] = {CTL_HW, HW_CPUSPEED}; s->active = 0; _cpuclock_status_check_available(s); if (sysctl(mib, 2, &frequency, &len, NULL, 0) == 0) { frequency *= 1000; if (frequency != s->cur_frequency) ret = 1; s->cur_frequency = frequency; s->active = 1; } mib[1] = HW_SETPERF; if (sysctl(mib, 2, &percent, &len, NULL, 0) == 0) { s->cur_percent = percent; } s->can_set_frequency = 1; s->cur_governor = NULL; #elif defined(__FreeBSD__) || defined(__DragonFly__) float ratio; size_t len = sizeof(frequency); s->active = 0; _cpuclock_status_check_available(s); s->can_set_frequency = eina_list_count(s->frequencies); /* frequency is stored in dev.cpu.0.freq */ if (sysctlbyname("dev.cpu.0.freq", &frequency, &len, NULL, 0) == 0) { frequency *= 1000; if (frequency != s->cur_frequency) ret = 1; if (!frequency) frequency = 1; s->cur_frequency = frequency; s->active = 1; if (s->can_set_frequency) { s->cur_max_frequency = (int) eina_list_nth(s->frequencies, 0); if (!s->cur_max_frequency) s->cur_max_frequency = 1; s->cur_min_frequency = (int) eina_list_nth(s->frequencies, eina_list_count(s->frequencies) - 1); ratio = (s->cur_max_frequency) / 100.0; s->cur_percent = s->cur_frequency / ratio; } } s->cur_governor = NULL; #else char buf[4096]; FILE *f; int frequency_min = 0x7fffffff; int frequency_max = 0; int freqtot = 0; int i; s->active = 0; _cpuclock_status_check_available(s); // average out frequencies of all cores for (i = 0; i < 64; i++) { snprintf(buf, sizeof(buf), "/sys/devices/system/cpu/cpu%i/cpufreq/scaling_cur_freq", i); f = fopen(buf, "r"); if (f) { if (fgets(buf, sizeof(buf), f) == NULL) { fclose(f); continue; } fclose(f); frequency = atoi(buf); if (frequency > frequency_max) frequency_max = frequency; if (frequency < frequency_min) frequency_min = frequency; freqtot += frequency; s->active = 1; } else break; } if (i < 1) i = 1; frequency = freqtot / i; if (frequency != s->cur_frequency) ret = 1; if (frequency_min != s->cur_min_frequency) ret = 1; if (frequency_max != s->cur_max_frequency) ret = 1; s->cur_frequency = frequency; s->cur_min_frequency = frequency_min; s->cur_max_frequency = frequency_max; // printf("%i | %i %i\n", frequency, frequency_min, frequency_max); // FIXME: this assumes all cores are on the same governor f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed", "r"); if (f) { s->can_set_frequency = 1; fclose(f); } else { s->can_set_frequency = 0; } f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", "r"); if (f) { char *p; if (fgets(buf, sizeof(buf), f) == NULL) { fclose(f); return ret; } fclose(f); for (p = buf; (*p != 0) && (isalnum(*p)); p++) ; *p = 0; if ((!s->cur_governor) || (strcmp(buf, s->cur_governor))) { ret = 1; E_FREE(s->cur_governor); s->cur_governor = strdup(buf); for (i = strlen(s->cur_governor) - 1; i >= 0; i--) { if (isspace(s->cur_governor[i])) s->cur_governor[i] = 0; else break; } } } f = fopen("/sys/devices/system/cpu/intel_pstate/min_perf_pct", "r"); if (f) { if (fgets(buf, sizeof(buf), f) != NULL) { s->pstate_min = atoi(buf); s->pstate = 1; } fclose(f); } f = fopen("/sys/devices/system/cpu/intel_pstate/max_perf_pct", "r"); if (f) { if (fgets(buf, sizeof(buf), f) != NULL) { s->pstate_max = atoi(buf); s->pstate = 1; } fclose(f); } f = fopen("/sys/devices/system/cpu/intel_pstate/no_turbo", "r"); if (f) { if (fgets(buf, sizeof(buf), f) != NULL) { s->pstate_turbo = atoi(buf); if (s->pstate_turbo) s->pstate_turbo = 0; else s->pstate_turbo = 1; s->pstate = 1; } fclose(f); } #endif return ret; } static void _cpuclock_resize_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_data EINA_UNUSED) { Evas_Coord w, h; Instance *inst = data; edje_object_parts_extends_calc(elm_layout_edje_get(inst->cfg->cpuclock.o_gadget), 0, 0, &w, &h); if (w < 1) w = 1; if (h < 1) h = 1; if (inst->cfg->esm == E_SYSINFO_MODULE_CPUCLOCK) evas_object_size_hint_aspect_set(inst->o_main, EVAS_ASPECT_CONTROL_BOTH, w, h); else evas_object_size_hint_aspect_set(inst->cfg->cpuclock.o_gadget, EVAS_ASPECT_CONTROL_BOTH, w, h); } static void _cpuclock_cb_frequency_check_main(void *data, Ecore_Thread *th) { Thread_Config *thc = data; for (;; ) { Cpu_Status *status; if (ecore_thread_check(th)) break; status = _cpuclock_status_new(); if (_cpuclock_status_check_current(status)) ecore_thread_feedback(th, status); else _cpuclock_status_free(status); if (ecore_thread_check(th)) break; e_powersave_sleeper_sleep(thc->sleeper, thc->interval); if (ecore_thread_check(th)) break; } } static void _cpuclock_cb_frequency_check_notify(void *data, Ecore_Thread *th EINA_UNUSED, void *msg) { Cpu_Status *status = msg; Eina_Bool freq_changed = EINA_FALSE; Eina_Bool init_set = EINA_FALSE; Thread_Config *thc = data; if (!thc->inst) return; if (!thc->inst->cfg) return; if (thc->inst->cfg->esm != E_SYSINFO_MODULE_CPUCLOCK && thc->inst->cfg->esm != E_SYSINFO_MODULE_SYSINFO) return; if ((thc->inst->cfg->cpuclock.status) && (status) && ( #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) (status->cur_percent != thc->inst->cfg->cpuclock.status->cur_percent) || #endif (status->cur_frequency != thc->inst->cfg->cpuclock.status->cur_frequency) || (status->cur_min_frequency != thc->inst->cfg->cpuclock.status->cur_min_frequency) || (status->cur_max_frequency != thc->inst->cfg->cpuclock.status->cur_max_frequency) || (status->can_set_frequency != thc->inst->cfg->cpuclock.status->can_set_frequency))) freq_changed = EINA_TRUE; E_FREE_FUNC(thc->inst->cfg->cpuclock.status, _cpuclock_status_free); thc->inst->cfg->cpuclock.status = status; if (freq_changed) { _cpuclock_face_update_current(thc->inst); } if (thc->inst->cfg->cpuclock.status->active == 0) elm_layout_signal_emit(thc->inst->cfg->cpuclock.o_gadget, "e,state,disabled", "e"); else if (thc->inst->cfg->cpuclock.status->active == 1) elm_layout_signal_emit(thc->inst->cfg->cpuclock.o_gadget, "e,state,enabled", "e"); if (!init_set) { _cpuclock_set_pstate(thc->inst->cfg->cpuclock.pstate_min - 1, thc->inst->cfg->cpuclock.pstate_max - 1, thc->inst->cfg->cpuclock.status->pstate_turbo); init_set = EINA_TRUE; } } static void _cpuclock_cb_frequency_check_end(void *data, Ecore_Thread *th EINA_UNUSED) { Thread_Config *thc = data; e_powersave_sleeper_free(thc->sleeper); E_FREE(thc); } EINTERN void _cpuclock_poll_interval_update(Instance *inst) { Thread_Config *thc; if (inst->cfg->cpuclock.frequency_check_thread) { ecore_thread_cancel(inst->cfg->cpuclock.frequency_check_thread); inst->cfg->cpuclock.frequency_check_thread = NULL; } thc = E_NEW(Thread_Config, 1); if (thc) { thc->inst = inst; thc->sleeper = e_powersave_sleeper_new(); thc->interval = inst->cfg->cpuclock.poll_interval; inst->cfg->cpuclock.frequency_check_thread = ecore_thread_feedback_run(_cpuclock_cb_frequency_check_main, _cpuclock_cb_frequency_check_notify, _cpuclock_cb_frequency_check_end, _cpuclock_cb_frequency_check_end, thc, EINA_TRUE); } e_config_save_queue(); } static Eina_Bool _screensaver_on(void *data) { Instance *inst = data; if (inst->cfg->cpuclock.frequency_check_thread) { ecore_thread_cancel(inst->cfg->cpuclock.frequency_check_thread); inst->cfg->cpuclock.frequency_check_thread = NULL; } return ECORE_CALLBACK_RENEW; } static Eina_Bool _screensaver_off(void *data) { Instance *inst = data; _cpuclock_config_updated(inst); return ECORE_CALLBACK_RENEW; } static void _cpuclock_removed_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_data) { Instance *inst = data; Ecore_Event_Handler *handler; if (inst->o_main != event_data) return; if (inst->cfg->cpuclock.popup_pbar) E_FREE_FUNC(inst->cfg->cpuclock.popup_pbar, evas_object_del); if (inst->cfg->cpuclock.popup) E_FREE_FUNC(inst->cfg->cpuclock.popup, evas_object_del); if (inst->cfg->cpuclock.configure) E_FREE_FUNC(inst->cfg->cpuclock.configure, evas_object_del); EINA_LIST_FREE(inst->cfg->cpuclock.handlers, handler) ecore_event_handler_del(handler); evas_object_event_callback_del_full(inst->o_main, EVAS_CALLBACK_DEL, sysinfo_cpuclock_remove, data); evas_object_smart_callback_del_full(e_gadget_site_get(inst->o_main), "gadget_removed", _cpuclock_removed_cb, inst); if (inst->cfg->cpuclock.frequency_check_thread) { ecore_thread_cancel(inst->cfg->cpuclock.frequency_check_thread); inst->cfg->cpuclock.frequency_check_thread = NULL; return; } if (inst->cfg->cpuclock.governor) eina_stringshare_del(inst->cfg->cpuclock.governor); E_FREE_FUNC(inst->cfg->cpuclock.status, _cpuclock_status_free); sysinfo_config->items = eina_list_remove(sysinfo_config->items, inst->cfg); if (inst->cfg->id >= 0) sysinfo_instances = eina_list_remove(sysinfo_instances, inst); E_FREE(inst->cfg); E_FREE(inst); } void sysinfo_cpuclock_remove(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_data EINA_UNUSED) { Instance *inst = data; Ecore_Event_Handler *handler; if (inst->cfg->cpuclock.popup_pbar) E_FREE_FUNC(inst->cfg->cpuclock.popup_pbar, evas_object_del); if (inst->cfg->cpuclock.popup) E_FREE_FUNC(inst->cfg->cpuclock.popup, evas_object_del); if (inst->cfg->cpuclock.configure) E_FREE_FUNC(inst->cfg->cpuclock.configure, evas_object_del); EINA_LIST_FREE(inst->cfg->cpuclock.handlers, handler) ecore_event_handler_del(handler); if (inst->cfg->cpuclock.frequency_check_thread) { ecore_thread_cancel(inst->cfg->cpuclock.frequency_check_thread); inst->cfg->cpuclock.frequency_check_thread = NULL; } if (inst->cfg->cpuclock.governor) eina_stringshare_del(inst->cfg->cpuclock.governor); E_FREE_FUNC(inst->cfg->cpuclock.status, _cpuclock_status_free); } static void _cpuclock_created_cb(void *data, Evas_Object *obj, void *event_data EINA_UNUSED) { Instance *inst = data; E_Gadget_Site_Orient orient = e_gadget_site_orient_get(e_gadget_site_get(inst->o_main)); Eina_List *l = NULL; e_gadget_configure_cb_set(inst->o_main, _cpuclock_configure_cb); if (inst->cfg->cpuclock.pstate_min == 0) inst->cfg->cpuclock.pstate_min = 1; if (inst->cfg->cpuclock.pstate_max == 0) inst->cfg->cpuclock.pstate_max = 101; inst->cfg->cpuclock.percent = 0; inst->cfg->cpuclock.tot_min_frequency = 0; inst->cfg->cpuclock.tot_max_frequency = 0; inst->cfg->cpuclock.o_gadget = elm_layout_add(inst->o_main); if (orient == E_GADGET_SITE_ORIENT_VERTICAL) e_theme_edje_object_set(inst->cfg->cpuclock.o_gadget, "base/theme/gadget/cpuclock", "e/gadget/cpuclock/main_vert"); else e_theme_edje_object_set(inst->cfg->cpuclock.o_gadget, "base/theme/gadget/cpuclock", "e/gadget/cpuclock/main"); E_EXPAND(inst->cfg->cpuclock.o_gadget); E_FILL(inst->cfg->cpuclock.o_gadget); edje_object_signal_callback_add(elm_layout_edje_get(inst->cfg->cpuclock.o_gadget), "e,action,governor,next", "*", _cpuclock_face_cb_set_governor, inst); edje_object_signal_callback_add(elm_layout_edje_get(inst->cfg->cpuclock.o_gadget), "e,action,frequency,increase", "*", _cpuclock_face_cb_set_frequency, inst); edje_object_signal_callback_add(elm_layout_edje_get(inst->cfg->cpuclock.o_gadget), "e,action,frequency,decrease", "*", _cpuclock_face_cb_set_frequency, inst); evas_object_event_callback_add(inst->cfg->cpuclock.o_gadget, EVAS_CALLBACK_RESIZE, _cpuclock_resize_cb, inst); elm_box_pack_end(inst->o_main, inst->cfg->cpuclock.o_gadget); evas_object_event_callback_add(inst->cfg->cpuclock.o_gadget, EVAS_CALLBACK_MOUSE_UP, _cpuclock_mouse_up_cb, inst); evas_object_show(inst->cfg->cpuclock.o_gadget); evas_object_smart_callback_del_full(obj, "gadget_created", _cpuclock_created_cb, data); inst->cfg->cpuclock.status = _cpuclock_status_new(); _cpuclock_status_check_available(inst->cfg->cpuclock.status); E_LIST_HANDLER_APPEND(inst->cfg->cpuclock.handlers, E_EVENT_SCREENSAVER_ON, _screensaver_on, inst); E_LIST_HANDLER_APPEND(inst->cfg->cpuclock.handlers, E_EVENT_SCREENSAVER_OFF, _screensaver_off, inst); E_LIST_HANDLER_APPEND(inst->cfg->cpuclock.handlers, E_EVENT_POWERSAVE_UPDATE, _cpuclock_event_cb_powersave, inst); _cpuclock_config_updated(inst); if ((inst->cfg->cpuclock.restore_governor) && (inst->cfg->cpuclock.governor)) { for (l = inst->cfg->cpuclock.status->governors; l; l = l->next) { if (!strcmp(l->data, inst->cfg->cpuclock.governor)) { _cpuclock_set_governor(inst->cfg->cpuclock.governor); break; } } } } Evas_Object * sysinfo_cpuclock_create(Evas_Object *parent, Instance *inst) { Eina_List *l = NULL; if (inst->cfg->cpuclock.pstate_min == 0) inst->cfg->cpuclock.pstate_min = 1; if (inst->cfg->cpuclock.pstate_max == 0) inst->cfg->cpuclock.pstate_max = 101; inst->cfg->cpuclock.percent = 0; inst->cfg->cpuclock.tot_min_frequency = 0; inst->cfg->cpuclock.tot_max_frequency = 0; inst->cfg->cpuclock.o_gadget = elm_layout_add(parent); e_theme_edje_object_set(inst->cfg->cpuclock.o_gadget, "base/theme/gadget/cpuclock", "e/gadget/cpuclock/main"); E_EXPAND(inst->cfg->cpuclock.o_gadget); E_FILL(inst->cfg->cpuclock.o_gadget); evas_object_event_callback_add(inst->cfg->cpuclock.o_gadget, EVAS_CALLBACK_MOUSE_UP, _cpuclock_mouse_up_cb, inst); edje_object_signal_callback_add(elm_layout_edje_get(inst->cfg->cpuclock.o_gadget), "e,action,governor,next", "*", _cpuclock_face_cb_set_governor, inst); edje_object_signal_callback_add(elm_layout_edje_get(inst->cfg->cpuclock.o_gadget), "e,action,frequency,increase", "*", _cpuclock_face_cb_set_frequency, inst); edje_object_signal_callback_add(elm_layout_edje_get(inst->cfg->cpuclock.o_gadget), "e,action,frequency,decrease", "*", _cpuclock_face_cb_set_frequency, inst); evas_object_event_callback_add(inst->cfg->cpuclock.o_gadget, EVAS_CALLBACK_RESIZE, _cpuclock_resize_cb, inst); evas_object_show(inst->cfg->cpuclock.o_gadget); inst->cfg->cpuclock.status = _cpuclock_status_new(); _cpuclock_status_check_available(inst->cfg->cpuclock.status); E_LIST_HANDLER_APPEND(inst->cfg->cpuclock.handlers, E_EVENT_SCREENSAVER_ON, _screensaver_on, inst); E_LIST_HANDLER_APPEND(inst->cfg->cpuclock.handlers, E_EVENT_SCREENSAVER_OFF, _screensaver_off, inst); E_LIST_HANDLER_APPEND(inst->cfg->cpuclock.handlers, E_EVENT_POWERSAVE_UPDATE, _cpuclock_event_cb_powersave, inst); _cpuclock_config_updated(inst); if ((inst->cfg->cpuclock.restore_governor) && (inst->cfg->cpuclock.governor)) { for (l = inst->cfg->cpuclock.status->governors; l; l = l->next) { if (!strcmp(l->data, inst->cfg->cpuclock.governor)) { _cpuclock_set_governor(inst->cfg->cpuclock.governor); break; } } } return inst->cfg->cpuclock.o_gadget; } static Config_Item * _conf_item_get(int *id) { Config_Item *ci; Eina_List *l; if (*id > 0) { EINA_LIST_FOREACH(sysinfo_config->items, l, ci) if (*id == ci->id && ci->esm == E_SYSINFO_MODULE_CPUCLOCK) return ci; } ci = E_NEW(Config_Item, 1); if (*id != -1) ci->id = eina_list_count(sysinfo_config->items) + 1; else ci->id = -1; ci->esm = E_SYSINFO_MODULE_CPUCLOCK; ci->cpuclock.poll_interval = 32; ci->cpuclock.restore_governor = 0; ci->cpuclock.auto_powersave = 1; ci->cpuclock.powersave_governor = NULL; ci->cpuclock.governor = NULL; ci->cpuclock.pstate_min = 1; ci->cpuclock.pstate_max = 101; ci->cpuclock.configure = NULL; sysinfo_config->items = eina_list_append(sysinfo_config->items, ci); return ci; } Evas_Object * cpuclock_create(Evas_Object *parent, int *id, E_Gadget_Site_Orient orient EINA_UNUSED) { Instance *inst; inst = E_NEW(Instance, 1); inst->cfg = _conf_item_get(id); *id = inst->cfg->id; inst->o_main = elm_box_add(parent); evas_object_data_set(inst->o_main, "Instance", inst); evas_object_smart_callback_add(parent, "gadget_created", _cpuclock_created_cb, inst); evas_object_smart_callback_add(parent, "gadget_removed", _cpuclock_removed_cb, inst); evas_object_event_callback_add(inst->o_main, EVAS_CALLBACK_DEL, sysinfo_cpuclock_remove, inst); evas_object_show(inst->o_main); if (inst->cfg->id < 0) return inst->o_main; sysinfo_instances = eina_list_append(sysinfo_instances, inst); return inst->o_main; }