enlightenment/src/bin/e_exehist.c

563 lines
14 KiB
C

#include "e.h"
#include <libgen.h>
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;
/* 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();
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/applications/defaults.list",
efreet_data_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;
}