#include "e.h" #include "e_mod_main.h" #include "evry.h" #define WIDTH 400 #define HEIGHT 350 #define INPUTLEN 40 #define MATCH_LAG 0.33 static int _evry_cb_key_down(void *data, int type, void *event); static int _evry_cb_key_down(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); static void _evry_backspace(void); static void _evry_update(void); static void _evry_matches_clear(void); static void _evry_list_clear(void); static void _evry_show_candidates(Evry_Plugin *plugin); static int _evry_update_timer(void *data); static void _evry_matches_update(void); static void _evry_clear(void); static void _evry_item_next(void); static void _evry_item_prev(void); static void _evry_plugin_next(void); static void _evry_plugin_prev(void); static void _evry_scroll_to(int i); static void _evry_item_desel(Evry_Item *it); static void _evry_item_sel(Evry_Item *it); static void _evry_item_remove(Evry_Item *it); static void _evry_action(int finished); static void _evry_cb_plugin_sel(void *data1, void *data2); /* local subsystem globals */ static E_Popup *popup = NULL; static Evas_Object *o_list = NULL; static Evas_Object *o_main = NULL; static Evas_Object *icon_object = NULL; static Evas_Object *o_toolbar = NULL; static char *cmd_buf = NULL; static Eina_List *handlers = NULL; static Ecore_X_Window input_window = 0; static Eina_List *plugins = NULL; static Ecore_Timer *update_timer = NULL; /* static Ecore_Animator *animator = NULL; */ static Evry_Item *item_selected = NULL; static Evry_Item *item_mouseover = NULL; static double scroll_align_to; static double scroll_align; static int plugin_count; static Evry_Plugin *plugin_selected; static int toolbar_nr; static int ev_last_is_mouse; /* externally accessible functions */ EAPI int evry_init(void) { return 1; } EAPI int evry_shutdown(void) { evry_hide(); return 1; } EAPI void evry_plugin_add(Evry_Plugin *plugin) { plugins = eina_list_append(plugins, plugin); /* TODO sorting, initialization, etc */ } EAPI void evry_plugin_remove(Evry_Plugin *plugin) { plugins = eina_list_remove(plugins, plugin); /* cleanup */ } EAPI int evry_show(E_Zone *zone) { Evas_Object *o; int x, y, w, h; E_OBJECT_CHECK_RETURN(zone, 0); E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, 0); if (popup) return 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)) { ecore_x_window_free(input_window); input_window = 0; return 0; } w = WIDTH; h = HEIGHT; x = zone->x + (zone->w / 2) - (w / 2); y = zone->y + (zone->h / 2) - (h / 2); popup = e_popup_new(zone, x, y, w, h); if (!popup) return 0; cmd_buf = malloc(INPUTLEN); if (!cmd_buf) { e_object_del(E_OBJECT(popup)); return 0; } ecore_x_netwm_window_type_set(popup->evas_win, ECORE_X_WINDOW_TYPE_UTILITY); cmd_buf[0] = 0; e_popup_layer_set(popup, 255); 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); o_main = o; e_theme_edje_object_set(o, "base/theme/everything", "e/widgets/everything/main"); edje_object_part_text_set(o, "e.text.label", cmd_buf); o = e_box_add(popup->evas); o_list = o; e_box_orientation_set(o, 0); e_box_homogenous_set(o, 1); edje_object_part_swallow(o_main, "e.swallow.list", o); evas_object_show(o); o = o_main; evas_object_move(o, 0, 0); evas_object_resize(o, w, h); evas_object_show(o); e_popup_edje_bg_object_set(popup, o); o = e_widget_toolbar_add(popup->evas, 48 * e_scale, 48 * e_scale); e_widget_toolbar_scrollable_set(o, 0); edje_object_part_swallow(o_main, "e.swallow.bar", o); evas_object_show(o); o_toolbar = o; evas_event_thaw(popup->evas); 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_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)); _evry_matches_update(); ev_last_is_mouse = 0; item_mouseover = NULL; item_selected = NULL; e_popup_show(popup); return 1; } EAPI void evry_hide(void) { Ecore_Event *ev; char *str; Evry_Plugin *plugin; Eina_List *l; if (!popup) return; evas_event_freeze(popup->evas); _evry_matches_clear(); e_popup_hide(popup); e_box_freeze(o_list); EINA_LIST_FOREACH(plugins, l, plugin) { plugin->cleanup(); } e_box_thaw(o_list); evas_object_del(o_list); o_list = NULL; evas_object_del(o_toolbar); o_toolbar = NULL; evas_object_del(o_main); o_main = NULL; evas_event_thaw(popup->evas); e_object_del(E_OBJECT(popup)); popup = 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; free(cmd_buf); cmd_buf = NULL; plugin_selected = NULL; item_selected = NULL; item_mouseover = NULL; } /* local subsystem functions */ static int _evry_cb_key_down(void *data, int type, void *event) { Ecore_Event_Key *ev; ev_last_is_mouse = 0; ev = event; if (ev->event_window != input_window) return 1; if (!strcmp(ev->key, "Up")) _evry_item_prev(); else if (!strcmp(ev->key, "Down")) _evry_item_next(); else if (!strcmp(ev->key, "Right")) _evry_plugin_next(); else if (!strcmp(ev->key, "Left")) _evry_plugin_prev(); else if (!strcmp(ev->key, "Return")) _evry_action(1); else if (!strcmp(ev->key, "Return") && (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)) _evry_action(0); /* else if (!strcmp(ev->key, "Tab")) * _evry_complete(); * else if (!strcmp(ev->key, "Return")) * _evry_exec(); */ else if (!strcmp(ev->key, "u") && (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)) _evry_clear(); else if (!strcmp(ev->key, "Escape")) evry_hide(); else if (!strcmp(ev->key, "BackSpace")) _evry_backspace(); else if (!strcmp(ev->key, "Delete")) _evry_backspace(); else { if (ev->compose) { if ((strlen(cmd_buf) < (INPUTLEN - strlen(ev->compose)))) { strcat(cmd_buf, ev->compose); _evry_update(); if (!update_timer) update_timer = ecore_timer_add(MATCH_LAG, _evry_update_timer, NULL); } } } return 1; } static int _evry_cb_mouse_down(void *data, int type, void *event) { Ecore_Event_Mouse_Button *ev; ev = event; if (ev->event_window != input_window) return 1; if (item_mouseover) { if (item_selected != item_mouseover) { if (item_selected) _evry_item_desel(item_selected); item_selected = item_mouseover; _evry_item_sel(item_selected); } } else { evas_event_feed_mouse_up(popup->evas, ev->buttons, 0, ev->timestamp, NULL); } return 1; } static int _evry_cb_mouse_up(void *data, int type, 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_action(1); else if (ev->buttons == 3) _evry_action(0); } else { evas_event_feed_mouse_up(popup->evas, ev->buttons, 0, ev->timestamp, NULL); } return 1; } static int _evry_cb_mouse_move(void *data, int type, void *event) { Ecore_Event_Mouse_Move *ev; ev = event; if (ev->event_window != input_window) return 1; if (!ev_last_is_mouse) { ev_last_is_mouse = 1; if (item_mouseover) { if (item_selected && (item_selected != item_mouseover)) _evry_item_desel(item_selected); if (!item_selected || (item_selected != item_mouseover)) { item_selected = item_mouseover; _evry_item_sel(item_selected); } } } evas_event_feed_mouse_move(popup->evas, ev->x - popup->x, ev->y - popup->y, ev->timestamp, NULL); return 1; } static int _evry_cb_mouse_wheel(void *data, int type, 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_item_prev(); } else if (ev->z > 0) /* down */ { int i; for (i = ev->z; i > 0; i--) _evry_item_next(); } return 1; } static void _evry_cb_item_mouse_in(void *data, Evas *evas, Evas_Object *obj, void *event_info) { item_mouseover = data; if (!ev_last_is_mouse) return; if (item_selected) _evry_item_desel(item_selected); if (!(item_selected = data)) return; _evry_item_sel(item_selected); } static void _evry_cb_item_mouse_out(void *data, Evas *evas, Evas_Object *obj, void *event_info) { item_mouseover = NULL; } static void _evry_cb_plugin_sel(void *data1, void *data2) { Evry_Plugin *plugin; Eina_List *l; int i = 0; if (plugin_selected == data1) return; _evry_list_clear(); plugin_selected = data1; for (l = plugins; l; l = l->next) { plugin = l->data; if (!plugin->candidates) continue; if (plugin == plugin_selected) { _evry_show_candidates(plugin); toolbar_nr = i; e_widget_toolbar_item_select(o_toolbar, toolbar_nr); } else i++; } } static void _evry_backspace(void) { int len, val, pos; len = strlen(cmd_buf); if (len > 0) { pos = evas_string_char_prev_get(cmd_buf, len, &val); if ((pos < len) && (pos >= 0)) { cmd_buf[pos] = 0; _evry_update(); if (!update_timer) update_timer = ecore_timer_add(MATCH_LAG, _evry_update_timer, NULL); } } } static void _evry_update(void) { Efreet_Desktop *desktop; Evas_Object *o; edje_object_part_text_set(o_main, "e.text.label", cmd_buf); if (icon_object) evas_object_del(icon_object); icon_object = NULL; if (!cmd_buf[0]) return; } static void _evry_action(int finished) { if (plugin_selected && item_selected) { plugin_selected->action(item_selected); } else e_exec(popup->zone, NULL, cmd_buf, NULL, "everything"); if (finished) evry_hide(); } static void _evry_clear(void) { if (cmd_buf[0] != 0) { cmd_buf[0] = 0; _evry_update(); if (!update_timer) update_timer = ecore_timer_add(MATCH_LAG, _evry_update_timer, NULL); } } static void _evry_show_candidates(Evry_Plugin *plugin) { Evry_Item *it; Eina_List *l; int mw, mh, h; Evas_Object *o; e_box_freeze(o_list); EINA_LIST_FOREACH(plugin->candidates, l, it) { o = edje_object_add(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); evas_object_show(o); /* XXX eek*/ plugin->icon_get(it, popup->evas); if (edje_object_part_exists(o, "e.swallow.icons") && it->o_icon) { edje_object_part_swallow(o, "e.swallow.icons", it->o_icon); evas_object_show(it->o_icon); } edje_object_size_min_calc(o, &mw, &mh); e_box_pack_end(o_list, o); e_box_pack_options_set(o, 1, 1, /* fill */ 1, 0, /* expand */ 0.5, 0.5, /* align */ mw, mh, /* min */ 9999, mh /* max */ ); } e_box_thaw(o_list); e_box_min_size_get(o_list, NULL, &mh); evas_object_geometry_get(o_list, NULL, NULL, NULL, &h); if (mh <= h) e_box_align_set(o_list, 0.5, 0.0); else e_box_align_set(o_list, 0.5, 1.0); evas_event_thaw(popup->evas); } static void _evry_matches_update() { Evry_Plugin *plugin, *first = NULL; Eina_List *l; char buf[64]; int candidates; _evry_matches_clear(); plugin_count = 0; toolbar_nr = 0; EINA_LIST_FOREACH(plugins, l, plugin) { if (strlen(cmd_buf) == 0) { candidates = !plugin->need_query ? plugin->fetch(NULL) : 0; } else { candidates = plugin->fetch(cmd_buf); } if (candidates) { snprintf(buf, 64, "%s (%d)", plugin->name, eina_list_count(plugin->candidates)); e_widget_toolbar_item_append(o_toolbar, NULL, buf, _evry_cb_plugin_sel, plugin, NULL); if (!first) first = plugin; /* if (!plugin_selected) * { * plugin_selected = plugin; * } * else */ if (plugin == plugin_selected) toolbar_nr = plugin_count; plugin_count++; } } if ((toolbar_nr == 0) && (plugin_count > 0)) { plugin_selected = first; } if (plugin_selected) { _evry_show_candidates(plugin_selected); e_widget_toolbar_item_select(o_toolbar, toolbar_nr); } } static void _evry_item_remove(Evry_Item *it) { /* if (ev_last_mouse == it) * ev_last_mouse = NULL; */ evas_object_del(it->o_bg); if (it->o_icon) evas_object_del(it->o_icon); it->o_icon = NULL; } static void _evry_matches_clear(void) { Evry_Plugin *plugin; Eina_List *l; // FIXME add toolbar item remove method or use sth different evas_object_del(o_toolbar); Evas_Object *o = e_widget_toolbar_add(popup->evas, 48 * e_scale, 48 * e_scale); e_widget_toolbar_scrollable_set(o, 0); edje_object_part_swallow(o_main, "e.swallow.bar", o); evas_object_show(o); o_toolbar = o; _evry_list_clear(); EINA_LIST_FOREACH(plugins, l, plugin) plugin->cleanup(); } static void _evry_list_clear(void) { Evry_Item *it; Eina_List *l; if (plugin_selected) { evas_event_freeze(popup->evas); e_box_freeze(o_list); EINA_LIST_FOREACH(plugin_selected->candidates, l, it) _evry_item_remove(it); e_box_thaw(o_list); evas_event_thaw(popup->evas); } item_selected = NULL; } static void _evry_scroll_to(int i) { int n, h, mh; n = eina_list_count(plugin_selected->candidates); e_box_min_size_get(o_list, NULL, &mh); evas_object_geometry_get(o_list, NULL, NULL, NULL, &h); if (mh <= h) return; if (n > 1) { scroll_align_to = (double)i / (double)(n - 1); /* if (e_config->everything_scroll_animate) * { * eap_scroll_to = 1; * if (!eap_scroll_timer) * eap_scroll_timer = ecore_timer_add(0.01, _evry_eap_scroll_timer, NULL); * if (!animator) * animator = ecore_animator_add(_evry_animator, NULL); * } * else */ { scroll_align = scroll_align_to; e_box_align_set(o_list, 0.5, 1.0 - scroll_align); } } else e_box_align_set(o_list, 0.5, 1.0); } static void _evry_item_desel(Evry_Item *it) { 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"); } static void _evry_item_sel(Evry_Item *it) { 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"); } static int _evry_update_timer(void *data) { _evry_matches_update(); update_timer = NULL; return 0; } static void _evry_item_next(void) { Eina_List *l; int i; if (item_selected) { for (i = 0, l = plugin_selected->candidates; l; l = l->next, i++) { if (l->data == item_selected) { if (l->next) { _evry_item_desel(item_selected); item_selected = l->next->data; _evry_item_sel(item_selected); _evry_scroll_to(i + 1); } break; } } } else if (plugin_selected->candidates) { item_selected = plugin_selected->candidates->data; _evry_item_sel(item_selected); _evry_scroll_to(0); } /* if (item_selected) * edje_object_part_text_set(o_main, "e.text.label", item_selected->label); */ } static void _evry_item_prev(void) { Eina_List *l; int i; if (item_selected) { _evry_item_desel(item_selected); for (i = 0, l = plugin_selected->candidates; l; l = l->next, i++) { if (l->data == item_selected) { if (l->prev) { item_selected = l->prev->data; _evry_item_sel(item_selected); _evry_scroll_to(i - 1); } else item_selected = NULL; break; } } } /* if (item_selected) * edje_object_part_text_set(o_main, "e.text.label", item_selected->label); * else * edje_object_part_text_set(o_main, "e.text.label", cmd_buf); */ } static void _evry_plugin_next(void) { Eina_List *l; Evry_Plugin *plugin; Evry_Item *it; int changed = 0; int i; if (!plugin_selected) return; l = eina_list_data_find_list(plugins, plugin_selected); if (l && l->next) { for (l = l->next; l; l = l->next) { plugin = l->data; if (plugin->candidates) { toolbar_nr++; changed = 1; break; } } } if (!changed) { for (l = plugins; l; l = l->next) { plugin = l->data; if ((plugin != plugin_selected) && plugin->candidates) { changed = 1; toolbar_nr = 0; break; } } } if (changed) { _evry_list_clear(); plugin_selected = plugin; _evry_show_candidates(plugin); e_widget_toolbar_item_select(o_toolbar, toolbar_nr); } } static void _evry_plugin_prev(void) { Eina_List *l; Evry_Plugin *plugin; Evry_Item *it; int changed = 0; int i; if (!plugin_selected) return; l = eina_list_data_find_list(plugins, plugin_selected); if (l && l->prev) { for (l = l->prev; l; l = l->prev) { plugin = l->data; if (plugin->candidates) { toolbar_nr--; changed = 1; break; } } } if (!changed) { for (l = eina_list_last(plugins); l; l = l->prev) { plugin = l->data; if ((plugin != plugin_selected) && plugin->candidates) { changed = 1; toolbar_nr = plugin_count - 1; break; } } } if (changed) { _evry_list_clear(); plugin_selected = plugin; _evry_show_candidates(plugin); e_widget_toolbar_item_select(o_toolbar, toolbar_nr); } }