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