1 #include "e_mod_main.h"
7 static const char *home_dir = NULL;
8 static int home_dir_len;
9 static char dir_buf[1024];
10 static char thumb_buf[4096];
13 evry_util_file_detail_set(Evry_Item_File *file)
18 if (EVRY_ITEM(file)->detail)
23 home_dir = e_user_homedir_get();
24 home_dir_len = strlen(home_dir);
27 dir = ecore_file_dir_get(file->path);
28 if (!dir || !home_dir) return;
30 if (!strncmp(dir, home_dir, home_dir_len))
32 tmp = dir + home_dir_len;
35 snprintf(dir_buf, sizeof(dir_buf), "~%s", tmp);
37 snprintf(dir_buf, sizeof(dir_buf), "~%s/", tmp);
39 EVRY_ITEM(file)->detail = eina_stringshare_add(dir_buf);
43 if (!strncmp(dir, "//", 2))
44 EVRY_ITEM(file)->detail = eina_stringshare_add(dir + 1);
46 EVRY_ITEM(file)->detail = eina_stringshare_add(dir);
53 evry_fuzzy_match(const char *str, const char *match)
55 const char *p, *m, *next;
58 unsigned int last = 0;
59 unsigned int offset = 0;
61 unsigned char first = 0;
62 /* ignore punctuation */
67 unsigned int m_num = 0;
68 unsigned int m_cnt = 0;
69 unsigned int m_min[MAX_WORDS];
70 unsigned int m_len = 0;
72 if (!match || !str || !match[0] || !str[0])
75 /* remove white spaces at the beginning */
76 for (; (*match != 0) && isspace(*match); match++);
77 for (; (*str != 0) && isspace(*str); str++);
79 /* count words in match */
80 for (m = match; (*m != 0) && (m_num < MAX_WORDS);)
82 for (; (*m != 0) && !isspace(*m); m++);
83 for (; (*m != 0) && isspace(*m); m++);
84 m_min[m_num++] = MAX_FUZZ;
86 for (m = match; ip && (*m != 0); m++)
87 if (ip && ispunct(*m)) ip = 0;
89 m_len = strlen(match);
91 /* with less than 3 chars match must be a prefix */
92 if (m_len < 3) m_len = 0;
97 while((m_cnt < m_num) && (*next != 0))
100 if (m_cnt == 0) m = match;
102 /* end of matching */
111 /* match current word of string against current match */
112 for (p = next; *next != 0; p++)
114 /* new word of string begins */
115 if ((*p == 0) || isspace(*p) || (ip && ispunct(*p)))
117 if (m_cnt < m_num - 1)
119 /* test next match */
120 for (; (*m != 0) && !isspace(*m); m++);
121 for (; (*m != 0) && isspace(*m); m++);
127 /* go to next word */
128 for (; (*p != 0) && ((isspace(*p) || (ip && ispunct(*p)))); p++);
136 /* current char matches? */
137 if (tolower(*p) != tolower(*m))
146 if (offset <= m_len * 3)
150 if (min < MAX_FUZZ && offset <= m_len * 3)
152 /* first offset of match in word */
159 min += offset + (offset - last) * 5;
162 /* try next char of match */
163 if (*(++m) != 0 && !isspace(*m))
166 /* end of match: store min weight of match */
167 min += (cnt - m_cnt) > 0 ? (cnt - m_cnt) : 0;
169 if (min < m_min[m_cnt])
174 /* go to next match */
175 for (; (*m != 0) && !isspace(*m); m++);
178 if (m_cnt < m_num - 1)
180 /* test next match */
181 for (; (*m != 0) && isspace(*m); m++);
187 /* go to next word */
188 for (; (*p != 0) && !((isspace(*p) || (ip && ispunct(*p)))); p++);
189 for (; (*p != 0) && ((isspace(*p) || (ip && ispunct(*p)))); p++);
203 for (m_cnt = 0; m_cnt < m_num; m_cnt++)
217 if (strcmp(match, str))
225 _evry_fuzzy_match_sort_cb(const void *data1, const void *data2)
227 const Evry_Item *it1 = data1;
228 const Evry_Item *it2 = data2;
230 if (it1->priority - it2->priority)
231 return (it1->priority - it2->priority);
233 if (it1->fuzzy_match || it2->fuzzy_match)
235 if (it1->fuzzy_match && !it2->fuzzy_match)
238 if (!it1->fuzzy_match && it2->fuzzy_match)
241 if (it1->fuzzy_match - it2->fuzzy_match)
242 return (it1->fuzzy_match - it2->fuzzy_match);
249 evry_fuzzy_match_sort(Eina_List *items)
251 return eina_list_sort(items, -1, _evry_fuzzy_match_sort_cb);
255 evry_items_sort_func(const void *data1, const void *data2)
257 const Evry_Item *it1 = data1;
258 const Evry_Item *it2 = data2;
260 if ((it1->type == EVRY_TYPE_ACTION ||
261 it1->subtype == EVRY_TYPE_ACTION) &&
262 (it2->type == EVRY_TYPE_ACTION ||
263 it2->subtype == EVRY_TYPE_ACTION))
265 const Evry_Action *act1 = data1;
266 const Evry_Action *act2 = data2;
268 /* sort actions that match the specific type before
269 those matching general type */
270 if (act1->it1.item && act2->it1.item)
272 if ((act1->it1.type == act1->it1.item->type) &&
273 (act2->it1.type != act2->it1.item->type))
276 if ((act1->it1.type != act1->it1.item->type) &&
277 (act2->it1.type == act2->it1.item->type))
281 /* sort context specific actions before
283 if (act1->remember_context)
285 if (!act2->remember_context)
290 if (act2->remember_context)
295 /* if (it1->type == EVRY_TYPE_PLUGIN &&
296 * it2->type != EVRY_TYPE_PLUGIN)
298 * return (it1->usage > it2->usage ? -1 : 1);
300 * else if (it2->type == EVRY_TYPE_PLUGIN &&
301 * it1->type != EVRY_TYPE_PLUGIN)
303 * return (it1->usage > it2->usage ? -1 : 1);
306 /* sort items which match input or which
307 match much better first */
308 if (it1->fuzzy_match > 0 || it2->fuzzy_match > 0)
310 if (it2->fuzzy_match <= 0)
313 if (it1->fuzzy_match <= 0)
316 if (abs (it1->fuzzy_match - it2->fuzzy_match) > 5)
317 return (it1->fuzzy_match - it2->fuzzy_match);
320 /* sort recently/most frequently used items first */
321 if (it1->usage > 0.0 || it2->usage > 0.0)
323 return (it1->usage > it2->usage ? -1 : 1);
326 /* sort items which match input better first */
327 if (it1->fuzzy_match > 0 || it2->fuzzy_match > 0)
329 if (it1->fuzzy_match - it2->fuzzy_match)
330 return (it1->fuzzy_match - it2->fuzzy_match);
333 /* sort itemswith higher priority first */
334 if ((it1->plugin == it2->plugin) &&
335 (it1->priority - it2->priority))
336 return (it1->priority - it2->priority);
338 /* sort items with higher plugin priority first */
339 if (it1->type != EVRY_TYPE_ACTION &&
340 it2->type != EVRY_TYPE_ACTION)
342 int prio1 = it1->plugin->config->priority;
343 int prio2 = it2->plugin->config->priority;
346 return (prio1 - prio2);
349 return strcasecmp(it1->label, it2->label);
353 evry_util_plugin_items_add(Evry_Plugin *p, Eina_List *items, const char *input,
354 int match_detail, int set_usage)
360 EINA_LIST_FOREACH(items, l, it)
365 evry_history_item_usage_set(it, input, NULL);
369 p->items = eina_list_append(p->items, it);
373 it->fuzzy_match = evry_fuzzy_match(it->label, input);
377 match = evry_fuzzy_match(it->detail, input);
379 if (!(it->fuzzy_match) || (match && (match < it->fuzzy_match)))
380 it->fuzzy_match = match;
384 p->items = eina_list_append(p->items, it);
387 p->items = eina_list_sort(p->items, -1, evry_items_sort_func);
393 evry_icon_theme_get(const char *icon, Evas *e)
395 Evas_Object *obj = e_icon_add(e);
396 e_icon_preload_set(obj, 1);
397 e_icon_scale_size_set(obj, 128);
399 if (!e_util_icon_theme_set(obj, icon))
401 evas_object_del(obj);
409 _evry_icon_mime_theme_get(const char *mime, Evas *e)
411 Evas_Object *o = NULL;
416 if (snprintf(buf, sizeof(buf), "e/icons/fileman/mime/%s", mime) >= (int)sizeof(buf))
419 file = e_theme_edje_file_get("base/theme/icons", buf);
422 o = edje_object_add(e);
424 if (!edje_object_file_set(o, file, buf))
436 evry_icon_mime_get(const char *mime, Evas *e)
438 Evas_Object *o = NULL;
441 if (!e_config->icon_theme_overrides)
442 o = _evry_icon_mime_theme_get(mime, e);
446 icon = efreet_mime_type_icon_get(mime, e_config->icon_theme, 128);
448 o = e_util_icon_add(icon, e);
451 return _evry_icon_mime_theme_get(mime, e);
455 _file_icon_get(Evry_Item *it, Evas *e)
457 Evas_Object *o = NULL;
462 if (it->icon[0] == '/')
465 e_icon_preload_set(o, 1);
467 if (!e_icon_file_set(o, it->icon))
475 if (!(o) && (!it->icon) && file->mime &&
476 (/*(!strncmp(file->mime, "image/", 6)) || */
477 (!strncmp(file->mime, "video/", 6)) ||
478 (!strncmp(file->mime, "application/pdf", 15))) &&
479 (evry_file_url_get(file)))
481 char *sum = evry_util_md5_sum(file->url);
483 snprintf(thumb_buf, sizeof(thumb_buf),
484 "%s/.thumbnails/normal/%s.png",
485 e_user_homedir_get(), sum);
488 if (ecore_file_exists(thumb_buf))
489 it->icon = eina_stringshare_add(thumb_buf);
491 it->icon = eina_stringshare_add("");
494 if (!(o) &&it->browseable)
495 o = evry_icon_theme_get("folder", e);
497 if (!(o) && file->mime)
498 o = evry_icon_mime_get(file->mime, e);
501 o = evry_icon_mime_get("unknown", e);
507 evry_util_icon_get(Evry_Item *it, Evas *e)
509 Evas_Object *o = NULL;
511 if (!o && it->icon_get)
512 o = it->icon_get(it, e);
515 if (CHECK_TYPE(it, EVRY_TYPE_FILE))
516 o = _file_icon_get(it, e);
519 if (!o && it->icon && it->icon[0] == '/')
522 e_icon_preload_set(o, 1);
524 if (!e_icon_file_set(o, it->icon))
532 o = evry_icon_theme_get(it->icon, e);
538 evry_util_exec_app(const Evry_Item *it_app, const Evry_Item *it_file)
541 Eina_List *files = NULL;
545 if (!it_app) return 0;
546 GET_APP(app, it_app);
547 GET_FILE(file, it_file);
549 zone = e_util_zone_current_get(e_manager_current_get());
553 if (file && evry_file_path_get(file))
559 /* when the file is no a directory and the app
560 opens folders, pass only the dir */
561 if (!IS_BROWSEABLE(file))
563 EINA_LIST_FOREACH(app->desktop->mime_types, l, mime)
568 if (!strcmp(mime, "x-directory/normal"))
571 if (file->mime && !strcmp(mime, file->mime))
581 tmp = ecore_file_dir_get(file->path);
582 files = eina_list_append(files, tmp);
586 files = eina_list_append(files, file->path);
589 e_exec(zone, app->desktop, NULL, files, NULL);
591 if (file && file->mime && !open_folder)
592 e_exehist_mime_desktop_add(file->mime, app->desktop);
595 eina_list_free(files);
601 files = eina_list_append(files, app->file);
602 e_exec(zone, app->desktop, NULL, files, NULL);
603 eina_list_free(files);
607 e_exec(zone, app->desktop, NULL, NULL, NULL);
612 if (file && evry_file_path_get(file))
615 len = strlen(app->file) + strlen(file->path) + 4;
617 snprintf(exe, len, "%s \'%s\'", app->file, file->path);
618 e_exec(zone, NULL, exe, NULL, NULL);
623 exe = (char *) app->file;
624 e_exec(zone, NULL, exe, NULL, NULL);
633 * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et
636 * Unescapes the given URL escaped string of given length. Returns a
637 * pointer to a malloced string with length given in *olen.
638 * If length == 0, the length is assumed to be strlen(string).
639 * If olen == NULL, no output length is stored.
641 #define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x)))
644 evry_util_url_unescape(const char *string, int length)
646 int alloc = (length?length:(int)strlen(string))+1;
647 char *ns = malloc(alloc);
658 if(('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2]))
660 /* this is two hexadecimal digits following a '%' */
663 hexstr[0] = string[1];
664 hexstr[1] = string[2];
667 hex = strtoul(hexstr, &ptr, 16);
668 in = (unsigned char)(hex & (unsigned long) 0xFF);
669 // in = ultouc(hex); /* this long is never bigger than 255 anyway */
678 ns[strindex]=0; /* terminate it */
686 _isalnum(unsigned char in)
690 case '0': case '1': case '2': case '3': case '4':
691 case '5': case '6': case '7': case '8': case '9':
692 case 'a': case 'b': case 'c': case 'd': case 'e':
693 case 'f': case 'g': case 'h': case 'i': case 'j':
694 case 'k': case 'l': case 'm': case 'n': case 'o':
695 case 'p': case 'q': case 'r': case 's': case 't':
696 case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
697 case 'A': case 'B': case 'C': case 'D': case 'E':
698 case 'F': case 'G': case 'H': case 'I': case 'J':
699 case 'K': case 'L': case 'M': case 'N': case 'O':
700 case 'P': case 'Q': case 'R': case 'S': case 'T':
701 case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
710 evry_util_url_escape(const char *string, int inlength)
712 size_t alloc = (inlength?(size_t)inlength:strlen(string))+1;
714 char *testing_ptr = NULL;
715 unsigned char in; /* we need to treat the characters unsigned */
716 size_t newlen = alloc;
736 newlen += 2; /* the size grows with two, since this'll become a %XX */
740 testing_ptr = realloc(ns, alloc);
752 snprintf(&ns[strindex], 4, "%%%02X", in);
758 ns[strindex]=0; /* terminate it */
763 evry_file_path_get(Evry_Item_File *file)
774 if (!strncmp(file->url, "file://", 7))
778 if (!(path = evry_util_url_unescape(tmp, 0)))
781 file->path = eina_stringshare_add(path);
789 evry_file_url_get(Evry_Item_File *file)
791 char dest[PATH_MAX * 3 + 7];
801 memset(dest, 0, PATH_MAX * 3 + 7);
803 snprintf(dest, 8, "file://");
805 /* Most app doesn't handle the hostname in the uri so it's put to NULL */
806 for (i = 7, p = file->path; *p != '\0'; p++, i++)
808 if (isalnum(*p) || strchr("/$-_.+!*'()", *p))
812 snprintf(&(dest[i]), 4, "%%%02X", (unsigned char)*p);
817 file->url = eina_stringshare_add(dest);
823 _cb_free_item_changed(void *data __UNUSED__, void *event)
825 Evry_Event_Item_Changed *ev = event;
827 evry_item_free(ev->item);
832 evry_item_changed(Evry_Item *it, int icon, int selected)
834 Evry_Event_Item_Changed *ev;
835 ev = E_NEW(Evry_Event_Item_Changed, 1);
837 ev->changed_selection = selected;
838 ev->changed_icon = icon;
840 ecore_event_add(_evry_events[EVRY_EVENT_ITEM_CHANGED], ev, _cb_free_item_changed, NULL);
843 static char thumb_buf[4096];
844 static const char hex[] = "0123456789abcdef";
847 evry_util_md5_sum(const char *str)
850 unsigned char hash[MD5_HASHBYTES];
852 char md5out[(2 * MD5_HASHBYTES) + 1];
854 MD5Update (&ctx, (unsigned char const*)str,
855 (unsigned)strlen (str));
856 MD5Final (hash, &ctx);
858 for (n = 0; n < MD5_HASHBYTES; n++)
860 md5out[2 * n] = hex[hash[n] >> 4];
861 md5out[2 * n + 1] = hex[hash[n] & 0x0f];
863 md5out[2 * n] = '\0';
865 return strdup(md5out);