#include "e.h" #include E_API int E_EVENT_EXEHIST_UPDATE = 0; /* local subsystem functions */ typedef struct _E_Exehist E_Exehist; typedef struct _E_Exehist_Item E_Exehist_Item; struct _E_Exehist { Eina_List *history; Eina_List *mimes; int startup_id; }; struct _E_Exehist_Item { const char *exe; const char *normalized_exe; const char *launch_method; double exetime; unsigned int count; }; static void _e_exehist_unload_queue(void); static void _e_exehist_load(void); static void _e_exehist_clear(void); static void _e_exehist_unload(void); static void _e_exehist_limit(void); static const char *_e_exehist_normalize_exe(const char *exe); static void _e_exehist_cb_unload(void *data); static int _e_exehist_sort_exe_cb(const void *d1, const void *d2); static int _e_exehist_sort_pop_cb(const void *d1, const void *d2); /* local subsystem globals */ static E_Config_DD *_e_exehist_config_edd = NULL; static E_Config_DD *_e_exehist_config_item_edd = NULL; static E_Exehist *_e_exehist = NULL; static E_Powersave_Deferred_Action *_e_exehist_unload_defer = NULL; static int _e_exehist_changes = 0; static void _upgrade_defaults_to_mimeapps(void) { char buf[PATH_MAX], buf2[PATH_MAX]; snprintf(buf, sizeof(buf), "%s/mimeapps.list", efreet_config_home_get()); if (ecore_file_exists(buf)) return; ecore_file_mkpath(efreet_config_home_get()); snprintf(buf2, sizeof(buf2), "%s/applications/defaults.list", efreet_data_home_get()); ecore_file_cp(buf2, buf); } /* externally accessible functions */ EINTERN int e_exehist_init(void) { _e_exehist_config_item_edd = E_CONFIG_DD_NEW("E_Exehist_Item", E_Exehist_Item); #undef T #undef D #define T E_Exehist_Item #define D _e_exehist_config_item_edd E_CONFIG_VAL(D, T, exe, STR); E_CONFIG_VAL(D, T, normalized_exe, STR); E_CONFIG_VAL(D, T, launch_method, STR); E_CONFIG_VAL(D, T, exetime, DOUBLE); _e_exehist_config_edd = E_CONFIG_DD_NEW("E_Exehist", E_Exehist); #undef T #undef D #define T E_Exehist #define D _e_exehist_config_edd E_CONFIG_LIST(D, T, history, _e_exehist_config_item_edd); E_CONFIG_LIST(D, T, mimes, _e_exehist_config_item_edd); E_CONFIG_VAL(D, T, startup_id, INT); E_EVENT_EXEHIST_UPDATE = ecore_event_type_new(); _upgrade_defaults_to_mimeapps(); return 1; } EINTERN int e_exehist_shutdown(void) { if (_e_exehist_unload_defer) { e_powersave_deferred_action_del(_e_exehist_unload_defer); _e_exehist_unload_defer = NULL; } _e_exehist_cb_unload(NULL); E_CONFIG_DD_FREE(_e_exehist_config_item_edd); E_CONFIG_DD_FREE(_e_exehist_config_edd); return 1; } E_API void e_exehist_startup_id_set(int id) { _e_exehist_load(); if (!_e_exehist) return; _e_exehist->startup_id = id; _e_exehist_changes++; _e_exehist_unload_queue(); } E_API int e_exehist_startup_id_get(void) { int id; _e_exehist_load(); if (!_e_exehist) return 0; id = _e_exehist->startup_id; _e_exehist_unload_queue(); return id; } E_API void e_exehist_add(const char *launch_method, const char *exe) { E_Exehist_Item *ei; _e_exehist_load(); if (!_e_exehist) return; ei = E_NEW(E_Exehist_Item, 1); if (!ei) { _e_exehist_unload_queue(); return; } ei->launch_method = eina_stringshare_add(launch_method); ei->exe = eina_stringshare_add(exe); ei->normalized_exe = _e_exehist_normalize_exe(exe); ei->exetime = ecore_time_unix_get(); _e_exehist->history = eina_list_append(_e_exehist->history, ei); _e_exehist_limit(); _e_exehist_changes++; ecore_event_add(E_EVENT_EXEHIST_UPDATE, NULL, NULL, NULL); _e_exehist_unload_queue(); } E_API void e_exehist_del(const char *exe) { E_Exehist_Item *ei; Eina_List *l; Eina_Bool ok = EINA_FALSE; _e_exehist_load(); if (!_e_exehist) return; EINA_LIST_FOREACH(_e_exehist->history, l, ei) { if ((ei->exe) && (!strcmp(exe, ei->exe))) { eina_stringshare_del(ei->exe); eina_stringshare_del(ei->normalized_exe); eina_stringshare_del(ei->launch_method); free(ei); _e_exehist->history = eina_list_remove_list(_e_exehist->history, l); _e_exehist_changes++; _e_exehist_unload_queue(); ok = EINA_TRUE; } } if (ok) ecore_event_add(E_EVENT_EXEHIST_UPDATE, NULL, NULL, NULL); } E_API void e_exehist_clear(void) { _e_exehist_load(); if (!_e_exehist) return; _e_exehist_clear(); _e_exehist_changes++; ecore_event_add(E_EVENT_EXEHIST_UPDATE, NULL, NULL, NULL); _e_exehist_unload_queue(); } E_API int e_exehist_popularity_get(const char *exe) { Eina_List *l; E_Exehist_Item *ei; const char *normal; int count = 0; _e_exehist_load(); if (!_e_exehist) return 0; normal = _e_exehist_normalize_exe(exe); if (!normal) return 0; EINA_LIST_FOREACH(_e_exehist->history, l, ei) { if ((ei->normalized_exe) && (!strcmp(normal, ei->normalized_exe))) count++; } eina_stringshare_del(normal); _e_exehist_unload_queue(); return count; } E_API double e_exehist_newest_run_get(const char *exe) { Eina_List *l; E_Exehist_Item *ei; const char *normal; _e_exehist_load(); if (!_e_exehist) return 0.0; normal = _e_exehist_normalize_exe(exe); if (!normal) return 0.0; EINA_LIST_REVERSE_FOREACH(_e_exehist->history, l, ei) { if ((ei->normalized_exe) && (!strcmp(normal, ei->normalized_exe))) { eina_stringshare_del(normal); _e_exehist_unload_queue(); return ei->exetime; } } eina_stringshare_del(normal); _e_exehist_unload_queue(); return 0.0; } E_API Eina_List * e_exehist_list_get(void) { return e_exehist_sorted_list_get(E_EXEHIST_SORT_BY_DATE, 0); } E_API Eina_List * e_exehist_sorted_list_get(E_Exehist_Sort sort_type, int max) { Eina_List *list = NULL, *pop = NULL, *l = NULL, *m; Eina_Iterator *iter; E_Exehist_Item *ei; int count = 1; E_Exehist_Item *prev = NULL; if (!max) max = 20; _e_exehist_load(); switch (sort_type) { case E_EXEHIST_SORT_BY_EXE: case E_EXEHIST_SORT_BY_POPULARITY: l = eina_list_clone(_e_exehist->history); l = eina_list_sort(l, 0, _e_exehist_sort_exe_cb); iter = eina_list_iterator_new(l); break; default: iter = eina_list_iterator_reversed_new(_e_exehist->history); break; } EINA_ITERATOR_FOREACH(iter, ei) { int bad = 0; if (!(ei->normalized_exe)) continue; if (sort_type == E_EXEHIST_SORT_BY_POPULARITY) { if (!prev || (strcmp(prev->normalized_exe, ei->normalized_exe))) { prev = ei; pop = eina_list_append(pop, ei); } prev->count++; } else { const char *exe; EINA_LIST_FOREACH(list, m, exe) { if (!exe) continue; if (!strcmp(exe, ei->exe)) { bad = 1; break; } } if (!(bad)) { list = eina_list_append(list, ei->exe); count++; } } if (count > max) break; } if (sort_type == E_EXEHIST_SORT_BY_POPULARITY) { count = 1; pop = eina_list_sort(pop, 0, _e_exehist_sort_pop_cb); EINA_LIST_FOREACH(pop, l, prev) { list = eina_list_append(list, prev->exe); count++; if (count > max) break; } eina_list_free(pop); } eina_list_free(l); eina_iterator_free(iter); _e_exehist_unload_queue(); return list; } E_API void e_exehist_mime_desktop_add(const char *mime, Efreet_Desktop *desktop) { const char *f; E_Exehist_Item *ei; Eina_List *l; char buf[PATH_MAX]; Efreet_Ini *ini; if ((!mime) || (!desktop)) return; if (!desktop->orig_path) return; _e_exehist_load(); if (!_e_exehist) return; f = efreet_util_path_to_file_id(desktop->orig_path); if (!f) return; snprintf(buf, sizeof(buf), "%s/mimeapps.list", efreet_config_home_get()); ini = efreet_ini_new(buf); //fprintf(stderr, "try open %s = %p\n", buf, ini); if (ini) { //fprintf(stderr, "SAVE mime %s with %s\n", mime, desktop->orig_path); if (!efreet_ini_section_set(ini, "Default Applications")) { efreet_ini_section_add(ini, "Default Applications"); efreet_ini_section_set(ini, "Default Applications"); } if (desktop->orig_path) efreet_ini_string_set(ini, mime, ecore_file_file_get(desktop->orig_path)); efreet_ini_save(ini, buf); efreet_ini_free(ini); } EINA_LIST_FOREACH(_e_exehist->mimes, l, ei) { if ((ei->launch_method) && (!strcmp(mime, ei->launch_method))) { if ((ei->exe) && (!strcmp(f, ei->exe))) { _e_exehist_unload_queue(); return; } if (ei->exe) eina_stringshare_del(ei->exe); if (ei->launch_method) eina_stringshare_del(ei->launch_method); free(ei); _e_exehist->mimes = eina_list_remove_list(_e_exehist->mimes, l); _e_exehist_changes++; break; } } ei = E_NEW(E_Exehist_Item, 1); if (!ei) { _e_exehist_unload_queue(); return; } ei->launch_method = eina_stringshare_add(mime); ei->exe = eina_stringshare_add(f); ei->exetime = ecore_time_unix_get(); _e_exehist->mimes = eina_list_append(_e_exehist->mimes, ei); _e_exehist_limit(); _e_exehist_changes++; _e_exehist_unload_queue(); } E_API Efreet_Desktop * e_exehist_mime_desktop_get(const char *mime) { Efreet_Desktop *desktop; E_Exehist_Item *ei; Eina_List *l; //fprintf(stderr, "e_exehist_mime_desktop_get(%s)\n", mime); if (!mime) return NULL; _e_exehist_load(); //fprintf(stderr, "x\n"); if (!_e_exehist) return NULL; EINA_LIST_FOREACH(_e_exehist->mimes, l, ei) { //fprintf(stderr, "look for %s == %s\n", mime, ei->launch_method); if ((ei->launch_method) && (!strcmp(mime, ei->launch_method))) { desktop = NULL; if (ei->exe) desktop = efreet_util_desktop_file_id_find(ei->exe); //fprintf(stderr, " desk = %p\n", desktop); if (desktop) { _e_exehist_unload_queue(); return desktop; } } } _e_exehist_unload_queue(); return NULL; } /* local subsystem functions */ static void _e_exehist_unload_queue(void) { if (_e_exehist_unload_defer) e_powersave_deferred_action_del(_e_exehist_unload_defer); _e_exehist_unload_defer = e_powersave_deferred_action_add(_e_exehist_cb_unload, NULL); } static void _e_exehist_load(void) { if (!_e_exehist) _e_exehist = e_config_domain_load("exehist", _e_exehist_config_edd); if (!_e_exehist) _e_exehist = E_NEW(E_Exehist, 1); } static void _e_exehist_clear(void) { if (_e_exehist) { E_Exehist_Item *ei; EINA_LIST_FREE(_e_exehist->history, ei) { eina_stringshare_del(ei->exe); eina_stringshare_del(ei->normalized_exe); eina_stringshare_del(ei->launch_method); free(ei); } EINA_LIST_FREE(_e_exehist->mimes, ei) { eina_stringshare_del(ei->exe); eina_stringshare_del(ei->launch_method); free(ei); } } } static void _e_exehist_unload(void) { _e_exehist_clear(); E_FREE(_e_exehist); } static void _e_exehist_limit(void) { /* go from first item in hist on and either delete all items before a * specific timestamp, or if the list count > limit then delete items * * for now - limit to 500 */ if (_e_exehist) { while (eina_list_count(_e_exehist->history) > 500) { E_Exehist_Item *ei; ei = eina_list_data_get(_e_exehist->history); eina_stringshare_del(ei->exe); eina_stringshare_del(ei->normalized_exe); eina_stringshare_del(ei->launch_method); free(ei); _e_exehist->history = eina_list_remove_list(_e_exehist->history, _e_exehist->history); } while (eina_list_count(_e_exehist->mimes) > 500) { E_Exehist_Item *ei; ei = eina_list_data_get(_e_exehist->mimes); eina_stringshare_del(ei->exe); eina_stringshare_del(ei->launch_method); free(ei); _e_exehist->mimes = eina_list_remove_list(_e_exehist->mimes, _e_exehist->mimes); } } } static const char * _e_exehist_normalize_exe(const char *exe) { char *base, *buf, *cp, *space = NULL; const char *ret; Eina_Bool flag = EINA_FALSE; buf = strdup(exe); base = basename(buf); if ((base[0] == '.') && (base[1] == '\0')) { free(buf); return NULL; } cp = base; while (*cp) { if (isspace(*cp)) { if (!space) space = cp; if (flag) flag = EINA_FALSE; } else if (!flag) { /* usually a variable in the desktop exe field */ if (space && *cp == '%') flag = EINA_TRUE; else { char lower = tolower(*cp); space = NULL; if (lower != *cp) *cp = lower; } } cp++; } if (space) *space = '\0'; ret = eina_stringshare_add(base); free(buf); return ret; } static void _e_exehist_cb_unload(void *data EINA_UNUSED) { if (_e_exehist_changes) { e_config_domain_save("exehist", _e_exehist_config_edd, _e_exehist); _e_exehist_changes = 0; } _e_exehist_unload(); _e_exehist_unload_defer = NULL; } static int _e_exehist_sort_exe_cb(const void *d1, const void *d2) { const E_Exehist_Item *ei1, *ei2; ei1 = d1; ei2 = d2; if ((!ei1) || (!ei1->normalized_exe)) return 1; if ((!ei2) || (!ei2->normalized_exe)) return -1; return strcmp(ei1->normalized_exe, ei2->normalized_exe); } static int _e_exehist_sort_pop_cb(const void *d1, const void *d2) { const E_Exehist_Item *ei1, *ei2; if (!(ei1 = d1)) return 1; if (!(ei2 = d2)) return -1; return ei2->count - ei1->count; }