efl/legacy/efreet/src/lib/efreet_utils.c

1236 lines
33 KiB
C

/* vim: set sw=4 ts=4 sts=4 et: */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <fnmatch.h>
#include <Ecore.h>
#include <Ecore_File.h>
#include "Efreet.h"
#include "efreet_private.h"
typedef struct Efreet_Cache_Fill Efreet_Cache_Fill;
typedef struct Efreet_Cache_Fill_Dir Efreet_Cache_Fill_Dir;
typedef struct Efreet_Cache_Search Efreet_Cache_Search;
typedef struct Efreet_Cache_Search_List Efreet_Cache_Search_List;
typedef struct Efreet_Monitor Efreet_Monitor;
typedef struct Efreet_Util_Desktop Efreet_Util_Desktop;
struct Efreet_Cache_Fill
{
Eina_List *dirs;
Efreet_Cache_Fill_Dir *current;
DIR *files;
};
struct Efreet_Cache_Fill_Dir
{
char *path;
char *file_id;
int priority;
};
struct Efreet_Cache_Search
{
Efreet_Util_Desktop *result;
const char *what1;
const char *what2;
};
struct Efreet_Cache_Search_List
{
Eina_List *list;
const char *what;
};
struct Efreet_Monitor
{
char *file_id;
Ecore_File_Monitor *monitor;
int priority;
};
struct Efreet_Util_Desktop
{
Efreet_Desktop *desktop;
int priority;
};
/* define macros and variable for using the eina logging system */
#ifdef EFREET_MODULE_LOG_DOM
#undef EFREET_MODULE_LOG_DOM
#endif
#define EFREET_MODULE_LOG_DOM _efreet_utils_log_dom
static int _efreet_utils_log_dom = -1;
static char *efreet_util_path_in_default(const char *section, const char *path);
static int efreet_util_cache_fill(void *data);
static void efreet_util_cache_add(const char *path, const char *file_id, int priority, int event);
static void efreet_util_cache_remove(const char *path, const char *file_id, int priority);
static void efreet_util_cache_reload(const char *path, const char *file_id, int priority);
static void efreet_util_cache_dir_free(void *data);
static Eina_Bool efreet_util_cache_search_mime(const Eina_Hash *hash, void *value, void *fdata);
static Eina_Bool efreet_util_cache_search_wm_class(const Eina_Hash *hash, void *value, void *fdata);
static Eina_Bool efreet_util_cache_search_exec(const Eina_Hash *hash, void *value, void *fdata);
static Eina_Bool efreet_util_cache_search_name(const Eina_Hash *hash, void *value, void *fdata);
static Eina_Bool efreet_util_cache_search_generic_name(const Eina_Hash *hash, void *value, void *fdata);
static Eina_Bool efreet_util_cache_search_name_glob(const Eina_Hash *hash, void *value, void *fdata);
static Eina_Bool efreet_util_cache_search_exec_glob(const Eina_Hash *hash, void *value, void *fdata);
static Eina_Bool efreet_util_cache_search_generic_name_glob(const Eina_Hash *hash, void *value, void *fdata);
static Eina_Bool efreet_util_cache_search_comment_glob(const Eina_Hash *hash, void *value, void *fdata);
static int efreet_util_glob_match(const char *str, const char *glob);
static void efreet_util_monitor(const char *path, const char *file_id, int priority);
static void efreet_util_monitor_cb(void *data, Ecore_File_Monitor *monitor,
Ecore_File_Event event, const char *path);
static void efreet_util_monitor_free(void *data);
static void efreet_util_menus_find_helper(Eina_List *menus, const char *config_dir);
static void efreet_util_desktops_by_category_add(Efreet_Desktop *desktop);
static void efreet_util_desktops_by_category_remove(Efreet_Desktop *desktop);
static void efreet_util_desktop_free(Efreet_Util_Desktop *ud);
static void efreet_event_desktop_change_free(void *data, void *ev);
static Eina_Hash *desktop_by_file_id = NULL;
static Eina_Hash *file_id_by_desktop_path = NULL;
static Eina_Hash *desktops_by_category = NULL;
static Ecore_Idler *idler = NULL;
static Efreet_Cache_Fill *fill = NULL;
static Eina_List *monitors = NULL;
static int init = 0;
EAPI int EFREET_EVENT_DESKTOP_LIST_CHANGE = 0;
EAPI int EFREET_EVENT_DESKTOP_CHANGE = 0;
EAPI int
efreet_util_init(void)
{
Eina_List *dirs;
if (init++) return init;
_efreet_utils_log_dom = eina_log_domain_register("Efreet_util",EFREET_DEFAULT_LOG_COLOR);
if(_efreet_utils_log_dom < 0)
{
ERROR("Efreet: Could not create a log domain for efreet_util");
return 0;
}
if (!EFREET_EVENT_DESKTOP_LIST_CHANGE)
EFREET_EVENT_DESKTOP_LIST_CHANGE = ecore_event_type_new();
if (!EFREET_EVENT_DESKTOP_CHANGE)
EFREET_EVENT_DESKTOP_CHANGE = ecore_event_type_new();
desktop_by_file_id = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_util_desktop_free));
file_id_by_desktop_path = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del));
desktops_by_category = eina_hash_string_superfast_new(EINA_FREE_CB(eina_list_free));
monitors = NULL;
fill = NEW(Efreet_Cache_Fill, 1);
dirs = efreet_default_dirs_get(efreet_data_home_get(), efreet_data_dirs_get(),
"applications");
if (dirs)
{
Efreet_Cache_Fill_Dir *dir;
char *path;
int priority = 0;
while (dirs)
{
path = eina_list_data_get(dirs);
dir = NEW(Efreet_Cache_Fill_Dir, 1);
dir->path = path;
dir->priority = priority++;
fill->dirs = eina_list_append(fill->dirs, dir);
dirs = eina_list_remove_list(dirs, dirs);
}
}
idler = ecore_idler_add(efreet_util_cache_fill, NULL);
return init;
}
EAPI int
efreet_util_shutdown(void)
{
Efreet_Monitor *em;
Efreet_Cache_Fill_Dir *dir;
if (--init) return init;
if (idler)
{
ecore_idler_del(idler);
while (fill->dirs)
{
dir = eina_list_data_get(fill->dirs);
efreet_util_cache_dir_free(dir);
fill->dirs = eina_list_remove_list(fill->dirs, fill->dirs);
}
if (fill->current) efreet_util_cache_dir_free(fill->current);
if (fill->files) closedir(fill->files);
free(fill);
}
idler = NULL;
IF_FREE_HASH(desktop_by_file_id);
IF_FREE_HASH(file_id_by_desktop_path);
while (monitors)
{
em = eina_list_data_get(monitors);
efreet_util_monitor_free(em);
monitors = eina_list_remove_list(monitors, monitors);
}
IF_FREE_HASH(desktops_by_category);
eina_log_domain_unregister(_efreet_utils_log_dom);
return init;
}
static char *
efreet_util_path_in_default(const char *section, const char *path)
{
Eina_List *dirs;
char *ret = NULL;
char *dir;
dirs = efreet_default_dirs_get(efreet_data_home_get(), efreet_data_dirs_get(),
section);
EINA_LIST_FREE(dirs, dir)
{
if (!strncmp(path, dir, strlen(dir)))
{
ret = dir;
break;
}
free(dir);
}
EINA_LIST_FREE(dirs, dir)
if (ret != dir) free(dir);
return ret;
}
EAPI const char *
efreet_util_path_to_file_id(const char *path)
{
size_t len;
char *tmp, *p;
char *base;
const char *file_id = NULL;
if (!path) return NULL;
file_id = eina_hash_find(file_id_by_desktop_path, path);
if (file_id) return file_id;
base = efreet_util_path_in_default("applications", path);
if (!base) return NULL;
len = strlen(base);
if (strlen(path) <= len)
{
free(base);
return NULL;
}
if (strncmp(path, base, len))
{
free(base);
return NULL;
}
tmp = strdup(path + len + 1);
p = tmp;
while (*p)
{
if (*p == '/') *p = '-';
p++;
}
free(base);
file_id = eina_stringshare_add(tmp);
free(tmp);
eina_hash_del(file_id_by_desktop_path, path, NULL);
eina_hash_add(file_id_by_desktop_path, path, (void *)file_id);
return file_id;
}
EAPI Eina_List *
efreet_util_desktop_mime_list(const char *mime)
{
Efreet_Cache_Search_List search;
Eina_Iterator *it;
search.list = NULL;
search.what = eina_stringshare_add(mime);
it = eina_hash_iterator_data_new(desktop_by_file_id);
eina_iterator_foreach(it, EINA_EACH(efreet_util_cache_search_mime), &search);
eina_iterator_free(it);
eina_stringshare_del(search.what);
return search.list;
}
EAPI Efreet_Desktop *
efreet_util_desktop_wm_class_find(const char *wmname, const char *wmclass)
{
Efreet_Cache_Search search;
Efreet_Util_Desktop *ud;
Eina_Iterator *it;
if ((!wmname) && (!wmclass)) return NULL;
search.what1 = wmname;
search.what2 = wmclass;
search.result = NULL;
it = eina_hash_iterator_data_new(desktop_by_file_id);
eina_iterator_foreach(it, EINA_EACH(efreet_util_cache_search_wm_class), &search);
eina_iterator_free(it);
ud = search.result;
if (ud)
{
efreet_desktop_ref(ud->desktop);
return ud->desktop;
}
return NULL;
}
EAPI Efreet_Desktop *
efreet_util_desktop_file_id_find(const char *file_id)
{
Efreet_Desktop *desktop = NULL;
Efreet_Util_Desktop *ud = NULL;
Eina_List *dirs, *l;
const char *dir;
int priority = 0;
if (!file_id) return NULL;
ud = eina_hash_find(desktop_by_file_id, file_id);
if (ud) return ud->desktop;
dirs = efreet_default_dirs_get(efreet_data_home_get(), efreet_data_dirs_get(),
"applications");
if (!dirs) return NULL;
EINA_LIST_FOREACH(dirs, l, dir)
{
char *tmp, *p;
char buf[PATH_MAX];
tmp = strdup(file_id);
p = tmp;
while (p)
{
snprintf(buf, sizeof(buf), "%s/%s", dir, tmp);
desktop = efreet_desktop_get(buf);
if (desktop) break;
p = strchr(p, '-');
if (p) *p = '/';
}
free(tmp);
if (desktop) break;
priority++;
}
while (dirs)
{
free(eina_list_data_get(dirs));
dirs = eina_list_remove_list(dirs, dirs);
}
if (desktop)
{
Efreet_Event_Desktop_Change *ev;
ud = NEW(Efreet_Util_Desktop, 1);
ud->priority = priority;
ud->desktop = desktop;
eina_hash_del(desktop_by_file_id, file_id, NULL);
eina_hash_add(desktop_by_file_id, file_id, ud);
efreet_util_desktops_by_category_add(desktop);
ev = NEW(Efreet_Event_Desktop_Change, 1);
ev->current = desktop;
efreet_desktop_ref(ev->current);
ev->change = EFREET_DESKTOP_CHANGE_ADD;
ecore_event_add(EFREET_EVENT_DESKTOP_CHANGE, ev, efreet_event_desktop_change_free, NULL);
}
return desktop;
}
EAPI Efreet_Desktop *
efreet_util_desktop_exec_find(const char *exec)
{
Efreet_Cache_Search search;
Eina_Iterator *it;
if (!exec) return NULL;
search.what1 = exec;
search.what2 = NULL;
search.result = NULL;
it = eina_hash_iterator_data_new(desktop_by_file_id);
eina_iterator_foreach(it, EINA_EACH(efreet_util_cache_search_exec), &search);
eina_iterator_free(it);
if (!search.result) return NULL;
efreet_desktop_ref(search.result->desktop);
return search.result->desktop;
}
EAPI Efreet_Desktop *
efreet_util_desktop_name_find(const char *name)
{
Efreet_Cache_Search search;
Eina_Iterator *it;
if (!name) return NULL;
search.what1 = name;
search.what2 = NULL;
search.result = NULL;
it = eina_hash_iterator_data_new(desktop_by_file_id);
eina_iterator_foreach(it, EINA_EACH(efreet_util_cache_search_name), &search);
eina_iterator_free(it);
if (!search.result) return NULL;
efreet_desktop_ref(search.result->desktop);
return search.result->desktop;
}
EAPI Efreet_Desktop *
efreet_util_desktop_generic_name_find(const char *generic_name)
{
Efreet_Cache_Search search;
Eina_Iterator *it;
if (!generic_name) return NULL;
search.what1 = generic_name;
search.what2 = NULL;
search.result = NULL;
it = eina_hash_iterator_data_new(desktop_by_file_id);
eina_iterator_foreach(it, EINA_EACH(efreet_util_cache_search_generic_name), &search);
eina_iterator_free(it);
if (!search.result) return NULL;
efreet_desktop_ref(search.result->desktop);
return search.result->desktop;
}
EAPI Eina_List *
efreet_util_desktop_name_glob_list(const char *glob)
{
Efreet_Cache_Search_List search;
Eina_Iterator *it;
search.list = NULL;
search.what = glob;
it = eina_hash_iterator_data_new(desktop_by_file_id);
eina_iterator_foreach(it, EINA_EACH(efreet_util_cache_search_name_glob), &search);
eina_iterator_free(it);
return search.list;
}
EAPI Eina_List *
efreet_util_desktop_exec_glob_list(const char *glob)
{
Efreet_Cache_Search_List search;
Eina_Iterator *it;
search.list = NULL;
search.what = glob;
it = eina_hash_iterator_data_new(desktop_by_file_id);
eina_iterator_foreach(it, EINA_EACH(efreet_util_cache_search_exec_glob), &search);
eina_iterator_free(it);
return search.list;
}
EAPI Eina_List *
efreet_util_desktop_generic_name_glob_list(const char *glob)
{
Efreet_Cache_Search_List search;
Eina_Iterator *it;
search.list = NULL;
search.what = glob;
it = eina_hash_iterator_data_new(desktop_by_file_id);
eina_iterator_foreach(it, EINA_EACH(efreet_util_cache_search_generic_name_glob), &search);
eina_iterator_free(it);
return search.list;
}
EAPI Eina_List *
efreet_util_desktop_comment_glob_list(const char *glob)
{
Efreet_Cache_Search_List search;
Eina_Iterator *it;
search.list = NULL;
search.what = glob;
it = eina_hash_iterator_data_new(desktop_by_file_id);
eina_iterator_foreach(it, EINA_EACH(efreet_util_cache_search_comment_glob), &search);
eina_iterator_free(it);
return search.list;
}
static Eina_Bool
_hash_keys(Eina_Hash *hash __UNUSED__, const void *key, void *fdata)
{
Eina_List **l = fdata;
*l = eina_list_append(*l, key);
return EINA_TRUE;
}
/**
* Find all desktop categories
* This list must be freed using EINA_LIST_FREE
*
* @return an Eina_List of category names (const char *)
*/
EAPI Eina_List *
efreet_util_desktop_categories_list(void)
{
Eina_Iterator *it;
Eina_List *list = NULL;
it = eina_hash_iterator_key_new(desktops_by_category);
if (it)
{
eina_iterator_foreach(it, EINA_EACH(_hash_keys), &list);
eina_iterator_free(it);
}
return list;
}
/**
* Find all desktops in a given category
*
* Note: this returns a pointer to an internal list. Do not add to, remove from, or delete this list.
*
* @param category the category name
* @return a list of desktops
*/
EAPI Eina_List *
efreet_util_desktop_category_list(const char *category)
{
return eina_hash_find(desktops_by_category, category);
}
#if 0
static Eina_Bool
dump(Eina_Hash *hash, const char *key, void *value, __UNUSED__ void *data)
{
INF("%s -> %p", (char *)key, value);
}
#endif
static int
efreet_util_cache_fill(__UNUSED__ void *data)
{
Efreet_Cache_Fill_Dir *dir;
struct dirent *file = NULL;
double start;
char buf[PATH_MAX];
if ((!fill->dirs) && (!fill->files))
{
free(fill);
idler = NULL;
fill = NULL;
efreet_cache_clear();
ecore_event_add(EFREET_EVENT_DESKTOP_LIST_CHANGE, NULL, NULL, NULL);
return 0;
}
if (!fill->current)
{
fill->current = eina_list_data_get(fill->dirs);
fill->dirs = eina_list_remove_list(fill->dirs, fill->dirs);
if (!fill->current)
{
while (fill->dirs)
{
dir = eina_list_data_get(fill->dirs);
efreet_util_cache_dir_free(dir);
fill->dirs = eina_list_remove_list(fill->dirs, fill->dirs);
}
free(fill);
idler = NULL;
fill = NULL;
#if 0
eina_hash_foreach(desktop_by_file_id, dump, NULL);
eina_hash_foreach(file_id_by_desktop_path, dump, NULL);
DBG("%d", eina_hash_population(desktop_by_file_id));
#endif
efreet_cache_clear();
ecore_event_add(EFREET_EVENT_DESKTOP_LIST_CHANGE, NULL, NULL, NULL);
return 0;
}
}
start = ecore_time_get();
if (!fill->files)
{
fill->files = opendir(fill->current->path);
}
if (!fill->files)
{
/* Couldn't open this dir, continue to next */
efreet_util_cache_dir_free(fill->current);
fill->current = NULL;
}
else
{
do
{
char file_id[PATH_MAX];
file = readdir(fill->files);
if (!file) break;
if (!strcmp(file->d_name, ".") || !strcmp(file->d_name, "..")) continue;
snprintf(buf, PATH_MAX, "%s/%s", fill->current->path, file->d_name);
if (fill->current->file_id)
snprintf(file_id, PATH_MAX, "%s-%s", fill->current->file_id, file->d_name);
else
strcpy(file_id, file->d_name);
if (ecore_file_is_dir(buf))
{
Efreet_Cache_Fill_Dir *dir;
dir = NEW(Efreet_Cache_Fill_Dir, 1);
dir->path = strdup(buf);
dir->file_id = strdup(file_id);
dir->priority = fill->current->priority;
fill->dirs = eina_list_append(fill->dirs, dir);
}
else
efreet_util_cache_add(buf, file_id, fill->current->priority, 0);
} while ((ecore_time_get() - start) < 0.01);
if (!file)
{
/* This dir has been search through */
efreet_util_monitor(fill->current->path, fill->current->file_id,
fill->current->priority);
efreet_util_cache_dir_free(fill->current);
fill->current = NULL;
closedir(fill->files);
fill->files = NULL;
}
}
return 1;
}
static void
efreet_util_cache_add(const char *path, const char *file_id, int priority, int event)
{
Efreet_Desktop *desktop;
Efreet_Util_Desktop *ud;
char *ext;
ext = strrchr(path, '.');
if (!ext || strcmp(ext, ".desktop")) return;
desktop = efreet_desktop_get(path);
if (!desktop || desktop->type != EFREET_DESKTOP_TYPE_APPLICATION)
{
if (desktop) efreet_desktop_free(desktop);
return;
}
if (!eina_hash_find(file_id_by_desktop_path, desktop->orig_path))
{
eina_hash_add(file_id_by_desktop_path,
desktop->orig_path,
(void *)eina_stringshare_add(file_id));
}
ud = eina_hash_find(desktop_by_file_id, file_id);
if (!ud)
{
ud = NEW(Efreet_Util_Desktop, 1);
ud->priority = priority;
ud->desktop = desktop;
eina_hash_add(desktop_by_file_id, file_id, ud);
efreet_util_desktops_by_category_add(desktop);
if (event)
{
Efreet_Event_Desktop_Change *ev;
ev = NEW(Efreet_Event_Desktop_Change, 1);
ev->current = desktop;
efreet_desktop_ref(ev->current);
ev->change = EFREET_DESKTOP_CHANGE_ADD;
efreet_cache_clear();
ecore_event_add(EFREET_EVENT_DESKTOP_CHANGE, ev, efreet_event_desktop_change_free, NULL);
}
}
else if (priority < ud->priority)
{
efreet_util_desktops_by_category_remove(ud->desktop);
efreet_util_desktops_by_category_add(desktop);
if (event)
{
Efreet_Event_Desktop_Change *ev;
ev = NEW(Efreet_Event_Desktop_Change, 1);
ev->current = desktop;
efreet_desktop_ref(ev->current);
ev->previous = ud->desktop;
efreet_desktop_ref(ev->previous);
ev->change = EFREET_DESKTOP_CHANGE_UPDATE;
efreet_desktop_free(ud->desktop);
ud->desktop = desktop;
efreet_cache_clear();
ecore_event_add(EFREET_EVENT_DESKTOP_CHANGE, ev, efreet_event_desktop_change_free, NULL);
}
else
{
efreet_desktop_free(ud->desktop);
ud->desktop = desktop;
}
}
else
efreet_desktop_free(desktop);
}
static void
efreet_util_cache_remove(const char *path, const char *file_id, int priority)
{
Efreet_Util_Desktop *ud;
char *ext;
ext = strrchr(path, '.');
if (!ext || strcmp(ext, ".desktop")) return;
ud = eina_hash_find(desktop_by_file_id, file_id);
if (ud && (ud->priority >= priority))
{
Efreet_Event_Desktop_Change *ev;
efreet_util_desktops_by_category_remove(ud->desktop);
ev = NEW(Efreet_Event_Desktop_Change, 1);
ev->current = ud->desktop;
efreet_desktop_ref(ev->current);
ev->change = EFREET_DESKTOP_CHANGE_REMOVE;
efreet_cache_clear();
ecore_event_add(EFREET_EVENT_DESKTOP_CHANGE, ev, efreet_event_desktop_change_free, NULL);
eina_hash_del(desktop_by_file_id, file_id, ud);
/* This call will search application dirs and add the file to cache if it
* exists. */
efreet_util_desktop_file_id_find(file_id);
}
eina_hash_del(file_id_by_desktop_path, path, eina_hash_find(file_id_by_desktop_path, path));
}
static void
efreet_util_cache_reload(const char *path, const char *file_id, int priority)
{
Efreet_Desktop *desktop;
Efreet_Util_Desktop *ud;
char *ext;
ext = strrchr(path, '.');
if (!ext || strcmp(ext, ".desktop")) return;
desktop = efreet_desktop_get(path);
if (!desktop || desktop->type != EFREET_DESKTOP_TYPE_APPLICATION)
{
if (desktop) efreet_desktop_free(desktop);
return;
}
ud = eina_hash_find(desktop_by_file_id, file_id);
if (ud)
{
Efreet_Event_Desktop_Change *ev;
if (ud->priority < priority)
{
efreet_desktop_free(desktop);
return;
}
efreet_util_desktops_by_category_remove(ud->desktop);
efreet_util_desktops_by_category_add(desktop);
ev = NEW(Efreet_Event_Desktop_Change, 1);
ev->current = desktop;
efreet_desktop_ref(ev->current);
ev->previous = ud->desktop;
efreet_desktop_ref(ev->previous);
ev->change = EFREET_DESKTOP_CHANGE_UPDATE;
efreet_cache_clear();
ecore_event_add(EFREET_EVENT_DESKTOP_CHANGE, ev, efreet_event_desktop_change_free, NULL);
efreet_desktop_free(ud->desktop);
ud->desktop = desktop;
}
else
{
Efreet_Event_Desktop_Change *ev;
ud = NEW(Efreet_Util_Desktop, 1);
ud->priority = priority;
ud->desktop = desktop;
eina_hash_add(desktop_by_file_id, file_id, ud);
efreet_util_desktops_by_category_remove(ud->desktop);
efreet_util_desktops_by_category_add(desktop);
ev = NEW(Efreet_Event_Desktop_Change, 1);
ev->current = desktop;
efreet_desktop_ref(ev->current);
ev->change = EFREET_DESKTOP_CHANGE_ADD;
efreet_cache_clear();
ecore_event_add(EFREET_EVENT_DESKTOP_CHANGE, ev, efreet_event_desktop_change_free, NULL);
}
}
static void
efreet_util_cache_dir_free(void *data)
{
Efreet_Cache_Fill_Dir *dir;
dir = data;
IF_FREE(dir->path);
IF_FREE(dir->file_id);
free(dir);
}
static Eina_Bool
efreet_util_cache_search_mime(__UNUSED__ const Eina_Hash *hash, void *value, void *fdata)
{
Efreet_Cache_Search_List *search;
Efreet_Util_Desktop *ud;
Eina_List *l;
const char *mime;
search = fdata;
ud = value;
if (!ud->desktop->mime_types) return EINA_TRUE;
EINA_LIST_FOREACH(ud->desktop->mime_types, l, mime)
if (search->what == mime)
{
efreet_desktop_ref(ud->desktop);
search->list = eina_list_append(search->list, ud->desktop);
break;
}
return EINA_TRUE;
}
static Eina_Bool
efreet_util_cache_search_wm_class(__UNUSED__ const Eina_Hash *hash, void *value, void *fdata)
{
Efreet_Cache_Search *search;
Efreet_Util_Desktop *ud;
ud = value;
search = fdata;
if (!ud->desktop) return EINA_TRUE;
if (!ud->desktop->startup_wm_class) return EINA_TRUE;
if ((search->what2) && (!strcmp(ud->desktop->startup_wm_class, search->what2)))
{
search->result = ud;
return EINA_FALSE;
}
else if ((search->what1) && (!strcmp(ud->desktop->startup_wm_class, search->what1)))
{
search->result = ud;
return EINA_FALSE;
}
return EINA_TRUE;
}
static Eina_Bool
efreet_util_cache_search_exec(__UNUSED__ const Eina_Hash *hash, void *value, void *fdata)
{
Efreet_Cache_Search *search;
Efreet_Util_Desktop *ud;
char *exec;
const char *file;
ud = value;
search = fdata;
if (!ud->desktop->exec) return EINA_TRUE;
exec = ecore_file_app_exe_get(ud->desktop->exec);
if (!exec) return EINA_TRUE;
if (!strcmp(exec, search->what1))
{
free(exec);
search->result = ud;
return EINA_FALSE;
}
file = ecore_file_file_get(exec);
if (file && !strcmp(file, search->what1))
{
free(exec);
search->result = ud;
return EINA_FALSE;
}
free(exec);
return EINA_TRUE;
}
static Eina_Bool
efreet_util_cache_search_name(__UNUSED__ const Eina_Hash *hash, void *value, void *fdata)
{
Efreet_Cache_Search *search;
Efreet_Util_Desktop *ud;
ud = value;
search = fdata;
if (!ud->desktop->name) return EINA_TRUE;
if (!strcmp(ud->desktop->name, search->what1))
{
search->result = ud;
return EINA_FALSE;
}
return EINA_TRUE;
}
static Eina_Bool
efreet_util_cache_search_generic_name(__UNUSED__ const Eina_Hash *hash, void *value, void *fdata)
{
Efreet_Cache_Search *search;
Efreet_Util_Desktop *ud;
ud = value;
search = fdata;
if (!ud->desktop->generic_name) return EINA_TRUE;
if (!strcmp(ud->desktop->generic_name, search->what1))
{
search->result = ud;
return EINA_FALSE;
}
return EINA_TRUE;
}
static Eina_Bool
efreet_util_cache_search_name_glob(__UNUSED__ const Eina_Hash *hash, void *value, void *fdata)
{
Efreet_Cache_Search_List *search;
Efreet_Util_Desktop *ud;
search = fdata;
ud = value;
if (!ud->desktop) return EINA_TRUE;
if (efreet_util_glob_match(ud->desktop->name, search->what))
{
efreet_desktop_ref(ud->desktop);
search->list = eina_list_append(search->list, ud->desktop);
}
return EINA_TRUE;
}
static Eina_Bool
efreet_util_cache_search_exec_glob(__UNUSED__ const Eina_Hash *hash, void *value, void *fdata)
{
Efreet_Cache_Search_List *search;
Efreet_Util_Desktop *ud;
char *exec;
search = fdata;
ud = value;
if (!ud->desktop->exec) return EINA_TRUE;
exec = ecore_file_app_exe_get(ud->desktop->exec);
if (!exec) return EINA_TRUE;
if (efreet_util_glob_match(exec, search->what))
{
efreet_desktop_ref(ud->desktop);
search->list = eina_list_append(search->list, ud->desktop);
}
free(exec);
return EINA_TRUE;
}
static Eina_Bool
efreet_util_cache_search_generic_name_glob(__UNUSED__ const Eina_Hash *hash, void *value, void *fdata)
{
Efreet_Cache_Search_List *search;
Efreet_Util_Desktop *ud;
search = fdata;
ud = value;
if (efreet_util_glob_match(ud->desktop->generic_name, search->what))
{
efreet_desktop_ref(ud->desktop);
search->list = eina_list_append(search->list, ud->desktop);
}
return EINA_TRUE;
}
static Eina_Bool
efreet_util_cache_search_comment_glob(__UNUSED__ const Eina_Hash *hash, void *value, void *fdata)
{
Efreet_Cache_Search_List *search;
Efreet_Util_Desktop *ud;
search = fdata;
ud = value;
if (efreet_util_glob_match(ud->desktop->comment, search->what))
{
efreet_desktop_ref(ud->desktop);
search->list = eina_list_append(search->list, ud->desktop);
}
return EINA_TRUE;
}
static int
efreet_util_glob_match(const char *str, const char *glob)
{
if (!str || !glob)
return 0;
if (glob[0] == '\0')
{
if (str[0] == '\0') return 1;
return 0;
}
if (!strcmp(glob, "*")) return 1;
if (!fnmatch(glob, str, 0)) return 1;
return 0;
}
static void
efreet_util_monitor(const char *path, const char *file_id, int priority)
{
Efreet_Monitor *em;
em = NEW(Efreet_Monitor, 1);
em->monitor = ecore_file_monitor_add(path, efreet_util_monitor_cb, em);
if (file_id) em->file_id = strdup(file_id);
em->priority = priority;
monitors = eina_list_append(monitors, em);
}
static void
efreet_util_monitor_cb(void *data, Ecore_File_Monitor *monitor __UNUSED__,
Ecore_File_Event event, const char *path)
{
Efreet_Monitor *em;
char file_id[PATH_MAX];
em = data;
if (em->file_id)
snprintf(file_id, sizeof(file_id), "%s-%s", em->file_id, ecore_file_file_get(path));
else
strcpy(file_id, ecore_file_file_get(path));
switch (event)
{
case ECORE_FILE_EVENT_NONE:
/* Ignore */
break;
case ECORE_FILE_EVENT_CREATED_FILE:
efreet_util_cache_add(path, file_id, em->priority, 1);
break;
case ECORE_FILE_EVENT_CREATED_DIRECTORY:
{
Efreet_Cache_Fill_Dir *dir;
if (!fill)
{
fill = NEW(Efreet_Cache_Fill, 1);
}
dir = NEW(Efreet_Cache_Fill_Dir, 1);
dir->path = strdup(path);
dir->file_id = strdup(file_id);
dir->priority = em->priority;
fill->dirs = eina_list_append(fill->dirs, dir);
if (!idler)
idler = ecore_idler_add(efreet_util_cache_fill, NULL);
}
break;
case ECORE_FILE_EVENT_DELETED_FILE:
efreet_util_cache_remove(path, file_id, em->priority);
break;
case ECORE_FILE_EVENT_DELETED_DIRECTORY:
/* Ignore, we should already have a monitor on any subdir */
break;
case ECORE_FILE_EVENT_DELETED_SELF:
if (eina_list_data_find(monitors, em))
monitors = eina_list_remove(monitors, em);
efreet_util_monitor_free(em);
break;
case ECORE_FILE_EVENT_MODIFIED:
efreet_util_cache_reload(path, file_id, em->priority);
break;
}
}
static void
efreet_util_monitor_free(void *data)
{
Efreet_Monitor *em;
em = data;
if (em->monitor) ecore_file_monitor_del(em->monitor);
IF_FREE(em->file_id);
free(em);
}
/**
* Returns a list of .menu files found in the various config dirs.
* @return An eina list of menu file paths (const char *). This must be freed with EINA_LIST_FREE.
*/
EAPI Eina_List *
efreet_util_menus_find(void)
{
Eina_List *menus = NULL;
Eina_List *dirs, *l;
const char *dir;
efreet_util_menus_find_helper(menus, efreet_config_home_get());
dirs = efreet_config_dirs_get();
EINA_LIST_FOREACH(dirs, l, dir)
efreet_util_menus_find_helper(menus, dir);
return menus;
}
static void
efreet_util_menus_find_helper(Eina_List *menus, const char *config_dir)
{
DIR *files = NULL;
struct dirent *file = NULL;
char dbuf[PATH_MAX], fbuf[PATH_MAX];
snprintf(dbuf, sizeof(dbuf), "%s/menus", config_dir);
files = opendir(dbuf);
if (!files) return;
while ((file = readdir(files))) {
const char *exten;
exten = strrchr(file->d_name, '.');
if (!exten) continue;
if (strcmp(".menu", exten)) continue;
snprintf(fbuf, PATH_MAX, "%s/%s", dbuf, file->d_name);
if (ecore_file_is_dir(fbuf)) continue;
menus = eina_list_append(menus, strdup(fbuf));
}
closedir(files);
}
static void
efreet_util_desktops_by_category_add(Efreet_Desktop *desktop)
{
Eina_List *l;
const char *category;
if (!desktop->categories) return;
EINA_LIST_FOREACH(desktop->categories, l, category)
{
Eina_List *list;
int newlist = 0;
list = eina_hash_find(desktops_by_category, category);
if (!list) newlist = 1;
if (!eina_list_data_find(list, desktop))
list = eina_list_append(list, desktop);
if (newlist)
eina_hash_add(desktops_by_category, category, list);
else
eina_hash_modify(desktops_by_category, category, list);
}
}
static void
efreet_util_desktops_by_category_remove(Efreet_Desktop *desktop)
{
Eina_List *l;
const char *category;
if (!desktop->categories) return;
EINA_LIST_FOREACH(desktop->categories, l, category)
{
Eina_List *list;
list = eina_hash_find(desktops_by_category, category);
if (!list) continue;
if (eina_list_data_find(list, desktop))
list = eina_list_remove(list, desktop);
if (!list)
eina_hash_del(desktops_by_category, category, list);
else
eina_hash_modify(desktops_by_category, category, list);
}
}
static void
efreet_util_desktop_free(Efreet_Util_Desktop *ud)
{
if (!ud) return;
efreet_desktop_free(ud->desktop);
free(ud);
}
static void
efreet_event_desktop_change_free(void *data __UNUSED__, void *ev)
{
Efreet_Event_Desktop_Change *event;
event = ev;
if (event->current) efreet_desktop_free(event->current);
if (event->previous) efreet_desktop_free(event->previous);
free(event);
}