enlightenment/src/modules/everything/evry.c

2636 lines
59 KiB
C

#include "e.h"
#include "e_mod_main.h"
/* TODO */
/* - animations
* - mouse handlers
* - show item descriptions
* - keybinding configuration
* - shortcuts for plugins
*/
#define INPUTLEN 40
#define MATCH_LAG 0.33
#define MAX_FUZZ 150
typedef struct _Evry_State Evry_State;
typedef struct _Evry_Window Evry_Window;
typedef struct _Evry_List_Window Evry_List_Window;
typedef struct _Evry_Selector Evry_Selector;
struct _Evry_State
{
char *input;
/* all available plugins for current state */
Eina_List *plugins;
/* currently active plugins, i.e. those that provide items */
Eina_List *cur_plugins;
/* active plugin */
Evry_Plugin *plugin;
/* selected item */
Evry_Item *sel_item;
/* Eina_List *sel_items; */
/* this is for the case when the current plugin was not selected
manually and a higher priority (async) plugin retrieves
candidates, the higher priority plugin is made current */
Eina_Bool plugin_auto_selected;
Eina_Bool item_auto_selected;
Eina_List *items;
};
/* */
struct _Evry_Selector
{
Evas_Object *o_main;
Evas_Object *o_icon;
/* current state */
Evry_State *state;
/* stack of states (for browseable plugins) */
Eina_List *states;
/* provides collection of items from other plugins */
Evry_Plugin *aggregator;
/* */
Eina_List *actions;
/* all plugins that belong to this selector*/
Eina_List *plugins;
};
struct _Evry_Window
{
E_Popup *popup;
Evas_Object *o_main;
Eina_Bool request_selection;
/* E_Popup *input_win; */
};
struct _Evry_List_Window
{
E_Popup *popup;
Evas_Object *o_main;
Evas_Object *o_list;
Evas_Object *o_tabs;
int ev_last_is_mouse;
Evry_Item *item_mouseover;
Ecore_Animator *scroll_animator;
Ecore_Timer *scroll_timer;
double scroll_align_to;
double scroll_align;
Ecore_Idler *item_idler;
Eina_Bool visible;
};
static void _evry_matches_update(Evry_Selector *sel);
static void _evry_plugin_action(Evry_Selector *sel, int finished);
static void _evry_backspace(Evry_State *s);
static void _evry_update(Evry_State *s, int fetch);
static void _evry_clear(Evry_State *s);
static int _evry_update_timer(void *data);
static Evry_State *_evry_state_new(Evry_Selector *sel, Eina_List *plugins);
static void _evry_state_pop(Evry_Selector *sel);
static void _evry_select_plugin(Evry_State *s, Evry_Plugin *p);
static void _evry_update_text_label(Evry_State *s);
static void _evry_browse_item(Evry_Selector *sel);
static void _evry_browse_back(Evry_Selector *sel);
static void _evry_selectors_switch(void);
static void _evry_plugin_list_insert(Evry_State *s, Evry_Plugin *p);
static Evry_Window *_evry_window_new(E_Zone *zone);
static void _evry_window_free(Evry_Window *win);
static Evry_Selector *_evry_selector_new(int type);
static void _evry_selector_free(Evry_Selector *sel);
static void _evry_selector_activate(Evry_Selector *sel);
static void _evry_selector_update(Evry_Selector *sel);
static void _evry_selector_icon_set(Evry_Selector *sel);
static int _evry_selector_subjects_get(void);
static int _evry_selector_actions_get(Evry_Item *it);
static int _evry_selector_objects_get(const char *type);
static Evry_List_Window *_evry_list_win_new(E_Zone *zone);
static void _evry_list_win_free(Evry_List_Window *win);
static void _evry_list_win_show(void);
static void _evry_list_win_hide(void);
static void _evry_list_clear_list(Evry_State *s);
static void _evry_list_update(Evry_State *s);
static void _evry_list_show_items(Evry_State *s, Evry_Plugin *plugin);
static void _evry_list_item_next(Evry_State *s);
static void _evry_list_item_prev(Evry_State *s);
static void _evry_list_item_first(Evry_State *s);
static void _evry_list_item_last(Evry_State *s);
static void _evry_list_plugin_next(Evry_State *s);
static void _evry_list_plugin_prev(Evry_State *s);
static void _evry_list_plugin_next_by_name(Evry_State *s, const char *key);
static void _evry_list_scroll_to(Evry_State *s, Evry_Item *it);
static void _evry_list_item_desel(Evry_State *s, Evry_Item *it);
static void _evry_list_item_sel(Evry_State *s, Evry_Item *it);
static void _evry_list_tab_scroll_to(Evry_State *s, Evry_Plugin *p);
static void _evry_list_tab_show(Evry_State *s, Evry_Plugin *p);
static void _evry_list_tabs_update(Evry_State *s);
static int _evry_list_animator(void *data);
static int _evry_list_scroll_timer(void *data);
static int _evry_list_item_idler(void *data);
static int _evry_plug_actions_init(void);
static void _evry_plug_actions_free(void);
static int _evry_plug_actions_begin(Evry_Plugin *p, const Evry_Item *it);
static int _evry_plug_actions_fetch(Evry_Plugin *p, const char *input);
static void _evry_plug_actions_cleanup(Evry_Plugin *p);
static Evas_Object *_evry_plug_actions_item_icon_get(Evry_Plugin *p, const Evry_Item *it, Evas *e);
static Evry_Plugin *_evry_plug_aggregator_new(void);
static void _evry_plug_aggregator_free(Evry_Plugin *p);
static int _evry_plug_aggregator_fetch(Evry_Plugin *p, const char *input);
static int _evry_plug_aggregator_action(Evry_Plugin *p, const Evry_Item *item, const char *input);
static void _evry_plug_aggregator_cleanup(Evry_Plugin *p);
static Evas_Object *_evry_plug_aggregator_item_icon_get(Evry_Plugin *p, const Evry_Item *it, Evas *e);
static int _evry_cb_key_down(void *data, int type, void *event);
static int _evry_cb_selection_notify(void *data, int type, void *event);
/* static int _evry_cb_mouse_down(void *data, int type, void *event);
* static int _evry_cb_mouse_up(void *data, int type, void *event);
* static int _evry_cb_mouse_move(void *data, int type, void *event);
* static int _evry_cb_mouse_wheel(void *data, int type, void *event);
* static void _evry_cb_item_mouse_in(void *data, Evas *evas, Evas_Object *obj, void *event_info);
* static void _evry_cb_item_mouse_out(void *data, Evas *evas, Evas_Object *obj, void *event_info); */
/* local subsystem globals */
static Evry_Window *win = NULL;
static Evry_List_Window *list = NULL;
static Ecore_X_Window input_window = 0;
static Eina_List *handlers = NULL;
static Ecore_Timer *update_timer = NULL;
static Evry_Selector *selectors[3];
static Evry_Selector *selector = NULL;
static Evry_Plugin *action_selector = NULL;
/* externally accessible functions */
int
evry_init(void)
{
_evry_plug_actions_init();
return 1;
}
int
evry_shutdown(void)
{
evry_hide();
_evry_plug_actions_free();
return 1;
}
int
evry_show(E_Zone *zone)
{
if (win) return 0;
E_OBJECT_CHECK_RETURN(zone, 0);
E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, 0);
input_window = ecore_x_window_input_new(zone->container->win, zone->x,
zone->y, zone->w, zone->h);
ecore_x_window_show(input_window);
if (!e_grabinput_get(input_window, 1, input_window))
goto error;
win = _evry_window_new(zone);
if (!win) goto error;
list = _evry_list_win_new(zone);
if (!list) goto error;
list->visible = EINA_FALSE;
/* TODO check NULL */
selectors[0] = _evry_selector_new(type_subject);
selectors[1] = _evry_selector_new(type_action);
selectors[2] = _evry_selector_new(type_object);
_evry_selector_subjects_get();
_evry_selector_activate(selectors[0]);
_evry_selector_update(selector);
e_popup_layer_set(list->popup, 255);
e_popup_layer_set(win->popup, 255);
e_popup_show(win->popup);
e_popup_show(list->popup);
if (list->visible)
{
e_popup_show(list->popup);
_evry_list_update(selector->state);
}
e_box_align_set(list->o_tabs, 0.0, 0.5);
handlers = eina_list_append
(handlers, ecore_event_handler_add
(ECORE_EVENT_KEY_DOWN, _evry_cb_key_down, NULL));
handlers = eina_list_append
(handlers, ecore_event_handler_add
(ECORE_X_EVENT_SELECTION_NOTIFY,
_evry_cb_selection_notify, win));
/* handlers = eina_list_append
* (handlers, ecore_event_handler_add
* (ECORE_EVENT_MOUSE_BUTTON_DOWN, _evry_cb_mouse_down, NULL));
* handlers = eina_list_append
* (handlers, ecore_event_handler_add
* (ECORE_EVENT_MOUSE_BUTTON_UP, _evry_cb_mouse_up, NULL));
* handlers = eina_list_append
* (handlers, ecore_event_handler_add
* (ECORE_EVENT_MOUSE_MOVE, _evry_cb_mouse_move, NULL));
* handlers = eina_list_append
* (handlers, ecore_event_handler_add
* (ECORE_EVENT_MOUSE_WHEEL, _evry_cb_mouse_wheel, NULL)); */
return 1;
error:
if (win && selectors[0])
_evry_selector_free(selectors[0]);
if (win && selectors[1])
_evry_selector_free(selectors[1]);
if (win && selectors[2])
_evry_selector_free(selectors[2]);
if (win)
_evry_window_free(win);
if (list)
_evry_list_win_free(list);
win = NULL;
list = NULL;
ecore_x_window_free(input_window);
input_window = 0;
return 0;
}
void
evry_hide(void)
{
Ecore_Event *ev;
if (!win) return;
_evry_list_clear_list(selector->state);
if (update_timer)
ecore_timer_del(update_timer);
update_timer = NULL;
list->visible = EINA_FALSE;
_evry_selector_free(selectors[0]);
_evry_selector_free(selectors[1]);
_evry_selector_free(selectors[2]);
selectors[0] = NULL;
selectors[1] = NULL;
selectors[2] = NULL;
selector = NULL;
_evry_list_win_free(list);
list = NULL;
_evry_window_free(win);
win = NULL;
EINA_LIST_FREE(handlers, ev)
ecore_event_handler_del(ev);
ecore_x_window_free(input_window);
e_grabinput_release(input_window, input_window);
input_window = 0;
}
void
evry_clear_input(void)
{
Evry_State *s = selector->state;
if (s->input[0] != 0)
{
s->input[0] = 0;
}
}
/* static int item_cnt = 0; */
Evry_Item *
evry_item_new(Evry_Plugin *p, const char *label, void (*cb_free) (Evry_Item *item))
{
Evry_Item *it;
it = E_NEW(Evry_Item, 1);
if (!it) return NULL;
it->plugin = p;
if (label) it->label = eina_stringshare_add(label);
it->ref = 1;
/* item_cnt++; */
return it;
}
void
evry_item_free(Evry_Item *it)
{
if (!it) return;
it->ref--;
if (it->ref > 0) return;
/* printf("%d, %d\t 0x%x 0x%x 0x%x free: %s\n",
* it->ref, item_cnt - 1,
* it->label, it->uri, it->mime,
* it->label); */
/* item_cnt--; */
if (it->cb_free) it->cb_free(it);
if (it->label) eina_stringshare_del(it->label);
if (it->uri) eina_stringshare_del(it->uri);
if (it->mime) eina_stringshare_del(it->mime);
if (it->o_bg) evas_object_del(it->o_bg);
if (it->o_icon) evas_object_del(it->o_icon);
E_FREE(it);
}
void
_evry_item_ref(Evry_Item *it)
{
it->ref++;
}
void
evry_plugin_async_update(Evry_Plugin *p, int action)
{
Evry_State *s;
Evry_Plugin *agg;
if (!win) return;
s = selector->state;
agg = selector->aggregator;
/* received data from a plugin of the current selector ? */
if (!s || !eina_list_data_find(s->plugins, p)) return;
if (action == EVRY_ASYNC_UPDATE_ADD)
{
if (!p->items)
{
/* remove plugin */
if (!eina_list_data_find(s->cur_plugins, p)) return;
s->cur_plugins = eina_list_remove(s->cur_plugins, p);
if (s->plugin == p)
_evry_select_plugin(s, NULL);
}
else
{
/* add plugin to current plugins*/
_evry_plugin_list_insert(s, p);
if (!s->plugin || !eina_list_data_find_list(s->cur_plugins, s->plugin))
_evry_select_plugin(s, NULL);
}
/* update aggregator */
if (eina_list_count(s->cur_plugins) > 1)
{
agg->fetch(agg, s->input);
/* add aggregator */
if (!(s->cur_plugins->data == agg))
{
s->cur_plugins = eina_list_prepend(s->cur_plugins, agg);
if (s->plugin_auto_selected)
_evry_select_plugin(s, agg);
}
}
/* plugin is visible */
if ((s->plugin == p) || (s->plugin == agg))
{
_evry_selector_update(selector);
p = s->plugin;
_evry_list_clear_list(s);
_evry_list_show_items(s, p);
_evry_list_scroll_to(s, s->sel_item);
}
/* plugin box was updated: realign */
if (s->plugin)
{
_evry_list_tabs_update(s);
_evry_list_tab_scroll_to(s, s->plugin);
}
}
}
int
evry_fuzzy_match(const char *str, const char *match)
{
const char *p, *m, *next;
char mc, pc;
int sum = 0;
unsigned int last = 0;
unsigned int offset = 0;
unsigned int min = 0;
unsigned char first = 0;
/* words in match */
unsigned int words = 1;
unsigned int word = 0;
unsigned int word_min[64];
if (!match || !str) return 0;
/* remove white spaces at the beginning */
for (; (*match != 0) && isspace(*match); match++);
for (; (*str != 0) && isspace(*str); str++);
/* count words in match */
word_min[0] = MAX_FUZZ;
for (m = match; *m != 0 && *(m+1) != 0; m++)
{
if (isspace(*m) && !isspace(*(m+1)))
{
word_min[words++] = MAX_FUZZ;
}
}
next = str;
m = match;
for (word = 0; word < words && *next != 0; )
{
/* reset match */
if (word == 0) m = match;
/* end of matching */
if (*m == 0) break;
mc = tolower(*m);
offset = 0;
last = 0;
min = 1;
first = 0;
/* match current word of string against current match */
for (p = next; *next != 0; p++)
{
/* new word of string begins */
if (*p == 0 || isspace(*p))
{
if (word < words - 1)
{
/* test next match */
for (; (*m != 0) && !isspace(*m); m++);
for (; (*m != 0) && isspace(*m); m++);
word++;
break;
}
else
{
/* go to next word */
for (; (*p != 0) && isspace(*p); p++);
next = p;
word = 0;
break;
}
}
pc = tolower(*p);
/* current char matches? */
if (pc != mc)
{
offset++;
continue;
}
/* first offset of match in word */
if (!first)
{
offset *= 10;
last = offset;
first = 1;
}
min += offset + (offset - last) * 10;
last = offset;
/* try next char of match */
m++;
if (*m != 0 && !isspace(*m))
{
mc = tolower(*m);
continue;
}
/* end of match: store min weight of match */
if (min < word_min[word])
word_min[word] = min;
if (word < words - 1)
{
/* test next match */
for (; (*m != 0) && isspace(*m); m++);
word++;
break;
}
else if(*p != 0)
{
/* go to next word */
for (; (*p != 0) && !isspace(*p); p++);
for (; (*p != 0) && isspace(*p); p++);
next = p;
word = 0;
break;
}
else
{
next = p;
break;
}
}
}
for (word = 0; word < words; word++)
{
if (word_min[word] >= MAX_FUZZ)
{
sum = 0;
break;
}
sum += word_min[word];
}
/* if (sum)
* printf("min %d >> %s - %s\n", sum, match, str); */
return sum;
}
/* local subsystem functions */
static Evry_List_Window *
_evry_list_win_new(E_Zone *zone)
{
int x, y;
Evry_List_Window *list_win;
E_Popup *popup;
Evas_Object *o;
x = (zone->w / 2) - (win->popup->w / 3);
y = (zone->h / 2);
/* TODO get offsets from theme */
popup = e_popup_new(zone, x + 50, y - 4,
win->popup->w * 2/3 - 100,
evry_conf->height);
if (!popup) return NULL;
list_win = E_NEW(Evry_List_Window, 1);
if (!list_win)
{
e_object_del(E_OBJECT(popup));
return NULL;
}
list_win->popup = popup;
evas_event_freeze(popup->evas);
evas_event_feed_mouse_in(popup->evas, ecore_x_current_time_get(), NULL);
evas_event_feed_mouse_move(popup->evas, -1000000, -1000000, ecore_x_current_time_get(), NULL);
o = edje_object_add(popup->evas);
list_win->o_main = o;
e_theme_edje_object_set(o, "base/theme/everything",
"e/widgets/everything/list");
o = e_box_add(popup->evas);
list_win->o_list = o;
e_box_orientation_set(o, 0);
e_box_homogenous_set(o, 1);
edje_object_part_swallow(list_win->o_main, "e.swallow.list", o);
evas_object_show(o);
o = list_win->o_main;
evas_object_move(o, 0, 0);
evas_object_resize(o, list_win->popup->w, list_win->popup->h);
evas_object_show(o);
e_popup_edje_bg_object_set(popup, o);
o = e_box_add(popup->evas);
e_box_orientation_set(o, 1);
/* e_box_homogenous_set(o, 1); */
edje_object_part_swallow(list_win->o_main, "e.swallow.bar", o);
evas_object_show(o);
list_win->o_tabs = o;
evas_event_thaw(popup->evas);
return list_win;
}
static void
_evry_list_win_free(Evry_List_Window *list_win)
{
if (list_win->scroll_timer)
ecore_timer_del(list_win->scroll_timer);
if (list_win->scroll_animator)
ecore_animator_del(list_win->scroll_animator);
if (list_win->item_idler)
ecore_idler_del(list_win->item_idler);
e_popup_hide(list_win->popup);
evas_event_freeze(list_win->popup->evas);
evas_object_del(list_win->o_list);
evas_object_del(list_win->o_tabs);
evas_object_del(list_win->o_main);
/* evas_event_thaw(list_win->popup->evas); */
e_object_del(E_OBJECT(list_win->popup));
E_FREE(list_win);
}
static void
_evry_list_win_show(void)
{
if (list->visible) return;
list->visible = EINA_TRUE;
_evry_list_update(selector->state);
edje_object_signal_emit(list->o_main, "e,state,list_show", "e");
}
static void
_evry_list_win_hide(void)
{
Eina_List *l;
Evry_Plugin *p;
if (!list->visible) return;
list->visible = EINA_FALSE;
EINA_LIST_FOREACH(selector->plugins, l, p)
{
e_box_unpack(p->tab);
evas_object_del(p->tab);
p->tab = NULL;
}
_evry_list_clear_list(selector->state);
edje_object_signal_emit(list->o_main, "e,state,list_hide", "e");
/* e_popup_hide(list->popup); */
}
static Evry_Window *
_evry_window_new(E_Zone *zone)
{
int x, y, mw, mh;
Evry_Window *win;
E_Popup *popup;
Evas_Object *o;
popup = e_popup_new(zone, 100, 100, 1, 1);
if (!popup) return NULL;
win = E_NEW(Evry_Window, 1);
if (!win)
{
e_object_del(E_OBJECT(popup));
return NULL;
}
win->popup = popup;
o = edje_object_add(popup->evas);
win->o_main = o;
e_theme_edje_object_set(o, "base/theme/everything",
"e/widgets/everything/main");
edje_object_size_min_get(o, &mw, &mh);
x = (zone->w / 2) - (mw / 2);
y = (zone->h / 2) - mh;
e_popup_move_resize(popup, x, y, mw, mh);
o = win->o_main;
e_popup_edje_bg_object_set(win->popup, o);
evas_object_move(o, 0, 0);
evas_object_resize(o, mw, mh);
evas_object_show(o);
ecore_x_netwm_window_type_set(popup->evas_win, ECORE_X_WINDOW_TYPE_UTILITY);
return win;
}
static void
_evry_window_free(Evry_Window *win)
{
e_popup_hide(win->popup);
evas_event_freeze(win->popup->evas);
evas_object_del(win->o_main);
/* evas_event_thaw(win->popup->evas); */
e_object_del(E_OBJECT(win->popup));
E_FREE(win);
}
static Evry_Selector *
_evry_selector_new(int type)
{
Evry_Plugin *p;
Eina_List *l;
Evry_Selector *sel = E_NEW(Evry_Selector, 1);
Evas_Object *o = edje_object_add(win->popup->evas);
sel->o_main = o;
e_theme_edje_object_set(o, "base/theme/everything",
"e/widgets/everything/selector_item");
evas_object_show(o);
if (type == type_subject)
edje_object_part_swallow(win->o_main, "e.swallow.subject_selector", o);
else if (type == type_action)
edje_object_part_swallow(win->o_main, "e.swallow.action_selector", o);
else if (type == type_object)
edje_object_part_swallow(win->o_main, "e.swallow.object_selector", o);
p = _evry_plug_aggregator_new();
p->private = sel;
sel->plugins = eina_list_append(sel->plugins, p);
sel->aggregator = p;
EINA_LIST_FOREACH(evry_conf->plugins, l, p)
{
if (!p->config->enabled) continue;
if (p->type != type) continue;
sel->plugins = eina_list_append(sel->plugins, p);
}
if (type == type_action)
sel->plugins = eina_list_append(sel->plugins, action_selector);
return sel;
}
static void
_evry_selector_free(Evry_Selector *sel)
{
Evry_Plugin *p;
if (sel->o_icon)
evas_object_del(sel->o_icon);
evas_object_del(sel->o_main);
if (list->visible && (sel == selector))
_evry_list_clear_list(sel->state);
while (sel->states)
_evry_state_pop(sel);
EINA_LIST_FREE(sel->plugins, p)
{
if (p->tab) evas_object_del(p->tab);
p->tab = NULL;
}
_evry_plug_aggregator_free(sel->aggregator);
if (sel->plugins) eina_list_free(sel->plugins);
E_FREE(sel);
}
static void
_evry_selector_activate(Evry_Selector *sel)
{
if (selector)
{
Evry_Plugin *p;
Eina_List *l;
edje_object_signal_emit(selector->o_main, "e,state,unselected", "e");
edje_object_part_text_set(selector->o_main, "e.text.plugin", "");
EINA_LIST_FOREACH(selector->plugins, l, p)
{
e_box_unpack(p->tab);
evas_object_del(p->tab);
p->tab = NULL;
}
_evry_list_win_hide();
}
selector = sel;
edje_object_signal_emit(sel->o_main, "e,state,selected", "e");
if (sel->state)
{
_evry_update_text_label(sel->state);
if (sel->state->sel_item)
edje_object_part_text_set(sel->o_main, "e.text.plugin",
sel->state->sel_item->plugin->name);
if (list->visible && sel->state->plugin)
{
_evry_list_tabs_update(sel->state);
_evry_list_show_items(sel->state, sel->state->plugin);
}
}
}
static void
_evry_selector_icon_set(Evry_Selector *sel)
{
Evry_State *s = sel->state;
Evry_Item *it;
Evas_Object *o;
if (!edje_object_part_exists(sel->o_main, "e.swallow.icons")) return;
if (sel->o_icon)
{
evas_object_del(sel->o_icon);
sel->o_icon = NULL;
}
if (!s) return;
it = s->sel_item;
if (it && it->plugin && it->plugin->icon_get)
{
o = it->plugin->icon_get(it->plugin, it, win->popup->evas);
if (o)
{
edje_object_part_swallow(sel->o_main, "e.swallow.icons", o);
evas_object_show(o);
sel->o_icon = o;
}
}
else if (s->plugin && s->plugin->icon)
{
o = e_icon_add(win->popup->evas);
evry_icon_theme_set(o, s->plugin->icon);
edje_object_part_swallow(sel->o_main, "e.swallow.icons", o);
evas_object_show(o);
sel->o_icon = o;
}
}
static void
_evry_selector_update(Evry_Selector *sel)
{
Evry_State *s = sel->state;
Evry_Item *it = NULL;
if (s)
{
it = s->sel_item;
if (!s->plugin && it)
_evry_list_item_desel(s, NULL);
else if (it && !eina_list_data_find_list(s->plugin->items, it))
_evry_list_item_desel(s, NULL);
it = s->sel_item;
if (s->plugin && (!it || s->item_auto_selected))
{
/* get first item */
if (s->plugin->items)
{
it = s->plugin->items->data;
s->item_auto_selected = EINA_TRUE;
_evry_list_item_sel(s, it);
}
}
}
_evry_selector_icon_set(sel);
if (it)
{
edje_object_part_text_set(sel->o_main, "e.text.label", it->label);
if (sel == selector)
edje_object_part_text_set(sel->o_main, "e.text.plugin", it->plugin->name);
else
edje_object_part_text_set(sel->o_main, "e.text.plugin", "");
}
else
{
/* no items for this state - clear selector */
edje_object_part_text_set(sel->o_main, "e.text.label", "");
if (sel == selector && s && s->plugin)
edje_object_part_text_set(sel->o_main, "e.text.plugin", s->plugin->name);
else
edje_object_part_text_set(sel->o_main, "e.text.plugin", "");
}
if (sel == selectors[0])
{
_evry_selector_actions_get(it);
_evry_selector_update(selectors[1]);
}
}
static void
_evry_list_update(Evry_State *s)
{
if (!list->visible) return;
_evry_list_clear_list(s);
_evry_list_tabs_update(s);
if (!s->plugin) return;
_evry_list_show_items(s, s->plugin);
_evry_list_scroll_to(s, s->sel_item);
}
static int
_evry_selector_subjects_get(void)
{
Eina_List *l, *plugins = NULL;
Evry_Plugin *p;
Evry_Selector *sel = selectors[0];
EINA_LIST_FOREACH(sel->plugins, l, p)
{
if (p->begin)
{
if (p->begin(p, NULL))
plugins = eina_list_append(plugins, p);
}
else
plugins = eina_list_append(plugins, p);
}
if (!plugins) return 0;
_evry_state_new(sel, plugins);
_evry_matches_update(sel);
return 1;
}
static int
_evry_selector_actions_get(Evry_Item *it)
{
Eina_List *l, *plugins = NULL;
Evry_Plugin *p;
Evry_Selector *sel = selectors[1];
while (sel->state)
_evry_state_pop(sel);
if (!it) return 0;
EINA_LIST_FOREACH(sel->plugins, l, p)
{
if (strcmp(p->type_in, it->plugin->type_out) &&
(p != action_selector) &&
(p != sel->aggregator)) continue;
if (p->begin)
{
if (p->begin(p, it))
plugins = eina_list_append(plugins, p);
}
else
plugins = eina_list_append(plugins, p);
}
if (!plugins) return 0;
_evry_state_new(sel, plugins);
_evry_matches_update(sel);
return 1;
}
static int
_evry_selector_objects_get(const char *type)
{
Eina_List *l, *plugins = NULL;
Evry_Plugin *p;
Evry_Selector *sel = selectors[2];
Evry_Item *it;
while (sel->state)
_evry_state_pop(sel);
it = selectors[0]->state->sel_item;
EINA_LIST_FOREACH(sel->plugins, l, p)
{
if (strcmp(p->type_out, type) &&
(p != sel->aggregator)) continue;
if (p->begin)
{
if (p->begin(p, it))
plugins = eina_list_append(plugins, p);
}
else
plugins = eina_list_append(plugins, p);
}
if (!plugins) return 0;
_evry_state_new(sel, plugins);
_evry_matches_update(sel);
return 1;
}
static Evry_State *
_evry_state_new(Evry_Selector *sel, Eina_List *plugins)
{
Evry_State *s = E_NEW(Evry_State, 1);
s->input = malloc(INPUTLEN);
s->input[0] = 0;
s->plugins = plugins;
sel->states = eina_list_prepend(sel->states, s);
sel->state = s;
return s;
}
static void
_evry_state_pop(Evry_Selector *sel)
{
Evry_Plugin *p;
Evry_State *s;
s = sel->state;
_evry_list_item_desel(s, NULL);
free(s->input);
EINA_LIST_FREE(s->plugins, p)
p->cleanup(p);
E_FREE(s);
sel->states = eina_list_remove_list(sel->states, sel->states);
if (sel->states)
sel->state = sel->states->data;
else
sel->state = NULL;
}
static void
_evry_browse_item(Evry_Selector *sel)
{
Evry_State *s = sel->state;
Evry_Item *it;
Eina_List *l, *plugins = NULL;
Evry_Plugin *p;
it = s->sel_item;
if (!it || !it->browseable) return;
_evry_list_clear_list(sel->state);
EINA_LIST_FOREACH(sel->plugins, l, p)
{
if (!p->browse) continue;
if (!strstr(p->type_in, it->plugin->type_out)) continue;
if (p->browse(p, it))
plugins = eina_list_append(plugins, p);
}
if (plugins)
{
_evry_list_win_show();
_evry_state_new(sel, plugins);
_evry_matches_update(sel);
_evry_selector_update(sel);
}
_evry_list_update(sel->state);
_evry_update_text_label(sel->state);
}
static void
_evry_browse_back(Evry_Selector *sel)
{
Evry_State *s = sel->state;
if (!s || !sel->states->next) return;
_evry_list_clear_list(s);
_evry_state_pop(sel);
sel->aggregator->fetch(sel->aggregator, sel->state->input);
_evry_selector_update(sel);
_evry_list_update(sel->state);
_evry_update_text_label(sel->state);
}
static void
_evry_selectors_switch(void)
{
Evry_State *s = selector->state;
if (update_timer)
{
if ((s && !s->plugin->async_query) &&
((selector == selectors[0]) ||
(selector == selectors[1])))
{
_evry_list_clear_list(s);
_evry_matches_update(selector);
_evry_selector_update(selector);
}
ecore_timer_del(update_timer);
update_timer = NULL;
}
if (selector == selectors[0])
{
if (s->sel_item)
_evry_selector_activate(selectors[1]);
}
else if (selector == selectors[1])
{
int next_selector = 0;
if (s->sel_item && s->sel_item->plugin == action_selector)
{
Evry_Action *act = s->sel_item->data[0];
if (act && act->type_in2)
{
_evry_selector_objects_get(act->type_in2);
_evry_selector_update(selectors[2]);
edje_object_signal_emit(win->o_main,
"e,state,object_selector_show", "e");
next_selector = 2;
}
}
_evry_selector_activate(selectors[next_selector]);
}
else if (selector == selectors[2])
{
_evry_list_clear_list(s);
while (selector->states)
_evry_state_pop(selector);
edje_object_signal_emit(win->o_main,
"e,state,object_selector_hide", "e");
_evry_selector_activate(selectors[0]);
}
}
static int
_evry_cb_key_down(void *data __UNUSED__, int type __UNUSED__, void *event)
{
Ecore_Event_Key *ev;
Evry_State *s = selector->state;
/* ev_last_is_mouse = 0;
* item_mouseover = NULL; */
win->request_selection = EINA_FALSE;
ev = event;
if (ev->event_window != input_window) return 1;
if (!strcmp(ev->key, "Up"))
_evry_list_item_prev(s);
else if (!strcmp(ev->key, "Down"))
_evry_list_item_next(s);
else if (!strcmp(ev->key, "Right") &&
((ev->modifiers & ECORE_EVENT_MODIFIER_CTRL) ||
(ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT)))
_evry_list_plugin_next(s);
else if (!strcmp(ev->key, "Left") &&
((ev->modifiers & ECORE_EVENT_MODIFIER_CTRL) ||
(ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT)))
_evry_list_plugin_prev(s);
else if (!strcmp(ev->key, "Right"))
_evry_browse_item(selector);
else if (!strcmp(ev->key, "Left"))
_evry_browse_back(selector);
else if ((!strcmp(ev->key, "Return")) &&
((ev->modifiers & ECORE_EVENT_MODIFIER_CTRL) ||
(ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT)))
_evry_plugin_action(selector, 0);
else if (!strcmp(ev->key, "Return"))
_evry_plugin_action(selector, 1);
else if (!strcmp(ev->key, "Tab") &&
((ev->modifiers & ECORE_EVENT_MODIFIER_ALT) ||
(ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)))
_evry_list_plugin_next(s);
else if (!strcmp(ev->key, "Tab"))
_evry_selectors_switch();
else if (!strcmp(ev->key, "u") &&
(ev->modifiers & ECORE_EVENT_MODIFIER_CTRL))
_evry_clear(s);
else if ((!strcmp(ev->key, "Escape")) ||
(!strcmp(ev->key, "e") &&
(ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)))
evry_hide();
else if ((!strcmp(ev->key, "BackSpace")) ||
(!strcmp(ev->key, "Delete")))
_evry_backspace(s);
else if (!strcmp(ev->key, "End"))
_evry_list_item_last(s);
else if (!strcmp(ev->key, "Home"))
_evry_list_item_first(s);
else if (!strcmp(ev->key, "v") &&
(ev->modifiers & ECORE_EVENT_MODIFIER_CTRL))
{
win->request_selection = EINA_TRUE;
ecore_x_selection_primary_request(win->popup->evas_win,
ECORE_X_SELECTION_TARGET_UTF8_STRING);
}
else if ((ev->key) &&
(ev->modifiers & ECORE_EVENT_MODIFIER_CTRL))
_evry_list_plugin_next_by_name(s, ev->key);
else if ((ev->compose) &&
(!(ev->modifiers & ECORE_EVENT_MODIFIER_ALT) ||
(ev->modifiers & ECORE_EVENT_MODIFIER_WIN)))
{
if (strlen(s->input) < (INPUTLEN - strlen(ev->compose)))
{
strcat(s->input, ev->compose);
if (isspace(*ev->compose))
_evry_update(s, 0);
else
_evry_update(s, 1);
}
}
return 1;
}
static void
_evry_backspace(Evry_State *s)
{
int len, val, pos;
len = strlen(s->input);
if (len > 0)
{
pos = evas_string_char_prev_get(s->input, len, &val);
if ((pos < len) && (pos >= 0))
{
s->input[pos] = 0;
_evry_update(s, 1);
}
}
}
static void
_evry_update_text_label(Evry_State *s)
{
if (strlen(s->input) > 0)
edje_object_signal_emit(list->o_main, "e,state,entry_show", "e");
else
edje_object_signal_emit(list->o_main, "e,state,entry_hide", "e");
edje_object_part_text_set(win->o_main, "e.text.label", s->input);
edje_object_part_text_set(list->o_main, "e.text.label", s->input);
}
static void
_evry_update(Evry_State *s, int fetch)
{
_evry_update_text_label(s);
if (fetch)
{
if (update_timer) ecore_timer_del(update_timer);
update_timer = ecore_timer_add(MATCH_LAG, _evry_update_timer, s);
}
}
static int
_evry_update_timer(void *data)
{
/* XXX pass selector as data? */
_evry_matches_update(selector);
_evry_selector_update(selector);
_evry_list_update(selector->state);
_evry_list_tabs_update(selector->state);
update_timer = NULL;
return 0;
}
static void
_evry_clear(Evry_State *s)
{
if ((s->plugin && s->plugin->trigger && s->input) &&
(!strncmp(s->plugin->trigger, s->input, strlen(s->plugin->trigger))))
{
s->input[strlen(s->plugin->trigger)] = 0;
_evry_update(s, 1);
}
else if (s->input[0] != 0)
{
s->input[0] = 0;
_evry_update(s, 1);
edje_object_signal_emit(list->o_main, "e,state,entry_hide", "e");
}
}
static void
_evry_plugin_action(Evry_Selector *sel, int finished)
{
Evry_State *s_subject, *s_action, *s_object;
s_subject = selectors[0]->state;
s_action = selectors[1]->state;
s_object = NULL;
if (!s_subject || !s_action) return;
if (update_timer)
{
if ((selector->state->plugin) &&
(!selector->state->plugin->async_query))
{
_evry_matches_update(selector);
_evry_selector_update(selector);
}
ecore_timer_del(update_timer);
update_timer = NULL;
}
if (!s_subject->sel_item || !s_action->sel_item) return;
if (s_action->sel_item->plugin == action_selector)
{
Evry_Action *act = s_action->sel_item->data[0];
Evry_Item *it_object = NULL;
if (selectors[2] == selector) /* && selector->state ? */
it_object = selector->state->sel_item;
if (act->type_in2 && !it_object) return;
act->action(act, s_subject->sel_item, it_object, NULL);
}
else
{
Evry_Item *it = s_action->sel_item;
s_action->plugin->action(s_action->plugin, it, selector->state->input);
}
if (s_subject->plugin->action)
s_subject->plugin->action(s_subject->plugin,
s_subject->sel_item,
s_subject->input);
if (s_object && s_object->plugin->action)
s_object->plugin->action(s_object->plugin,
s_object->sel_item,
s_object->input);
if (finished)
evry_hide();
}
static void
_evry_list_show_items(Evry_State *s, Evry_Plugin *p)
{
Evry_Item *it;
Eina_List *l;
int mw, mh, h;
Evas_Object *o;
if (!p) return;
if (p->realize_items) p->realize_items(p, list->popup->evas);
if (list->scroll_timer)
{
ecore_timer_del(list->scroll_timer);
list->scroll_timer = NULL;
}
if (list->scroll_animator)
{
ecore_animator_del(list->scroll_animator);
list->scroll_animator = NULL;
}
if (!list->visible) return;
list->scroll_align = 0;
evas_event_freeze(list->popup->evas);
e_box_freeze(list->o_list);
EINA_LIST_FOREACH(p->items, l, it)
{
o = it->o_bg;
if (!o)
{
o = edje_object_add(list->popup->evas);
it->o_bg = o;
e_theme_edje_object_set(o, "base/theme/everything",
"e/widgets/everything/item");
edje_object_part_text_set(o, "e.text.title", it->label);
/* evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_IN,
* _evry_cb_item_mouse_in, it);
* evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_OUT,
* _evry_cb_item_mouse_out, it); */
}
edje_object_size_min_calc(o, &mw, &mh);
e_box_pack_end(list->o_list, o);
e_box_pack_options_set(o, 1, 1, 1, 0, 0.5, 0.5, mw, mh, 9999, mh);
evas_object_show(o);
if (it->o_icon && edje_object_part_exists(o, "e.swallow.icons"))
{
edje_object_part_swallow(o, "e.swallow.icons", it->o_icon);
evas_object_show(it->o_icon);
}
if (it == s->sel_item)
{
edje_object_signal_emit(it->o_bg, "e,state,selected", "e");
if (it->o_icon)
edje_object_signal_emit(it->o_icon, "e,state,selected", "e");
if (it->browseable)
edje_object_signal_emit(it->o_bg, "e,state,arrow_show", "e");
}
_evry_item_ref(it);
s->items = eina_list_append(s->items, it);
}
e_box_thaw(list->o_list);
list->item_idler = ecore_idler_add(_evry_list_item_idler, p);
e_box_min_size_get(list->o_list, NULL, &mh);
evas_object_geometry_get(list->o_list, NULL, NULL, NULL, &h);
if (mh <= h)
e_box_align_set(list->o_list, 0.5, 0.0);
else
e_box_align_set(list->o_list, 0.5, 1.0);
evas_event_thaw(list->popup->evas);
_evry_list_tab_scroll_to(s, p);
}
static void
_evry_list_clear_list(Evry_State *s)
{
Evry_Item *it;
if (list->item_idler)
{
ecore_idler_del(list->item_idler);
list->item_idler = NULL;
}
if (s && s->items)
{
evas_event_freeze(list->popup->evas);
e_box_freeze(list->o_list);
EINA_LIST_FREE(s->items, it)
{
if (it->o_bg)
{
e_box_unpack(it->o_bg);
evas_object_hide(it->o_bg);
}
if (it->o_icon)
evas_object_hide(it->o_icon);
evry_item_free(it);
}
}
e_box_thaw(list->o_list);
evas_event_thaw(list->popup->evas);
/* } */
}
static int
_evry_list_item_idler(void *data)
{
Evry_Plugin *p = data;
int cnt = 5;
Eina_List *l;
Evry_Item *it;
if (!list->item_idler) return 0;
if (!p->icon_get) goto end;
e_box_freeze(list->o_list);
EINA_LIST_FOREACH(p->items, l, it)
{
if (it->o_icon) continue;
it->o_icon = p->icon_get(p, it, list->popup->evas);
if (it->o_icon)
{
edje_object_part_swallow(it->o_bg, "e.swallow.icons", it->o_icon);
evas_object_show(it->o_icon);
cnt--;
}
if (cnt == 0) break;
}
e_box_thaw(list->o_list);
if (cnt == 0) return 1;
end:
list->item_idler = NULL;
return 0;
}
static void
_evry_matches_update(Evry_Selector *sel)
{
Evry_State *s = sel->state;
Evry_Plugin *p;
Eina_List *l;
Eina_Bool has_items = EINA_FALSE;
EINA_LIST_FREE(s->cur_plugins, p);
if (s->input)
{
EINA_LIST_FOREACH(s->plugins, l, p)
{
/* input matches plugin trigger? */
if (!p->trigger) continue;
if ((strlen(s->input) >= strlen(p->trigger)) &&
(!strncmp(s->input, p->trigger, strlen(p->trigger))))
{
s->cur_plugins = eina_list_append(s->cur_plugins, p);
p->fetch(p, s->input);
break;
}
}
}
if (!s->cur_plugins)
{
EINA_LIST_FOREACH(s->plugins, l, p)
{
if (p->trigger) continue;
if (p == sel->aggregator) continue;
if (strlen(s->input) == 0)
{
if (!p->need_query)
has_items = p->fetch(p, NULL);
}
else
{
has_items = p->fetch(p, s->input);
}
if (has_items || sel->states->next)
s->cur_plugins = eina_list_append(s->cur_plugins, p);
}
if (eina_list_count(s->cur_plugins) > 1)
{
sel->aggregator->fetch(sel->aggregator, s->input);
s->cur_plugins = eina_list_prepend(s->cur_plugins, sel->aggregator);
}
else
sel->aggregator->cleanup(sel->aggregator);
}
if (s->plugin && !eina_list_data_find_list(s->cur_plugins, s->plugin))
s->plugin = NULL;
_evry_select_plugin(s, s->plugin);
}
static void
_evry_list_scroll_to(Evry_State *s, Evry_Item *it)
{
int n, h, mh, i = 0;
Eina_List *l;
if (!it) return;
for(l = s->plugin->items; l; l = l->next, i++)
if (l->data == it) break;
n = eina_list_count(s->plugin->items);
e_box_min_size_get(list->o_list, NULL, &mh);
evas_object_geometry_get(list->o_list, NULL, NULL, NULL, &h);
/* edje_object_part_geometry_get(list->o_main, "e.swallow.list", NULL, NULL, &max_w, &max_h); */
/* printf("MAX %d %d %d\n", max_h, h, mh);
* if (max_h != h)
* evas_object_resize(list->o_list, max_w, max_h); */
if (i >= n || mh <= h)
{
e_box_align_set(list->o_list, 0.5, 0.0);
return;
}
if (n > 1)
{
list->scroll_align_to = (double)i / (double)(n - 1);
if (evry_conf->scroll_animate)
{
if (!list->scroll_timer)
list->scroll_timer = ecore_timer_add(0.01, _evry_list_scroll_timer, NULL);
if (!list->scroll_animator)
list->scroll_animator = ecore_animator_add(_evry_list_animator, NULL);
}
else
{
list->scroll_align = list->scroll_align_to;
e_box_align_set(list->o_list, 0.5, 1.0 - list->scroll_align);
}
}
else
e_box_align_set(list->o_list, 0.5, 1.0);
}
static void
_evry_list_tab_scroll_to(Evry_State *s, Evry_Plugin *p)
{
int n, w, mw, i;
double align;
Eina_List *l;
for(i = 0, l = s->cur_plugins; l; l = l->next, i++)
if (l->data == p) break;
n = eina_list_count(s->cur_plugins);
e_box_min_size_get(list->o_tabs, &mw, NULL);
evas_object_geometry_get(list->o_tabs, NULL, NULL, &w, NULL);
if (mw <= w)
{
e_box_align_set(list->o_tabs, 0.0, 0.5);
return;
}
if (n > 1)
{
align = (double)i / (double)(n - 1);
/* if (evry_conf->scroll_animate)
* {
* if (!scroll_timer)
* scroll_timer = ecore_timer_add(0.01, _evry_list_scroll_timer, NULL);
* if (!scroll_animator)
* scroll_animator = ecore_animator_add(_evry_list_animator, NULL);
* }
* else */
{
e_box_align_set(list->o_tabs, 1.0 - align, 0.5);
}
}
else
e_box_align_set(list->o_tabs, 1.0, 0.5);
}
static void
_evry_list_item_desel(Evry_State *s, Evry_Item *it)
{
if (s->sel_item)
{
it = s->sel_item;
if (list->visible)
{
if (it->o_bg)
edje_object_signal_emit(it->o_bg, "e,state,unselected", "e");
if (it->o_icon)
edje_object_signal_emit(it->o_icon, "e,state,unselected", "e");
}
evry_item_free(it);
s->sel_item = NULL;
}
}
static void
_evry_list_item_sel(Evry_State *s, Evry_Item *it)
{
if (s->sel_item == it) return;
_evry_list_item_desel(s, NULL);
if (list->visible)
{
if (it->o_bg)
edje_object_signal_emit(it->o_bg, "e,state,selected", "e");
if (it->o_icon)
edje_object_signal_emit(it->o_icon, "e,state,selected", "e");
if (it->browseable)
edje_object_signal_emit(it->o_bg, "e,state,arrow_show", "e");
if (s == selector->state)
_evry_list_scroll_to(s, it);
}
_evry_item_ref(it);
s->sel_item = it;
}
static void
_evry_list_item_next(Evry_State *s)
{
Eina_List *l;
Evry_Item *it;
if (!s->plugin || !s->plugin->items) return;
if (!list->visible)
{
_evry_list_win_show();
return;
}
s->plugin_auto_selected = EINA_FALSE;
s->item_auto_selected = EINA_FALSE;
if (!s->sel_item)
{
_evry_list_item_sel(s, s->plugin->items->data);
_evry_selector_update(selector);
return;
}
EINA_LIST_FOREACH (s->plugin->items, l, it)
{
if (it == s->sel_item)
{
if (l->next)
{
_evry_list_item_sel(s, l->next->data);
_evry_selector_update(selector);
}
break;
}
}
}
static void
_evry_list_item_prev(Evry_State *s)
{
Eina_List *l;
Evry_Item *it;
if (!s->plugin || !s->plugin->items) return;
s->plugin_auto_selected = EINA_FALSE;
s->item_auto_selected = EINA_FALSE;
if (!s->sel_item) return;
EINA_LIST_FOREACH (s->plugin->items, l, it)
{
if (it == s->sel_item)
{
if (l->prev)
{
_evry_list_item_sel(s, l->prev->data);
_evry_selector_update(selector);
return;
}
break;
}
}
_evry_list_win_hide();
}
static void
_evry_list_item_first(Evry_State *s)
{
if (!s->plugin || !s->plugin->items) return;
s->plugin_auto_selected = EINA_FALSE;
s->item_auto_selected = EINA_FALSE;
_evry_list_item_sel(s, s->plugin->items->data);
_evry_selector_update(selector);
}
static void
_evry_list_item_last(Evry_State *s)
{
if (!s->plugin || !s->plugin->items) return;
s->plugin_auto_selected = EINA_FALSE;
s->item_auto_selected = EINA_FALSE;
_evry_list_item_sel(s, eina_list_last(s->plugin->items)->data);
_evry_selector_update(selector);
}
static void
_evry_select_plugin(Evry_State *s, Evry_Plugin *p)
{
if (!s || !s->cur_plugins) return;
if (!p && s->cur_plugins)
{
p = s->cur_plugins->data;
s->plugin_auto_selected = EINA_TRUE;
}
if (p && list->visible)
{
if (s->plugin && s->plugin != p)
edje_object_signal_emit(s->plugin->tab, "e,state,unselected", "e");
edje_object_signal_emit(p->tab, "e,state,selected", "e");
}
if ((p || !s->plugin) && s->plugin != p)
{
_evry_list_item_desel(s, NULL);
s->plugin = p;
}
}
static void
_evry_list_plugin_next(Evry_State *s)
{
Eina_List *l;
Evry_Plugin *p = NULL;
if (!s->plugin) return;
/* _evry_list_win_show(); */
l = eina_list_data_find_list(s->cur_plugins, s->plugin);
if (l && l->next)
p = l->next->data;
else if (s->plugin != s->cur_plugins->data)
p = s->cur_plugins->data;
if (p)
{
s->plugin_auto_selected = EINA_FALSE;
_evry_list_clear_list(s);
_evry_select_plugin(s, p);
_evry_list_show_items(s, p);
_evry_selector_update(selector);
}
}
static void
_evry_list_plugin_next_by_name(Evry_State *s, const char *key)
{
Eina_List *l;
Evry_Plugin *p, *first = NULL, *next = NULL;
int found = 0;
if (!s->plugin) return;
EINA_LIST_FOREACH(s->cur_plugins, l, p)
{
if (p->name && (!strncasecmp(p->name, key, 1)))
{
if (!first) first = p;
if (found && !next)
next = p;
}
if (p == s->plugin) found = 1;
}
if (next)
p = next;
else if (first != s->plugin)
p = first;
else
p = NULL;
if (p)
{
s->plugin_auto_selected = EINA_FALSE;
_evry_list_clear_list(s);
_evry_select_plugin(s, p);
_evry_list_show_items(s, p);
_evry_selector_update(selector);
}
}
static void
_evry_list_plugin_prev(Evry_State *s)
{
Eina_List *l;
Evry_Plugin *p = NULL;
if (!s->plugin) return;
/* _evry_list_win_show(); */
l = eina_list_data_find_list(s->cur_plugins, s->plugin);
if (l && l->prev)
p = l->prev->data;
else
{
l = eina_list_last(s->cur_plugins);
if (s->plugin != l->data)
p = l->data;
}
if (p)
{
s->plugin_auto_selected = EINA_FALSE;
_evry_list_clear_list(s);
_evry_select_plugin(s, p);
_evry_list_show_items(s, p);
_evry_selector_update(selector);
}
}
static int
_evry_list_scroll_timer(void *data __UNUSED__)
{
if (list->scroll_animator)
{
double spd;
spd = evry_conf->scroll_speed;
list->scroll_align = (list->scroll_align * (1.0 - spd)) +
(list->scroll_align_to * spd);
return 1;
}
list->scroll_timer = NULL;
return 0;
}
static int
_evry_list_animator(void *data __UNUSED__)
{
double da;
Eina_Bool scroll_to = 1;
da = list->scroll_align - list->scroll_align_to;
if (da < 0.0) da = -da;
if (da < 0.01)
{
list->scroll_align = list->scroll_align_to;
scroll_to = 0;
}
e_box_align_set(list->o_list, 0.5, 1.0 - list->scroll_align);
if (scroll_to) return 1;
list->scroll_animator = NULL;
return 0;
}
static void
_evry_list_tabs_update(Evry_State *s)
{
Eina_List *l;
Evry_Plugin *p;
/* remove tabs for not active plugins */
EINA_LIST_FOREACH(selector->plugins, l, p)
{
if (p->tab && !eina_list_data_find(s->cur_plugins, p))
{
e_box_unpack(p->tab);
evas_object_del(p->tab);
p->tab = NULL;
}
}
/* show/update tabs of active plugins */
EINA_LIST_FOREACH(s->cur_plugins, l, p)
{
_evry_list_tab_show(s, p);
if (s->plugin == p)
edje_object_signal_emit(p->tab, "e,state,selected", "e");
else
edje_object_signal_emit(p->tab, "e,state,unselected", "e");
}
}
static void
_evry_list_tab_show(Evry_State *s, Evry_Plugin *p)
{
Evas_Object *o;
Evas_Coord mw = 0, mh = 0;
char buf[64];
Eina_List *l;
e_box_freeze(list->o_tabs);
if (p->tab)
{
o = p->tab;
e_box_unpack(p->tab);
}
else
{
o = edje_object_add(list->popup->evas);
e_theme_edje_object_set(o, "base/theme/everything",
"e/widgets/everything/tab_item");
}
snprintf(buf, 64, "%s (%d)", p->name, eina_list_count(p->items));
edje_object_part_text_set(o, "e.text.label", buf);
edje_object_size_min_calc(o, &mw, &mh);
l = eina_list_data_find_list(s->cur_plugins, p);
if (l && l->prev)
{
Evry_Plugin *p2 = l->prev->data;
e_box_pack_after(list->o_tabs, o, p2->tab);
}
else
e_box_pack_end(list->o_tabs, o);
evas_object_show(o);
e_box_pack_options_set(o, 1, 1, 0, 0, 0.5, 0.5, mw, mh, 9999, 9999);
e_box_thaw(list->o_tabs);
p->tab = o;
}
static int
_evry_fuzzy_sort_cb(const void *data1, const void *data2)
{
const Evry_Item *it1 = data1;
const Evry_Item *it2 = data2;
if ((it1->plugin == it2->plugin) &&
(it1->priority - it2->priority))
return (it1->priority - it2->priority);
if (it1->fuzzy_match && !it2->fuzzy_match)
return -1;
if (!it1->fuzzy_match && it2->fuzzy_match)
return 1;
if (it1->fuzzy_match - it2->fuzzy_match)
return (it1->fuzzy_match - it2->fuzzy_match);
if (it1->plugin->config->priority - it2->plugin->config->priority)
return (it1->plugin->config->priority - it2->plugin->config->priority);
return (it1->priority - it2->priority);
}
/* action selector plugin: provides list of actions registered for
candidate types provided by current plugin */
static int
_evry_plug_actions_init(void)
{
Plugin_Config *pc;
Evry_Plugin *p = E_NEW(Evry_Plugin, 1);
p->name = "Select Action";
p->type = type_action;
p->type_in = "ANY";
p->type_out = "NONE";
p->begin = &_evry_plug_actions_begin;
p->cleanup = &_evry_plug_actions_cleanup;
p->fetch = &_evry_plug_actions_fetch;
p->icon_get = &_evry_plug_actions_item_icon_get;
pc = E_NEW(Plugin_Config, 1);
pc->name = eina_stringshare_add(p->name);
pc->enabled = 1;
pc->priority = 1;
p->config = pc;
action_selector = p;
return 1;
}
static void
_evry_plug_actions_free(void)
{
Evry_Plugin *p = action_selector;
eina_stringshare_del(p->config->name);
E_FREE(p->config);
E_FREE(p);
}
static int
_evry_plug_actions_begin(Evry_Plugin *p, const Evry_Item *it)
{
Evry_Action *act;
Eina_List *l;
Evry_Selector *sel = selectors[1];
_evry_plug_actions_cleanup(p);
if (!it) return 0;
const char *type = it->plugin->type_out;
EINA_LIST_FOREACH(evry_conf->actions, l, act)
{
if ((strstr(act->type_in1, type)) &&
(!act->check_item || act->check_item(act, it)))
{
sel->actions = eina_list_append(sel->actions, act);
}
}
if (sel->actions) return 1;
return 0;
}
static int
_evry_plug_actions_fetch(Evry_Plugin *p, const char *input)
{
Evry_Action *act;
Eina_List *l;
Evry_Item *it;
Evry_Selector *sel = selectors[1];
int match = 0;
EINA_LIST_FREE(p->items, it)
evry_item_free(it);
EINA_LIST_FOREACH(sel->actions, l, act)
{
if (input)
match = evry_fuzzy_match(act->name, input);
if (!input || match)
{
it = evry_item_new(p, act->name, NULL);
it->fuzzy_match = match;
it->data[0] = act;
p->items = eina_list_append(p->items, it);
}
}
if (input)
p->items = eina_list_sort(p->items, eina_list_count(p->items), _evry_fuzzy_sort_cb);
if (p->items) return 1;
return 0;
}
static void
_evry_plug_actions_cleanup(Evry_Plugin *p)
{
Evry_Item *it;
Evry_Selector *sel = selectors[1];
EINA_LIST_FREE(p->items, it)
evry_item_free(it);
if (sel->actions) eina_list_free(sel->actions);
sel->actions = NULL;
}
static Evas_Object *
_evry_plug_actions_item_icon_get(Evry_Plugin *p __UNUSED__, const Evry_Item *it, Evas *e)
{
Evas_Object *o = NULL;
Evry_Action *act = it->data[0];
if (!act) return NULL;
if (act->icon_get)
o = act->icon_get(act, e);
else if (act->icon)
{
o = e_icon_add(e);
evry_icon_theme_set(o, act->icon);
}
return o;
}
static Evry_Plugin *
_evry_plug_aggregator_new(void)
{
Plugin_Config *pc;
Evry_Plugin *p = E_NEW(Evry_Plugin, 1);
p->name = "All";
p->type_in = "NONE";
p->type_out = "NONE";
p->cleanup = &_evry_plug_aggregator_cleanup;
p->fetch = &_evry_plug_aggregator_fetch;
p->action = &_evry_plug_aggregator_action;
p->icon_get = &_evry_plug_aggregator_item_icon_get;
pc = E_NEW(Plugin_Config, 1);
pc->name = eina_stringshare_add(p->name);
pc->enabled = 1;
pc->priority = -1;
p->config = pc;
return p;
}
static void
_evry_plug_aggregator_free(Evry_Plugin *p)
{
if (p->config->name) eina_stringshare_del(p->config->name);
E_FREE(p->config);
E_FREE(p);
}
static int
_evry_plug_aggregator_fetch(Evry_Plugin *p, const char *input)
{
Evry_Selector *selector = p->private;
Evry_State *s = selector->state;
Eina_List *l, *ll;
Evry_Plugin *plugin;
Evry_Item *it;
int cnt = 0;
Eina_List *items = NULL;
EINA_LIST_FREE(p->items, it)
evry_item_free(it);
EINA_LIST_FOREACH(s->cur_plugins, l, plugin)
cnt += eina_list_count(plugin->items);
if (input[0])
{
EINA_LIST_FOREACH(s->cur_plugins, l, plugin)
{
EINA_LIST_FOREACH(plugin->items, ll, it)
{
if (!it->fuzzy_match)
it->fuzzy_match = evry_fuzzy_match(it->label, input);
if (it->fuzzy_match)
{
_evry_item_ref(it);
items = eina_list_append(items, it);
p->items = eina_list_append(p->items, it);
}
}
}
}
if (!input[0] || eina_list_count(items) < 20)
{
EINA_LIST_FOREACH(s->cur_plugins, l, plugin)
{
for (cnt = 0, ll = plugin->items; ll && cnt < 15; ll = ll->next, cnt++)
{
if (!items || !eina_list_data_find_list(items, ll->data))
{
it = ll->data;
_evry_item_ref(it);
it->fuzzy_match = 0;
p->items = eina_list_append(p->items, it);
}
}
}
}
eina_list_free(items);
if (input[0])
p->items = eina_list_sort(p->items, eina_list_count(p->items), _evry_fuzzy_sort_cb);
return 1;
}
static int
_evry_plug_aggregator_action(Evry_Plugin *p, const Evry_Item *it, const char *input)
{
if (it->plugin && it->plugin->action)
return it->plugin->action(it->plugin, it, input);
return 0;
}
static void
_evry_plug_aggregator_cleanup(Evry_Plugin *p)
{
Evry_Item *it;
EINA_LIST_FREE(p->items, it)
evry_item_free(it);
}
static Evas_Object *
_evry_plug_aggregator_item_icon_get(Evry_Plugin *p, const Evry_Item *it, Evas *e)
{
if (it->plugin && it->plugin->icon_get)
return it->plugin->icon_get(it->plugin, it, e);
return NULL;
}
static void
_evry_plugin_list_insert(Evry_State *s, Evry_Plugin *p)
{
Eina_List *l;
Evry_Plugin *plugin;
EINA_LIST_FOREACH(s->cur_plugins, l, plugin)
if (p == plugin)
return;
else
if (p->config->priority < plugin->config->priority)
break;
if (l)
s->cur_plugins = eina_list_prepend_relative_list(s->cur_plugins, p, l);
else
s->cur_plugins = eina_list_append(s->cur_plugins, p);
}
/* taken from e_utils. just changed 48 to 72.. we need
evry_icon_theme_set(Evas_Object *obj, const char *icon,
size:small, mid, large) imo */
static int
_evry_icon_theme_set(Evas_Object *obj, const char *icon)
{
const char *file;
char buf[4096];
if ((!icon) || (!icon[0])) return 0;
snprintf(buf, sizeof(buf), "e/icons/%s", icon);
file = e_theme_edje_file_get("base/theme/icons", buf);
if (file[0])
{
e_icon_file_edje_set(obj, file, buf);
return 1;
}
return 0;
}
static int
_evry_icon_fdo_set(Evas_Object *obj, const char *icon)
{
char *path = NULL;
unsigned int size;
if ((!icon) || (!icon[0])) return 0;
size = e_util_icon_size_normalize(72 * e_scale);
path = efreet_icon_path_find(e_config->icon_theme, icon, size);
if (!path) return 0;
e_icon_file_set(obj, path);
E_FREE(path);
return 1;
}
EAPI int
evry_icon_theme_set(Evas_Object *obj, const char *icon)
{
if (e_config->icon_theme_overrides)
{
if (_evry_icon_fdo_set(obj, icon))
return 1;
return _evry_icon_theme_set(obj, icon);
}
else
{
if (_evry_icon_theme_set(obj, icon))
return 1;
return _evry_icon_fdo_set(obj, icon);
}
}
static int
_evry_cb_selection_notify(void *data, int type, void *event)
{
Ecore_X_Event_Selection_Notify *ev;
Evry_State *s = selector->state;
if (!s || (data != win)) return 1;
if (!win->request_selection) return 1;
win->request_selection = EINA_FALSE;
ev = event;
if ((ev->selection == ECORE_X_SELECTION_CLIPBOARD) ||
(ev->selection == ECORE_X_SELECTION_PRIMARY))
{
if (strcmp(ev->target, ECORE_X_SELECTION_TARGET_UTF8_STRING) == 0)
{
Ecore_X_Selection_Data_Text *text_data;
text_data = ev->data;
strncat(s->input, text_data->text, (INPUTLEN - strlen(s->input)) - 1);
_evry_update(s, 1);
}
}
return 1;
}
/* static int
* _evry_cb_mouse_down(void *data __UNUSED__, int type __UNUSED__, void *event)
* {
* Ecore_Event_Mouse_Button *ev;
* Evry_State *s =state;
*
* ev = event;
* if (ev->event_window != input_window) return 1;
*
* if (item_mouseover)
* {
* if (s->sel_item != item_mouseover)
* {
* if (s->sel_item) _evry_list_item_desel(s->sel_item);
* s->sel_item = item_mouseover;
* _evry_list_item_sel(s->sel_item);
* }
* }
* else
* {
* evas_event_feed_mouse_up(popup_list->evas, ev->buttons, 0, ev->timestamp, NULL);
* }
*
* return 1;
* }
*
* static int
* _evry_cb_mouse_up(void *data __UNUSED__, int type __UNUSED__, void *event)
* {
* Ecore_Event_Mouse_Button *ev;
*
* ev = event;
* if (ev->event_window != input_window) return 1;
*
* if (item_mouseover)
* {
* if (ev->buttons == 1)
* _evry_plugin_action(1);
* else if (ev->buttons == 3)
* _evry_plugin_action(0);
* }
* else
* {
* evas_event_feed_mouse_up(popup_list->evas, ev->buttons, 0, ev->timestamp, NULL);
* }
*
* return 1;
* }
*
* static int
* _evry_cb_mouse_move(void *data __UNUSED__, int type __UNUSED__, void *event)
* {
* Ecore_Event_Mouse_Move *ev;
* Evry_State *s =state;
*
* ev = event;
* if (ev->event_window != input_window) return 1;
*
* if (!ev_last_is_mouse)
* {
* ev_last_is_mouse = 1;
* if (item_mouseover)
* {
* if (s->sel_item && (s->sel_item != item_mouseover))
* _evry_list_item_desel(s->sel_item);
* if (!s->sel_item || (s->sel_item != item_mouseover))
* {
* s->sel_item = item_mouseover;
* _evry_list_item_sel(s->sel_item);
* }
* }
* }
*
* evas_event_feed_mouse_move(popup_list->evas, ev->x - popup_list->x,
* ev->y - popup_list->y, ev->timestamp, NULL);
*
* return 1;
* }
*
* static int
* _evry_cb_mouse_wheel(void *data __UNUSED__, int type __UNUSED__, void *event)
* {
* Ecore_Event_Mouse_Wheel *ev;
*
* ev = event;
* if (ev->event_window != input_window) return 1;
*
* ev_last_is_mouse = 0;
*
* if (ev->z < 0) /\* up *\/
* {
* int i;
*
* for (i = ev->z; i < 0; i++) _evry_list_item_prev();
* }
* else if (ev->z > 0) /\* down *\/
* {
* int i;
*
* for (i = ev->z; i > 0; i--) _evry_list_item_next();
* }
* return 1;
* }
*
* static void
* _evry_cb_item_mouse_in(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
* {
* Evry_State *s =state;
*
* if (!ev_last_is_mouse) return;
*
* item_mouseover = data;
*
* if (s->sel_item) _evry_list_item_desel(s->sel_item);
* if (!(s->sel_item = data)) return;
* _evry_list_item_sel(s->sel_item);
* }
*
* static void
* _evry_cb_item_mouse_out(void *data __UNUSED__, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
* {
* item_mouseover = NULL;
* } */
/* static int
* _evry_cb_plugin_sort_by_trigger(const void *data1, const void *data2)
* {
* const Evry_Plugin *p1 = data1;
* const Evry_Plugin *p2 = data2;
* if (p1->trigger)
* {
* if (!strncmp(state->input, p1->trigger, strlen(p1->trigger)))
* return 1;
* }
*
* return p1->config->priority - p2->config->priority;
* } */