1 #include "e.h"
2 #include "evry_api.h"
3 // TODO - show error when input not parseable
4 
5 typedef struct _Plugin Plugin;
6 
7 struct _Plugin
8 {
9    Evry_Plugin base;
10 };
11 
12 static Eina_Bool _cb_data(void *data, int type, void *event);
13 static Eina_Bool _cb_error(void *data, int type, void *event);
14 static Eina_Bool _cb_del(void *data, int type, void *event);
15 
16 static const Evry_API *evry = NULL;
17 static Evry_Module *evry_module = NULL;
18 static Evry_Plugin *_plug;
19 static Ecore_Event_Handler *action_handler = NULL;
20 
21 static Ecore_Exe *exe = NULL;
22 static Eina_List *history = NULL;
23 static Eina_List *handlers = NULL;
24 static int error = 0;
25 static Eina_Bool active = EINA_FALSE;
26 static char _module_icon[] = "accessories-calculator";
27 static Evry_Item *cur_item = NULL;
28 
29 static Evry_Plugin *
_begin(Evry_Plugin * plugin,const Evry_Item * item EINA_UNUSED)30 _begin(Evry_Plugin *plugin, const Evry_Item *item EINA_UNUSED)
31 {
32    Plugin *p;
33 
34    if (active)
35      return NULL;
36 
37    EVRY_PLUGIN_INSTANCE(p, plugin)
38 
39    active = EINA_TRUE;
40 
41    return EVRY_PLUGIN(p);
42 }
43 
44 static int
_run_bc(Plugin * p)45 _run_bc(Plugin *p)
46 {
47    handlers = eina_list_append
48        (handlers, ecore_event_handler_add
49          (ECORE_EXE_EVENT_DATA, _cb_data, p));
50    handlers = eina_list_append
51        (handlers, ecore_event_handler_add
52          (ECORE_EXE_EVENT_ERROR, _cb_error, p));
53    handlers = eina_list_append
54        (handlers, ecore_event_handler_add
55          (ECORE_EXE_EVENT_DEL, _cb_del, p));
56 
57    exe = ecore_exe_pipe_run("bc -l",
58                             ECORE_EXE_PIPE_READ |
59                             ECORE_EXE_PIPE_READ_LINE_BUFFERED |
60                             ECORE_EXE_PIPE_WRITE |
61                             ECORE_EXE_PIPE_ERROR |
62                             ECORE_EXE_PIPE_ERROR_LINE_BUFFERED,
63                             NULL);
64    return !!exe;
65 }
66 
67 static void
_finish(Evry_Plugin * plugin)68 _finish(Evry_Plugin *plugin)
69 {
70    GET_PLUGIN(p, plugin);
71    Ecore_Event_Handler *h;
72    Evry_Item *it;
73    int items = 0;
74 
75    EINA_LIST_FREE (p->base.items, it)
76      {
77         if ((items++ > 1) && (items < 10))
78           history = eina_list_prepend(history, eina_stringshare_add(it->label));
79 
80         if (it == cur_item)
81           cur_item = NULL;
82 
83         EVRY_ITEM_FREE(it);
84      }
85 
86    if (cur_item)
87      {
88         EVRY_ITEM_FREE(cur_item);
89         cur_item = NULL;
90      }
91 
92    EINA_LIST_FREE (handlers, h)
93      ecore_event_handler_del(h);
94 
95    if (exe)
96      {
97         ecore_exe_terminate(exe);
98         ecore_exe_free(exe);
99         exe = NULL;
100      }
101    active = EINA_FALSE;
102 
103    E_FREE(p);
104 }
105 
106 static Eina_Bool
_cb_action_performed(EINA_UNUSED void * data,EINA_UNUSED int type,void * event)107 _cb_action_performed(EINA_UNUSED void *data, EINA_UNUSED int type, void *event)
108 {
109    Eina_List *l;
110    Evry_Item *it, *it2, *it_old;
111    Evry_Event_Action_Performed *ev = event;
112    Evry_Plugin *p = _plug;
113 
114    if (!ev->it1 || !(ev->it1->plugin == p))
115      return ECORE_CALLBACK_PASS_ON;
116 
117    if (!p->items)
118      return ECORE_CALLBACK_PASS_ON;
119 
120    /* remove duplicates */
121    if (p->items->next)
122      {
123         it = p->items->data;
124 
125         EINA_LIST_FOREACH (p->items->next, l, it2)
126           {
127              if (!strcmp(it->label, it2->label))
128                {
129                   p->items = eina_list_promote_list(p->items, l);
130                   evry->item_changed(it, 0, 1);
131                   EVRY_PLUGIN_UPDATE(p, EVRY_UPDATE_ADD);
132                   return ECORE_CALLBACK_PASS_ON;
133                }
134           }
135      }
136 
137    it_old = p->items->data;
138    it_old->selected = EINA_FALSE;
139 
140    it2 = EVRY_ITEM_NEW(Evry_Item, p, it_old->label, NULL, NULL);
141    it2->context = eina_stringshare_ref(p->name);
142    p->items = eina_list_prepend(p->items, it2);
143    evry->item_changed(it2, 0, 1);
144    EVRY_PLUGIN_UPDATE(p, EVRY_UPDATE_ADD);
145 
146    return ECORE_CALLBACK_PASS_ON;
147 }
148 
149 static int
_fetch(Evry_Plugin * plugin,const char * input)150 _fetch(Evry_Plugin *plugin, const char *input)
151 {
152    GET_PLUGIN(p, plugin);
153 
154    char buf[1024];
155    Evry_Item *it;
156 
157    if (!input) return 0;
158 
159    if (!exe && !_run_bc(p)) return 0;
160 
161    if (!cur_item)
162      {
163         it = EVRY_ITEM_NEW(Evry_Item, p, "0", NULL, NULL);
164         it->context = eina_stringshare_ref(p->base.name);
165         cur_item = it;
166      }
167 
168    if (history)
169      {
170         const char *result;
171 
172         EINA_LIST_FREE (history, result)
173           {
174              it = EVRY_ITEM_NEW(Evry_Item, p, result, NULL, NULL);
175              it->context = eina_stringshare_ref(p->base.name);
176              p->base.items = eina_list_prepend(p->base.items, it);
177              eina_stringshare_del(result);
178           }
179      }
180 
181    if (!strncmp(input, "scale=", 6))
182      snprintf(buf, 1024, "%s\n", input);
183    else
184      snprintf(buf, 1024, "scale=3;%s\n", input);
185 
186    ecore_exe_send(exe, buf, strlen(buf));
187 
188    /* XXX after error we get no response for first input ?! - send a
189       second time...*/
190    if (error)
191      {
192         ecore_exe_send(exe, buf, strlen(buf));
193         error = 0;
194      }
195 
196    return EVRY_PLUGIN_HAS_ITEMS(p);
197 }
198 
199 static Eina_Bool
_cb_data(void * data,int type EINA_UNUSED,void * event)200 _cb_data(void *data, int type EINA_UNUSED, void *event)
201 {
202    Ecore_Exe_Event_Data *ev = event;
203    Evry_Plugin *p = data;
204    Evry_Item *it;
205 
206    if (ev->exe != exe) return ECORE_CALLBACK_PASS_ON;
207 
208    if (ev->lines)
209      {
210         it = cur_item;
211         eina_stringshare_del(it->label);
212         it->label = eina_stringshare_add(ev->lines->line);
213 
214         if (!(it = eina_list_data_get(p->items)) || (it != cur_item))
215           {
216              p->items = eina_list_prepend(p->items, cur_item);
217              EVRY_PLUGIN_UPDATE(p, EVRY_UPDATE_ADD);
218           }
219         else if (it)
220           evry->item_changed(it, 0, 0);
221      }
222 
223    return ECORE_CALLBACK_PASS_ON;
224 }
225 
226 static Eina_Bool
_cb_error(void * data,int type EINA_UNUSED,void * event)227 _cb_error(void *data, int type EINA_UNUSED, void *event)
228 {
229    Ecore_Exe_Event_Data *ev = event;
230    Evry_Plugin *p = data;
231 
232    if (ev->exe != exe)
233      return ECORE_CALLBACK_PASS_ON;
234 
235    p->items = eina_list_remove(p->items, cur_item);
236    EVRY_PLUGIN_UPDATE(p, EVRY_UPDATE_ADD);
237    error = 1;
238 
239    return ECORE_CALLBACK_PASS_ON;
240 }
241 
242 static Eina_Bool
_cb_del(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)243 _cb_del(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
244 {
245    Ecore_Exe_Event_Del *e = event;
246 
247    if (e->exe != exe)
248      return ECORE_CALLBACK_PASS_ON;
249 
250    exe = NULL;
251    return ECORE_CALLBACK_PASS_ON;
252 }
253 
254 static int
_plugins_init(const Evry_API * _api)255 _plugins_init(const Evry_API *_api)
256 {
257    evry = _api;
258 
259    if (!evry->api_version_check(EVRY_API_VERSION))
260      return EINA_FALSE;
261 
262    action_handler = evry->event_handler_add(EVRY_EVENT_ACTION_PERFORMED,
263                                             _cb_action_performed, NULL);
264 
265    _plug = EVRY_PLUGIN_BASE(N_("Calculator"), _module_icon, EVRY_TYPE_TEXT,
266                             _begin, _finish, _fetch);
267 
268    _plug->history = EINA_FALSE;
269    _plug->async_fetch = EINA_TRUE;
270 
271    if (evry->plugin_register(_plug, EVRY_PLUGIN_SUBJECT, 0))
272      {
273         Plugin_Config *pc = _plug->config;
274         pc->view_mode = VIEW_MODE_LIST;
275         pc->trigger = eina_stringshare_add("=");
276         pc->trigger_only = EINA_TRUE;
277         pc->aggregate = EINA_FALSE;
278         /* pc->top_level = EINA_FALSE; */
279         /* pc->min_query = 3; */
280      }
281 
282    return EINA_TRUE;
283 }
284 
285 static void
_plugins_shutdown(void)286 _plugins_shutdown(void)
287 {
288    ecore_event_handler_del(action_handler);
289    action_handler = NULL;
290 
291    EVRY_PLUGIN_FREE(_plug);
292 }
293 
294 /***************************************************************************/
295 
296 Eina_Bool
evry_plug_calc_init(E_Module * m EINA_UNUSED)297 evry_plug_calc_init(E_Module *m EINA_UNUSED)
298 {
299    EVRY_MODULE_NEW(evry_module, evry, _plugins_init, _plugins_shutdown);
300 
301    return EINA_TRUE;
302 }
303 
304 void
evry_plug_calc_shutdown(void)305 evry_plug_calc_shutdown(void)
306 {
307    EVRY_MODULE_FREE(evry_module);
308 }
309 
310 void
evry_plug_calc_save(void)311 evry_plug_calc_save(void){}
312 
313