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);
254 static int _sort_flags = 0;
257 _evry_items_sort_func(const void *data1, const void *data2)
259 const Evry_Item *it1 = data1;
260 const Evry_Item *it2 = data2;
262 /* if (!((!_sort_flags) &&
263 * (it1->type == EVRY_TYPE_ACTION) &&
264 * (it2->type == EVRY_TYPE_ACTION)))
266 /* only sort actions when there is input otherwise show default order */
268 if (((it1->type == EVRY_TYPE_ACTION) || (it1->subtype == EVRY_TYPE_ACTION)) &&
269 ((it2->type == EVRY_TYPE_ACTION) || (it2->subtype == EVRY_TYPE_ACTION)))
271 const Evry_Action *act1 = data1;
272 const Evry_Action *act2 = data2;
274 /* sort actions that match the specific type before
275 those matching general type */
276 if (act1->it1.item && act2->it1.item)
278 if ((act1->it1.type == act1->it1.item->type) &&
279 (act2->it1.type != act2->it1.item->type))
282 if ((act1->it1.type != act1->it1.item->type) &&
283 (act2->it1.type == act2->it1.item->type))
287 /* sort context specific actions before
289 if (act1->remember_context)
291 if (!act2->remember_context)
296 if (act2->remember_context)
304 /* when there is no input sort items with higher
305 * plugin priority first */
306 if (it1->type != EVRY_TYPE_ACTION &&
307 it2->type != EVRY_TYPE_ACTION)
309 int prio1 = it1->plugin->config->priority;
310 int prio2 = it2->plugin->config->priority;
313 return prio1 - prio2;
317 /* sort items which match input or which
318 match much better first */
319 if (it1->fuzzy_match > 0 || it2->fuzzy_match > 0)
321 if (it2->fuzzy_match <= 0)
324 if (it1->fuzzy_match <= 0)
327 if (abs (it1->fuzzy_match - it2->fuzzy_match) > 5)
328 return it1->fuzzy_match - it2->fuzzy_match;
331 /* sort recently/most frequently used items first */
332 if (it1->usage > 0.0 || it2->usage > 0.0)
334 return it1->usage > it2->usage ? -1 : 1;
337 /* sort items which match input better first */
338 if (it1->fuzzy_match > 0 || it2->fuzzy_match > 0)
340 if (it1->fuzzy_match - it2->fuzzy_match)
341 return it1->fuzzy_match - it2->fuzzy_match;
344 /* sort itemswith higher priority first */
345 if ((it1->plugin == it2->plugin) &&
346 (it1->priority - it2->priority))
347 return it1->priority - it2->priority;
349 /* sort items with higher plugin priority first */
350 if (it1->type != EVRY_TYPE_ACTION &&
351 it2->type != EVRY_TYPE_ACTION)
353 int prio1 = it1->plugin->config->priority;
354 int prio2 = it2->plugin->config->priority;
357 return prio1 - prio2;
360 return strcasecmp(it1->label, it2->label);
364 evry_util_items_sort(Eina_List **items, int flags)
367 *items = eina_list_sort(*items, -1, _evry_items_sort_func);
372 evry_util_plugin_items_add(Evry_Plugin *p, Eina_List *items, const char *input,
373 int match_detail, int set_usage)
379 EINA_LIST_FOREACH (items, l, it)
384 evry_history_item_usage_set(it, input, NULL);
388 p->items = eina_list_append(p->items, it);
392 it->fuzzy_match = evry_fuzzy_match(it->label, input);
396 match = evry_fuzzy_match(it->detail, input);
398 if (!(it->fuzzy_match) || (match && (match < it->fuzzy_match)))
399 it->fuzzy_match = match;
403 p->items = eina_list_append(p->items, it);
406 p->items = eina_list_sort(p->items, -1, _evry_items_sort_func);
412 evry_icon_theme_get(const char *icon, Evas *e)
414 Evas_Object *o = NULL;
420 e_icon_scale_size_set(o, 128);
421 e_icon_preload_set(o, 1);
425 if (!e_icon_file_set(o, icon))
431 else if (!e_util_icon_theme_set(o, icon))
441 evry_util_icon_get(Evry_Item *it, Evas *e)
443 Evas_Object *o = NULL;
447 o = it->icon_get(it, e);
451 if ((it->icon) && (it->icon[0] == '/'))
453 o = evry_icon_theme_get(it->icon, e);
457 if (CHECK_TYPE(it, EVRY_TYPE_FILE))
466 o = evry_icon_theme_get("folder", e);
470 if ((!it->icon) && (file->mime) &&
471 ( /*(!strncmp(file->mime, "image/", 6)) || */
472 (!strncmp(file->mime, "video/", 6)) ||
473 (!strncmp(file->mime, "application/pdf", 15))) &&
474 (evry_file_url_get(file)))
476 sum = evry_util_md5_sum(file->url);
478 snprintf(thumb_buf, sizeof(thumb_buf),
479 "%s/.thumbnails/normal/%s.png",
480 e_user_homedir_get(), sum);
483 if ((o = evry_icon_theme_get(thumb_buf, e)))
485 it->icon = eina_stringshare_add(thumb_buf);
490 if ((!it->icon) && (file->mime))
492 icon = efreet_mime_type_icon_get(file->mime, e_config->icon_theme, 128);
493 /* XXX can do _ref ?*/
494 if ((o = evry_icon_theme_get(icon, e)))
496 /* it->icon = eina_stringshare_add(icon); */
501 if ((icon = efreet_mime_type_icon_get("unknown", e_config->icon_theme, 128)))
502 it->icon = eina_stringshare_add(icon);
504 it->icon = eina_stringshare_add("");
507 if (CHECK_TYPE(it, EVRY_TYPE_APP))
511 o = e_util_desktop_icon_add(app->desktop, 128, e);
514 o = evry_icon_theme_get("system-run", e);
520 o = evry_icon_theme_get(it->icon, e);
526 o = evry_icon_theme_get("folder", e);
530 o = evry_icon_theme_get("unknown", e);
535 evry_util_exec_app(const Evry_Item *it_app, const Evry_Item *it_file)
538 Eina_List *files = NULL;
542 if (!it_app) return 0;
543 GET_APP(app, it_app);
544 GET_FILE(file, it_file);
546 zone = e_util_zone_current_get(e_manager_current_get());
550 if (file && evry_file_path_get(file))
556 /* when the file is no a directory and the app
557 opens folders, pass only the dir */
558 if (!IS_BROWSEABLE(file))
560 EINA_LIST_FOREACH (app->desktop->mime_types, l, mime)
565 if (!strcmp(mime, "x-directory/normal"))
568 if (file->mime && !strcmp(mime, file->mime))
578 tmp = ecore_file_dir_get(file->path);
579 files = eina_list_append(files, tmp);
583 files = eina_list_append(files, file->path);
586 e_exec(zone, app->desktop, NULL, files, NULL);
588 if (file && file->mime && !open_folder)
589 e_exehist_mime_desktop_add(file->mime, app->desktop);
592 eina_list_free(files);
598 files = eina_list_append(files, app->file);
599 e_exec(zone, app->desktop, NULL, files, NULL);
600 eina_list_free(files);
604 e_exec(zone, app->desktop, NULL, NULL, NULL);
609 if (file && evry_file_path_get(file))
612 len = strlen(app->file) + strlen(file->path) + 4;
614 snprintf(exe, len, "%s \'%s\'", app->file, file->path);
615 e_exec(zone, NULL, exe, NULL, NULL);
620 exe = (char *)app->file;
621 e_exec(zone, NULL, exe, NULL, NULL);
630 * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et
633 * Unescapes the given URL escaped string of given length. Returns a
634 * pointer to a malloced string with length given in *olen.
635 * If length == 0, the length is assumed to be strlen(string).
636 * If olen == NULL, no output length is stored.
638 #define ISXDIGIT(x) (isxdigit((int)((unsigned char)x)))
641 evry_util_url_unescape(const char *string, int length)
643 int alloc = (length ? length : (int)strlen(string)) + 1;
644 char *ns = malloc(alloc);
655 if (('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2]))
657 /* this is two hexadecimal digits following a '%' */
660 hexstr[0] = string[1];
661 hexstr[1] = string[2];
664 hex = strtoul(hexstr, &ptr, 16);
665 in = (unsigned char)(hex & (unsigned long)0xFF);
666 // in = ultouc(hex); /* this long is never bigger than 255 anyway */
675 ns[strindex] = 0; /* terminate it */
683 _isalnum(unsigned char in)
758 evry_util_url_escape(const char *string, int inlength)
760 size_t alloc = (inlength ? (size_t)inlength : strlen(string)) + 1;
762 char *testing_ptr = NULL;
763 unsigned char in; /* we need to treat the characters unsigned */
764 size_t newlen = alloc;
784 newlen += 2; /* the size grows with two, since this'll become a %XX */
788 testing_ptr = realloc(ns, alloc);
800 snprintf(&ns[strindex], 4, "%%%02X", in);
806 ns[strindex] = 0; /* terminate it */
811 evry_file_path_get(Evry_Item_File *file)
822 if (!strncmp(file->url, "file://", 7))
826 if (!(path = evry_util_url_unescape(tmp, 0)))
829 file->path = eina_stringshare_add(path);
837 evry_file_url_get(Evry_Item_File *file)
839 char dest[PATH_MAX * 3 + 7];
849 memset(dest, 0, PATH_MAX * 3 + 7);
851 snprintf(dest, 8, "file://");
853 /* Most app doesn't handle the hostname in the uri so it's put to NULL */
854 for (i = 7, p = file->path; *p != '\0'; p++, i++)
856 if (isalnum(*p) || strchr("/$-_.+!*'()", *p))
860 snprintf(&(dest[i]), 4, "%%%02X", (unsigned char)*p);
865 file->url = eina_stringshare_add(dest);
871 _cb_free_item_changed(void *data __UNUSED__, void *event)
873 Evry_Event_Item_Changed *ev = event;
875 evry_item_free(ev->item);
880 evry_item_changed(Evry_Item *it, int icon, int selected)
882 Evry_Event_Item_Changed *ev;
883 ev = E_NEW(Evry_Event_Item_Changed, 1);
885 ev->changed_selection = selected;
886 ev->changed_icon = icon;
888 ecore_event_add(_evry_events[EVRY_EVENT_ITEM_CHANGED], ev, _cb_free_item_changed, NULL);
891 static char thumb_buf[4096];
892 static const char hex[] = "0123456789abcdef";
895 evry_util_md5_sum(const char *str)
898 unsigned char hash[MD5_HASHBYTES];
900 char md5out[(2 * MD5_HASHBYTES) + 1];
902 MD5Update (&ctx, (unsigned char const *)str,
903 (unsigned)strlen (str));
904 MD5Final (hash, &ctx);
906 for (n = 0; n < MD5_HASHBYTES; n++)
908 md5out[2 * n] = hex[hash[n] >> 4];
909 md5out[2 * n + 1] = hex[hash[n] & 0x0f];
911 md5out[2 * n] = '\0';
913 return strdup(md5out);